梯度消失与梯度爆炸

梯度消失和梯度爆炸的现象

对于图1所示的含有3个隐藏层的神经网络:
梯度消失问题发生时,靠近输出层的hidden layer 3的权值更新相对正常,但是靠近输入层的hidden layer1的权值更新会变得很慢,导致靠近输入层的隐藏层权值几乎不变,扔接近于初始化的权值。这就导致hidden layer 1 相当于只是一个映射层,对所有的输入做了一个函数映射,这时此深度神经网络的学习就等价于只有后几层的隐藏层网络在学习。
梯度爆炸的情况是:当初始的权值过大,靠近输入层的hidden layer 1的权值变化比靠近输出层的hidden layer 3的权值变化更快,就会引起梯度爆炸的问题。

梯度消失和梯度爆炸的原因

两种情况下梯度消失经常出现,一是在深层网络中,二是采用了不合适的损失函数,比如sigmoid。
梯度爆炸一般出现在深层网络权值初始化值太大的情况下。

假设存在一个网络结构如图:

其表达式为:

\[f\left(w_{1}\right)=f_{3}\left(w_{3} f_{2}\left(w_{2} f_{1}\left(w_{1}\right)\right)\right) \]

若要对于\(\mathrm{w}_{1}\)求梯度,根据链式求导法则,得到的解为:

\[\frac{\partial f}{\partial w_{I}}=\frac{\partial f_{3}}{\partial f_{2}} w_{3} \times \frac{\partial f_{2}}{\partial f_{I}} w_{2} \times \frac{\partial f_{1}}{w_{1}} \]

如果我们使用标准化初始\(w\),那么各个层次的相乘都是0-1之间的小数,而r如果激活函数f的导数也是0-1之间的数,其连乘后,结果会变的很小,导致梯度消失。若我们初始化的\(w\)是很大的数,\(w\)大到乘以激活函数的导数都大于1,那么连乘后,可能会导致求导的结果很大,形成梯度爆炸

例如常用的Sigmoid函数,其导数:

\[\sigma^{\prime}(x)=\sigma(x)(1-\sigma(x))=-\left(\sigma(x)-\frac{1}{2}\right)^{2}+\frac{1}{4} \]

可见Sigmoid的导数的最大值为1/4,通常初始化的网络权值\(w\)通常都小于1,从而有:

\[\left|\sigma^{\prime}(z) w\right| \leq \frac{1}{4} \]

梯度消失、爆炸的解决方案

梯度剪切、正则

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

另外一种解决梯度爆炸的手段是采用权重正则化(weithts regularization)比较常见的是L1正则,和L2正则。

例如带有L2正则项在损失函数的形式:

\[Loss=\left(y-W^{T} x\right)^{2}+\alpha\|W\|^{2} \]

其中,\(\alpha\) 是指正则项系数,因此,如果发生梯度爆炸,权值的范数就会变的非常大,通过正则化项,可以部分限制梯度爆炸的发生。

使用 relu、leakrelu、elu等激活函数

Relu

Relu:思想也很简单,如果激活函数的导数为1,那么就不存在梯度消失爆炸的问题了,每层的网络都可以得到相同的更新速度,relu就这样应运而生。

从上图中,我们可以很容易看出,relu函数的导数在正数部分是恒等于1的,因此在深层网络中使用relu激活函数就不会导致梯度消失和爆炸的问题。

\[\operatorname{Re} \operatorname{lu}(\mathrm{x})=\max (\mathrm{x}, 0)=\left\{\begin{array}{l}{0, x<0} \\ {x, x>0}\end{array}\right\} \]

relu 的主要贡献在于:

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

缺点

  • 由于负数部分恒为0,会导致一些神经元无法激活(可通过设置小学习率部分解决)
  • 输出不是以0为中心的

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

leakrelu

leakrelu就是为了解决relu的0区间带来的影响,其数学表达为:

\[leakrelu=\max (k * x, x) \]

其中k是leak系数,一般选择0.01或者0.02,或者通过学习而来。

leakrelu解决了0区间带来的影响,而且包含了relu的所有优点。

elu

elu激活函数也是为了解决relu的0区间带来的影响,其数学表达为:

\[f(x)=\left\{\begin{array}{ll}{x} & {\text { if } x>0} \\ {\alpha(\exp (x)-1)} & {\text { if } x \leq 0}\end{array}\right. \]

导数为:

\[f^{\prime}(x)=\left\{\begin{array}{ll}{1} & {\text { if } x>0} \\ {f(x)+\alpha} & {\text { if } x \leq 0}\end{array}\right. \]

图像为:

其中α是一个可调整的参数,它控制着ELU负值部分在何时饱和。
右侧线性部分使得ELU能够缓解梯度消失,而左侧软饱能够让ELU对输入变化或噪声更鲁棒。
ELU的输出均值接近于零,所以收敛速度更快。
但是elu相对于leakrelu来说,计算要更耗时间一些。

batchnorm

Batchnorm是深度学习发展以来提出的最重要的成果之一了,目前已经被广泛的应用到了各大网络中,具有加速网络收敛速度,提升训练稳定性的效果,Batchnorm本质上是解决反向传播过程中的梯度问题。batchnorm全名是batch normalization,简称BN,即批规范化,通过规范化操作将输出信号x规范化保证网络的稳定性。

举个简单例子:

正向传播:

\[f_{2}=f_{1}\left(w^{T} * x+b\right) \]

那么反向传播:

\[\frac{\partial f_{2}}{\partial x}=\frac{\partial f_{2}}{\partial f_{1}} w \]

反向传播式子中有\(w\)的存在,所以\(w\)的大小影响了梯度的消失和爆炸,batchnorm就是通过对每一层的输出规范为均值和方差一致的方法,消除了\(w\)带来的放大缩小的影响,进而解决梯度消失和爆炸的问题,或者可以理解为BN将输出从饱和区拉倒了非饱和区。

残差结构

残差可以很轻松的构建几百层,一千多层的网络而不用担心梯度消失过快的问题,原因就在于残差的捷径(shortcut)部分,其中残差单元如下图所示:

相比较于以前网络的直来直去结构,残差中有很多这样的跨层连接结构,这样的结构在反向传播中具有很大的好处,见下式:

\[\frac{\partial l o s s}{\partial x_{l}}=\frac{\partial \operatorname{loss}}{\partial x_{L}} \cdot \frac{\partial x_{L}}{\partial x_{l}}=\frac{\partial \operatorname{los} s}{\partial x_{L}} \cdot\left(1+\frac{\partial}{\partial x_{L}} \sum_{i=l}^{L-1} F\left(x_{i}, W_{i}\right)\right) \]

式子的第一个因子 \(\frac{\partial \operatorname{los} s}{\partial x_{L}}\)表示的损失函数到达 L 的梯度,小括号中的1表明短路机制可以无损地传播梯度,而另外一项残差梯度则需要经过带有weights的层,梯度不是直接传递过来的。残差梯度不会那么巧全为-1,而且就算其比较小,有1的存在也不会导致梯度消失。所以残差学习会更容易。

LSTM

LSTM全称是长短期记忆网络(long-short term memory networks),是不那么容易发生梯度消失的,主要原因在于LSTM内部复杂的“门”(gates),如下图,LSTM通过它内部的“门”可以接下来更新的时候“记住”前几次训练的”残留记忆“,因此,经常用于生成文本中。

posted @ 2019-04-21 15:50  youngliu91  阅读(903)  评论(0)    收藏  举报