之前也写过关于反向传播算法中几个公式的推导,最近总被人问到其中推导的细节,发现之前写的内容某在些地方很牵强,很突兀,没有一步一步紧跟逻辑(我也不准备修正,因为它也代表了一种思考方式)。这两天又重新回顾了一下反向传播算法,所有就再次来说说反向传播算法。这篇博文的目的在于要交代清楚为什么要引入反向传播算法,以及为什么它叫反向传播。
1.从前(正)向传播谈起
在谈反向传播算法之前,我们先来简单回顾一下正向传播(详细版戳此处)。假设有如下网络结构:

其中:
LSlKwlij=神经网络总共包含的层数=第l层的神经元数目=输出层的神经元数,亦即分类的数目=第l层第j个神经元与第l+1层第i个神经元之间的权重值
即对如上网络结构来说,L=3,s1=3,s2=2,s3=K=2,ali表示第l层第i个神经元的**值,bl表示第l层的偏置。
则有如下正向传播过程:
z21z22=a11w111+a12w112+a13w113+b1=a11w121+a12w122+a13w123+b1⟹[z21z22]=[w111w121w112w122w113w123]2×3×⎡⎣⎢⎢a11a12a13⎤⎦⎥⎥3×1+[b1b1]⟹z2=a1w1+b1⟹a2=f(z2)⟹z3=a2w2+b2⟹a3=f(z3)
所以可以得出正向传播过程几个公式:
zl+1i=al1wli1+al2wli2+⋯+alSlwliSl+blzl+1=alwl+blal=f(zl)(1)(2)(3)
其中,f()表示**函数,如sigmoid函数。
现在我们已经知道了正向传播的过程,也就是说当我们训练得到参数w之后,就可以用正向传播通过网络来预测了。但是大家有没有想过,参数w是怎么训练得到的?那第一反应肯定是运用梯度下降算法。既然是用梯度下降算法来求解参数,那第一步当然就是求解梯度了。
2.求解梯度
为了方便阅读,在这个位置再插入一张上面同样的网络结结构图:

此时,我们假设网络的目标函数为误差平方函数,且暂时不管正则化,同时只考虑一个样本即:
J=12(hw,b(x)−y)2
且此处hw,b(x)=a3
由此,我们可以发现:如果J对w111求导,则J是关于a3的函数,a3是关于z3的函数,z3是关于a2的函数,a2是关于z2的函数,w111是关于z2的函数。
为了更加清晰下面的求导过程,我们先来举两个例子,看看链式求导的过程(如果熟悉链式求导规则,请直接忽略)。
例1:
假设有如下函数:
f⟹∂f∂w=sin(t),t=x2,x=5w=∂f∂t⋅∂t∂x⋅∂x∂w=cos(t)⋅2x⋅5=cos(x2)⋅2x⋅5=cos(25w2)⋅10w⋅5=50wcos(25w2)
作为验证,我们直接将t,x带入f然后求导:
f⟹∂f∂w=sin(x2)=sin(25w2)=cos(25w2)⋅50w=50wcos(25w2)
例2:
我们再来看一个抽象的,没有表达式得链式求导,假设有如下函数表达式:
f=g(t),t=ϕ(x+y),x=h(w),y=μ(w)
则我们可以画出如下关系图:

