🏠 总目录📚 本教程 知识蒸馏
📑 本页目录(点开跳转)

18b · 知识蒸馏

68 分钟 | ⭐ 压缩三件套里唯一能让模型"变得更适合你"的那件


🎯 一句话

量化改数值精度、剪枝去掉连接、蒸馏换一个更小的模型 —— 三者正交,可以叠加。 但蒸馏和另外两件有个本质区别:量化和剪枝只能让模型变小,蒸馏能让它变得更适合你的任务。 代价是它很容易"整体只掉 1 个点、某个人群掉 15 个点", 而且算力成本比从零训同尺寸模型还贵约 2.8 倍。 所以这一章的重点不是怎么做,而是 —— 你怎么知道自己伤到了谁、这笔账划不划算。


🧩 一、先把压缩三件套摆清楚

第 18 章讲完量化之后,很多人以为压缩就是量化。其实压缩有三条完全不同的路,它们动的是模型的三个不同维度

   同一个 Linear 层:W 的形状 [4096, 4096],FP16

   ① 量化:形状不变,每个数从 16 bit 变 4 bit
      [4096, 4096] FP16  →  [4096, 4096] INT4       ⭐ 改的是【数值精度】

   ② 剪枝:数值精度不变,把一部分位置变成 0(或者直接删掉行列)
      [4096, 4096] FP16  →  [4096, 4096] 里 90% 是 0   (非结构化)
                         →  [4096, 2048] FP16          (结构化)⭐ 改的是【连接/尺寸】

   ③ 蒸馏:这一层本身没变,是【整个模型换成另一个更小的模型】
      32 层 × 4096  →  16 层 × 2048,权重全部重新学
                                                     ⭐ 改的是【模型本身】

因为动的维度不同,三者是正交的,可以叠加:一个典型的极限压缩流水线是「结构化剪枝 → 蒸馏恢复 → INT4 量化」,三步各自独立生效。

对照表:先看清代价再选

量化 非结构化剪枝 结构化剪枝 蒸馏
典型压缩比 2~4 倍(INT8/INT4) 稀疏度 50~90% 1.5~3 倍 3~10 倍
典型掉点 极小(W4A16 常 <1%) 小(同压缩比下最优) 较大 ⚠️ 看任务,窄任务可近乎无损
要不要重训 不用(PTQ 只要校准集) 要微调恢复 必须重训/蒸馏恢复 要完整训练
要不要原始数据 只要几百条校准样本 要一部分训练数据 要相当量的数据 要大量数据(或 teacher 现生成)
省显存 ✅ 确定省 ⚠️ 默认一点不省 ✅ 确定省 ✅ 确定省
加速 ✅ 确定加速 ⭐ 💀 通用硬件上通常不加速 ✅ 确定加速 ✅ 确定加速
落地成本 小时级 天级 周级 周~月级,最贵

先记住这张表里最反直觉的两格非结构化剪枝默认既不省显存、也不加速(第五节讲透为什么); 蒸馏是三者里最贵的,贵在你还得跑 teacher(第七节算这笔账)。 换句话说:量化是"先做的",另外两个是"确实需要才做的"。


🌡️ 二、蒸馏的机制:软标签里的"暗知识"

硬标签扔掉了什么

假设一个 5 类分类任务,一张图是「猫」。

   硬标签(真实 one-hot):
   猫=1  老虎=0  狗=0  汽车=0  卡车=0
        ↑ 老虎和汽车在标签里【一样错】

   teacher 的软标签(softmax 输出):
   猫=0.87  老虎=0.12  狗=0.008  汽车=0.001  卡车=0.001
        ⭐ 老虎的概率是汽车的【120 倍】
        → teacher 在告诉学生:「猫更像老虎,一点都不像汽车」

这个「类与类之间有多像」的信息,在硬标签里完全不存在。Hinton 把它叫做暗知识(dark knowledge) —— 它藏在那些"错误答案"的相对大小里。

   ⭐ 信息量的角度:
   · 硬标签:一个样本只给 log2(5) ≈ 2.3 bit 的监督
   · 软标签:一个样本给的是整个 5 维分布 —— 连续值,信息多得多

   → 这就是为什么【同样的数据量下】,蒸馏出来的小模型
     常常比拿硬标签从零训练的同尺寸模型强

