Pytorch 理解'背后的原因;RuntimeError:叶变量已移动到图形内部';
我试图了解pytorch和autograd在其中的工作原理。我尝试创建一个张量,用其他张量的值填充它,然后检查梯度。但是,我遇到了Pytorch 理解'背后的原因;RuntimeError:叶变量已移动到图形内部';,pytorch,Pytorch,我试图了解pytorch和autograd在其中的工作原理。我尝试创建一个张量,用其他张量的值填充它,然后检查梯度。但是,我遇到了RuntimeError:如果我没有将requires\u grad设置为False,则叶变量已移动到图形内部 代码: 输出: --------------------------------------------------------------------------- RuntimeError Tra
RuntimeError:如果我没有将requires\u grad
设置为False
,则叶变量已移动到图形内部
代码:
输出:
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-22-1000fc52a64c> in <module>
13 outi[1] = out2
14
---> 15 outi.backward(torch.tensor([0.,1.]))
~/anaconda3/envs/pytorch/lib/python3.8/site-packages/torch/tensor.py in backward(self, gradient, retain_graph, create_graph)
183 products. Defaults to ``False``.
184 """
--> 185 torch.autograd.backward(self, gradient, retain_graph, create_graph)
186
187 def register_hook(self, hook):
~/anaconda3/envs/pytorch/lib/python3.8/site-packages/torch/autograd/__init__.py in backward(tensors, grad_tensors, retain_graph, create_graph, grad_variables)
123 retain_graph = create_graph
124
--> 125 Variable._execution_engine.run_backward(
126 tensors, grad_tensors, retain_graph, create_graph,
127 allow_unreachable=True) # allow_unreachable flag
RuntimeError: leaf variable has been moved into the graph interior
empty. it worked
输出:
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-22-1000fc52a64c> in <module>
13 outi[1] = out2
14
---> 15 outi.backward(torch.tensor([0.,1.]))
~/anaconda3/envs/pytorch/lib/python3.8/site-packages/torch/tensor.py in backward(self, gradient, retain_graph, create_graph)
183 products. Defaults to ``False``.
184 """
--> 185 torch.autograd.backward(self, gradient, retain_graph, create_graph)
186
187 def register_hook(self, hook):
~/anaconda3/envs/pytorch/lib/python3.8/site-packages/torch/autograd/__init__.py in backward(tensors, grad_tensors, retain_graph, create_graph, grad_variables)
123 retain_graph = create_graph
124
--> 125 Variable._execution_engine.run_backward(
126 tensors, grad_tensors, retain_graph, create_graph,
127 allow_unreachable=True) # allow_unreachable flag
RuntimeError: leaf variable has been moved into the graph interior
empty. it worked
有人能帮我了解引擎盖下发生了什么,以及将require\u grad
设置为True后发生了什么变化,从而导致了这种行为吗?感谢您阅读简介
首先,定义PyTorch中的leaf
变量,您可以检查(我的重点):
所有具有的张量都需要_grad
,该张量为False
张量按惯例
对于具有要求_grad
为True
的张量,它们将
叶张量,如果它们是由用户创建的。这意味着他们
不是操作的结果,因此grad\u fn为None
让我们看看这是如何在原始代码中查找outi
变量的。创建后立即运行此代码段:
outi = torch.empty(2, requires_grad=True)
print(outi.is_leaf, outi.grad_fn, outi.requires_grad)
print(outi.is_leaf, outi.grad_fn, outi.requires_grad)
给出:
True, None, True
因为它是由用户创建的,并且之前没有创建它的操作,所以它应该是上面引用的第二个粗体字
现在这一行:
outi[0] = out1
outi[1] = out2
使用两个节点,它们不是叶,并且是返回到x
的图形的一部分(这是其中唯一的叶)。通过这样做,outi
也是原始x
图形的一部分,必须反向传播,但您将其指定为一片叶子(稍后将详细介绍),不能反向传播(根据定义,它们要么不需要梯度,要么由用户创建)。outi
asleaf
的版本已放在图表上,在上述赋值之后,此代码段:
outi = torch.empty(2, requires_grad=True)
print(outi.is_leaf, outi.grad_fn, outi.requires_grad)
print(outi.is_leaf, outi.grad_fn, outi.requires_grad)
更改:
False <CopySlices object at 0x7f2dfa83a3d0> True
但是,如果您像一样使用赋值,而不破坏预期行为,则此张量可以“升级”为非叶张量
为什么??由于内存优化,因为您隐式地(或在代码中显式地)说,您不需要此变量的梯度,PyTorch只保留叶变量的梯度(除非您指定。保留特定的张量的
)。因此,这里唯一的变化将是它不再是一片叶子,但是这不会违背承诺,因为.grad
将是None
如果您像最初那样拥有requires_grad=True
,那么根据PyTorch语义,您可以合理地认为:
outi.grad
将给你一个带梯度的张量。但是,如果这个需要将_grad=True
张量更改为非叶张量,那么根据定义,它就不会有这个字段(因为非叶张量有。grad=None
)
在我看来,这似乎是他们的一个设计决策,以避免与requires_grad=True
混淆并破坏预期的用户体验
顺便说一句。如果他们不允许图形中的leaf
变量,那么现在运行正常的操作(需要\u grad=False
)也应该被禁止。但由于要求_grad=False
是隐式的,并且经常使用(创建张量或类似于您所做的事情),因此它似乎没有太大的伸缩性。如果不允许,情况会严重得多。另一方面,如果您指定requires_grad=True
,则可以假定您更清楚自己在做什么,并且确实需要该渐变
BTW2.这个解释可能有点牵强,但希望能有所启发。关于这个错误,我还没有发现任何官方消息(承认我没有深入挖掘)
一些资源,(这一个很重要,有人要求对一些设计决策进行论证,尽管没有得到批准)
评论
评论1
我认为这个等级是从片中继承下来的,而且
.grad有空
是的,它有requires_grad
作为True
以及它现在是图表的一部分,,但是grad
不可用,因为它不再是叶子。在backward
之后打印outi.grad
将显示None
和以下警告:
UserWarning:不是叶张量的张量的.grad属性
正在访问。它的.grad属性在运行期间不会填充
autograd.backward()。如果你确实想要一个非叶子的渐变
张量,在非叶张量上使用.retain_grad()。如果您访问
非叶张量错误,请确保访问叶张量
相反更多信息,请参见github.com/pytorch/pytorch/pull/30531
信息
因此,.grad
属性无论如何都是None
,因为用户希望将requires\u grad=False
作为创建参数。如果用户要设置requires\u grad=True
,则可能期望梯度不是None
,此时PyTorch会引发错误,因为在这种情况下可能与用户期望不一致
评论2
例如:
a = torch.ones(2,requires_grad=False)
b = 2*a
b.requires_grad=True
print(b.is_leaf) #True
我对您的代码做了一些更改,以便一步一步地进行:
a = torch.ones(2, requires_grad=False)
print(a.is_leaf) # True
我们应该从a
开始,这里,a
是一片叶子,根据文档如下所示:
所有需要_grad为False的张量都将为leaf
张量按惯例
现在b
是leaf
,因为它不需要梯度(因为a
不需要梯度,它不需要通过这个分支反向传播)。使用操作张量需要_grad=False
创建不b.requires_grad = True
print(b.is_leaf)