def test_crossover(self): genome1 = Genome(self.genome_params) genome2 = Genome(self.genome_params) genome1.connect() genome2.connect() genome1.fitness = 5 genome2.fitness = 20 genome2.mutate() assert len(genome2.nodes) == 4 assert len(genome2.connection_genes) == 4 assert genome2.connection_genes[3].innovation_number == 4 disabled_gene = None for idx, cg in enumerate(genome2.connection_genes): if not cg.enabled: disabled_gene = idx break child = genome2.crossover(genome1, genome2) # child inherited fittest parent nodes assert len(child.nodes) == len(genome2.nodes) # should be of same length despite some being disjoint genes assert len(child.connection_genes) == len(genome2.connection_genes) # check child got disabled gene transferred assert not child.connection_genes[disabled_gene].enabled
def test_mate(self): Genome.reset() genome1 = Genome() genome2 = Genome() new_genome = Genome() genes1 = [] genes2 = [] genome1.allocate_hidden_nodes(1) genome2.allocate_hidden_nodes(1) new_genome.allocate_hidden_nodes(1) #genome 1 input_node_id_11 = genome1.add_input_node() input_node_id_21 = genome1.add_input_node() hidden_node_id_11 = genome1.add_hidden_node() output_node_id_11 = genome1.add_output_node() output_node_id_21 = genome1.add_output_node() genes1.append(Gene(input_node_id_11, hidden_node_id_11, weight = 10.0)) genes1.append(Gene(input_node_id_21, hidden_node_id_11)) genes1.append(Gene(hidden_node_id_11, output_node_id_11)) genes1.append(Gene(hidden_node_id_11, output_node_id_21)) genome1.set_genes((genes1)) #genome 2 input_node_id_12 = genome2.add_input_node() input_node_id_22 = genome2.add_input_node() hidden_node_id_12 = genome2.add_hidden_node() output_node_id_12 = genome2.add_output_node() output_node_id_22 = genome2.add_output_node() genes2.append(Gene(input_node_id_12, hidden_node_id_12, weight = 20.0)) genes2.append(Gene(input_node_id_22, hidden_node_id_12)) genes2.append(Gene(hidden_node_id_12, output_node_id_12)) genes2.append(Gene(hidden_node_id_12, output_node_id_22, enabled = False)) genome2.set_genes((genes2)) genome2.allocate_genes(1) genome2.add_new_connection(input_node_id_12, output_node_id_12) #new genome Genome.mate(genome1, genome2, new_genome) self.assertEqual(new_genome.genes[0].weight, 15.0) self.assertEqual(len(new_genome.genes), 5) self.assertFalse(new_genome.genes[3].enabled)
def generate_genome_with_hidden_units(n_input, n_output, n_hidden=3): # nodes node_genes = {} for i in range(n_output + n_hidden): node_genes = add_node(node_genes, key=i) # connections # input to hidden connection_genes = {} input_hidden_tuples = list( product(list(range(-1, -n_input - 1, -1)), list(range(n_output, n_output + n_hidden)))) for tuple_ in input_hidden_tuples: connection_genes = add_connection(connection_genes, key=tuple_) # hidden to output hidden_output_tuples = list( product(list(range(n_output, n_output + n_hidden)), list(range(0, n_output)))) for tuple_ in hidden_output_tuples: connection_genes = add_connection(connection_genes, key=tuple_) # initialize genome genome = Genome(key=1) genome.node_genes = node_genes genome.connection_genes = connection_genes return genome
def test_add_node(self): Genome.reset() genome = Genome() genome.allocate_hidden_nodes(3) input_node_id_1 = genome.add_input_node() input_node_id_2 = genome.add_input_node() hidden_node_id_1 = genome.add_hidden_node() hidden_node_id_2 = genome.add_hidden_node() hidden_node_id_3 = genome.add_hidden_node() output_node_id_1 = genome.add_output_node() output_node_id_2 = genome.add_output_node() #Inserted check self.assertTrue(input_node_id_1 in range(len(genome.nodes))) self.assertTrue(input_node_id_2 in range(len(genome.nodes))) self.assertTrue(hidden_node_id_1 in range(len(genome.nodes))) self.assertTrue(hidden_node_id_2 in range(len(genome.nodes))) self.assertTrue(hidden_node_id_3 in range(len(genome.nodes))) self.assertTrue(output_node_id_1 in range(len(genome.nodes))) self.assertTrue(output_node_id_2 in range(len(genome.nodes))) #Added to output ndoes check self.assertFalse(input_node_id_1 in genome.output_nodes_ids) self.assertFalse(input_node_id_2 in genome.output_nodes_ids) self.assertFalse(hidden_node_id_1 in genome.output_nodes_ids) self.assertFalse(hidden_node_id_2 in genome.output_nodes_ids) self.assertFalse(hidden_node_id_3 in genome.output_nodes_ids) self.assertTrue(output_node_id_1 in genome.output_nodes_ids) self.assertTrue(output_node_id_2 in genome.output_nodes_ids) #Type set check self.assertEqual(genome.nodes[input_node_id_1].type, Type.INPUT) self.assertEqual(genome.nodes[input_node_id_2].type, Type.INPUT) self.assertEqual(genome.nodes[hidden_node_id_1].type, Type.HIDDEN) self.assertEqual(genome.nodes[hidden_node_id_2].type, Type.HIDDEN) self.assertEqual(genome.nodes[hidden_node_id_3].type, Type.HIDDEN) self.assertEqual(genome.nodes[output_node_id_1].type, Type.OUTPUT) self.assertEqual(genome.nodes[output_node_id_2].type, Type.OUTPUT) #ID set check self.assertEqual(genome.nodes[input_node_id_1].id, input_node_id_1) self.assertEqual(genome.nodes[input_node_id_2].id, input_node_id_2) self.assertEqual(genome.nodes[hidden_node_id_1].id, hidden_node_id_1) self.assertEqual(genome.nodes[hidden_node_id_2].id, hidden_node_id_2) self.assertEqual(genome.nodes[hidden_node_id_3].id, hidden_node_id_3) self.assertEqual(genome.nodes[output_node_id_1].id, output_node_id_1) self.assertEqual(genome.nodes[output_node_id_2].id, output_node_id_2)
def initialze_network(self, **kwargs): number_hidden_nodes = kwargs['number_hidden_nodes'] number_genes = kwargs['number_genes'] new_weight_range = kwargs['new_weight_range'] genome = Genome() genes = [] genome.allocate_hidden_nodes(number_hidden_nodes) self.input_node1 = genome.add_input_node() self.input_node2 = genome.add_input_node() self.output_node = genome.add_output_node() genes.append( Gene(0, self.output_node, new_weight_range - 2 * new_weight_range * random.random())) genes.append( Gene(self.input_node1, self.output_node, new_weight_range - 2 * new_weight_range * random.random())) genes.append( Gene(self.input_node2, self.output_node, new_weight_range - 2 * new_weight_range * random.random())) genome.set_genes(genes) genome.allocate_genes(number_genes) return Network(genome)
def fully_connected_nn(n_inputs, n_outputs): """Generate a genotype representing a fully connected neural network. Arguments: n_inputs: How many inputs the network should have. n_outputs: How many outputs the network should have. Returns: The generated genotype. """ genome = Genome() sensors = [NodeGene(Sensor()) for _ in range(n_inputs)] outputs = [NodeGene(Output()) for _ in range(n_outputs)] connections = [] for input_id in range(n_inputs): for output_id in range(n_inputs, n_inputs + n_outputs): connections.append(ConnectionGene(output_id, input_id)) genome.add_genes(sensors) genome.add_genes(outputs) genome.add_genes(connections) return genome
def test_regression_case(self): config = create_configuration(filename='/regression-siso.json') config.parallel_evaluation = False genome = Genome(key=1) genome.create_random_genome() dataset = get_dataset(config.dataset, train_percentage=config.train_percentage, testing=True) n_samples = 3 network = ComplexStochasticNetwork(genome=genome) x, y_true, output_distribution = calculate_prediction_distribution( network, dataset=dataset, problem_type=config.problem_type, is_testing=True, n_samples=n_samples, use_sigmoid=False) expected_output_distribution_shape = [ len(y_true), n_samples, config.n_output ] self.assertEqual(list(output_distribution.shape), expected_output_distribution_shape)
def _breed(parents): # create a new child with topology size at least as big as either parents child = Genome(parents[0].x_dim, parents[0].y_dim, random_weights=False) child.h_dim = max(parents[0].h_dim, parents[1].h_dim) # if both parents have h_dim = 1, then randomly mix weights # otherwise, breed them by crossover if parents[0].h_dim == 1 and parents[1].h_dim == 1: w1 = mix_weights(parents[0].w1, parents[1].w1) w2 = mix_weights(parents[0].w2, parents[1].w2) else: if parents[0].h_dim < parents[1].h_dim: small_genome = parents[0] large_genome = parents[1] else: small_genome = parents[1] large_genome = parents[0] slice_idx = np.random.randint(1, small_genome.h_dim + 1) w1 = np.vstack( [small_genome.w1[:slice_idx], large_genome.w1[slice_idx:]]) w2 = np.hstack( [small_genome.w2[:, :slice_idx], large_genome.w2[:, slice_idx:]]) child.w1 = w1 child.w2 = w2 child.genome_type = "bred" return child
def test_genome_only_links_to_valid_nodes(self): link_tester = [LinkGene(0, 3), LinkGene(1, 3), LinkGene(2, 4), LinkGene(0, 5)] try: genome = Genome(self.config, node_genes=self.test_node_genes, link_genes=link_tester) self.fail("Genome should raise exception if link connects to non-existing node") except ValueError: pass
def test_genome_doesnt_create_inputs_as_sinks(self): link_tester = [LinkGene(0, 1), LinkGene(3, 2), LinkGene(2, 4)] try: genome = Genome(self.config, node_genes=self.test_node_genes, link_genes=link_tester) self.fail("Genome should raise exception if input is sink") except ValueError: pass
def test_genome_doesnt_create_duplicate_links(self): link_tester = [LinkGene(0, 3), LinkGene(1, 3), LinkGene(2, 4)] try: genome = Genome(self.config, node_genes=self.test_node_genes, link_genes=link_tester) self.fail("Genome should raise exception if duplicate links exist") except AssertionError: pass
def get_offspring(self, offspring_key, genome1: Genome, genome2: Genome): assert isinstance(genome1.fitness, (int, float)) assert isinstance(genome2.fitness, (int, float)) if genome1.fitness > genome2.fitness: parent1, parent2 = genome1, genome2 else: parent1, parent2 = genome2, genome1 offspring = Genome(key=offspring_key) # Inherit connection genes for key, cg1 in parent1.connection_genes.items(): cg2 = parent2.connection_genes.get(key) if cg2 is None: # Excess or disjoint gene: copy from the fittest parent. logger.debug('Use connection copy') offspring.connection_genes[key] = cg1.copy() else: # Homologous gene: combine genes from both parents. offspring.connection_genes[ key] = self._get_connection_crossover(cg1, cg2) # Inherit node genes for key, ng1 in parent1.node_genes.items(): ng2 = parent2.node_genes.get(key) assert key not in offspring.node_genes if ng2 is None: # Extra gene: copy from the fittest parent logger.debug('Use node copy') offspring.node_genes[key] = ng1.copy() else: # Homologous gene: combine genes from both parents. offspring.node_genes[key] = self._get_node_crossover(ng1, ng2) return offspring
def test_add_gene(self): Genome.reset() genome = Genome() genes = [] genome.allocate_hidden_nodes(1) input_node_id_1 = genome.add_input_node() input_node_id_2 = genome.add_input_node() hidden_node_id_1 = genome.add_hidden_node() output_node_id_1 = genome.add_output_node() output_node_id_2 = genome.add_output_node() genes.append(Gene(input_node_id_1, hidden_node_id_1)) genes.append(Gene(input_node_id_2, hidden_node_id_1)) genes.append(Gene(hidden_node_id_1, output_node_id_1)) genes.append(Gene(hidden_node_id_1, output_node_id_2)) genome.set_genes((genes)) gene = Gene(input_node_id_1, output_node_id_1) genome.add_gene(gene) self.assertEqual(genome.nodes[output_node_id_1].connected_nodes[1], genome.nodes[input_node_id_1])
def generate_genome_given_graph(graph, connection_weights): genome = Genome(key='foo') unique_node_keys = [] input_nodes = [] for connection in graph: for node_key in connection: if node_key not in unique_node_keys: unique_node_keys.append(node_key) if node_key < 0: input_nodes.append(node_key) input_nodes = set(input_nodes) unique_node_keys = list( set(unique_node_keys + genome.get_output_nodes_keys()) - input_nodes) nodes = {} for node_key in unique_node_keys: node = NodeGene(key=node_key).random_initialization() node.set_mean(0) node.set_std(STD) nodes[node_key] = node connections = {} for connection_key, weight in zip(graph, connection_weights): connection = ConnectionGene(key=connection_key) connection.set_mean(weight) connection.set_std(STD) connections[connection_key] = connection genome.connection_genes = connections genome.node_genes = nodes return genome
def test_genome_does_not_allow_duplicate_node_indices(self): print(len(self.test_node_genes)) self.test_node_genes[0].idx = 1 self.test_node_genes[1].idx = 1 try: genome = Genome(self.config, node_genes=self.test_node_genes) except AssertionError: pass
def test_genome_needs_right_number_output_genes(self): try: self.config.num_outputs = 3 genome = Genome(self.config, node_genes=self.test_node_genes) self.config.num_outputs = 2 self.fail("Should raise exception if n_outputs does not match number of output genes") except AssertionError: pass
def test_mutate_delete_connection(self): genome = Genome(key='foo').create_random_genome() possible_connections_to_delete = \ set(ArchitectureMutation._calculate_possible_connections_to_delete(genome=genome)) expected_possible_connections_to_delete = {(-1, 0), (-2, 0)} self.assertSetEqual(expected_possible_connections_to_delete, possible_connections_to_delete)
def create(self): genomes = [] for i in range(self.genome_params.population_size): g = Genome(self.genome_params) g.connect() genomes.append(g) return genomes
def test_draw_random_phenome(self): self.config.num_inputs = 3 self.config.num_outputs = 3 gen = Genome(self.config) phenome = FeedForwardPhenome(genome=gen, config=self.config) self.config.num_inputs = 2 self.config.num_outputs = 2 phenome.draw(testing=True)
def setUp(self): self.config = Config('../tests/conf_tester.conf') NodeGene.counter = 1 LinkGene.innovation_counter = 0 self.test_node_genes = [NodeGene(node_type='INPUT',), NodeGene(node_type='INPUT'), NodeGene(node_type='OUTPUT'), NodeGene(node_type='OUTPUT')] self.test_link_genes = [LinkGene(2, 3, weight=1), LinkGene(1, 3, weight=1)] self.genome = Genome(self.config, node_genes=self.test_node_genes, link_genes=self.test_link_genes)
def test_randomly_created_genome(self): config = self.config config.num_outputs = 3 config.num_inputs = 3 genome = Genome(config) self.config = Config('../tests/conf_tester.conf') assert len(genome.output_genes) == 3, \ "Genome should have 3 outputs, has %i" % len(genome.output_genes) assert len(genome.input_genes) == 3, \ "Genome should have 3 inputs, has %i" % len(genome.input_genes)
def test_write_and_read_geneme(self): filename = self.path + '/genome_test.json' genome = Genome(key=0) genome.create_random_genome() genome.save_genome(filename) genome_read = Genome.create_from_file(filename) self.assertEqual(len(genome.__dict__), len(genome_read.__dict__))
def test_mutate_delete_connection_when_two_input_one_hidden(self): self.config.n_initial_hidden_neurons = 1 genome = Genome(key='foo').create_random_genome() possible_connections_to_delete = set( ArchitectureMutation._calculate_possible_connections_to_delete( genome=genome)) expected_possible_connections_to_delete = {(-1, 1), (-2, 1), (1, 0)} self.assertSetEqual(expected_possible_connections_to_delete, possible_connections_to_delete)
def generate_genome_without_hidden_units(): # output nodes node_genes = {} node_genes = add_node(node_genes, key=0) connection_genes = {} connection_genes = add_connection(connection_genes, key=(-1, 0)) connection_genes = add_connection(connection_genes, key=(-2, 0)) genome = Genome(key=1) genome.node_genes = node_genes genome.connection_genes = connection_genes return genome
def test_classification_case(self): config = create_configuration(filename='/classification-miso.json') genome = Genome(key=1) genome.create_random_genome() n_samples = 5 estimator = PredictionDistributionEstimatorGenome(genome=genome, config=config, testing=True, n_samples=n_samples)\ .estimate() \ .enrich_with_dispersion_quantile() \ .calculate_metrics_by_dispersion_quantile() results = estimator.results self.assertTrue(isinstance(results, pd.DataFrame))
def initialize_population(self): population = {} for i in range(self.pop_size): key = next(self.genome_indexer) if self.config.initial_genome_filename is None: genome = Genome(key=key) genome.create_random_genome() else: filename = self.config.initial_genome_filename genome = Genome.create_from_file(filename=filename, key=key) population[key] = genome self.ancestors[key] = tuple() return population
def __init__(self, population_size, num_inputs, num_outputs): self.population_size = population_size # We initially create random-weighted organisms self.organisms = [] for _ in range(population_size): self.organisms.append(Organism(Genome(num_inputs, num_outputs))) # The global innovation counter is used to assign unique ids to innovations across generations self.global_innovation_counter = UniqueId(num_outputs) # The global node counter is used to assign unique ids to nodes across organisms self.global_node_counter = UniqueId(num_inputs + 1 + num_outputs) # The global species counter is used to assign unique ids to species across generations self.global_species_counter = UniqueId() self.species = []
def __init__(self, num_input, num_output, pop_size=POP_SIZE): self.generation = 1 self.num_input = num_input self.num_output = num_output self.pop_size = pop_size self.num_survive = int(self.pop_size * SURVIVE_RATE) self.num_mutate = int(self.pop_size * MUTATE_RATE) self.num_breed = self.pop_size - int(self.num_survive + self.num_mutate) self.num_diverge = int(self.pop_size * DIVERGE_RATE) # creation of initial gene pool self.genomes = [ Genome(self.num_input, self.num_output) for _ in range(self.pop_size) ] return
def test_add_new_connection(self): Genome.reset() genome = Genome() genes = [] genome.allocate_hidden_nodes(1) input_node_id_1 = genome.add_input_node() input_node_id_2 = genome.add_input_node() hidden_node_id_1 = genome.add_hidden_node() output_node_id_1 = genome.add_output_node() output_node_id_2 = genome.add_output_node() genes.append(Gene(input_node_id_1, hidden_node_id_1)) genes.append(Gene(input_node_id_2, hidden_node_id_1)) genes.append(Gene(hidden_node_id_1, output_node_id_1)) genes.append(Gene(hidden_node_id_1, output_node_id_2)) genome.set_genes((genes)) genome.allocate_genes(1) connected = genome.add_new_connection(input_node_id_1, output_node_id_1) self.assertEqual(genome.nodes[output_node_id_1].connected_nodes[1], genome.nodes[input_node_id_1]) self.assertTrue(connected) connected1 = genome.add_new_connection(input_node_id_1, input_node_id_2) connected2 = genome.add_new_connection(output_node_id_1, output_node_id_2) connected3 = genome.add_new_connection(output_node_id_2, hidden_node_id_1) connected4 = genome.add_new_connection(output_node_id_2, input_node_id_1) self.assertFalse(connected1) self.assertFalse(connected2) self.assertFalse(connected3) self.assertFalse(connected4)
def cross(self, genome1, genome2, gene_tracker): child_genome = Genome() for node in genome1.nodes: child_genome.add_node(node.copy()) for connection in genome1.connections: new_connection = connection.copy() if genome2.contains_connection(new_connection.in_node_id, new_connection.out_node_id): other_connection = genome2.get_connection( new_connection.in_node_id, new_connection.out_node_id) if not new_connection.enabled or not other_connection.enabled: should_enable = random.random() > self.disable_probability if new_connection.enabled != should_enable: new_connection.disable( ) if new_connection.enabled else new_connection.enable( ) if random.choice([True, False]): new_connection.weight = other_connection.weight child_genome.add_connection(new_connection) return child_genome