关于optimizer.step()引发卷积原地操作梯度错误的技术问询
PyTorch多优化器与反向传播的原地操作问题解答
疑问1:optimizer.step()方法如何引发卷积中的原地操作?
Adam优化器的step()方法会原地更新参数张量,同时它还会维护参数对应的动量、二阶矩等状态缓冲区(比如exp_avg、exp_avg_sq)。当你在第一次反向传播(s_loss.backward(retain_graph=True))后就调用第一个优化器的step(),它会直接修改共享网络中卷积层的参数值,同时参数张量的内部版本号(_version)会递增。
PyTorch的自动微分机制会跟踪张量版本,确保反向传播时使用的参数和前向传播时的参数是同一版本。后续执行loss.backward()时,需要基于前向传播的原始参数计算梯度,但此时参数已经被step()原地修改,版本不匹配,就会触发“卷积参数张量版本不匹配”的原地操作错误——因为反向传播过程中检测到参数已被意外篡改。
疑问2:为何将step()调用移至所有反向传播之后能解决该错误?
把所有反向传播操作完成后再调用优化器的step(),核心逻辑是先把所有需要的梯度计算并累积到参数的.grad属性中,再统一更新参数:
- 所有反向传播结束后,前向传播依赖的参数版本已不再需要,此时执行
step()修改参数,不会干扰已经完成的梯度计算过程。 - 两个优化器的
step()基于最终累积的梯度更新各自负责的参数,不会在反向传播中途修改参数,避免了参数版本在梯度计算过程中发生变化,自然就不会触发版本不匹配的错误。
注:替换为dice-loss仍出现相同错误,是因为问题根源不在损失函数,而在于优化器更新时机与反向传播的参数版本冲突,和损失函数类型无关。
内容的提问来源于stack exchange,提问作者Pooya Mohammadi Kazaj
相关产品推荐
相关产品推荐

