深度学习之循环神经网络(7)梯度裁剪

  • 1. 张量限幅
  • 2. 限制范数
  • 3. 全局范数裁剪
  • 梯度弥散

 梯度爆炸可以通过 梯度裁剪(Gradient Clipping)的方式在一定程度上的解决。梯度裁剪与张量限幅非常类似,也是通过将梯度张量的数值或者范数限制在某个较小的区间内,从而将远大于1的梯度值减少,避免出现梯度爆炸。

 在深度学习中,有3种常用的梯度裁剪方式。

1. 张量限幅

 直接对张量的数值进行限幅,使得张量W\boldsymbol WW的所有元素wij∈[min,max]w_{ij}\in[\text{min},\text{max}]wij​∈[min,max]。在TensorFlow中,可以通过tf.clip_by_value()函数来实现。例如:

import tensorflow as tfa = tf.random.uniform([2, 2])
# print(a)
print(tf.clip_by_value(a, 0.2, 0.6))  # 梯度值裁剪

运行结果如下所示:

tf.Tensor(
[[0.46144927 0.6       ][0.4977187  0.22363663]], shape=(2, 2), dtype=float32)

2. 限制范数

 通过限制梯度张量W\boldsymbol WW的范数来实现梯度裁剪。比如对W\boldsymbol WW的二范数∥W∥2\|\boldsymbol W\|_2∥W∥2​约束在[0,max][0,\text{max}][0,max]之间,如果∥W∥2\|\boldsymbol W\|_2∥W∥2​大于max\text{max}max值,则按照
W′=W∥W∥2⋅max\boldsymbol W'=\frac{\boldsymbol W}{\|\boldsymbol W\|_2} \cdot \text{max}W′=∥W∥2​W​⋅max
方式将∥W∥2\|\boldsymbol W\|_2∥W∥2​约束在max\text{max}max内。可以通过tf.clip_by_norm函数方便地实现梯度张量W\boldsymbol WW裁剪。例如:

import tensorflow as tfa = tf.random.uniform([2, 2]) * 5
# 按范数方式裁剪
b = tf.clip_by_norm(a, 5)
# 裁剪前和裁剪后的张量范数
print(tf.norm(a), tf.norm(b))

运行结果如下所示:

tf.Tensor(6.1878695, shape=(), dtype=float32) tf.Tensor(5.0, shape=(), dtype=float32)

可以看到,对于大于max\text{max}max的L2范数的张量,通过裁剪后范数值缩减为5。

3. 全局范数裁剪

 神经网络的更新方向是由所有参数的梯度张量W\boldsymbol WW共同表示的,前两种方式只考虑单个梯度张量的限幅,会出现网络更新方向发生变动的情况。如果能够考虑所有参数的梯度W\boldsymbol WW的范数,实现等比例的缩放,那么就能既很好地限制网络的梯度值,同时不改变网络的更新方向。这就是第三种梯度裁剪的方式:全局范数裁剪。在TensorFlow中,可以通过tf.clip_by_global_norm函数快捷地缩放整体网络梯度W\boldsymbol WW的范数。

令W(i)\boldsymbol W^{(i)}W(i)的表示网络参数的第iii个梯度张量,首先通过
global_norm=∑i∥W(i)∥22\text{global\_norm}=\sqrt{\sum_i\|\boldsymbol W^{(i)} \|_2^2 }global_norm=i∑​∥W(i)∥22​​
计算网络的总范数global_norm\text{global\_norm}global_norm,对第III个参数W(i)\boldsymbol W^{(i)}W(i),通过
W(i)=W(i)⋅max_normmax⁡(global_norm,max_norm)\boldsymbol W^{(i)}=\frac{\boldsymbol W^{(i)}\cdot \text{max\_norm}}{\text{max⁡(global\_norm,max\_norm)}}W(i)=max⁡(global_norm,max_norm)W(i)⋅max_norm​
进行裁剪,其中max_norm\text{max\_norm}max_norm是用户指定的全局最大范数值。例如:

