0% acharam este documento útil (0 voto)
2 visualizações9 páginas

Projeto Simples de Machine Learning Com Python

O documento descreve um projeto de neuroevolução utilizando machine learning com Pygame, onde criaturas com redes neurais aprendem a coletar comida através de um algoritmo genético. Cada criatura possui uma rede neural que determina suas ações com base na comida disponível, e após várias gerações, elas melhoram seu desempenho. O código inclui configurações para a simulação, implementação da rede neural e lógica de evolução das criaturas.
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
0% acharam este documento útil (0 voto)
2 visualizações9 páginas

Projeto Simples de Machine Learning Com Python

O documento descreve um projeto de neuroevolução utilizando machine learning com Pygame, onde criaturas com redes neurais aprendem a coletar comida através de um algoritmo genético. Cada criatura possui uma rede neural que determina suas ações com base na comida disponível, e após várias gerações, elas melhoram seu desempenho. O código inclui configurações para a simulação, implementação da rede neural e lógica de evolução das criaturas.
Direitos autorais
© All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd

🧬

"""
NEUROEVOLUÇÃO - Machine Learning com Pygame
================================================
Criaturas com redes neurais aprendem a coletar comida
usando Algoritmo Genético + Neuroevolução.

Como funciona o ML aqui:


- Cada criatura tem uma rede neural (percepção → decisão)
- Aptidão (fitness) = comida coletada
- Ao fim de cada geração: elitismo + crossover + mutação
- Após ~10-20 gerações, as criaturas ficam visivelmente melhores!

Controles:
ESPAÇO → Pausar / Retomar
1/2/3/4 → Velocidade (1x, 2x, 5x, 10x)
R → Reiniciar simulação
Q / ESC → Sair
"""

import pygame
import numpy as np
import random
import math
import sys

# ─── Configurações ────────────────────────────────────────────────────────────


WIDTH, HEIGHT = 960, 720
FPS = 60
UI_H = 100 # Altura do painel superior

N_CREATURES = 40
N_FOOD = 25
GENERATION_SECS = 12 # Segundos por geração

# Rede Neural
INPUT_SIZE = 7
HIDDEN_SIZE = 10
OUTPUT_SIZE = 2

# Evolução
MUTATION_RATE = 0.12
MUTATION_STR = 0.35
ELITE_FRAC = 0.20

# Paleta de cores
C_BG = (12, 16, 28)
C_UI = (18, 23, 42)
C_BORDER = (45, 65, 110)
C_FOOD = (60, 220, 110)
C_FOOD_GLOW = (30, 110, 55)
C_CREATURE = (80, 160, 255)
C_BEST = (255, 210, 50)
C_WORST = (80, 90, 130)
C_TEXT = (190, 205, 235)
C_DIM = (90, 105, 145)
C_CHART = (70, 210, 140)
C_ACCENT = (255, 140, 60)

# ─── Rede Neural ──────────────────────────────────────────────────────────────


class NeuralNet:
def __init__(self):
self.w1 = [Link](INPUT_SIZE, HIDDEN_SIZE) * 0.6
self.b1 = [Link](HIDDEN_SIZE) * 0.3
self.w2 = [Link](HIDDEN_SIZE, OUTPUT_SIZE) * 0.6
self.b2 = [Link](OUTPUT_SIZE) * 0.3

def predict(self, x):


h = [Link](x @ self.w1 + self.b1)
return [Link](h @ self.w2 + self.b2)

def flat(self):
return [Link]([[Link](), self.b1, [Link](), self.b2])

def load(self, w):


i = 0
s = INPUT_SIZE * HIDDEN_SIZE
self.w1 = w[i:i+s].reshape(INPUT_SIZE, HIDDEN_SIZE); i += s
self.b1 = w[i:i+HIDDEN_SIZE]; i += HIDDEN_SIZE
s = HIDDEN_SIZE * OUTPUT_SIZE
self.w2 = w[i:i+s].reshape(HIDDEN_SIZE, OUTPUT_SIZE); i += s
self.b2 = w[i:i+OUTPUT_SIZE]

