我目前正在实施RPROP算法,并且在解决XOR问题时发现它无法正常工作。在我看来,这是因为当您给神经网络输入值时,输入神经元中的2个输出为0.因此,当您计算该神经元的误差率的偏导数时,您得到0值。这意味着当RPROP算法运行时,它会计算当前偏导数对前一个偏导数的符号,这表示符号正确为0。因此,不计算Δ,但是前一个与当前偏导数的符号变化一起使用。这会导致更新值为0,因此算法失败。
我想知道是否有人能告诉我到底出错了什么,因为我已经阅读了算法并看到了安装实施,我仍然在努力解决这个问题。
为隐藏图层计算误差梯度:
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算法,其中Synapse包含输入神经元,输出神经元以及权重和权重增量:
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();
}
将辅助函数类实现为:
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);
}
}
关于我的逻辑失败的地方的任何帮助都会非常感激,因为我已经尝试了很多方法来使这个算法对抗算法。
非常感谢 乔