import tensorflow as tfw1 = tf.random.normal([3,3])  # 创建梯度张量1
w2 = tf.random.normal([3,3])  # 创建梯度张量2
# 计算global norm
global_norm = tf.math.sqrt(tf.norm(w1)**2+tf.norm(w2)**2)
# 根据global norm和max norm=2裁剪
(ww1, ww2), global_norm = tf.clip_by_global_norm([w1,w2],2)
# 计算裁剪后的张量组的global norm
global_norm2 = tf.math.sqrt(tf.norm(ww1)**2+tf.norm(ww2)**2)
print(global_norm, global_norm2)

运行结果如下所示:

tf.Tensor(4.220784, shape=(), dtype=float32) tf.Tensor(1.9999999, shape=(), dtype=float32)

可以看到,通过裁剪后,网络参数的梯度组的总范数缩减到max_norm=2\text{max\_norm}=2max_norm=2。需要注意的是,tf.clip_by_global_norm返回裁剪后的张量Listglobal_norm这两个对象,其中global_norm表示裁剪前的梯度总范数和。

 通过梯度裁剪,可以较大程度地抑制梯度爆炸现象。如下图所示,图中曲面表示的J(w,b)J(w,b)J(w,b)函数在不同网络参数www和bbb下的误差值JJJ,其中有一块区域J(w,b)J(w,b)J(w,b)函数的梯度变化较大,一旦网络参数进入此区域,很容易出现梯度爆炸的现象,使得网络状态迅速恶化。下图右侧演示了添加梯度裁剪后的优化轨迹,由于对梯度进行了有效限制,使得每次更新的步长得到有效控制,从而防止网络突然恶化。

梯度裁剪的优化轨迹示意图

 在网络训练时,梯度裁剪一般在计算出梯度后,梯度更新之前进行。例如:

with tf.GradientTape() as tape:logits = model(x) # 前向传播loss = criteon(y, logits) # 误差计算
# 计算梯度值
grads = tape.gradient(loss, model.trainable_variables)
grads, _ = tf.clip_by_global_norm(grads, 25) # 全局梯度裁剪
# 利用裁剪后的梯度张量更新参数
optimizer.apply_gradients(zip(grads, model.trainable_variables))

梯度弥散

 对于梯度弥散现象,可以通过增大学习率、减少网络深度、增加Skip Connection等一系列的措施抑制。

 增大学习率ηηη可以在一定程度上防止梯度弥散现象,当出现梯度弥散时,网络的梯度∇θL∇_θ\mathcal L∇θ​L接近于0,此时若学习率ηηη也较小,如η=1e−5η=1\text{e}-5η=1e−5,则梯度更新步长更加微小。通过增大学习率,如令η=1e−2η=1\text{e}-2η=1e−2,有可能使得网络的状态得到快速更新,从而逃离梯度弥散区域。

 对于深层次的神经网络,梯度由最末层逐渐向首层传播,梯度弥散一般更有可能出现在网络的开始数层。在深度残差网络出现之前,几十上百层的深层网络训练起来非常困难,前面数层的物流梯度极容易出现梯度离散现象,从而使得网络参数长时间得不到更新。深度残差网络较好地克服了梯度弥散现象,从而让神经网络层数达到成百上千层。一般来说,减少网络深度可以减轻梯度弥散现象,但是网络层数减少后,网络表达能力也会偏弱,需要用户自行平衡。

