理解神经网络反向传播

50

更新:问题的更好表述。

我试图通过一个XOR神经网络的例子来理解反向传播算法。对于这种情况,有2个输入神经元+1个偏置,2个隐藏层神经元+1个偏置,以及1个输出神经元。

 A   B  A XOR B
 1    1   -1
 1   -1    1
-1    1    1
-1   -1   -1

一个示例XOR神经网络
(来源:wikimedia.org

我正在使用随机反向传播算法

阅读了一些资料后,我发现输出单元的误差会传递到隐藏层……最初这让我感到困惑,因为当你到达神经网络的输入层时,每个神经元都从两个隐藏层神经元中获得一个误差调整。特别地,误差的分布方式一开始很难理解。

步骤1:计算每个输入实例的输出。
步骤2:计算输出神经元(在我们的情况下只有一个)与目标值之间的误差:
Step 2
步骤3:使用步骤2中的误差来计算每个隐藏单元h的误差:
Step 3

'weight kh'是隐藏单元h和输出单元k之间的权重。这很令人困惑,因为输入单元没有与输出单元直接相关联的权重。经过几个小时的公式思考,我开始思考求和符号的含义,并得出结论:每个连接到隐藏层神经元的输入神经元的权重都要乘以输出误差并进行求和。这是一个合理的结论,但公式似乎有点令人困惑,因为它明确表示了'weight kh'(在输出层k和隐藏层h之间)。

这里我是否正确地理解了一切?可以有人确认一下吗?

输入层的O(h)是什么意思?我的理解是每个输入节点有两个输出:一个进入隐藏层的第一个节点,另一个进入隐藏层的第二个节点。在公式O(h)*(1 - O(h))的哪个部分应该插入这两个输出中的哪一个呢?
Step 3


2
昨天看到这个引用,注意到第二步图像已经移动第三步图像也是如此。 - LinkBerest
3个回答

35

你发布的教程实际上是有误的。我对比了Bishop的两本标准书籍和两个我工作中的实现,确信这一点。下面我将指出具体的问题所在。

需要注意的重要事项是,您始终在寻找与单元或权重的误差函数的导数相关的信息。前者是delta,后者则是您用来更新权重的。

如果您想理解反向传播,那么您就必须要了解链式法则。这里完全是关于链式法则。如果您不知道它的确切工作原理,请在维基百科上查阅 - 它并不难懂。但是,只要您理解了派生,一切都会迎刃而解。我保证! :)

∂E/∂W可以通过链式法则组合成∂E/∂o ∂o/∂W。 ∂o/∂W很容易计算,因为它只是单位激活/输出相对于权重的导数。 ∂E/∂o实际上是我们所说的delta。(在此假设E、o和W是向量/矩阵)

对于输出单元,我们已经有了它们,因为那里是我们可以计算误差的地方。 (通常,我们有一个误差函数,它化简为(t_k - o_k)的delta,例如线性输出的二次误差函数和逻辑输出的交叉熵误差函数。)

现在的问题是,我们如何获得内部单元的导数?我们知道一个单元的输出是所有传入单元的加权和,并在此之后应用传递函数。 因此,o_k = f(sum(w_kj * o_j, for all j))。

所以我们要做的就是,将o_k与o_j相对。因为delta_j = ∂E/∂o_j = ∂E/∂o_k ∂o_k/∂o_j = delta_k ∂o_k/o_j。因此,一旦有了delta_k,我们就可以计算出delta_j!

让我们开始吧。o_k = f(sum(w_kj * o_j, for all j)) => ∂o_k/∂o_j = f'(sum(w_kj * o_j, for all j)) * w_kj = f'(z_k) * w_kj.