对 LLM 更夸张:词表 12.8 万,硬标签只有 17 bit,而 teacher 每个位置给的是一个 12.8 万维的分布。同样的 token 预算,监督信号密度差了好几个数量级 —— 这就是现在各家小尺寸模型普遍用蒸馏而不是从零预训练的根本原因。

温度 T:把暗知识"放大"出来

问题是:teacher 训得越好,softmax 越尖锐(猫=0.999),暗知识就被压扁得看不见了。温度就是用来把分布摊平的:

$$p_i = \frac{\exp(z_i / T)}{\sum_j \exp(z_j / T)}$$

   同一组 teacher logits [6.0, 4.0, 0.5, 0.2, -1.0],不同 T:

   T=1  → [0.875, 0.118, 0.004, 0.003, 0.001]   非目标类几乎全是 0,暗知识看不见
   T=2  → [0.659, 0.243, 0.042, 0.036, 0.020]
   T=4  → [0.441, 0.268, 0.112, 0.103, 0.077]   ⭐ 类间差异清楚了
   T=8  → [0.314, 0.245, 0.158, 0.152, 0.131]
   T→∞ → 均匀分布,什么信息都没有了 💀

🔑 T 的取值是一个权衡T 太小 → 软标签退化成硬标签,蒸馏白做; T 太大 → 所有类趋同,暗知识被"teacher 自己都不确定"的噪声淹没。 分类任务典型 T = 2~5LLM 蒸馏常直接用 T = 1 —— 因为词表巨大,teacher 的分布本来就足够"软",不需要额外摊平。

⭐ 那个必须记住的细节:T² 缩放

总损失通常长这样:

$$\mathcal{L} = \alpha \cdot T^2 \cdot \mathrm{KL}\big(p_T^{teacher} \,\|\, p_T^{student}\big) + (1-\alpha)\cdot \mathrm{CE}(z^{student}, y)$$

那个 $T^2$ 不是装饰,少了它你调 T 就等于同时在调学习率。

🔗 $\mathrm{KL}$ 在这里不是「一个可选的距离度量」,它就是这条式子的全部数学原理 01b · KL 散度。 ⭐ 去那里能捡到两件对蒸馏很实用的事: ① $\mathrm{KL}(p\|q) = \mathrm{H}(p,q) - \mathrm{H}(p)$ —— teacher 分布 $p$ 固定时 $\mathrm{H}(p)$ 是常数, 所以「最小化 KL」和「最小化交叉熵」对学生来说是同一个优化问题, 这就是为什么框架里 KLDivLoss 和「拿软标签当目标算 CE」两种写法都能用、结果一样。 ② KL 不对称:这里写的是 $\mathrm{KL}(\text{teacher}\,\|\,\text{student})$,teacher 在前,是前向 KL—— 它罚的是「teacher 有概率而 student 没有」,逼学生把 teacher 的每个峰都覆盖住。 ⚠️ 顺序写反成 $\mathrm{KL}(\text{student}\|\text{teacher})$ 语义完全变了:变成只挑一个峰钻进去, 学生会在长尾类上直接躺平——而长尾正是本章后面反复警告的那个「整体 −1pp、某个分组 −15pp」的重灾区。别把这两个符号写反。

📐 为什么恰好是 T²(想看再点)

KL 项对学生 logit $z_i$ 的梯度是

$$\frac{\partial}{\partial z_i}\mathrm{KL} = \frac{1}{T}\Big(\sigma(z/T)_i - \sigma(t/T)_i\Big)$$

前面那个 $\frac{1}{T}$ 来自链式法则(softmax 的输入被除了 T)。

当 T 较大时,对 $\sigma(z/T)_i$ 做一阶展开(设 logits 零均值、类数 C):

$$\sigma(z/T)_i \approx \frac{1}{C} + \frac{z_i}{C\,T}$$

代回去:

$$\frac{\partial}{\partial z_i}\mathrm{KL} \approx \frac{1}{T}\cdot\frac{z_i - t_i}{C\,T} = \frac{z_i - t_i}{C\,T^2}$$

