3

I'm struggling with implementing Resilient Propagation correctly. I already implemented the backpropagation Algorithm to train a Neural Network, and it works as expected for an XOR-Net, i.e. it takes about 600 Epochs to drop Error below 1%. Now i tried implementing Resilient Propagation (http://en.wikipedia.org/wiki/Rprop) for the same problem and for the first few Epochs Error drops quickly to 23% but then raises to 50% and stays there.
I implemented it exactly as per description in http://www.heatonresearch.com/book/introduction-neural-network-math.html, but that's a puzzling Description: it's different from the wikipedia Rprop-Page AND from the implementation in encog, which was written by the same author as the book, as far as i know. I also already tried the different implementations from the different sources, but nothing worked.

Some of the differences between the various sources:

  • using signum(currentPartialDerivative) instead of signum(currentPartialDerivative * previousPartialDerivative) for the calculation of the weight-changes
  • using the last weight change, instead of the new update value for the new weight change
  • Calculating the weight changes firstly and the new update values secondly

What is the correct way of implementing this? Subsequently the Implementation according to the book:

public ResilientPropagation() {
    initialUpdateValue = 0.01;
    deltaMaximum = 50;
    deltaMinimum = 0.000001;
    negativeEta = 0.5;
    positiveEta = 1.2;
    double zeroTolerance = 0.0000000000000001;
    signum = new Signum(zeroTolerance);

    init();
}

@Override
public double calculateWeightChange(Synapse synapse, double partialDerivative) {
    if (!synapseValues.containsKey(synapse)){
        double initialPartialDerivative = 0;
        synapseValues.put(synapse, new SynapseValues(initialUpdateValue, initialPartialDerivative));
    }

    SynapseValues values = synapseValues.get(synapse);
    double signChange = signum.value(values.lastPartialDerivative * partialDerivative);
    values.lastPartialDerivative = partialDerivative;
    double weightChange = 0;
    if (signChange > 0){
        newUpdateValue = Math.min(positiveEta * values.updateValue, deltaMaximum);
        weightChange = -1*newUpdateValue;
    } else if (signChange < 0){
        newUpdateValue = Math.max(negativeEta * values.updateValue, deltaMinimum);
        weightChange = newUpdateValue;
    } else {
        newUpdateValue = values.updateValue;
        double weightChange = 0;
    }
    values.updateValue = newUpdateValue;
    return weightChange;
}

The same Method for normal Backpropagation works fine:

@Override
public double calculateWeightChange(Synapse synapse, double partialDerivative) {
    double previousChange = previousWeightChange.get(synapse) != null ? previousWeightChange.get(synapse) : 0;
    double weightChange = learningRate * partialDerivative + momentum * previousChange;
    previousWeightChange.put(synapse, weightChange);
    return weightChange;
}
4

1 回答 1

1

RPROP 算法有几种不同的变体。自从本书出版以来,Encog 已经被修改以支持更多的它们。本书重点介绍了 Reidmiller 的一篇论文所定义的经典 RPROP。随后的论文提出了额外的算法。这解释了 Encog 优化的 RPROP 算法与书中描述的一些差异。

查看您上面的代码,我有一些建议可能会有所帮助。大多数情况下,我不确定您的最后一个 else 子句。你有“double weightChange = 0”,它什么也不做。我认为你需要删除双重。您还需要对“零”是什么建立一些容忍度。梯度的变化很少会精确地达到零,所以我会建立一个大约为零的范围,可能是 -0.00001 到 +0.00001 以触发 else 子句。然后确保您实际上将 weightChange 设置为零。

我从我自己的 rprop 实现中回忆起的另一个问题是,用于反向传播的梯度符号是用于反向传播的梯度的逆符号。您可以尝试翻转 RPROP 的渐变符号,这在我的 Encog 实现中是必需的。

RPROP 的这个实现可能对您有用,它是经典的 Reidmiller 实现。它运行正常并且误差收敛。

https://github.com/encog/encog-java-core/blob/master/src/main/java/org/encog/neural/freeform/training/FreeformResilientPropagation.java

不确定这是否会有所帮助。在不运行代码的情况下,这就是我所看到的全部。

于 2014-12-09T21:07:34.177 回答