def genome_seeder(n): count = 0 while count < n: for seed_genome in seed_genomes: genome = copy(seed_genome) mutator(genome) yield genome count += 1
def genome_pair_factory(weight_gen=default_gen(), bias_gen=default_gen()): Node.innov_iter = itertools.count() Edge.innov_iter = itertools.count() np.random.seed(1) g1 = minimal(input_size=2, output_size=3, depth=5) n1 = g1.add_node(4) g1.add_edge(g1.layers[0][0], n1) g1.add_edge(n1, g1.outputs[0]) n2 = g1.add_node(3) g1.add_edge(g1.layers[0][1], n2) g1.add_edge(n2, g1.outputs[2]) g2 = copy(g1) n4 = g2.add_node(2) g2.add_edge(g2.layers[0][1], n4) g2.add_edge(n4, g2.layers[3][0]) n5 = g1.add_node(4) g1.add_edge(g1.layers[3][0], n5) g1.add_edge(n5, g1.outputs[0]) n3 = g1.add_node(3) e1 = g1.add_edge(g1.layers[0][0], n3) e2 = g1.add_edge(n3, g1.outputs[2]) g2.layers[3].append(Node.copy(n3)) g2.nodes.append(Node.copy(n3)) n6 = g1.add_node(3) g1.add_edge(g1.layers[0][0], n6) g1.add_edge(n6, g1.outputs[1]) g2.add_edge(g2.layers[0][0], n3) e2 = g2.add_edge(n3, g2.outputs[2]) for w, edge in zip(weight_gen, [*g1.edges, *g2.edges]): edge.weight = w for w, node in zip(bias_gen, [*g1.nodes, *g2.nodes]): node.weight = w return g1, g2
def call_on_population(self, population): """Takes population of speciated genomes and evolves them into the next generation of genomes. - First we compute the population proportion that each group is granted. - Then we keep only the top species_member_survival_rate of each generation. - for each group - we put the top performing genome into the new populations - randomly draw Genomes from the remaining top performing genomes and apply mutations/pairing until the rest of the groups population share is taken up. :param population: NEATPopulation object :return: None """ total_group_fitness_sum = sum([item['group_fitness'] for key, item in population.species.items()]) new_genomes = [] for key, item in population.species.items(): pop_prop = int(round(population.population_size * (item['group_fitness'] / total_group_fitness_sum))) survival_prop = int(len(item['group']) * self.species_member_survival_rate) survival_prop = 5 if survival_prop < 5 else survival_prop item['group'] = item['group'][:survival_prop] best_performer = copy(item['group'][0]) new_genomes.append(best_performer) for _ in range(pop_prop - 1): selected_gene = choice(item['group']) new_genome = self.call_on_genome(selected_gene) if random() > self.mutation_without_crossover_rate: other_genome = None if random() < self.interspecies_mating_rate and len(population.species) > 1: # select from other species other_item = choice([item for _, item in population.species.items()]) if len(other_item['group']) > 2: other_genome = choice([g for g in other_item['group'] if g is not selected_gene]) elif len(item['group']) > 2: other_genome = choice([g for g in item['group'] if g is not selected_gene]) if other_genome: secondary, primary = sorted([new_genome, other_genome], key=lambda g: g.fitness) new_genome = self.crossover(primary, secondary) new_genomes.append(new_genome) population.generation += 1 population.genomes = new_genomes
def test_genome_weight_mutation(self): new_uniform_weight = 0.5 with patch('numpy.random.uniform', side_effect=[ 0.1, *[0.95, 0.4, 0.95, *[random() for _ in range(10)]], new_uniform_weight, *[random() for _ in range(10)] ]): with patch('numpy.random.normal', side_effect=[[0.1], [0.4], [random() for _ in range(10)]]): g = minimal(input_size=2, output_size=3, depth=5) m_g = copy(g) mutate_weights = curry_weight_mutator( weight_mutation_likelihood=0.8, weight_mutation_rate_random=0.1, weight_mutation_rate_uniform=0.9, weight_mutation_variance=0.1) mutate_weights(m_g) self.assertEqual(m_g.edges[0].weight, new_uniform_weight) self.assertEqual(g.edges[1].weight + 0.1, m_g.edges[1].weight)
def test_copy_factory(self): g = minimal() n2 = g.add_node(3) g.add_edge(g.layers[0][0], n2) g.add_edge(n2, g.outputs[0]) g_copy = copy(g) self.assertNotEqual(g_copy, g) for node_copy, node in zip(g_copy.nodes, g.nodes): self.assertEqual(node_copy.innov, node.innov) for layer_copy, layer in zip(g_copy.layers, g.layers): self.assertEqual(len(layer_copy), len(layer)) for node_copy, node in zip(layer_copy, layer): self.assertNotEqual(node_copy, node) self.assertEqual(node_copy.innov, node.innov) self.assertEqual(len(node_copy.edges_in), len(node.edges_in)) self.assertEqual(len(node_copy.edges_out), len(node.edges_out)) for edge_copy, edge in zip(g_copy.edges, g.edges): self.assertNotEqual(edge_copy, edge) self.assertEqual(edge_copy.innov, edge.innov)
def call_on_population(self, population): """Mutate Population. sorts genomes by fitness, removes any past a certain cutoff. Randomly samples from the remaining genomes and mutates them until the population is compelte again. :param population: Population Object being mutated :return: None """ genomes = sorted(population.genomes, key=lambda g: g.fitness, reverse=True) cutoff = int(self.survival_rate * population.population_size) genomes = genomes[0:cutoff] population.genomes = [*genomes] new_genomes = np.random.choice(genomes, population.population_size - cutoff) for genome in new_genomes: new_genome = copy(genome) self.call_on_genome(new_genome) population.genomes.append(new_genome) population.generation += 1
def call_on_genome(self, genome): """Action on genome. Only performs weight and topological mutations. :param genome: Genome to copy and mutate. :return: New genome. """ new_genome = copy(genome) new_genome.fitness = genome.fitness for edge in new_genome.edges: self.weight_mutator(edge) for node in new_genome.nodes: self.weight_mutator(node) if np.random.uniform(0, 1, 1) < self.new_node_probability: add_node(new_genome) if np.random.uniform(0, 1, 1) < self.new_edge_probability: add_edge(new_genome) return new_genome