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);
        }
Esempio n. 2
0
File: NN.cs Progetto: Hundo1018/NN
        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;
                    }
                }
            }
        }
Esempio n. 3
0
        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:
                ;
            }
        }