【发布时间】:2018-05-24 06:47:42
【问题描述】:
我一直在努力用 Java 构建一个简单的 NN。我已经在这个项目上工作了几个月,我想完成它。我的主要问题是我不知道如何正确实现反向传播(所有来源都使用 Python、数学术语,或者过于简单地解释这个想法)。今天我尝试自己推断意识形态,我使用的规则是:
权重更新 = 误差 * sigmoidDerivative(error) * 权重本身;
错误 = 输出 - 实际; (最后一层)
error = sigmoidDerivative(error from previous layer) * 将此神经元附加到给出错误的神经元的权重(中间层)
我的主要问题是输出趋于平均值,而我的次要问题是权重更新为一个非常奇怪的值。 (可能是权重问题导致收敛)
我要训练的内容:对于输入 1-9 ,预期输出为:(x*1.2+1)/10。这只是一个随机出现的规则。我正在使用结构为 1-1-1(3 层,1 个网络/层)的 NN。在下面的链接中,我附上了两次运行:一次我使用遵循规则 (x*1.2+1)/10 的训练集,另一次我使用 (x*1.2+1)/100。除以 10 后,第一个权重趋于无穷大;除以 100 后,第二个权重趋于 0。我一直在尝试调试它,但我不知道我应该寻找什么或出了什么问题。任何建议都非常感谢。提前感谢大家,祝大家有美好的一天!
https://wetransfer.com/downloads/55be9e3e10c56ab0d6b3f36ad990ebe120171210162746/1a7b6f
按照上述规则,我将 1->9 及其各自的输出作为训练样本,我将它们运行了 100_000 个时期。我每 100 个 epoch 记录一次错误,因为使用更少的数据点更容易绘制,同时对于 9 的每个预期输出仍然有 1000 个数据点。反向传播和权重更新的代码:
//for each layer in the Dweights array
for(int k=deltaWeights.length-1; k >= 0; k--)
{
for(int i=0; i<deltaWeights[k][0].length; i++) // for each neuron in the layer
{
if(k == network.length-2) // if we're on the last layer, we calculate the errors directly
{
outputErrors[k][i] = outputs[i] - network[k+1][i].result;
errors[i] = outputErrors[k][i];
}
else // otherwise the error is actually the sum of errors feeding backwards into the neuron currently being processed * their respective weight
{
for(int j=0; j<outputErrors[k+1].length; j++)
{ // S'(error from previous layer) * weight attached to it
outputErrors[k][i] += sigmoidDerivative(outputErrors[k+1][j])[0] * network[k+1][i].emergingWeights[j];
}
}
}
for (int i=0; i<deltaWeights[k].length; i++) // for each neuron
{
for(int j=0; j<deltaWeights[k][i].length; j++) // for each weight attached to that respective neuron
{ // error S'(error) weight connected to respective neuron
deltaWeights[k][i][j] = outputErrors[k][j] * sigmoidDerivative(outputErrors[k][j])[0] * network[k][i].emergingWeights[j];
}
}
}
// we use the learning rate as an order of magnitude, to scale how drastic the changes in this iteration are
for(int k=deltaWeights.length-1; k >= 0; k--) // for each layer
{
for (int i=0; i<deltaWeights[k].length; i++) // for each neuron
{
for(int j=0; j<deltaWeights[k][i].length; j++) // for each weight attached to that respective neuron
{
deltaWeights[k][i][j] *= 1; // previously was learningRate; MSEAvgSlope
network[k][i].emergingWeights[j] += deltaWeights[k][i][j];
}
}
}
return errors;
编辑:突然想到一个问题:因为我使用 sigmoid 作为我的激活函数,我的输入和输出神经元应该只在 0-1 之间吗?我的输出在 0-1 之间,但我的输入实际上是 1-9。
Edit2:将输入值标准化为 0.1-0.9 并更改:
outputErrors[k][i] += sigmoidDerivative(outputErrors[k+1][j])[0] * network[k+1][i].emergingWeights[j];
到:
outputErrors[k][i] = sigmoidDerivative(outputErrors[k+1][j])[0] * network[k+1][i].emergingWeights[j]* outputErrors[k+1][j];
这样我就可以保留输出错误本身的符号。这修复了第一个重量中的无限趋势。现在,运行 /10 时,第一个权重趋于 0,运行 /100 后,第二个权重趋于 0。仍然希望有人能帮我解决问题。 :(
【问题讨论】:
标签: java neural-network convergence