RuntimeError:梯度计算所需变量已被inplace操作修改

参考文章:

1. 梯度计算所需变量已被inplace操作修改:RuntimeError”

2. torch.Tensor.detach()和Tensor.requires_grad方法的用法

3. Pytorch 反向传播 计算图被修改的报错

4. 生成对抗网络Runtime Error: one of the variables needed for gradient computation

问题:

在用pytorch生成对抗网络的时候,出现错误:

RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [512, 121]], which is output 0 of AsStridedBackward0, is at version 2; expected version 1 instead. Hint: the backtrace further above shows the operation that failed to compute its gradient. The variable in question was changed in there or anywhere later. Good luck!

在与GPT4的沟通中,发现了是“一个变量在进行梯度计算时被“原位操作”(inplace operation)修改了,这导致梯度无法被正确计算。”但是就算全部给它,它还是不能告诉我,到底怎么修改。
它给的建议主要是:

  1. 检查梯度共享: 确保在生成器和判别器之间没有不恰当的梯度共享。如果有共享层或参数,这可能会导致梯度计算问题。

  2. 避免原位操作: 检查所有可能影响到梯度计算的Tensor操作,确保没有进行原位操作。特别是在计算损失和执行反向传播之前,要特别小心。

  3. 简化损失计算: 检查损失函数的计算方式。确保损失的计算没有涉及到复杂的操作,这可能导致梯度计算错误。

  4. 分离和克隆Tensor: 在将生成器的输出传递给判别器之前,尝试使用 detach()clone() 方法来创建一个不具有梯度的Tensor副本。这有助于防止不必要的梯度传播。

  5. 逐步调试: 您已经在输出中加入了许多调试语句,这很好。您可以进一步缩小错误发生的范围。尤其是检查 gen_loss.backward(retain_graph=True) 这一步是否可能影响到判别器的梯度计算。

  6. 修改网络结构: 如果问题依旧存在,您可能需要重新审视生成器和判别器的网络结构,以确保它们的输入输出尺寸、层的设置都是正确的。

  7. 运行环境和库版本: 确保您使用的PyTorch版本和运行环境没有问题。有时候,库的不同版本或者环境配置的差异也可能导致意想不到的错误。

经过我把每个变量都打印出来,发现问题出现在discriminator_loss.backward()这一步!

由于我生成器和判别器之间还有一些对多生成器输出的操作,因此,在不能判断到底哪里出问题的情况下,我把判别器的部分代码,不断移动位置。

在更新完生成之后,立马更新判别器,报错变成了:

RuntimeError: Trying to backward through the graph a second time (or directly access saved tensors after they have already been freed). Saved intermediate values of the graph are freed when you call .backward() or autograd.grad(). Specify retain_graph=True if you need to backward through the graph a second time or if you need to access saved tensors after calling backward.

解决方法:

1. 使用 detach() 方法,将生成器输出与其计算图分离

其实,大体是知道需要将某个输出进行分离,但问题是很难找到是哪个变量需要分离,在gpt4审查代码中也发现不了明显的错误。

最终修改: