C# 当误差梯度的当前偏导数等于0时,RPROP的实现失败

C# 当误差梯度的当前偏导数等于0时,RPROP的实现失败,c#,machine-learning,neural-network,.net-core,backpropagation,C#,Machine Learning,Neural Network,.net Core,Backpropagation,我目前正在实现RPROP算法,并且发现它在解决XOR问题时无法工作。在我看来,这是因为当你给神经网络输入值时,2个输入神经元的输出为0。因此,当计算该神经元错误率的偏导数时,得到的值为0。这意味着当RPROP算法运行时,它计算出当前偏导数与前一偏导数的符号,这表示符号正确为0。因此,不计算delta,而是将前一个delta与当前偏导数的符号变化一起使用。这导致更新值为0,因此算法失败 我想知道是否有人能告诉我我到底做错了什么,因为我已经仔细阅读了算法,看到了encog的实现,并且仍然在努力解决这

我目前正在实现RPROP算法,并且发现它在解决XOR问题时无法工作。在我看来,这是因为当你给神经网络输入值时,2个输入神经元的输出为0。因此,当计算该神经元错误率的偏导数时,得到的值为0。这意味着当RPROP算法运行时,它计算出当前偏导数与前一偏导数的符号,这表示符号正确为0。因此,不计算delta,而是将前一个delta与当前偏导数的符号变化一起使用。这导致更新值为0,因此算法失败

我想知道是否有人能告诉我我到底做错了什么,因为我已经仔细阅读了算法,看到了encog的实现,并且仍然在努力解决这个问题

隐藏层的误差梯度计算如下:

public void SetNeuronErrorGradient(Neuron neuron)
    {
        neuron.ErrorGradient = neuron.OutputSynapses.Sum(a => a.OutputNeuron.ErrorGradient * a.Weight) *
                           neuron.ActivationFunction.Derivative(neuron.LatestFedValueFromInputSynapses);
    }
输出层的误差梯度计算如下:

public void SetNeuronErrorGradient(Neuron neuron, double target)
{
    neuron.ErrorGradient = CalculateErrorForOutputAgainstTarget(neuron, target) *
                       neuron.ActivationFunction.Derivative(neuron.LatestFedValueFromInputSynapses);
}
RPROP的算法实现如下,其中突触由输入神经元、输出神经元以及权重和权重增量组成:

public sealed partial class ResilientBackPropagationSynapseWeightCalculator : IUpdateSynapseWeights
{
    private static ILogger Log => LoggerProvider.For<ResilientBackPropagationSynapseWeightCalculator>();

    private readonly Dictionary<Synapse, double> synapseToPreviousPartialDerivative
        = new Dictionary<Synapse, double>(SynapseEqualityComparer.Instance());

    private readonly Dictionary<Synapse, double> synapseToPreviousDeltaWithoutDirection
        = new Dictionary<Synapse, double>(SynapseEqualityComparer.Instance());

    private ResilientBackPropagationSynapseWeightCalculator()
    {}

    public void CalculateAndUpdateInputSynapseWeights(Neuron neuron, ParallelOptions parallelOptions)
    {
        neuron.InputSynapses.ForEach(
            synapse =>
            {
                var previousPartialDerivative = GetPreviousPartialDerivativeOfSynapse(synapse);
                var currentPartialDerivative = synapse.OutputNeuron.ErrorGradient * synapse.InputNeuron.Output;

                var weightDelta = CalculateSynapseWeightDelta(
                    synapse,
                    currentPartialDerivative,
                    previousPartialDerivative);

                synapse.WeightDelta = weightDelta;
                synapse.Weight = synapse.Weight + weightDelta;
            });
    }

    private double GetPreviousPartialDerivativeOfSynapse(Synapse synapse)
    {
        if (synapseToPreviousPartialDerivative.TryGetValue(synapse, out var previousPartialDerivative))
        {
            return previousPartialDerivative;
        }

        synapseToPreviousPartialDerivative[synapse] = 0;
        return 0;
    }

