RNN梯度裁剪
最近抗疫在家蹲监狱,恰巧参加DataWhale组织的组队学习,这次的内容是深度学习,看到RNN的讲解这里,有一个“梯度裁剪”的方法不是很理解,故百度一波,整理一下,首先放上讲解中的定义(也是我百度出来的第一篇博客里的内容):
循环神经网络中较容易出现梯度衰减或梯度爆炸,这会导致网络几乎无法训练。裁剪梯度(clip gradient)是一种应对梯度爆炸的方法。假设我们把所有模型参数的梯度拼接成一个向量 𝑔 ,并设裁剪的阈值是 𝜃 。裁剪后的梯度的 𝐿2 范数不超过 𝜃 。
m i n ( θ ∣ ∣ g ∣ ∣ , 1 ) g min(\frac{\theta}{||g||},1)g min(∣∣g∣∣θ,1)g (1)
第一次看过这个定义后,我知道这方法无非就是设置一个阈值,当梯度过大时,反向传播(BP)就按设定的阈值来,至于上面的公式,看不懂。那么就从头道来,这里参考的是知乎大神,原文链接:深度炼丹之梯度裁剪
梯度爆炸问题的出现
考虑最简单的形式,假设一个单层感知机:
Y
=
w
X
+
b
Y =wX+b
Y=wX+b
其中Y是输出,X是输入,w是需要训练的参数,为进一步简化,设b=0,这样单层感知机变为:
Y
=
w
X
Y =wX
Y=wX
那么这个单层感知机的梯度grad是:
g
r
a
d
=
d
Y
d
w
=
X
grad=\frac{dY}{dw}=X
grad=dwdY=X
现在带值进去看,假设w初始值
w
0
w_0
w0为1,X=120,学习率lr=0.1,现在进行BP过程:
w
=
w
0
−
l
r
∗
g
r
a
d
w=w_0-lr*grad
w=w0−lr∗grad
w
=
1
−
0.1
∗
120
=
−
11
w=1-0.1*120=-11
w=1−0.1∗120=−11
这只是一次BP,梯度就这么大,在RNN里,有多少个时间序列,grad就会累乘多少个,当时间序列很长,每个grad都是远大于1的数值时,当BP过程传到前面时就会造成梯度爆炸。
pytorch中的梯度裁剪方法
pytorch中使用clip_grad_value_()函数对grad进行限制,源码:
def clip_grad_value_(parameters, clip_value):
r"""Clips gradient of an iterable of parameters at specified value.
Gradients are modified in-place.
Arguments:
parameters (Iterable[Tensor] or Tensor): an iterable of Tensors or a
single Tensor that will have gradients normalized
clip_value (float or int): maximum allowed value of the gradients.
The gradients are clipped in the range
"""
if isinstance(parameters, torch.Tensor):
parameters = [parameters]
clip_value = float(clip_value)
for p in filter(lambda p: p.grad is not None, parameters):
p.grad.data.clamp_(min=-clip_value, max=clip_value)
源码中clip_value就是自己设置的阈值,从最后一行来看,这个函数的作用就是把grad限制在 ± \pm ±|clip_value|之内,貌似与公式(1)没什么关系 - -!
回看公式(1)
通过上述理解,我再次看到公式(1)时:
m
i
n
(
θ
∣
∣
g
∣
∣
,
1
)
g
min(\frac{\theta}{||g||},1)g
min(∣∣g∣∣θ,1)g现固定一个你自己设置的阈值
θ
\theta
θ(为了方便说明,就设
θ
\theta
θ=2),由于式中g为梯度grad,当g很大时,会造成梯度爆炸问题,假设此时那那
∣
∣
g
∣
∣
=
4
||g|| =4
∣∣g∣∣=4,
θ
∣
∣
g
∣
∣
=
0.5
<
1
\frac{\theta}{||g||}=0.5<1
∣∣g∣∣θ=0.5<1,那么
m
i
n
(
θ
∣
∣
g
∣
∣
,
1
)
g
=
θ
∣
∣
g
∣
∣
g
=
0.5
g
min(\frac{\theta}{||g||},1)g=\frac{\theta}{||g||}g=0.5g
min(∣∣g∣∣θ,1)g=∣∣g∣∣θg=0.5g
当g不是很大时,假设此时
∣
∣
g
∣
∣
=
1
||g||=1
∣∣g∣∣=1,
θ
∣
∣
g
∣
∣
=
2
>
1
\frac{\theta}{||g||}=2>1
∣∣g∣∣θ=2>1,那么
m
i
n
(
θ
∣
∣
g
∣
∣
,
1
)
g
=
1
∗
g
=
g
min(\frac{\theta}{||g||},1)g=1*g=g
min(∣∣g∣∣θ,1)g=1∗g=g
通过对公式(1)的分析可以看出,梯度裁剪就是当你梯度太大时强行把梯度缩小(通过乘以一个小于1的数,即
θ
∣
∣
g
∣
∣
\frac{\theta}{||g||}
∣∣g∣∣θ),当你梯度不是很大时,保持原样。
至于解释中 “裁剪后的梯度的L2范数不超过 θ \theta θ ”我还不是很理解,以及为什么选择 θ ∣ ∣ g ∣ ∣ \frac{\theta}{||g||} ∣∣g∣∣θ当裁剪系数,希望有大佬可以告诉我,前面内容表述如有理解不当烦请轻喷,谢谢。