即,
t是
f的函数,
y和x都是
t的函数,
w分别又都是
y和x的函数,也就是说我们有两条路径可以到达
w,所以
⟹∂f∂w=∂f∂t⋅∂t∂y⋅∂y∂w+∂f∂t⋅∂t∂x⋅∂x∂w=∂f∂t⋅(∂t∂y⋅∂y∂w+∂t∂x⋅∂x∂w)
所以有:
∂J∂w111∂J∂w112∂J∂w222=∂J∂a31⋅∂a31∂z31⋅∂z31∂a21⋅∂a2∂z21⋅∂z21∂w111+∂J∂a32⋅∂a32∂z32⋅∂z32∂a21⋅∂a2∂z21⋅∂z21∂w111=∂J∂a31⋅∂a31∂z31⋅∂z31∂a21⋅∂a2∂z21⋅∂z21∂w112+∂J∂a32⋅∂a32∂z32⋅∂z32∂a21⋅∂a2∂z21⋅∂z21∂w112⋮=∂J∂a32⋅∂a32∂z32⋅∂z32∂w222
我们可以发现,当J对第2层的参数求导还相对不麻烦,但当J对第1层的参数求导的时候就做了很多重复的计算;并且这还是网络相对简单的时候,要是网络相对复杂一点,这个过程简直就是难以下手。这也是为什么神经网络在一段时间发展缓慢的原因,就是因为没有一种高效的计算梯度的方式。
3.一种高效的梯度求解办法
∂J∂w111=(∂J∂a31⋅∂a31∂z31⋅∂z31∂a21⋅∂a2∂z21)⋅∂z21∂w111+(∂J∂a32⋅∂a32∂z32⋅∂z32∂a21⋅∂a2∂z21)⋅∂z21∂w111
从上面的求导公式可以看出,不管你是从哪一条路径过来,在对w111求导之前都会先到达z21,即先对z21求导之后,才会有∂z21∂w111。也就是说,我不管你是经过什么样的路径,在对连接第l层第j个神经元与第l+1第i个神经元的参数wlij求导之前,肯定会先对zl+1i求导。因此,对任意参数的求导过程,可以改写为:
∂J∂wlij=∂J∂zl+1i⋅∂zl+1i∂wlij=∂J∂zl+1i⋅alj(4)
例如:
∂J∂w111=∂J∂z1+11⋅∂z1+11∂w111=∂J∂z21⋅∂z21∂w111
所以,现在的问题变成了如何求解红色部分了,即:
∂J∂zl+1i=???
从网络结构图可以,J对任意zli求导,求导路径必定会经过第l+1层的所有神经元,于是有:
∂J∂zli=∂J∂zl+11⋅∂zl+11∂zli+∂J∂zl+12⋅∂zl+12∂zli+⋯+∂J∂zl+1Sl+1⋅∂zl+1Sl+1∂zli=∑k=1Sl+1∂J∂zl+1k⋅∂zl+1k∂zli=∑k=1Sl+1∂J∂zl+1k⋅∂∂zli(al1wlk1+al2wlk2+⋯+alSlwlkSl+bl)⋯⋯由(1)可知=∑k=1Sl+1∂J∂zl+1k⋅∂∂zli∑j=1Slaljwlkj=∑k=1Sl+1∂J∂zl+1k⋅∂∂zli∑j=1Slf(zlj)wlkj=∑k=1Sl+1∂J∂zl+1k⋅f′(zli)wlki(5)
于是我们得到:
∂J∂zli=∑k=1Sl+1∂J∂zl+1k⋅f′(zli)wlki(6)
因此
∂J∂zl+1i=∑k=1Sl+2∂J∂zl+2k⋅f′(zl+1i)wl+1ki
为了便于书写和观察规律,我们引入一个中间变量δli=∂J∂zli,则(5)得:
δli=∂J∂zli=∑k=1Sl+1δl+1k⋅f′(zli)wlki(l<=L−1)(7)
注:之所以要l<=L−1,是因为由(5)得推导过程可知,l最大只能取到L−1,第L层后面没有网络层了。
所以:
δLi=∂J∂zLi=∂∂zLi[12∑k=1SL(hk(x)−yk)2]=∂∂zLi[12∑k=1SL(f(zLk)−yk)2]=[f(zLi)−yi]⋅f′(zLi)=[aLi−yi]⋅f′(zLi)(8)
同时将(7)带入(4)可知:
∂J∂wlij=δl+1i⋅alj(9)
通过上面的所有推导,我们可以得到如下3个公式:
∂J∂wlij=δl+1i⋅aljδli=∂J∂zli=∑k=1Sl+1δl+1k⋅f′(zli)wlki(0<l≤L−1)δLi=[aLi−yi]⋅f′(zLi)
且经过适量化后为:
∂J∂wl=δl+1⋅(al)Tδl=(wl)T⋅δl+1∗f′(zl)δL=[aL−y]∗f′(zL)(10)(11)(12)
符号⋅表示矩阵乘法;符号∗表示两个矩阵相同位置的元素对应相乘
由(10)(11)(12)分析可知,欲求J对wl的导数,必先知道δl+1;而欲知δl+1,必先求δl+2,以此类推……
由此可知对于整个求导过程,一定是先求δL,再求δL−1,一直到δ2
为了方便阅读,在这个位置再插入一张上面同样的网络结结构图:

对于这样一个网络结构,整个求导过程(不含bl)如下:
Step1:δ3=[a3−y]∗f′(z3)Step2:∂J∂w2=δ3⋅(a2)TStep3:δ2=(w2)T⋅δ3∗f′(z2)Step4:∂J∂w1=δ2⋅(a1)T
于是我们终于发现了这么一个不争的事实:
1.最先求解出导数的参数一定位于第L−1层上(如此处的w2);
2.要想求解第l层参数的导数,一定会用到第l+1层上的中间变量δl+1(如此处求解w1的导数,用到了δ2);
3.整个过程是从后往前的;
所以,该过程被形象的称为反向(后向)传播算法。
另:δl被称为第l层的“残差”
一个重要的结论:
反向传播算法是用来求解梯度的!
反向传播算法是用来求解梯度的!
反向传播算法是用来求解梯度的!
重要的话说三遍,因为不少人总是把梯度下降和反向传播两个搞得稀里糊涂的。
4.总结
通过举例对平方误差目标函数反向传播算算法公式的推导,我们可以总结出更为一般的情况,即:
∂J∂wl=δl+1⋅(al)Tδl=(wl)T⋅δl+1∗f′(zl)δLi=∂J∂zLi=∂J∂aLi⋅∂aLi∂zLi=∂J∂aLi⋅∂f(zLi)∂zLi=∂J∂aLi⋅f′(zLi)∂J∂bl=δl+1(13)(14)(15)(16)
我们可以看到,仅仅只有公式(15)才依赖于不同的目标函数;比如在交叉熵中δLi=aL−y推导戳此处.
关于反向传播算法的推导基本上可以告一段落了,下一篇我们将通过一个例子用python来实现,这样就会更清楚了 。