PyTorch autograd -- 只能为标量输出隐式创建 grad

Posted

技术标签:

【中文标题】PyTorch autograd -- 只能为标量输出隐式创建 grad【英文标题】:PyTorch autograd -- grad can be implicitly created only for scalar outputs 【发布时间】:2019-02-18 09:46:24 【问题描述】:

我正在使用PyTorch 中的autograd 工具,发现自己需要通过整数索引访问一维张量中的值。像这样的:

def basic_fun(x_cloned):
    res = []
    for i in range(len(x)):
        res.append(x_cloned[i] * x_cloned[i])
    print(res)
    return Variable(torch.FloatTensor(res))


def get_grad(inp, grad_var):
    A = basic_fun(inp)
    A.backward()
    return grad_var.grad


x = Variable(torch.FloatTensor([1, 2, 3, 4, 5]), requires_grad=True)
x_cloned = x.clone()
print(get_grad(x_cloned, x))

我收到以下错误消息:

[tensor(1., grad_fn=<ThMulBackward>), tensor(4., grad_fn=<ThMulBackward>), tensor(9., grad_fn=<ThMulBackward>), tensor(16., grad_fn=<ThMulBackward>), tensor(25., grad_fn=<ThMulBackward>)]
Traceback (most recent call last):
  File "/home/mhy/projects/pytorch-optim/predict.py", line 74, in <module>
    print(get_grad(x_cloned, x))
  File "/home/mhy/projects/pytorch-optim/predict.py", line 68, in get_grad
    A.backward()
  File "/home/mhy/.local/lib/python3.5/site-packages/torch/tensor.py", line 93, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph)
  File "/home/mhy/.local/lib/python3.5/site-packages/torch/autograd/__init__.py", line 90, in backward
    allow_unreachable=True)  # allow_unreachable flag
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn

总的来说,我对如何使用变量的克隆版本应该如何在梯度计算中保留该变量持怀疑态度。变量本身实际上并未用于计算A,因此当您调用A.backward() 时,它不应该是该操作的一部分。

感谢您对这种方法的帮助,或者如果有更好的方法可以避免丢失梯度历史并且仍然使用requires_grad=True 对一维张量进行索引!

**编辑(9 月 15 日):**

res 是一个包含 1 到 5 平方值的零维张量列表。为了连接一个包含 [1.0, 4.0, ..., 25.0] 的张量,我将 return Variable(torch.FloatTensor(res)) 更改为 torch.stack(res, dim=0) ,产生tensor([ 1., 4., 9., 16., 25.], grad_fn=&lt;StackBackward&gt;)

但是,我收到了这个由 A.backward() 行引起的新错误。

Traceback (most recent call last):
  File "<project_path>/playground.py", line 22, in <module>
    print(get_grad(x_cloned, x))
  File "<project_path>/playground.py", line 16, in get_grad
    A.backward()
  File "/home/mhy/.local/lib/python3.5/site-packages/torch/tensor.py", line 93, in backward
    torch.autograd.backward(self, gradient, retain_graph, create_graph)
  File "/home/mhy/.local/lib/python3.5/site-packages/torch/autograd/__init__.py", line 84, in backward
    grad_tensors = _make_grads(tensors, grad_tensors)
  File "/home/mhy/.local/lib/python3.5/site-packages/torch/autograd/__init__.py", line 28, in _make_grads
    raise RuntimeError("grad can be implicitly created only for scalar outputs")
RuntimeError: grad can be implicitly created only for scalar outputs

【问题讨论】:

您的PyTorch 版本是什么。我在0.3.1 版本中执行了您的代码,并且您的代码正常工作。没有错误。 我在 Python 3.5 中使用的是 0.4.1 版本。请看看我的新更新。 【参考方案1】:

我将basic_fun 更改为以下内容,这解决了我的问题:

def basic_fun(x_cloned):
    res = torch.FloatTensor([0])
    for i in range(len(x)):
        res += x_cloned[i] * x_cloned[i]
    return res

这个版本返回一个标量值。

【讨论】:

【参考方案2】:

在 basic_fun 函数中, res 变量已经是一个 torch-autograd-Variable 你不需要再次转换它。恕我直言

def basic_fun(x_cloned):
    res = []
    for i in range(len(x)):
        res.append(x_cloned[i] * x_cloned[i])
    print(res)
    #return Variable(torch.FloatTensor(res))
    return res[0]

def get_grad(inp, grad_var):
    A = basic_fun(inp)
    A.backward()
    return grad_var.grad


x = Variable(torch.FloatTensor([1, 2, 3, 4, 5]), requires_grad=True)
x_cloned = x.clone()
print(get_grad(x_cloned, x))

【讨论】:

感谢您的关注!我试图从张量列表中创建一个张量。我通过将return Variable(torch.FloatTensor(res)) 更改为torch.stack(res, dim=0) 解决了这个问题。

以上是关于PyTorch autograd -- 只能为标量输出隐式创建 grad的主要内容,如果未能解决你的问题,请参考以下文章

PyTorch - autograd自动微分

PyTorch 之 简介相关软件框架基本使用方法tensor 的几种形状和 autograd 机制

自动求梯度(pytorch版本)——2.20

pytorch 与 autograd.numpy

『PyTorch』第五弹_深入理解autograd_上:Variable

pytorch 笔记: 扩展torch.autograd