为什么会产生梯度消失和梯度爆炸?
目前优化神经网络的方法都是基于BP,即根据损失函数计算的误差通过梯度反向传播的方式,指导深度网络权值的更新优化。其中将误差从末层往前传递的过程需要链式法则(Chain Rule)的帮助,因此反向传播算法可以说是梯度下降在链式法则中的应用。
而链式法则是一个连乘的形式,所以当层数越深的时候,梯度将以指数形式传播。梯度消失问题和梯度爆炸问题一般随着网络层数的增加会变得越来越明显。在根据损失函数计算的误差通过梯度反向传播的方式对深度网络权值进行更新时,得到的梯度值接近0或特别大,也就是梯度消失或爆炸。梯度消失或梯度爆炸在本质原理上其实是一样的。
梯度消失
现象:当梯度消失发生时,接近于输出层的隐藏层由于其梯度相对正常,所以权值更新时也就相对正常,但是当越靠近输入层时,由于梯度值小于1,那么经过链式法则的连乘形式,也会很容易衰减至0,就会产生梯度消失。
原因:一是在深层网络中,二是采用了不合适的损失函数,比如sigmoid。
梯度消失的表现:模型无法从训练数据中获得更新,损失几乎保持不变。
梯度爆炸
现象:在深层神经网络或循环神经网络中,误差的梯度可在更新中累积相乘。如果网络层之间的梯度值大于 1.0,那么重复相乘会导致梯度呈指数级增长,梯度变的非常大,然后导致网络权重的大幅更新,并因此使网络变得不稳定。
原因:深层网络和权值初始化值太大
梯度爆炸的表现:
(1)模型型不稳定,更新过程中的损失出现显著变化。
(2)训练过程中,模型损失变成 NaN。
细致分析各个原因
1.深层网络
由于深度网络是多层非线性函数的堆砌,整个深度网络可以视为是一个复合的非线性多元函数(这些非线性多元函数其实就是每层的激活函数),那么对loss function求不同层的权值偏导,相当于应用梯度下降的链式法则,链式法则是一个连乘的形式,所以当层数越深的时候,梯度将以指数传播。
2.激活函数
sigmoid导数的图像
如果使用sigmoid作为损失函数,其梯度是不可能超过0.25的,而我们初始化的网络权值
通常都小于1,因此链式求导,层数越多,求导结果越小,因而很容易发生梯度消失。
3.初始化权重的值过大
当W比较大的时候,根据链式相乘(反向传播)可得,则前面的网络层比后面的网络层梯度变化更快,很容易发生梯度爆炸的问题。
解决办法
1. 梯度剪切:对梯度设定阈值【针对梯度爆炸】
梯度剪切这个方案主要是针对梯度爆炸提出的,其思想是设置一个梯度剪切阈值,然后更新梯度的时候,如果梯度超过这个阈值,那么就将其强制限制在这个范围之内。对于RNN,加入gradient clipping,每当梯度达到一定的阈值,就把他们设置回一个小一些的数字;这可以防止梯度爆炸。
2. 权重正则化
另外一种解决梯度爆炸的手段是采用权重正则化(weithts regularization),正则化主要是通过对网络权重做正则来限制过拟合。
3. 选择relu等梯度大部分落在常数上的激活函数
relu函数的导数在正数部分是恒等于1的,因此在深层网络中使用relu激活函数就不会导致梯度消失和爆炸的问题。
4. 重新设置网络结构,减少网络层数,调整学习率(消失增大,爆炸减小)。
减小学习率、减小batch size(避免梯度爆炸)
5. batch normalization
BN就是通过对每一层的输出规范为均值和方差一致的方法,消除了权重参数放大缩小带来的影响,进而解决梯度消失和爆炸的问题,或者可以理解为BN将输出从饱和区拉倒了非饱和区。
6.残差网络的捷径(shortcut)
Deep Residual Learning for Image Recognition
相比较于以前直来直去的网络结构,残差中有很多这样(如上图所示)的跨层连接结构,这样的结构在反向传播中具有很大的好处,可以避免梯度消失。
7.LSTM的“门(gate)”结构
LSTM 通过它内部的“门”可以在接下来更新的时候“记住”前几次训练的”残留记忆“。
其他
现在的网络普遍采用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的尺度变大,梯度消失得特别快,网络得不到更新,就再也拉不回来了。