0%

PyTorch微分

PyTorch微分与梯度:从原理到实战

在深度学习的宏大叙事中,PyTorch 的 torch.autograd 模块无疑是那个最沉默却最强大的幕后推手。它实现了自动微分机制,让复杂的神经网络训练变得像搭积木一样简单。很多开发者习惯于调用 .backward(),却未必真正理解其背后的数学原理与工程细节。

今天,我们就剥开 PyTorch 的“黑盒”,深入探讨它是如何通过计算图追踪梯度,以及反向传播与梯度下降是如何协同工作,让模型从“无知”变得“睿智”。

计算图与自动微分:PyTorch 的“记忆”

PyTorch 的微分机制基于动态计算图。当你使用 Tensor 进行运算时,PyTorch 不仅在计算数值,还在后台构建一个有向无环图,记录数据是如何流动的。

要让一个张量进入这个“追踪系统”,只需设置 requires_grad=True。一旦开启,PyTorch 就会记录所有作用在该张量上的操作。

1
2
3
4
5
6
7
8
9
10
11
import torch

# 定义一个需要追踪梯度的张量
x = torch.tensor(2.0, requires_grad=True)

# 进行一系列运算:y = x^2 + 3x + 1
y = x**2 + 3*x + 1

# 此时,y 拥有一个 grad_fn 属性,指向创建它的函数
# grad_fn 属性:它指向创建该张量的函数对象。这个对象记录了前向传播的操作细节,以便在反向传播时能够利用链式法则计算梯度
print(f"计算图节点: {y.grad_fn}")

在这个例子中,y 不仅仅是一个数值 11,它还持有着一条“线索”,指向它是如何通过 x 计算得来的。这就是反向传播的基础。

反向传播:链式法则的自动化

当我们得到最终的输出(通常是损失值 Loss)后,调用 .backward() 方法,PyTorch 就会启动自动微分引擎。它利用链式法则,从输出端向输入端反向遍历计算图,计算梯度。

对于标量(如 Loss),PyTorch 可以直接计算梯度;对于非标量,通常需要传入梯度参数。但在训练场景下,我们主要关注标量 Loss 对参数的梯度。

1
2
3
4
5
6
# 执行反向传播
y.backward()
# grad_fn 是“过程”,它记录了张量是如何被计算出来的,是反向传播的路线图。
# grad 是“结果”,它存储了反向传播计算完成后,最终的梯度值
# 查看 x 的梯度 dy/dx = 2x + 3,当 x=2 时,结果应为 7
print(f"x 的梯度: {x.grad}") # 输出: tensor(7.)

何为梯度?

grad 就是导数,更准确地说,它是梯度

在数学上,梯度本质上就是偏导数组成的向量。你可以把 grad 理解为 PyTorch 帮你算出来的“导数结果”。

我们可以从以下三个层面来看:

数学层面:导数 vs 梯度
  • 一元函数(只有一个变量 $x$):
    比如 $y = x^2$。
    这时候,梯度 = 导数
    导数是 $2x$。如果你的 $x=3$,那么导数就是 6。PyTorch 算出来的 x.grad 就是 tensor(6.)

  • 多元函数(有多个变量 $x_1, x_2, …$):
    比如 $z = x^2 + y^2$。
    这时候,我们要分别求 $z$ 对 $x$ 的导数(偏导数)和 $z$ 对 $y$ 的导数(偏导数)。
    把这两个导数拼在一起,就变成了一个向量:$(\frac{\partial z}{\partial x}, \frac{\partial z}{\partial y})$。
    这个向量就叫梯度

结论: 在深度学习中,我们的损失函数通常有成千上万个参数(权重和偏置),所以求出来的“导数”是一个巨大的向量,我们习惯称之为梯度

代码层面:grad 存的是什么?

在 PyTorch 中,x.grad 是一个张量,它的形状和 $x$ 完全一样,里面存的每一个数字,都是损失函数对 $x$ 中对应元素的导数

看这个简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import torch

# 1. 定义 x,开启梯度追踪
x = torch.tensor(3.0, requires_grad=True)

# 2. 定义公式 y = x^2
y = x ** 2

# 3. 反向传播(求导)
y.backward()

# 4. 查看结果
print(x.grad)
# 输出: tensor(6.)

为什么是 6?
因为 $y = x^2$ 的导数公式是 $2x$。
当 $x = 3$ 时,导数 $2 \times 3 = 6$。
PyTorch 把计算结果 6 存进了 x.grad 里。

直观理解:它代表什么?

grad(导数/梯度)代表的是“变化率”和“方向”。

  • 数值大小:代表变化的快慢。
  • 正负号:代表变化的方向。
    • 如果 grad正数:说明 $x$ 增加,结果 $y$ 也会增加(上坡)。
    • 如果 grad负数:说明 $x$ 增加,结果 $y$ 反而会减小(下坡)。

在训练神经网络时,我们就是利用这个 grad

  • 如果 grad 是正的,我们就把权重减小一点(为了让 Loss 变小)。
  • 如果 grad 是负的,我们就把权重增大一点。

所以当你看到 x.grad 时,你可以直接把它读作:“损失函数相对于 x 的导数”

梯度下降:从理论到参数更新

计算出梯度只是第一步,梯度的物理意义是“函数增长最快的方向”。为了让模型拟合数据(即最小化损失函数),我们需要沿着梯度的反方向更新参数。这就是梯度下降。

结语

PyTorch 的微分机制将复杂的数学推导封装在了简洁的 API 之下。从 requires_grad 开启追踪,到 .backward() 自动计算梯度,再到优化器执行梯度下降,这一整套流程构成了深度学习训练的基石。

欢迎关注我的其它发布渠道