Ejemplo n.º 1
0
    def __init__(self, target_id=None, input_id=None):
        """Create a connection gene.

        Creates a empty connection gene if either target_id or input_id
        are set to None.

        Arguments:
            target_id: the id of the node that receives the input.
            input_id: the id of the node that provides the input.
        """
        self.is_enabled = True

        if target_id is None or input_id is None:
            self.connection = None
            self.innovation_number = None

            return

        self.connection = Connection(target_id, input_id)

        try:
            self.innovation_number = ConnectionGene.pool[self.connection]
        except KeyError:
            self.innovation_number = len(ConnectionGene.pool) + 1
            ConnectionGene.pool[self.connection] = self.innovation_number
Ejemplo n.º 2
0
    def test_connection_json(self):
        """Test whether a connection can be saved to and loaded from JSON."""
        c = Connection(1, 0)

        out_file = json.dumps(c.to_json())

        c_load = Connection.from_json(json.loads(out_file))

        self.assertEqual(c, c_load)
        self.assertEqual(c.id, c_load.id)
        self.assertEqual(c.weight, c_load.weight)
Ejemplo n.º 3
0
    def replicate(self):

        copy = Network(self.config, replication=True)

        innovation_number_to_node = {0: copy.bias}

        # Copy Input Nodes
        for node in self.input_nodes:
            node_copy = node.replicate()
            copy.input_nodes.append(node_copy)
            innovation_number_to_node[node_copy.number] = node_copy

        # Copy Hidden Nodes
        for node in self.hidden_nodes:
            node_copy = node.replicate()
            copy.hidden_nodes.append(node_copy)
            innovation_number_to_node[node_copy.number] = node_copy

        # Copy Output Nodes
        for node in self.output_nodes:
            node_copy = node.replicate()
            copy.output_nodes.append(node_copy)
            innovation_number_to_node[node_copy.number] = node_copy

        # Copy Connections
        for out_node in self.hidden_nodes + self.output_nodes:
            node_copy = innovation_number_to_node[out_node.number]

            for connection in out_node.connections:

                input_node_copy = innovation_number_to_node[
                    connection.input_node.number]
                output_node_copy = innovation_number_to_node[
                    connection.output_node.number]

                connection_copy = Connection(input_node_copy,
                                             output_node_copy,
                                             self.config,
                                             number=connection.number)
                connection_copy.enabled = connection.enabled
                connection_copy.weight = connection.weight

                node_copy.add_connection(connection_copy)

                if connection in self.splitable_connections:
                    copy.splitable_connections.add(connection_copy)

                if input_node_copy.number == 0:
                    copy.bias_connections.append(connection_copy)
                else:
                    copy.connections.append(connection_copy)

        return copy
Ejemplo n.º 4
0
    def from_json(config):
        gene = ConnectionGene()
        gene.connection = Connection.from_json(config['connection'])
        gene.innovation_number = config['innovation_number']
        gene.is_enabled = config['is_enabled']

        return gene
Ejemplo n.º 5
0
 def create_initial_connections(self):
     self.input_nodes = [Input() for _ in range(self.num_inputs)]
     output_activation = self.get_activation(
         self.config['output_activation'])
     self.output_nodes = [
         Output(output_activation) for _ in range(self.num_outputs)
     ]
     for out_node in self.output_nodes:
         bias_connection = Connection(self.bias, out_node, self.config)
         self.bias_connections.append(bias_connection)
         out_node.add_connection(bias_connection)
         for in_node in self.input_nodes:
             connection = Connection(in_node, out_node, self.config)
             self.connections.append(connection)
             out_node.add_connection(connection)
             self.splitable_connections.add(connection)
Ejemplo n.º 6
0
    def add_input(self, node_id, other_id):
        """Add an input (form a connection) to a node.

        Arguments:
            node_id: the id of the node that will receive the input.
            other_id: the id of the node that will provide the input.
        """
        self.connections_dict[node_id].append(Connection(node_id, other_id))

        # Adding a connection may break the graph so we force the graph to be
        # compiled again to enforce a re-run of sanity and validity checks.
        self.is_compiled = False
