神经网络反向传播的数学原理

作者:李飞腾
链接:https://zhuanlan.zhihu.com/p/22473137
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

如果能二秒内在脑袋里解出下面的问题,本文便结束了。

已知:J=(Xw-y)^T(Xw-y)=||Xw-y||^2,其中X\in R^{m \times n}, w \in R^{n \times 1}, y \in R^{m \times 1}

求:\frac{\partial J}{\partial X} \frac{\partial J}{\partial w} \frac{\partial J}{\partial y}



到这里,请耐心看完下面的公式推导,无需长久心里建设。

首先,反向传播的数学原理是“求导的链式法则” :

fgx的可导函数,则(f \circ g)'(x) = f'(g(x))g'(x)

接下来介绍

  • 矩阵、向量求导的维数相容原则
  • 利用维数相容原则快速推导反向传播
  • 编程实现前向传播、反向传播
  • 卷积神经网络的反向传播

快速矩阵、向量求导

这一节展示如何使用链式法则、转置、组合等技巧来快速完成对矩阵、向量的求导

一个原则维数相容,实质是多元微分基本知识,没有在课本中找到下列内容,维数相容原则是我个人总结:

维数相容原则:通过前后换序、转置 使求导结果满足矩阵乘法且结果维数满足下式:

如果x\in R^{m\times n} f(x)\in R^1,那么\frac{\partial f(x)}{\partial x} \in R^{m\times n}

利用维数相容原则解上例:

step1:把所有参数当做实数来求导,J=(Xw-y)^2

依据链式法则有\frac{\partial J}{\partial X}=2(Xw-y)w\frac{\partial J}{\partial w}=2(Xw-y)X\frac{\partial J}{\partial y}=-2(Xw-y)

可以看出除了\frac{\partial J}{\partial y}=-2(Xw-y)\frac{\partial J}{\partial X}\frac{\partial J}{\partial w}的求导结果在维数上连矩阵乘法都不能满足。

step2:根据step1的求导结果,依据维数相容原则做调整:前后换序、转置

依据维数相容原则\frac{\partial J}{\partial X} \in R^{m \times n},但\frac{\partial J}{\partial X} \in R^{m \times n} = 2(Xw-y)w(Xw-y)\in R^{m \times 1}w \in R^{n \times 1},自然得调整为\frac{\partial J}{\partial X}=2(Xw-y)w^T

同理:\frac{\partial J}{\partial w} \in R^{n \times 1},但 \frac{\partial J}{\partial w} \in R^{n \times 1} = 2(Xw-y)X(Xw-y) \in R^{m \times 1}X \in R^{m \times n},那么通过换序、转置我们可以得到维数相容的结果2X^T(Xw-y)

对于矩阵、向量求导:

  • “当做一维实数使用链式法则求导,然后做维数相容调整,使之符合矩阵乘法原则且维数相容”是快速准确的策略;
  • “对单个元素求导、再整理成矩阵形式”这种方式整理是困难的、过程是缓慢的,结果是易出错的(不信你试试)。

如何证明经过维数相容原则调整后的结果是正确的呢?直觉!简单就是美...

快速反向传播

神经网络的反向传播求得“各层”参数Wb的导数,使用梯度下降(一阶GD、SGD,二阶LBFGS、共轭梯度等)优化目标函数。

接下来,展示不使用下标的记法(W_{ij}, b_iorb_j)直接对Wb求导,反向传播是链式法则维数相容原则的完美体现,对每一层参数的求导利用上一层的中间结果完成。

这里的标号,参考UFLDL教程 - Ufldl

前向传播:

z^{(l+1)}=W^{(l)}a^{(l)}+b^{(l)} (公式1)

a^{(l+1)} =f(z^{(l+1)}) (公式2)

z^{(l)}为第l层的中间结果,a^{(l)}为第l层的激活值,其中第l+1层包含元素:输入a^{(l)},参数W^{(l)}b^{(l)},激活函数f(),中间结果z^{(l+1)},输出a^{(l+1)}

设神经网络的损失函数为J(W,b) \in R^1(这里不给出具体公式,可以是交叉熵、MSE等),根据链式法则有:

\bigtriangledown_{W^{(l)}}J(W,b)=\frac{\partial J(W,b)}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial W^{(l)}}=\delta ^{(l+1)}(a ^{(l)})^T \bigtriangledown_{b^{(l)}}J(W,b)=\frac{\partial J(W,b)}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial b^{(l)}}=\delta ^{(l+1)}

这里记 \frac{\partial J(W,b)}{\partial z^{(l+1)}}=\delta ^{(l+1)},其中\frac{\partial z^{(l+1)}}{\partial W^{(l)}}=a ^{(l)}\frac{\partial z^{(l+1)}}{\partial b^{(l)}}= 1可由 公式1 得出,a ^{(l)}加转置符号(a ^{(l)})^{T}是根据维数相容原则作出的调整。

如何求 \delta ^{(l)}=\frac{\partial J(W,b)}{\partial z^{(l)}}? 可使用如下递推(需根据维数相容原则作出调整):

\delta ^{(l)}=\frac{\partial J}{\partial z^{(l)}}=\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial a^{(l)}} \frac{\partial a^{(l)}}{\partial z^{(l)}}= ((W^{(l)})^{T}\delta ^{(l+1)}) \cdot  f'(z^{(l)})

其中\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial a^{(l)}} = (W^{(l)})^T \delta ^{(l+1)} \frac{\partial a^{(l)}}{\partial z^{(l)}} = f'(z^{(l)})