梯度正比于 $1/T^2$。 所以乘上 $T^2$ 之后,软损失的梯度尺度不再随 T 变化 —— 这样 $\alpha$(软硬损失的配比)才有稳定含义,你调 T 的时候不会顺带把有效学习率改了 64 倍。

下面这段可以直接跑,它就是上面那段推导的数值验证

import torch
import torch.nn.functional as F

teacher  = torch.tensor([[6.0, 4.0, 0.5, 0.2, -1.0]])
student0 = torch.tensor([[7.233, 3.765, -1.243, 0.655, -1.868]])   # 训练中期:已接近 teacher

def soft_loss_and_grad(T, scale):
    s = student0.clone().requires_grad_(True)
    loss = F.kl_div(F.log_softmax(s / T, dim=-1),          # 学生用 log_softmax
                    F.softmax(teacher / T, dim=-1),        # teacher 用 softmax
                    reduction="batchmean")
    if scale:
        loss = loss * T * T                                # ⭐ T² 缩放就这一行
    loss.backward()
    return loss.item(), s.grad.norm().item()

print(f"{'T':<5}{'loss(raw)':>12}{'|grad|raw':>12}{'loss(xT2)':>12}{'|grad|xT2':>12}")
for T in [1.0, 2.0, 4.0, 8.0, 16.0]:
    l1, g1 = soft_loss_and_grad(T, scale=False)
    l2, g2 = soft_loss_and_grad(T, scale=True)
    print(f"{T:<5}{l1:>12.6f}{g1:>12.6f}{l2:>12.6f}{g2:>12.6f}")

实跑结果

   T        loss(raw)   |grad|raw    loss(xT2)   |grad|xT2
   1.0       0.086481    0.128587     0.086481    0.128587
   2.0       0.073135    0.090805     0.292538    0.363222
   4.0       0.030420    0.030387     0.486713    0.486194
   8.0       0.008472    0.007675     0.542194    0.491218
   16.0      0.002127    0.001868     0.544426    0.478094

   ⭐ 看 |grad|raw 那一列:4→8→16,每翻一倍 T,梯度缩小【正好约 4 倍】
      0.0304 → 0.00768 → 0.00187   (3.96×、4.11×)—— 这就是 1/T²
   ⭐ 看 |grad|xT2 那一列:0.486 → 0.491 → 0.478,稳定住了

一句话记住不乘 T²,你把 T 从 2 调到 8,等于偷偷把蒸馏损失的学习率降了 16 倍。 很多"蒸馏调不出效果"的案例,根因就是这一行。


🧬 三、蒸馏做在哪一层:logit / 特征 / 注意力

蒸馏不是只能学最后的输出。teacher 内部的每一层都是可以对齐的监督信号。

teacher 内部的每一层,都可以当成 student 的监督信号 teacher(大) student(小) Embedding Embedding 表示蒸馏 Layer 4 Layer 2 特征蒸馏 隐状态 MSE,维度不同要加投影 注意力蒸馏 attention map 对齐 Layer 12 Layer 6 特征蒸馏 ⚠️ 哪层配哪层是【你定的超参】 Logits Logits logit 蒸馏 KL + 温度,最通用
四种对齐方式可以叠加,但哪一层配哪一层是你自己定的超参 —— 这也是特征蒸馏最容易翻车的地方。
层次 学什么 代表工作 特点 / 坑
logit 蒸馏 输出分布 Hinton KD 最通用:学生结构可以和 teacher 完全不同。信号最少
特征蒸馏(hint) 中间层隐状态 FitNets / TinyBERT 信号强得多,收敛更快。⚠️ 维度不同要加投影层,层怎么配是人定的
注意力蒸馏 attention map("看哪里") TinyBERT / MiniLM Transformer 专用,对语法/结构类任务提升明显。⚠️ 要求头数可对齐
关系蒸馏 样本之间的相对关系 RKD / MiniLM 的 value-relation 对结构差异最鲁棒,不要求维度对齐

实践顺序先只上 logit 蒸馏,跑通、拿到 baseline,再考虑加特征/注意力。 特征蒸馏引入的超参(配层方案、投影层、各项权重)能吃掉你两周, 而在很多任务上它比纯 logit 蒸馏只多 0.5 个点。


