/// <summary>
        /// Считаем дельта-отклонение, пересчитываем веса нейронов
        /// </summary>
        /// <param name="answer"></param>
        private double CalculateDeviation(NeuralNetworkDomain neuralNet, double answer)
        {
            //Считаем значение средней квадратичной ошибки
            var outNeuron = neuralNet.Neurons.Single(n => n.NeuronType == NeuronType.OutputNeuronType);

            neuralNet.MSEcounter++;
            neuralNet.ErrorMSE += Math.Pow((answer - outNeuron.DataOut), 2);

            //Считаем дельта-отклонение для слоя вывода
            outNeuron.DeltaDeviation = DeltaOutput(answer, outNeuron.DataOut);

            CalculateHiddenLayerDeltaDeviation(neuralNet, NeuronType.SecondLayerHiddenNeuronType);

            CalculateHiddenLayerDeltaDeviation(neuralNet, NeuronType.FirstLayerHiddenNeuronType);

            //Считаем изменение веса синапсов слоя ввода
            foreach (var neuron in neuralNet.Neurons.Where(n => n.NeuronType == NeuronType.InputNeuronType))
            {
                //градиент для градиентного спуска
                double grad = 0;

                foreach (var synapse in neuron.OutputSynapses)
                {
                    var targetDeviation = synapse.OutputNeuron.DeltaDeviation;
                    grad = targetDeviation * neuron.DataOut;
                    synapse.DeltaWeight = neuralNet.LearningSpeed * grad + neuralNet.Moment * synapse.DeltaWeight;
                    synapse.Weight     += synapse.DeltaWeight;
                }
            }
            return(neuralNet.ErrorMSE / neuralNet.MSEcounter);
        }
        public CalibrationResultDomain Calibrate(NeuralNetworkDomain neuralNet, double answer)
        {
            Calculate(neuralNet);
            var error = CalculateDeviation(neuralNet, answer);

            return(new CalibrationResultDomain
            {
                Error = error,
                Result = neuralNet.Neurons.Single(n => n.NeuronType == NeuronType.OutputNeuronType).DataOut
            });
        }
        /// <summary>
        /// Считаем выходное значение проходом вперёд
        /// </summary>
        /// <param name="neuralNet"></param>
        private void Calculate(NeuralNetworkDomain neuralNet)
        {
            //Обсчитываем скрытый слой и слои вывода
            var neurons = neuralNet.Neurons
                          .Where(n => n.NeuronType != NeuronType.InputNeuronType)
                          .OrderBy(n => n.NeuronType);

            foreach (var neuron in neurons)
            {
                neuron.DataIn = 0;
                foreach (var synapse in neuron.InputSynapses)
                {
                    neuron.DataIn += synapse.InputNeuron.DataOut * synapse.Weight;
                }
                neuron.DataOut = Sigmoid(neuron.DataIn);
            }
        }
        /// <summary>
        /// Считаем дельта-отклонение для указанного слоя скрытых нейронов и изменяем веса синапсов
        /// </summary>
        /// <param name="hiddenLayerType"></param>
        private void CalculateHiddenLayerDeltaDeviation(NeuralNetworkDomain neuralNet, NeuronType hiddenLayerType)
        {
            foreach (var neuron in neuralNet.Neurons.Where(n => n.NeuronType == hiddenLayerType))
            {
                //сумма произведения всех исходящих весов и дельта-отклонения нейрона, с которым связан синапс
                double sum = 0;
                //градиент для градиентного спуска
                double grad = 0;

                foreach (var synapse in neuron.OutputSynapses)
                {
                    var targetDeviation = synapse.OutputNeuron.DeltaDeviation;
                    sum += targetDeviation * synapse.Weight;
                    grad = targetDeviation * neuron.DataOut;
                    synapse.DeltaWeight = neuralNet.LearningSpeed * grad + neuralNet.Moment * synapse.DeltaWeight;
                    synapse.Weight     += synapse.DeltaWeight;
                }
                neuron.DeltaDeviation = SigmoidDiff(neuron.DataOut) * sum;
            }
        }
 public double Reckon(NeuralNetworkDomain neuralNet)
 {
     Calculate(neuralNet);
     return(neuralNet.Neurons.Single(n => n.NeuronType == NeuronType.OutputNeuronType).DataOut);
 }