梯度消失与梯度爆炸

什么是梯度消失和梯度爆炸,分别会引发什么问题

我们知道神经网络在训练过程中会利用梯度对网络的权重进行更新迭代。
当梯度出现指数级递减或指数递增时,称为梯度消失或者梯度爆炸。

假定激活函数 $g(z) = z$, 令 $b^{[l]} = 0$,对于目标输出有:
$\hat{y} = W^{[L]}W^{[L-1]}…W^{[2]}W^{[1]}X$
1)对于 W[l]的值小于 1 的情况,激活函数的值将以指数级递减
2)对于 W[l]的值大于 1 的情况,激活函数的值将以指数级递增
同理的情况会出现在反向求导。

梯度消失时,权重更新缓慢,训练难度大大增加。梯度消失相对梯度爆炸更常见。
梯度爆炸时,权重大幅更新,网络变得不稳定。较好的情况是网络无法利用训练数据学习,最差的情况是权值增大溢出,变成网络无法更新的 NaN 值。


如何利用初始化缓解梯度消失和爆炸

根据 z=w1x1+w2x2+…+wnxn+b
可知,当输入的数量 n 较大时,我们希望每个 wi 的值都小一些,这样它们的和得到的 z 也较小。
为了得到较小的 wi,设置Var(wi)=1/n,这里称为 Xavier initialization

WL = np.random.randn(WL.shape[0], WL.shape[1]) * np.sqrt(1/n)

其中 n 是输入的神经元个数,即WL.shape[1]。
这样,激活函数的输入 x 近似设置成均值为 0,标准方差为 1,神经元输出 z 的方差就正则化到 1 了。虽然没有解决梯度消失和爆炸的问题,但其在一定程度上确实减缓了梯度消失和爆炸的速度。

同理,也有 He Initialization。它和 Xavier initialization 唯一的区别是Var(wi)=2/n,适用于 ReLU 作为激活函数时。
当激活函数使用 ReLU 时,Var(wi)=2/n;当激活函数使用 tanh 时,Var(wi)=1/n。


如何确定是否出现梯度爆炸

信号如下:

  • 训练过程中,每个节点和层的误差梯度值持续超过1.0。
  • 模型不稳定,梯度显著变化,快速变大。
  • 训练过程中,模型权重变成 NaN 值。
  • 模型无法从训练数据中获得更新。

如何解决梯度消失和梯度膨胀

梯度消失和梯度爆炸都可以通过激活函数或Batch Normalization来解决。吴恩达:BN有效原因

对于梯度爆炸,这里列举一些最佳实验方法:

  1. 重新设计网络模型
    在深度神经网络中,梯度爆炸可以通过重新设计层数更少的网络来解决。
    使用更小的批尺寸对网络训练也有好处。
    在循环神经网络中,训练过程中在更少的先前时间步上进行更新(沿时间的截断反向传播,truncated Backpropagation through time)可以缓解梯度爆炸问题。

  2. 使用 ReLU 激活函数
    在深度多层感知机神经网络中,梯度爆炸的发生可能是因为激活函数,如之前很流行的 Sigmoid 和 Tanh 函数。
    使用 ReLU 激活函数可以减少梯度爆炸。采用 ReLU 激活函数是最适合隐藏层的新实践。

  3. 使用长短期记忆网络
    在循环神经网络中,梯度爆炸的发生可能是因为某种网络的训练本身就存在不稳定性,如随时间的反向传播本质上将循环网络转换成深度多层感知机神经网络。
    使用长短期记忆(LSTM)单元和相关的门类型神经元结构可以减少梯度爆炸问题。
    采用 LSTM 单元是适合循环神经网络的序列预测的最新最好实践。

  4. 使用梯度截断(Gradient Clipping)
    在非常深且批尺寸较大的多层感知机网络和输入序列较长的 LSTM 中,仍然有可能出现梯度爆炸。如果梯度爆炸仍然出现,你可以在训练过程中检查和限制梯度的大小。这就是梯度截断。
    处理梯度爆炸有一个简单有效的解决方案:如果梯度超过阈值,就截断它们。
    ——《Neural Network Methods in Natural Language Processing》,2017.
    具体来说,检查误差梯度的值是否超过阈值,如果超过,则截断梯度,将梯度设置为阈值。
    梯度截断可以一定程度上缓解梯度爆炸问题(梯度截断,即在执行梯度下降步骤之前将梯度设置为阈值)。
    ——《深度学习》,2016.
    在 Keras 深度学习库中,你可以在训练之前设置优化器上的 clipnorm 或 clipvalue 参数,来使用梯度截断。
    默认值为 clipnorm=1.0 、clipvalue=0.5。详见:https://keras.io/optimizers/。

  5. 使用权重正则化(Weight Regularization)
    如果梯度爆炸仍然存在,可以尝试另一种方法,即检查网络权重的大小,并惩罚产生较大权重值的损失函数。该过程被称为权重正则化,通常使用的是 L1 惩罚项(权重绝对值)或 L2 惩罚项(权重平方)。
    对循环权重使用 L1 或 L2 惩罚项有助于缓解梯度爆炸。
    ——On the difficulty of training recurrent neural networks,2013.
    在 Keras 深度学习库中,你可以通过在层上设置 kernel_regularizer 参数和使用 L1 或 L2 正则化项进行权重正则化。


如何解决RNN梯度爆炸和弥散的问题

梯度爆炸:当梯度大于一定阈值的的时候,将它截断为一个较小的数。
下图可视化了梯度截断的效果。它展示了一个小的rnn(其中W为权值矩阵,b为bias项)的决策面。这个模型是一个一小段时间的rnn单元组成;实心箭头表明每步梯度下降的训练过程。
当梯度下降过程中,模型的目标函数取得了较高的误差时,梯度将被送到远离决策面的位置。截断模型产生了一个虚线,它将误差梯度拉回到离原始梯度接近的位置。

梯度弥散:第一种方法是将随机初始化改为一个有关联的矩阵初始化。第二种方法是使用ReLU代替sigmoid函数。ReLU的导数不是0就是1.因此,神经元的梯度将始终为1,而不会当梯度传播了一定时间之后变小。

基本的 RNN 不擅长捕获这种长期依赖关系, LSTM 和 GRU 都可以作为缓解梯度消失问题的方案。