🛑 读到这里可以停 —— 前半章讲完了(约 26 分钟)。 后半章还有:LLM 时代的蒸馏 · 一个事故复盘 · 怎么决策:什么时候值得蒸馏 回来的时候不用重读,直接从下一节接着看就行。


🤖 四、LLM 时代的蒸馏

LLM 蒸馏和经典分类蒸馏不是一回事,主要有三种形态:

① Token 级蒸馏(word-level KD)

每个位置对齐词表上的完整分布。信号最密,效果最好,但有个硬约束:

   ⚠️ teacher 和 student 必须【同 tokenizer、同词表】
      不然两边的 logits 根本对不上位置

   → 这就是为什么各家的小模型基本都是
     「同一家、同一个 tokenizer 的大模型」蒸出来的

② 序列级蒸馏(SeqKD)

让 teacher 把完整答案生成出来,学生拿这些答案当硬标签做普通的 SFT。

   ⭐ 等价于:在 teacher 的"众数序列"上做最大似然
      信号比 token 级弱(每个位置只有 1 个 token,没有分布)

   ✅ 但工程上简单太多:
      · tokenizer 不同也行、架构不同也行
      · teacher 可以只是一个 API
      · 数据可以离线生成一次、反复用

③ 数据蒸馏 —— ⚠️ 这里有法务问题

用大模型生成数据来训小模型,也叫蒸馏,而且它是当下最常见的形态。技术上它就是 SeqKD 的放大版;但它多了一层技术之外的约束:

⚠️ 绝大多数商用大模型 API 的服务条款,明确禁止用其输出去训练竞争模型。 开源权重模型也各有各的许可 —— 有些要求衍生模型继承许可, 有些要求在模型名字里带上原模型名。

这是立项前的第一道检查,不是上线前的最后一道。 一个已经训完的模型如果发现数据来源不合规,它没有补救措施,只能扔掉。 💀

   ⭐ 立项时必须回答的三个问题:
   ① 数据是哪个模型生成的?它的条款/许可怎么写的?
   ② 这个小模型会不会对外提供服务、会不会和 teacher 构成竞争?
   ③ 生成记录留存了吗(哪个模型、哪个版本、什么时候、什么 prompt)?

④ 自蒸馏(self-distillation)

teacher 和 student 同尺寸,甚至就是同一个模型。听起来没意义,但它是好几个实用技巧的统一框架:

用法 做什么
Born-again 用训好的自己当 teacher 再训一遍,纯当正则化,指标常有小幅提升
上下文蒸馏 把一段很长的 system prompt「蒸进权重」:带 prompt 的自己当 teacher,不带 prompt 的自己当 student → 推理时省掉这段上下文
推理链压缩 把「长 CoT 输出」蒸成「短输出」:省 token、省延迟
对齐回灌 把 RLHF/DPO 之后的行为蒸回一个更小或更快的模型

💀 五、一个事故复盘

事故一:整体掉 1 个点,某个人群掉 15 个点

发生了什么:一个客服意图分类服务,7B teacher 蒸成 1.3B student。验收指标:teacher 准确率 93.3%,student 92.3%,整体只掉 1.03pp,远好于 3pp 的红线,一次通过上线。上线两周后运营反馈:某类低频工单(占总量 1%)的转人工率翻了 3 倍。回头一查——那个分组的准确率从 85% 掉到了 70%,掉了 15pp。

这段代码就是当时应该跑而没跑的那一步

from collections import defaultdict

