Search code examples
pythonneural-networkfeed-forward

how to use neat's feed forward network by itself?


I want to use NEAT's neural network by itself so I can control how the selection of the fittest(training) is done along with other things, but the source code for NEAT's feed forward network can't be used alone(to create one I have to have a config file, and a genome).

Source code for nn.feed_forward:

from neat.graphs import feed_forward_layers


class FeedForwardNetwork(object):
    def __init__(self, inputs, outputs, node_evals):
        self.input_nodes = inputs
        self.output_nodes = outputs
        self.node_evals = node_evals
        self.values = dict((key, 0.0) for key in inputs + outputs)

    def activate(self, inputs):
        if len(self.input_nodes) != len(inputs):
            raise RuntimeError("Expected {0:n} inputs, got {1:n}".format(len(self.input_nodes), len(inputs)))

        for k, v in zip(self.input_nodes, inputs):
            self.values[k] = v

        for node, act_func, agg_func, bias, response, links in self.node_evals:
            node_inputs = []
            for i, w in links:
                node_inputs.append(self.values[i] * w)
            s = agg_func(node_inputs)
            self.values[node] = act_func(bias + response * s)

        return [self.values[i] for i in self.output_nodes]


    @staticmethod
    def create(genome, config): # I don't want to have to pass in either arguments to create a network
        """ Receives a genome and returns its phenotype (a FeedForwardNetwork). """

        # Gather expressed connections.
        connections = [cg.key for cg in genome.connections.values() if cg.enabled]

        layers = feed_forward_layers(config.genome_config.input_keys, config.genome_config.output_keys, connections)
        node_evals = []
        for layer in layers:
            for node in layer:
                inputs = []
                for conn_key in connections:
                    inode, onode = conn_key
                    if onode == node:
                        cg = genome.connections[conn_key]
                        inputs.append((inode, cg.weight))

                ng = genome.nodes[node]
                aggregation_function = config.genome_config.aggregation_function_defs.get(ng.aggregation)
                activation_function = config.genome_config.activation_defs.get(ng.activation)
                node_evals.append((node, activation_function, aggregation_function, ng.bias, ng.response, inputs))

        return FeedForwardNetwork(config.genome_config.input_keys, config.genome_config.output_keys, node_evals)

Also I want to be able to mutate the neural network(connections, weights, ect).


Solution

  • To create a FeedForwardNetwork, you need to use the create method or set the inputs, outputs, node_evals manually.

    input

    The input is the list of the "key"(refer to the doc) of the input nodes. It is a list of int, like [-1, -2, ...,-num_inputs], where num_inputs is the number of input nodes you set in the config_file.

    output

    The output is the list of the "key" of the output nodes. It is a list of int, like [0, 1, 2, ..., (num_outputs-1)], where num_outputs is the number of output nodes you set in the config_file.

    node_evals

    The node_evals is a list of tuple.

    The size of the tuple:

    Each element in the tuple correpsonds to one node that have "in" connections, so the tuple size is num_of_hiddens+num_of_outputs in the network. (Note, this is decided by the genome instead of the config, so the "num_of_outputs" and "num_of_hiddens" can be different from the "num_outputs" and "num_hidden" in the config_file).

    The elements in the tuple:

    As you can see in the create method and the activate method, an element in the tuple includes:

    1. tuple[0]: The key of corresponding node.
    2. tuple[1]: The activation_function of the node. I think it is a function that input a float and output a float.
    3. tuple[2]: The aggregation_function of the node. I think it can be any function that input a list of float, and output another float. For example, compute the sum of the elements in the list.
    4. tuple[3]: Bias of the node, float.
    5. tuple[4]: Response of the node, float.
    6. tuple[5]: Links that provide inputs for this neuron(node), denoted as node i. It is a list of tuple. The length of tuple[5] is the number of input neuron of current neuron i. As for the sub-tuple inside tuple[5], sub_tuple[0] is the key of a input neuron (here "input" means a node that input to node i, instead of the "input" of the whole network), and the sub_tuple[1] (it's of float type) is the connection weight between the certain input neuron and node i.

    If you take a look at the implementation of activate, you may have a better understanding of the physical meaning of "activation_function", "aggregation_function", "bias", "response" and "links".


    I would also suggest you to run an example over here, add a breakpoint at the creatation of the FeedForwardNetwork and inspect the data type.