通过小例子理解Pytorch自动求导原理
编辑日期: 2024-07-16 文章阅读: 次
梯度结果
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
y = x + 2
z = y.mean()
z.backward()
print(x.grad) # 输出: tensor([0.3333, 0.3333, 0.3333])
例子解释梯度求导
让我们详细解释一下这个 PyTorch 代码示例中的每一步操作。
1. 创建张量 x
x = torch.tensor([1.0, 2.0, 3.0], requires_grad=True)
x
,值为 [1.0, 2.0, 3.0]
。requires_grad=True
表示我们希望对这个张量进行自动求导,也就是说,我们希望能够计算关于这个张量的梯度。
2. 执行张量运算
y = x + 2
x
进行加法运算,结果是一个新的张量 y
,其值为 [3.0, 4.0, 5.0]
。这个运算会记录在计算图中,以便后续进行反向传播时使用。
3. 计算张量 z
z = y.mean()
y
的均值。mean()
函数会将张量 y
中的所有元素求和,然后除以元素的个数,得到一个标量值。对于这个例子,y
的均值是 (3.0 + 4.0 + 5.0) / 3 = 4.0
,所以 z
是一个值为 4.0
的标量张量。
4. 进行反向传播
z.backward()
backward()
方法开始反向传播计算梯度。由于 z
是通过多个张量运算得到的,因此这个过程会计算 z
对 x
的梯度。
5. 打印梯度
print(x.grad) # 输出: tensor([0.3333, 0.3333, 0.3333])
x.grad
中保存了 z
对 x
的梯度。我们来详细计算这个梯度。
梯度计算过程
我们需要计算 z
对 x
的梯度,即 ∂z/∂x
。回顾一下每一步运算:
y = x + 2
z = y.mean()
首先,我们计算 z
对 y
的梯度。
因为 z = mean(y)
,均值的梯度是每个元素的梯度都是 1/3
(因为 y
中有 3 个元素),所以有:
\[ \frac{\partial z}{\partial y_i} = \frac{1}{3} \]
接下来,根据链式法则,z
对 x
的梯度是 z
对 y
的梯度乘以 y
对 x
的梯度。因为 y = x + 2
,所以:
\[ \frac{\partial y_i}{\partial x_i} = 1 \]
所以最终的梯度是: $$ \frac{\partial z}{\partial x_i} = \frac{\partial z}{\partial y_i} \cdot \frac{\partial y_i}{\partial x_i} = \frac{1}{3} \cdot 1 = \frac{1}{3} \approx 0.3333 $$
因为 x
中每个元素对 z
的贡献是相同的,所以 x.grad
中每个元素的梯度都是 0.3333
。因此,输出 x.grad
是 tensor([0.3333, 0.3333, 0.3333])
。
这个示例展示了 PyTorch 中自动求导的基本原理,通过记录操作构建计算图,然后使用反向传播计算梯度。