前言
之前有证明过一次人工神经网络——【BP】反向传播算法证明 ,但是回头看的时候,有很多地方非常不严谨,特此拿出来再单独证明一次BP,并严格保证其严谨性。如果想看看粗略的证明,可以去看我之前的博客,毕竟那个貌似也没人说细节有问题,估计很多人没有动手拆分推导。
三层sigmoid激活函数BP扩展到任意激活函数
第一步:前向传播
下图展示了一个三层神经网络:
相关说明:
可见层定义为X X ,共有n n 个单元,下标用i i 索引
隐藏层定义为B B ,共有p p 个单元,下标用j j 索引,偏置为α α 输出层定义为Y Y ,共有q q 个单元,下标用k k 索引,偏置为β β 隐藏层到可见层权重矩阵为W W ,大小为( p , n ) ( p , n ) 隐藏层到输出层权重矩阵为V,大小为( q , p ) (q,p)
各层神经元的值:
可见层:x i xi 隐藏层:b j = σ ( ∑ n i = 1 W j i x i + α j ) bj=σ(∑i=1nWjixi+αj) 输出层:y k = σ ( ∑ p j = 1 V k j b j + β k ) yk=σ(∑j=1pVkjbj+βk)
误差:
第二步:误差反向传播
模型参数校正是从后往前进行的,所以称为误差逆传播,计算是从输出层到隐藏层,再从隐藏层到输入层。更新的是权重和偏置,称为模型参数,两层的权重和偏置的更新是类似的。
输出层到隐藏层的参数更新
先对权重V k j Vkj 求梯度:
Δ V k j = ∂ E ∂ V k j = ∂ E ∂ y k × ∂ y k ∂ V k j = ( y k − o k ) × σ ′ ( ∑ j = 1 p V k j b j + β k ) × b j ΔVkj=∂E∂Vkj=∂E∂yk×∂yk∂Vkj=(yk−ok)×σ′(∑j=1pVkjbj+βk)×bj
再对输出层的偏置
β k βk 求梯度:
Δ β k = ∂ E ∂ β k = ∂ E ∂ y k × ∂ y k ∂ β k = ( y k − o k ) × σ ′ ( ∑ j = 1 p V k j b j + β k ) Δβk=∂E∂βk=∂E∂yk×∂yk∂βk=(yk−ok)×σ′(∑j=1pVkjbj+βk)
隐藏层到输入层的参数更新
先对权重W j i Wji 求梯度
Δ W j i = ∂ E ∂ W j i = ∂ E ∂ b j × ∂ b j ∂ W j i = ∑ k = 1 q [ ∂ E k ∂ y k × ∂ y k ∂ b j ] × ∂ b j ∂ W j i = ∑ k = 1 q [ ( y k − o k ) × σ ′ ( ∑ j = 1 p V k j b j + β k ) × V k j ] × σ ′ ( ∑ i = 1 n W j i x i + α j ) × x i = ∑ k = 1 q [ Δ β k × V k j ] × σ ′ ( ∑ i = 1 n W j i x i + α j ) × x i ΔWji=∂E∂Wji=∂E∂bj×∂bj∂Wji=∑k=1q[∂Ek∂yk×∂yk∂bj]×∂bj∂Wji=∑k=1q[(yk−ok)×σ′(∑j=1pVkjbj+βk)×Vkj]×σ′(∑i=1nWjixi+αj)×xi=∑k=1q[Δβk×Vkj]×σ′(∑i=1nWjixi+αj)×xi
再对偏置
α j αj 求梯度
Δ α j = ∂ E ∂ α j = ∂ E ∂ b j × ∂ b j ∂ α j = ∑ k = 1 q [ ∂ E k ∂ y k × ∂ y k ∂ b j ] × ∂ b j ∂ α j = ∑ k = 1 q [ ( y k − o k ) × σ ′ ( ∑ j = 1 p V k j b j + β k ) × V k j ] × σ ′ ( ∑ i = 1 n W j i x i + α j ) = ∑ k = 1 q [ Δ β k × V k j ] × σ ′ ( ∑ i = 1 n W j i x i + α j ) Δαj=∂E∂αj=∂E∂bj×∂bj∂αj=∑k=1q[∂Ek∂yk×∂yk∂bj]×∂bj∂αj=∑k=1q[(yk−ok)×σ′(∑j=1pVkjbj+βk)×Vkj]×σ′(∑i=1nWjixi+αj)=∑k=1q[Δβk×Vkj]×σ′(∑i=1nWjixi+αj)
三层任意激活函数BP扩展到任意层数
网络定义
总共有n n 层,用l l 索引层数,第l l 层第j j 个单元到第l − 1 l−1 层第i i 的连接权重为W l j i W j i l ,第l l 层的第j j 个单元值用y l j yjl 索引,偏置用b l j bjl 索引,则有
y l j E = σ ( ∑ i W l j i y l − 1 i + b l j ) = 1 2 ∑ j ( o j − y n j ) 2 yjl=σ(∑iWjilyil−1+bjl)E=12∑j(oj−yjn)2
误差对于任意层的偏置参数求导
∂ E ∂ b l j = ∂ E ∂ y l j × ∂ y l j ∂ b l j = ∂ E ∂ y l j × σ ′ ( ∑ i W l j i y l − 1 i + b l j ) ∂E∂bjl=∂E∂yjl×∂yjl∂bjl=∂E∂yjl×σ′(∑iWjilyil−1+bjl)
很容易发现重点在于∂ E ∂ y l j ∂E∂yjl 的推导,这个就是传说中的链式法则,从最后一层递推到第l l 层,这一步一定要注意上下标
我之前很理所当然地写出了下式
∂ E ∂ y l = ∂ E ∂ y n × ∂ y n ∂ y n − 1 ⋯ × ∂ y l + 1 ∂ y l ∂ E ∂ y l = ∂ E ∂ y n × ∂ y n ∂ y n − 1 ⋯ × ∂ y l + 1 ∂ y l
如果按照矩阵求导方法深究这个式子是有问题的,第一项
∂ E ∂ y n ∂E∂yn 是标量对向量的偏导,
∂ y n ∂ y n − 1 ∂yn∂yn−1 是列向量对列向量的求导,它俩的维度根本不一样,做不了乘法操作。那么如何执行链式求导?可以从最后层向前推几层试试:
∂ E ∂ y n i = o i − y i ∂E∂yin=oi−yi
误差函数对第n − 1 n−1 层的第i i 个单元的偏导:
∂ E ∂ y n − 1 i = ∑ j [ ∂ E ∂ y n j × ∂ y n j ∂ y n − 1 i ] ∂ E ∂ y i n − 1 = ∑ j [ ∂ E ∂ y j n × ∂ y j n ∂ y i n − 1 ]
误差函数对第n − 2 n−2 层的第i i 个单元的偏导:
∂ E ∂ y n − 2 i = ∑ j [ ∂ E ∂ y n − 1 j × ∂ y n − 1 j ∂ y n − 2 i ] ∂ E ∂ y i n − 2 = ∑ j [ ∂ E ∂ y j n − 1 × ∂ y j n − 1 ∂ y i n − 2 ]
然后将误差函数对第n − 1 n−1 层的第j j 个单元的偏导带入进来就可以求出来
以此类推…………………
误差函数对第l l 层的第i i 个单元的偏导:
∂ E ∂ y l i = ∑ j [ ∂ E ∂ y l + 1 j × ∂ y l + 1 j ∂ y l i ] ∂ E ∂ y i l = ∑ j [ ∂ E ∂ y j l + 1 × ∂ y j l + 1 ∂ y i l ]
上述式子中的∂ E ∂ y l + 1 i ∂E∂yil+1 可以用递推的方法求解出来,而另一项是: ∂ y l + 1 j ∂ y l i = σ ′ ( ∑ i W l + 1 j i y l i + b l + 1 j ) × W l + 1 j i ∂yjl+1∂yil=σ′(∑iWjil+1yil+bjl+1)×Wjil+1
最终得到误差函数关于第l l 层的第i i 个单元偏置参数的偏导
∂ E ∂ b l i = ∂ E ∂ y l j × σ ′ ( ∑ i W l j i y l − 1 i + b l j ) = ∂ E ∂ y l + 1 j × ∂ y l + 1 j ∂ y l i × σ ′ ( ∑ i W l j i y l − 1 i + b l j ) = ∑ j [ ∂ E ∂ y l + 1 j × σ ′ ( ∑ i W l + 1 j i y l i + b l + 1 j ) × W l + 1 j i ] × σ ′ ( ∑ i W l j i y l − 1 i + b l j ) ∂E∂bil=∂E∂yjl×σ′(∑iWjilyil−1+bjl)=∂E∂yjl+1×∂yjl+1∂yil×σ′(∑iWjilyil−1+bjl)=∑j[∂E∂yjl+1×σ′(∑iWjil+1yil+bjl+1)×Wjil+1]×σ′(∑iWjilyil−1+bjl)
注意上式开头的
∑ j ∑j 中的
j j 是第
l + 1 l + 1 层的神经元索引,后面的
σ ′ ( ∑ i + b l J ) σ′(∑i+bJl) 的
j j 是第
i i 层的索引。
式子看起来很复杂,感觉跟网上看到的不一样啊,网上的多简单,这个看着这么多加和以及乘法,乱七八糟的,必须得验证一下,我们把它套到三层BP中,验证隐层和输出层的偏置更新:
∂ E ∂ b n j = ∂ E ∂ y n j × σ ′ ( ∑ i W n j i y n − 1 i + b l j ) = ( y j − o j ) × σ ′ ( ∑ i W n j i y n − 1 i + b l j ) ∂E∂bjn=∂E∂yjn×σ′(∑iWjinyin−1+bjl)=(yj−oj)×σ′(∑iWjinyin−1+bjl)
∂ E ∂ b n − 1 j = ∑ j [ ∂ E ∂ y n j × σ ′ ( ∑ i W n j i y l i + b n j ) × W n j i ] × σ ′ ( ∑ i W l j i y n − 2 i + b n − 1 j ) = ∑ j [ ( y j − o j ) × σ ′ ( ∑ i W n j i y l i + b n j ) × W n j i ] × σ ′ ( ∑ i W l j i y n − 2 i + b n − 1 j ) ∂E∂bjn−1=∑j[∂E∂yjn×σ′(∑iWjinyil+bjn)×Wjin]×σ′(∑iWjilyin−2+bjn−1)=∑j[(yj−oj)×σ′(∑iWjinyil+bjn)×Wjin]×σ′(∑iWjilyin−2+bjn−1)
可以发现与第二章的结论完全一致的。
误差对任意层的权重参数求导
这个其实与偏置很类似:
∂ E ∂ W l j i = ∂ E ∂ y l j × ∂ y l j ∂ W l j i = ∂ E ∂ y l j × σ ′ ( ∑ i W l j i y l − 1 i + b l j ) × y l − 1 i = ∂ E ∂ b l j × y l − 1 i = ∑ j [ ∂ E ∂ y l + 1 j × σ ′ ( ∑ i W l + 1 j i y l i + b l + 1 j ) × W l + 1 j i ] × σ ′ ( ∑ i W l j i y l − 1 i + b l j ) × y l − 1 i ∂E∂Wjil=∂E∂yjl×∂yjl∂Wjil=∂E∂yjl×σ′(∑iWjilyil−1+bjl)×yil−1=∂E∂bjl×yil−1=∑j[∂E∂yjl+1×σ′(∑iWjil+1yil+bjl+1)×Wjil+1]×σ′(∑iWjilyil−1+bjl)×yil−1
简化结果
上面的式子看的头晕眼花,复杂得飞起,网上其它教程为啥都那么简单,只有δ l + 1 δl+1 什么什么的,我们来试试将上式简化一波,同时也是由于神经网络中并不是一个梯度一个梯度更新,你没有看到过谁写梯度更新用for
循环分别控制权重w j i wji 的两个维度吧,一般都是直接用矩阵运算计算得到w w ,记住E E 是实数值而非向量,W W 和b b 一个是二维矩阵,一个是一维列向量,然后利用矩阵求导法则试试。
在此,先规定,我们所求的偏置向量为列向量,这里先套用实值对列向量的导数如下:
∂ E ∂ b l = ⎡ ⎣ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ∂ E ∂ b 1 ∂ E ∂ b 2 ⋮ ∂ E ∂ b i ⋮ ⎤ ⎦ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ∂E∂bl=[∂E∂b1∂E∂b2⋮∂E∂bi⋮]
为了便于书写或者与网络的证明方法对齐,我们还设
δ l + 1 j z l j ⇒ ∂ E ∂ b l i = ∂ E ∂ y l + 1 j × σ ′ ( ∑ i W l + 1 j i y l i + b l + 1 j ) = ( ∑ i W l j i y l − 1 i + b l j ) = ∑ j [ ∂ E ∂ y l + 1 j × σ ′ ( ∑ i W l + 1 j i y l i + b l + 1 j ) × W l + 1 j i ] × σ ′ ( ∑ i W l j i y l − 1 i + b l j ) = ∑ j ( δ l + 1 j × W l + 1 j i ) × σ ′ ( z l i ) δjl+1=∂E∂yjl+1×σ′(∑iWjil+1yil+bjl+1)zjl=(∑iWjilyil−1+bjl)⇒∂E∂bil=∑j[∂E∂yjl+1×σ′(∑iWjil+1yil+bjl+1)×Wjil+1]×σ′(∑iWjilyil−1+bjl)=∑j(δjl+1×Wjil+1)×σ′(zil)
然后我们简化
∂ E b l ∂Ebl ,即误差
值 对第
l l 层偏置
向量 求导得到的梯度
向量
∂ E ∂ b l = ⎡ ⎣ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ W l + 1 11 W l + 1 12 ⋮ W l + 1 1 i ⋮ W l + 1 21 W l + 1 22 ⋱ W l + 1 2 i ⋮ ⋯ ⋯ ⋱ ⋯ ⋮ W l + 1 j 1 W l + 1 j 2 ⋱ W l + 1 j i ⋮ ⋯ ⋯ ⋮ ⋯ ⋮ ⎤ ⎦ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ × ⎡ ⎣ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ δ l + 1 1 δ l + 1 2 ⋮ δ l + 1 j ⋮ ⎤ ⎦ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⊙ ⎡ ⎣ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ ⎢ σ ′ ( z l 1 ) σ ′ ( z l 2 ) ⋮ σ ′ ( z l i ) ⋮ ⎤ ⎦ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ ⎥ = ( W l + 1 ) T × δ l + 1 ⊙ σ ′ ( z l ) ∂ E ∂ b l = [ W 11 l + 1 W 21 l + 1 ⋯ W j 1 l + 1 ⋯ W 12 l + 1 W 22 l + 1 ⋯ W j 2 l + 1 ⋯ ⋮ ⋱ ⋱ ⋱ ⋮ W 1 i l + 1 W 2 i l + 1 ⋯ W j i l + 1 ⋯ ⋮ ⋮ ⋮ ⋮ ⋮ ] × [ δ 1 l + 1 δ 2 l + 1 ⋮ δ j l + 1 ⋮ ] ⊙ [ σ ′ ( z 1 l ) σ ′ ( z 2 l ) ⋮ σ ′ ( z i l ) ⋮ ] = ( W l + 1 ) T × δ l + 1 ⊙ σ ′ ( z l )
注意式子中”
× × ”代表矩阵与列向量的乘法操作,
⊙ ⊙ 代表两个相同维度列向量的对应位置元素乘积。
现在应该熟悉了最终的式子与网上的基本一致。这就是整个BP的推导过程。
后记
此篇博客一方面是对上一篇证明BP的博客的更进一步详解与结论证明,另一方面是为了矫正自己之前对矩阵偏导的误解。矩阵偏导分别包含:行向量对行向量的偏导、行向量对列向量的偏导、列向量对列向量的偏导、列向量对行向量的偏导、矩阵对行向量的偏导、矩阵对列向量的偏导、行向量对矩阵的偏导、列向量对矩阵的偏导、矩阵对矩阵的偏导;在证明BP的时候,要严格按照求导法则来做,不能弄混了。
关于使用矩阵对向量的求导来证BP的一些问题,可以见本人与刘建平老师在深度神经网络(DNN)反向传播算法(BP)博客评论区的讨论,主要针对∂ ( W X ) ∂ X ∂(WX)∂X 即下一层未激活前的输入向量对上一层激活后的输出向量的偏导值是否为W T WT 或者是更大矩阵的讨论。