【问题标题】:can't find the inplace operation: one of the variables needed for gradient computation has been modified by an inplace operation找不到就地操作:梯度计算所需的变量之一已被就地操作修改
【发布时间】:2019-05-10 11:55:03
【问题描述】:

我正在尝试计算网络的雅可比损失(即执行双反向传播),我收到以下错误: RuntimeError:梯度计算所需的变量之一已被就地操作修改

我的代码中找不到inplace操作,所以不知道要修复哪一行。

*最后一行出现错误: loss3.backward()

            inputs_reg = Variable(data, requires_grad=True)
            output_reg = self.model.forward(inputs_reg)

            num_classes = output.size()[1]
            jacobian_list = []
            grad_output = torch.zeros(*output_reg.size())

            if inputs_reg.is_cuda:
                grad_output = grad_output.cuda()
                jacobian_list = jacobian.cuda()

            for i in range(10):

                zero_gradients(inputs_reg)
                grad_output.zero_()
                grad_output[:, i] = 1
                jacobian_list.append(torch.autograd.grad(outputs=output_reg,
                                                  inputs=inputs_reg,
                                                  grad_outputs=grad_output,
                                                  only_inputs=True,
                                                  retain_graph=True,
                                                  create_graph=True)[0])


            jacobian = torch.stack(jacobian_list, dim=0)
            loss3 = jacobian.norm()
            loss3.backward()

【问题讨论】:

  • grad_output.zero_() 似乎是就地操作。您可能在self.model 中进行了就地操作。
  • grad_output.zero_() 是就地操作。在 PyTorch 中,就地操作以下划线结尾。我想你想写 `grad_output.zero_grad()
  • 在将新列(对应于我希望计算梯度的输出)设置为 1 之前,我需要将 grad_output 归零。所以我将 grad_output.zero_() 更改为 grad_output[:,i-1] = 0 并没有帮助。
  • 实际上我上面描述的是将一个就地操作替换为另一个。

标签: pytorch backpropagation


【解决方案1】:

您可以使用set_detect_anomaly function available in autograd 包来准确查找导致错误的行。

这是link,它描述了相同的问题以及使用上述功能的解决方案。

【讨论】:

    【解决方案2】:

    grad_output.zero_() 是就地的,grad_output[:, i-1] = 0 也是。就地意味着“修改张量而不是返回已应用修改的新张量”。一个未就地的示例解决方案是torch.where。将第一列归零的示例

    import torch
    t = torch.randn(3, 3)
    ixs = torch.arange(3, dtype=torch.int64)
    zeroed = torch.where(ixs[None, :] == 1, torch.tensor(0.), t)
    
    zeroed
    tensor([[-0.6616,  0.0000,  0.7329],
            [ 0.8961,  0.0000, -0.1978],
            [ 0.0798,  0.0000, -1.2041]])
    
    t
    tensor([[-0.6616, -1.6422,  0.7329],
            [ 0.8961, -0.9623, -0.1978],
            [ 0.0798, -0.7733, -1.2041]])
    

    注意t 如何保留它之前的值,而zeroed 拥有你想要的值。

    【讨论】:

      【解决方案3】:

      谢谢! 我将 grad_output 中的就地操作有问题的代码替换为:

                  inputs_reg = Variable(data, requires_grad=True)
                  output_reg = self.model.forward(inputs_reg)
                  num_classes = output.size()[1]
      
                  jacobian_list = []
                  grad_output = torch.zeros(*output_reg.size())
      
                  if inputs_reg.is_cuda:
                      grad_output = grad_output.cuda()
      
                  for i in range(5):
                      zero_gradients(inputs_reg)
      
                      grad_output_curr = grad_output.clone()
                      grad_output_curr[:, i] = 1
                      jacobian_list.append(torch.autograd.grad(outputs=output_reg,
                                                               inputs=inputs_reg,
                                                               grad_outputs=grad_output_curr,
                                                               only_inputs=True,
                                                               retain_graph=True,
                                                               create_graph=True)[0])
      
                  jacobian = torch.stack(jacobian_list, dim=0)
                  loss3 = jacobian.norm()
                  loss3.backward()
      

      【讨论】:

      • 请注意,grad_output_curr[:, i] = 1 行仍然是就地操作,可能(也可能不会)进一步造成麻烦。
      猜你喜欢
      • 2020-11-11
      • 2020-08-02
      • 2019-12-29
      • 2020-09-15
      • 2021-11-04
      • 2020-01-03
      • 2020-08-25
      • 2022-10-01
      • 2021-08-05
      相关资源
      最近更新 更多