详解机器学习中的梯度消失、爆炸缘由及其解决方法

前言

本文主要深刻介绍深度学习中的梯度消失和梯度爆炸的问题以及解决方案。本文分为三部分,第一部分主要直观的介绍深度学习中为何使用梯度更新,第二部分主要介绍深度学习中梯度消失及爆炸的缘由,第三部分对提出梯度消失及爆炸的解决方案。有基础的同鞋能够跳着阅读。
其中,梯度消失爆炸的解决方案主要包括如下几个部分。html

- 预训练加微调
- 梯度剪切、权重正则(针对梯度爆炸)
- 使用不一样的激活函数
- 使用batchnorm
- 使用残差结构
- 使用LSTM网络

第一部分:为何要使用梯度更新规则


在介绍梯度消失以及爆炸以前,先简单说一说梯度消失的根源—–深度神经网络和反向传播。目前深度学习方法中,深度神经网络的发展造就了咱们能够构建更深层的网络完成更复杂的任务,深层网络好比深度卷积网络,LSTM等等,并且最终结果代表,在处理复杂任务上,深度网络比浅层的网络具备更好的效果。可是,目前优化神经网络的方法都是基于反向传播的思想,即根据损失函数计算的偏差经过梯度反向传播的方式,指导深度网络权值的更新优化。这样作是有必定缘由的,首先,深层网络由许多非线性层堆叠而来,每一层非线性层均可以视为是一个非线性函数 f ( x ) f(x) (非线性来自于非线性激活函数),所以整个深度网络能够视为是一个复合的非线性多元函数
F ( x ) = f n ( . . . f 3 ( f 2 ( f 1 ( x ) θ 1 + b ) θ 2 + b ) . . . ) F(x) = {f_n}(...{f_3}({f_2}({f_1}(x)*{\theta _1} + b)*{\theta _2} + b)...) 咱们最终的目的是但愿这个多元函数能够很好的完成输入到输出之间的映射,假设不一样的输入,输出的最优解是 g ( x ) g(x) ,那么,优化深度网络就是为了寻找到合适的权值,知足 L o s s = L ( g ( x ) , F ( x ) ) Loss = L(g(x),F(x)) 取得极小值点,好比最简单的损失函数
L o s s = g ( x ) f ( x ) 2 2 Loss = ||g(x)-f(x)||^2_2 ,假设损失函数的数据空间是下图这样的,咱们最优的权值就是为了寻找下图中的最小值点,对于这种数学寻找最小值问题,采用梯度降低的方法再适合不过了。
这里写图片描述web

第二部分:梯度消失、爆炸

梯度消失与梯度爆炸实际上是一种状况,看接下来的文章就知道了。两种状况下梯度消失常常出现,一是在深层网络中,二是采用了不合适的损失函数,好比sigmoid。梯度爆炸通常出如今深层网络和权值初始化值太大的状况下,下面分别从这两个角度分析梯度消失和爆炸的缘由。算法

1.深层网络角度

比较简单的深层网络以下:
这里写图片描述
图中是一个四层的全链接网络,假设每一层网络激活后的输出为 f i ( x ) f_i(x) ,其中 i i 为第 i i 层, x x 表明第 i i 层的输入,也就是第 i 1 i-1 层的输出, f f 是激活函数,那么,得出 f i + 1 = f ( f i w i + 1 + b i + 1 ) f_{i+1}=f(f_i*w_{i+1}+b_{i+1}) ,简单记为 f i + 1 = f ( f i w i + 1 ) f_{i+1}=f(f_i*w_{i+1})
BP算法基于梯度降低策略,以目标的负梯度方向对参数进行调整,参数的更新为 w w + Δ w w \leftarrow w+\Delta w ,给定学习率 α \alpha ,得出 Δ w = α L o s s w \Delta w=-\alpha \frac{\partial Loss}{\partial w} 。若是要更新第二隐藏层的权值信息,根据链式求导法则,更新梯度信息:
Δ w 2 = L o s s w 2 = L o s s f 4 f 4 f 3 f 3 f 2 f 2 w 2 \Delta w_2=\frac{\partial Loss}{\partial w_2}=\frac{\partial Loss}{\partial f_4}\frac{\partial f_4}{\partial f_3}\frac{\partial f_3}{\partial f_2}\frac{\partial f_2}{\partial w_2} ,很容易看出来 f 2 w 2 = f ( f 1 w 2 ) f 1 \frac{\partial f_2}{\partial w_2}=\frac{\partial f}{\partial (f_1*w_2)}f_1 ,即第二隐藏层的输入。
因此说, f 4 f 3 × w 4 \frac{\partial f_4}{\partial f_3} \times w4 就是对激活函数进行求导,若是此部分大于1,那么层数增多的时候,最终的求出的梯度更新将以指数形式增长,即发生梯度爆炸,若是此部分小于1,那么随着层数增多,求出的梯度更新信息将会以指数形式衰减,即发生了梯度消失。若是说从数学上看不够直观的话,下面几个图能够很直观的说明深层网络的梯度问题 1 ^1 (图片内容来自参考文献1):微信