Ejemplo n.º 7
0
    def mutate(self, genome, gene_tracker):
        possible_connections = [
            connection for connection in genome.connections
            if connection.enabled
        ]
        count = len(possible_connections)
        if count == 0:
            return

        connection = random.choice(possible_connections)
        new_node_id = gene_tracker.get_node_id(connection.in_node_id,
                                               connection.out_node_id,
                                               connection.iteration)

        in_node_layer = genome.get_node(connection.in_node_id).layer
        out_node_layer = genome.get_node(connection.out_node_id).layer
        new_node_layer = in_node_layer + 1
        if new_node_layer == out_node_layer:
            for node in genome.nodes:
                if node.layer >= new_node_layer:
                    node.layer += 1
        genome.add_node(
            Node(new_node_id, new_node_layer, self.activation,
                 self._new_bias()))

        connection.disable()

        innovation_in = gene_tracker.get_connection_innovation(
            connection.in_node_id, new_node_id)
        genome.add_connection(
            Connection(innovation_in, connection.in_node_id, new_node_id, True,
                       0, self.new_weight))

        innovation_out = gene_tracker.get_connection_innovation(
            new_node_id, connection.out_node_id)
        genome.add_connection(
            Connection(innovation_out, new_node_id, connection.out_node_id,
                       True, 0, connection.weight))
Ejemplo n.º 8
0
    def create_connection(self, inode, onode, splittable=True):

        # Reuse node innovation number from previous identical mutation if possible
        number = get_connection_innovation_number(inode.number, onode.number)

        connection = Connection(inode, onode, self.config, number=number)
        self.connections.append(connection)

        # Connect to out node
        onode.add_connection(connection)

        if splittable: self.splitable_connections.add(connection)

        # Save number for future potential duplicate structural mutations
        if number is None:
            register_connection(inode.number, onode.number, connection.number)

        return connection
Ejemplo n.º 9
0
    def from_json(config):
        """Load a graph object from JSON.

        Arguments:
            config: the JSON dictionary loaded from file.

        Returns: a graph object.
        """
        graph = Graph()

        graph.add_nodes([Node.from_json(node) for node in config['nodes']])
        for connection in [
                Connection.from_json(connection)
                for connection in config['connections']
        ]:
            graph.add_connection(connection)

        graph.compile()

        return graph
Ejemplo n.º 10
0
    def mutate(self, genome, gene_tracker, max_tries=100):
        # TODO: Find a way how to efficiently determine a non-existing (or disabled) connection.
        current_try = 0
        while True:
            in_node, out_node = tuple(random.sample(genome.nodes, 2))
            if in_node.layer > out_node.layer:
                in_node, out_node = out_node, in_node
            if in_node.layer != out_node.layer and not self._contains_enabled_connection(
                    genome, in_node.id, out_node.id):
                break

            current_try += 1
            if current_try >= max_tries:
                return

        if genome.contains_connection(in_node.id, out_node.id):
            connection = genome.get_connection(in_node.id, out_node.id)
            connection.enable()
        else:
            innovation = gene_tracker.get_connection_innovation(
                in_node.id, out_node.id)
            connection = Connection(innovation, in_node.id, out_node.id, True,
                                    0, self._new_weight())
            genome.add_connection(connection)
Ejemplo n.º 11
0
genome.add_node(Node(9, 1, ReLU(), 1.0))
genome.add_node(Node(10, 1, ReLU(), 1.0))

genome.add_node(Node(11, 2, ReLU(), 1.0))
genome.add_node(Node(12, 2, ReLU(), 1.0))
genome.add_node(Node(13, 2, ReLU(), 1.0))
genome.add_node(Node(14, 2, ReLU(), 1.0))

