我们知道反向传播(BP)算法的发明促成了神经网络的第二次发展浪潮,到目前为止BP算法依旧是训练神经网络的首选算法。但是对于如此重要的一个算法,我们大多数人只是记住算法的计算公式,或者在程序中直接调用,对算法的来龙去脉知之甚少,这篇博客将从数学上推导出BP算法的计算公式。
损失函数最小化和梯度下降法
几乎所有的机器学习算法的训练目标都是找到使损失函数最小的参数。具体到神经网络模型中,我们给定网络输入
{
(
x
1
,
y
^
1
)
,
(
x
2
,
y
^
2
)
,
.
.
.
,
(
x
n
,
y
^
n
)
}
\{(x^1,\hat{y}^1),(x^2,\hat{y}^2),...,(x^n,\hat{y}^n)\}
{(x1,y^1),(x2,y^2),...,(xn,y^n)},其中
x
k
x^k
xk表示第
k
(
k
∈
[
1
,
n
]
)
k(k\in[1,n])
k(k∈[1,n])个输入样本,
y
^
k
(
k
∈
[
1
,
n
]
)
\hat{y}^k(k\in[1,n])
y^k(k∈[1,n])代表对应的理想输出。我们期望网络输出和理想输出的总体误差越小越好,我们用损失函数
C
C
C来度量这个误差,因此得到我们的训练目标——使损失函数
C
C
C尽可能小(
C
C
C的定义方式有多种,下面只是其中一种):
C
=
1
N
∑
k
=
1
N
(
y
k
−
y
^
k
)
2
C=\frac{1}{N}\sum_{k=1}^N(y^k-\hat{y}^k)^2
C=N1k=1∑N(yk−y^k)2
其中
y
k
y^k
yk表示网络输出,现在我们就是要去找到损失函数的最小值点,对应的参数就是我们要求的最佳参数。求最小值在数学中经常使用梯度下降算法,所以求解问题等价于求:
∂
C
∂
w
i
j
l
∂
C
∂
b
i
l
\frac{\partial C}{\partial w_{ij}^l}\\ \frac{\partial C}{\partial b_{i}^l}
∂wijl∂C∂bil∂C
其中 w i j l w_{ij}^l wijl表示第 l l l层第 i i i个神经元与第 l − 1 l-1 l−1层第 j j j个神经元之间的连接权重, b i l b_{i}^l bil表示第 l l l层第 i i i个神经元的偏置。如果我们直接去求所有神经元的导数,将是一个费时费力的过程,能不能找到一个高效的算法来计算网络参数的梯度呢?
链式求导法则
在介绍BP算法之前,有必要介绍一下高等数学中的链式求导法则,主要包括以下两种情形。
Case 1
y
=
g
(
x
)
z
=
h
(
y
)
Δ
(
x
)
→
Δ
(
y
)
→
Δ
(
z
)
y=g(x)\quad z=h(y)\\ \Delta(x)\to\Delta(y)\to\Delta(z)
y=g(x)z=h(y)Δ(x)→Δ(y)→Δ(z)
有
d
z
d
x
=
d
z
d
y
d
y
d
x
\frac{dz}{dx}=\frac{dz}{dy}\frac{dy}{dx}
dxdz=dydzdxdy
Case 2
x
=
g
(
s
)
y
=
h
(
s
)
z
=
k
(
x
,
y
)
x=g(s)\quad y=h(s)\quad z=k(x,y)
x=g(s)y=h(s)z=k(x,y)
有
∂
z
∂
s
=
∂
z
∂
x
∂
x
∂
s
+
∂
z
∂
y
∂
y
∂
s
\frac{\partial z}{\partial s}=\frac{\partial z}{\partial x}\frac{\partial x}{\partial s} + \frac{\partial z}{\partial y}\frac{\partial y}{\partial s}
∂s∂z=∂x∂z∂s∂x+∂y∂z∂s∂y
上面两条就称为求导的链式法则。
BP算法推导过程
下面以求
∂
C
∂
w
i
j
l
\frac{\partial C}{\partial w_{ij}^l}
∂wijl∂C为例。首先看下图所示的一般情况。
根据链式求导法则有,
Δ
w
i
j
l
→
Δ
z
i
l
→
⋯
→
Δ
C
\Delta w_{ij}^l\to\Delta z_i^l\to\cdots\to\Delta C
Δwijl→Δzil→⋯→ΔC
所以我们可以将
∂
C
∂
w
i
j
l
\frac{\partial C}{\partial w_{ij}^l}
∂wijl∂C下成下面的形式:
∂
C
∂
w
i
j
l
=
∂
C
∂
z
i
l
∂
z
i
l
∂
w
i
j
l
\frac{\partial C}{\partial w_{ij}^l}=\frac{\partial C}{\partial z_i^l}\frac{\partial z_i^l}{\partial w_{ij}^l}
∂wijl∂C=∂zil∂C∂wijl∂zil
根据
z
i
l
=
∑
j
w
i
j
l
a
j
l
−
1
+
b
i
l
z_i^l=\sum_jw_{ij}^la_j^{l-1}+b_i^l
zil=j∑wijlajl−1+bil
有
∂
z
i
l
∂
w
i
j
l
=
a
j
l
−
1
\frac{\partial z_i^l}{\partial w_{ij}^l}=a_j^{l-1}
∂wijl∂zil=ajl−1
所以现在的目标就是求出
∂
C
∂
z
i
l
\frac{\partial C}{\partial z_i^l}
∂zil∂C。
令
∂
C
∂
z
i
l
=
δ
i
l
\frac{\partial C}{\partial z_i^l}=\delta_i^l
∂zil∂C=δil
我们容易发现,当
l
l
l是最后一层(即
l
=
L
l=L
l=L)时,
δ
i
L
\delta_i^L
δiL是容易计算的。
因为
Δ
z
i
L
→
Δ
a
i
L
=
Δ
y
i
→
Δ
C
\Delta z_i^L\to\Delta a_i^L=\Delta y_i\to\Delta C
ΔziL→ΔaiL=Δyi→ΔC
所以
δ
i
L
=
∂
C
∂
z
i
L
=
∂
C
∂
y
i
∂
y
i
∂
z
i
L
\delta_i^L=\frac{\partial C}{\partial z_i^L}=\frac{\partial C}{\partial y_i}\frac{\partial y_i}{\partial z_i^L}
δiL=∂ziL∂C=∂yi∂C∂ziL∂yi
式中第一项取决于我们定义的损失函数,第二项就是对激活函数求导,我们记为
σ
′
(
z
i
L
)
\sigma^\prime(z_i^L)
σ′(ziL)。考虑第
L
L
L层中所有的神经元,写成矩阵的形式有:
δ
L
=
σ
′
(
z
L
)
⋅
∇
C
(
y
)
(1)
\begin{aligned} \delta^L=\sigma^\prime(z^L)\centerdot\nabla C(y) \tag 1 \end{aligned}
δL=σ′(zL)⋅∇C(y)(1)
现在考虑
l
l
l不是最后一层的情况,同样的,我们根据求导的链式法则有:
所以
δ
i
l
=
∂
C
∂
z
i
l
=
∂
a
i
l
∂
z
i
l
∑
k
∂
C
∂
z
k
l
+
1
∂
z
k
l
+
1
∂
a
i
l
\delta_i^l=\frac{\partial C}{\partial z_i^l}=\frac{\partial a_i^l}{\partial z_i^l}\sum_k\frac{\partial C}{\partial z_k^{l+1}}\frac{\partial z_k^{l+1}}{\partial a_i^l}
δil=∂zil∂C=∂zil∂ailk∑∂zkl+1∂C∂ail∂zkl+1
式中,第一项同样是激活函数的导数,第二项又是一个
δ
k
l
+
1
\delta_k^{l+1}
δkl+1,第三项等于
w
k
i
l
+
1
w_{ki}^{l+1}
wkil+1。所以有:
δ
i
l
=
σ
′
(
z
i
l
)
∑
k
w
k
i
l
+
1
δ
k
l
+
1
\delta_i^l=\sigma^\prime(z_i^l)\sum_kw_{ki}^{l+1}\delta_k^{l+1}
δil=σ′(zil)k∑wkil+1δkl+1
同样整理成矩阵的形式有:
δ
l
=
σ
′
(
z
l
)
⋅
(
w
l
+
1
)
T
⋅
δ
l
+
1
(2)
\delta^l=\sigma^\prime(z^l)\centerdot (w^{l+1})^T\centerdot\delta^{l+1} \tag 2
δl=σ′(zl)⋅(wl+1)T⋅δl+1(2)
最后,综上所述,整理(1)(2)可得:
δ
l
=
{
σ
′
(
z
L
)
⋅
∇
C
(
y
)
l
=
L
σ
′
(
z
l
)
⋅
(
w
l
+
1
)
T
⋅
δ
l
+
1
l
≠
L
\delta^l = \begin{cases} \sigma^\prime(z^L)\centerdot\nabla C(y) &\text{$l=L$}\\ \sigma^\prime(z^l)\centerdot (w^{l+1})^T\centerdot\delta^{l+1} &\text{$l\neq L$} \end{cases}
δl={σ′(zL)⋅∇C(y)σ′(zl)⋅(wl+1)T⋅δl+1l=Ll=L
同前向传播比较,我们发现误差是一个从后向前传递的过程,所以我们称该算法为反向传播(BackPropagation,BP)算法。具体的误差传播过程如下图所示:
总结
BP算法作为一个经典的神经网络训练算法深刻的促进了神经网络的发展,目前一些深度学习算法中依旧可以看到BP的身影。但是BP算法也存在一些缺陷,比如:
- 训练时间长
- 可能陷入局部最小值
针对BP算法的这些缺陷,目前也有许多BP算法的改进型,比如Adagrad,Momentum等。总之,BP算法作为神经网络训练最经典的算法,需要我们从来源到结果有一个深入的了解。