def stratified_report(rows, groups):
    """rows: (分组, teacher是否正确, student是否正确) 的列表"""
    n, t, s = defaultdict(int), defaultdict(int), defaultdict(int)
    for g, ok_t, ok_s in rows:
        n[g] += 1; t[g] += ok_t; s[g] += ok_s
    N = sum(n.values())
    T, S = sum(t.values()) / N, sum(s.values()) / N
    print(f"{'分组':<10}{'样本数':>8}{'teacher':>10}{'student':>10}{'Δ(pp)':>9}")
    print(f"{'全体':<10}{N:>8}{T:>10.3f}{S:>10.3f}{(S - T) * 100:>+9.2f}")
    worst = None
    for g in groups:
        d = (s[g] / n[g] - t[g] / n[g]) * 100      # ⭐ 每个分组【单独】算 Δ
        print(f"{g:<10}{n[g]:>8}{t[g]/n[g]:>10.3f}{s[g]/n[g]:>10.3f}{d:>+9.2f}")
        if worst is None or d < worst[1]:
            worst = (g, d)
    print(f"\n最差分组: {worst[0]}  Δ={worst[1]:+.2f}pp   (全体只有 {(S-T)*100:+.2f}pp)")
    return worst

groups = ["主力人群", "次要A", "次要B", "长尾C", "长尾D"]
size   = [8000, 1200, 500, 200, 100]
acc_t  = [0.940, 0.920, 0.900, 0.880, 0.850]
acc_s  = [0.933, 0.915, 0.880, 0.800, 0.700]
rows = []
for g, n_, at, as_ in zip(groups, size, acc_t, acc_s):
    rows += [(g, 1 if i < round(n_ * at) else 0,
                 1 if i < round(n_ * as_) else 0) for i in range(n_)]

worst = stratified_report(rows, groups)
assert worst[1] > -3.0, f"⭐ 分组 {worst[0]} 掉了 {worst[1]:.1f}pp,阻塞上线"

实跑输出(最后一行 assert 会触发,这正是它该做的事):

   分组             样本数   teacher   student    Δ(pp)
   全体           10000     0.933     0.923    -1.03
   主力人群        8000     0.940     0.933    -0.70
   次要A           1200     0.920     0.915    -0.50
   次要B            500     0.900     0.880    -2.00
   长尾C            200     0.880     0.800    -8.00
   长尾D            100     0.850     0.700   -15.00      💀

   最差分组: 长尾D  Δ=-15.00pp   (全体只有 -1.03pp)

为什么没发现(三个原因叠在一起):

   ① 评测集是从【蒸馏数据里随机切】的
      → 分布和蒸馏数据完全一样,长尾 D 只有 100 条
      → 在整体指标里权重只有 1%,掉 15pp 只贡献 0.15pp

   ② ⭐ 更深的原因:软标签在低频类上【本来就没信息】
      teacher 自己在长尾 D 上就不自信(softmax 接近均匀)
      → 蒸馏信号 ≈ 噪声 → 学生等于在这些类上【什么都没学到】
      → 蒸馏对长尾的伤害是【系统性的】,不是偶然

   ③ 验收只看了一个整体 accuracy 数字,没有分层

代价:两周 SLA 违约 + 客服加班;回滚到 teacher,1.3B 带来的每月约 40% 推理成本节约全部退回;三周的蒸馏工作报废。

补什么

补丁 内容
评测集独立 ⚠️ 评测集必须来自另一个时间窗、另一个采样源,不能从蒸馏数据里切
分层验收 指标从「整体 Δ」改成「整体 Δ + 每个分组 Δ」,任一分组 Δ < −3pp 直接阻塞
长尾特殊对待 低频类上调高硬标签权重(降 α),或对长尾过采样,或直接保留 teacher 兜底路由
teacher 不确定性 teacher 熵高的样本单独标记,这些样本上蒸馏信号本来就不可信

🧭 六、怎么决策:什么时候值得蒸馏

决策表

你想要什么 该用什么
省显存 + 提速,不想训练 量化,先做这个,永远先做这个
量化做完还不够小 结构化剪枝 + 蒸馏恢复,再量化
窄任务上要一个远小于通用模型的模型 蒸馏 —— 这是它唯一压过量化的场景
要换一个和 teacher 不同的架构(如换 tokenizer、换成非 Transformer) 蒸馏(只能序列级)
目标硬件有稀疏 Tensor Core 2:4 半结构化
只是想省显存,模型能力不能动 量化 + KV Cache 量化,别碰另外两个

蒸馏真正的独门价值不是"压缩",是"专精": 量化和剪枝都只能让模型变小,不能让它变得更适合你的任务蒸馏可以:用 70B 在你的业务数据上生成的答案,训一个 1B 的专用模型, 在这一个任务上可以接近甚至超过 teacher,而通用能力全部丢掉 —— 这正是你要的。 反过来,如果你要的是一个"什么都会、只是小一点"的通用模型,蒸馏是最差的选择。

