/// <summary> /// Create a default minimal genome that describes a NN with the given number of inputs and outputs. /// </summary> /// <returns></returns> public static IGenome CreateGenome(NeatParameters neatParameters, IdGenerator idGenerator, int inputNeuronCount, int outputNeuronCount, float connectionProportion, bool neatBrain) { IActivationFunction actFunct; NeuronGene neuronGene; // temp variable. NeuronGeneList inputNeuronGeneList = new NeuronGeneList(); // includes bias neuron. NeuronGeneList outputNeuronGeneList = new NeuronGeneList(); NeuronGeneList neuronGeneList = new NeuronGeneList(); ConnectionGeneList connectionGeneList = new ConnectionGeneList(); // IMPORTANT NOTE: The neurons must all be created prior to any connections. That way all of the genomes // will obtain the same innovation ID's for the bias,input and output nodes in the initial population. // Create a single bias neuron. //TODO: DAVID proper activation function change to NULL? actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn"); neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Bias, actFunct, 0f); inputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); // Create input neuron genes. for (int i = 0; i < inputNeuronCount; i++) { //TODO: DAVID proper activation function change to NULL? neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Input, actFunct, 0f); inputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); } // Create output neuron genes. if (neatBrain) { actFunct = ActivationFunctionFactory.GetActivationFunction("SteepenedSigmoidApproximation"); } else { actFunct = ActivationFunctionFactory.GetActivationFunction("BipolarSigmoid"); } for (int i = 0; i < outputNeuronCount; i++) { //actFunct = ActivationFunctionFactory.GetRandomActivationFunction(neatParameters); //TODO: DAVID proper activation function neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Output, actFunct, 1f); outputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); } // Loop over all possible connections from input to output nodes and create a number of connections based upon // connectionProportion. foreach (NeuronGene targetNeuronGene in outputNeuronGeneList) { foreach (NeuronGene sourceNeuronGene in inputNeuronGeneList) { // Always generate an ID even if we aren't going to use it. This is necessary to ensure connections // between the same neurons always have the same ID throughout the generated population. uint connectionInnovationId = idGenerator.NextInnovationId; if (Utilities.NextDouble() < connectionProportion) { // Ok lets create a connection. connectionGeneList.Add(new ConnectionGene(connectionInnovationId, sourceNeuronGene.InnovationId, targetNeuronGene.InnovationId, (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0)); // Weight 0 +-5 } } } // Don't create any hidden nodes at this point. Fundamental to the NEAT way is to start minimally! return(new NeatGenome(idGenerator.NextGenomeId, neuronGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount)); }
public static IGenome CreateGenomePreserveID(NeatParameters neatParameters, IdGenerator idGenerator, int inputNeuronCount, int outputNeuronCount, float connectionProportion) { IActivationFunction actFunct; NeuronGene neuronGene; // temp variable. NeuronGeneList inputNeuronGeneList = new NeuronGeneList(); // includes bias neuron. NeuronGeneList outputNeuronGeneList = new NeuronGeneList(); NeuronGeneList neuronGeneList = new NeuronGeneList(); ConnectionGeneList connectionGeneList = new ConnectionGeneList(); int nodeCount = 0; WINManager win = WINManager.SharedWIN; // IMPORTANT NOTE: The neurons must all be created prior to any connections. That way all of the genomes // will obtain the same innovation ID's for the bias,input and output nodes in the initial population. // Create a single bias neuron. //TODO: DAVID proper activation function change to NULL? actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn"); //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Bias, actFunct); WINNode neuronNode = win.findOrInsertNodeWithProperties(idGenerator, WINNode.NodeWithProperties(nodeCount++, NeuronType.Bias) ); neuronGene = new NeuronGene(null, neuronNode.UniqueID, NeuronGene.INPUT_LAYER, NeuronType.Bias, actFunct); inputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); // Create input neuron genes. actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn"); for (int i = 0; i < inputNeuronCount; i++) { //TODO: DAVID proper activation function change to NULL? //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Input, actFunct); neuronNode = win.findOrInsertNodeWithProperties(idGenerator, WINNode.NodeWithProperties(nodeCount++, NeuronType.Input)); neuronGene = new NeuronGene(null, neuronNode.UniqueID, NeuronGene.INPUT_LAYER, NeuronType.Input, actFunct); inputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); } // Create output neuron genes. //actFunct = ActivationFunctionFactory.GetActivationFunction("NullFn"); for (int i = 0; i < outputNeuronCount; i++) { actFunct = ActivationFunctionFactory.GetActivationFunction("BipolarSigmoid"); //actFunct = ActivationFunctionFactory.GetRandomActivationFunction(neatParameters); //TODO: DAVID proper activation function //neuronGene = new NeuronGene(idGenerator.NextInnovationId, NeuronType.Output, actFunct); neuronNode = win.findOrInsertNodeWithProperties(idGenerator, WINNode.NodeWithProperties(nodeCount++, NeuronType.Output)); neuronGene = new NeuronGene(null, neuronNode.UniqueID, NeuronGene.OUTPUT_LAYER, NeuronType.Output, actFunct); outputNeuronGeneList.Add(neuronGene); neuronGeneList.Add(neuronGene); } int currentConnCount = 0; WINConnection winConn; // Loop over all possible connections from input to output nodes and create a number of connections based upon // connectionProportion. foreach (NeuronGene targetNeuronGene in outputNeuronGeneList) { foreach (NeuronGene sourceNeuronGene in inputNeuronGeneList) { // Always generate an ID even if we aren't going to use it. This is necessary to ensure connections // between the same neurons always have the same ID throughout the generated population. //PAUL NOTE: //instead of generating and not using and id, we use the target and connection properties to uniquely identify a connection in WIN //uint connectionInnovationId = idGenerator.NextInnovationId; if (Utilities.NextDouble() < connectionProportion) { // Ok lets create a connection. //first we search or create the winconnection object winConn = win.findOrInsertConnectionWithProperties(idGenerator, WINConnection.ConnectionWithProperties(currentConnCount, sourceNeuronGene.InnovationId, targetNeuronGene.InnovationId)); //our winconn will have our innovationID, and our weight like normal //this will also respect the idgenerator, since it gets sent in as well, for legacy purposes connectionGeneList.Add(new ConnectionGene(winConn.UniqueID, sourceNeuronGene.InnovationId, targetNeuronGene.InnovationId, (Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0) ); //(Utilities.NextDouble() * neatParameters.connectionWeightRange) - neatParameters.connectionWeightRange / 2.0)); // Weight 0 +-5 } currentConnCount++; } } //WIN will eventually be in control of all the genomes that are created as well, but not quite yet! //TODO: WIN should be generating genomeIDs explicitly // Don't create any hidden nodes at this point. Fundamental to the NEAT way is to start minimally! return(new NeatGenome(idGenerator.NextGenomeId, neuronGeneList, connectionGeneList, inputNeuronCount, outputNeuronCount)); }