【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除
标题
237、【AI】【模型部署】基座模型研究:反向传播
背景
上篇 blog 【AI】【模型部署】基座模型研究:硬标签与软标签 把训练目标讲清了:真实标签默认是硬标签(one-hot),但模型输出
Q
Q
Q 一直是软的;为了缓解过度自信、给其他 token 一点机会,可以用标签平滑或知识蒸馏把目标换成软标签,推理时还能靠温度与 top-k/top-p 采样调节多样性。无论目标用硬标签还是软标签,最后都要算一个损失(交叉熵),再面对同一个问题:知道"错了多少"之后,怎么知道每个参数该改多少? 这正是本篇要讲的反向传播。
模型部署
训练循环里,loss.backward() 只占一行,但它承担了整个训练的"归因"工作:把最后的误差,按贡献大小分摊到成千上万个参数上。这篇把 backward() 拆开,从链式法则讲到代码。
🧩 从链式法则说起
反向传播的数学内核是链式法则(chain rule):复合函数求导,外层导数乘以内层导数。一个最简单的两层函数:
y
=
w
x
+
b
,
L
=
(
y
−
t
)
2
y = wx + b,\\qquad L = (y-t)^2
y=wx+b,L=(y−t)2
想求损失对参数
w
w
w 的导数,就一层层往回乘:
∂
L
∂
w
=
∂
L
∂
y
⋅
∂
y
∂
w
=
2
(
y
−
t
)
⋅
x
\\frac{\\partial L}{\\partial w} = \\frac{\\partial L}{\\partial y}\\cdot\\frac{\\partial y}{\\partial w} = 2(y-t)\\cdot x
∂w∂L=∂y∂L⋅∂w∂y=2(y−t)⋅x

图 2 展示了这条链:先算
L
L
L 对
y
y
y 的敏感度
2
(
y
−
t
)
2(y-t)
2(y−t),再乘
y
y
y 对
w
w
w 的敏感度
x
x
x。"敏感度"就是导数的物理含义——
w
w
w 动一点点,损失会跟着动多少。
🧩 计算图:前向算数值,反向算梯度
把上面的
x
→
y
→
L
x \\to y \\to L
x→y→L 每一步都看成一个节点,就得到一张计算图(computational graph):
- 前向:从输入往输出,边走边算数值,并把每一步的中间结果记下来;
- 反向:从损失节点出发往回走,每个节点用"上游传来的梯度 × 本节点局部导数"算出对流经变量的梯度。

因为反向走的是同一条图的逆序,所以整体代价只比前向多一个常数倍(约 2~3 倍),这就是 反向模式自动微分(reverse-mode automatic differentiation),也是各框架 autograd 的实现方式。
🧩 梯度就是"敏感度"
一个参数的梯度
∂
L
/
∂
w
\\partial L/\\partial w
∂L/∂w,回答的就是"把
w
w
w 调大一点,损失会变大还是变小、变多少"。它的符号给出方向,绝对值给出幅度。整张网络里成千上万个参数,反向传播会一次性把每个参数的梯度都算出来——这正是它不可替代的地方:参数量太大,逐个数值求导根本不可行,而反向传播让"求全部梯度"和前向同阶。
🧩 为什么不用数值求导
最朴素的想法是"扰动一个参数、看损失变化多少",也就是数值微分。它有两个致命问题:
N
N
N 个参数就要
N
N
N 次前向;千亿参数直接不可行;
反向传播只做"一次前向 + 一次反向",就把所有参数的梯度都算出来,代价与前向同阶——这才是它能训练大模型的根本原因。
🧩 softmax + 交叉熵的梯度为什么漂亮
上篇讲到 F.cross_entropy 内部是 softmax 加负对数。把这两步合起来对 logits 求导,会得到一个极其简洁的结果:
∂
L
∂
z
=
p
−
y
\\frac{\\partial L}{\\partial z} = p – y
∂z∂L=p−y
其中
p
p
p 是 softmax 后的预测概率,
y
y
y 是真实 one-hot 标签。预测到哪里、真实在哪里,差多少,梯度就是多少。

