如何做渐变剪切在 Pytorch?

什么是正确的方法来执行渐变剪切在 Pytorch?

我有一个爆炸梯度问题。

117712 次浏览

通过 论坛讨论的阅读得出了这样的结论:

clipping_value = 1 # arbitrary value of your choosing
torch.nn.utils.clip_grad_norm(model.parameters(), clipping_value)

我确信它比这个代码片段更有深度。

clip_grad_norm (在执行原位修改时,实际上已经不推荐使用 clip_grad_norm_,因为后面的 _语法更一致)通过连接传递给函数的所有参数来剪辑 总的来说梯度的范数,从 文件中可以看出:

范数是通过所有的梯度一起计算的,就好像它们被连接成一个单一的向量。梯度就地修改。

从你的例子来看,你想要的是 clip_grad_value_,它有一个类似的语法,也修改了原来的渐变:

clip_grad_value_(model.parameters(), clip_value)

另一种选择是注册一个 倒钩倒钩。这需要当前的梯度作为输入,并可能返回一个张量,将用于代替以前的梯度,即修改它。这个钩子在每次计算出梯度之后都会被调用,也就是说,一旦钩子被注册,就不需要手动剪切了:

for p in model.parameters():
p.register_hook(lambda grad: torch.clamp(grad, -clip_value, clip_value))

来自 给你的一个更完整的例子:

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


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

如果你使用自动混合精度(AMP) ,你需要做更多的剪辑之前,AMP 规模的梯度:

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


# Unscales the gradients of optimizer's assigned params in-place
scaler.unscale_(optimizer)


# Since the gradients of optimizer's assigned params are unscaled, clips as usual:
torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm)


# optimizer's gradients are already unscaled, so scaler.step does not unscale them,
# although it still skips optimizer.step() if the gradients contain infs or NaNs.
scaler.step(optimizer)


# Updates the scale for next iteration.
scaler.update()

参考资料: https://pytorch.org/docs/stable/notes/amp_examples.html#gradient-clipping