/// <summary> /// Receives feedback from subsequent layer neurons. As error /// information percolates back, the neuron will calculate its delta /// and partials. /// </summary> /// <param name="source">The axon sending the feedback</param> /// <param name="val">The feedback value</param> public virtual void ReceiveFeedback(double val, Axon source) { if (inputAxonIds.Count == 0) { return; } if (missingFeedback == null) { //missingFeedback = new ArrayList(outputAxonIds); missingFeedback = new Dictionary <Guid, Guid>(); foreach (Guid id in outputAxonIds) { missingFeedback[id] = id; } } missingFeedback.Remove(source.Id); feedback[outputAxonIds.IndexOf(source.Id)] = val; // feedback[(int)(outputAxonIndexes[source.Id])] = val; if (missingFeedback.Count == 0) { double delta = training.CalculateDelta(feedback, activation.Derivative(rawValue)); training.CalculatePartials(inputs, delta); foreach (var item in inputAxons) { item.Value.Feedback(delta * Weights[inputAxonIds.IndexOf(item.Key)]); } missingFeedback = null; } }
/// <summary> /// This receives an input signal from the input axon. It then /// initializes the set of missing inputs (if necessary) with the /// ids of the input axons. If the axon is one of the axons that /// has not sent its signal, it is removed from the set of /// missing axons and the input value is stored. If the size of the /// missing input set drops to zero, the output value is calculate, /// and the neuron is fired. /// </summary> /// <param name="firingAxon">The axon sending signal</param> /// <param name="val">The value firing into this neuron</param> public virtual void ReceiveSignal(Axon firingAxon, double val) { if (missingInput == null) { missingInput = new Dictionary <Guid, Guid>(); foreach (Guid id in inputAxonIds) { missingInput[id] = id; } //missingInput.AddRange(inputAxonIds); } if (missingInput[firingAxon.Id] != null) { inputs[inputAxonIds.IndexOf(firingAxon.Id)] = val; //inputs[(int)(inputAxonIndexes[firingAxon.Id])] = val; missingInput.Remove(firingAxon.Id); } if (missingInput.Count == 0) { rawValue = DotProduct(inputs, Weights); outputValue = activation.Activation(rawValue); FireNeuron(); missingInput = null; } }
/// <summary> /// Adds a new output axon to the neuron. When the neuron fires, /// all the output axons are fired with the output value. /// </summary> /// <param name="axon">The new axon</param> public void AddOutputAxon(Axon axon) { outputAxonIds.Add(axon.Id); //outputAxonIndexes[axon.Id] = outputAxonIds.Count - 1; outputAxons[axon.Id] = axon; feedback = new double[outputAxonIds.Count]; }
/// <summary> /// Connect two neurons. This method is used to /// build up connections within the network. The only connection established /// by default is the connection to the bias node. /// </summary> /// <param name="baseNeuron">A base neuron to connect</param> /// <param name="dendrite">A dendrite neuron to connect</param> public void Connect(Neuron baseNeuron, Neuron dendrite) { Axon axon = new Axon(); axon.Base = baseNeuron; axon.Dendrite = dendrite; baseNeuron.AddOutputAxon(axon); dendrite.AddInputAxon(axon); axons.Add(axon); }
/// <summary> /// Connect a neuron to the bias neuron. /// </summary> /// <param name="neuron">The bias neuron</param> private void ConnectToBias(Neuron neuron) { Axon biasAxon = new Axon(); biasAxon.Base = bias; biasAxon.Dendrite = neuron; bias.AddOutputAxon(biasAxon); neuron.AddInputAxon(biasAxon); axons.Add(biasAxon); }
/// <summary> /// Add a new input axon to the neuron. This will adjust the weights /// and inputs appropriately. Since this is normally used in neural /// construction - it re-randomizes the weights. /// </summary> /// <param name="axon">The new input Axon</param> public void AddInputAxon(Axon axon) { inputAxonIds.Add(axon.Id); // inputAxonIndexes[axon.Id] = inputAxonIds.Count - 1; inputAxons[axon.Id] = axon; Random r = new Random(); weights = new double[weights.Length + 1]; for (int i = 0; i < weights.Length; i++) { weights[i] = r.NextDouble() * 2.0 - 1.0; } inputs = new double[inputs.Length + 1]; for (int i = 0; i < weights.Length; i++) { inputs[i] = r.NextDouble(); } }
/// <summary> /// Receives feedback from subsequent layer neurons. As error /// information percolates back, the neuron will calculate its delta /// and partials. /// </summary> /// <param name="source">The axon sending the feedback</param> /// <param name="val">The feedback value</param> public virtual void ReceiveFeedback(double val, Axon source) { if(inputAxonIds.Count == 0) { return; } if(missingFeedback == null) { //missingFeedback = new ArrayList(outputAxonIds); missingFeedback = new Dictionary<Guid, Guid>(); foreach(Guid id in outputAxonIds) { missingFeedback[id] = id; } } missingFeedback.Remove(source.Id); feedback[outputAxonIds.IndexOf(source.Id)] = val; // feedback[(int)(outputAxonIndexes[source.Id])] = val; if(missingFeedback.Count == 0) { double delta = training.CalculateDelta(feedback, activation.Derivative(rawValue)); training.CalculatePartials(inputs, delta); foreach (var item in inputAxons) { item.Value.Feedback(delta * Weights[inputAxonIds.IndexOf(item.Key)]); } missingFeedback = null; } }
/// <summary> /// This receives an input signal from the input axon. It then /// initializes the set of missing inputs (if necessary) with the /// ids of the input axons. If the axon is one of the axons that /// has not sent its signal, it is removed from the set of /// missing axons and the input value is stored. If the size of the /// missing input set drops to zero, the output value is calculate, /// and the neuron is fired. /// </summary> /// <param name="firingAxon">The axon sending signal</param> /// <param name="val">The value firing into this neuron</param> public virtual void ReceiveSignal(Axon firingAxon, double val) { if(missingInput == null) { missingInput = new Dictionary<Guid, Guid>(); foreach(Guid id in inputAxonIds) { missingInput[id] = id; } //missingInput.AddRange(inputAxonIds); } if(missingInput[firingAxon.Id] != null) { inputs[inputAxonIds.IndexOf(firingAxon.Id)] = val; //inputs[(int)(inputAxonIndexes[firingAxon.Id])] = val; missingInput.Remove(firingAxon.Id); } if(missingInput.Count == 0) { rawValue = DotProduct(inputs, Weights); outputValue = activation.Activation(rawValue); FireNeuron(); missingInput = null; } }
/// <summary> /// Add a new input axon to the neuron. This will adjust the weights /// and inputs appropriately. Since this is normally used in neural /// construction - it re-randomizes the weights. /// </summary> /// <param name="axon">The new input Axon</param> public void AddInputAxon(Axon axon) { inputAxonIds.Add(axon.Id); // inputAxonIndexes[axon.Id] = inputAxonIds.Count - 1; inputAxons[axon.Id] = axon; Random r = new Random(); weights = new double[weights.Length + 1]; for(int i = 0; i < weights.Length; i++) { weights[i] = r.NextDouble() * 2.0 - 1.0; } inputs = new double[inputs.Length + 1]; for(int i = 0; i < weights.Length; i++) { inputs[i] = r.NextDouble(); } }