⚠️ 蒸馏的成本:这笔账常被低估

   假设 7B teacher → 1.3B student,用 1.3B 的一次前向当作 1 个单位:

   ① student 训练(前向 + 反向)≈ 3 个单位
   ② ⭐ teacher 前向 ≈ 7/1.3 ≈ 5.4 个单位
   ──────────────────────────────────────
   合计 ≈ 8.4 个单位

   ⭐ 其中 【5.4/8.4 ≈ 64% 的算力花在 teacher 身上】
     → 蒸馏 1.3B 比从零训练同样的 1.3B 贵【约 2.8 倍】

那能不能把软标签离线缓存下来、只跑一次 teacher?能,但存储可能直接劝退

   词表 128k,只存 top-50:每 token ≈ 50 × (4 值 + 4 索引) = 400 字节

   100B token × 400 字节 = 40 TB    ⚠️
   1T   token × 400 字节 = 400 TB   💀

   → 所以实践里通常是:
     · 小规模、要多轮训练 → 离线缓存 top-k(k 取 5~20)
     · 大规模 → 在线跑 teacher,认下那 64% 的算力
     · 或者干脆用【序列级蒸馏】,只存 teacher 生成的文本(便宜几百倍)⭐

⚠️ 排期时请把这条写进去蒸馏的算力成本 ≈ 训练同尺寸模型的 3 倍,周期以周/月计。 而量化是几个小时。做决定前先算清楚你省下的推理成本要多久才能回本 —— 一个月省 40% 推理费、花掉三个月工程量的项目,未必划算。

⚠️ 评估:绝不能在蒸馏数据上评

   💀 最危险的闭环:
     teacher 生成数据 → 学生学 → 【在同一批数据上评估学生】

   为什么这是错的:
   ① 学生在上面得分高,只说明它学会了【模仿 teacher】,
      不说明它学会了【任务】
   ② ⭐ teacher 的错误被当成了标准答案 ——
      学生把错误学得越像,分数越高 💀
   ③ 分布完全一致,没有任何泛化信号

   ✅ 正确做法:
   · 评测集来自【另一个时间窗 / 另一个采样源】,人工标注
   · 必须分层(第五节)
   · 必须有一批 teacher 也会答错的样本,用来看错误有没有被继承

🔗 和站内其他章的关系

相关的地方 这里的位置
第 18 章 量化 压缩三件套的第一件;量化改数值精度,蒸馏换整个模型,正交可叠加
第 18c 章 剪枝 第三件。⭐ 现在 LLM 上的主流是组合拳:结构化剪枝选出小架构 → 蒸馏把能力搬回来
第 19 章 投机解码 也是"用小模型帮大模型",但它精确无损,蒸馏是有损的;草稿模型本身常常就是蒸出来的 ⭐
《推荐算法》18 进阶专题 精排蒸粗排 那边给推荐场景的用法(排序蒸馏、粗排一致性),本章给温度 / T² 的机制
《大模型全景导论》06 推理优化 部署侧取舍清单 那边给"该不该压缩"的产品视角,本章给"压了之后怎么验收"
《模型上线之后》02 离线好不等于线上好 离线指标骗人 本章那个事故就是这条规律在蒸馏上的具体形态:整体 −1pp,长尾 −15pp
《大模型全景导论》05 微调与 LoRA 那一章把蒸馏列为「想用小模型省钱」这个场景的主力路径,但只给了一句话。从那边带着「我要蒸一个小模型」的念头过来的人,需要的是本章的温度 / T² 机制和验收纪律
《模型上线之后》18 成本与容量 成本核算 蒸馏值不值得的账在这里算:省下的推理费要多久覆盖掉三个月工程量
《Kaggle竞赛方法论》03 模型融合与后处理 集成 集成蒸馏:teacher 可以是一个 ensemble,蒸成单模型上线 —— 竞赛里的标准收尾 ⭐