注:下图中的隐层标号和第一张全链接图隐层标号恰好相反。
图中的曲线表示权值更新的速度,对于下图两个隐层的网络来讲,已经能够发现隐藏层2的权值更新速度要比隐藏层1更新的速度慢网络

这里写图片描述

那么对于四个隐层的网络来讲,就更明显了,第四隐藏层比第一隐藏层的更新速度慢了两个数量级:

这里写图片描述

总结:从深层网络角度来说,不一样的层学习的速度差别很大,表现为网络中靠近输出的层学习的状况很好,靠近输入的层学习的很慢,有时甚至训练了好久,前几层的权值和刚开始随机初始化的值差很少。所以,梯度消失、爆炸,其根本缘由在于反向传播训练法则,属于先天不足,另外多说一句,Hinton提出capsule的缘由就是为了完全抛弃反向传播,若是真能大范围普及,那真是一个革命。app

2.激活函数角度

其实也注意到了,上文中提到计算权值更新信息的时候须要计算前层偏导信息,所以若是激活函数选择不合适,好比使用sigmoid,梯度消失就会很明显了,缘由看下图,左图是sigmoid的损失函数图,右边是其导数的图像,若是使用sigmoid做为损失函数,其梯度是不可能超过0.25的,这样通过链式求导以后,很容易发生梯度消失,sigmoid函数数学表达式为: s i g m o i d ( x ) = 1 1 + e x sigmoid(x)=\frac{1}{1+e^{-x}}
sigmoid函数 sigmoid函数导数框架

同理,tanh做为激活函数,它的导数图以下,能够看出,tanh比sigmoid要好一些,可是它的导数仍然是小于1的。tanh数学表达为:

t a n h ( x ) = e x e x e x + e x tanh(x)=\frac{e^x-e^{-x}}{e^x+e^{-x}} 机器学习

这里写图片描述

第三部分:梯度消失、爆炸的解决方案


2.1 方案1-预训练加微调