def clone(self):
nn = NeuralNet()
[Link]([Link]().copy())
return nn

def crossover(self, other):


child = NeuralNet()
a, b = [Link](), [Link]()
mask = [Link](len(a)) < 0.5
[Link]([Link](mask, a, b))
return child

def mutate(self):
w = [Link]()
mask = [Link](len(w)) < MUTATION_RATE
w += mask * [Link](len(w)) * MUTATION_STR
[Link](w)
# ─── Criatura ─────────────────────────────────────────────────────────────────
class Creature:
R = 7
MAX_SPD = 2.8
MAX_ACC = 0.28
TRAIL_LEN = 25

def __init__(self, nn=None):


[Link] = [Link]([
[Link](30, WIDTH - 30),
[Link](UI_H + 20, HEIGHT - 30)
], dtype=float)
[Link] = [Link](2) * 0.5
[Link] = nn or NeuralNet()
[Link] = 0
[Link] = []

# Constrói vetor de entrada para a rede neural


def _inputs(self, foods):
if not foods:
return [Link](INPUT_SIZE)

diffs = [Link](foods) - [Link]


dists = [Link](diffs, axis=1)
idx = int([Link](dists))
d = diffs[idx]
dist = dists[idx]
angle = math.atan2(d[1], d[0])

# Segunda comida mais próxima


if len(foods) > 1:
idx2 = int([Link](dists)[1])
d2 = diffs[idx2]
dist2 = dists[idx2]
else:
d2, dist2 = d, dist

diag = [Link](WIDTH, HEIGHT)


return [Link]([
d[0] / WIDTH, d[1] / HEIGHT,
[Link][0] / self.MAX_SPD, [Link][1] / self.MAX_SPD,
dist / diag,
d2[0] / WIDTH, d2[1] / HEIGHT,
])

def update(self, foods):


inputs = self._inputs(foods)
out = [Link](inputs) * self.MAX_ACC
[Link] += out
spd = [Link]([Link])
if spd > self.MAX_SPD:
[Link] *= self.MAX_SPD / spd
[Link] += [Link]

# Bordas — rebater
for ax in range(2):
lo = (UI_H + self.R) if ax == 1 else self.R
hi = HEIGHT - self.R if ax == 1 else WIDTH - self.R
if [Link][ax] < lo:
[Link][ax] = lo
[Link][ax] *= -0.7
elif [Link][ax] > hi:
[Link][ax] = hi
[Link][ax] *= -0.7

[Link]([Link]())
if len([Link]) > self.TRAIL_LEN:
[Link](0)

def eat(self, foods):


eaten = []
for i, f in enumerate(foods):
if [Link](f - [Link]) < self.R + 7:
[Link](i)
[Link] += 1
return eaten

def draw(self, surf, rank, total):


t = rank / max(total - 1, 1) # 0=melhor 1=pior
cr = tuple(int(C_BEST[c] * (1 - t) + C_WORST[c] * t) for c in range(3))

# Rastro
for i, pt in enumerate([Link]):
alpha = i / len([Link])
tc = tuple(int(cr[c] * alpha * 0.5) for c in range(3))
[Link](surf, tc, [Link](int), max(1, int(alpha * 3)))

pi = [Link](int)

# Halo do melhor
if rank == 0:
[Link](surf, (80, 60, 20), pi, self.R + 6)

# Corpo
[Link](surf, cr, pi, self.R)
[Link](surf, (200, 220, 255), pi, self.R, 1)

# Ponteiro de direção
angle = math.atan2([Link][1], [Link][0])
tip = (pi[0] + int([Link](angle) * (self.R + 5)),
pi[1] + int([Link](angle) * (self.R + 5)))
[Link](surf, (220, 235, 255), pi, tip, 2)
# ─── Simulação Principal ──────────────────────────────────────────────────────
class Simulation:

def __init__(self):
[Link]()

