public double Train(double[] input, double[] expectedOutput, double[]?actualOutput, double learningRate, IErrorFunction errorFunction) { if (input.Length != InputSize) { throw new ArgumentException("Expected vector to be of size " + InputSize + ".", nameof(input)); } if (expectedOutput.Length != OutputSize) { throw new ArgumentException("Expected vector to be of size " + OutputSize + ".", nameof(expectedOutput)); } var vectors = new double[Layers.Count + 1][]; vectors[0] = input; for (int i = 0; i < Layers.Count; i++) { var layer = Layers[i]; if (actualOutput == null || i != Layers.Count - 1) { vectors[i + 1] = ArraySource(layer.OutputSize); } else { vectors[i + 1] = actualOutput; } layer.Evaluate(vectors[i], vectors[i + 1]); } var output = vectors[vectors.Length - 1]; if (output.Length != OutputSize) { throw new InvalidOperationException("Internal error."); } var outputErrorSignal = ArraySource(OutputSize); var error = errorFunction.Derivative(expectedOutput, output, outputErrorSignal); for (int i = Layers.Count - 1; i >= 0; i--) { var layer = Layers[i]; var inputErrorSignal = ArraySource(layer.InputSize); layer.Train(vectors[i], vectors[i + 1], outputErrorSignal, inputErrorSignal, learningRate); outputErrorSignal = inputErrorSignal; } return(error); }
public void Backward(double[] target) { //輸出層需要使用誤差函數來定義誤差 for (int i = 0; i < layers.Last().neurons.Length; i++) { layers.Last().neurons[i].outputDer = errorFunction.Derivative(layers.Last().neurons[i].output, target[i]); } //從隱藏層最後一層往前回饋直到 輸入層(不含) for (int currentLayerIndex = layers.Count - 1; currentLayerIndex >= 1; currentLayerIndex--) { Layer currentLayer = layers[currentLayerIndex]; //算出每個神經元的誤差導數 //1: 總輸入 //2: 輸入權重 for (int neuronIndex = 0; neuronIndex < currentLayer.neurons.Length; neuronIndex++) { Neuron currentNeuron = currentLayer.neurons[neuronIndex]; //神經元.輸入導數 = 神經元.輸出導數 * 激勵導數函式(神經元.總輸入) currentNeuron.inputDer = currentNeuron.outputDer * currentNeuron.activateFunction.Derivative(currentNeuron.totalInput); //神經元.累積輸入導數 += 神經元.輸入導數 currentNeuron.accInputDer += currentNeuron.inputDer; //神經元.累積輸入導數的數量 currentNeuron.numAccumulatedDers++; } //進入神經元的每個權重的誤差導數 for (int neuronIndex = 0; neuronIndex < currentLayer.neurons.Length; neuronIndex++) { Neuron currentNeuron = currentLayer.neurons[neuronIndex]; for (int i = 0; i < currentNeuron.weight.Length; i++) { Neuron prevNeuron = layers[currentLayerIndex - 1].neurons[i]; if (currentNeuron.isDead[i]) { continue; } currentNeuron.weightErrorDer[i] = currentNeuron.inputDer * prevNeuron.output; currentNeuron.weightAccErrorDer[i] += currentNeuron.weightErrorDer[i]; currentNeuron.weightNumAccumulatedDers[i]++; } } if (currentLayerIndex == 1) { continue; } //前一層 Layer prevLayer = layers[currentLayerIndex - 1]; //前一層的每一顆 for (int i = 0; i < prevLayer.neurons.Length; i++) { Neuron prevNeuron = prevLayer.neurons[i]; //計算每個神經元的誤差導數 prevNeuron.outputDer = 0; //前一層的每根輸出連結 == 這一層的輸入連結 for (int j = 0; j < currentLayer.neurons.Length; j++) { prevNeuron.outputDer += currentLayer.neurons[j].weight[i] * currentLayer.neurons[j].inputDer; } } } }
public void Back(Vector actual) { // BFS starting at the end var s = new Stack <Neuron>(); for (var i = 0; i < _network.OutputLayer.Length; i++) { var n = _network.OutputLayer[i]; n.OutputDerivative = _errorFunction.Derivative(n.Output, actual[i]); s.Push(n); } while (s.Count != 0) { var layer = s.ToArray(); s.Clear(); // compute error derivative for (var i = 0; i < layer.Length; i++) { var n = layer[i]; n.InputDerivative = n.OutputDerivative * n.Activation.Derivative(n.Input); n.InputDerivativeSum += n.InputDerivative; n.InputDerivativeCount++; } // error derivative with respect to input weights for (var i = 0; i < layer.Length; i++) { var n = layer[i]; for (var j = 0; j < n.Inputs.Count; j++) { var inputLink = n.Inputs[j]; inputLink.ErrorDerivative = n.InputDerivative * inputLink.Source.Output; inputLink.ErrorDerivativeSum += inputLink.ErrorDerivative; inputLink.DerivativeCount++; } } for (var i = 0; i < layer.Length; i++) { var n = layer[i]; for (var j = 0; j < n.Inputs.Count; j++) { s.Push(n.Inputs[j].Source); } } if (s.Count != 0) { var prevLayer = s.ToArray(); for (var i = 0; i < prevLayer.Length; i++) { var n = prevLayer[i]; if (n.Inputs.Count == 0) { goto OUT; } } for (var i = 0; i < prevLayer.Length; i++) { var n = prevLayer[i]; n.OutputDerivative = 0.0; for (var j = 0; j < n.Outputs.Count; j++) { var outSynapse = n.Outputs[j]; n.OutputDerivative += outSynapse.Weight * outSynapse.Destination.InputDerivative; } } } OUT: ; } }