云计算百科
云计算领域专业知识百科平台

237、【AI】【模型部署】基座模型研究:反向传播

【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如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

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 237、【AI】【模型部署】基座模型研究:反向传播
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!