直觉理解

神经网络是一个由许多简单运算堆叠起来的函数:每一层先做一次线性变换(矩阵乘法加偏置),再过一个非线性的激活函数。层数一多,这个函数就能拟合非常复杂的输入输出关系。

训练就是调整网络里的参数,让损失函数变小。要知道每个参数该往哪个方向调,需要损失对每个参数的偏导数,也就是梯度。反向传播是高效计算这些梯度的算法:先从输入算到输出(前向传播),再从损失出发,按链式法则把梯度一层层往回传(反向传播)。算出梯度后,交给梯度下降去更新参数。

定义与公式

前向传播

以两层的多层感知机(MLP)为例,输入 ,第 层的计算是

其中 , 是激活函数。最后一层的输出 与标签 一起算出损失 。

如果去掉激活函数,多层线性变换相乘后仍然是一个线性变换,网络再深也只能表示线性函数。非线性激活是神经网络表达能力的来源。

反向传播

反向传播的核心是微积分里的链式法则。记 ,则

表示逐元素相乘。从最后一层的 开始,逐层往前递推,就得到了所有参数的梯度。前向传播时保存下来的中间结果 、 在这里被重复利用,所以计算梯度的代价与一次前向传播同一个量级,而不是逐个参数求导。

计算图与自动求导

现代框架把整个计算记录成一张计算图:节点是张量,边是运算。每个基本运算都知道自己的局部导数,框架沿着图反向遍历、套用链式法则,就能自动算出任意参数的梯度。这就是 PyTorch 的自动求导(autograd),详见PyTorch张量与自动求导。

梯度消失与梯度爆炸

反向传播时,梯度要连乘经过每一层的权重和激活函数的导数。层数很深时:

  • 如果这些因子普遍小于 1,梯度会指数级衰减,靠前的层几乎学不到东西,这叫梯度消失。sigmoid、tanh 在饱和区导数接近 0,是早期深层网络难训练的主要原因。
  • 如果普遍大于 1,梯度会指数级增长,这叫梯度爆炸,训练会发散。

常用的缓解手段有:用 ReLU 一类不易饱和的激活函数、合理的参数初始化、归一化、残差连接(让梯度可以跳过若干层直接回传),以及梯度裁剪。

代码示例

用 PyTorch 搭一个两层网络,调用 backward() 自动求梯度,再与手算结果对照:

import torch
 
torch.manual_seed(0)
x = torch.randn(4, 3)                     # 4 个样本,每个 3 维
y = torch.randn(4, 1)
W1 = torch.randn(3, 5, requires_grad=True)
W2 = torch.randn(5, 1, requires_grad=True)
 
h = torch.relu(x @ W1)                    # 隐藏层
y_hat = h @ W2                            # 输出层
loss = (y_hat - y).pow(2).mean()          # 均方误差
loss.backward()                           # 反向传播
 
# 手算 W2 的梯度:dL/dW2 = h^T · dL/dy_hat
grad_y_hat = 2 * (y_hat - y) / y.numel()
print(torch.allclose(W2.grad, h.T @ grad_y_hat))   # True

代码里样本按行排列,所以写成 ,与公式里的 互为转置,本质相同。

在 AI 中的作用

几乎所有深度学习模型都由「线性变换 + 非线性」这种基本单元组成,都用反向传播加梯度下降来训练。Transformer 里的前馈层就是一个两层 MLP;大语言模型的训练,本质上也是在一个上千亿参数的计算图上反复做前向传播和反向传播。反向传播算法在 1986 年由 Rumelhart、Hinton 和 Williams 的论文推广开来,是深度学习的基石。

相关