反向传播是利用链式法则递归计算表达式的梯度的方法。
理解反向传播过程及其精妙之处,对于理解、实现、设计和调试神经网络非常关键。
在神经网络中f对应的是损失函数(L),输入x里面包含训练数据和神经网络的权重。举个例子,损失函数可以是SVM的损失函数,输入则包含了训练数据(xi,yi),i=1...N、权重W和偏差b。
几个概念
对于函数f(x,y) = xy;
导数
![]()
- 分别表示在x方向和y方向的导数;
- 表示变量变化导致的函数在该方向上的变化率。
![]()
- 对于上述公式,可以认为h值非常小,函数可以被一条直线近似,而导数就是这条直线的斜率。
- 换句话说,每个变量的导数指明了整个表达式对于该变量的值的敏感程度。
梯度
- 梯度∇f是偏导数的向量,
;
- 上式是说,如果该变量比另一个变量大,那么梯度是1,反之为0。例如,若x=4,y=2,那么max是4,所以函数对于y就不敏感。
- 也就是说,在y上增加h,函数还是输出为4,所以梯度是0:因为对于函数输出是没有效果的。
链式法则
- 考虑更复杂的包含多个函数的复合函数,比如f(x,y,z)=(x+y)z。
- 将公式分成两部分:q=x+y和f=qz。
- 链式法则指出将这些梯度表达式链接起来的正确方式是相乘,比如
;
- 最后得到变量的梯度[dfdx, dfdy, dfdz],它们告诉我们函数f对于变量[x, y, z]的敏感程度。
- 这是一个最简单的反向传播。
反向传播的直观理解
反向传播是一个优美的局部过程。在整个计算线路图中,每个门单元都会得到一些输入并立即计算两个东西:
- 这个门的输出值
- 其输出值关于输入值的局部梯度。
一旦前向传播完毕,在反向传播的过程中,门单元门将最终获得整个网络的最终输出值在自己的输出值上的梯度。
链式法则指出,门单元应该将回传的梯度乘以它对其的输入的局部梯度,从而得到整个网络的输出对该门单元的每个输入值的梯度。
反向传播实例
- 这个表达式描述了一个含输入x和权重w的2维的神经元,该神经元使用了sigmoid激活函数;
- 这个函数是由多个门组成的。除了上文介绍的加法门,乘法门,取最大值门,还有下面这4种:
- 函数fc使用对输入值进行了常量c的平移,fa将输入值扩大了常量a倍。它们是加法和乘法的特例。
- 使用sigmoid激活函数的2维神经元的例子。输入是[x0, x1],可学习的权重是[w0, w1, w2]。
- 在上面的例子中可以看见一个函数操作的长链条,链条上的门都对w和x的点积结果进行操作。该函数被称为sigmoid函数σ(x)。
- sigmoid函数关于其输入的求导是可以简化的
- 举个例子,sigmoid表达式输入为1.0,则在前向传播中计算出输出为0.73。根据上面的公式,局部梯度为(1-0.73)*0.73~=0.2,和之前的计算流程比起来,现在的计算使用一个单独的简单表达式即可。因此,在实际的应用中将这些操作装进一个单独的门单元中将会非常有用。
结论
- 对前向传播变量进行缓存:在计算反向传播时,前向传播过程中得到的一些中间变量非常有用。在实际操作中,最好代码实现对于这些中间变量的缓存,这样在反向传播的时候也能用上它们。如果这样做过于困难,也可以(但是浪费计算资源)重新计算它们。
- 在不同分支的梯度要相加:如果变量x,y在前向传播的表达式中出现多次,那么进行反向传播的时候就要非常小心,使用+=而不是=来累计这些变量的梯度(不然就会造成覆写)。这是遵循了在微积分中的多元链式法则,该法则指出如果变量在线路中分支走向不同的部分,那么梯度在回传的时候,就应该进行累加。
- 应该将函数分成不同的模块,这样计算局部梯度相对容易,然后基于链式法则将其“链”起来。重要的是,不需要把这些表达式写在纸上然后演算它的完整求导公式,因为实际上并不需要关于输入变量的梯度的数学公式。只需要将表达式分成不同的可以求导的模块(模块可以是矩阵向量的乘法操作,或者取最大值操作,或者加法操作等),然后在反向传播中一步一步地计算梯度。