def main(): node_list = [ NodeGene(node_id=0, node_type='source'), NodeGene(node_id=1, node_type='source'), NodeGene(node_id=2, node_type='output', bias=1), NodeGene(node_id=3, node_type='output', bias=1), NodeGene(node_id=4, node_type='output', bias=1) ] connection_list = [ ConnectionGene(input_node=0, output_node=2, innovation_number=1, weight=-0.351, enabled=True), ConnectionGene(input_node=0, output_node=3, innovation_number=2, weight=-0.351, enabled=True), ConnectionGene(input_node=0, output_node=4, innovation_number=3, weight=-0.351, enabled=True), ConnectionGene(input_node=1, output_node=2, innovation_number=4, weight=-0.351, enabled=True), ConnectionGene(input_node=1, output_node=3, innovation_number=5, weight=-0.351, enabled=True), ConnectionGene(input_node=1, output_node=4, innovation_number=6, weight=-0.351, enabled=True) ] genome = GenomeMultiClass(connections=connection_list, nodes=node_list, key=3) x_data, y_data = create_data(n_generated=500) genome_nn = GenomeNeuralNetwork(genome=genome, create_weights_bias_from_genome=False, activation_type='sigmoid', learning_rate=0.1, x_train=x_data, y_train=y_data) print(genome.num_layers_including_input) print(genome.constant_weight_connections) print(genome.layer_connections_dict)
def create_new_population(self, population_size, num_features): population = {} node_list = [] connection_list = [] # Create the source nodes for node in range(num_features): node_list.append(NodeGene(node_id=node, node_type='source')) # Add the output node (There is only one in this case) node_list.append( NodeGene(node_id=num_features, node_type='output', bias=1)) # Save the innovations for the first generation. for source_node_id in range(num_features): # Increment for the new innovation self.global_innovation_number += 1 # The output node will always have the node_id equal to the number of features self.innovation_tracker[( source_node_id, num_features)] = self.global_innovation_number # For each feature there will be a connection to the output for i in range(num_features): connection = (i, num_features) # The connection was already saved, so this should return true assert (connection in self.innovation_tracker) connection_list.append( ConnectionGene( input_node=i, output_node=num_features, innovation_number=self.innovation_tracker[connection], enabled=True)) # Create a population of size population_size for index in range(population_size): # Deep copies otherwise changing the connection weight change's it for every genome that has the same # reference to the class deep_copy_connections = copy.deepcopy(connection_list) deep_copy_nodes = copy.deepcopy(node_list) # Set all the connections to a random weight for each genome for connection in deep_copy_connections: connection.weight = np.random.randn() # Increment since the index value has been assigned self.genome_indexer += 1 # Create the genome population[index] = Genome(connections=deep_copy_connections, nodes=deep_copy_nodes, key=self.genome_indexer) self.show_population_weight_distribution(population=population) return population
def main(): node_list = [ NodeGene(node_id=1, node_type='source'), NodeGene(node_id=2, node_type='source'), NodeGene(node_id=3, node_type='hidden'), NodeGene(node_id=4, node_type='hidden'), NodeGene(node_id=5, node_type='output') ] # Note that one of the connections isn't enabled connection_list = [ ConnectionGene(input_node=1, output_node=5, innovation_number=1, enabled=True), ConnectionGene(input_node=1, output_node=4, innovation_number=2, enabled=True), ConnectionGene(input_node=2, output_node=3, innovation_number=3, enabled=True), ConnectionGene(input_node=2, output_node=4, innovation_number=4, enabled=True), ConnectionGene(input_node=3, output_node=4, innovation_number=7, enabled=True), ConnectionGene(input_node=3, output_node=5, innovation_number=8, enabled=True), ConnectionGene(input_node=4, output_node=5, innovation_number=6, enabled=True) ] genome = Genome(connections=connection_list, nodes=node_list, key=3) print(genome.num_layers_including_input) print(genome.constant_weight_connections) print(genome.layer_connections_dict)
def add_successful_genome_for_test(self, current_gen, use_this_genome): """ This function adds a pre programmed genome which is known to converge for the XOR dataset. :param current_gen: :param use_this_genome: Whether this genome should be added to the population or not :return: """ # Wait for current_gen > 1 because if using backprop the first gen skips using backprop. if current_gen > 1 and use_this_genome: node_list = [ NodeGene(node_id=0, node_type='source'), NodeGene(node_id=1, node_type='source'), NodeGene(node_id=2, node_type='output', bias=0.5), NodeGene(node_id=3, node_type='hidden', bias=1), NodeGene(node_id=4, node_type='hidden', bias=1), NodeGene(node_id=5, node_type='hidden', bias=1), NodeGene(node_id=6, node_type='hidden', bias=1), ] connection_list = [ConnectionGene(input_node=0, output_node=3, innovation_number=1, enabled=True, weight=np.random.randn()), ConnectionGene(input_node=1, output_node=3, innovation_number=2, enabled=True, weight=np.random.randn()), ConnectionGene(input_node=0, output_node=4, innovation_number=3, enabled=True, weight=np.random.randn()), ConnectionGene(input_node=1, output_node=4, innovation_number=4, enabled=True, weight=np.random.randn()), ConnectionGene(input_node=3, output_node=5, innovation_number=5, enabled=True, weight=np.random.randn()), ConnectionGene(input_node=4, output_node=5, innovation_number=6, enabled=True, weight=np.random.randn()), ConnectionGene(input_node=3, output_node=6, innovation_number=7, enabled=True, weight=np.random.randn()), ConnectionGene(input_node=4, output_node=6, innovation_number=8, enabled=True, weight=np.random.randn()), ConnectionGene(input_node=5, output_node=2, innovation_number=9, enabled=True, weight=np.random.rand()), ConnectionGene(input_node=6, output_node=2, innovation_number=10, enabled=True, weight=np.random.randn()) ] test_genome = Genome(connections=connection_list, nodes=node_list, key=1) test_genome.fitness = -99999999999 self.population[32131231] = test_genome
def add_node(self, reproduction_instance, innovation_tracker): """ Add a node between two existing nodes """ # Create the new node new_node = NodeGene(node_id=(max(self.nodes.keys()) + 1), node_type='hidden', bias=1) # The connection where the node will be added connections_list = list(self.connections.values()) # Remove any connections which aren't enabled as a candidate where a node can be added for connection in connections_list: if not connection.enabled: connections_list.remove(connection) connection_to_add_node = random.choice(connections_list) # Disable the connection since it will be replaced connection_to_add_node.enabled = False input_node = connection_to_add_node.input_node output_node = connection_to_add_node.output_node # Create new connection gene. Which has a weight of 1 first_combination = (input_node, new_node.node_id) if first_combination in innovation_tracker: first_new_connection = ConnectionGene( input_node=input_node, output_node=new_node.node_id, innovation_number=innovation_tracker[first_combination], weight=1) else: # Increment since there is a new innovation reproduction_instance.global_innovation_number += 1 first_new_connection = ConnectionGene( input_node=input_node, output_node=new_node.node_id, innovation_number=reproduction_instance. global_innovation_number, weight=1) # Save the innovation since it's new innovation_tracker[ first_combination] = reproduction_instance.global_innovation_number second_combination = (new_node.node_id, output_node) # The second connection keeps the weight of the connection it replaced if second_combination in innovation_tracker: second_new_connection = ConnectionGene( input_node=new_node.node_id, output_node=output_node, innovation_number=innovation_tracker[second_combination], weight=connection_to_add_node.weight) else: # Increment since there is a new innovation reproduction_instance.global_innovation_number += 1 second_new_connection = ConnectionGene( input_node=new_node.node_id, output_node=output_node, innovation_number=reproduction_instance. global_innovation_number, weight=connection_to_add_node.weight) # save the innovation if it doesn't already exist innovation_tracker[ second_combination] = reproduction_instance.global_innovation_number # Add the new node and connections self.nodes[new_node.node_id] = new_node self.connections[ first_new_connection.innovation_number] = first_new_connection self.connections[ second_new_connection.innovation_number] = second_new_connection return first_new_connection, second_new_connection
def create_new_population(self, population_size, num_features, num_classes): population = {} source_node_list = [] output_node_list = [] # Create the source and output nodes for node_id in range(num_features + num_classes): if node_id < num_features: source_node_list.append( NodeGene(node_id=node_id, node_type='source')) else: output_node_list.append( NodeGene(node_id=node_id, node_type='output', bias=1)) # Save innovations on population creation for source_node in source_node_list: for output_node in output_node_list: # Increment for the new innovation self.global_innovation_number += 1 # The output node will always have the node_id equal to the number of features self.innovation_tracker[( source_node.node_id, output_node.node_id)] = self.global_innovation_number connection_list = [] # For each feature there will be a connection to the output for source_node in source_node_list: for output_node in output_node_list: connection = (source_node.node_id, output_node.node_id) # The connection was already saved, so this should return true assert (connection in self.innovation_tracker) connection_list.append( ConnectionGene( input_node=source_node.node_id, output_node=output_node.node_id, innovation_number=self.innovation_tracker[connection], enabled=True)) all_nodes_list = source_node_list + output_node_list # Create a population of size population_size for index in range(population_size): # Deep copies otherwise changing the connection weight change's it for every genome that has the same # reference to the class deep_copy_connections = copy.deepcopy(connection_list) deep_copy_nodes = copy.deepcopy(all_nodes_list) # Set all the connections to a random weight for each genome for connection in deep_copy_connections: connection.weight = np.random.randn() # Increment since the index value has been assigned self.genome_indexer += 1 # Create the genome population[index] = GenomeMultiClass( connections=deep_copy_connections, nodes=deep_copy_nodes, key=self.genome_indexer) self.show_population_weight_distribution(population=population) return population