Neural Networks and Deep Learning(五)为什么深度神经网络难以训练

本章我们将分析一下为什么深度神经网络难以训练的问题。

首先来看问题:如果神经网络的层次不断加深,则在BP误差反向传播的过程中,网络前几层的梯度更新会非常慢,导致前几层的权重无法学习到比较好的值,这就是梯度消失问题(The vanishing gradient problem)。

以我们在第三章学习的network2.py为例(交叉熵损失函数+Sigmoid激活函数),我们可以计算每个神经元中误差对偏移量b的偏导\partial C/ \partial b,根据第二章BP网络的知识,\partial C/ \partial b也是\partial C/ \partial w的一部分(BP3和BP4的关系),所以如果\partial C/ \partial b的绝对值大,则说明梯度大,在误差反向传播的时候,bw更新就快。

假设network2的网络结构是[784,30,30,10],即有两个隐藏层,则我们可以画出在误差反向传播过程中,隐藏层每个神经元的\partial C/ \partial b的大小,用柱子长度表示。由下图可知,我们发现第二个隐藏层的梯度普遍大于第一个隐藏层的梯度,这会是一般现象吗,还是偶然现象?

既然梯度出现了层与层的差异,则可以定义第l层的梯度(如不加说明,则默认是误差C对偏移量b的梯度)向量的长度为\| \delta^l \|,比如\| \delta^1 \|表示第一个隐藏层中每个神经元的\partial C/ \partial b的绝对值之和,就是一范数,如果\| \delta^l \|越大,则说明这一层权重的更新越快。

由此,我们可以画出当有两个隐藏层时,\| \delta^l \|随epoch的变化情况:

当有三个隐藏层时:

当有四个隐藏层时:

我们发现,规律是惊人的一致,即越靠近输出层的隐藏层,\| \delta^l \|越大,即梯度更新越快;越靠近输入层的隐藏层,\| \delta^l \|越小,即梯度更新越慢。

这就会导致梯度消失的问题(The vanishing gradient problem):即在误差反向传播过程中,刚开始权重更新比较快,越到后面(越靠近输入层),则权重更新变得很慢,无法搜索到比较优的值。

所以,对于同样的network2,其他参数都不变,只是单纯增加网络层数,验证集上的准确率反而会下降!按理说网络层数增加,验证集上的准确率会上升,或者不变,至少不应该下降啊,因为最不济增加的网络层什么都不做,准确率应该一样才对,为什么反而下降了呢。虽然层数增加了,但因为上述梯度消失问题,靠近输入层的权重反而没学好,因为权重是随机初始化的,所以验证集上的准确率反而下降了。

那么,为什么层数增加会导致梯度消失问题呢,我们可以从BP的更新公式中一探究竟。

为了简化问题,假设我们的网络每一层只有一个神经元:

则根据BP的更新公式,可以计算得到

\begin{eqnarray}\frac{\partial C}{\partial b_1} = \sigma'(z_1) \, w_2 \sigma'(z_2) \,w_3 \sigma'(z_3) \, w_4 \sigma'(z_4) \, \frac{\partial C}{\partial a_4}.\tag{1}\end{eqnarray}

计算过程其实很简单,对照本博客开头的那张图,\sigma'(z_4) \, \frac{\partial C}{\partial a_4}就是(BP1),把(BP1)带入(BP2),就是不断乘以w^{l+1} \sigma'(z^l),然后就能得到下图的公式。

我们在第三章时也曾介绍到梯度消失问题,当时提出的应对策略是采用交叉熵损失函数+Sigmoid,在求解梯度时可以把\sigma'抵消掉,以此来解决梯度消失的问题。但是请注意,当时求解的仅仅是误差对输出层的梯度,可以通过交叉熵损失函数+Sigmoid抵消\sigma',对应到上图就是仅仅最后两项的\sigma'(z_4) \, \frac{\partial C}{\partial a_4}可以抵消\sigma',即只有BP公式中的(BP1)可以抵消\sigma'。而如果误差继续反向传播,则其他层的梯度依然包含\sigma'项,由上图就可以看到,\frac{\partial C}{\partial b_1}除了最后的\sigma'(z_4) \, \frac{\partial C}{\partial a_4}抵消了一个\sigma',前面还有3个\sigma'连乘。如果\sigma是Sigmoid激活函数的话,很容易就导致在Sigmoid两端,梯度更新缓慢的问题,然后又通过乘法放大了梯度消失的问题。

观察公式(1),我们发现梯度中包含很多w_j \sigma'(z_j)项相乘,如果\sigma是Sigmoid,则\sigma'(z_j) \leq 1/4,等号在z_j=0时取得;又因为权重随机初始化自w_j\sim N(0,1),所以很容易有|w_j| < 1,这就导致|w_j \sigma'(z_j)| < 1/4,多个w_j \sigma'(z_j)项相乘,越乘越小,导致梯度消失。

由下图可知,不同层的梯度,有部分是相同的,区别就在于w_j \sigma'(z_j)项乘的多少,所以这就能说明为什么反向传播得越多(越靠近输入层),梯度更新越慢。

上述w_j \sigma'(z_j)项连乘的问题不但会导致梯度消失问题,有时候还可能导致梯度爆炸(The exploding gradient problem)。比如假设令w_1 = w_2 = w_3 = w_4 = 100,令b_i = -100 * a_{i-1},使得z_i = w_i a_{i-1} + b_i = 0,这就有\sigma'(z_j) = 1/4,进而有w_j\sigma'(z_j)=100 * \frac{1}{4} = 25>1。多个w_j \sigma'(z_j)项相乘就会越乘越大,导致梯度爆炸。

所以根源还是出现在多个w_j \sigma'(z_j)项相乘的问题上,导致BP梯度更新不稳定,有时候可能梯度消失,有时候可能梯度爆炸,这就导致深度神经网络训练起来有难度。也许把Sigmoid激活函数换成ReLU可以解决这个问题?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.