对于Sigmoid传输函数的情况,这变为 z_k(1 - z_k) * w_kj。(教程中有错误,作者说成了 o_k(1 - o_k) * w_kj!


2
+1 对于在反向传播背后的直觉和计算细节之间交替说明的做法表示赞同。 - doug
3
这个教程没有错。f'(z_k) = f(z_k)(1 - f(z_k)),等同于 o_k(1 - o_k) - IVlad
由于您似乎很了解反向传播 @bayer,也许您对 https://stackoverflow.com/questions/53287032/multi-layer-neural-network-back-propagation-formula-using-stochastic-gradient-d 有什么想法?非常感谢您的帮助。 - Basj

8

我不确定您的问题是什么,但我自己通过了那个教程,我可以向您保证,除了一个明显的拼写错误外,它没有任何错误。

我假设您的问题是因为您对反向传播隐藏 delta如何导出感到困惑。如果这确实是您的问题,请考虑:

alt text
(来源:pandamatak.com)

您可能对作者如何导出此方程式感到困惑。这实际上是多元链式法则的直接应用。即(下面内容摘自维基百科):

“假设z = f(u,v)的每个参数都是二元函数,使得u = h(x,y)且v = g(x,y),并且这些函数都是可微分的。然后链式法则看起来像:

alt text

alt text "

现在想象将链式法则通过归纳论证扩展到

E(z'1,z'2,..,z'n) 其中z'k是第k个输出层的预激活输出, 且z'k(wji)也就是说E是z'的函数,而z'本身是wji的函数(如果一开始您不理解,请仔细思考神经网络的设置方式)。将链式法则直接扩展到n个变量:

δE(z'1,z'2,..,z'n)/δwji = Σk δE/δz'k δz'k/δwji

这是最重要的一步,作者随后再次应用链式法则,这次在总和内部扩展δz'k/δwji项,即

δz'k/δwji = δz'k/δoj δoj/δzj δzj/δwji
如果你对链式法则感到困难,你可能需要学习多元微积分课程或阅读教材中的相关章节。祝你好运。

@gmatt,感谢您的参与...这个问题有点老(2010年2月),但我找到了问题出在哪里。 - Kiril
@Idog或其他遇到此问题的人,第一个算法的链接已更改:http://pandamatak.com/people/anand/771/html/img334.gif - LinkBerest

3
我从第三步的方程中读到的是:
  1. O_h = 这个隐藏单元的最后输出(输入层的O_h是实际输入值)
  2. w_kh = 连接这个隐藏单元和下一层单元(向输出方向)之间的权重
  3. delta_k = 下一层单元(向输出方向,与上一个符号相同)的误差
每个单元只有一个输出,但每个输出与下一层之间的连接都有权重。因此,输出相同,但在接收端,如果链接的权重不同,则每个单元将接收到不同的值。O_h始终指代该神经元在最后一次迭代时的值。按定义,输入层没有“误差”,因此误差不适用于输入层。
需要逐层计算误差,从输出侧开始,因为我们需要计算第N层的误差值以计算第N-1层。你是正确的,在反向传播中,输入和输出之间没有直接连接。
我相信方程式是正确的,尽管可能有点令人困惑。可能令人困惑的是,在正向传播中,对于每个单元,我们必须考虑该单元左侧的所有单元和链接(输入值),但在误差传播(反向传播)中,我们必须考虑正在处理的单元右侧(输出值)的单元。

好的,在阅读更多内容后,我也同意您的观点:O_h是单位的实际值。关于delta_k的一点澄清:如何计算隐藏层的delta_k?我知道如何为输出层计算它,因为我们可以直接将其与XOR目标值进行比较。但是隐藏层的目标值是什么?我假设我们只计算一次,针对输出层,并将其用于所有层。 - Kiril
隐藏神经元没有“目标值”。您必须使用步骤3中列出的方程来计算隐藏层神经元的所有delta_k。请注意,您只需要输出值和右侧神经元层中的错误来完成计算 - 这就是为什么必须从输出开始向输入方向计算错误的原因。 - cjcela
第二步中的方程仅适用于输出神经元的误差。第三步中的方程适用于隐藏神经元的误差。输入层神经元没有误差项。 - cjcela
好的,所以输入神经元的Delta是通过将其输出Oh(1-Oh)乘以计算得到的右侧隐藏单元的权重误差之和来计算的。 假设顶部隐藏单元的误差为0.02,底部隐藏单元的误差为0.01,从输入单元到两个隐藏单元的权重为0.5,并且输入单元的输出为1,则最终会得到1(1-1)(0.50.02+0.5*0.01) = 0;因此不会对输入单元的权重进行调整。 - Kiril
1
刚刚发现了一些可能有用的东西,Lirik。在这里看看C/C++源代码:http://www.codeproject.com/KB/recipes/BP.aspx - 一切都在那里。 - cjcela

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接