浅谈神经网络中的梯度爆炸问题

在神经网络中,梯度下降算法是使用非常广泛的优化算法。梯度下降算法的变体有好多,比如随机梯度下降(Stochastic gradient descent,SGD)、小批量梯度下降(Mini Batch Gradient Descent)等,但对于梯度下降算法而言,难免需要考虑梯度下降算法中遇到的梯度弥散以及梯度爆炸等问题,本文主要讲解神经网络中的梯度爆炸问题,从以下三个方面讲解:

  • 什么是梯度爆炸,以及在训练过程中梯度爆炸会引发哪些问题;
  • 如何知道网络模型是否存在梯度爆炸;
  • 如何在网络模型中解决梯度爆炸问题;

梯度爆炸是什么?

误差梯度在网络训练时被用来得到网络参数更新的方向和幅度,进而在正确的方向上以合适的幅度更新网络参数。在深层网络或递归神经网络中,误差梯度在更新中累积得到一个非常大的梯度,这样的梯度会大幅度更新网络参数,进而导致网络不稳定。在极端情况下,权重的值变得特别大,以至于结果会溢出(NaN值,无穷与非数值)。当梯度爆炸发生时,网络层之间反复乘以大于1.0的梯度值使得梯度值成倍增长。

梯度爆炸会引发哪些问题?

在深度多层感知机网络中,梯度爆炸会导致网络不稳定,最好的结果是无法从训练数据中学习,最坏的结果是由于权重值为NaN而无法更新权重。

梯度爆炸会使得学习不稳定;

                           —— 深度学习第282页

在循环神经网络(RNN)中,梯度爆炸会导致网络不稳定,使得网络无法从训练数据中得到很好的学习,最好的结果是网络不能在长输入数据序列上学习。

梯度爆炸问题指的是训练过程中梯度大幅度增加,这是由于长期组件爆炸造成的;

         ——训练循环神经网络的困难

如何知道网络中是否有梯度爆炸问题?

在网络训练过程中,如果发生梯度爆炸,那么会有一些明显的迹象表明这一点,例如:

  • 模型无法在训练数据上收敛(比如,损失函数值非常差);
  • 模型不稳定,在更新的时候损失有较大的变化;
  • 模型的损失函数值在训练过程中变成NaN值;

如果你遇到上述问题,我们就可以深入分析网络是否存在梯度爆炸问题。还有一些不太为明显的迹象可以用来确认网络中是否存在梯度爆炸问题:

  • 模型在训练过程中,权重变化非常大;
  • 模型在训练过程中,权重变成NaN值;
  • 每层的每个节点在训练时,其误差梯度值一直是大于1.0;

如何解决梯度爆炸问题?

解决梯度爆炸问题的方法有很多,本部分将介绍一些有效的实践方法:

1.重新设计网络模型

在深层神经网络中,梯度爆炸问题可以通过将网络模型的层数变少来解决。此外,在训练网络时,使用较小批量也有一些好处。在循环神经网络中,训练时使用较小时间步长更新(也被称作截断反向传播)可能会降低梯度爆炸发生的概率。

2.使用修正线性激活函数

在深度多层感知机中,当激活函数选择为一些之前常用的Sigmoid或Tanh时,网络模型会发生梯度爆炸问题。而使用修正线性激活函数(ReLU)能够减少梯度爆炸发生的概率,对于隐藏层而言,使用修正线性激活函数(ReLU)是一个比较合适的激活函数,当然ReLU函数有许多变体,大家在实践过程中可以逐一使用以找到最合适的激活函数。

3.使用长短周期记忆网络

由于循环神经网络中存在的固有不稳定性,梯度爆炸可能会发生。比如,通过时间反向传播,其本质是将循环网络转变为深度多层感知神经网络。通过使用长短期记忆单元(LSTM)或相关的门控神经结构能够减少梯度爆炸发生的概率。

对于循环神经网络的时间序列预测而言,采用LSTM是新的最佳实践。

4.使用梯度裁剪

在深度多层感知网络中,当有大批量数据以及LSTM是用于很长时间序列时,梯度爆炸仍然会发生。当梯度爆炸发生时,可以在网络训练时检查并限制梯度的大小,这被称作梯度裁剪。

梯度裁剪是处理梯度爆炸问题的一个简单但非常有效的解决方案,如果梯度值大于某个阈值,我们就进行梯度裁剪。

——自然语言处理中的神经网络方法的第5.2.4节

具体而言,检查误差梯度值就是与一个阈值进行比较,若误差梯度值超过设定的阈值,则截断或设置为阈值。

在某种程度上,梯度爆炸问题可以通过梯度裁剪来缓解(在执行梯度下降步骤之前对梯度进行阈值操作)

——深度学习第294页

在Keras深度学习库中,在训练网络之前,可以对优化器的clipnorm和  clipvalue参数进行设置来使用梯度裁剪,一般而言,默认将clipnorm和  clipvalue分别设置为1和0.5.

5.使用权重正则化

如果梯度爆炸问题仍然发生,另外一个方法是对网络权重的大小进行校验,并对大权重的损失函数增添一项惩罚项,这也被称作权重正则化,常用的有L1(权重的绝对值和)正则化与L2(权重的绝对值平方和再开方)正则化。

使用L1或L2惩罚项会减少梯度爆炸的发生概率

——训练循环神经网络的困难

在Keras深度学习库中,可以在每层上使用L1或L2正则器设置kernel_regularizer参数来完成权重的正则化操作。

进一步阅读

如果你想进一步深入研究梯度爆炸问题,本节将提供更多的资源:

