如何在PyTorch中正确执行梯度裁剪?
我的模型存在梯度爆炸的问题。
如何在PyTorch中正确执行梯度裁剪?
我的模型存在梯度爆炸的问题。
这里是一个更完整的示例,来自这里:
optimizer.zero_grad()
loss, hidden = model(data, hidden, targets)
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(), args.clip)
optimizer.step()
opt.zero_grad()
是否有影响?我猜可能越早清零,内存释放就越快? - Charlie Parkermax_norm
(剪切阈值)的值来自args
(可能是来自argparse
模块)。 - vdiclip_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))
register_hook
只在梯度上工作吗?因为我本来期望像param.grad
这样的东西。谢谢。 - sachinruk阅读论坛讨论后得出如下结论:
clipping_value = 1 # arbitrary value of your choosing
torch.nn.utils.clip_grad_norm(model.parameters(), clipping_value)
我相信这不仅仅只是这段代码片段所涵盖的。
如果您正在使用自动混合精度(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
该链接是关于PyTorch的自动混合精度(AMP)中梯度裁剪的示例说明。在训练深度神经网络时,梯度裁剪是一种常用的技术,旨在防止梯度爆炸现象的发生。本链接提供了使用PyTorch执行梯度裁剪的代码示例。