此方法来自Hinton在2006年发表的一篇论文,Hinton为了解决梯度的问题,提出采起无监督逐层训练方法,其基本思想是每次训练一层隐节点,训练时将上一层隐节点的输出做为输入,而本层隐节点的输出做为下一层隐节点的输入,此过程就是逐层“预训练”(pre-training);在预训练完成后,再对整个网络进行“微调”(fine-tunning)。Hinton在训练深度信念网络(Deep Belief Networks中,使用了这个方法,在各层预训练完成后,再利用BP算法对整个网络进行训练。此思想至关因而先寻找局部最优,而后整合起来寻找全局最优,此方法有必定的好处,可是目前应用的不是不少了。svg

2.2 方案2-梯度剪切、正则

梯度剪切这个方案主要是针对梯度爆炸提出的,其思想是设置一个梯度剪切阈值,而后更新梯度的时候,若是梯度超过这个阈值,那么就将其强制限制在这个范围以内。这能够防止梯度爆炸。函数

注:在WGAN中也有梯度剪切限制操做,可是和这个是不同的,WGAN限制梯度更新信息是为了保证lipchitz条件。

另一种解决梯度爆炸的手段是采用权重正则化(weithts regularization)比较常见的是 l 1 l1 正则,和 l 2 l2 正则,在各个深度框架中都有相应的API可使用正则化,好比在 t e n s o r f l o w tensorflow 中,若搭建网络的时候已经设置了正则化参数,则调用如下代码能够直接计算出正则损失:

regularization_loss = tf.add_n(tf.losses.get_regularization_losses(scope='my_resnet_50'))

若是没有设置初始化参数,也可使用如下代码计算 l 2 l2 正则损失:

l2_loss = tf.add_n([tf.nn.l2_loss(var) for var in tf.trainable_variables() if 'weights' in var.name])

正则化是经过对网络权重作正则限制过拟合,仔细看正则项在损失函数的形式:
L o s s = ( y W T x ) 2 + α W 2 Loss=(y-W^Tx)^2+ \alpha ||W||^2
其中, α \alpha 是指正则项系数,所以,若是发生梯度爆炸,权值的范数就会变的很是大,经过正则化项,能够部分限制梯度爆炸的发生。

注:事实上,在深度神经网络中,每每是梯度消失出现的更多一些。

2.3 方案3-relu、leakrelu、elu等激活函数

**Relu:**思想也很简单,若是激活函数的导数为1,那么就不存在梯度消失爆炸的问题了,每层的网络均可以获得相同的更新速度,relu就这样应运而生。先看一下relu的数学表达式:

这里写图片描述

其函数图像:

这里写图片描述
从上图中,咱们能够很容易看出,relu函数的导数在正数部分是恒等于1的,所以在深层网络中使用relu激活函数就不会致使梯度消失和爆炸的问题。

relu的主要贡献在于:

-- 解决了梯度消失、爆炸的问题
 -- 计算方便,计算速度快
 -- 加速了网络的训练

同时也存在一些缺点

-- 因为负数部分恒为0,会致使一些神经元没法激活(可经过设置小学习率部分解决)
 -- 输出不是以0为中心的

尽管relu也有缺点,可是仍然是目前使用最多的激活函数

leakrelu
leakrelu就是为了解决relu的0区间带来的影响,其数学表达为: l e a k r e l u = m a x ( k x , x ) leakrelu=max(k*x,x) 其中k是leak系数,通常选择0.01或者0.02,或者经过学习而来

这里写图片描述

leakrelu解决了0区间带来的影响,并且包含了relu的全部优势
elu
elu激活函数也是为了解决relu的0区间带来的影响,其数学表达为:这里写图片描述
其函数及其导数数学形式为:

这里写图片描述

可是elu相对于leakrelu来讲,计算要更耗时间一些

2.4 解决方案4-batchnorm

Batchnorm是深度学习发展以来提出的最重要的成果之一了,目前已经被普遍的应用到了各大网络中,具备加速网络收敛速度,提高训练稳定性的效果,Batchnorm本质上是解决反向传播过程当中的梯度问题。batchnorm全名是batch normalization,简称BN,即批规范化,经过规范化操做将输出信号x规范化保证网络的稳定性。
具体的batchnorm原理很是复杂,在这里不作详细展开,此部分大概讲一下batchnorm解决梯度的问题上。具体来讲就是反向传播中,通过每一层的梯度会乘以该层的权重,举个简单例子:
正向传播中 f 2 = f 1 ( w T x + b ) f_2=f_1(w^T*x+b) ,那么反向传播中, f 2 w = f 2 f 1 x \frac {\partial f_2}{\partial w}=\frac{\partial f_2}{\partial f_1}x ,反向传播式子中有 x x 的存在,因此 x x 的大小影响了梯度的消失和爆炸,batchnorm就是经过对每一层的输出规范为均值和方差一致的方法,消除了 x x 带来的放大缩小的影响,进而解决梯度消失和爆炸的问题,或者能够理解为BN将输出从饱和区拉倒了非饱和区。
有关batch norm详细的内容能够参考个人另外一篇博客:
http://blog.csdn.net/qq_25737169/article/details/79048516

2.5 解决方案5-残差结构

残差结构提及残差的话,不得不提这篇论文了:Deep Residual Learning for Image Recognition,关于这篇论文的解读,能够参考知乎连接:https://zhuanlan.zhihu.com/p/31852747这里只简单介绍残差如何解决梯度的问题。
事实上,就是残差网络的出现致使了image net比赛的终结,自从残差提出后,几乎全部的深度网络都离不开残差的身影,相比较以前的几层,几十层的深度网络,在残差网络面前都不值一提,残差能够很轻松的构建几百层,一千多层的网络而不用担忧梯度消失过快的问题,缘由就在于残差的捷径(shortcut)部分,其中残差单元以下图所示:
这里写图片描述
相比较于之前网络的直来直去结构,残差中有不少这样的跨层链接结构,这样的结构在反向传播中具备很大的好处,见下式:
这里写图片描述
式子的第一个因子 l o s s x L \frac{\partial loss}{\partial {{x}_{L}}} 表示的损失函数到达 L 的梯度,小括号中的1代表短路机制能够无损地传播梯度,而另一项残差梯度则须要通过带有weights的层,梯度不是直接传递过来的。残差梯度不会那么巧全为-1,并且就算其比较小,有1的存在也不会致使梯度消失。因此残差学习会更容易。

注:上面的推导并非严格的证实。

2.6 解决方案6-LSTM

LSTM全称是长短时间记忆网络(long-short term memory networks),是不那么容易发生梯度消失的,主要缘由在于LSTM内部复杂的“门”(gates),以下图,LSTM经过它内部的“门”能够接下来更新的时候“记住”前几回训练的”残留记忆“,所以,常常用于生成文本中。目前也有基于CNN的LSTM,感兴趣的能够尝试一下。

这里写图片描述

参考资料:

1.《Neural networks and deep learning》
2.《机器学习》周志华
3. https://www.cnblogs.com/willnote/p/6912798.html
4. https://www.zhihu.com/question/38102762
5. http://www.jianshu.com/p/9dc9f41f0b29


若是感兴趣,请关注微信公众号,还有更多精彩:
这里写图片描述