    private double CalculateSynapseWeightDelta(
        Synapse synapse,
        double currentPartialDerivative,
        double previousPartialDerivative)
    {
        var errorGradientSign =
            ResilientBackPropagationHelper.Sign(currentPartialDerivative * previousPartialDerivative);

        double weightDelta;

        if (errorGradientSign > 0)
        {
            weightDelta = ResilientBackPropagationHelper
                .CalculateDeltaToContinueTowardsErrorGraidentMinimum(
                    synapse,
                    currentPartialDerivative,
                    synapseToPreviousDeltaWithoutDirection);

            synapseToPreviousPartialDerivative[synapse] = currentPartialDerivative;
        }
        else if (errorGradientSign < 0)
        {
            weightDelta = ResilientBackPropagationHelper
                .CalculateDeltaToRevertPreviousWeightAdjustment(
                    synapse,
                    currentPartialDerivative,
                    synapseToPreviousDeltaWithoutDirection);

            synapseToPreviousPartialDerivative[synapse] = 0; //0 so no adjustment next iteration.
        }
        else
        {
            weightDelta = ResilientBackPropagationHelper
                .CalculateDeltaDirection(
                    synapse,
                    currentPartialDerivative,
                    synapseToPreviousDeltaWithoutDirection);

            synapseToPreviousPartialDerivative[synapse] = currentPartialDerivative; 
        }

        return weightDelta;
    }

