Java 简单神经网络的奇异收敛性

Java 简单神经网络的奇异收敛性,java,neural-network,convergence,Java,Neural Network,Convergence,我一直在努力用Java构建一个简单的NN。我在这个项目上断断续续地工作了几个月,我想完成它。我的主要问题是,我不知道如何正确地实现反向传播(所有源代码都使用Python、数学术语,或者过于简单地解释这个想法)。今天我试着自己推断意识形态,我使用的规则是: 权重更新=错误*西格莫迪竞争(错误)*权重本身 误差=输出-实际值;(最后一层) 错误=SigmoidePrivative(来自上一层的错误)*将此神经元附加到给出错误的神经元的权重(中间层) 我的主要问题是输出收敛到一个平均值,我的第二个问题

我一直在努力用Java构建一个简单的NN。我在这个项目上断断续续地工作了几个月,我想完成它。我的主要问题是,我不知道如何正确地实现反向传播(所有源代码都使用Python、数学术语,或者过于简单地解释这个想法)。今天我试着自己推断意识形态,我使用的规则是:

权重更新=错误*西格莫迪竞争(错误)*权重本身
误差=输出-实际值;(最后一层)
错误=SigmoidePrivative(来自上一层的错误)*将此神经元附加到给出错误的神经元的权重(中间层)

我的主要问题是输出收敛到一个平均值,我的第二个问题是权重更新到一个非常奇怪的值。(可能是权重问题导致了收敛)

我想训练的是:对于输入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。我一直在尝试调试它,但我不知道应该查找什么,也不知道出了什么问题。任何建议都将不胜感激。提前谢谢大家,祝大家度过美好的一天

按照上面的规则,我有一个训练样本1->9和它们各自的输出,我运行它们10万次。我每100个纪元记录一次错误,因为用更少的数据点绘图更容易,而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;
致:

    outputErrors[k][i] = sigmoidDerivative(outputErrors[k+1][j])[0] * network[k+1][i].emergingWeights[j]* outputErrors[k+1][j];       

所以我保留了输出错误本身的符号。这修复了第一个权重中的无穷大趋势。现在,在/10跑时,第一个权重趋于0,在/100跑时,第二个权重趋于0。还是希望有人能为我收拾残局(

我发现您的代码存在一些问题,例如体重更新不正确。我还强烈建议您通过引入方法来组织代码清理程序

反向传播通常很难有效地实现,但形式定义很容易翻译成任何语言。我不建议您查看学习神经网络的代码。请查看数学并尝试理解这一点。这使您能够更灵活地从头实现一个

我可以通过在伪代码中描述向前和向后传递来给您一些提示

作为一种表示法,我对输入使用
I
,对隐藏层使用
j
,对输出层使用
k
。然后输入层的偏差是
bias\u I
。对于连接一个节点到另一个节点的权重,权重是
w\u mn
。激活是
a(x)
及其导数
a'(x)

向前传球:

for each n of j
       dot = 0
       for each m of i
              dot += m*w_mn
       n = a(dot + bias_i)
相同的方法适用于输出层
k
和隐藏层
j
。因此,对于此步骤,只需将
j
替换为
k
,将
i
替换为
j

向后传球:

for each n of j
       dot = 0
       for each m of i
              dot += m*w_mn
       n = a(dot + bias_i)
计算输出节点的增量:

for each n of k
       d_n = a'(n)(n - target)
这里,
target
是预期的输出,
n
是当前输出节点的输出。
dun
是此节点的增量。 这里需要注意的一点是,logistic函数和tanh函数的导数包含原始函数的输出,不必重新计算这些值。 逻辑函数是
f(x)=1/(1+e^(-x))
及其导数
f'(x)=f(x)(1-f(x))
。由于每个输出节点
n
处的值先前是用
f(x)
计算的,因此可以简单地将
n(1-n)
作为导数。在上述情况下,这将计算delta如下:

d_n = n(1-n)(n - target)
for each n of j
      for each m of k
            w_nm -= learning_rate*n*d_m
以相同的方式,计算隐藏节点的增量

for each n of j
      d_n = 0
      for each m of k
             d_n += d_m*w_jk
      d_n = a'(n)*d_n
下一步是使用梯度执行权重更新。这是通过一种称为梯度下降的算法完成的。无需详细说明,这可以通过以下方式完成:

d_n = n(1-n)(n - target)
for each n of j
      for each m of k
            w_nm -= learning_rate*n*d_m
上面的层也是如此。只需将
j
替换为
i
,将
k
替换为
j


要更新偏差,只需将连接节点的增量相加,乘以学习率,然后从特定偏差中减去该乘积。

谢谢你的回答!我会慢慢浏览你的帖子,并用你的版本更新我的实现。我会用“官方”回复你然后评论。当然。如果你对我的答案有任何疑问,请告诉我。如果我发现错误,我会让你知道并相应地更新答案。快速问题:我记得在网上看到更新应该在每个历元之后进行。因此,对于我的9个示例数据集,我计算了每个示例的权重更新,并得到了平均uPATEM的基础上,然后应用它在一个时代的结束。目前,我正在更新每一个例子后的权重,这是一个问题?另一个问题:在隐藏层的增量代码,你正在做:d'n= a’(x)*dnn。你的意思是“(n))(在中间层的当前神经元的激活的衍生物)?当您更新使用的权重时:w_nm-=学习率md_m此处的“m”表示神经元m的输入(来自输出层)?