那么我们可以从最顶层逐层往下,便可以递推求得每一层的\delta ^{(l)} = \frac{\partial J(W,b)}{\partial z^{(l)}}

注意:\frac{\partial a^{(l)}}{\partial z^{(l)}} = f'(z^{(l)})是逐维求导,在公式中是点乘的形式。

反向传播整个流程如下

1) 进行前向传播计算,利用前向传播公式,得到隐藏层和输出层 的激活值。

2) 对输出层(第l层),计算残差:

\delta ^{(l)} =\frac{\partial J(W,b)}{\partial z^{(l)}}(不同损失函数,结果不同,这里不给出具体形式)

3) 对于l-1, l-2 , ... , 2的隐藏层,计算:

\delta ^{(l)}=\frac{\partial J}{\partial z^{(l)}}=\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial a^{(l)}}\frac{\partial a^{(l)}}{\partial z^{(l)}}=((W^{(l)})^{T}\delta ^{(l+1)}) \cdot f'(z^{(l)})

4) 计算各层参数W^{(l)}b^{(l)}偏导数:

\bigtriangledown_{W^{(l)}}J(W,b)=\frac{\partial J(W,b)}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial W^{(l)}}=\delta ^{(l+1)}(a ^{(l)})^T
\bigtriangledown_{b^{(l)}}J(W,b)=\frac{\partial J(W,b)}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial b^{(l)}}=\delta ^{(l+1)}


编程实现

大部分开源library(如:caffe,Kaldi/src/{nnet1,nnet2})的实现通常把W^{(l)}b^{(l)}作为一个layer,激活函数f()作为一个layer(如:sigmoid、relu、softplus、softmax)。

反向传播时分清楚该层的输入、输出即能正确编程实现,如:

z^{(l+1)}=W^{(l)}a^{(l)}+b^{(l)} (公式1)

a^{(l+1)} =f(z^{(l+1)}) (公式2)


(1)式AffineTransform/FullConnected层,以下是伪代码:


注: out_diff =  \frac{\partial J}{\partial z^{(l+1)}} 是上一层(Softmax 或 Sigmoid/ReLU的 in_diff)已经求得:

in\_diff = \frac{\partial J}{\partial a^{(l)}} = \frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial a^{(l)}} = W^T * out\_diff (公式 1-1)

W\_diff =\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial W^{(l)}} = out\_diff * in^T (公式 1-2)

b\_diff =\frac{\partial J}{\partial z^{(l+1)}} \frac{\partial z^{(l+1)}}{\partial b^{(l)}} = out\_diff * 1 (公式 1-3)


(2)式激活函数层(以Sigmoid为例)

注:out_diff = \frac{\partial J}{\partial a^{(l+1)}}是上一层AffineTransform的in_diff,已经求得,

in\_diff = \frac{\partial J}{\partial z^{(l+1)}} = \frac{\partial J}{\partial a^{(l+1)}} \frac{\partial a^{(l+1)}}{\partial z^{(l+1)}} = out\_diff \cdot out \cdot (1-out)

在实际编程实现时,in、out可能是矩阵(通常以一行存储一个输入向量,矩阵的行数就是batch_size),那么上面的C++代码就要做出变化(改变前后顺序、转置,把函数参数的Vector换成Matrix,此时Matrix out_diff 每一行就要存储对应一个Vector的diff,在update的时候要做这个batch的加和,这个加和可以通过矩阵相乘out_diff*input(适当的转置)得到。

如果熟悉SVD分解的过程,通过SVD逆过程就可以轻松理解这种通过乘积来做加和的技巧。

丢掉那些下标记法吧!


卷积层求导

卷积怎么求导呢?实际上卷积可以通过矩阵乘法来实现(是否旋转无所谓的,对称处理,caffe里面是不是有image2col),当然也可以使用FFT在频率域做加法。

那么既然通过矩阵乘法,维数相容原则仍然可以运用,CNN求导比DNN复杂一些,要做些累加的操作。具体怎么做还要看编程时选择怎样的策略、数据结构。


快速矩阵、向量求导之维数相容大法已成。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
神经网络反向传播(Backpropagation)是一种常用的训练神经网络的算法,其主要思想是通过计算神经网络输出误差,并将误差传递回神经网络中进行参数更新,从而不断优化神经网络的性能。 反向传播算法的主要过程如下: 1. 前向传播:将输入数据送入神经网络,按照从输入层到输出层的顺序依次计算每个神经元的输出值。 2. 计算误差:将神经网络输出的结果与真实标签值进行比较,计算输出误差。 3. 反向传播:将输出误差反向传播神经网络中,计算每个神经元的误差贡献,然后根据误差贡献更新神经元的参数。 4. 重复迭代:不断重复以上步骤,直到神经网络的性能达到预期要求为止。 具体来说,反向传播算法是通过链式法则(Chain Rule)实现误差反向传播的。在网络的每一层中,根据链式法则可以将误差贡献分解为上一层误差贡献和当前层神经元的激活函数对权重的导数乘积的和。然后,根据误差贡献和权重的导数,可以更新当前层的神经元权重和偏置值,从而不断优化神经网络的性能。 理解反向传播算法需要掌握数学知识,包括微积分、矩阵求导、链式法则等。同时,还需要对神经网络模型的结构和参数有一定的了解。通过不断练习和实践,可以逐渐掌握反向传播算法的原理和实现方法,并应用到实际的神经网络模型中进行训练和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值