예제 #1
0
        /// <summary>
        /// Initializes a new Network Layer.  A network layer is sub neural network made up of inputs, hidden layer(s) and an output layer.
        /// </summary>
        /// <param name="inputNodes">Number of Nodes at the input layer (includes bias Node).</param>
        /// <param name="outputNodes">Number of Nodes at the output layer.</param>
        /// <param name="isFullyConnected">Indicates whether the output layer of this network is fully connected with the next Network Layer / Network.</param>
        /// <param name="hiddenLayers">Number of Nodes in each layer and the number of layers, where the array length is the number of
        /// layers and each value is the number of Nodes in that layer.</param>
        /// <param name="fnNodeInitializer">Function for creating a new Node at each layer (zero-based) and Node index (zero-based).  The 0 index layer corresponds to the input layer.</param>
        /// <param name="isAutoencoder">Determines whether this Network layer is an auto-encoding layer.</param>
        /// <param name="layerConnections">(Optional) Connection properties for this Network where the first dimension is the layer, second the Node index in that layer,
        /// and third the Node indexes in the next layer to pair with.<para>For example: 1 => 2 => [2, 3] will link Node 2 in layer 1 to Nodes 2 + 3 in layer 2.</para></param>
        /// <param name="createBiasNodes">(Optional) Indicates whether bias nodes are automatically created (thus bypassing the <paramref name="fnNodeInitializer"/> function).</param>
        /// <param name="linkBiasNodes">(Optional) Indicates whether bias nodes in hidden layers are automatically linked to their respective hidden nodes.
        /// <para>If this is set to True, it will override any bias node connections specified in parameter <paramref name="layerConnections"/></para></param>
        public NetworkLayer(int inputNodes, int outputNodes, bool isFullyConnected, int[] hiddenLayers, Func <int, int, Neuron> fnNodeInitializer,
                            bool isAutoencoder = false, int[][][] layerConnections = null, bool createBiasNodes = true, bool linkBiasNodes = true) : base()
        {
            this.IsFullyConnected = isFullyConnected;
            this.IsAutoencoder    = isAutoencoder;

            if (!this.IsFullyConnected && (layerConnections == null || layerConnections.Length != (2 + hiddenLayers.Length)))
            {
                throw new ArgumentException("Connections must be supplied when the output layer is not fully connected with the next Network Layer.", nameof(layerConnections));
            }

            IFunction ident = new Ident();

            this.In    = new Neuron[inputNodes];
            this.In[0] = new Neuron {
                Label = "B0", ActivationFunction = ident
            };

            // create input nodes
            for (int i = 1; i < this.In.Length; i++)
            {
                this.In[i] = fnNodeInitializer(0, i);
            }

            // create hidden layers
            Neuron[][] hiddenNodes = new Neuron[hiddenLayers.Length][];

            for (int hiddenLayer = 0; hiddenLayer < hiddenLayers.Count(); hiddenLayer++)
            {
                hiddenNodes[hiddenLayer] = new Neuron[hiddenLayers[hiddenLayer]];

                for (int h = 0; h < hiddenLayers[hiddenLayer]; h++)
                {
                    if (h == 0)
                    {
                        // create the bias node in this layer
                        if (createBiasNodes)
                        {
                            hiddenNodes[hiddenLayer][0] = new Neuron {
                                Label = $"B{hiddenLayer + 1}", ActivationFunction = ident
                            }
                        }
                        ;
                        else
                        {
                            hiddenNodes[hiddenLayer][0] = fnNodeInitializer(hiddenLayer + 1, h);
                        }
                    }
                    else
                    {
                        // create the hidden node in this layer
                        hiddenNodes[hiddenLayer][h] = fnNodeInitializer(hiddenLayer + 1, h);
                    }
                }

                // do hidden to hidden node connections
                if (hiddenLayer > 0 && (hiddenLayer != hiddenLayers.Length - 1))
                {
                    bool useConnection = (layerConnections != null && layerConnections[hiddenLayer + 1] != null);

                    if (linkBiasNodes)
                    {
                        for (int node = 1; node < hiddenNodes[hiddenLayer].Length; node++)
                        {
                            Edge.Create(hiddenNodes[hiddenLayer - 1][0], hiddenNodes[hiddenLayer][node]);
                        }
                    }

                    // connect nodes in previous layer with this layer
                    for (int h = 0; h < hiddenLayers[hiddenLayer - 1]; h++)
                    {
                        if (linkBiasNodes && h == 0)
                        {
                            continue;
                        }

                        // check for connection properties
                        if (useConnection && layerConnections[hiddenLayer + 1].Length > h && layerConnections[hiddenLayer + 1][h] != null)
                        {
                            // use connection properties
                            foreach (int connection in layerConnections[hiddenLayer + 1][h])
                            {
                                Edge.Create(hiddenNodes[hiddenLayer - 1][h], hiddenNodes[hiddenLayer][connection]);
                            }
                        }
                    }
                }
            }

            // creating output nodes
            this.Out = new Neuron[outputNodes];
            for (int i = 0; i < outputNodes; i++)
            {
                this.Out[i] = fnNodeInitializer(hiddenLayers.Length + 1, i);
            }

            // link last hidden layer with output nodes
            for (int i = 0; i < this.Out.Length; i++)
            {
                for (int j = 0; j < hiddenNodes.Last().Length; j++)
                {
                    Edge.Create(hiddenNodes.Last().ElementAt(j), this.Out[i]);
                }
            }
        }