[Link].set_caption("
[Link] = [Link]()
🧬
[Link] = [Link].set_mode((WIDTH, HEIGHT))
Neuroevolução — Machine Learning com Pygame")

self.font_sm = [Link]("monospace", 14)


self.font_md = [Link]("monospace", 17)
self.font_lg = [Link]("monospace", 22, bold=True)
self.font_xl = [Link]("monospace", 28, bold=True)

self._reset()

def _reset(self):
[Link] = 1
[Link] = 0
self.best_history = [] # melhor fitness por geração
self.avg_history = []
[Link] = 0 # frames decorridos na geração
[Link] = 1
[Link] = False
[Link] = [Creature() for _ in range(N_CREATURES)]
[Link] = self._spawn_foods()

def _spawn_foods(self):
return [[Link]([
[Link](20, WIDTH - 20),
[Link](UI_H + 15, HEIGHT - 15)
], dtype=float) for _ in range(N_FOOD)]

# ── Algoritmo Genético ────────────────────────────────────────────────────


def _evolve(self):
[Link](key=lambda c: [Link], reverse=True)
bests = [Link][0].fitness
avg = sum([Link] for c in [Link]) / N_CREATURES
self.best_history.append(bests)
self.avg_history.append(avg)
if bests > [Link]:
[Link] = bests

n_elite = max(2, int(N_CREATURES * ELITE_FRAC))


elites = [Link][:n_elite]
new_pop = []

# Elitismo — copia os melhores direto


for e in elites:
new_pop.append(Creature(nn=[Link]()))

# Resto — crossover entre elites + mutação


while len(new_pop) < N_CREATURES:
p1, p2 = [Link](elites, k=2)
child_nn = [Link]([Link])
child_nn.mutate()
new_pop.append(Creature(nn=child_nn))

[Link] = new_pop
[Link] = self._spawn_foods()
[Link] = 0
[Link] += 1

# ── Loop de Simulação ─────────────────────────────────────────────────────


def _step(self):
for c in [Link]:
[Link]([Link])
eaten = [Link]([Link])
for i in sorted(eaten, reverse=True):
[Link](i)
# Reabastecer comida
while len([Link]) < N_FOOD:
[Link]([Link]([
[Link](20, WIDTH - 20),
[Link](UI_H + 15, HEIGHT - 15)
], dtype=float))
[Link] += 1
if [Link] >= GENERATION_SECS * FPS:
self._evolve()

# ── Desenhar Comida ───────────────────────────────────────────────────────


def _draw_food(self):
for f in [Link]:
fi = [Link](int)
[Link]([Link], C_FOOD_GLOW, fi, 9)
[Link]([Link], C_FOOD, fi, 6)
[Link]([Link], (180, 255, 200), fi, 3)

# ── Painel Superior ───────────────────────────────────────────────────────


def _draw_ui(self):
[Link]([Link], C_UI, (0, 0, WIDTH, UI_H))
[Link]([Link], C_BORDER, (0, UI_H), (WIDTH, UI_H), 2)

# Título
title = self.font_xl.render("NEUROEVOLUÇÃO", True, (130, 185, 255))
[Link](title, (18, 10))
sub = self.font_sm.render("Redes Neurais + Algoritmo Genético", True, C_DIM)
[Link](sub, (20, 44))
sub2 = self.font_sm.render("Criaturas evoluem para coletar comida", True,
C_DIM)
[Link](sub2, (20, 62))
ctrl = self.font_sm.render("[SPC] Pausa [1-4] Vel [R] Reset [Q] Sair", True,
(70, 90, 140))
[Link](ctrl, (20, 80))

# Stats
cur_best = max(([Link] for c in [Link]), default=0)
cur_avg = sum([Link] for c in [Link]) / N_CREATURES
t_left = max(0, GENERATION_SECS - [Link] / FPS)

stats = [
("GEN", str([Link]), C_TEXT),
("MELHOR", str(cur_best), C_BEST),
("MÉDIA", f"{cur_avg:.1f}", C_CHART),
("RECORDE",str([Link]), C_ACCENT),
("TEMPO", f"{t_left:.1f}s", C_TEXT),
("VEL", f"{[Link]}x", C_TEXT),
]
sx = 340
for i, (lbl, val, col) in enumerate(stats):
bx = sx + i * 100
l = self.font_sm.render(lbl, True, C_DIM)
v = self.font_lg.render(val, True, col)
[Link](l, (bx, 12))
[Link](v, (bx, 32))

# Barra de progresso da geração


prog_w = WIDTH - 340 - 20
elapsed = [Link] / (GENERATION_SECS * FPS)
[Link]([Link], C_BORDER, (340, 76, prog_w, 8), border_radius=4)
[Link]([Link], (80, 140, 220),
(340, 76, int(prog_w * elapsed), 8), border_radius=4)

# Mini gráfico de evolução


self._draw_chart()

def _draw_chart(self):
if len(self.best_history) < 2:
return
cx, cy, cw, ch = WIDTH - 180, 8, 170, 80
[Link]([Link], (20, 26, 46), (cx, cy, cw, ch), border_radius=4)
[Link]([Link], C_BORDER, (cx, cy, cw, ch), 1, border_radius=4)

lbl = self.font_sm.render("Evolução do Fitness", True, C_DIM)


[Link](lbl, (cx + 4, cy + 3))

maxf = max(max(self.best_history), 1)
n = min(len(self.best_history), cw // 4)
bh = self.best_history[-n:]
ah = self.avg_history[-n:]
pad = 14
def to_pt(i, v):
px = cx + int(i * (cw - 4) / max(n - 1, 1)) + 2
py = cy + ch - pad - int(v / maxf * (ch - pad - 6)) - 2
return px, py

for series, col in [(ah, (60, 160, 100)), (bh, C_CHART)]:


pts = [to_pt(i, v) for i, v in enumerate(series)]
if len(pts) >= 2:
[Link]([Link], col, False, pts, 2)

# ── Main Loop ─────────────────────────────────────────────────────────────


def run(self):
while True:
[Link](FPS)

for event in [Link]():


if [Link] == [Link]:
[Link](); [Link]()
if [Link] == [Link]:
k = [Link]
if k in (pygame.K_q, pygame.K_ESCAPE):
[Link](); [Link]()
elif k == pygame.K_SPACE:
[Link] = not [Link]
elif k == pygame.K_r:
self._reset()
elif k == pygame.K_1: [Link] = 1
elif k == pygame.K_2: [Link] = 2
elif k == pygame.K_3: [Link] = 5
elif k == pygame.K_4: [Link] = 10

if not [Link]:
for _ in range([Link]):
self._step()

# ── Render ─────────────────────────────────────────────
[Link](C_BG)

# Grade sutil de fundo


for gx in range(0, WIDTH, 60):
[Link]([Link], (18, 24, 42), (gx, UI_H), (gx, HEIGHT))
for gy in range(UI_H, HEIGHT, 60):
[Link]([Link], (18, 24, 42), (0, gy), (WIDTH, gy))

self._draw_food()

# Criaturas ordenadas por fitness (piores primeiro, melhor por cima)


ranked = sorted(enumerate([Link]),
key=lambda x: x[1].fitness)
for draw_rank, (orig_rank, c) in enumerate(ranked):
[Link]([Link],
rank=N_CREATURES - 1 - draw_rank,
total=N_CREATURES)

self._draw_ui()

# Legenda
leg = [
("● Melhor criatura", C_BEST),
("● Pior criatura", C_WORST),
("● Comida", C_FOOD),
]
for i, (txt, col) in enumerate(leg):
s = self.font_sm.render(txt, True, col)
[Link](s, (WIDTH - 185, UI_H + 10 + i * 20))

if [Link]:
ov = [Link]((WIDTH, HEIGHT - UI_H), [Link])
[Link]((0, 0, 0, 120))

msg = self.font_xl.render("⏸
[Link](ov, (0, UI_H))
PAUSADO", True, (255, 250, 200))
[Link](msg, (WIDTH // 2 - 90, HEIGHT // 2 - 16))

[Link]()

# ─── Entrada ──────────────────────────────────────────────────────────────────


if __name__ == "__main__":
try:
import numpy
except ImportError:
print("Instale numpy: pip install numpy")
[Link](1)

Simulation().run()

Você também pode gostar