目前我正在尝试为我的网络实施Resilient Propagation。我是基于encog实现这样做的,但有一件事我不明白:
对于RPROP而言,The documentation和iRPROP +表示更改> 0:weightChange = -sign(gradient)* delta
第298行和第366行中的The source code没有减号!
因为我认为两者在某种情况下都是正确的:为什么两者之间存在差异?
关于渐变:我在输出层使用tanh作为激活。这是梯度的正确计算吗?
gradientOutput = (1 - lastOutput[j] * lastOutput[j]) * (target[j] - lastOutput[j]);
答案 0 :(得分:3)
在重新阅读相关论文并查阅教科书后,我认为此时的编辑文档不正确。为什么不通过在源代码中临时添加减号来试试呢?如果您使用相同的初始权重,您应该收到完全相同的结果,因为文档是正确的。但最后,重要的是你如何使用weightUpdate变量。如果文档的作者用于从权重中减去weightUpdate而不是添加它,那么这将起作用。
编辑:我在原始答案中重新审视了有关渐变计算的部分。
首先,这里简要说明如何设想输出图层中权重的渐变。首先,计算输出与目标值之间的误差。
你现在要做的是“责备”前一层中活跃的神经元。想象一下输出神经元说“嗯,我这里有错误,谁负责?”。负责任的是前一层的神经元。根据输出与目标值相比太小或太大,它将增加或减少前一层中每个神经元的权重,具体取决于它们的活动程度。
x是隐藏层中神经元的激活。
o是输出神经元的激活。
φ是输出神经元的激活函数,φ'是它的导数。
Edit2 :更正了以下部分。增加了反向传播的矩阵式计算。
每个输出神经元j的错误是:
(1)δ out,j =φ'(o j )(t - o j )
连接隐藏神经元i和输出神经元j的权重的梯度:
(2)grad i,j = x i *δ out,j
每个隐藏神经元i的反向传播误差,权重为w:
(3)δ hid,i =φ'(x)*Σw i,j *δ out,j
通过重复应用公式2和3,您可以反向传播到输入图层。
关于一个培训样本写入循环:
每个输出神经元j的错误是:
for(int j=0; j < numOutNeurons; j++) {
errorOut[j] = activationDerivative(o[j])*(t[j] - o[j]);
}
连接隐藏神经元i和输出神经元j的权重的梯度:
for(int i=0; i < numHidNeurons; i++) {
for(int j=0; j < numOutNeurons; j++) {
grad[i][j] = x[i] * errorOut[j]
}
}
每个隐藏神经元的反向传播错误i:
for(int i=0; i < numHidNeurons; i++) {
for(int j=0; j < numOutNeurons; j++) {
errorHid[i] = activationDerivative(x[i]) * weights[i][j] * errorOut[j]
}
}
在没有卷积的完全连接的多层感知器或类似的东西中,您可以使用标准矩阵操作,这要快得多。
假设您的每个样本都是输入矩阵中的一行,而列是其属性,您可以通过网络传播输入,如下所示:
activations[0] = input;
for(int i=0; i < numWeightMatrices; i++){
activations[i+1] = activations[i].dot(weightMatrices[i]);
activations[i+1] = activationFunction(activations[i+1]);
}
然后反向传播:
n = numWeightMatrices;
error = activationDerivative(activations[n]) * (target - activations[n]);
for (int l=n-1; l >= 0; l--){
gradient[l] = activations[l].transposed().dot(error);
if (l > 0) {
error = error.dot(weightMatrices[l].transposed());
error = activationDerivative(activations[l])*error;
}
}
我在上面的解释中省略了偏倚神经元。在文献中,建议将偏倚神经元建模为每个激活矩阵中的附加列,其总是1.0。您将需要处理一些切片分配。使用矩阵反向传播循环时,不要忘记在每一步之前将偏差位置的误差设置为0!
答案 1 :(得分:0)
private float resilientPropagation(int i, int j){
float gradientSignChange = sign(prevGradient[i][j]*gradient[i][j]);
float delta = 0;
if(gradientSignChange > 0){
float change = Math.min((prevChange[i][j]*increaseFactor), maxDelta);
delta = sign(gradient[i][j])*change;
prevChange[i][j] = change;
prevGradient[i][j] = gradient[i][j];
}
else if(gradientSignChange < 0){
float change = Math.max((prevChange[i][j]*decreaseFactor), minDelta);
prevChange[i][j] = change;
delta = -prevDelta[i][j];
prevGradient[i][j] = 0;
}
else if(gradientSignChange == 0){
float change = prevChange[i][j];
delta = sign(gradient[i][j])*change;
prevGradient[i][j] = gradient[i][j];
}
prevDelta[i][j] = delta;
return delta;
}
gradient[i][j] = error[j]*layerInput[i];
weights[i][j]= weights[i][j]+resilientPropagation(i,j);