深度学习防止梯度消失与梯度爆炸的几种方法

深度学习防止梯度消失与梯度爆炸的几种方法

  • 一:梯度剪切、正则
  • 二:Relu、Leakrelu、Elu等激活函数
  • 三:batchnorm
  • 四:残差结构
  • 五:LSTM
  • 六:预训练加微调

一:梯度剪切、正则

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

optimizer.zero_grad()        
loss, hidden = model(data, hidden, targets)
loss.backward()

torch.nn.utils.clip_grad_norm_(model.parameters(), args.clip)
optimizer.step()

另外一种解决梯度爆炸的手段是采用权重正则化(weithts regularization)比较常见的是l1正则,和l2正则,在各个深度框架中都有相应的API可以使用正则化,比如在pytorch中,若搭建网络的时候已经设置了正则化参数,则调用以下代码可以直接计算出正则损失。
torch.optim集成了很多优化器,如SGD,Adadelta,Adam,Adagrad,RMSprop等,这些优化器自带的一个参数weight_decay,用于指定权值衰减率,相当于L2正则化中的λ参数,注意torch.optim集成的优化器只有L2正则化方法,你可以查看注释,参数weight_decay 的解析是:

 weight_decay (float, optional): weight decay (L2 penalty) (default: 0)

L2 regularization.

optimizer = optim.Adam(model.parameters(),lr=learning_rate,weight_decay=0.01)

正则化是通过对网络权重做正则限制过拟合,仔细看正则项在损失函数的形式:
regularization 公式:
L o s s = ( y − W T x ) 2 + α ∣ ∣ W ∣ ∣ 2 , . Loss = (y-W^Tx)^2 + \alpha \lvert\rvert W\lvert \rvert ^2,. Loss=(yWTx)2+αW2,.
其中, α \alpha α 是指正则项系数,因此,如果发生梯度爆炸,权值的范数就会变的非常大,通过正则化项,可以部分限制梯度爆炸的发生。

二:Relu、Leakrelu、Elu等激活函数

Relu:思想也很简单,如果激活函数的导数为1,那么就不存在梯度消失爆炸的问题了,每层的网络都可以得到相同的更新速度,relu就这样应运而生。先看一下relu的数学表达式:
R e l u ( x ) = m a x ( 0 , x ) Relu(x) = max(0, x) Relu(x)=max(0,x)
我们可以很容易看出,relu函数的导数在正数部分是恒等于1的,因此在深层网络中使用relu激活函数就不会导致梯度消失和爆炸的问题。
relu的主要贡献在于:

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

缺点是:

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

LeakRelu:leakrelu就是为了解决relu的0区间带来的影响,其数学表达为:
L e a k R e l u ( x ) = { x , x > 0 ; λ x , x ⩽ 0 ; LeakRelu(x) = \left\{ \begin{matrix} x, x>0; \\ \lambda x, x\leqslant0; \end{matrix}\right. LeakRelu(x)={x,x>0;λx,x0;
其中 λ \lambda λ是leak系数,一般选择0.1或者0.2,或者通过学习而来。
leakrelu解决了0区间带来的影响,而且包含了relu的所有优点。

Elu:elu激活函数也是为了解决relu的0区间带来的影响,其数学表达为:
E l u ( x ) = { x , x > 0 ; α ( e x − 1 ) , x ⩽ 0 ; Elu(x) = \left\{ \begin{matrix} x, x>0; \\ \alpha (e^x -1), x\leqslant0; \end{matrix}\right. Elu(x)={x,x>0;α(ex1),x0;
但是elu相对于leakrelu来说,计算要更耗时间一些

三:batchnorm

BatchNorm是深度学习发展以来提出的最重要的成果之一了,目前已经被广泛的应用到了各大网络中,具有加速网络收敛速度,提升训练稳定性的效果,Batchnorm本质上是解决反向传播过程中的梯度问题。batchnorm全名是batch normalization,简称BN,即批规范化,通过规范化操作将输出信号x规范化到均值为0,方差为1保证网络的稳定性。
具体的batchnorm原理非常复杂,在这里不做详细展开,此部分大概讲一下batchnorm解决梯度的问题上。具体来说就是反向传播中,经过每一层的梯度会乘以该层的权重,举个简单例子: 正向传播中 f 2 = f 1 ( w T x + b ) f_{2} =f_{1}(w^Tx+b) f2=f1(wTx+b) ,那么反向传播中, ∂ f 2 ∂ x = ∂ f 2 ∂ f 1 w \frac{\partial f_{2}}{\partial x} =\frac{\partial f_{2}}{\partial f_{1}}w xf2=f1f2w ,反向传播式子中有w的存在,所以 的大小影响了梯度的消失和爆炸,batchnorm就是通过对每一层的输出做scale和shift的方法,通过一定的规范化手段,把每层神经网络任意神经元这个输入值的分布强行拉回到接近均值为0方差为1的标准正太分布,即严重偏离的分布强制拉回比较标准的分布,这样使得激活输入值落在非线性函数对输入比较敏感的区域,这样输入的小变化就会导致损失函数较大的变化,使得让梯度变大,避免梯度消失问题产生,而且梯度变大意味着学习收敛速度快,能大大加快训练速度。

四:残差结构

事实上,就是残差网络的出现导致了image net比赛的终结,自从残差提出后,几乎所有的深度网络都离不开残差的身影,相比较之前的几层,几十层的深度网络,在残差网络面前都不值一提,残差可以很轻松的构建几百层,一千多层的网络而不用担心梯度消失过快的问题,原因就在于残差的捷径(shortcut)部分,其中残差单元如下图所示:
深度学习防止梯度消失与梯度爆炸的几种方法_第1张图片
相比较于以前网络的直来直去结构,残差中有很多这样的跨层连接结构,这样的结构在反向传播中具有很大的好处,见下式:
Alt
式子的第一个因子 ∂ l o s s ∂ x L \frac{\partial loss}{\partial x_{L}} xLloss 表示的损失函数到达 L 的梯度,小括号中的1表明短路机制可以无损地传播梯度,而另外一项残差梯度则需要经过带有weights的层,梯度不是直接传递过来的。残差梯度不会那么巧全为-1,而且就算其比较小,有1的存在也不会导致梯度消失。所以残差学习会更容易。

五:LSTM

LSTM全称是长短期记忆网络(long-short term memory networks),是不那么容易发生梯度消失的,主要原因在于LSTM内部复杂的“门”(gates),如下图,LSTM通过它内部的“门”可以接下来更新的时候“记住”前几次训练的”残留记忆“,因此,经常用于生成文本中。目前也有基于CNN的LSTM,感兴趣的可以尝试一下。
深度学习防止梯度消失与梯度爆炸的几种方法_第2张图片

六:预训练加微调

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

你可能感兴趣的:(普通trick,深度学习,人工智能,机器学习,神经网络)