【问题标题】:How to do gradient clipping in pytorch?如何在pytorch中进行渐变剪裁?
【发布时间】:2019-07-10 00:18:51
【问题描述】:

在pytorch中执行渐变裁剪的正确方法是什么?

我有一个爆炸梯度问题,我需要编程解决它。

【问题讨论】:

  • @pierrom 谢谢。我自己找到了那个线程。认为在这里提问可以节省所有追随我和谷歌的人快速回答阅读所有讨论的麻烦(我自己还没有完成),并且只是得到一个快速的答案,stackoverflow风格。上论坛找答案让我想起了 1990

标签: python machine-learning deep-learning pytorch gradient-descent


【解决方案1】:

好吧,我遇到了同样的错误。我尝试使用剪辑规范,但它不起作用。

我不想更改网络或添加正则化器。所以我将优化器更改为 Adam,它就可以工作了。

然后我使用 Adam 的预训练模型开始训练并使用 SGD + 动量进行微调。它现在正在工作。

【讨论】:

  • “不起作用”是什么意思?
  • 仍然给出一个'nan'
【解决方案2】:

如果您使用的是自动混合精度 (AMP),则需要在剪辑之前做更多工作:

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

# Unscales the gradients of optimizer's assigned params in-place
self.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

【讨论】:

    【解决方案3】:

    clip_grad_norm(实际上已弃用 clip_grad_norm_,在执行就地修改时遵循更一致的尾随 _ 语法)剪辑了 overall 渐变的规范通过连接所有传递给函数的参数,从the documentation可以看出:

    范数是在所有梯度上一起计算的,就好像它们被连接成一个向量一样。渐变被原地修改。

    从您的示例看来,您希望 clip_grad_value_ 具有相似的语法,并且还可以就地修改渐变:

    clip_grad_value_(model.parameters(), clip_value)
    

    另一种选择是注册backward hook。这将当前梯度作为输入,并可能返回一个张量,该张量将用于代替先前的梯度,即修改它。每次计算梯度后都会调用此钩子,即一旦注册钩子就无需手动裁剪:

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

    【讨论】:

      【解决方案4】:

      阅读the forum discussion 给出了这个:

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

      我相信它比只有这段代码 sn-p 更深入。

      【讨论】:

        【解决方案5】:

        一个更完整的例子

        optimizer.zero_grad()        
        loss, hidden = model(data, hidden, targets)
        loss.backward()
        
        torch.nn.utils.clip_grad_norm_(model.parameters(), args.clip)
        optimizer.step()
        

        来源:https://github.com/pytorch/pytorch/issues/309

        【讨论】:

        • 为什么这个更完整?我看到更多的选票,但不明白为什么这更好。你能解释一下吗?
        • 这只是遵循一种流行的模式,可以在 loss.backward() 和 optimizer.step() 之间插入 torch.nn.utils.clip_grad_norm_(model.parameters(), args.clip)
        • 什么是args.clip?
        • 在前向传球之前是否致电opt.zero_grad() 是否重要?我的猜测是,它越早归零可能越早释放 MEM?
        猜你喜欢
        • 2021-09-15
        • 2020-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多