图 3 用一个 5 词表的例子展示:正确项
p
−
y
p-y
p−y 为负(梯度把它的概率往上推),其余项为正(把它们的概率往下压)。这也解释了为什么交叉熵"好训练"——梯度天然带方向,不需要额外的缩放。
🧩 最小例子:手推一次更新
用最前面那个
y
=
w
x
+
b
,
L
=
(
y
−
t
)
2
y=wx+b,\\ L=(y-t)^2
y=wx+b, L=(y−t)2 的例子,设
x
=
1
,
b
=
0
,
t
=
1
x=1,\\ b=0,\\ t=1
x=1, b=0, t=1,当前
w
=
0.5
w=0.5
w=0.5:
| 前向 |
y = w x + b y = wx+b y=wx+b |
0.5 0.5 0.5 |
| 损失 |
L = ( y − t ) 2 L=(y-t)^2 L=(y−t)2 |
0.25 0.25 0.25 |
| 梯度 |
2 ( y − t ) ⋅ x 2(y-t)\\cdot x 2(y−t)⋅x |
− 1.0 -1.0 −1.0 |
| 更新 |
w ← w − η ⋅ ( − 1.0 ) w \\leftarrow w-\\eta\\cdot(-1.0) w←w−η⋅(−1.0) |
0.5 + η 0.5+\\eta 0.5+η |
若学习率
η
=
0.1
\\eta=0.1
η=0.1,
w
w
w 从
0.5
0.5
0.5 变成
0.6
0.6
0.6,
y
y
y 更接近目标
1
1
1,损失随之下降。真实网络只是把这一步在每层、每个参数上重复,并用计算图自动完成。

图 5 是这一步的几何直觉:沿着负梯度方向,把参数往损失更低的地方挪一点点。
🧩 梯度怎么穿过整张 Transformer
在真实模型里,反向传播要依次穿过输出层 → 每一层的均方根归一化(Root Mean Square Normalization,RMSNorm)→ 前馈网络(Feed-Forward Network,FFN)→ 注意力 → 词嵌入。以第 231 篇同款的微型模型为例,结构是"词嵌入 + 若干 Block + 归一化 + 输出头":
x = self.tok_emb(idx) # 词嵌入
for blk in self.blocks: # 每个 Block: RMSNorm + 注意力 + RMSNorm + FFN
x = blk(x, cos, sin)
return self.lm_head(self.norm(x)) # 输出头 → logits
前向是"从上到下"走一遍,反向就是从 lm_head 的梯度开始,一层层往回乘,直到词嵌入。注意力里的 matmul、softmax、RMSNorm、SiLU 激活,每个算子都有对应的局部导数——框架在 backward() 时自动调用它们。
📊 三个接口:zero_grad / backward / step
上篇代码里的 opt.zero_grad(); loss.backward(); opt.step(),三者分工明确:
| opt.zero_grad() | 把上一轮梯度清零 | 梯度累加,更新错乱 |
| loss.backward() | 反向传播,填好每个参数的 .grad | 没有梯度,无法学习 |
| opt.step() | 用 .grad 更新参数 | 光算不改,loss 不动 |
opt 是优化器。最朴素的更新是随机梯度下降(Stochastic Gradient Descent,SGD):
w
←
w
−
η
∂
L
/
∂
w
w \\leftarrow w – \\eta\\,\\partial L/\\partial w
w←w−η∂L/∂w。实践中常用 AdamW(自适应学习率 + 权重衰减),它对不同参数自动调整步长,收敛更稳——微型模型用的就是 torch.optim.AdamW。
📊 为什么还要梯度裁剪与 warmup
反向传播把很多层的导数连乘,层数一深就容易出事:若每层导数约
0.5
0.5
0.5,连乘十层就是
0.5
10
≈
0.001
0.5^{10}\\approx0.001
0.510≈0.001(梯度消失);若每层约
2
2
2,连乘十层就是
2
10
=
1024
2^{10}=1024
210=1024(梯度爆炸)。真实预训练因此加两道保险(上篇提过):
- 梯度裁剪(gradient clipping):给梯度的范数设上限,防止一步跨太大把权重打飞;
- 学习率 warmup 后衰减:先小步热身再逐渐放大,避免一开始就震荡。
这些在微型实验里被省掉了,但放大到千亿参数时是必需品。
🧩 把它接回预训练循环
现在再看整条链路就完整了:前向得到 logits,交叉熵算出"错了多少",反向传播把误差分摊成每个参数的梯度,优化器按梯度更新权重,然后重复。上篇的 loss 从 7.3883 一路降到 0.7821,就是这一套循环把语言统计规律一点点压进权重的过程。

图 4 是这条循环的总览:前向 → 损失 → 反向 → 更新,重复万亿次。
📌 一句话记忆
反向传播是链式法则在计算图上的反向应用:前向算数值,反向用"上游梯度 × 本层局部导数"逐层求出每个参数的梯度;softmax 与交叉熵组合后,对 logits 的梯度恰好是
p
−
y
p-y
p−y;backward() 填好 .grad,优化器(SGD 或 AdamW)按梯度把参数往低处挪一点;深层网络还要靠梯度裁剪与 warmup 保持稳定。
OK,本篇先到这里,如有疑问,欢迎评论区留言讨论,祝各位功力大涨,技术更上一层楼!!!更多内容见下篇 blog
网硕互联帮助中心

评论前必须登录!
注册