Pytorch 理解'背后的原因;RuntimeError:叶变量已移动到图形内部';

Pytorch 理解'背后的原因;RuntimeError:叶变量已移动到图形内部';,pytorch,Pytorch,我试图了解pytorch和autograd在其中的工作原理。我尝试创建一个张量,用其他张量的值填充它,然后检查梯度。但是,我遇到了RuntimeError:如果我没有将requires\u grad设置为False,则叶变量已移动到图形内部 代码: 输出: --------------------------------------------------------------------------- RuntimeError Tra

我试图了解pytorch和autograd在其中的工作原理。我尝试创建一个张量,用其他张量的值填充它,然后检查梯度。但是,我遇到了
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
as
leaf
的版本已放在图表上,在上述赋值之后,此代码段:

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)