书籍

文献

文章

Keras API

总结

  通过本文,你将会学习到如何在训练深层神经网络时发现梯度爆炸问题,尤其是以下几点:

  • 什么是梯度爆炸,以及在训练过程中梯度爆炸会引发哪些问题;
  • 如何知道网络模型是否存在梯度爆炸;
  • 如何在网络模型中解决梯度爆炸问题;

作者信息


Jason Brownlee,机器学习专家,专注于机器学习的推广教育。

Linkedin: http://www.linkedin.com/in/jasonbrownlee/

文章原标题《A Gentle Introduction to Exploding Gradients in Neural Networks》,作者:Jason Brownlee,译者:海棠,审阅:。

文章为简译,更为详细的内容,请查看原文

时间: 2024-09-18 14:31:54

浅谈神经网络中的梯度爆炸问题的相关文章

浅谈Python中copy()方法的使用

  这篇文章主要介绍了浅谈Python中copy()方法的使用,Python中的拷贝分为潜拷贝和深拷贝,本文只是简单介绍用法,需要的朋友可以参考下 copy()方法返回字典的浅拷贝. 语法 以下是copy()方法的语法: ? 1 dict.copy() 参数 NA 返回值 此方法返回字典的浅拷贝. 例子 下面的例子显示了copy()方法的使用. ? 1 2 3 4 5 6 #!/usr/bin/python   dict1 = {'Name': 'Zara', 'Age': 7};   dict

浅谈ASP中Request对象获取客户端数据的顺序

request|对象|客户端|数据 浅谈ASP中Request对象获取客户端数据的顺序 /**描述:在使用ASP Request对象时需要注意的小问题作者:慈勤强Email : cqq1978@yeah.net**/ 在ASP中Request对象是获取客户端提交数据的一个很重要的对象,大家对他也是非常熟悉了.虽然如此,还是经常有人问我下面的几种写法有什么不同,到底应该怎么写?strMessage = Request("msg")strMessage = Request.Form(&qu

浅谈jquery中delegate()与live()

  这篇文章主要介绍了浅谈jquery中delegate()与live()的相关资料,需要的朋友可以参考下 delegate() 方法为指定的元素(属于被选元素的子元素)添加一个或多个事件处理程序 例如给id是showspan的div中的span标签添加事件 ? 1 2 3 4 5 6 7 8 9 10 <div id="showspan"><span>showspan**showspan</span></div> <span>

浅谈javascript中call()、apply()、bind()的用法

  浅谈javascript中call().apply().bind()的用法         一直对Javascript中的apply/call/bind的用法很模糊,恰好看到了这篇文章.对三者之间的区别与联系算是有了比较清晰的认识.这里记录下来,分享给大家. call(thisObj,arg1,arg2...).apply(thisObj,[obj1,obj2...])这二个方法是每个函数都包含的非继承的方法 call(thisobj[, args])和apply(thisobj[, arg

浅谈javascript中this在事件中的应用

 这篇文章主要介绍了浅谈javascript中this在事件中的应用实例,非常有助于我们对this关键字的理解,这里推荐给大家.     this关键字在javascript中是非常强大的,但是如果你不清楚它是怎么工作的就很难使用它.   代码如下: function dosomething(){ this.style.color="#fff"; }   上面这段代码中的this指向什么呢,运行dosomething()会输出什么呢? 在javascript中,this总是指向当前执行

浅谈java中异步多线程超时导致的服务异常_java

在项目中为了提高大并发量时的性能稳定性,经常会使用到线程池来做多线程异步操作,多线程有2种,一种是实现runnable接口,这种没有返回值,一种是实现Callable接口,这种有返回值. 当其中一个线程超时的时候,理论上应该不 影响其他线程的执行结果,但是在项目中出现的问题表明一个线程阻塞,其他线程返回的接口都为空.其实是个很简单的问题,但是由于第一次碰到,还是想了一些时间的.很简单,就是因为阻塞的那个线 程没有释放,并发量一大,线程池数量就满了,所以其他线程都处于等待状态. 附上一段自己写的调

浅谈JS中的!=、== 、!==、===的用法和区别_javascript技巧

var num = 1; var str = '1'; var test = 1; test == num //true 相同类型 相同值 test === num //true 相同类型 相同值 test !== num //false test与num类型相同,其值也相同, 非运算肯定是false num == str //true 把str转换为数字,检查其是否相等. num != str //false == 的 非运算 num === str //false 类型不同,直接返回fals

浅谈VC中的字节对齐

原文地址:浅谈VC中的字节对齐 前几天时,在公司和同事说到了字节对齐,一直对这个概念比较模糊,只是在<程序员面试宝典>中看到过简单的描述和一些面试题.后来在论坛中有看到有朋友在询问字节对齐的相关问题,自己也答不上来,觉得应该研究一下,所以就有了这一篇博文,是对学习的一个总结,也是对成长轨迹的一个记录.       字节对齐,又叫内存对齐,个人理解就是一种C++中的类型在内存中空间分配策略.每一种类型存储的起始地址,都要求是一个对齐模数(alignment modulus)的整数倍.问题来了,为

浅谈js中startsWith函数不能在任何浏览器兼容的问题

在做js测试的时候用到了startsWith函数,但是他并不是每个浏览器都有的,所以我们一般要重写一下这个函数,具体的用法可以稍微总结一下. 在有些浏览器中他是undefined 所以我们可以这样的处理一下 if (typeof String.prototype.startsWith != 'function') {    String.prototype.startsWith = function (prefix){    return this.slice(0, prefix.length)