genome.add_node(Node(15, 3, ReLU(), 1.0))
genome.add_node(Node(16, 3, ReLU(), 1.0))
genome.add_node(Node(17, 3, ReLU(), 1.0))

genome.add_node(Node(4, 4, ReLU(), 1.0))
genome.add_node(Node(5, 4, ReLU(), 1.0))

genome.add_connection(Connection(1, 1, 6, True, 0, 0.5))
genome.add_connection(Connection(1, 1, 7, True, 0, -1.0))
genome.add_connection(Connection(1, 1, 9, True, 0, -0.4))

genome.add_connection(Connection(1, 2, 6, True, 0, 0.7))
genome.add_connection(Connection(1, 2, 7, True, 0, -0.1))

genome.add_connection(Connection(1, 3, 6, False, 0, 0.6))
genome.add_connection(Connection(1, 3, 9, True, 0, -0.18))
genome.add_connection(Connection(1, 3, 8, True, 0, 0.72))
genome.add_connection(Connection(1, 3, 7, True, 0, -0.9))

genome.add_connection(Connection(1, 6, 11, True, 0, 0.6))
genome.add_connection(Connection(1, 6, 13, False, 0, -0.5))
genome.add_connection(Connection(1, 7, 14, True, 0, 1.0))
genome.add_connection(Connection(1, 7, 12, True, 0, -0.9))
Ejemplo n.º 12
0
class ConnectionGene(Gene):
    """Represents a connection gene."""
    pool = {}

    def __init__(self, target_id=None, input_id=None):
        """Create a connection gene.

        Creates a empty connection gene if either target_id or input_id
        are set to None.

        Arguments:
            target_id: the id of the node that receives the input.
            input_id: the id of the node that provides the input.
        """
        self.is_enabled = True

        if target_id is None or input_id is None:
            self.connection = None
            self.innovation_number = None

            return

        self.connection = Connection(target_id, input_id)

        try:
            self.innovation_number = ConnectionGene.pool[self.connection]
        except KeyError:
            self.innovation_number = len(ConnectionGene.pool) + 1
            ConnectionGene.pool[self.connection] = self.innovation_number

    def copy(self):
        """Make a copy of this gene.

        Returns: the copy of this gene.
        """
        copy = ConnectionGene()
        copy.connection = self.connection.copy()
        copy.is_enabled = self.is_enabled
        copy.innovation_number = self.innovation_number

        return copy

    @property
    def alignment_key(self):
        return self.innovation_number

    @property
    def weight(self):
        return self.connection.weight

    @weight.setter
    def weight(self, value):
        self.connection.weight = value

    def combine_by_average(self, other):
        new_gene = self.copy()

        new_gene.weight = 0.5 * (self.weight + other.weight)

        return new_gene

    def to_json(self):
        return dict(connection=self.connection.to_json(),
                    innovation_number=self.innovation_number,
                    is_enabled=self.is_enabled)

    @staticmethod
    def from_json(config):
        gene = ConnectionGene()
        gene.connection = Connection.from_json(config['connection'])
        gene.innovation_number = config['innovation_number']
        gene.is_enabled = config['is_enabled']

        return gene

    def __str__(self):
        return 'Connection_Gene_%d(%s)' % (self.innovation_number,
                                           self.connection) + \
               ' (disabled)' if not self.is_enabled else ''

    def __eq__(self, other):
        return self.connection == other.connection and \
               self.innovation_number == other.innovation_number

    def __hash__(self):
        return self.innovation_number

    def __lt__(self, other):
        return self.innovation_number < other.innovation_number
Ejemplo n.º 13
0
 def remove(self, genome: conn.Connection):
     self.__genomes.remove(genome)
     self.__remove_node(genome.get_in_out_nodes())
Ejemplo n.º 14
0
    def add(self, genome: conn.Connection):
        self.__genomes.add(genome)

        # unpack tuple into separated arguments
        self.__add_node(genome.get_in_out_nodes())