def mutate_add_connection(self, config): """ Attempt to add a new connection, the only restriction being that the output node cannot be one of the network input pins. """ possible_outputs = list(iterkeys(self.nodes)) out_node = choice(possible_outputs) possible_inputs = possible_outputs + config.input_keys in_node = choice(possible_inputs) # Don't duplicate connections. key = (in_node, out_node) if key in self.connections: # TODO: Should this be using mutation to/from rates? Hairy to configure... if config.check_structural_mutation_surer(): self.connections[key].enabled = True return # Don't allow connections between two output nodes if in_node in config.output_keys and out_node in config.output_keys: return if in_node in config.output_keys: return # No need to check for connections between input nodes: # they cannot be the output end of a connection (see above). # For feed-forward networks, avoid creating cycles. if config.feed_forward and creates_cycle( list(iterkeys(self.connections)), key): return cg = self.create_connection(config, in_node, out_node) self.connections[cg.key] = cg
def mutate_add_connection(self, config): # Choose the outnode layer layer_num = randint(0, config.num_layer - 1) # If choose out_node form the first layer, the input_node should choose from input ot the network. if layer_num == 0: out_node = choice(list(self.layer[layer_num][1])) in_node = choice(config.input_keys) else: out_node = choice(list(self.layer[layer_num][1])) in_node = choice(list(self.layer[layer_num - 1][1])) # Don't duplicate connections. key = (in_node, out_node) if key in self.connections: # TODO: Should this be using mutation to/from rates? Hairy to configure... if config.check_structural_mutation_surer(): self.connections[key].enabled = True return # Don't allow connections between two output nodes if in_node in config.output_keys and out_node in config.output_keys: return # No need to check for connections between input nodes: # they cannot be the output end of a connection (see above). # For feed-forward networks, avoid creating cycles. if config.feed_forward and creates_cycle( list(iterkeys(self.connections)), key): return cg = self.create_connection(config, in_node, out_node) self.connections[cg.key] = cg
def mutate_add_connection(self, config): ''' Attempt to add a new connection, the only restriction being that the output node cannot be one of the network input pins. ''' possible_outputs = list(iterkeys(self.nodes)) out_node = choice(possible_outputs) possible_inputs = possible_outputs + config.input_keys in_node = choice(possible_inputs) # Don't duplicate connections. key = (in_node, out_node) if key in self.connections: return # Don't allow connections between two output nodes if in_node in config.output_keys and out_node in config.output_keys: return # Don't allow connections between two input nodes if in_node in config.input_keys and out_node in config.input_keys: return # For feed-forward networks, avoid creating cycles. if config.feed_forward and creates_cycle( list(iterkeys(self.connections)), key): return cg = self.create_connection(config, in_node, out_node) self.connections[cg.key] = cg
def test_creates_cycle(): assert creates_cycle([(0, 1), (1, 2), (2, 3)], (0, 0)) assert creates_cycle([(0, 1), (1, 2), (2, 3)], (1, 0)) assert not creates_cycle([(0, 1), (1, 2), (2, 3)], (0, 1)) assert creates_cycle([(0, 1), (1, 2), (2, 3)], (2, 0)) assert not creates_cycle([(0, 1), (1, 2), (2, 3)], (0, 2)) assert creates_cycle([(0, 1), (1, 2), (2, 3)], (3, 0)) assert not creates_cycle([(0, 1), (1, 2), (2, 3)], (0, 3)) assert creates_cycle([(0, 2), (1, 3), (2, 3), (4, 2)], (3, 4)) assert not creates_cycle([(0, 2), (1, 3), (2, 3), (4, 2)], (4, 3))
def mutate_add_connection(self, config): num = 0 for i in range(config.conn_add_num): # Choose the outnode layer layer_num = randint(0, config.num_layer - 1) # If choose out_node form the first layer, the input_node should choose from input of the network. if layer_num == 0: out_node = choice(list(self.layer[layer_num][1])) in_node = choice(config.input_keys) else: out_node = choice(list(self.layer[layer_num][1])) #in_node = choice(list(self.layer[layer_num - 1][1])) # Changed to support dense connection. by Andrew 2019.3.18 left = 1 right = layer_num if layer_num < config.num_dense_layer else config.num_dense_layer in_node_layer_distance = randint(left, right) in_node = choice( list(self.layer[layer_num - in_node_layer_distance][1])) # Don't duplicate connections. key = (in_node, out_node) if key in self.connections: # TODO: Should this be using mutation to/from rates? Hairy to configure... if config.check_structural_mutation_surer(): self.connections[key].enabled = True continue # Don't allow connections between two output nodes if in_node in config.output_keys and out_node in config.output_keys: continue # No need to check for connections between input nodes: # they cannot be the output end of a connection (see above). # For feed-forward networks, avoid creating cycles. if config.feed_forward and creates_cycle( list(iterkeys(self.connections)), key): continue cg = self.create_connection(config, in_node, out_node) self.connections[cg.key] = cg num += 1 print("{0} connections added!".format(num))
def get_possible_new_connections(self, config): possible_connections = [] possible_outputs = list(iterkeys(self.nodes)) possible_inputs = possible_outputs + config.input_keys for p_o in possible_outputs: for p_i in possible_inputs: key = (p_i, p_o) if key in self.connections: continue if p_i in config.output_keys and p_o in config.output_keys: continue if config.feed_forward and creates_cycle( list(iterkeys(self.connections)), key): continue possible_connections.append(key) return possible_connections
def mutate_add_shared_connection(self, config): possible_outputs = list(self.nodes) out_node = choice(possible_outputs) possible_inputs = possible_outputs + config.input_keys in_node = choice(possible_inputs) # Don't duplicate connections. key = (in_node, out_node) if key in self.connections: # TODO: Should this be using mutation to/from rates? Hairy to configure... if config.check_structural_mutation_surer(): self.connections[key].enabled = True return # Don't allow connections between two output nodes if in_node in config.output_keys and out_node in config.output_keys: return # No need to check for connections between input nodes: # they cannot be the output end of a connection (see above). # For feed-forward networks, avoid creating cycles. if config.feed_forward and creates_cycle(list(self.connections), key): return if not self.sharedWeights: weightGene = WeightGene() weightGene.init_attributes(config) self.sharedWeights.add(weightGene) else: if random() < config.conn_reuse_weight_prob: weightGene = sample(self.sharedWeights, 1)[0] else: weightGene = WeightGene() weightGene.init_attributes(config) cg = self.create_shared_connection(config, in_node, out_node, weightGene) self.connections[cg.key] = cg
def mutate_add_connection(self, config): """ Attempt to add a new connection, the only restriction being that the output node cannot be one of the network input pins. """ possible_outputs = list(self.nodes) out_node = choice(possible_outputs) possible_inputs = possible_outputs + config.input_keys in_node = choice(possible_inputs) # Don't duplicate connections. key = (in_node, out_node) if key in self.connections: # TODO: Should this be using mutation to/from rates? Hairy to configure... if config.check_structural_mutation_surer(): self.connections[key].enabled = True return # Don't allow connections between two output nodes if in_node in config.output_keys and out_node in config.output_keys: return # No need to check for connections between input nodes: # they cannot be the output end of a connection (see above). # For feed-forward networks, avoid creating cycles. if config.feed_forward and creates_cycle(list(self.connections), key): return # If this is a MLRecurrentNetwork setup, there's a chance of a recurrent edge if in_node >= 0 and config.nw_type == 'mlrnn': if random() > config.recurrent_con_prob: in_node = -in_node - config.num_inputs - 1 cg = self.create_connection(config, in_node, out_node) self.connections[cg.key] = cg