我正在努力正确实现Resilient Propagation。我已经实现了反向传播算法来训练神经网络,并且对于XOR-Net,它的表现符合预期,即需要大约600个Epochs才能将误差降至1%以下。现在我尝试为相同的问题实现Resilient Propagation(http://en.wikipedia.org/wiki/Rprop),并且在前几个Epochs中,误差迅速下降到23%,但之后上升到50%并一直保持在那里。
我按照http://www.heatonresearch.com/book/introduction-neural-network-math.html中的描述完全实现了它,但这是一个令人困惑的描述:它与维基百科Rprop页面和encog中的实现有所不同,而encog是由该书的作者编写的,据我所知。 我已经尝试了来自不同来源的不同实现,但没有任何效果。
各种来源之间的一些差异:
同样的方法对于正常的反向传播也可以正常工作:
我按照http://www.heatonresearch.com/book/introduction-neural-network-math.html中的描述完全实现了它,但这是一个令人困惑的描述:它与维基百科Rprop页面和encog中的实现有所不同,而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();
}
@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;
}
同样的方法对于正常的反向传播也可以正常工作:
@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;
}