    public static ResilientBackPropagationSynapseWeightCalculator Create()
        => new ResilientBackPropagationSynapseWeightCalculator();
}
公共密封部分类弹性备份传播SynapseWeightCalculator:IUUpdate SynapseWeights
{
私有静态ILogger Log=>LoggerProvider.For();
专用只读词典synapseToPreviousPartialDerivative
=新字典(SynapseQualityComparer.Instance());
专用只读词典synapseToPreviousDeltaWithoutDirection
=新字典(SynapseQualityComparer.Instance());
专用弹性备份传播SynapsWeghtCalculator()
{}
public void CalculateAndedInputSynapseWeights(神经元神经元,并行选项并行选项)
{
神经元输入突触ForEach(
突触=>
{
var PreviousPartialDelivative=GetPreviousPartialDelivativeOfSynapse(突触);
var currentPartialDelivative=synapse.OutputNeuron.ErrorGradient*synapse.InputNeuron.Output;
var weightDelta=计算SynapsWeghtDelta(
突触,
当前部分派生,
先前的部分派生);
synapse.WeightDelta=WeightDelta;
突触重量=突触重量+重量增量;
});
}
私有双通道部分衍生同步(Synapse Synapse)
{
if(synapseToPreviousPartialDerivative.TryGetValue(synapse,out var previousPartialDerivative))
{
返回先前的部分派生;
}
synapseToPreviousPartialDerivative[synapse]=0;
返回0;
}
专用双计算SynapsWeghtDelta(
突触突触,
双电流部分导数,
双上一部分导数)
{
var误差梯度符号=
ResilientBackPropagationHelper.Sign(CurrentPartialDelivative*PreviousPartialDelivative);
双权三角洲;
如果(errorGradientSign>0)
{
weightDelta=ResilientBackPropagationHelper
.CalculateDeltaToContinueTowardsErrorGraidentMinimum(
突触,
当前部分派生,
SynapsetoPreviousDelta(无方向);
SynapsetoPreviousPartialDelivative[突触]=当前PartialDelivative;
}
else if(errorGradientSign<0)
{
weightDelta=ResilientBackPropagationHelper
.CalculatedEltatoRevertePreviousWeightAdjustment(
突触,
当前部分派生,
SynapsetoPreviousDelta(无方向);
synapseToPreviousPartialDerivative[synapse]=0;//0,因此下一次迭代无调整。
}
其他的
{
weightDelta=ResilientBackPropagationHelper
.CalculateDeltaDirection(
突触,
当前部分派生,
SynapsetoPreviousDelta(无方向);
SynapsetoPreviousPartialDelivative[突触]=当前PartialDelivative;
}
返回权重增量;
}
公共静态弹性BackPropagationSynapseweightCalculator创建()
=>新的ResilientBackPropagationSynapseWeightCalculator();
}
帮助器函数类实现为:

internal static class ResilientBackPropagationHelper
{
    private const double NegativeWeightUpdateAmount = 0.5;
    private const double PositiveWeightUpdateAmount = 1.2;
    private const double MaximumWeightUpdate = 50.0;
    private const double MinimumWeightUpdate = 1.0E-6;
    private const double InitialUpdateValue = 0.1;

    private const double ZeroTolerance = 0.00000000000000001d;

    public static int Sign(double value)
    {
        if (Math.Abs(value) < ZeroTolerance)
        {
            return 0;
        }
        if (value > 0)
        {
            return 1;
        }
        return -1;
    }

    public static double CalculateDeltaToContinueTowardsErrorGraidentMinimum(
        Synapse synapse,
        double currentPartialDerivative,
        Dictionary<Synapse, double> synapseToPreviousDeltaWithoutDirection)
    {
        if (synapseToPreviousDeltaWithoutDirection.TryGetValue(synapse, out var previousUpdateValue))
        {
            var delta = Math.Min(previousUpdateValue * PositiveWeightUpdateAmount, MaximumWeightUpdate);
            synapseToPreviousDeltaWithoutDirection[synapse] = delta;
            return Sign(currentPartialDerivative) * delta;
        }

        throw new InvalidOperationException($"You cannot increase a prevous delta is none is present.");
    }

    public static double CalculateDeltaToRevertPreviousWeightAdjustment(
        Synapse synapse,
        double currentPartialDerivative,
        Dictionary<Synapse, double> synapseToPreviousDeltaWithoutDirection)
    {
        if (synapseToPreviousDeltaWithoutDirection.TryGetValue(synapse, out var previousUpdateValue))
        {
            var delta = Math.Max(previousUpdateValue * NegativeWeightUpdateAmount, MinimumWeightUpdate);
            synapseToPreviousDeltaWithoutDirection[synapse] = delta;
            return -synapse.WeightDelta;
        }

        throw new InvalidOperationException($"You cannot revert a previous change if none is known.");
    }

    public static double CalculateDeltaDirection(
        Synapse synapse,
        double currentPartialDerivative,
        Dictionary<Synapse, double> synapseToPreviousDeltaWithoutDirection)
    {
        if (synapseToPreviousDeltaWithoutDirection.TryGetValue(synapse, out var previousUpdateValue))
        {
            return Sign(currentPartialDerivative) * previousUpdateValue;
        }

        synapseToPreviousDeltaWithoutDirection.Add(synapse, InitialUpdateValue);

        return CalculateDeltaDirection(
            synapse,
            currentPartialDerivative,
            synapseToPreviousDeltaWithoutDirection);
    }
}
内部静态类ResilientBackPropagationHelper
{
private const double NegativeWeightUpdateAmount=0.5;
private const double PositiveWeightUpdateAmount=1.2;
private const double MaximumWeightUpdate=50.0;
private const double MinimumWeightUpdate=1.0E-6;
private const double InitialUpdateValue=0.1;
私有常量双零容差=0.00000000000000001d;
公共静态整数符号(双值)
{
if(数学绝对值)<零公差)
{
返回0;
}
如果(值>0)
{
返回1;
}
返回-1;
}
公共静态双计算LTAToContinueTowardSerrorGraidentMinimum(
突触突触,
双电流部分导数,
字典SYNAPTOSETOPREVIOUSDELTA(不带方向)
{
if(synapseToPreviousDeltaWithoutDirection.TryGetValue(synapse,out var previousUpdateValue))
{
var delta=Math.Min(先前的UpdateValue*PositiveWeightUpdateAmount,MaximumWeightUpdate);
SynapsetoPreviousDelta无方向[synapse]=delta;
返回符号(当前部分导数)*delta;
}
抛出新的InvalidOperationException($“如果不存在上一个增量,则不能增加上一个增量。”);
}
公共静态双计算LTATORERVERTIONE先前的权重调整(
突触突触,
双电流部分导数,
Dic