梯度裁剪以避免梯度爆炸

梯度裁剪

梯度用数学式子表达即为偏导数,梯度爆炸就等价于偏导数很大。

梯度裁剪应用的前提

网络在训练过程中出现了梯度爆炸(loss激增or直接NaN)的现象。梯度爆炸问题一般会随着网络层数的增加而变得越来越明显。

根据weight更新的计算公式:wi=wi−α∂N(Θ)∂wiw_i = w_i - \alpha \frac{\partial N(\Theta)}{\partial w_i}wi=wiαwiN(Θ), 其中∂N(Θ)∂wi\frac{\partial N(\Theta)}{\partial w_i}wiN(Θ)为复合函数求导。若每一层的偏导数都大于1,且层数又多,则容易发生梯度爆炸现象。

解决梯度爆炸问题的办法

  • 将学习率α\alphaα设置得小一点。但是如果使用重启余弦退火算法,就不可避免地会在重启时学习率跳到很大,学习率调到太小也不利于继续寻找最优解。而
  • 使用梯度裁剪,即控制∂N(Θ)∂wi\frac{\partial N(\Theta)}{\partial w_i}wiN(Θ)不能超过某一阈值。

PyTorch使用梯度裁剪

梯度裁剪的使用位置在loss.backward()得到梯度值之后,在使用optimizer.step()进行权重值更新之前。

固定阈值裁剪(对象:for gradient of each parameter)

约束每个权重参数wiw_iwi的梯度值∂N(Θ)∂wi∈[−x,x]\frac{\partial N(\Theta)}{\partial w_i}\in [-x, x]wiN(Θ)[x,x].

例子:

import torch.nn as nn
outputs = model(data)
loss= loss_fn(outputs, target)
optimizer.zero_grad()
loss.backward()
nn.utils.clip_grad_value_(model.parameters(), clip_value=x)
optimizer.step()

优点:简单粗暴;

缺点:因为是element-wise的操作,很难找到合适的阈值。

根据参数的范数来衡量(对象:for all gradients)

对所有权重参数{wi}i=1K\{w_i\}_{i=1}^{K}{wi}i=1K的总体范数进行约束。所有权重参数的总体范数为∥g∥n=[(∂N(Θ)∂w1)n+⋯+(∂N(Θ)∂wK)n]1n\Vert \mathbf{g}\Vert_n = {[(\frac{\partial N(\Theta)}{\partial w_1})^n + \cdots + (\frac{\partial N(\Theta)}{\partial w_K})^n]}^{\frac{1}{n}}gn=[(w1N(Θ))n++(wKN(Θ))n]n1,设置阈值ccc

∥g∥n≤c\Vert \mathbf{g}\Vert_n\leq cgnc时,不做clip的操作。

∥g∥n>c\Vert \mathbf{g}\Vert_n > cgn>c,执行操作g:=c∥g∥n⋅g\mathbf{g} := \frac{c}{\Vert \mathbf{g}\Vert_n} \cdot \mathbf{g}g:=gncg,最终∥g∥n=c\Vert \mathbf{g}\Vert_n = cgn=c

所以,通过对范数进行约束,以达到∥g∥n≤c\Vert \mathbf{g}\Vert_n\leq cgnc的目的,这种对于梯度值整体做缩放的操作,比较容易调参。

例子:

import torch.nn as nn
outputs = model(data)
loss= loss_fn(outputs, target)
optimizer.zero_grad()
loss.backward()
nn.utils.clip_grad_norm_(model.parameters(), max_norm=c, norm_type=2)
optimizer.step()

根据经验,ccc值的选取应由大到小,依次为10, 5, 1, 0.1。如果都不行的话,则需观察梯度更新时的值来进行具体设置。

关于实时梯度值的观测

此处举例观察各层梯度值的二范数(应该写在loss.backward()之后)中的最大值

max_grad_norm = 0
for param in model.parameters():
	if param.grad is not None:
		max_grad_norm = max(param.grad.data.norm(2), max_grad_norm)
print("the max value of gradient's L2 norm is {}".format(max_grad_norm))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值