def test_from_genes_constructor(self): g = minimal(input_size=2, output_size=3, depth=5) n2 = g.add_node(4) g.add_edge(g.layers[0][0], n2) g.add_edge(n2, g.outputs[0]) n2 = g.add_node(3) g.add_edge(g.layers[0][1], n2) g.add_edge(n2, g.outputs[2]) n2 = g.add_node(3) g.add_edge(g.layers[0][0], n2) g.add_edge(n2, g.outputs[2]) edges = [e.to_reduced_repr for e in g.edges] nodes = [n.to_reduced_repr for n in g.nodes] g_2 = from_genes( nodes, edges, input_size=2, output_size=3, depth=5) self.assertEqual( [[n.to_reduced_repr for n in layer] for layer in g_2.layers], [[n.to_reduced_repr for n in layer] for layer in g.layers] ) self.assertEqual( [edge.to_reduced_repr for edge in g_2.edges], [edge.to_reduced_repr for edge in g.edges] )
def simple_adres_example(): genome = minimal( input_size=1, output_size=1 ) weights_len = len(genome.edges) + len(genome.nodes) init_mu = np.random.uniform(-3, 3, weights_len) mutator = ADRESMutator( initial_mu=init_mu, std_dev=0.1 ) seeder = curry_genome_seeder( mutator=mutator, seed_genomes=[genome] ) population = RESPopulation( population_size=1000, genome_seeder=seeder ) target_mu = np.random.uniform(-3, 3, len(init_mu)) assign_population_fitness = build_simple_env(target_mu) for i in range(100): assign_population_fitness(population) mutator(population) loss = np.linalg.norm(mutator.mu - target_mu) print(f'generation: {i}, loss: {loss}')
def neat_bipedal_walker(): pop_size = 400 mutator = NEATMutator(new_edge_probability=0.1, new_node_probability=0.05) genome = minimal(input_size=24, output_size=4, depth=5) seeder = curry_genome_seeder(mutator=mutator, seed_genomes=[genome]) metric = generate_neat_metric(c_1=1, c_2=1, c_3=3) population = NEATPopulation(population_size=pop_size, delta=4, genome_seeder=seeder, metric=metric) ds = DataStore(name='bip_walker_NEAT_data') assign_population_fitness = build_env(env_name='BipedalWalker-v3', num_steps=200, repetition=1) counter_fn = make_counter_fn() for i in range(500): success = assign_population_fitness(population) if success and counter_fn(): break population.speciate() data = population.to_dict() mutator(population) ds.save(data) print_progress(data) return True
def curry_genome_seeder(mutator, seed_genomes=None): """Construct genome generator. Given a mutator and a collection of initial genomes builds a function that can then return as many as needed. Used for populating Population Objects. :param mutator: defined Mutator object that acts on genomes. :param seed_genomes: list of genomes that will be copied and mutated. :return: Generator function that takes a value n and returns n genomes generated by sampling the seed_genome list, copying and mutating. :raises ValueError: mutator param must be of type Mutator. """ if not seed_genomes: seed_genomes = [minimal()] if not issubclass(type(mutator), Mutator): raise ValueError('Mutator param must be of type Mutator') 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 return genome_seeder
def neat_cart_pole(): pop_size = 1000 mutator = NEATMutator(new_edge_probability=0.1, new_node_probability=0.05) seed_genome = minimal(input_size=4, output_size=1, depth=5) seeder = curry_genome_seeder(mutator=mutator, seed_genomes=[seed_genome]) metric = generate_neat_metric(c_1=1, c_2=1, c_3=3) population = NEATPopulation(population_size=pop_size, genome_seeder=seeder, delta=4, metric=metric) assign_population_fitness = build_env() counter_fn = make_counter_fn() for i in range(5): success = assign_population_fitness(population) if success and counter_fn(): break population.speciate() data = population.to_dict() print_progress(data) mutator(population) score = run_env(data['best_genome'], env_name='CartPole-v0', render=True) print(f'best_fitness: {score}') return True
def simple_simple_example(): genome = minimal( input_size=1, output_size=1 ) weights_len = len(genome.edges) + len(genome.nodes) init_mu = np.random.uniform(-3, 3, weights_len) mutator = SIMPLEMutator( std_dev=0.01, survival_rate=0.01 ) seeder = curry_genome_seeder( mutator=mutator, seed_genomes=[genome] ) population = SIMPLEPopulation( population_size=1000, genome_seeder=seeder ) target_mu = np.random.uniform(-3, 3, len(init_mu)) assign_population_fitness = build_simple_env(target_mu) for i in range(100): assign_population_fitness(population) mutator(population) weights = np.array([genome.weights for genome in population.genomes]) mu = weights.mean(axis=0) loss = np.linalg.norm(mu - target_mu) print(f'generation: {i}, loss: {loss}')
def genome_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]) 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]) n6 = g1.add_node(3) g1.add_edge(g1.layers[0][0], n6) g1.add_edge(n6, g1.outputs[1]) for w, edge in zip(weight_gen, g1.edges): edge.weight = w for w, node in zip(bias_gen, g1.nodes): node.weight = w return g1
def test_edge_copy(self): g1 = minimal(input_size=1, output_size=1, depth=1) g2 = minimal(input_size=1, output_size=1, depth=1) n = g1.add_node(1) g2.add_node(1) e1 = g1.add_edge(g1.layers[0][0], n) g1.add_edge(n, g1.layers[2][0]) mutation_rate = 0.1 ne = Edge.copy(e1, g2) self.assertNotEqual(ne, e1) self.assertEqual(ne.innov, e1.innov) self.assertLess(abs(ne.weight - e1.weight), mutation_rate)
def test_edge_copy_err(self): # Test copy edge throws correct error if node doesn't exist on # new_genome. g1 = minimal(input_size=1, output_size=1, depth=1) g2 = minimal(input_size=1, output_size=1, depth=1) n = g1.add_node(1) e1 = g1.add_edge(g1.layers[0][0], n) g1.add_edge(n, g1.layers[2][0]) with self.assertRaises(Exception) as context: Edge.copy(e1, g2) err_msg = 'to_node does not exist on new_genome.' self.assertTrue(err_msg == str(context.exception))
def test_update_weights(self): g = minimal(input_size=2, output_size=3, depth=5) update_vector = [random() for _ in range(len(g.edges) + len(g.nodes))] g.weights = update_vector updated_weights = [ target.weight for target in itertools.chain(g.nodes, g.edges) ] self.assertEqual(update_vector, updated_weights)
def test_add_edge_mutation(self): g = minimal(input_size=2, output_size=3, depth=5) num_of_nodes = len(g.nodes) num_of_edges = len(g.edges) greatest_edge_innov = sorted(g.edges, key=lambda n: n.innov)[-1].innov add_edge(g) self.assertEqual(len(g.nodes), num_of_nodes) self.assertEqual(len(g.edges), num_of_edges + 1) new_edge = sorted(g.edges, key=lambda n: n.innov)[-1] self.assertEqual(new_edge.innov, greatest_edge_innov + 1) self.assertGreater(new_edge.to_node.layer_num, new_edge.from_node.layer_num)
def test_add_node_mutation(self): g = minimal(input_size=2, output_size=3, depth=5) num_of_nodes = len(g.nodes) num_of_edges = len(g.edges) add_node(g) self.assertEqual(len(g.nodes), num_of_nodes + 1) self.assertEqual(len(g.edges), num_of_edges + 2) old_edge = [e for e in g.edges if not e.active][0] new_node = sorted(g.nodes, key=lambda n: n.innov)[-1] self.assertEqual(new_node.edges_in[0].from_node.layer_num, old_edge.from_node.layer_num) self.assertEqual(new_node.edges_out[0].to_node.layer_num, old_edge.to_node.layer_num)
def setup_simple_res_env(mutator_type=None): genome = minimal(input_size=1, output_size=1) weights_len = len(genome.edges) + len(genome.nodes) init_mu = np.random.uniform(-3, 3, weights_len) if mutator_type == RESMutator: mutator = mutator_type(initial_mu=init_mu, std_dev=0.1, alpha=1) elif mutator_type == ADRESMutator: mutator = mutator_type(initial_mu=init_mu, std_dev=0.1) else: mutator = SIMPLEMutator(std_dev=0.01, survival_rate=0.1) seeder = curry_genome_seeder(mutator=mutator, seed_genomes=[genome]) population = RESPopulation(population_size=1000, genome_seeder=seeder) return population, mutator, init_mu
def test_get_addmissable_edges(self): g = minimal(input_size=2, output_size=3, depth=5) n2 = g.add_node(3) g.add_edge(g.layers[0][0], n2) g.add_edge(n2, g.outputs[0]) self.assertEqual(len(g.layer_edges_in(3)), 1) self.assertEqual(len(g.layer_edges_out(3)), 1) for layer_num in [2, 4, 5]: self.assertEqual(len(g.layer_edges_in(layer_num)), 0) self.assertEqual(len(g.layer_edges_out(layer_num)), 0) self.assertEqual(len(g.get_admissible_edges()), 5) addmissable = lambda e: e.to_node.layer_num - e.from_node.layer_num > 1 for e in g.get_admissible_edges(): self.assertEqual(addmissable(e), True)
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 test_minimal_factory(self): g = minimal(input_size=2, output_size=3, depth=5) # Check correct nodes self.assertEqual(len(g.inputs), 2) self.assertEqual(len(g.nodes), 1) self.assertEqual(len(g.outputs), 3) for node in g.inputs: self.assertEqual(node.layer_num, 0) for node in g.outputs: self.assertEqual(node.layer_num, len(g.layers) - 1) self.assertEqual(len(g.layers), 7) # check central connecting node edges self.assertEqual( g.layer_edges_in(layer_num=6), g.layer_edges_out(layer_num=1) ) self.assertEqual( g.layer_edges_in(layer_num=1), g.layer_edges_out(layer_num=0) )
def neat_xor_example(): pop_size = 150 mutator = NEATMutator( new_edge_probability=0.1, new_node_probability=0.05 ) seed_genome = minimal( input_size=2, output_size=1, depth=3 ) seeder = curry_genome_seeder( mutator=mutator, seed_genomes=[seed_genome] ) metric = generate_neat_metric() population = NEATPopulation( population_size=pop_size, delta=3, genome_seeder=seeder, metric=metric ) def xor(a, b): return bool(a) != bool(b) def generate_data(n): data = [ [[True, True], xor(True, True)], [[True, False], xor(True, False)], [[False, True], xor(False, True)], [[False, False], xor(False, False)] ] for i in range(n): yield data[i % 4] sln_count = 0 best_fitness = None for _ in tqdm(range(1000)): for genome in population.genomes: fitness = 0 best_fitness = 0 model = Model(genome.to_reduced_repr) for inputs, output in generate_data(4): pred = model(inputs)[0] pred = pred > 0 fitness += pred == output if fitness > best_fitness: best_fitness = fitness genome.fitness = fitness/4 if best_fitness == 4: sln_count += 1 if sln_count == 10: break population.speciate() mutator(population) fitness_scores = [] best_genome = None best_fitness = 0 for genome in population.genomes: fitness = 0 model = Model(genome.to_reduced_repr) for inputs, output in generate_data(4): pred = model(inputs)[0] pred = pred > 0 fitness += pred == output fitness = fitness / 4 if fitness > best_fitness: best_fitness = fitness best_genome = genome fitness_scores.append(fitness) print() print('best_fitness:', best_fitness) print_population(population) print_genome(best_genome) return True
def test_update_weights_error(self): g = minimal(input_size=2, output_size=3, depth=5) with self.assertRaises(DimensionMismatchError): g.weights = [0 for _ in range(len(g.edges) + len(g.nodes) - 1)]