详解梯度消失、梯度爆炸问题

1、梯度消失(vanishing gradient problem)、梯度爆炸(exploding gradient problem)原因

神经网络最终的目的是希望损失函数loss取得极小值。所以最终的问题就变成了一个寻找函数最小值的问题,在数学上,很自然的就会想到使用梯度下降(求导)来解决。

梯度消失、梯度爆炸其根本原因在于反向传播训练法则(BP算法):是指在使用梯度下降法对误差进行反向传播时,由于求偏导累乘而出现趋于0(梯度消失)或者趋于无穷大(梯度爆炸)的问题 。

所以梯度消失和爆炸出现的原因经常是因为网络层次过深,以及**函数选择不当,比如sigmoid函数。

反向传播(用于优化神网参数):根据损失函数计算的误差通过反向传播的方式,指导深度网络参数的更新优化。

2、梯度消失、爆炸会带来哪些影响

当梯度消失发生时,接近于输出层的隐藏层由于其梯度相对正常,所以权值更新时也就相对正常,但是当越靠近输入层时,由于梯度消失现象,会导致靠近输入层的隐藏层权值更新缓慢或者更新停滞。这就导致在训练时,只等价于后面几层的浅层网络的学习。

当梯度爆炸发生时,初始的权值过大,靠近输入层的权值变化比靠近输出层的权值变化更快,就会引起梯度爆炸的问题。最终导致

(1)模型型不稳定,更新过程中的损失出现显著变化。
(2)训练过程中,模型损失变成 NaN。

3、原因推导

以最简单的网络结构为例,加入有三个隐藏层(hidden layer),每层的神经元(neuron)个数都是1(下图)。其中,C是损失函数;每一层的输入为z,输出为a,其中有z = w*a + b

下面的分析仅仅针对bias(w也是可以类比的)

假设我们需要更新参数b1 ,那么我们就要求出损失函数对参数 b1的导数,根据链式法则,公式如上图所示:

 

详解梯度消失、梯度爆炸问题

而对于**函数,之前一直使用Sigmoid函数:

详解梯度消失、梯度爆炸问题

其函数图像成一个S型,如下所示,它会将正无穷到负无穷的数映射到0~1之间:

详解梯度消失、梯度爆炸问题

 

当我们对Sigmoid函数求导时,得到其结果如下:

详解梯度消失、梯度爆炸问题

Sigmoid函数求导图像:

详解梯度消失、梯度爆炸问题

从求导结果可以看出,sigmoid导数在0取得最大值1/4。

如果我们使用均值为0,方差为1的高斯分布初始化参数w,有|w| < 1,所以有:

详解梯度消失、梯度爆炸问题

可以看出随着网络层数的加深,最后的乘积会指数级衰减,这就是梯度弥散的根本原因。求出损失函数对参数 b1的导数很小很小。

|W|>1时,最后的乘积会指数级增加,从而引发梯度爆炸。

在极端情况下,权重的值变得非常大,以至于溢出,导致 NaN 值

5.sigmoid时,消失和爆炸哪个更易发生?

量化分析梯度爆炸出现时a的树枝范围:因为sigmoid导数最大为1/4,故只有当abs(w)>4时才可能出现。

由此计算出a的数值变化范围很小,仅仅在此窄范围内会出现梯度爆炸问题。而最普遍发生的是梯度消失问题。

6.如何解决梯度消失和梯度爆炸?

梯度消失:

  1.使用ReLU,maxout等替代sigmoid。

        2.batch normalization

梯度爆炸:

  1.使用Gradient Clipping(梯度裁剪)。通过Gradient Clipping,将梯度约束在一个范围内,这样不会使得梯度过大。 

        2.更换参数初始化方法

Relu和sigmoid区别:

1)sigmoid函数值在[0,1],ReLU函数值在[0,+无穷],所以sigmoid函数可以描述概率,ReLU适合用来描述实数;

(2)sigmoid函数的梯度随着x的增大或减小和消失,而ReLU不会。

扩展:


loss突然变nan的原因?

可能原因:
1、training sample中出现了脏数据,或输入数据未进行归一化
2、学习速率过大,梯度值过大,产生梯度爆炸;
3、在某些涉及指数计算,可能最后算得值为INF(无穷)(比如不做其他处理的softmax中分子分母需要计算exp(x),值过大,最后可能为INF/INF,得到NaN,此时你要确认你使用的softmax中在计算exp(x)做了相关处理(比如减去最大值等等));
4、不当的损失函数(尤其是自定义的损失函数时);
5、在卷积层的卷积步伐大于卷积核大小的时候。


现在的网络普遍采用ReLU**函数,为什么仍然存在梯度爆炸和消失的问题呢?


梯度消失和 梯度爆炸在relu下都存在, 随着 网络层数变深, activations倾向于越大和越小的方向前进, 往大走梯度爆炸(回想一下你在求梯度时, 每反向传播一层, 都要乘以这一层的activations), 往小走进入死区, 梯度消失。 这两个问题最大的影响是,深层网络难于converge。BN和xavier初始化(经指正, 这里最好应该用msra初始化, 这是he kaiming大神他们对xavier的修正, 其实就是xavier多除以2)很大程度上解决了该问题。sigmoid不存在梯度爆炸, 在activations往越大越小的方向上前进时, 梯度都会消失。
ReLU的负半轴梯度为0,所以有时候(比较少见)也还是会梯度消失,这时可以使用PReLU替代,如果用了PReLU还会梯度弥散和爆炸,请调整初始化参数,对自己调参没信心或者就是懒的,请直接上BN。至于sigmoid为什么会有梯度消失现象,是因为sigmoid(x)在不同尺度的x下的梯度变化太大了,而且一旦x的尺度变大,梯度消失得特别快,网络得不到更新,就再也拉不回来了。