From 17cf9a67db9760e32c3433c2ec762c573d61eb64 Mon Sep 17 00:00:00 2001 From: George Lacey Date: Mon, 16 Oct 2017 16:19:21 +0100 Subject: [PATCH] Tidy code - Don't mutate the elite - Remove unused methods - Remove roulette selection --- src/lifecycle.py | 13 +++++++++++-- src/main.py | 29 ++++++++++++++--------------- src/population.py | 32 +++++++++++++------------------- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/src/lifecycle.py b/src/lifecycle.py index d59805f..bcfebc4 100644 --- a/src/lifecycle.py +++ b/src/lifecycle.py @@ -16,7 +16,9 @@ class Lifecycle(object): self.iterations += 1 elite = self.params["elite"] crossover = self.params["crossover"] - self.population.advance_generation(elite, crossover_rate=crossover, n_arena=4) + mutation = self.params["mutation"] + self.population.advance_generation(elite, crossover_rate=crossover, + n_arena=4, mutation=mutation) self.best_fit.append(self.population.best_fitness()) self.average_fit.append(self.population.avg_fitness()) if epoch > 50: @@ -24,7 +26,6 @@ class Lifecycle(object): if max(recent_best) - min(recent_best) < 0.02: break - def best_fitness(self): return self.population.best_fitness() @@ -32,11 +33,19 @@ class Lifecycle(object): plt.plot(self.best_fit) plt.xlabel("Epoch") plt.ylabel("Best fitness") + plt.title(self.get_params()) if show: plt.show() if location is not None: plt.savefig(location) + def get_params(self): + return_string = ("mutation: %d " % self.params['mutation']) + return_string += ("crossover: %d " % self.params['crossover']) + return_string += ("elite: %d " % self.params['elite']) + return_string += ("iter: %d" % self.iterations) + return return_string + def get_csv(self): id = {'id': self.id} best_fitness = {'best_fit': self.best_fitness()} diff --git a/src/main.py b/src/main.py index aadcda6..245ba13 100644 --- a/src/main.py +++ b/src/main.py @@ -1,4 +1,3 @@ -import os from multiprocessing import Process, Queue from lifecycle import Lifecycle from file import File @@ -8,14 +7,16 @@ import time param_example = {'population_size': 10, 'elite': round(0.1 * 10), 'crossover': round(0.6 * 10), + 'mutation': 0, 'epochs': 1000, 'iter': 0} -def gen_param(pop, elite, crossover, epochs): +def gen_param(pop, elite, crossover, epochs, mutation=0): return {'population_size': pop, - 'elite': round(elite * pop), - 'crossover': round(crossover * pop), + 'elite': round((elite / 100) * pop), + 'crossover': round((crossover / 100) * pop), + 'mutation': mutation, 'epochs': epochs} @@ -25,25 +26,23 @@ outputs = Queue() def run_instance(instance, output_list): instance.start() output_list.put(instance.get_csv()) + instance.generate_graph(location="images/%d.png" % instance.id, show=False) print(instance.id) -def cls(): - os.system('cls' if os.name == 'nt' else 'clear') - - output_file = File("output.csv", ['id', 'best_fit'] + list(param_example)) - output_file.write_header() instances = list() +instance_id = 0 -id = 0 - -for i in [x * 1 for x in range(0, 100)]: - instances.append(Process(name="Thread-%d" % i, target=run_instance, - args=[Lifecycle(id, gen_param(50, 0, 0.5, 500)), outputs])) - id += 1 +for i in range(20, 90, 10): + for j in range(0, 3): + instances.append( + Process(name="Thread-%d" % i, target=run_instance, + args=[Lifecycle(instance_id, + gen_param(50, j, i, 500, mutation=5)), outputs])) + instance_id += 1 start_time = time.time() diff --git a/src/population.py b/src/population.py index cf7ad8e..a446ab7 100644 --- a/src/population.py +++ b/src/population.py @@ -72,38 +72,32 @@ class Population(object): return sorted_members - def advance_generation(self, n_elite, crossover_rate=0.5, n_arena=4): + def advance_generation(self, n_elite, crossover_rate=0.5, n_arena=4, mutation=0): new_generation = list() - # elitism - for member in self.elite(n_elite): - new_generation.append(member) - - # parent - # for ind in range(0, n_crossover): - # self.roulette_crossover(new_generation) - - while len(new_generation) < len(self.members): + while len(new_generation) < len(self.members) - n_elite: if n_arena > 0: x, y = self.tournament_selection(n_arena, crossover_rate) - else: - x, y = self.roulette_crossover() new_generation.append(x) new_generation.append(y) - self.members = new_generation + # Remove excess members + while len(new_generation) > len(self.members) - n_elite: + new_generation.pop() - self.mutate(10) + for member in new_generation: + if rand.random() < mutation/100: + member.mutate() + + # elitism + new_generation += self.elite(n_elite) + + self.members = new_generation def remove_member(self, member): self.members.remove(member) - def roulette_crossover(self): - parent_one = self.roulette() - parent_two = self.roulette() - return parent_one.crossover(parent_two) - def tournament_selection(self, arena_size, rate): parents = list() for i in range(arena_size):