PyTorch - 使用 `param.grad` 会影响学习过程吗? [解决了]

时间:2021-01-24 21:53:20

标签: python neural-network pytorch

我正在 CIFAR-10 上训练 ResNet34。当我尝试为 param.grad 操作 model.parameters() 时,我有一个非常奇怪的行为。

以下函数是所有混乱发生的地方。由于试图了解会发生什么,它目前没有做任何有用的事情。

def add_error(error):
    params = (param for param in model.parameters() if param.requires_grad)
    # [param.grad + err for param, err in zip(params, error)]                        # Line 2
    # new_error = [param.grad + err for param, err in zip(params, error)]            # Line 3
    for param in params:
      param.grad.zero_()
    # new_error = [torch.zeros(param.grad.shape, device=device) for param in params] # Line 6
    return new_error

用于梯度下降步骤:

def step(model, optimizer, batch, labels, error):
  optimizer.zero_grad()
  loss = compute_loss(model, batch, labels)
  loss.backward()

  new_error = add_error(error=error)      <- add_error is called here
  optimizer.step()
  return new_error

其中优化器是 optim.SGD(model.parameters(), lr=0.1)compute_loss 本质上在 nn.CrossEntropyLoss()model(batch) 上调用 labels

我的期望:由于我将梯度设置为 0,所以无论我做什么,都不会发生任何变化:损失应该一直在原始值(2.4)附近

实际发生的事情

  • 当我只取消第 6 行的注释时,一切都按预期进行:损失接近常数 2.4
  • 当我只取消第 3 行的注释时,学习就好像我根本没有调用 add_error 一样。 IE。损失以与通常 SGD 相同的速度下降:2.4 -> 1.7 -> 1.3 -> ...(每个时期)。换句话说,以某种方式传播了梯度。
  • 当我取消注释第 2 行和第 6 行时:最奇怪的事情。损失增加4.3,然后缓慢减少4.3 -> 4.2 -> 4.14 -> 4.1 -> ...(我怀疑这种减少是批量标准化的结果)。

请注意,在这两种情况下,我实际上都使用 error,实际上我从未使用 error 来更新渐变。 此外,添加更多行(如第 2 行)不会影响结果。

问题:发生了什么?

  • 为什么损失会减少?渐变应始终为 $0$。
  • 如何改变损失值本身?

如果有帮助,我可能会尝试制作 MCVE 并将其发布在 pastebin 上(这将是一堵代码墙,太大而无法放在这里)。

1 个答案:

答案 0 :(得分:0)

这个问题非常愚蠢:params 是一个生成器,在第一次迭代后就耗尽了。创建一个列表而不是一个生成器可以解决这个问题。

相关问题