-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgeneticAlgorithm.py
139 lines (113 loc) · 4.81 KB
/
geneticAlgorithm.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
''' Network Config
Layer Input -> 24
Layer 1 -> 16 neurons
Layer 2 -> 16 neurons
Layer Ouput -> 4
Population = 2000 individuals
amount of weights per individual = 24*16 + 16*16 + 16*4 + 16 + 16 + 4 = 740
2000*740 = 1480000
'''
import tensorflow as tf
import random
import numpy as np
from snake import snake
from statistics import plot
import os
pressure = 300
mutation_chance = 0.2
def compare(x, y):
print(x, y)
return x[0] - y[0]
def individual():
layers = tf.keras.models.Sequential([
tf.keras.layers.InputLayer(input_shape=(24,)),
tf.keras.layers.Dense(16, activation='relu'),
tf.keras.layers.Dense(16, activation='relu'),
tf.keras.layers.Dense(4, activation='softmax')
]).layers
return [ layer.get_weights() for layer in layers ]
def createPopulation(quantity):
return [individual() for i in range(quantity)]
def calcularFitness(individual):
"""
Calcula el fitness de un individuo concreto.
"""
model = tf.keras.models.Sequential([
tf.keras.layers.InputLayer(input_shape=(24,)),
tf.keras.layers.Dense(16, activation='relu'),
tf.keras.layers.Dense(16, activation='relu'),
tf.keras.layers.Dense(4, activation='softmax')
])
for i in range(3):
model.layers[i].set_weights(individual[i])
game.restart(model)
duration = 0
score = 0
while 1:
final, score, cont = game.game()
if final == True:
break
duration += 1
fitness = (5+score)**2 + duration/20 - min(250, 500-cont)/250
plot_scores_food.append(score)
plot_scores.append(fitness)
plot(plot_scores_food, plot_scores)
return fitness
def selection_and_reproduction(population):
"""
Puntua todos los elementos de la poblacion (population) y se queda con los mejores
guardandolos dentro de 'selected'.
Despues mezcla el material genetico de los elegidos para crear nuevos individuos y
llenar la poblacion (guardando tambien una copia de los individuos seleccionados sin
modificar).
Por ultimo muta a los individuos.
"""
puntuados = [ (calcularFitness(i), i) for i in population] #Calcula el fitness de cada individuo, y lo guarda en pares ordenados de la forma (5 , [1,2,1,1,4,1,8,9,4,1])
puntuados = [i[1] for i in sorted(puntuados, key=lambda a: a[0])] #Ordena los pares ordenados y se queda solo con el array de valores
population = puntuados
selected = puntuados[(len(puntuados)-pressure):] #Esta linea selecciona los 'n' individuos del final, donde n viene dado por 'pressure'
#Se mezcla el material genetico para crear nuevos individuos
for i in range(len(population)-pressure):
padre = random.sample(selected, 2) #Se eligen dos padres
for j in range(3):
punto = random.randint(1,len(population[i][j][0])-1) #Se elige un punto para hacer el intercambio
population[i][j][0][:punto] = padre[0][j][0][:punto] #Se mezcla el material genetico de los padres en cada nuevo individuo
population[i][j][0][punto:] = padre[1][j][0][punto:]
punto = random.randint(1,len(population[i][j][1])-1) #Se elige un punto para hacer el intercambio
population[i][j][1][:punto] = padre[0][j][1][:punto] #Se mezcla el material genetico de los padres en cada nuevo individuo
population[i][j][1][punto:] = padre[1][j][1][punto:]
return population #El array 'population' tiene ahora una nueva poblacion de individuos, que se devuelven
def mutation(population):
"""
Se mutan los individuos al azar. Sin la mutacion de nuevos genes nunca podria
alcanzarse la solucion.
"""
for i in range(len(population)-pressure):
if random.random() <= mutation_chance: #Cada individuo de la poblacion (menos los padres) tienen una probabilidad de mutar
for j in range(3):
punto = random.randint(0,len(population[i][j][0])-1) #Se elgie un punto al azar
population[i][j][0][punto] = np.random.uniform(-1, 1, size=population[i][j][0][punto].shape) #y un nuevo valor para este punto
punto = random.randint(0,len(population[i][j][1])-1) #Se elgie un punto al azar
population[i][j][1][punto] = random.uniform(-1, 1) #y un nuevo valor para este punto
return population
plot_scores_food = []
plot_scores = []
if os.path.isfile('data.npy'):
population = np.load('data.npy', allow_pickle=True)
else:
print("Creating population...")
population = createPopulation(1000)
np.save('data', np.array(population, dtype=object))
game = snake(460, 680, 120)
for i in range(1000):
print("generation:", i)
population = selection_and_reproduction(population)
population = mutation(population)
np.save('data', np.array(population, dtype=object))
#if os.path.isfile('score.npy'):
# plot_scores = np.load('score.npy', allow_pickle=True)
#
#if os.path.isfile('score_food.npy'):
# plot_scores_food = np.load('score_food.npy', allow_pickle=True)
# np.save('score', plot_scores)
# np.save('score_food', plot_scores_food)