从 numpy 创建张量时缺少梯度
Lack of gradient when creating tensor from numpy
有人可以向我解释以下行为吗?
import torch
import numpy as np
z = torch.tensor(np.array([1., 1.]), requires_grad=True).float()
def pre_main(z):
return z * 3.0
x = pre_main(z)
x.backward(torch.tensor([1., 1.]))
print(z.grad)
打印:
None
同时:
import torch
import numpy as np
z = torch.tensor([1., 1.], requires_grad=True).float()
def pre_main(z):
return z * 3.0
x = pre_main(z)
x.backward(torch.tensor([1., 1.]))
print(z.grad)
打印:
tensor([3., 3.])
为什么从 numpy 数组构建时我的渐变被破坏了?我该如何解决这个问题?
可以先将numpy数组转为tensor,然后指定需要的梯度:
z = torch.from_numpy(np.array([1., 1.])).float()
z = torch.tensor(z, requires_grad=True)
x = pre_main(z)
x.backward(torch.tensor([1., 1.]))
print(z.grad)
多一点挖掘表明,如果在创建初始张量后删除浮点数转换 .float()
,则梯度计算有效。如果可行,您可以通过在 numpy 数组本身中指定 dtype 来完成此操作:
z = torch.tensor(np.array([1., 1.], dtype=np.float32), requires_grad=True)
x = pre_main(z)
x.backward(torch.tensor([1., 1.]))
print(z.grad)
您的渐变未被破坏:grad
returns None
因为它从未保存在 grad
属性上。这是因为 non-leaf 张量在反向传播过程中没有存储它们的梯度。因此,您在 运行 您的第一个代码段时收到的警告消息:
UserWarning: The .grad
attribute of a Tensor
that is not a leaf Tensor
is being accessed. Its .grad
attribute won't be populated during autograd.backward()
.
当您的 z
张量定义为:
时就是这种情况
>>> z = torch.tensor(np.array([1., 1.]), requires_grad=True).float()
>>> z.is_leaf
False
相比于:
>>> z = torch.tensor([1., 1.], requires_grad=True).float()
>>> z.is_leaf
True
表示后者的梯度值在z.grad
.
但请注意:
>>> z = torch.tensor(np.array([1., 1.]), requires_grad=True)
>>> z.is_leaf
True
为了进一步解释这一点:当张量第一次被初始化时,它是一个叶节点(.is_leaf
returns True
)。一旦你在它上面应用了一个函数(这里 .float()
是一个 in-place 运算符)它就不再是叶子了,因为它有 parents in计算图。
所以真的,没有什么可以修复...不过你可以做的是确保在调用向后传递时将渐变保存在 z.grad
上。所以,第二个问题归结为如何store/accessnon-leaf节点上的梯度?。
现在,如果您想在 .backward()
调用时存储渐变。您可以按照警告消息中的说明使用 retain_grad()
:
z = torch.tensor(np.array([1., 1.]), requires_grad=True).float()
z.retain_grad()
或者,因为我们希望它是叶节点,所以通过使用 FloatTensor
将 numpy.array
转换为 torch.Tensor
来解决它:
z = torch.FloatTensor(np.array([1., 1.]))
z.requires_grad=True
或者,您可以坚持使用 torch.tensor
并提供 dtype
:
z = torch.tensor(np.array([1., 1.]), dtype=torch.float64, requires_grad=True)
有人可以向我解释以下行为吗?
import torch
import numpy as np
z = torch.tensor(np.array([1., 1.]), requires_grad=True).float()
def pre_main(z):
return z * 3.0
x = pre_main(z)
x.backward(torch.tensor([1., 1.]))
print(z.grad)
打印:
None
同时:
import torch
import numpy as np
z = torch.tensor([1., 1.], requires_grad=True).float()
def pre_main(z):
return z * 3.0
x = pre_main(z)
x.backward(torch.tensor([1., 1.]))
print(z.grad)
打印:
tensor([3., 3.])
为什么从 numpy 数组构建时我的渐变被破坏了?我该如何解决这个问题?
可以先将numpy数组转为tensor,然后指定需要的梯度:
z = torch.from_numpy(np.array([1., 1.])).float()
z = torch.tensor(z, requires_grad=True)
x = pre_main(z)
x.backward(torch.tensor([1., 1.]))
print(z.grad)
多一点挖掘表明,如果在创建初始张量后删除浮点数转换 .float()
,则梯度计算有效。如果可行,您可以通过在 numpy 数组本身中指定 dtype 来完成此操作:
z = torch.tensor(np.array([1., 1.], dtype=np.float32), requires_grad=True)
x = pre_main(z)
x.backward(torch.tensor([1., 1.]))
print(z.grad)
您的渐变未被破坏:grad
returns None
因为它从未保存在 grad
属性上。这是因为 non-leaf 张量在反向传播过程中没有存储它们的梯度。因此,您在 运行 您的第一个代码段时收到的警告消息:
UserWarning: The
.grad
attribute of aTensor
that is not a leafTensor
is being accessed. Its.grad
attribute won't be populated duringautograd.backward()
.
当您的 z
张量定义为:
>>> z = torch.tensor(np.array([1., 1.]), requires_grad=True).float()
>>> z.is_leaf
False
相比于:
>>> z = torch.tensor([1., 1.], requires_grad=True).float()
>>> z.is_leaf
True
表示后者的梯度值在z.grad
.
但请注意:
>>> z = torch.tensor(np.array([1., 1.]), requires_grad=True)
>>> z.is_leaf
True
为了进一步解释这一点:当张量第一次被初始化时,它是一个叶节点(.is_leaf
returns True
)。一旦你在它上面应用了一个函数(这里 .float()
是一个 in-place 运算符)它就不再是叶子了,因为它有 parents in计算图。
所以真的,没有什么可以修复...不过你可以做的是确保在调用向后传递时将渐变保存在 z.grad
上。所以,第二个问题归结为如何store/accessnon-leaf节点上的梯度?。
现在,如果您想在 .backward()
调用时存储渐变。您可以按照警告消息中的说明使用 retain_grad()
:
z = torch.tensor(np.array([1., 1.]), requires_grad=True).float()
z.retain_grad()
或者,因为我们希望它是叶节点,所以通过使用 FloatTensor
将 numpy.array
转换为 torch.Tensor
来解决它:
z = torch.FloatTensor(np.array([1., 1.]))
z.requires_grad=True
或者,您可以坚持使用 torch.tensor
并提供 dtype
:
z = torch.tensor(np.array([1., 1.]), dtype=torch.float64, requires_grad=True)