/// <summary> /// Adds new connections for the specified node for the parent and child nodes. /// </summary> /// <param name="network">Current network.</param> /// <param name="node">Neuron being added.</param> /// <param name="parentNodes">Parent nodes that this neuron is connected with.</param> /// <param name="childNodes">Child nodes that this neuron is connected to.</param> /// <param name="epsilon">Weight initialization parameter.</param> /// <returns></returns> public static Network AddConnections(this Network network, Neuron node, IEnumerable <Neuron> parentNodes, IEnumerable <Neuron> childNodes, double epsilon = double.NaN) { if (epsilon == double.NaN) { epsilon = Edge.GetEpsilon(node.ActivationFunction.Minimum, node.ActivationFunction.Maximum, parentNodes.Count(), childNodes.Count()); } if (parentNodes != null) { for (int i = 0; i < parentNodes.Count(); i++) { network.AddEdge(Edge.Create(parentNodes.ElementAt(i), node, epsilon: epsilon)); } } if (childNodes != null) { for (int j = 0; j < childNodes.Count(); j++) { network.AddEdge(Edge.Create(node, childNodes.ElementAt(j), epsilon: epsilon)); } } return(network); }
/// <summary> /// Creates a new fully connected deep neural network based on the supplied size and depth parameters. /// </summary> /// <param name="network">New network instance.</param> /// <param name="inputLayer">Neurons in the input layer.</param> /// <param name="outputLayer">Neurons in the output layer.</param> /// <param name="activationFunction">Activation function for the hidden and output layers.</param> /// <param name="outputFunction">(Optional) Output function of the the Nodes in the output layer (overrides the Activation function).</param> /// <param name="fnNodeInitializer">(Optional) Function to call for initializing new Nodes, where int1: layer, int2: node index, NodeType: node type.</param> /// <param name="fnWeightInitializer">(Optional) Function to call for initializing the weights of each connection (including bias nodes). /// <para>Where int1 = Source layer (0 is input layer), int2 = Source Node, int3 = Target node in the next layer.</para></param> /// <param name="lossFunction">Loss function to apply in computing the error cost.</param> /// <param name="epsilon">Weight initialization parameter for random weight selection. Weight will be in the range of: -epsilon to +epsilon.</param> /// <param name="hiddenLayers">An array of hidden neuron dimensions, where each element is the size of each layer (excluding bias nodes).</param> /// <returns>Returns an untrained neural network model.</returns> public static Network Create(this Network network, int inputLayer, int outputLayer, IFunction activationFunction, IFunction outputFunction = null, Func <int, int, NodeType, Neuron> fnNodeInitializer = null, Func <int, int, int, double> fnWeightInitializer = null, ILossFunction lossFunction = null, double epsilon = double.NaN, params int[] hiddenLayers) { IFunction ident = new Ident(); if (hiddenLayers == null || hiddenLayers.Length == 0) { hiddenLayers = new int[] { (int)System.Math.Ceiling((inputLayer + outputLayer + 1) * (2.0 / 3.0)) } } ; List <double> layers = new List <double>(); layers.Add(inputLayer); foreach (int l in hiddenLayers) { layers.Add(l + 1); } layers.Add(outputLayer); if (fnNodeInitializer == null) { fnNodeInitializer = new Func <int, int, NodeType, Neuron>((i, j, type) => new Neuron()); } if (fnWeightInitializer == null) { fnWeightInitializer = new Func <int, int, int, double>((l, i, j) => { double inputs = (l > 0 ? layers[l - 1] : 0); double outputs = (l < layers.Count - 1 ? layers[l + 1] : 0); double eps = (double.IsNaN(epsilon) ? Edge.GetEpsilon(activationFunction.Minimum, activationFunction.Maximum, inputs, outputs) : epsilon); return(Edge.GetWeight(eps)); }); } // creating input nodes network.In = new Neuron[inputLayer + 1]; network.In[0] = network.AddNode(new Neuron(true) { Label = "B0", ActivationFunction = ident, NodeId = 0, LayerId = 0 }); for (int i = 1; i < inputLayer + 1; i++) { network.In[i] = fnNodeInitializer(0, i, NodeType.Input); network.In[i].Label = (network.In[i].Label ?? string.Format("I{0}", i)); network.In[i].ActivationFunction = (network.In[i].ActivationFunction ?? ident); network.In[i].LayerId = 0; network.In[i].NodeId = i; network.AddNode(network.In[i]); } Neuron[] last = null; for (int layerIdx = 0; layerIdx < hiddenLayers.Length; layerIdx++) { // creating hidden nodes Neuron[] layer = new Neuron[hiddenLayers[layerIdx] + 1]; layer[0] = network.AddNode(new Neuron(true) { Label = $"B{layerIdx + 1}", ActivationFunction = ident, LayerId = layerIdx + 1, NodeId = 0 }); for (int i = 1; i < layer.Length; i++) { layer[i] = fnNodeInitializer(layerIdx + 1, i, NodeType.Hidden); layer[i].Label = (layer[i].Label ?? String.Format("H{0}.{1}", layerIdx + 1, i)); layer[i].ActivationFunction = (layer[i].ActivationFunction ?? activationFunction); layer[i].LayerId = layerIdx + 1; layer[i].NodeId = i; network.AddNode(layer[i]); } if (layerIdx > 0 && layerIdx < hiddenLayers.Length) { // create hidden to hidden (full) for (int i = 0; i < last.Length; i++) { for (int x = 1; x < layer.Length; x++) { network.AddEdge(Edge.Create(last[i], layer[x], weight: fnWeightInitializer(layerIdx, i, x), epsilon: epsilon)); } } } else if (layerIdx == 0) { // create input to hidden (full) for (int i = 0; i < network.In.Length; i++) { for (int j = 1; j < layer.Length; j++) { network.AddEdge(Edge.Create(network.In[i], layer[j], weight: fnWeightInitializer(layerIdx, i, j), epsilon: epsilon)); } } } last = layer; } // creating output nodes network.Out = new Neuron[outputLayer]; for (int i = 0; i < outputLayer; i++) { network.Out[i] = fnNodeInitializer(hiddenLayers.Length + 1, i, NodeType.Output); network.Out[i].Label = (network.Out[i].Label ?? String.Format("O{0}", i)); network.Out[i].ActivationFunction = (network.Out[i].ActivationFunction ?? activationFunction); network.Out[i].LayerId = hiddenLayers.Length + 1; network.Out[i].NodeId = i; network.AddNode(network.Out[i]); } // link from (last) hidden to output (full) for (int i = 0; i < network.Out.Length; i++) { for (int j = 0; j < last.Length; j++) { network.AddEdge(Edge.Create(last[j], network.Out[i], weight: fnWeightInitializer(hiddenLayers.Length, j, i), epsilon: epsilon)); } } network.OutputFunction = outputFunction; network.LossFunction = (lossFunction ?? network.LossFunction); return(network); }