Python - функция мутации генетического алгоритма не работает
Я создал ИИ в python/pygame, но даже после нескольких часов отладки, я не мог найти, почему люди (точки) не видоизменяются. Через несколько поколений все люди просто перекрывают друг друга и следуют по одному и тому же пути. Но после мутации они должны двигаться немного по-другому.
Вот как выглядит численность населения в 10 лет после каждых 2-3 поколений.
Изображение 1 Изображение 2 Изображение 3
Как видите, через несколько поколений они просто перекрываются, и все люди в популяции движутся вместе, следуя точно по одному и тому же пути! Нам нужны мутации!!!
Буду очень признателен вам, если вы найдете ошибку. Поблагодарить!
Я увидел код от: https://www.youtube.com/watch?v=BOZfhUcNiqk&t и попытался сделать это на python. Вот мой код
import pygame, random
import numpy as np
pygame.init()
width = 800
height = 600
screen = pygame.display.set_mode((width, height))
pygame.display.set_caption("The Dots")
FPS = 30
clock = pygame.time.Clock()
gameExit = False
grey = [30, 30, 30]
white = [255, 255, 255]
black = [0, 0, 0]
red = [255, 0, 0]
goal = [400, 10]
class Dot():
def __init__(self):
self.x = int(width/2)
self.y = int(height - 150)
self.r = 3
self.c = black
self.xVel = self.yVel = 0
self.xAcc = 0
self.yAcc = 0
self.dead = False
self.steps = 0
self.reached = False
self.brain = Brain(200)
def show(self):
pygame.draw.circle(screen, self.c, [int(self.x), int(self.y)], self.r)
def update(self):
if (self.x >= width or self.x <= 0 or self.y >= height or self.y <= 0):
self.dead = True
elif (np.sqrt((self.x-goal[0])**2 + (self.y-goal[1])**2) < 5):
self.reached = True
if not self.dead and not self.reached:
if len(self.brain.directions) > self.steps:
self.xAcc = self.brain.directions[self.steps][0]
self.yAcc = self.brain.directions[self.steps][1]
self.steps += 1
self.xVel += self.xAcc
self.yVel += self.yAcc
if self.xVel > 5:
self.xVel = 5
if self.yVel > 5:
self.yVel = 5
self.x += self.xVel
self.y += self.yVel
else: self.dead = True
def calculateFitness(self):
distToGoal = np.sqrt((self.x-goal[0])**2 + (self.y-goal[1])**2)
self.fitness = 1/(distToGoal**2)
return self.fitness
def getChild(self):
child = Dot()
child.brain = self.brain
return child
class Brain():
def __init__(self, size):
self.size = size
self.directions = []
self.randomize()
def randomize(self):
self.directions.append((np.random.normal(size=(self.size, 2))).tolist())
self.directions = self.directions[0]
def mutate(self):
for i in self.directions:
rand = random.random()
if rand < 1:
i = np.random.normal(size=(1, 2)).tolist()[0]
class Population():
def __init__(self, size):
self.size = size
self.dots = []
self.fitnessSum = 0
for i in range(self.size):
self.dots.append(Dot())
def show(self):
for i in self.dots:
i.show()
def update(self):
for i in self.dots:
i.update()
def calculateFitness(self):
for i in self.dots:
i.calculateFitness()
def allDead(self):
for i in self.dots:
if not i.dead and not i.reached:
return False
return True
def calculateFitnessSum(self):
self.fitnessSum = 0
for i in self.dots:
self.fitnessSum += i.fitness
def SelectParent(self):
rand = random.uniform(0, self.fitnessSum)
runningSum = 0
for i in self.dots:
runningSum += i.fitness
if runningSum > rand:
return i
def naturalSelection(self):
newDots = []
self.calculateFitnessSum()
for i in self.dots:
parent = self.SelectParent()
newDots.append(parent.getChild())
self.dots = newDots
def mutate(self):
for i in self.dots:
i.brain.mutate()
test = Population(100)
while not gameExit:
for event in pygame.event.get():
if event.type == pygame.QUIT:
gameExit = True
screen.fill(white)
if test.allDead():
#Genetic Algorithm
test.calculateFitness()
test.naturalSelection()
test.mutate()
else:
test.update()
test.show()
pygame.draw.circle(screen, red, goal, 4)
clock.tick(FPS)
pygame.display.update()
pygame.quit()
Спасибо за любую помощь!
1 ответ
Я не прошел весь код, но здесь
def mutate(self):
for i in self.directions:
rand = random.random()
if rand < 1:
i = np.random.normal(size=(1, 2)).tolist()[0]
вы пытаетесь присвоить новое значение i (которое является итератором), поэтому оно ничего не изменит, что объясняет, почему у вас возникают проблемы с мутациями.
У вас должно быть что-то вроде этого:
def mutate(self):
for i in range(len(self.directions)):
rand = random.random()
if rand < 1:
self.directions[i] = np.random.normal(size=(1, 2)).tolist()[0]
или вы можете использовать списки понимания https://docs.python.org/3/tutorial/datastructures.html