Pytorch 找不到导致“错误”的就地操作;RuntimeError:梯度计算所需的一个变量已被就地操作修改:“0”;
我对PyTorch比较陌生,我试图从一篇学术论文中复制一个算法,该算法使用Hessian矩阵近似一个术语。我设置了一个玩具问题,这样我就可以比较完整Hessian的结果和近似值。我发现并一直在使用它来计算算法的完整Hessian部分 我得到了一个错误:“RuntimeError:梯度计算所需的一个变量被一个就地操作修改了。” 我已经浏览了简单的示例代码、文档和许多关于这个问题的论坛帖子,但找不到任何就地操作。任何帮助都将不胜感激 这是我的密码:Pytorch 找不到导致“错误”的就地操作;RuntimeError:梯度计算所需的一个变量已被就地操作修改:“0”;,pytorch,autograd,hessian-matrix,Pytorch,Autograd,Hessian Matrix,我对PyTorch比较陌生,我试图从一篇学术论文中复制一个算法,该算法使用Hessian矩阵近似一个术语。我设置了一个玩具问题,这样我就可以比较完整Hessian的结果和近似值。我发现并一直在使用它来计算算法的完整Hessian部分 我得到了一个错误:“RuntimeError:梯度计算所需的一个变量被一个就地操作修改了。” 我已经浏览了简单的示例代码、文档和许多关于这个问题的论坛帖子,但找不到任何就地操作。任何帮助都将不胜感激 这是我的密码: import torch import torch
import torch
import torch.autograd as autograd
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np
torch.set_printoptions(precision=20, linewidth=180)
def jacobian(y, x, create_graph=False):
jac = []
flat_y = y.reshape(-1)
grad_y = torch.zeros_like(flat_y)
for i in range(len(flat_y)):
grad_y[i] = 1.
grad_x, = torch.autograd.grad(flat_y, x, grad_y, retain_graph=True, create_graph=create_graph)
jac.append(grad_x.reshape(x.shape))
grad_y[i] = 0.
return torch.stack(jac).reshape(y.shape + x.shape)
def hessian(y, x):
return jacobian(jacobian(y, x, create_graph=True), x)
def f(x):
return x * x
np.random.seed(435537698)
num_dims = 2
num_samples = 3
X = [np.random.uniform(size=num_dims) for i in range(num_samples)]
print('X: \n{}\n\n'.format(X))
mean = torch.Tensor(np.mean(X, axis=0))
mean.requires_grad = True
print('mean: \n{}\n\n'.format(mean))
cov = torch.Tensor(np.cov(X, rowvar=False))
print('cov: \n{}\n\n'.format(cov))
with autograd.detect_anomaly():
hessian_matrices = hessian(f(mean), mean)
print('hessian: \n{}\n\n'.format(hessian_matrices))
下面是堆栈跟踪的输出:
X:
[array([0.81700949, 0.17141617]), array([0.53579366, 0.31141496]), array([0.49756485, 0.97495776])]
mean:
tensor([0.61678934097290039062, 0.48592963814735412598], requires_grad=True)
cov:
tensor([[ 0.03043144382536411285, -0.05357056483626365662],
[-0.05357056483626365662, 0.18426130712032318115]])
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-3-5a1c492d2873> in <module>()
42
43 with autograd.detect_anomaly():
---> 44 hessian_matrices = hessian(f(mean), mean)
45 print('hessian: \n{}\n\n'.format(hessian_matrices))
2 frames
<ipython-input-3-5a1c492d2873> in hessian(y, x)
21
22 def hessian(y, x):
---> 23 return jacobian(jacobian(y, x, create_graph=True), x)
24
25 def f(x):
<ipython-input-3-5a1c492d2873> in jacobian(y, x, create_graph)
15 for i in range(len(flat_y)):
16 grad_y[i] = 1.
---> 17 grad_x, = torch.autograd.grad(flat_y, x, grad_y, retain_graph=True, create_graph=create_graph)
18 jac.append(grad_x.reshape(x.shape))
19 grad_y[i] = 0.
/usr/local/lib/python3.6/dist-packages/torch/autograd/__init__.py in grad(outputs, inputs, grad_outputs, retain_graph, create_graph, only_inputs, allow_unused)
155 return Variable._execution_engine.run_backward(
156 outputs, grad_outputs, retain_graph, create_graph,
--> 157 inputs, allow_unused)
158
159
RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: [torch.FloatTensor [2]] is at version 4; expected version 3 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!
X:
[阵列([0.81700949,0.17141617])、阵列([0.53579366,0.31141496])、阵列([0.49756485,0.97495776])]
意思是:
张量([0.6167893409729062,0.48592963814735412598],需要_grad=True)
冠状病毒:
张量([[0.03043144382536411285,-0.05357056483626365662],
[-0.05357056483626365662, 0.18426130712032318115]])
---------------------------------------------------------------------------
运行时错误回溯(上次最近调用)
在()
42
43带自动标记。检测异常()
--->44 hessian_矩阵=hessian(f(平均值),平均值)
45打印('hessian:\n{}\n\n'.格式(hessian_矩阵))
2帧
黑森语(y,x)
21
22 def hessian(y,x):
--->23返回雅可比矩阵(雅可比矩阵(y,x,create_graph=True),x)
24
25 def f(x):
在雅可比矩阵中(y,x,创建_图)
15对于范围内的i(透镜(平面y)):
16 grad_y[i]=1。
--->17 grad\u x,=torch.autograd.grad(展平,x,grad\u y,保留图=真,创建图=创建图)
18 jac.追加(渐变x.整形(x.形状))
19 grad_y[i]=0。
/usr/local/lib/python3.6/dist packages/torch/autograd/_init_uuuuuuuuuuuuuuuu.py渐变(输出、输入、渐变输出、保留图、创建图、仅输入、允许未使用)
155返回变量。\u执行\u引擎。向后运行\u(
156个输出,渐变输出,保留图,创建图,
-->157输入,允许(未使用)
158
159
RuntimeError:梯度计算所需的一个变量已被就地操作修改:[torch.FloatTensor[2]]处于版本4;应该是版本3。提示:上面的回溯显示了无法计算其梯度的操作。所讨论的变量在那里或以后的任何地方发生了更改。祝你好运
我真诚地认为这是PyTorch中的一个bug,但在发布了一个bug之后,我从albanD那里得到了一个很好的答案。他还指出,这是可以用来提问的
问题的出现是因为我们一次又一次地遍历计算图。但我无法理解这里到底发生了什么
错误消息所指的就地编辑是显而易见的:grad\u y[i]=1。
和grad\u y[i]=0。
。在计算中反复执行grad_y
是导致问题的原因。重新定义雅可比(…)如下对我很有用
定义雅可比矩阵(y,x,create_graph=False):
jac=[]
平面y=y。重塑(-1)
对于范围内的i(len(flat_y)):
grad_y=火炬。类零(平坦)
grad_y[i]=1。
grad\u x,=torch.autograd.grad(展平,x,grad\u y,保留图=真,创建图=创建图)
jac.append(渐变x重塑(x.shape))
返回火炬。堆叠(jac)。重塑(y形+x形)
另一种可行的方法,但对我来说更像是黑魔法,就是保持雅可比(…)不变,而是重新定义f(x)
def(x):
返回x*x*1
这也行 对于未来的读者来说,标题中提到的运行时错误可能会出现在比原作者更一般的环境中,例如,当在张量切片中移动和/或从列表理解中操作张量时,因为这正是我来到这里的背景(我的搜索引擎返回运行时错误的第一个链接) 为了防止这种运行时错误并确保梯度可以平滑流动,在上面的链接中提到了对我最有用的原理(但在解决方案消息中没有提到),它包括在移动它们(或其中的一些片段)时使用
torch.Tensor的.clone()
方法
例如:
some_container[slice_indices] = original_tensor[slice_indices].clone()
其中,只有原始\u tensor
具有要求\u grad=True
,随后(可能成批)操作将在tensor某些容器上执行
或:
似乎在C代码中发生了一些神奇的事情,torch.autograd.grad
…将f(x)
的定义从x*x
更改为x*x*torch
解决了这个问题。我不知道为什么…在我看来似乎是PyTorch中的一个bug…这确实让它神奇地发挥了作用。如果有人能解释一下原因,那就太好了。谢谢你的指导@Yunnosch,我已经试着做了更彻底的解释,并强调了我打算以何种方式添加到上一个sol中我希望它是合适的?如果我还漏掉一点,请告诉我…现在看起来更像是一个答案。我对“加宽”并不完全满意实际问题的范围。另一方面,来这里寻求标题的人可能会在这篇文章中找到帮助。我不知道Q/a对应该是什么样的,但我现在接受这一点作为答案。(严格来说,这不是我的技术领域,所以我不做判断,因为我可能太远了…)玩得开心。
some_container = [
tensor.clone()
for tensor in some_tensor_list if some_condition_fn(tensor)
]
new_composed_tensor = torch.cat(some_container, dim=0)