pytorch中的retain_grad()如何工作?我发现它的位置改变了毕业结果

Dec*_*yde 12 python pytorch

在 pytorch 中的一个简单测试中,我想查看非叶张量中的 grad,因此我使用retain_grad():

import torch
a = torch.tensor([1.], requires_grad=True)
y = torch.zeros((10))
gt = torch.zeros((10))

y[0] = a
y[1] = y[0] * 2
y.retain_grad()

loss = torch.sum((y-gt) ** 2)
loss.backward()
print(y.grad)
Run Code Online (Sandbox Code Playgroud)

它给了我一个正常的输出:

tensor([2., 4., 0., 0., 0., 0., 0., 0., 0., 0.])
Run Code Online (Sandbox Code Playgroud)

但是当我在 y[1] 之前和 y[0] 分配之后使用保留 grad() 时:

import torch
a = torch.tensor([1.], requires_grad=True)
y = torch.zeros((10))
gt = torch.zeros((10))

y[0] = a
y.retain_grad()
y[1] = y[0] * 2

loss = torch.sum((y-gt) ** 2)
loss.backward()
print(y.grad)
Run Code Online (Sandbox Code Playgroud)

现在输出更改为:

tensor([10.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.,  0.])
Run Code Online (Sandbox Code Playgroud)

我根本无法理解这个结果。

Oma*_*idi 7

好吧,发生的事情真的很奇怪。

本质.retain_grad()上是将任何非叶张量转换为叶张量,使其包含一个.grad属性(因为默认情况下,pytorch 仅计算叶张量的梯度)。

因此,在您的第一个示例中,在调用 后y.retain_grad(),它基本上转换y为具有可访问属性的叶张量.grad

但是,在第二个示例中,您最初将整个y张量转换为叶张量;然后,您(y[1]) 叶张量中创建了一个非叶张量(y),这就是造成混乱的原因。

y = torch.zeros((10))  # y is a non-leaf tensor

y[0] = a  # y[0] is a non-leaf tensor
y.retain_grad()  # y is a leaf tensor (including y[1])
y[1] = y[0] * 2  # y[1] is a non-leaf tensor, BUT y[0], y[2], y[3], ..., y[9] are all leaf tensors!
Run Code Online (Sandbox Code Playgroud)

令人困惑的部分是:

y[1] 调用后现在y.retain_grad() 一个带有.grad属性的叶张量。然而,计算y[1] 之后(y[1] = y[0] * 2)现在不是一个带有.grad属性的叶张量;它现在被视为新的非叶变量/张量。

因此,当调用 时, wrtloss.backward()的链式规则,特别是查看wrt 叶子的链式规则现在看起来像这样:lossylossy[1]


链式法则

  • `retain_grad()` 不会转换为叶张量。您可以通过打印“y.is_leaf”来验证这一点。成为叶子与保留毕业生不同。简单的叶张量总是保留梯度,而非叶张量默认情况下不会。 (2认同)