✅ 检查点

  1. 量化、剪枝、蒸馏各自改的是模型的哪个维度?为什么说它们正交?
  2. 为什么学 teacher 的软标签比学硬标签强?"暗知识"具体指什么?
  3. 温度 T 的作用是什么?T 太大和太小分别会怎样?
  4. 蒸馏损失里的 $T^2$ 是干什么的?不加会发生什么?
  5. logit 蒸馏、特征蒸馏、注意力蒸馏各有什么优势和限制?该先上哪个?
  6. 序列级蒸馏和 token 级蒸馏的区别?各自的约束是什么?
  7. 用大模型生成数据训小模型,技术之外要先检查什么?
  8. 蒸馏为什么会系统性地伤害长尾人群?验收指标该怎么改?
  9. 7B 蒸 1.3B,算力成本大概是从零训 1.3B 的几倍?大头在哪?
  10. 蒸馏真正压过量化的场景是哪一个?反过来什么时候它是最差选择?
  11. 为什么绝不能在蒸馏数据上评估学生?
👀 答案
  1. 量化改数值精度(16bit→4bit,形状不变)、剪枝改连接/尺寸(置零或删行列,精度不变)、蒸馏换整个模型(重新学一套权重)。动的是三个不同维度,所以可叠加,典型流水线是「结构化剪枝 → 蒸馏恢复 → INT4 量化」。
  2. 硬标签里"老虎"和"汽车"一样错,而 teacher 的软标签会告诉你猫像老虎的程度是像汽车的 120 倍 —— 这个类间相似性就是暗知识。信息量上硬标签只有 log2(C) bit,软标签是完整的 C 维分布;LLM 上是 17 bit vs 12.8 万维分布。
  3. 把尖锐的 softmax 摊平,让暗知识露出来。T 太小 → 退化成硬标签,蒸馏白做;T 太大 → 所有类趋同、信号被噪声淹没。分类典型 T=2~5,LLM 常直接用 T=1(词表大,本来就够软)。
  4. KL 对学生 logit 的梯度正比于 1/T²,乘上 T² 让软损失的梯度尺度不随 T 变化,α 才有稳定含义。不加的话,把 T 从 2 调到 8 等于偷偷把蒸馏损失的学习率降了 16 倍 —— 很多"蒸馏没效果"的根因就在这。
  5. logit 蒸馏最通用(学生结构可完全不同),但信号最少;特征蒸馏信号强、收敛快,但维度不同要加投影层、配层是超参;注意力蒸馏学"看哪里",对结构类任务好,但要求头数可对齐。⭐ 先只上 logit 蒸馏拿到 baseline。
  6. token 级每个位置对齐完整词表分布,信号最密,但要求同 tokenizer 同词表序列级让 teacher 生成完整答案、学生当硬标签学,信号弱但 tokenizer/架构都可以不同,teacher 可以只是个 API,数据能离线复用
  7. ⚠️ 许可条款。绝大多数商用 API 禁止用输出训练竞争模型,开源权重也各有许可要求。这是立项前第一道检查 —— 训完才发现不合规的模型没有补救措施,只能扔。
  8. 因为 ⭐ 软标签在低频类上本来就没信息 —— teacher 自己在这些类上就不自信,softmax 接近均匀,蒸馏信号≈噪声。加上评测集常从蒸馏数据里切、长尾在整体指标里权重极低,所以整体 −1pp 能掩盖某组 −15pp。验收要改成「整体 Δ + 每个分组 Δ,任一组 < −3pp 阻塞」,评测集必须独立于蒸馏数据。
  9. 约 2.8 倍。student 前向+反向 ≈ 3 个单位,teacher 前向 ≈ 5.4 个单位 —— 大头(约 64%)在 teacher 上。离线缓存软标签能摊销,但 top-50 缓存 1T token 要 400TB,通常只能存很小的 k 或改用序列级蒸馏。
  10. 窄任务上要一个远小于通用模型的专用模型 —— 用 teacher 在业务数据上生成的答案训一个 1B,在这一个任务上可以接近甚至超过 teacher,代价是通用能力全丢,而这正是你要的。反过来,要一个"什么都会、只是小一点"的通用模型,蒸馏是最差选择
  11. 因为 ① 得分高只说明学生学会了模仿 teacher,不说明学会了任务;② ⭐ teacher 的错误被当成标准答案,学生错得越像分越高;③ 分布完全一致,没有泛化信号。要用另一个时间窗/采样源、人工标注、分层的独立评测集。

