如何理解反向传播算法
对于一个算法或者模型的理解可以分为直观理解,算法理解和数学证明三个层次。直观的理解能够启发思维,算法层面的理解能够消除歧义,数学证明能够提供更一般化的问题描述,为潜在的问题提供分析工具。本文试图从这三个层面对神经网络中的反向传播算法做简单的总结,文中大量的图片和公式来源于《神经网络与深度学习》一书第二章1,后续不在 一一引用。
神经网络模型的数学表示
反向传播算法是神经网络的一种权重更新算法,最早提出于20世纪70年代,直到论文 2 的出现才逐渐受到重视,后续成为神经网络学习的主流算法之一。在给出具体的数学描述之前,这里首先给出神经网络模型中所使用的数学符号的含义。
我们使用 ωljk ω j k l 表示第 l−1 l − 1 层的第 k k 个神经元与第层的第 j j 个神经元的连接权重。如下图所示,是 第2层的第4个神经元到第三层的第2个神经元的权重。这里 j j 与的书写顺序初看比较别扭,需要稍微留意一下。
与此相似,我们使用 blj b j l 表示第 l l 层的第个神经元的偏置, alj a j l 表示第 l l 层的第个神经元的激活值,如下图所示。
使用
σ
σ
表示激活函数,第
l−1
l
−
1
层到第
l
l
层的前向传播可以表示为:
上述的求和是遍历第 l−1 l − 1 层的所有神经元。
为了方便进行矩阵化的描述,我们使用
ωl
ω
l
表示第
l
l
层的权重矩阵,矩阵的第行
k
k
列的元素就是。使用
bl
b
l
表示偏置向量,
al
a
l
表示激活值得向量。那么前向传播的向量表示为:
为了表示方便,我们又引入中间变量 zl=ωlal−1+bl z l = ω l a l − 1 + b l 表示线性组合部分,当然对于向量中的单个元素有: zlj=∑kωljkal−1k+blj z j l = ∑ k ω j k l a k l − 1 + b j l 。
一个
L
L
层的神经网络可以表示为:
对代价函数的基本假设
代价函数度量模型输出与真实值的拟合程度。反向传播算法解决的基本问题就是通过不断更新权重来最小化代价函数。一个典型的二次的代价函数可以表示为:
其中, n n 表示训练集的样本数量,是单个样本, y(x) y ( x ) 是对应的期望得到的输出, L L 是神经元的总层数。这里我们对代价函数做出两个基本假设。
假设一:代价函数可以表示为单个样本代价函数的平均,即代价函数可以写作:,其中 Cx C x 是单个样本的代价。
做出这个假设是因为我们后面讨论的梯度算法计算的是 ∂Cx/∂ω ∂ C x / ∂ ω 和 ∂Cx/∂b ∂ C x / ∂ b ,这样我们就可以通过求平均的方式得到 ∂C/∂ω ∂ C / ∂ ω 和 ∂C/∂b ∂ C / ∂ b 。后续在反向传播算法的描述中,为了简化表示, Cx C x 一般简记为 C C 。
假设二:代价函数依赖于神经网络最后一层的输出值,也就是说,这应该是一个比较显然的假设。
反向传播算法
反向传播算法解决的基本问题就是通过不断更新权重来最小化代价函数,一个自然的想法是通过梯度下降的方法来实现。牵涉到计算 ∂C/∂ωljk ∂ C / ∂ ω j k l 。然后通过 ωljk=ωljk−α∂C∂ωljk ω j k l = ω j k l − α ∂ C ∂ ω j k l 更新权重,其中 α α 是学习率。反向传播算法就是通过误差反向传播的算法给出一个步骤来计算偏导数 ∂C/∂ωljk ∂ C / ∂ ω j k l 。
首先我们定义第
l
l
层第个神经元的输入误差:
反向传播算法就是利用 δlj δ j l 来作为中间变量计算 ∂Cx/∂ω ∂ C x / ∂ ω 和 ∂Cx/∂b ∂ C x / ∂ b 。
反向传播算法利用四个等式来最终确定最终的偏导数,在具体介绍算法之前,我们首先引入符号
⨀
⨀
来表示两个矩阵对应元素相乘的操作,比如:
下面给出是个基本的等式,并给出证明。
等式一:输出层的误差公式
该等式计算输出层的误差。等式 BP1的证明是比较直观的,可以通过微积分中的链式法则很容易计算得到。
首先,
显然:
带入式(6)即可得到 BP1 B P 1 ,证毕。我们也给出BP1向量化的等价描述:
等式二:给定输入误差 δl+1 δ l + 1 时, δl δ l 的计算:
同理,利用链式法则
而根据前向传播的关系:
则有
代入式(8)得到:
同样,可以写成矩阵的形式,即可得到BP2。
等式三:给定
δlj
δ
j
l
关于偏重
blj
b
j
l
的偏导的计算
根据: zlj=∑kωljkal−1k+blj z j l = ∑ k ω j k l a k l − 1 + b j l 得到 ∂zlj∂blj=1 ∂ z j l ∂ b j l = 1 。那么
问题得证,同样矩阵形式描述为:
等式四:给定 δlj δ j l 关于偏重 ωljk ω j k l 的偏导的计算
同样,根据
zlj=∑kωljkal−1k+blj
z
j
l
=
∑
k
ω
j
k
l
a
k
l
−
1
+
b
j
l
,得到
∂zlj∂ωljk=al−1k
∂
z
j
l
∂
ω
j
k
l
=
a
k
l
−
1
。那么:
得证,同样我们可以采用矩阵形式描述:
至此,反向传播算法中四个基础的等式证明完毕。这里做个总结:
BP1计算最后一层的输入误差,然后可以利用BP2迭代的计算每一层的输入误差 δjl δ l j 。在各层输入误差计算完毕之后就可以通过BP3和BP4计算各个参数对应的偏导数。反向传播算法的算法描述为:
- 输入 x: 设置初始值 a0=x a 0 = x
- 前向传播:对于 l=1,2,…,L l = 1 , 2 , … , L ,计算 zl=wlal−1+bl z l = w l a l − 1 + b l 以及 al=σ(zl) a l = σ ( z l ) 。
- 计算最后一层的误差 δL=∇aC⊙σ′(zL). δ L = ∇ a C ⊙ σ ′ ( z L ) .
- 反向传播算法 对于 l=L−1,L−2,…,1 l = L − 1 , L − 2 , … , 1 ,计算 δl=((wl+1)Tδl+1)⊙σ′(zl) δ l = ( ( w l + 1 ) T δ l + 1 ) ⊙ σ ′ ( z l ) ;
- 计算各个参数对应的梯度 ∂C∂bl=δl ∂ C ∂ b l = δ l , ∂C∂wl=δl(al−1)T ∂ C ∂ w l = δ l ( a l − 1 ) T
从公式的角度,我们对学习过程可以获得以下理解:
- δl δ l 的计算依赖于 σ σ 。比如对于激活函数 σ(z)=11+e−z σ ( z ) = 1 1 + e − z ,在靠近0或1,也成为饱和状态时,其导数 σ′(z) σ ′ ( z ) 接近0,那么BP2中等式第二项接近0,导致 δ δ 接近0。那么后续计算的梯度同样会接近0,从而产生梯度消失的问题;所以,实践中为了加快学习速度会采用梯度不会饱和的激活函数,如RELU函数。
- 当 al a l 接近0时,从BP4中可以看出,同样会导致梯度接近0,同样会导致参数学习过慢。
反向传播的直观理解
反向传播算法的思路来源是什么?设想反向传播算法出现以前,利用梯度下降法寻找最优参数是一个非常自然的思路,那么面临的问题同样是计算
∂C/∂ω
∂
C
/
∂
ω
的问题。在看到解析求解梯度的困难后,很自然的想法可能是通过式(14)计算梯度。
然而,这样的计算在问题复杂度增加时会面临很大的问题。对于大型的深度网络,参数数量很容易达到 104 10 4 的数量级,那么按照式(14)就需要计算相应次数的前向传播才能得到估计的梯度,这在计算上是不可行的。对照反向传播算法,只需要进行一次前向传播和一次反向传播就可以完成梯度的计算,而且反向传播的计算复杂度与前向传播的复杂度是一致的。那么反向传播算法的计算效率是如何提升的呢?我们通过一个图示法进行说明。
假设,我们想计算 ωljk ω j k l 的波动对代价值的影响,那么它的波动就会形成一个传播路径,最终产生 ΔC Δ C 。
而且有:
那么,在这种情况下,很自然的想法是通过 ΔC Δ C 与 Δωljk Δ ω j k l 来估计 ∂C∂wljk ∂ C ∂ w j k l 。事实上,如果能将 ΔC Δ C 归因到是哪些参数引起的,那么问题也就解决了,反向传播的思路就是利用逐层误差再加上微积分的链式规则推导得出的。
这里再提一下新理论的发展过程,一个理论的创新是非常复杂的,不断演化的过程。比如我们这里看到的反向传播的理论非常的简单明了,但这背后可能包含了很多非常复杂的演进过程。一个新的理论的发展过程往往是这样的:最开始只是一个非常粗略的想法加上非常复杂但甚至包含错误的证明,然后等引起关注之后,会有更多的人参与进来,随之更简洁更有效的证明方法,才会被提出和改进,经过这样反复的迭代最后才形成我们看到的结果。举个简单例子,对于式(5)中误差的定义,如果我们最开始将其定义为: δlj=∂C∂alj δ j l = ∂ C ∂ a j l ,那么后续的推导和证明就会非常复杂,而对于 δlj δ j l 的定义就是不断这么摸索而来的结果。
总结
本文介绍了反向传播的原理与算法,同时给出了一个可以说是直观理解也可以说是算法的思想来源的说明。反向传播在深度学习,神经网络学习中具有非常普遍的应用。当然,目前同深度学习遭受到的质疑一样,反向传播也遭受了一些质疑3。但不管怎么说,掌握反向传播算法的原理才能更好的改进它。博客4 包含了从第一行代码开始写神经网络的教程,感兴趣的同学可以以其为案例尝试编程实现一下。
参考文献
- How the backpropagation algorithm works, http://neuralnetworksanddeeplearning.com/chap2.html ↩
- Rumelhart, D. E., Hinton, G. E., & Williams, R. J. (1986). Learning representations by back-propagating errors. Nature, 323(6088), 533–536. https://doi.org/10.1038/323533a0 ↩
- 反向传播为何饱受质疑https://mp.weixin.qq.com/s?src=11×tamp=1534695862&ver=1070&signature=nETPH-o3Ez3YpjK3rURMa4rthI3VexGfdz-YZLJvpCKjPR5P8nmMP2nLXsw7KwDVYkCI803P5C-NSZb0X71KAeEHQpeuoHoKRldiN8cAKJjxvhSMX-ci3dnyK-qgK04D&new=1 ↩
- http://www.wildml.com/2015/09/implementing-a-neural-network-from-scratch/ ↩