PyTorch-按顺序在两个不同的函数上调用 backward() 会第二次给出意外输出

PyTorch- call to backward() on two different functions in sequence gives unexpected output second time

我试图区分基于相同输入 x[=29] 的两个函数 zy =].在这样做的同时,我 运行 y.backward()z.backward()。根据我的理解,我在对输入进行任何操作之前创建了两个函数,因此 yz 应该是独立的并给出独立的结果分化。 但是,第二次调用 backward() 的输出给出了错误的输出。它可以被称为 y.backward() 然后 z.backward()。在这种情况下,z.backward() 给出 14 而不是 12 作为输出。如果我 运行 z.backward() 然后 y.backward()y.backward() 给出 14 作为输出。在这两种情况下,只有第一个输出是正确的。我不明白第二次给14是怎么回事。

import torch
x = torch.tensor(2.0, requires_grad=True)
y = 2 * x + 3
z = x**3 + 1

y.backward()
print('grad attribute of the tensor::',x.grad)

z.backward()
print('grad attribute of the tensor::',x.grad)

输出:

grad attribute of the tensor:: tensor(2.)
grad attribute of the tensor:: tensor(14.)

backward()不覆盖tensor grad属性;它 积累 它们。如果您不将反向传播之间的梯度归零,则生成的梯度将是每个反向传播的梯度之和。之所以这样实现,是为了更好地支持循环神经网络。

将梯度归零的最传统方法是调用torch.optim.Optimizer.zero_grad();这将使在构造时传递给优化器的所有参数的梯度归零。当您只是将渐变用于优化器步骤时,这很有效。还有 torch.nn.Module.zero_grad(),它将模块的参数归零(我相信它是递归的,所以它也应该将 sub-modules' 参数归零,等等)。

还要注意,如果需要复用中间结果(non-leaf张量的梯度),那么在调用backward()时需要传递retain_graph=True;在使用递归神经网络时通常就是这种情况。否则,PyTorch 将释放它们以节省内存。