🛑 可以停在这里

走神救援

压缩三件套动的是三个不同维度量化改数值精度(形状不变,16bit→4bit)、剪枝改连接/尺寸(下一章)、蒸馏换整个模型(重新学一套权重)——三者正交可叠加,典型流水线是「结构化剪枝 → 蒸馏恢复 → INT4 量化」。⭐但蒸馏和另外两件有本质区别:量化和剪枝只能让模型变小,蒸馏能让它变得更适合你的任务。机制:硬标签里「老虎」和「汽车」一样错,teacher 的软标签却告诉你猫像老虎的程度是像汽车的 120 倍——这个类间相似性就是暗知识;信息量上硬标签只有 log2(C) bit、软标签是完整分布,LLM 上是 17 bit vs 12.8 万维,这就是小模型普遍用蒸馏而不是从零预训练的根本原因。⭐温度 T 把尖锐的 softmax 摊平让暗知识露出来(分类 T=2~5,LLM 常用 T=1);⭐损失里那个 T² 不是装饰——KL 对学生 logit 的梯度正比于 1/T²,实跑验证:不乘 T² 时 T 每翻倍梯度缩小正好 4 倍(0.0304→0.00768→0.00187),不加 T² 就等于把 T 从 2 调到 8 时偷偷把学习率降了 16 倍,很多「蒸馏没效果」的根因就在这。可以做在三层:logit(最通用、学生结构可完全不同,信号最少)、特征(信号强但要投影层和配层超参)、注意力(学「看哪里」)——⭐先只上 logit 蒸馏拿 baselineLLM 时代三种形态:token 级(信号最密,⚠️要求同 tokenizer 同词表)、序列级 SeqKD(teacher 生成完整答案当硬标签,信号弱但架构/tokenizer 随便、teacher 可以只是个 API、数据能离线复用)、⚠️数据蒸馏(用大模型生成数据训小模型,受许可条款约束,绝大多数商用 API 禁止用输出训竞争模型——这是立项第一道检查,训完才发现不合规只能扔);还有自蒸馏(上下文蒸馏把长 system prompt 蒸进权重、长 CoT 压成短输出)。💀事故:蒸馏后整体只掉 1.03pp 通过上线,某个占 1% 的长尾人群掉了 15pp,转人工率翻 3 倍——原因是评测集从蒸馏数据里切、长尾权重只有 1%,更深的原因是⭐软标签在低频类上本来就没信息(teacher 自己不自信,分布接近均匀,信号≈噪声),所以蒸馏对长尾的伤害是系统性的、不是这次运气差;代价是两周 SLA 违约 + 三周工作报废 + 每月 40% 成本节约全退回;补丁是评测集必须独立于蒸馏数据 + 分层验收,任一分组 Δ<−3pp 直接阻塞。🧭决策:⭐永远先做量化(几小时就能做完),不够再考虑剪枝+蒸馏;⭐蒸馏真正的独门价值不是压缩而是专精——窄任务上训一个 1B 专用模型可以接近甚至超过 teacher,代价是通用能力全丢;要「什么都会只是小一点」的通用模型,蒸馏是最差选择。⚠️成本常被低估:7B 蒸 1.3B,student 前向+反向 3 个单位、teacher 前向 5.4 个单位——64% 算力花在 teacher 上,比从零训贵约 2.8 倍,周期以周/月计而量化是几小时,做决定前先算清省下的推理费要多久回本;离线缓存软标签能摊销但 top-50 存 1T token 要 400TB,所以大规模通常只能在线跑 teacher 或改用序列级。⚠️⭐最后一条:绝不能在蒸馏数据上评估学生——得分高只说明学会了模仿 teacher,而且teacher 的错误被当成标准答案,学生错得越像分越高,这是个会放大错误的闭环。

下一节 👉 18c-剪枝与稀疏化.md

打卡记录保存在你的浏览器里,首页能看到总进度