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