一、例子
import torchx = torch.arange(4.0)
x.requires_grad_(True)
y = 2 * torch.dot(x, x)
print(y)
y.backward()
x.grad == 4 * x
print(x.grad)
二、解读
1. import torch
这一行导入了PyTorch库。PyTorch是一个开源的机器学习库,广泛用于计算机视觉和自然语言处理等领域。
2. x = torch.arange(4.0)
这一行创建了一个一维张量 x,它包含了4个元素:[0., 1., 2., 3.]。张量是一个类似于数组的数据结构,可以在GPU上进行高效的数学操作。
3. x.requires_grad_(True)
这一行的作用是设置 x 张量的 requires_grad 标志为 True。这意味着PyTorch将会跟踪在 x 上执行的所有操作以便于后续进行自动求导(计算梯度)。`_ 在方法名后表明该操作是就地(in-place)进行,即会改变 x` 而不是创建一个新的副本。
4. y = 2 * torch.dot(x, x)
这一行定义了一个标量(单个数值) y。通过计算 x 与其自身的点积(`torch.dot(x, x)` 得到 x 中所有元素的平方和),再乘以 2,即 y = 2*(x[0]^2 + x[1]^2 + x[2]^2 + x[3]^2)。
5. y.backward()
这一行执行反向传播,自动计算 y 关于 x 的梯度,并将计算结果存储在 x.grad 属性中。因为 y 是关于 x 的一个标量函数,所以 x.grad 的形状将与 x 相同。
在反向传播过程中,当计算一个标量(即单个数值)函数关于一个向量的梯度时,得到的梯度(或称导数)将是一个与原向量形状相同的向量。这是因为梯度是对向量中每个独立变量的偏导数的集合。
让我们来回顾一下基本的微积分定义:
- 对于一个标量函数 f(x) 相对于一个单变量 x 的导数,表示的是 f 在 x 点的斜率,或者说是在 x 点处 f 随 x 的变化率。这里的导数是个单一的数值。
- 对于一个标量函数 f(x, y, z, ...) 相对于多变量(x, y, z, ...)的梯度,表示的是 f 在每个方向上的偏导数组成的向量。在这种情况下,梯度是一个向量,每个分量对应于函数对某个单一变量的偏导数。
在例子中,y 是关于向量 x 的一个标量函数。函数 y = 2 * torch.dot(x, x) 可看作是 y = 2 * (x[0]^2 + x[1]^2 + x[2]^2 + x[3]^2)。当对 y 进行反向传播时,PyTorch 会对向量 x 中的每个分量计算偏导数,并把这些偏导数放在一个新的向量中。这个新向量,也就是梯度,会与原向量 x 有着相同的形状和大小。
这就是为什么 x.grad 的形状将与 x 相同的原因。在这个例子中, x 是一个有4个元素的向量(一维张量),因此它的梯度 x.grad 也会是一个包含4个偏导数值的向量(一维张量),即每个元素对应输入向量 x 的每个分量的梯度。
6. x.grad == 4 * x
这是一个比较操作,判断 x.grad(`x` 的梯度)是否等同于 4 乘以 x。由于对 y = 2*(x[0]^2 + x[1]^2 + x[2]^2 + x[3]^2) 求导可得梯度 dy/dx = 4*x,这个比较应该是 True。
7. print(x.grad)
这一行打印出 x 的梯度。如果之前的比较 x.grad == 4 * x 为真,打印的结果应该是 [0., 4., 8., 12.]。
这段代码演示了利用PyTorch计算梯度的一个简单例子。通过设置 requires_grad 来跟踪运算,然后通过 backward() 方法来自动计算导数。