反向传播算法详细推导
反向传播(英语:Backpropagation,缩写为BP)是“误差反向传播”的简称,是一种与最优化方法(如梯度下降法)结合使用的,用来训练人工神经网络的常见方法。该方法对网络中所有权重计算损失函数的梯度。这个梯度会反馈给最优化方法,用来更新权值以最小化损失函数。 在神经网络上执行梯度下降法的主要算法。该算法会先按前向传播方式计算(并缓存)每个节点的输出值,然后再按反向传播遍历图的方式计算损失函数值相对于每个参数的偏导数。
我们将以全连接层,**函数采用 Sigmoid
函数,误差函数为 Softmax+MSE
损失函数的神经网络为例,推导其梯度传播方式。
准备工作
1、Sigmoid 函数的导数
回顾 sigmoid
函数的表达式:
σ(x)=1+e−x1
其导数为:
dxdσ(x)=dxd(1+e−x1)
=(1+e−x)2e−x
=(1+e−x)2(1+e−x)−1
=(1+e−x)21+e−x−(1+e−x1)2
=σ(x)−σ(x)2
=σ(1−σ)
可以看到,Sigmoid
函数的导数表达式最终可以表达为**函数的输出值的简单运算,利
用这一性质,在神经网络的梯度计算中,通过缓存每层的 Sigmoid 函数输出值,即可在需
要的时候计算出其导数。Sigmoid 函数导数的实现:
import numpy as np
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def derivative(x):
return sigmoid(x)*(1-sigmoid(x))
2、均方差函数梯度
均方差损失函数表达式为:
L=21k=1∑K(yk−ok)2
其中yk为真实值,ok为输出值。则它的偏导数∂oi∂L 可以展开为:
∂oi∂L=21k=1∑K∂oi∂(yk−ok)2
利用链式法则分解为
∂oi∂L=21k=1∑K⋅2⋅(yk−ok)⋅∂oi∂(yk−ok)
∂oi∂L=k=1∑K(yk−ok)⋅(−1)⋅∂oi∂ok
∂oi∂ok仅当 k = i
时才为 1
,其他点都为0
, 也就是说 ∂oi∂ok只与第 i
号节点相关,与其他节点无关,因此上式中的求和符号可以去掉,均方差的导数可以推导为
∂oi∂L=(oi−yi)
单个神经元梯度
对于采用 Sigmoid
**函数的神经元模型,它的数学模型可以写为
o1=σ(w1x+b1)
其中
- 变量的上标表示层数,如 o1 表示第一个隐藏层的输出
-
x
表示网络的输入
单个神经元模型如下图所示
- 输入节点数为
J
- 其中输入第 j 个节点到输出 o1 的权值连接记为 wj11
- 上标表示权值属于的层数,下标表示当前连接的起始节点号和终止节点号
- 如下标 j1 表示上一层的第 j 号节点到当前层的 1 号节点
- 未经过**函数的输出变量为 z11,经过**函数之后的输出为 o11
- 由于只有一个输出节点,故 o11=o1
下面我们来计算均方差算是函数的梯度
由于单个神经元只有一个输出,那么损失函数可以表示为
L=21(o11−t)2
添加 21 是为了计算方便,我们以权值连接的第 j∈[1,J] 号节点的权值 wj1 为例,考虑损失函数 L 对其的偏导数 ∂wj1∂L
∂wj1∂L=(o1−t)∂wj1∂o1
由于 o1=σ(z1) ,由上面的推导可知 Sigmoid 函数的导数 σ′=σ(1−σ)
∂wj1∂L=(o1−t)∂wj1∂σ(z1)
=(o1−t)σ(z1)(1−σ(z1))∂wj1∂z1
把 σ(z1) 写成 o1
=(o1−t)o1(1−o1)∂wj1∂z1
由于 ∂wj1∂z1=xj
∂wj1∂L=(o1−t)o1(1−o1)xj
从上式可以看到,误差对权值 wj1 的偏导数只与输出值 o1 、真实值 t
以及当前权值连接的输 xj 有关
全链接层梯度
我们把单个神经元模型推广到单层全连接层的网络上,如下图所示。输入层通过一个全连接层得到输出向量 o1 ,与真实标签向量 t
计算均方差。输入节点数为 J ,输出节点数为 K
。
与单个神经元不同,全链接层有多个输出节点 o11,o21,o31,...,oK1 ,每个输出节点对应不同真实标签 t1,t2,t3,...,tK ,均方误差可以表示为
L=21i=1∑K(oi1−ti)2
由于 ∂wjk∂L 只与 ok1 有关联,上式中的求和符号可以去掉,即 i=k
∂wjk∂L=(ok−tk)∂wjk∂ok
将 ok=σ(zk) 带入
∂wjk∂L=(ok−tk)∂wjk∂σ(zk)
考虑 Sigmoid 函数的导数 σ′=σ(1−σ)
∂wjk∂L=(ok−tk)σ(zk)(1−σ(zk))∂wjk∂zk1
将 σ(zk) 记为 ok
∂wjk∂L=(ok−tk)ok(1−ok)∂wjk∂zk1
最终可得
∂wjk∂L=(ok−tk)ok(1−ok)⋅xj
由此可以看到,某条连接 wjk 上面的连接,只与当前连接的输出节点 ok1 ,对应的真实值节点的标签 tk1 ,以及对应的输入节点 x
有关。
我们令 δk=(ok−tk)ok(1−ok) ,则 ∂wjk∂L 可以表达为
∂wjk∂L=δk⋅xj
其中 δk 变量表征连接线的终止节点的梯度传播的某种特性,使用 δk 表示后,∂wjk∂L 偏导数只与当前连接的起始节点 xj,终止节点处 δk 有关,理解起来比较直观。
反向传播算法
看到这里大家也不容易,毕竟这么多公式哈哈哈,不过激动的时刻到了
先回顾下输出层的偏导数公式
∂wjk∂L=(ok−tk)ok(1−ok)⋅xj=δk⋅xj
多层全连接层如下图所示
- 输出节点数为
K
,输出 ok=[o1k,o2k,o3k,...,okk]
- 倒数的二层的节点数为
J
,输出为 oJ=[o1J,o2J,...,oJJ]
- 倒数第三层的节点数为
I
,输出为 oI=[o1I,o2I,...,oII]
均方误差函数
∂wij∂L=∂wij∂21k∑(ok−tk)2
由于 L 通过每个输出节点 ok 与 wi 相关联,故此处不能去掉求和符号
∂wij∂L=k∑(ok−tk)∂wij∂ok
将 ok=σ(zk) 带入
∂wij∂L=k∑(ok−tk)∂wij∂σ(zk)
Sigmoid 函数的导数 σ′=σ(1−σ) ,继续求导,并将 σ(zk) 写回 ok
∂wij∂L=k∑(ok−tk)ok(1−ok)∂wij∂zk
对于 ∂wij∂zk 可以应用链式法则分解为
∂wij∂zk=oj∂zk⋅∂wij∂oj
由图可知 (zk=oj⋅wjk+bk) ,故有
oj∂zk=wjk
所以
∂wij∂L=k∑(ok−tk)ok(1−ok)wjk⋅∂wij∂oj
考虑到 ∂wij∂oj 与 k
无关,可将其提取出来
∂wij∂L=∂wij∂oj⋅k∑(ok−tk)ok(1−ok)wjk
再一次有 ok=σ(zk) ,并利用 Sigmoid 函数的导数 σ′=σ(1−σ) 有
∂wij∂L=oj(1−oj)∂wij∂zj⋅k∑(ok−tk)ok(1−ok)wjk
由于 ∂wij∂zj=oi(zj=oi⋅wij+bj)
∂wij∂L=oj(1−oj)oi⋅k∑(ok−tk)ok(1−ok)wjk
其中 δkK=(ok−tk)ok(1−ok) ,则
∂wij∂L=oj(1−oj)oi⋅k∑δkK⋅wjk
仿照输出层的书写方式,定义
δjJ=oj(1−oj)⋅k∑δkK⋅wjk
此时 ∂wij∂L 可以写为当前连接的起始节点的输出值 oi 与终止节点 j 的梯度信息 δjJ 的简单相乘运算:
∂wij∂L=δjJ⋅oiI
通过定义 δ 变量,每一层的梯度表达式变得更加清晰简洁,其中 $ \delta $ 可以简单理解为当前连接 wij 对误差函数的贡献值。
总结
输出层:
∂wjk∂L=δkK⋅oj
δkK=(ok−tk)ok(1−ok)
倒数第二层:
∂wij∂L=δjJ⋅oi
δjJ=oj(1−oj)⋅k∑δkK⋅wjk
倒数第三层:
∂wni∂L=δiI⋅on
δiI=oi(1−oi)⋅j∑δjJ⋅wij
其中 on 为倒数第三层的输入,即倒数第四层的输出
依照此规律,只需要循环迭代计算每一层每个节点的 δkK,δjJ,δiI,... 等值即可求得当前层的偏导数,从而得到每层权值矩阵 W 的梯度,再通过梯度下降算法迭代优化网络参数即可。
好了,反向传播算法推导完毕,代码实现可以参考另一篇博客神经网络之动手实现反向传播(BP)算法