Backward()函数
Backward函数实际上是通过传递参数(默认情况下是1x1单位张量)来计算梯度的,它通过Backward图一直到每个叶节点,每个叶节点都可以从调用的根张量追溯到叶节点。然后将计算出的梯度存储在每个叶节点的.grad
中。请记住,在正向传递过程中已经动态生成了后向图。backward函数仅使用已生成的图形计算梯度,并将其存储在叶节点中。
让我们分析以下代码:
import torch
# Creating the graph
x = torch.tensor(1.0, requires_grad = True)
z = x ** 3
z.backward() #Computes the gradient
print(x.grad.data) #Prints '3' which is dz/dx
需要注意的一件重要事情是,当调用z.backward()
时,一个张量会自动传递为z.backward(torch.tensor(1.0))
。torch.tensor(1.0)
是用来终止链式法则梯度乘法的外部梯度。这个外部梯度作为输入传递给MulBackward
函数,以进一步计算x的梯度。传递到.backward()
中的张量的维数必须与正在计算梯度的张量的维数相同。例如,如果梯度支持张量x和y如下:
x = torch.tensor([0.0, 2.0, 8.0], requires_grad = True)
y = torch.tensor([5.0 , 1.0 , 7.0], requires_grad = True)
z = x * y
然后,要计算z
关于x
或者y
的梯度,需要将一个外部梯度传递给z.backward()
函数,如下所示:
z.backward(torch.FloatTensor([1.0, 1.0, 1.0])
z.backward()
会给出 RuntimeError: grad can be implicitly created only for scalar outputs
反向函数传递的张量就像梯度加权输出的权值。从数学上讲,这是一个向量乘以非标量张量的雅可比矩阵(本文将进一步讨论),因此它几乎总是一个维度的单位张量,与 backward
张量相同,除非需要计算加权输出。
tldr :向后图是由autograd类在向前传递过程中自动动态创建的。
Backward()
只是通过将其参数传递给已经生成的反向图来计算梯度。
更多请看:https://mlog.club/article/25034
数学—雅克比矩阵和向量
从数学上讲,autograd类只是一个雅可比向量积计算引擎。雅可比矩阵是一个非常简单的单词,它表示两个向量所有可能的偏导数。它是一个向量相对于另一个向量的梯度。
注意:在这个过程中,PyTorch从不显式地构造整个雅可比矩阵。直接计算JVP (Jacobian vector product)通常更简单、更有效。
如果一个向量X = [x1, x2,…xn]通过f(X) = [f1, f2,…fn]来计算其他向量,则雅可比矩阵(J)包含以下所有偏导组合:
雅克比矩阵
上面的矩阵表示f(X)相对于X的梯度。
假设一个启用PyTorch梯度的张量X:
X = [x1,x2,…,xn](假设这是某个机器学习模型的权值)
X经过一些运算形成一个向量Y
Y = f(X) = [y1, y2,…,ym]
然后使用Y计算标量损失l。假设向量v恰好是标量损失l关于向量Y的梯度,如下:
向量v称为grad_tensor
,并作为参数传递给backward()
函数。
为了得到损失的梯度l关于权重X的梯度,雅可比矩阵J是向量乘以向量v
这种计算雅可比矩阵并将其与向量v相乘的方法使PyTorch能够轻松地为非标量输出提供外部梯度。