我在正确实现弹性传播方面遇到了困难。我已经实现了反向传播算法来训练神经网络,对于XOR网络,它按预期工作,大约需要600个周期将误差降至1%以下。现在我尝试为相同的问题实现弹性传播(http://en.wikipedia.org/wiki/Rprop),在最初的几个周期内,误差迅速下降到23%,但随后上升到50%并停留在那里。
我按照http://www.heatonresearch.com/book/introduction-neural-network-math.html中的描述精确实现了它,但那是一个令人困惑的描述:它与维基百科的Rprop页面以及由同一作者编写的encog中的实现不同,据我所知。我还尝试了不同来源的不同实现,但都没有成功。
不同来源之间的某些差异包括:
- 在计算权重变化时使用signum(currentPartialDerivative),而不是signum(currentPartialDerivative * previousPartialDerivative)
- 使用上一次权重变化,而不是新的更新值来计算新的权重变化
- 首先计算权重变化,然后计算新的更新值
正确的实现方式是什么?以下是根据书籍的实现:
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();}@Overridepublic 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;}
相同的方法在普通的反向传播中运行良好:
@Overridepublic 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;}
回答:
RPROP算法有几种不同的变体。自从书籍出版以来,Encog已经进行了修改以支持更多变体。书籍专注于Reidmiller论文中定义的经典RPROP。后续论文提出了其他算法。这解释了Encog的优化RPROP算法与书中描述的某些差异。
查看您上面的代码,我有一些建议可能会有所帮助。我主要不确定您的最终else子句。您有”double weightChange = 0″,这将不起作用。我认为您需要删除double。您还需要为“零”设定一些容忍度。梯度的变化很少会精确地达到零,所以我会为else子句设定一个关于零的范围,可能从-0.00001到+0.00001。然后确保您实际上将weightChange设置为零。
我记得在自己的RPROP实现中遇到的问题是,用于反向传播的梯度符号与用于反向传播的梯度符号相反。您可以尝试翻转RPROP的梯度符号,这在我的Encog实现中是必要的。
这个RPROP实现可能对您有用,这是经典的Reidmiller实现。它确实能正确运行,误差会收敛。
不确定这是否有帮助。在不运行代码的情况下,这就是我所看到的全部内容。