【发布时间】:2021-01-25 07:01:56
【问题描述】:
我正在 CIFAR-10 上训练 ResNet34。当我尝试为model.parameters() 操作param.grad 时,我的行为非常奇怪。
下面的函数是所有混乱发生的地方。由于试图了解发生了什么,它目前没有做任何有用的事情。
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 本质上是在model(batch) 和labels 上调用nn.CrossEntropyLoss()。
我的期望:由于我将梯度设置为 0,所以无论我做什么,都不会改变:损失应该始终在原始值 (2.4) 附近
实际发生的情况:
- 当我只取消注释第 6 行时,一切正常:损失接近常数
2.4。 - 当我只取消注释第 3 行时,学习就像我根本没有调用
add_error一样发生。 IE。损失以与通常 SGD 相同的速度减少:2.4 -> 1.7 -> 1.3 -> ...(每个 epoch)。换句话说,梯度以某种方式传播。 - 当我取消注释第 2 行和第 6 行时:最奇怪的事情。损失增加到
4.3,然后慢慢减少4.3 -> 4.2 -> 4.14 -> 4.1 -> ...(我怀疑这种减少是批量标准化的结果)。
请注意,在这两种情况下,我实际上都没有使用error,实际上我从未使用error 来更新渐变。
此外,像第 2 行这样添加更多行不会影响结果。
问题:发生了什么?
- 为什么损失会减少?梯度应始终为 $0$。
- 如何改变损失值本身?
如果有帮助,我可能会尝试生成 MCVE 并将其发布在 pastebin 上(这将是一堵代码墙,太大而无法放在这里)。
【问题讨论】:
标签: python neural-network pytorch