def test_create_initial_generation(self): config = NeatConfig(population_size=150, connection_max_weight=10, connection_min_weight=-10) generation1 = gs.create_initial_generation( 10, 3, step_activation, InnovationNumberGeneratorSingleCore(), SpeciesIDGeneratorSingleCore(), AgentIDGeneratorSingleCore(), config, seed=1) generation2 = gs.create_initial_generation( 10, 3, step_activation, InnovationNumberGeneratorSingleCore(), SpeciesIDGeneratorSingleCore(), AgentIDGeneratorSingleCore(), config, seed=1) self.assertEqual(0, generation1.number) self.assertEqual(0, generation2.number) self.assertEqual(150, len(generation1.agents)) # Compare if generations and generated genomes are the same for agent1, agent2 in zip(generation1.agents, generation2.agents): self.assertEqual(agent1.genome.seed, agent2.genome.seed) for node1, node2, i in zip(agent1.genome.nodes, agent2.genome.nodes, range(len(agent1.genome.nodes))): self.assertEqual(node1.innovation_number, node2.innovation_number) self.assertEqual(i, node1.innovation_number) self.assertEqual(node1.bias, node2.bias) if node1.node_type != NodeType.INPUT: self.assertNotAlmostEqual(0, node1.bias, delta=0.000000000001) # Check connection weights for connection1, connection2, i in zip( agent1.genome.connections, agent2.genome.connections, range(len(agent1.genome.connections))): self.assertEqual(connection1.weight, connection2.weight) self.assertEqual(connection1.innovation_number, connection2.innovation_number) self.assertEqual(i, connection1.innovation_number) self.assertNotAlmostEqual(0, connection1.weight, delta=0.000000000001)
def test_create_offspring_pairs(self): agent_id_generator = AgentIDGeneratorSingleCore() config = NeatConfig() rnd = np.random.RandomState(1) # First 10 random values # rnd.randint(3) = 1 # rnd.randint(3) = 0 # rnd.randint(3) = 0 # rnd.randint(3) = 1 # rnd.randint(3) = 1 # rnd.randint(3) = 0 # rnd.randint(3) = 0 # rnd.randint(3) = 1 tuple_list = ss.create_offspring_pairs(self.species1, 4, agent_id_generator, self.generation, rnd, config) # Test tuples agent_id_generator = AgentIDGeneratorSingleCore() self.assertEqual(4, len(tuple_list)) self.assertEqual((self.agent2.id, self.agent1.id, agent_id_generator.get_agent_id()), tuple_list[0]) self.assertEqual((self.agent1.id, self.agent2.id, agent_id_generator.get_agent_id()), tuple_list[1]) self.assertEqual((self.agent2.id, self.agent1.id, agent_id_generator.get_agent_id()), tuple_list[2]) self.assertEqual((self.agent1.id, self.agent2.id, agent_id_generator.get_agent_id()), tuple_list[3])
def evaluate(self, amount_input_nodes: int, amount_output_nodes, activation_function, challenge: Challenge, config: NeatConfig, seed: int) -> None: assert self.callback is not None # Initialize Parameters innovation_number_generator = InnovationNumberGeneratorSingleCore() species_id_generator = SpeciesIDGeneratorSingleCore() agent_id_generator = AgentIDGeneratorSingleCore() # Notify callback about starting evaluation self._notify_reporters_callback(lambda r: r.on_initialization()) # Prepare challenge challenge.initialization() initial_generation = gs.create_initial_generation(amount_input_nodes, amount_output_nodes, activation_function, innovation_number_generator, species_id_generator, agent_id_generator, config, seed) finished_generation = self._evaluation_loop(initial_generation, challenge, innovation_number_generator, species_id_generator, agent_id_generator, config) # Finish the evaluation and notify the callback self._cleanup(challenge) self._notify_reporters_callback(lambda r: r.on_finish(finished_generation, self.reporters))
def _run_master(self, amount_input_nodes: int, amount_output_nodes, activation_function, challenge: Challenge, config: NeatConfig, seed: int): logger.info("Maser - Name: {}, Size: {}, Rank {}/{}", self.name, self.size, self.rank, self.size - 1) logger.info("Waiting for workers to start...") with MPIPoolExecutor() as self.executor: self.executor.bootup(wait=True) logger.info("All Workers should have started") # Initialize Parameters innovation_number_generator = InnovationNumberGeneratorSingleCore() species_id_generator = SpeciesIDGeneratorSingleCore() agent_id_generator = AgentIDGeneratorSingleCore() # Notify callback about starting evaluation self._notify_reporters_callback(lambda r: r.on_initialization()) initial_generation = gs.create_initial_generation( amount_input_nodes, amount_output_nodes, activation_function, innovation_number_generator, species_id_generator, agent_id_generator, config, seed) finished_generation = self._evaluation_loop( initial_generation, challenge, innovation_number_generator, species_id_generator, agent_id_generator, config) self._notify_reporters_callback( lambda r: r.on_finish(finished_generation, self.reporters))
def test_evaluate_generation(self): generation = gs.create_initial_generation( 2, 1, step_activation, InnovationNumberGeneratorSingleCore(), SpeciesIDGeneratorSingleCore(), AgentIDGeneratorSingleCore(), self.config, 1) self.optimizer_single._evaluate_generation(generation, self.challenge) # Check challenge self.assertEqual(self.config.population_size, self.challenge.before_evaluation_count) self.assertEqual(self.config.population_size, self.challenge.evaluate_count) self.assertEqual(self.config.population_size, self.challenge.after_evaluation_count) # Check callback self.assertEqual(1, self.callback.on_generation_evaluation_start_count) self.assertEqual(self.config.population_size, self.callback.on_agent_evaluation_start_count) self.assertEqual(self.config.population_size, self.callback.on_agent_evaluation_end_count) self.assertEqual(1, self.callback.on_generation_evaluation_end_count) for expected_fitness, agent in zip(range(self.config.population_size), generation.agents): self.assertEqual(expected_fitness, agent.fitness)
def setUp(self) -> None: self.config = NeatConfig(population_size=10) self.generation = gs.create_initial_generation( 3, 2, step_activation, InnovationNumberGeneratorSingleCore(), SpeciesIDGeneratorSingleCore(), AgentIDGeneratorSingleCore(), self.config, 1) for i, agent in zip(range(len(self.generation.agents)), self.generation.agents): agent.fitness = i
def setUp(self) -> None: self.config = NeatConfig(population_size=7) self.inno_num_generator = InnovationNumberGeneratorSingleCore() self.species_id_generator = SpeciesIDGeneratorSingleCore() self.agent_id_generator = AgentIDGeneratorSingleCore() self.genome1 = gs.create_genome_structure(2, 1, step_activation, self.config, self.inno_num_generator) self.genome2 = gs.create_genome_structure(2, 1, step_activation, self.config, self.inno_num_generator) self.genome3 = gs.create_genome_structure(2, 1, step_activation, self.config, self.inno_num_generator) self.genome4 = gs.create_genome_structure(2, 1, step_activation, self.config, self.inno_num_generator) self.genome5 = gs.create_genome_structure(2, 1, step_activation, self.config, self.inno_num_generator) self.genome6 = gs.create_genome_structure(2, 1, step_activation, self.config, self.inno_num_generator) self.genome7 = gs.create_genome_structure(2, 1, step_activation, self.config, self.inno_num_generator) self.agent1 = Agent(1, self.genome1) self.agent1.fitness = 1 self.agent2 = Agent(2, self.genome2) self.agent2.fitness = 2 self.agent3 = Agent(3, self.genome3) self.agent3.fitness = 3 self.agent4 = Agent(4, self.genome4) self.agent4.fitness = 4 self.agent5 = Agent(5, self.genome5) self.agent5.fitness = 5 self.agent6 = Agent(6, self.genome6) self.agent6.fitness = 6 self.agent7 = Agent(7, self.genome7) self.agent7.fitness = 7 self.species1 = Species( self.species_id_generator.get_species_id(), self.agent1.genome, [self.agent1, self.agent1, self.agent2, self.agent3]) self.species2 = Species(self.species_id_generator.get_species_id(), self.agent4.genome, [self.agent4, self.agent5]) self.species3 = Species(self.species_id_generator.get_species_id(), self.agent6.genome, [self.agent6, self.agent7])
def test_create_initial_generation_genome(self): genome = Genome(20, [ Node("abc", NodeType.INPUT, 0.3, step_activation, 0), Node("def", NodeType.OUTPUT, 0.4, step_activation, 1) ], [ Connection("x", "abc", "def", 1.0, True), Connection("y", "def", "abc", -5, True) ]) generation = gs.create_initial_generation_genome( genome, InnovationNumberGeneratorSingleCore(), SpeciesIDGeneratorSingleCore(), AgentIDGeneratorSingleCore(), NeatConfig(population_size=3), seed=1) self.assertEqual(3, len(generation.agents)) self.assertEqual(0, generation.number) self.assertEqual(1, len(generation.species_list)) self.assertEqual(3, len(generation.species_list[0].members)) self.assertEqual(1, generation.seed) # First three random numbers # 1 - 12710949 # 2 - 4686059 # 3 - 6762380 self.assertEqual(12710949, generation.agents[0].genome.seed) self.assertEqual(4686059, generation.agents[1].genome.seed) self.assertEqual(6762380, generation.agents[2].genome.seed) for node1, node2, node3, i in zip(generation.agents[0].genome.nodes, generation.agents[1].genome.nodes, generation.agents[2].genome.nodes, range(3)): self.assertEqual(node1.innovation_number, node2.innovation_number) self.assertEqual(node2.innovation_number, node3.innovation_number) self.assertEqual(node3.innovation_number, i) for connection1, connection2, connection3, i in zip( generation.agents[0].genome.connections, generation.agents[1].genome.connections, generation.agents[2].genome.connections, range(3)): self.assertEqual(connection1.innovation_number, connection2.innovation_number) self.assertEqual(connection2.innovation_number, connection3.innovation_number) self.assertEqual(connection3.innovation_number, i)
def test_evaluation_loop(self): inno_generator = InnovationNumberGeneratorSingleCore() species_id_generator = SpeciesIDGeneratorSingleCore() agent_id_generator = AgentIDGeneratorSingleCore() initial_generation = gs.create_initial_generation( 2, 1, step_activation, inno_generator, species_id_generator, agent_id_generator, self.config, 1) final_generation = self.optimizer_single._evaluation_loop( initial_generation, self.challenge, inno_generator, species_id_generator, agent_id_generator, self.config) expected_generation_number = 10 self.assertEqual(expected_generation_number, final_generation.number) self.assertEqual(self.config.population_size, len(final_generation.agents)) # Check genome fitness for i, agent in zip(range(len(final_generation.agents)), final_generation.agents): self.assertEqual( expected_generation_number * self.config.population_size + i, agent.fitness) # Check challenge calls self.assertEqual( (1 + expected_generation_number) * self.config.population_size, self.challenge.before_evaluation_count) self.assertEqual( (1 + expected_generation_number) * self.config.population_size, self.challenge.evaluate_count) self.assertEqual( (1 + expected_generation_number) * self.config.population_size, self.challenge.after_evaluation_count) # Check callback calls self.assertEqual(expected_generation_number + 1, self.callback.on_generation_evaluation_start_count) self.assertEqual( (1 + expected_generation_number) * self.config.population_size, self.callback.on_agent_evaluation_start_count) self.assertEqual( (1 + expected_generation_number) * self.config.population_size, self.callback.on_agent_evaluation_end_count) self.assertEqual(expected_generation_number + 1, self.callback.on_generation_evaluation_end_count)
def test_build_generation_from_genome(self): initial_genome = Genome(20, [ Node(1, NodeType.INPUT, 0, step_activation, 0), Node(2, NodeType.OUTPUT, 0.4, step_activation, 1) ], [Connection(1, 1, 2, 1.0, True), Connection(2, 1, 2, -5, True)]) rnd = np.random.RandomState(1) generation = gs._build_generation_from_genome( initial_genome, SpeciesIDGeneratorSingleCore(), AgentIDGeneratorSingleCore(), 19, rnd, NeatConfig(population_size=3)) self.assertEqual(3, len(generation.agents)) self.assertEqual(0, generation.number) self.assertEqual(1, len(generation.species_list)) self.assertEqual(3, len(generation.species_list[0].members)) self.assertEqual(19, generation.seed) # First three random numbers # 1 - 12710949 # 2 - 4686059 # 3 - 6762380 self.assertEqual(12710949, generation.agents[0].genome.seed) self.assertEqual(4686059, generation.agents[1].genome.seed) self.assertEqual(6762380, generation.agents[2].genome.seed) # Check if every weight and bias is not equal to 0 for agent, i in zip(generation.agents, range(len(generation.agents))): genome = agent.genome self.assertEqual(i, agent.id) for node in genome.nodes: # Input nodes can have bias 0 if node.node_type == NodeType.INPUT: continue self.assertNotAlmostEqual(0, node.bias, delta=0.00000000001) for conn in genome.connections: self.assertNotAlmostEqual(0, conn.weight, delta=0.00000000001)
def _build_new_generation(self, generation: Generation, innovation_number_generator: InnovationNumberGeneratorInterface, species_id_generator: SpeciesIDGeneratorSingleCore, agent_id_generator: AgentIDGeneratorSingleCore, config: NeatConfig) -> Generation: # Notify callback self._notify_reporters_callback(lambda r: r.on_reproduction_start(generation)) # Get the random generator for the new generation new_generation_seed = np.random.RandomState(generation.seed).randint(2 ** 24) rnd = np.random.RandomState(new_generation_seed) # Get the best agents, which will be copied later best_agents_genomes = gs.get_best_genomes_from_species(generation.species_list, config.species_size_copy_best_genome) # Get allowed species for reproduction generation = ss.update_fitness_species(generation) species_list = ss.get_allowed_species_for_reproduction(generation, config.species_stagnant_after_generations) # TODO handle error no species if len(species_list) <= 5: species_list = generation.species_list # assert len(species_list) >= 1 # Calculate the adjusted fitness values min_fitness = min([a.fitness for a in generation.agents]) max_fitness = max([a.fitness for a in generation.agents]) species_list = ss.calculate_adjusted_fitness(species_list, min_fitness, max_fitness) # Remove the low performing genomes species_list = ss.remove_low_genomes(species_list, config.percentage_remove_low_genomes) # Calculate offspring for species off_spring_list = ss.calculate_amount_offspring(species_list, config.population_size - len(best_agents_genomes)) # Calculate off spring combinations off_spring_pairs = [] for species, amount_offspring in zip(species_list, off_spring_list): off_spring_pairs += ss.create_offspring_pairs(species, amount_offspring, agent_id_generator, generation, rnd, config) # Notify innovation number generator, that a new generation is created innovation_number_generator.next_generation(generation.number) # Create a dictionary for easy access agent_dict = {agent.id: agent for agent in generation.agents} # Create new agents - fill initially with best agents new_agents = [Agent(agent_id_generator.get_agent_id(), genome) for genome in best_agents_genomes] # Create agents with crossover self._notify_reporters_callback(lambda r: r.on_compose_offsprings_start()) for parent1_id, parent2_id, child_id in off_spring_pairs: parent1 = agent_dict[parent1_id] parent2 = agent_dict[parent2_id] child_seed = (parent1.genome.seed + parent2.genome.seed) % 2 ** 24 rnd_child = np.random.RandomState(child_seed) # Perform crossover for to get the nodes and connections for the child if parent1.fitness > parent2.fitness: child_nodes, child_connections = rp.cross_over(parent1.genome, parent2.genome, rnd_child, config) else: child_nodes, child_connections = rp.cross_over(parent2.genome, parent1.genome, rnd_child, config) # Create child genome child_genome = Genome(child_seed, child_nodes, child_connections) # Mutate genome child_genome = rp.mutate_weights(child_genome, rnd_child, config) child_genome, _, _, _ = rp.mutate_add_node(child_genome, rnd_child, innovation_number_generator, config) child_genome, _ = rp.mutate_add_connection(child_genome, rnd_child, innovation_number_generator, config) child_agent = Agent(child_id, child_genome) new_agents.append(child_agent) # Notify callback end self._notify_reporters_callback(lambda r: r.on_compose_offsprings_end()) # TODO convert back # Select new representative existing_species = [ss.select_new_representative(species, rnd) for species in generation.species_list] # Reset members and fitness existing_species = [ss.reset_species(species) for species in existing_species] # existing_species = [ss.reset_species(species) for species in generation.species_list] # Sort members into species new_species_list = ss.sort_agents_into_species(existing_species, new_agents, species_id_generator, config) logger.info("Species IDs: {}".format([s.id_ for s in new_species_list])) logger.info("Species Mem: {}".format([len(s.members) for s in new_species_list])) # Filter out empty species new_species_list = ss.get_species_with_members(new_species_list) # Create new generation, notify callback and return new generation new_generation = Generation(generation.number + 1, new_generation_seed, new_agents, new_species_list) self._notify_reporters_callback(lambda r: r.on_reproduction_end(new_generation)) return new_generation