梯度消失和梯度爆炸问题及其解决方法详解

387 阅读5分钟

by jsklearner

@TOC

梯度消失和梯度爆炸问题

概念

  • 梯度消失是因为随着网络深度的加深,网络反向传播的小于1的导数经过逐层累积而导致其越靠近输入层,其值越小,因此靠近输入层的权值更新就会非常缓慢甚至停滞不前,那么网络深度的加深就失去了其意义,网络只等价于后面基层浅层网络的学习。
  • 梯度爆炸一般出现深层网络和权值初始化值太大的情况下。随着网络的深度的加深,大于1的导数经过逐层累积,变得非常大,梯度值太大,会导致权值瞬间跳跃,指向不应该指向的位置,导致训练收敛缓慢,甚至陷入局部最小值。

原理详解

以梯度消失中的Sigmoid激活函数为例,下面四个图分别是Sigmod原函数公式及曲线和其导数公式及曲线。  啊

图片转存失败,建议将图片保存下来直接上传
在这里插入图片描述(https://img-blog.csdnimg.cn/20191030142938718.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2pza19sZWFybmVy,size_16,color_FFFFFF,t_70#pic_center =400x300)
在这里插入图片描述

图片转存失败,建议将图片保存下来直接上传
在这里插入图片描述(https://img-blog.csdnimg.cn/20191030142733508.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2pza19sZWFybmVy,size_16,color_FFFFFF,t_70#pic_center =400x300)

观察Sigmoid函数曲线,可以知道其输出分布在【0,1】区间,而且在输入值较大和较小的情况,其输出值变化都会比较小,仅仅当输入值接近为0时,它们才对输入强烈敏感。Sigmod单元的广泛饱和性会使得基于梯度的学习变得非常困难。因为这个原因,现在已经不鼓励将它们作为前馈网络的隐藏单元。

观察Simod导数曲线,呈现一个类似高斯分布的驼峰装,其取值范围在【0,0.25】之间,而我们初始化后的网络权值通常小于1,因此当层数增多时,小于0的值不断相乘,最后就会导致梯度消失的情况出现。而梯度爆炸则是当权值过大,导致其导数大于1,大于1的数不断相乘,发生梯度爆炸。 同时Sigmoid还有其他缺点,如输出不是以0为中心,而是0.5,这样在求解权重的梯度时,梯度总是正或负的,指数计算耗时。

总之不推荐使用sigmoid饱和激活函数。

不过sigmoid和tanh在RNN(LSTM、注意力机制等)结构上有所应用,作为门控或者概率值。

这里关于tanh为什么比simoid收敛快有一个比较好的说法,这里引用了:

梯度消失问题程度 tanh′(x)=1−tanh(x)2∈(0,1)tanh′⁡(x)=1−tanh⁡(x)2∈(0,1) sigmoid: s′(x)=s(x)×(1−s(x))∈(0,1/4)sigmoid: s′(x)=s(x)×(1−s(x))∈(0,1/4) 可以看出tanh(x)的梯度消失问题比sigmoid要轻.梯度如果过早消失,收敛速度较慢. 以零为中心的影响 如果当前参数(w0,w1)的最佳优化方向是(+d0, -d1),则根据反向传播计算公式,我们希望 x0 和 x1 符号相反。但是如果上一级神经元采用 Sigmoid 函数作为激活函数,sigmoid不以0为中心,输出值恒为正,那么我们无法进行最快的参数更新,而是走 Z 字形逼近最优解。

图片转存失败,建议将图片保存下来直接上传
在这里插入图片描述(https://img-blog.csdnimg.cn/2019103015550883.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2pza19sZWFybmVy,size_16,color_FFFFFF,t_70#pic_center =500x400)

解决方法

更改激活函数(Relu、Leaky-Relu、P-Relu等)

参考我的这篇博客 深度学习—非线性激活函数全面(Sigmoid、tanh、ReLU、Leaky ReLU、PReLU、RReLU、ELU、SELU、Swish、Maxout 10种)

权重初始化

不同的激活函数可能适用于不同的初始化方法,比如ReLU使用MSRA的初始化方法,tanh使用xavier的初始化方式。 第一选择应该是ReLU,但是如果效果不佳可以尝试使用其变体或者Maxout激活函数。 可以尝试tanh正切函数(以零点为中心,零点处梯度为1)。

加入BN层(Batch Normalization)

paper:Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift 最初来自于Google的Inception-v2,因为效果非常好,加快收敛速度明显。加上计算复杂度不高,目前大多数网络模型都会添加BN层,使得输出值在输入到非线性激活函数之前映射到【0,1】区间。而且可以减少前一层参数的变化对后一层输入值的影响,每一层独立训练,具有一定的正则化效果。 在这里插入图片描述

梯度剪切、权重正则(针对梯度爆炸)

梯度剪切是设置一个剪切阈值,如果更新梯度时,梯度大于此阈值,那么会将梯度拉回到阈值范围内,可以防止梯度爆炸。 权重正则,是防止过拟合的一个方法,但是当发生梯度爆炸时,权值的范数就会非常大,因此通过正则化项的限制,也可以防止梯度爆炸。

使用预训练模型进行finetue

这个方法和初始化的思想类似。原始思想是逐层进行训练,然后再对整个网络进行finetune,不过现阶段,大家普遍都是拿Imagenet上的预训练模型进行finetune。 finetune会使得网络权值分布在一个相对较好的区间内,在更新的时候,会降低梯度变得过大过小的可能性。

使用ResNet残差结构

来自何的大作,被认为是深度学习模型的里程碑,后来很多模型以及其他任务上的深度学习方法,都或多或少的参考了ResNet的skip connection结构。其在一定程度可以防止梯度消失。甚至在网络达到152层的时候,依然具有卓越的性能。


参考链接: 激活函数(ReLU, Swish, Maxout) 梯度消失和梯度爆炸问题详解 blog.csdn.net/qq_25737169…


2019.10.30 希望能帮到你。