深度学习之循环神经网络(7)梯度裁剪相关推荐

  1. 深度学习之循环神经网络(6)梯度弥散和梯度爆炸

    深度学习之循环神经网络(6)梯度弥散和梯度爆炸  循环神经网络的训练并不稳定,网络的善妒也不能任意加深.那么,为什么循环神经网络会出现训练困难的问题呢?简单回顾梯度推导中的关键表达式: ∂ht∂hi= ...

  2. 深度学习之循环神经网络(3)梯度传播

    深度学习之循环神经网络(3)梯度传播  通过循环神经网络的更新表达式可以看出输出对张量Wxh\boldsymbol W_{xh}Wxh​.Whh\boldsymbol W_{hh}Whh​和偏置b\b ...

  3. 深度学习之循环神经网络(12)预训练的词向量

    深度学习之循环神经网络(12)预训练的词向量  在情感分类任务时,Embedding层是从零开始训练的.实际上,对于文本处理任务来说,领域知识大部分是共享的,因此我们能够利用在其它任务上训练好的词向量 ...

  4. 深度学习之循环神经网络(10)GRU简介

    深度学习之循环神经网络(10)GRU简介 1. 复位门 2. 更新门 3. GRU使用方法  LSTM具有更长的记忆能力,在大部分序列任务上面都取得了比基础RNN模型更好的性能表现,更重要的是,LST ...

  5. 深度学习之循环神经网络(4)RNN层使用方法

    深度学习之循环神经网络(4)RNN层使用方法 1. SimpleRNNCell 2. 多层SimpleRNNCell网络 3. SimpleRNN层  在介绍完循环神经网络的算法原理之后,我们来学习如 ...

  6. 深度学习之循环神经网络(1)序列表示方法

    深度学习之循环神经网络(1)序列表示方法 序列表示方法 Embedding层 2. 预训练的词向量 前面的卷积神经网络利用数据的局部相关性和权值共享的思想大大减少了网络的参数量,非常适合于图片这种具有 ...

  7. 水很深的深度学习-Task05循环神经网络RNN

    循环神经网络 Recurrent Neural Network 参考资料: Unusual-Deep-Learning 零基础入门深度学习(5) - 循环神经网络 史上最小白之RNN详解_Tink19 ...

  8. 【深度学习】循环神经网络(RNN)的tensorflow实现

    [深度学习]循环神经网络(RNN)的tensorflow实现 一.循环神经网络原理 1.1.RNN的网络结构 1.2.RNN的特点 1.3.RNN的训练 二.循环神经网络的tensorflow实现 参 ...

  9. 深度学习原理-----循环神经网络(RNN、LSTM)

    系列文章目录 深度学习原理-----线性回归+梯度下降法 深度学习原理-----逻辑回归算法 深度学习原理-----全连接神经网络 深度学习原理-----卷积神经网络 深度学习原理-----循环神经网 ...

最新文章

  1. 卷积神经网络(CNN)数学原理解析
  2. 【AI】Win10-Tensorflow
  3. oracelp---随意 记录(nvl)
  4. Python基础教程:新式类与经典类
  5. asp mysql 连接字符串,在ASP中连接数据库(连接字符串)
  6. Windows mobile 下读取手机SIM卡信息
  7. iphone新旧手机数据传输已取消_iPhone 手机支付宝自动扣费?取消服务提示“无法解约”?...
  8. ftp java 关闭连接超时_关于FTP连接超时的解决办法
  9. 【STC15W402AS程序下载问题】
  10. Java 发送短信工具类
  11. win10 往vmware 黑苹果系统无法拖拽复制问题
  12. Java调用python脚本,进程长时间卡住问题
  13. ISO8583接口的详细资料
  14. 【读点论文】FBNetV2:Differentiable Neural Architecture Search for Spatial and Channel D扩大搜索空间,复用featuremap
  15. 计算机里找不到用户文件夹,电脑里面的文件夹不见了,怎么找回
  16. SDL是什么,能干什么,为什么我们要学习它?
  17. Kotlin 笔记 纯属娱乐萌新大佬绕道
  18. 瞧一瞧看一看啦“一段眼睛跟着鼠标转动的跟踪眼代码”
  19. Android Shortcuts使用详解
  20. 大数据所见即所得,人机共同进化之端倪

热门文章

  1. 数据库服务器查询格式化显示,在数据库服务器端养成设置NLS_LANG和NLS_DATE_FORMAT环境变量的习惯...
  2. 没有语言基础可以学python_没有Python语言基础可以学习深度学习吗?
  3. Android开发之Base64与bitmap互转的工具类
  4. Linux缺少qt5core,关于qt5:无法运行Qt应用:找不到版本“ Qt_5”
  5. c语言编程微信公众号图片直播,如何以图片的形式在微信公众号文章中添加小程序...
  6. 阿里云Tech Insight 企业迁云实战专场强势来袭!
  7. Boost中的Timer的使用——计算时间流逝
  8. 微信企业号开发之正式版的本地调试
  9. 这年头,胡萝卜也靠不住了
  10. OpenOffice介绍