/// <summary> /// Returns an IEnumerable that yields the mappings/connections defined by the mapping function (from the source nodes to /// the target nodes) as a sequence. The alternative of returning a list would require a very long list in extreme scenarios; /// this approach minimizes down memory usage. /// </summary> public IEnumerable<SubstrateConnection> GenerateConnections(SubstrateNodeSet srcNodeSet, SubstrateNodeSet tgtNodeSet) { // Test for scenario where srcNodeSet and tgtNodeSet are the same node set, that is, we are creating // connections within a nodeset and therefore we need to test (and honour) _allowLocalRecurrentConnections. if(srcNodeSet == tgtNodeSet) { // Mapping between nodes within a single node set. // Break the inner loop into two. This avoids having to make the local recurrent test connection // for every node pair - we only test when we actually have the same node as source and target. IList<SubstrateNode> nodeList = srcNodeSet.NodeList; int count = nodeList.Count; for(int i=0; i<count; i++) { // Loop over all nodes prior to the i'th. SubstrateNode srcNode = nodeList[i]; for(int j=0; j<i; j++) { if(_testNodePair(srcNode, nodeList[j])) { yield return new SubstrateConnection(srcNode, nodeList[j]); } } // Test for local recurrent connection. if(_allowLocalRecurrentConnections && _testNodePair(srcNode, srcNode)) { yield return new SubstrateConnection(srcNode, srcNode); } // Loop over all nodes after the i'th. for(int j=i+1; j<count; j++) { if(_testNodePair(srcNode, nodeList[j])) { yield return new SubstrateConnection(srcNode, nodeList[j]); } } } } else { // Mapping between nodes in two distinct node sets. foreach(SubstrateNode srcNode in srcNodeSet.NodeList) { foreach(SubstrateNode tgtNode in tgtNodeSet.NodeList) { if(_testNodePair(srcNode, tgtNode)) { yield return new SubstrateConnection(srcNode, tgtNode); } } } } }
/// <summary> /// Creates a substrate to use to create network defintions/the genome decoder. /// </summary> /// <param name="visualFieldResolution">The visual field's pixel resolution, e.g. 11 means 11x11 pixels.</param> /// <param name="lengthCppnInput">Indicates if the CPPNs being decoded have an extra input for specifying connection length.</param> public static Substrate CreateSubstrate(int visualFieldResolution, bool lengthCppnInput = false) { // Create two layer 'sandwich' substrate. int pixelCount = visualFieldResolution * visualFieldResolution; double pixelSize = 2.0 / visualFieldResolution; double originPixelXY = -1 + (pixelSize / 2.0); SubstrateNodeSet inputLayer = new SubstrateNodeSet(pixelCount); SubstrateNodeSet HiddenLayer = new SubstrateNodeSet(pixelCount); SubstrateNodeSet outputLayer = new SubstrateNodeSet(pixelCount); // Node IDs start at 1. (bias node is always zero). uint inputId = 1; uint outputId = (uint)(pixelCount + 1); uint hiddenId = (uint)(2 * pixelCount + 2); double yReal = originPixelXY; for (int y = 0; y < visualFieldResolution; y++, yReal += pixelSize) { double xReal = originPixelXY; for (int x = 0; x < visualFieldResolution; x++, xReal += pixelSize, inputId++, outputId++, hiddenId++) { //CJR: I leave the thrid dimintion in,cause I can ignore it when I'm adding inputs to the CPPN //but use it to dicate what set of outputs to use inputLayer.NodeList.Add(new SubstrateNode(inputId, new double[] { xReal, yReal, -1.0 })); if ((x % 2 == 0 && y % 2 == 0) || ((x + 1) % 2 == 0 && (y + 1) % 2 == 0)) { HiddenLayer.NodeList.Add(new SubstrateNode(hiddenId, new double[] { xReal, yReal, 0 })); } outputLayer.NodeList.Add(new SubstrateNode(outputId, new double[] { xReal, yReal, 1.0 })); } } List<SubstrateNodeSet> nodeSetList = new List<SubstrateNodeSet>(3); nodeSetList.Add(inputLayer); nodeSetList.Add(outputLayer); nodeSetList.Add(HiddenLayer); //CJR: Fist and second layer must be input/output respectively to be validated by the substrate, so hidden is third // Define connection mappings between layers/sets. List<NodeSetMapping> nodeSetMappingList = new List<NodeSetMapping>(3); nodeSetMappingList.Add(NodeSetMapping.Create(0, 2, (double?)null)); nodeSetMappingList.Add(NodeSetMapping.Create(2, 1, (double?)null)); // Construct substrate. Substrate substrate = new Substrate(nodeSetList, DefaultActivationFunctionLibrary.CreateLibraryNeat(SteepenedSigmoid.__DefaultInstance), 0, 0.2, 5, nodeSetMappingList); return substrate; }
/// <summary> /// Create a genome decoder for the experiment. /// </summary> protected override IGenomeDecoder<NeatGenome, IBlackBox> CreateHyperNeatGenomeDecoder() { // Create HyperNEAT network substrate. uint nodeId = 1; //-- Create input layer nodes. var inputLayer = new SubstrateNodeSet(samples.Length); for (int v = 0; v < samples.GetLength(0); v++) // variables { for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { var x = 2 * (double)i / n - 1; var y = 2 * (double)j / m - 1; var z = -(double)v / samples.GetLength(0); inputLayer.NodeList.Add(new SubstrateNode(nodeId++, new double[] { x, y, z })); } } } //-- Create output layer nodes. var outputLayers = new SubstrateNodeSet[nbClusters]; for (var c = 0; c < nbClusters; c++) // clusters { outputLayers[c] = new SubstrateNodeSet(n * m); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { var x = 2 * (double)i / n - 1; var y = 2 * (double)j / m - 1; var z = c / nbClusters; outputLayers[c].NodeList.Add(new SubstrateNode(nodeId++, new double[] { x, y, z })); } } } // Connect up layers. List<SubstrateNodeSet> nodeSetList = new List<SubstrateNodeSet>(1 + nbClusters); nodeSetList.Add(inputLayer); foreach (var layer in outputLayers) { nodeSetList.Add(layer); } List<NodeSetMapping> nodeSetMappingList = new List<NodeSetMapping>(nbClusters); for (int i = 0; i < nbClusters; i++) { var inputLayerIdx = 0; var outputLayerIdx = 1 + i; nodeSetMappingList.Add(NodeSetMapping.Create(inputLayerIdx, outputLayerIdx, (double?)null)); } // Construct substrate. Substrate substrate = new Substrate(nodeSetList, DefaultActivationFunctionLibrary.CreateLibraryNeat(SteepenedSigmoid.__DefaultInstance), 0, 0.2, 5, nodeSetMappingList); // Create genome decoder. Decodes to a neural network packaged with an activation scheme that defines a fixed number of activations per evaluation. IGenomeDecoder<NeatGenome, IBlackBox> genomeDecoder = new HyperNeatDecoder(substrate, _activationSchemeCppn, _activationScheme, _lengthCppnInput); return genomeDecoder; }
/// <summary> /// Creates a new HyperNEAT genome decoder that can be used to convert /// a genome into a phenome. /// </summary> public IGenomeDecoder<NeatGenome, IBlackBox> CreateHyperNeatGenomeDecoder() { var game = Parameters.GameFunction(null, null); int xTotal = game.Board.GetLength(0); int yTotal = game.Board.GetLength(1); // Create an input and an output layer for the HyperNEAT // substrate. Each layer corresponds to the game board // with 9 squares. SubstrateNodeSet inputLayer = new SubstrateNodeSet(Parameters.Inputs); SubstrateNodeSet outputLayer = new SubstrateNodeSet(Parameters.Outputs); // Each node in each layer needs a unique ID. uint uid = 1; // The game board is represented as a 2-dimensional plane. // Each square is at [0,...,1] in the x and y axis. // Thus, the game board for TicTacToe looks like this: // // (0,1) | (0.5,1) | (1,1) // (0,0.5) | (0.5,0.5) | (1,0.5) // (0,0) | (0.5,0) | (1,0) // for (int x = 0; x < xTotal; x++) for (int y = 0; y < yTotal; y++) inputLayer.NodeList.Add(new SubstrateNode(uid++, new double[] { x, y })); for (int x = 0; x < xTotal; x++) for (int y = 0; y < yTotal; y++) outputLayer.NodeList.Add(new SubstrateNode(uid++, new double[] { x, y })); List<SubstrateNodeSet> nodeSetList = new List<SubstrateNodeSet>(2); nodeSetList.Add(inputLayer); nodeSetList.Add(outputLayer); // Define a connection mapping from the input layer to the output layer. List<NodeSetMapping> nodeSetMappingList = new List<NodeSetMapping>(1); nodeSetMappingList.Add(NodeSetMapping.Create(0, 1, (double?)null)); // Construct the substrate using a plain sigmoid as the phenome's // activation function. All weights under 0.2 will not generate // connections in the final phenome. List<ActivationFunctionInfo> fnList = new List<ActivationFunctionInfo>(5); fnList.Add(new ActivationFunctionInfo(0, 0.2, Linear.__DefaultInstance)); fnList.Add(new ActivationFunctionInfo(1, 0.2, BipolarSigmoid.__DefaultInstance)); fnList.Add(new ActivationFunctionInfo(2, 0.2, Gaussian.__DefaultInstance)); fnList.Add(new ActivationFunctionInfo(3, 0.2, Sine.__DefaultInstance)); fnList.Add(new ActivationFunctionInfo(4, 0.2, PlainSigmoid.__DefaultInstance)); var activationFnLib = new DefaultActivationFunctionLibrary(fnList); Substrate substrate = new Substrate(nodeSetList, activationFnLib, 4, 0.2, 5, nodeSetMappingList); // Create genome decoder. Decodes to a neural network packaged with // an activation scheme that defines a fixed number of activations per evaluation. IGenomeDecoder<NeatGenome, IBlackBox> genomeDecoder = new HyperNeatDecoder(substrate, NetworkActivationScheme.CreateCyclicFixedTimestepsScheme(4), NetworkActivationScheme.CreateCyclicFixedTimestepsScheme(4), false); return genomeDecoder; }
private void AddNode(SubstrateNodeSet nodeSet, uint id, double x, double y, double z) { nodeSet.NodeList.Add(new SubstrateNode(id, new double[] {x, y, z})); }
/// <summary> /// Create a genome decoder for the experiment. /// </summary> public IGenomeDecoder<NeatGenome,IBlackBox> CreateGenomeDecoder() { // Create HyperNEAT network substrate. //-- Create input layer nodes. SubstrateNodeSet inputLayer = new SubstrateNodeSet(13); //-- Hip joint inputs. // Left hip joint. AddNode(inputLayer, 1, -1.0, +1.0, -1.0); // Angular velocity. AddNode(inputLayer, 2, -0.5, +1.0, -1.0); // Angle. // Right hip joint. AddNode(inputLayer, 3, +0.5, +1.0, -1.0); // Angle. AddNode(inputLayer, 4, +1.0, +1.0, -1.0); // Angular velocity. //-- Knee joint inputs. // Left knee joint. AddNode(inputLayer, 5, -1.0, -1.0, -1.0); // Angular velocity. AddNode(inputLayer, 6, -0.5, -1.0, -1.0); // Angle. // Right knee joint. AddNode(inputLayer, 7, +0.5, -1.0, -1.0); // Angular velocity. AddNode(inputLayer, 8, +1.0, -1.0, -1.0); // Angle. //-- Torso inputs. AddNode(inputLayer, 9, 0.0, +1.0, -1.0); // Torso elevation. AddNode(inputLayer, 10, 0.0, +0.75, -1.0); // Torso angle. AddNode(inputLayer, 11, 0.0, +0.5, -1.0); // Torso angular velocity. AddNode(inputLayer, 12, 0.0, +0.25, -1.0); // Velocity X. AddNode(inputLayer, 13, 0.0, 0.0, -1.0); // Velocity Y. //-- Output layer nodes. SubstrateNodeSet outputLayer = new SubstrateNodeSet(4); AddNode(outputLayer, 14, -1.0, +1.0, +1.0); // Left hip torque. AddNode(outputLayer, 15, +1.0, +1.0, +1.0); // Right hip torque. AddNode(outputLayer, 16, -1.0, -1.0, +1.0); // Left knee torque. AddNode(outputLayer, 17, +1.0, -1.0, +1.0); // Right knee torque. //-- Hidden layer nodes. SubstrateNodeSet h1Layer = new SubstrateNodeSet(4); AddNode(h1Layer, 18, -1.0, +1.0, 0.0); AddNode(h1Layer, 19, +1.0, +1.0, 0.0); AddNode(h1Layer, 20, -1.0, -1.0, 0.0); AddNode(h1Layer, 21, +1.0, -1.0, 0.0); // Connect up layers. List<SubstrateNodeSet> nodeSetList = new List<SubstrateNodeSet>(2); nodeSetList.Add(inputLayer); nodeSetList.Add(outputLayer); nodeSetList.Add(h1Layer); List<NodeSetMapping> nodeSetMappingList = new List<NodeSetMapping>(1); nodeSetMappingList.Add(NodeSetMapping.Create(0, 1, (double?)null)); // Input -> Output. nodeSetMappingList.Add(NodeSetMapping.Create(0, 2, (double?)null)); // Input -> Hidden. nodeSetMappingList.Add(NodeSetMapping.Create(2, 1, (double?)null)); // Hidden -> Output. nodeSetMappingList.Add(NodeSetMapping.Create(1, 2, (double?)null)); // Output -> Hidden // Construct substrate. Substrate substrate = new Substrate(nodeSetList, DefaultActivationFunctionLibrary.CreateLibraryNeat(SteepenedSigmoid.__DefaultInstance), 0, 0.2, 5, nodeSetMappingList); // Create genome decoder. Decodes to a neural network packaged with an activation scheme that defines a fixed number of activations per evaluation. IGenomeDecoder<NeatGenome,IBlackBox> genomeDecoder = new HyperNeatDecoder(substrate, _activationSchemeCppn, _activationScheme, _lengthCppnInput); return genomeDecoder; }
/// <summary> /// Creates a genome decoder. We split this code into a separate method so that it can be re-used by the problem domain visualization code /// (it needs to decode genomes to phenomes in order to create a visualization). /// </summary> /// <param name="visualFieldResolution">The visual field's pixel resolution, e.g. 11 means 11x11 pixels.</param> /// <param name="lengthCppnInput">Indicates if the CPPNs being decoded have an extra input for specifying connection length.</param> public IGenomeDecoder<NeatGenome,IBlackBox> CreateGenomeDecoder(int visualFieldResolution, bool lengthCppnInput) { // Create two layer 'sandwich' substrate. int pixelCount = visualFieldResolution * visualFieldResolution; double pixelSize = BoxesVisualDiscriminationEvaluator.VisualFieldEdgeLength / visualFieldResolution; double originPixelXY = -1 + (pixelSize/2.0); SubstrateNodeSet inputLayer = new SubstrateNodeSet(pixelCount); SubstrateNodeSet outputLayer = new SubstrateNodeSet(pixelCount); // Node IDs start at 1. (bias node is always zero). uint inputId = 1; uint outputId = (uint)(pixelCount + 1); double yReal = originPixelXY; for(int y=0; y<visualFieldResolution; y++, yReal += pixelSize) { double xReal = originPixelXY; for(int x=0; x<visualFieldResolution; x++, xReal += pixelSize, inputId++, outputId++) { inputLayer.NodeList.Add(new SubstrateNode(inputId, new double[] {xReal, yReal, -1.0})); outputLayer.NodeList.Add(new SubstrateNode(outputId, new double[] {xReal, yReal, 1.0})); } } List<SubstrateNodeSet> nodeSetList = new List<SubstrateNodeSet>(2); nodeSetList.Add(inputLayer); nodeSetList.Add(outputLayer); // Define connection mappings between layers/sets. List<NodeSetMapping> nodeSetMappingList = new List<NodeSetMapping>(1); nodeSetMappingList.Add(NodeSetMapping.Create(0, 1,(double?)null)); // Construct substrate. Substrate substrate = new Substrate(nodeSetList, DefaultActivationFunctionLibrary.CreateLibraryNeat(SteepenedSigmoid.__DefaultInstance), 0, 0.2, 5, nodeSetMappingList); // Create genome decoder. Decodes to a neural network packaged with an activation scheme that defines a fixed number of activations per evaluation. IGenomeDecoder<NeatGenome,IBlackBox> genomeDecoder = new HyperNeatDecoder(substrate, _activationSchemeCppn, _activationScheme, lengthCppnInput); return genomeDecoder; }
/// <summary> /// Returns an estimate/hint for the number of connections that would be created between the provided source and target node sets. /// </summary> public int GetConnectionCountHint(SubstrateNodeSet srcNodeSet, SubstrateNodeSet tgtNodeSet) { if(null == _maximumConnectionDistance) { return srcNodeSet.NodeList.Count * tgtNodeSet.NodeList.Count; } int count = 0; foreach(SubstrateConnection conn in GenerateConnections(srcNodeSet, tgtNodeSet)) { count++; } return count; }
/// <summary> /// Creates a new HyperNEAT genome decoder that can be used to convert a genome into a phenome. /// </summary> public IGenomeDecoder<NeatGenome, IBlackBox> CreateGenomeDecoder() { // Create an input and an output layer for the HyperNEAT // substrate. Each layer corresponds to the game board // with 9 squares. SubstrateNodeSet inputLayer = new SubstrateNodeSet(9); SubstrateNodeSet outputLayer = new SubstrateNodeSet(9); // Each node in each layer needs a unique ID. // The input nodes use ID range [1,9] and // the output nodes use [10,18]. uint inputId = 1, outputId = 10; // The game board is represented as a 2-dimensional plane. // Each square is at -1, 0, or 1 in the x and y axis. // Thus, the game board looks like this: // // (-1,1) | (0,1) | (1,1) // (-1,0) | (0,0) | (1,0) // (-1,-1) | (0,-1) | (1,-1) // // Note that the NeatPlayer class orders the board from // left to right, then top to bottom. So we need to create // nodes with the following IDs: // // 1 | 2 | 3 // 4 | 5 | 6 // 7 | 8 | 9 // for(int x = -1; x <= 1; x++) for (int y = 1; y >= -1; y--, inputId++, outputId++) { inputLayer.NodeList.Add(new SubstrateNode(inputId, new double[] { x, y })); outputLayer.NodeList.Add(new SubstrateNode(outputId, new double[] { x, y })); } List<SubstrateNodeSet> nodeSetList = new List<SubstrateNodeSet>(2); nodeSetList.Add(inputLayer); nodeSetList.Add(outputLayer); // Define a connection mapping from the input layer to the output layer. List<NodeSetMapping> nodeSetMappingList = new List<NodeSetMapping>(1); nodeSetMappingList.Add(NodeSetMapping.Create(0, 1, (double?)null)); // Construct the substrate using a steepened sigmoid as the phenome's // activation function. All weights under 0.2 will not generate // connections in the final phenome. Substrate substrate = new Substrate(nodeSetList, DefaultActivationFunctionLibrary.CreateLibraryCppn(), 0, 0.2, 5, nodeSetMappingList); // Create genome decoder. Decodes to a neural network packaged with // an activation scheme that defines a fixed number of activations per evaluation. IGenomeDecoder<NeatGenome, IBlackBox> genomeDecoder = new HyperNeatDecoder(substrate, _activationSchemeCppn, _activationScheme, false); return genomeDecoder; }
/// <summary> /// Create a genome decoder for the experiment. /// </summary> protected override IGenomeDecoder<NeatGenome, IBlackBox> CreateHyperNeatGenomeDecoder() { // Create HyperNEAT network substrate. uint nodeId = 1; //-- Create input layer nodes. SubstrateNodeSet inputLayer = new SubstrateNodeSet(_dataset.InputCount); for (var i = 0; i < _dataset.InputCount; i++) { inputLayer.NodeList.Add(new SubstrateNode(nodeId++, SetInputNodePosition(i).Extend(-1))); } //-- Create output layer nodes. var outputLayers = new SubstrateNodeSet[nbClusters]; for (var i = 0; i < nbClusters; i++) { outputLayers[i] = new SubstrateNodeSet(1); outputLayers[i].NodeList.Add(new SubstrateNode(nodeId++, SetOutputNodePosition(i).Extend(+1 + i))); } //-- Create hidden layer nodes. SubstrateNodeSet hiddenLayer = null; if (HiddenNodesCount > 0) { hiddenLayer = new SubstrateNodeSet(HiddenNodesCount); for (var i = 0; i < HiddenNodesCount; i++) { hiddenLayer.NodeList.Add(new SubstrateNode(nodeId++, SetHiddenNodePosition(i).Extend(0))); } } // Connect up layers. List<SubstrateNodeSet> nodeSetList = new List<SubstrateNodeSet>(2 + nbClusters + (HiddenNodesCount > 0 ? 1 : 0)); nodeSetList.Add(inputLayer); for (var i = 0; i < nbClusters; i++) { nodeSetList.Add(outputLayers[i]); } if (HiddenNodesCount > 0) { nodeSetList.Add(hiddenLayer); } List<NodeSetMapping> nodeSetMappingList = new List<NodeSetMapping>(nbClusters * (1 + (HiddenNodesCount > 0 ? 2 : 0))); var inputIdx = 0; var hiddenIdx = nbClusters + 1; for (var i = 0; i < nbClusters; i++) { var outputIdx = i + 1; if (HiddenNodesCount > 0) { nodeSetMappingList.Add(NodeSetMapping.Create(inputIdx, hiddenIdx, (double?)null)); // Input -> Hidden. nodeSetMappingList.Add(NodeSetMapping.Create(hiddenIdx, outputIdx, (double?)null)); // Hidden-> Output. nodeSetMappingList.Add(NodeSetMapping.Create(inputIdx, outputIdx, (double?)null)); // Input -> Output. } else { nodeSetMappingList.Add(NodeSetMapping.Create(inputIdx, outputIdx, (double?)null)); // Input -> Output. } } // Construct substrate. Substrate substrate = new Substrate(nodeSetList, DefaultActivationFunctionLibrary.CreateLibraryNeat(SteepenedSigmoid.__DefaultInstance), 0, 0.2, 5, nodeSetMappingList); // Create genome decoder. Decodes to a neural network packaged with an activation scheme that defines a fixed number of activations per evaluation. IGenomeDecoder<NeatGenome, IBlackBox> genomeDecoder = new HyperNeatDecoder(substrate, _activationSchemeCppn, _activationScheme, _lengthCppnInput); return genomeDecoder; }
/// <summary> /// Create a genome decoder for the experiment. /// </summary> protected override IGenomeDecoder<NeatGenome, IBlackBox> CreateHyperNeatGenomeDecoder() { // Create HyperNEAT network substrate. uint nodeId = 1; //-- Create input layer nodes. var inputLayer = new SubstrateNodeSet(nbInputs * f2); for (var i = 0; i < nbInputs; i++) { for (var j = 0; j < f; j++) { for (var k = 0; k < f; k++) { if (filter[j, k]) { var x = (double)j / f - 0.5; var y = (double)k / f - 0.5; inputLayer.NodeList.Add(new SubstrateNode(nodeId++, new double[] { x, y, -1 - i })); } } } } //-- Create hidden layer nodes. var hiddenLayers = new SubstrateNodeSet[nbClusters]; for (var i = 0; i < nbClusters; i++) { hiddenLayers[i] = new SubstrateNodeSet(f2); for (var j = 0; j < f; j++) { for (var k = 0; k < f; k++) { if (filter[j, k]) { var x = (double)j / f - 0.5; var y = (double)k / f - 0.5; hiddenLayers[i].NodeList.Add(new SubstrateNode(nodeId++, new double[] { x, y, 0 })); } } } } //-- Create output layer nodes. var outputLayers = new SubstrateNodeSet[nbClusters]; for (var i = 0; i < nbClusters; i++) { outputLayers[i] = new SubstrateNodeSet(f2); for (var j = 0; j < f; j++) { for (var k = 0; k < f; k++) { if (filter[j, k]) { var x = (double)j / f - 0.5; var y = (double)j / f - 0.5; outputLayers[i].NodeList.Add(new SubstrateNode(nodeId++, new double[] { x, y, +1 + i })); } } } } // Connect up layers. List<SubstrateNodeSet> nodeSetList = new List<SubstrateNodeSet>(1 + 2 * nbClusters); nodeSetList.Add(inputLayer); foreach (var layer in hiddenLayers) { nodeSetList.Add(layer); } foreach (var layer in outputLayers) { nodeSetList.Add(layer); } List<NodeSetMapping> nodeSetMappingList = new List<NodeSetMapping>(2 * nbClusters); for (int i = 0; i < nbClusters; i++) { var inputLayerIdx = 0; var hiddenLayerIdx = 1 + i; var outputLayerIdx = 1 + nbClusters + i; nodeSetMappingList.Add(NodeSetMapping.Create(inputLayerIdx, hiddenLayerIdx, (double?)null)); nodeSetMappingList.Add(NodeSetMapping.Create(hiddenLayerIdx, outputLayerIdx, (double?)null)); } // Construct substrate. Substrate substrate = new Substrate(nodeSetList, DefaultActivationFunctionLibrary.CreateLibraryNeat(SteepenedSigmoid.__DefaultInstance), 0, 0.2, 5, nodeSetMappingList); // Create genome decoder. Decodes to a neural network packaged with an activation scheme that defines a fixed number of activations per evaluation. IGenomeDecoder<NeatGenome, IBlackBox> genomeDecoder = new HyperNeatDecoder(substrate, _activationSchemeCppn, _activationScheme, _lengthCppnInput); return genomeDecoder; }
public IGenomeDecoder<NeatGenome, IBlackBox> CreateGenomeDecoder(bool lengthCppnInput) { // Create two layer sandwhich substract substrate. Inputs on bottom of cube and Outputs are on the top. SubstrateNodeSet inputLayer = new SubstrateNodeSet(Constants.INPUT_SIZE); SubstrateNodeSet outputLayer = new SubstrateNodeSet(Constants.OUTPUT_SIZE); for (uint height = 0; height < Constants.INPUT_HEIGHT; height++) { for (uint width = 0; width < Constants.INPUT_WIDTH; width++) { // start with 1 because of the bias node is 0 uint inputID = (height * Constants.INPUT_WIDTH) + width + 1; // Get X and Y positions on the hypercube. double posX = -1.0 + ((width * 1.0D / Constants.INPUT_WIDTH) * 2); double posY = -1.0 + ((height * 1.0D / Constants.INPUT_HEIGHT) * 2); // Add nodes to inputs inputLayer.NodeList.Add(new SubstrateNode(inputID, new double[] { posX, posY, -1.0 })); } } for (uint height = 0; height < Constants.OUTPUT_HEIGHT; height++) { for (uint width = 0; width < Constants.OUTPUT_WIDTH; width++) { // start with INPUT_SIZE + 1 because id's need to be unique uint outputID = Constants.INPUT_SIZE + (height * Constants.OUTPUT_WIDTH) + width + 1; // Get X and Y positions on the hypercube. double posX = -1.0 + ((width * 1.0D / Constants.OUTPUT_WIDTH) * 2); double posY = -1.0 + ((height * 1.0D / Constants.OUTPUT_HEIGHT) * 2); // Add nodes to ouputs outputLayer.NodeList.Add(new SubstrateNode(outputID, new double[] { posX, posY, 1.0 })); } } List<SubstrateNodeSet> nodeSetList = new List<SubstrateNodeSet>(2); nodeSetList.Add(inputLayer); nodeSetList.Add(outputLayer); // Define connection mappings between layers/sets. List<NodeSetMapping> nodeSetMappingList = new List<NodeSetMapping>(1); nodeSetMappingList.Add(NodeSetMapping.Create(0, 1, (double?)null)); // Construct substrate. Substrate substrate = new Substrate(nodeSetList, GetCppnActivationFunctionLibrary(), 0, Constants.THRESHOLD_WEIGHT, Constants.MAX_WEIGHT, nodeSetMappingList); // Create genome decoder. Decodes to a neural network packaged with an activation scheme that defines a fixed number of activations per evaluation. IGenomeDecoder<NeatGenome, IBlackBox> genomeDecoder = new HyperNeatDecoder(substrate, _activationSchemeCppn, _activationScheme, lengthCppnInput); return genomeDecoder; }
/// <summary> /// Creates a genome decoder. We split this code into a separate method so that it can be re-used by the problem domain visualization code /// (it needs to decode genomes to phenomes in order to create a visualization). /// </summary> /// <param name="visualFieldResolution">The visual field's pixel resolution, e.g. 11 means 11x11 pixels.</param> /// <param name="lengthCppnInput">Indicates if the CPPNs being decoded have an extra input for specifying connection length.</param> public IGenomeDecoder<NeatGenome,IBlackBox> CreateGenomeDecoder(int visualFieldResolution, bool lengthCppnInput) { // Create two layer 'sandwich' substrate. int pixelCount = visualFieldResolution * visualFieldResolution; double pixelSize = BoxesVisualDiscriminationEvaluator.VisualFieldEdgeLength / visualFieldResolution; double originPixelXY = -1 + (pixelSize/2.0); SubstrateNodeSet inputLayer = new SubstrateNodeSet(pixelCount); SubstrateNodeSet outputLayer = new SubstrateNodeSet(pixelCount); // Node IDs start at 1. (bias node is always zero). uint inputId = 1; uint outputId = (uint)(pixelCount + 1); double yReal = originPixelXY; for(int y=0; y<visualFieldResolution; y++, yReal += pixelSize) { double xReal = originPixelXY; for(int x=0; x<visualFieldResolution; x++, xReal += pixelSize, inputId++, outputId++) { inputLayer.NodeList.Add(new SubstrateNode(inputId, new double[] {xReal, yReal, -1.0})); outputLayer.NodeList.Add(new SubstrateNode(outputId, new double[] {xReal, yReal, 1.0})); } } /* ////////////////////////////////////////////////////////////////////////////// // Create two layer substrate. SubstrateNodeSet inputLayer = new SubstrateNodeSet(Constants.INPUT_SIZE); SubstrateNodeSet outputLayer = new SubstrateNodeSet(Constants.FULLY_CONNECTED_SIZE); // Inputs to Outputs Mapping // 1 1 2 2 3 3 // 1 2 3 1 1 2 2 3 3 // 4 5 6 ---> 4 4 5 5 6 6 // 7 8 9 4 4 5 5 6 6 // 7 7 8 8 9 9 // 7 7 8 8 9 9 for (uint width = 0; width < Constants.INPUT_WIDTH; width++) { for (uint height = 0; height < Constants.INPUT_HEIGHT; height++) { // start + 1 because of bias node uint inputID = (width * Constants.INPUT_HEIGHT) + height + 1; inputLayer.NodeList.Add(new SubstrateNode(inputID, new double[] { inputID })); } } // we're fully connected so we will have NEXT_LAYER_SIZE * IMAGE_SIZE weights. This is a lot. yes. for (uint height = 0; height < Constants.OUTPUT_SIZE; height++) { for (uint width = 0; width < Constants.INPUT_SIZE; width++) { uint outputID = Constants.INPUT_SIZE + (height * Constants.INPUT_SIZE) + width + 1; outputLayer.NodeList.Add(new SubstrateNode(outputID, new double[] { outputID })); } } /////////////////////////////////////////////////////////////////////////// */ List<SubstrateNodeSet> nodeSetList = new List<SubstrateNodeSet>(2); nodeSetList.Add(inputLayer); nodeSetList.Add(outputLayer); // Define connection mappings between layers/sets. List<NodeSetMapping> nodeSetMappingList = new List<NodeSetMapping>(1); nodeSetMappingList.Add(NodeSetMapping.Create(0, 1,(double?)null)); // Construct substrate. //Substrate substrate = new Substrate(nodeSetList, DefaultActivationFunctionLibrary.CreateLibraryNeat(SteepenedSigmoid.__DefaultInstance), 0, 0.2, 5, nodeSetMappingList); Substrate substrate = new Substrate(nodeSetList, DefaultActivationFunctionLibrary.CreateLibraryCppn(), 0, 0.2, 5, nodeSetMappingList); // Create genome decoder. Decodes to a neural network packaged with an activation scheme that defines a fixed number of activations per evaluation. IGenomeDecoder<NeatGenome,IBlackBox> genomeDecoder = new HyperNeatDecoder(substrate, _activationSchemeCppn, _activationScheme, lengthCppnInput); return genomeDecoder; }
/// <summary> /// Returns an IEnumerable that yields the mappings/connections defined by the mapping function (from the source nodes to /// the target nodes) as a sequence. The alternative of returning a list would require a very long list in extreme scenarios; /// this approach minimizes down memory usage. /// </summary> public IEnumerable <SubstrateConnection> GenerateConnections(SubstrateNodeSet srcNodeSet, SubstrateNodeSet tgtNodeSet) { // Test for scenario where srcNodeSet and tgtNodeSet are the same node set, that is, we are creating // connections within a nodeset and therefore we need to test (and honour) _allowLocalRecurrentConnections. if (srcNodeSet == tgtNodeSet) { // Mapping between nodes within a single node set. // Break the inner loop into two. This avoids having to make the local recurrent test connection // for every node pair - we only test when we actually have the same node as source and target. IList <SubstrateNode> nodeList = srcNodeSet.NodeList; int count = nodeList.Count; for (int i = 0; i < count; i++) { // Loop over all nodes prior to the i'th. SubstrateNode srcNode = nodeList[i]; for (int j = 0; j < i; j++) { if (_testNodePair(srcNode, nodeList[j])) { yield return(new SubstrateConnection(srcNode, nodeList[j])); } } // Test for local recurrent connection. if (_allowLocalRecurrentConnections && _testNodePair(srcNode, srcNode)) { yield return(new SubstrateConnection(srcNode, srcNode)); } // Loop over all nodes after the i'th. for (int j = i + 1; j < count; j++) { if (_testNodePair(srcNode, nodeList[j])) { yield return(new SubstrateConnection(srcNode, nodeList[j])); } } } } else { // Mapping between nodes in two distinct node sets. foreach (SubstrateNode srcNode in srcNodeSet.NodeList) { foreach (SubstrateNode tgtNode in tgtNodeSet.NodeList) { if (_testNodePair(srcNode, tgtNode)) { yield return(new SubstrateConnection(srcNode, tgtNode)); } } } } }