2024 年我想把一个大模型的能力,"压缩"进一个小很多的模型里——这样既省显存、又跑得快。我听说这个技术叫知识蒸馏。第一版我做得很省事:拿那个大模型(teacher)给一批数据打上标签,然后用这些标签去训练小模型(student)。本地一测——看着挺像回事:小模型训出来了,在训练集上loss 降得很低。我心里很踏实:"蒸馏嘛,不就是让小模型去模仿大模型的输出——拿大模型打的标签训小模型就行了。"可等我真正拿它去跑测试,一串问题冒了出来。第一种:小模型只会照搬最终答案,在那些连 teacher 自己都拿不准的边界样本上,它完全靠猜,泛化能力差得离谱。第二种最坑:teacher 偶尔会答错,而 student 把这些错误也照单全收,还学得特别"自信"。第三种:我把 student 的训练 loss 压到了很低,可一上真实测试集就崩——它只拟合了 teacher 给的那些硬答案,根本没学到 teacher 的"思考方式"。第四种:我换了个更小的 student,蒸馏完几乎没用——它的容量根本装不下。我盯着这一连串问题想了很久才彻底想明白,第一版错在一个根本的认知上:我以为"蒸馏就是让小模型去模仿大模型的最终输出"。这句话把"知识"理解成了"答案"。可它不是。知识蒸馏的核心,不是让 student 去拟合 teacher 的"硬标签(最终答案)",而是让它去拟合 teacher 输出的"软标签(完整的概率分布)"。teacher 在每个类别上的那一串概率——尤其是那些不是最高、却也不为零的概率——藏着 teacher 学到的"类别与类别之间的相似性结构",那才是真正的"知识"。真正用好蒸馏,核心不是"拿 teacher 打标签训 student",而是用温度把 teacher 的分布"软化"出来、用 KL 散度去对齐它、再权衡好 teacher 质量、student 容量和损失配比。这篇文章就把知识蒸馏梳理一遍:为什么"拿硬标签训小模型"根本不算蒸馏、软标签和温度到底是什么、蒸馏损失怎么配比、teacher 质量和 student 容量怎么权衡、蒸馏有哪几种类型,以及温度选取、分词器对齐、独立评估这些把蒸馏真正做对要避开的坑。
问题背景
先把那次蒸馏翻车的现象和我的误判讲清楚,后面所有的设计都是冲着纠正这个误判去的。
现象:拿 teacher 给数据打标签、再用标签训 student 之后,student 训练 loss 很低,但实际质量崩了:只会照搬最终答案、边界样本全靠猜;teacher 答错的地方 student 照学不误;训练 loss 低但真实测试集一上就崩;换更小的 student 蒸馏完几乎没用。
我当时的错误认知:"蒸馏就是让小模型去模仿大模型的输出,拿大模型打的标签训小模型就行了。"
真相:知识蒸馏要传递的"知识",不在 teacher 的最终答案里,而在它输出的完整概率分布里。teacher 对每个类别的概率(尤其是非最大的那些)编码了"类别之间有多像"——这才是 student 该学的东西。蒸馏真正的工程量,在于:用温度软化分布暴露出这些信息、用 KL 散度对齐软分布、配比好蒸馏损失与真实标签损失、筛掉 teacher 不可靠的样本、给 student 留够容量、用独立测试集而非蒸馏 loss 来评估。让 student 训出来只是开头,让它真正学到 teacher 的本事才是关键。
要把知识蒸馏做对,需要几块认知:
- 为什么"拿硬标签训小模型"不算蒸馏——argmax 丢掉了 teacher 绝大部分信息;
- 蒸馏的本质——软标签与温度,温度怎么把分布"软化"出来;
- 蒸馏损失——KL 散度对齐软分布,蒸馏损失与真实标签损失怎么配比;
- teacher 质量与 student 容量——teacher 错了 student 跟着错,容量不够白蒸馏;
- 蒸馏的类型、温度选取、分词器对齐、独立评估这些工程坑怎么处理。
一、为什么"拿硬标签训小模型"不算蒸馏
先把这件最根本的事钉死:当 teacher 看一张猫的图片,它输出的不是"这是猫"三个字,而是一串概率——比如猫 95%、狗 4%、老虎 0.9%、汽车 0.001%。这一串概率里,藏着 teacher 学到的全部"世界观":它认为猫和狗有点像、和老虎更像一点、和汽车八竿子打不着。这种"类别之间的相似度结构",就是 teacher 真正值钱的知识。可你一旦对它取 argmax、只留下"猫",就等于把这串概率里 99% 的信息全扔了——剩下的那个"猫",和数据集原本就有的标签一模一样。用这种硬标签训 student,student 从 teacher 身上学到的额外知识,是零。
下面这段代码,就是我那个"蒸了个寂寞"的第一版:
import numpy as np
# 反面教材:以为"蒸馏"就是拿大模型打的标签训小模型
def naive_distill(teacher, student, dataset, epochs=10):
for _ in range(epochs):
for x, _ in dataset:
# 第一步:让 teacher 给出预测
teacher_logits = teacher.forward(x)
# 第二步:取概率最高的那个类别,当成"标准答案"
hard_label = int(np.argmax(teacher_logits))
# 第三步:用这个硬标签训练 student
student.train_step(x, hard_label)
return student
# 破绽一:argmax 只留下"哪个类别最大",
# teacher 对其余类别的整个概率分布 —— 全丢了。
# 破绽二:teacher 答错时,student 把错误当真理照学不误。
# 破绽三:这跟"直接用数据集原始标签训 student"几乎没区别,
# student 根本没从 teacher 身上学到任何额外的东西。
这段代码能跑、student 也确实训出来了,它的问题不在代码本身,而在一个被忽略的前提:它默认"teacher 的价值,就在于它给出的那个最终答案"。可它错估了"知识"到底藏在哪。于是那串问题就有了解释:student 泛化差,是因为它只拿到了硬答案,没拿到 teacher 对"模棱两可情况"的细腻判断;teacher 的错误被照学,是因为argmax 之后,对的答案和错的答案看起来一模一样,student 无从分辨;训练 loss 低却崩,是因为它拟合的本就是一份和原始标签没区别的硬标签,学的是"背答案"而不是"学方法"。问题的根子清楚了:要做蒸馏,你得先让 teacher 那串被 argmax 抹掉的概率分布重新显形出来——而这,要靠"温度"。
二、蒸馏的本质:软标签与温度
问题来了:就算我不取 argmax、直接用 teacher 那串原始概率,也不太够用。因为一个训练得好的 teacher,它的输出分布往往非常"尖"——正确类别的概率逼近 1,其余类别全被压到接近 0。那些编码了"相似度"的非最大概率,数值小到几乎看不见。要把它们"放大"出来,就要用一个关键的旋钮——温度(temperature):
import numpy as np
def softmax_with_temperature(logits: np.ndarray, T: float = 1.0) -> np.ndarray:
"""带温度的 softmax:T 越大,输出的概率分布越"软"、越平缓。"""
# 先把 logits 除以温度 T,再做标准 softmax
scaled = logits / T
scaled = scaled - np.max(scaled) # 数值稳定:先减去最大值
exp = np.exp(scaled)
return exp / np.sum(exp)
温度 T 干的事很简单:在做 softmax 之前,先把所有 logits 都除以 T。T=1 就是普通的 softmax;T 越大,logits 之间的差距被压得越小,最后的概率分布就越平缓、越"软"。用一组具体的 logits,把这个效果看清楚:
import numpy as np
# 一张图片,teacher 输出的 logits:它"觉得"这是 2 号类
logits = np.array([1.0, 2.0, 8.0, 1.5])
# T=1:几乎是 one-hot,2 号类概率逼近 1,其余被压到接近 0
p1 = softmax_with_temperature(logits, T=1.0)
# T=4:分布被"软化",2 号类仍最大,但 0 号、1 号、3 号也露出了非零概率
p4 = softmax_with_temperature(logits, T=4.0)
print("T=1:", np.round(p1, 4)) # 例如 [0.001 0.002 0.996 0.001]
print("T=4:", np.round(p4, 4)) # 例如 [0.082 0.105 0.717 0.096]
# T=4 下那些"非最大"的概率,正是 teacher 学到的"类别相似度"
看 T=4 那一行:2 号类仍然是最大的(还是 0.717),但 0 号、1 号、3 号都露出了百分之几的概率。这几个小小的、非零的数字,就是 teacher 想告诉 student 的悄悄话:"这张图我认为是 2 号,但它和 1 号长得也有点像,和 0 号、3 号则更远一些。"这种"它虽然不是答案、但有多像"的信息,就是知识蒸馏里的"暗知识"(dark knowledge)。在 T=1 下,这些信息全被压成了 0.001、0.002,几乎被淹没;升高温度,就是把这些被淹没的信息重新放大、让 student 看得见。这就是蒸馏的核心动作:不要拿 teacher 的硬答案,要拿它在某个温度下的、软化过的整个分布。分布有了,下一个问题是:student 怎么去"学"这个分布?
三、蒸馏损失:KL 散度与损失配比
student 要做的,是让自己输出的软分布,尽量贴近 teacher 的软分布。"两个概率分布有多不一样",有一个专门的度量,叫 KL 散度。蒸馏损失,就是建立在它之上的:
import numpy as np
def kl_divergence(p: np.ndarray, q: np.ndarray) -> float:
"""KL 散度:衡量分布 q 偏离目标分布 p 有多远,越大越不像。"""
eps = 1e-9 # 防止 log(0)
p = np.clip(p, eps, 1.0)
q = np.clip(q, eps, 1.0)
return float(np.sum(p * np.log(p / q)))
def distillation_loss(student_logits, teacher_logits, T: float) -> float:
"""蒸馏损失:让 student 的软分布去对齐 teacher 的软分布。"""
soft_teacher = softmax_with_temperature(teacher_logits, T)
soft_student = softmax_with_temperature(student_logits, T)
# 注意:用了温度 T 之后,梯度会被缩小 T 的平方倍,
# 所以蒸馏损失通常要再乘上 T 的平方做补偿
return kl_divergence(soft_teacher, soft_student) * (T ** 2)
这里有个容易被漏掉的细节:distillation_loss 最后乘了一个 T ** 2。原因是——把 logits 除以 T 之后,反向传播时梯度也会被相应地缩小 T 的平方倍。如果不补偿,温度一高,蒸馏损失的梯度就变得微乎其微,student 几乎学不动。乘上 T ** 2,正好把这个缩放抵消掉。但光有蒸馏损失还不够。teacher 不是神,它也会错;而数据集本身是有真实标签的。所以实践中,student 的总损失,是两部分的加权和:
def combined_loss(student_logits, teacher_logits, true_label,
T: float = 4.0, alpha: float = 0.7) -> float:
"""总损失 = α·蒸馏损失 + (1-α)·真实标签损失。"""
# 蒸馏损失:跟 teacher 的软分布对齐(用温度 T)
distill = distillation_loss(student_logits, teacher_logits, T)
# 硬标签损失:跟数据集的真实标签对齐(用 T=1 的普通交叉熵)
p_student = softmax_with_temperature(student_logits, T=1.0)
hard = -np.log(np.clip(p_student[true_label], 1e-9, 1.0))
# alpha 越大 = 越信 teacher;alpha 越小 = 越信数据集的真实标签
return alpha * distill + (1 - alpha) * hard
这个 combined_loss 是蒸馏训练的真正核心。它说的是:student 一边要向 teacher 学(distill 那部分,学的是 teacher 的"判断方式"),另一边还要盯着数据集的真实标签(hard 那部分,作为一根"纠偏"的锚)。alpha 就是这两者之间的配比旋钮:teacher 质量很高时,alpha 可以大一点,让 student 多信 teacher;teacher 没那么靠谱时,alpha 就要调小,让真实标签把 student 拉回来。这里的认知要点是:蒸馏不是让 student 无条件地复制 teacher,而是让它"主要跟 teacher 学、同时用真实标签纠偏"。损失函数定下来了,可还有一个问题没解决:teacher 本身的对错,以及 student 装不装得下,都还没人管。
四、teacher 的质量与 student 的容量
蒸馏有一个残酷的前提,我一开始完全没意识到:student 的能力上限,被 teacher 的质量和 student 自己的容量,死死地卡住了。先说 teacher 质量。teacher 答错的样本,如果直接拿去蒸馏,student 不光会学错,还会带着 teacher 那份"错误的自信"一起学错。所以蒸馏前,该先筛一遍数据:
def filter_teacher_mistakes(teacher, dataset, conf_threshold=0.6):
"""蒸馏前先筛一遍:teacher 自己都没把握的样本,别拿去教 student。"""
clean = []
for x, true_label in dataset:
probs = softmax_with_temperature(teacher.forward(x), T=1.0)
pred = int(np.argmax(probs))
# teacher 预测对、且足够自信的样本,才是可靠的"教材"
if pred == true_label and probs[pred] >= conf_threshold:
clean.append((x, true_label))
print(f"原始 {len(dataset)} 条,过滤后保留 {len(clean)} 条")
return clean
再说 student 容量。这是我第一版换了个更小的 student 就彻底没用的原因。蒸馏能把大模型的能力"搬"过来,但搬运的目的地得装得下。一个容量太小的 student,无论你怎么蒸馏,它都学不像——这不是蒸馏方法的问题,是它根本没有足够的参数去承载那些知识:
def check_capacity(teacher_params: int, student_params: int) -> str:
"""student 和 teacher 的容量差距,决定了蒸馏能还原多少能力。"""
ratio = student_params / teacher_params
if ratio < 0.02:
return "student 太小:容量装不下,蒸馏后大概率严重掉点"
if ratio < 0.1:
return "压缩激进:可行,但要接受一定掉点,需充分蒸馏"
if ratio < 0.5:
return "压缩适中:蒸馏通常能保住大部分能力"
return "压缩幅度小:蒸馏收益有限,意义不大"
这两段代码合起来,讲的是同一个道理:蒸馏的效果,等于"teacher 有多好"乘以"student 装得下多少"。teacher 是知识的源头,源头里混了错误,student 学到的就是带错的知识;student 是知识的容器,容器太小,再好的知识也只能倒进去一部分、其余全溢出来。所以做蒸馏前的两件正经事是:第一,确认你的 teacher 在目标任务上确实足够强、并筛掉它不靠谱的输出;第二,给 student 留够容量——压缩比太激进,蒸馏救不回来。这两条前提都满足了,才轮到讨论"用哪种蒸馏方式"。
五、蒸馏的几种类型
前面讲的"对齐 teacher 和 student 的输出分布",是最经典、最常用的一种,叫 基于响应的蒸馏(response-based)——student 只学 teacher 最后那层的输出。但它不是唯一的。还有一种叫 基于特征的蒸馏(feature-based):不光对齐最终输出,还要对齐模型中间层的"表示"——相当于不只让 student 抄答案,还让它抄解题的中间步骤:
def feature_distillation_loss(student_feat, teacher_feat, projector):
"""中间层特征蒸馏:不只对齐最终输出,还对齐中间层的"表示"。"""
# student 和 teacher 的中间层维度通常不同,
# 需要一个 projector 把 student 的特征投影到 teacher 的维度
projected = projector(student_feat)
# 用均方误差,让 student 的中间表示靠近 teacher 的中间表示
return float(np.mean((projected - teacher_feat) ** 2))
而到了大语言模型的时代,蒸馏又多了一种非常实用的玩法:很多时候你拿不到 teacher 的内部 logits(比如它是个只给你 API 的闭源大模型),那就退一步——让 teacher 大量地生成高质量数据,再用这些数据去训练 student。这种做法,常被称为数据蒸馏或序列级蒸馏:
def build_distill_dataset(teacher_llm, prompts: list) -> list:
"""蒸馏 LLM 的常见做法:让 teacher 大模型生成高质量训练数据。"""
dataset = []
for prompt in prompts:
# 让 teacher 不只给最终答案,还给出完整的推理过程(思维链)
answer = teacher_llm.generate(prompt, with_reasoning=True)
# student 学的是 teacher 的"解题过程",不只是最终那个答案
dataset.append({"prompt": prompt, "completion": answer})
return dataset
# 关键:prompts 必须覆盖 teacher 能力的各个方面,
# 否则 student 只能学到 teacher 的一小块能力。
这里要建立一个整体的判断:蒸馏不是一招,而是一类方法。能拿到 teacher logits、做分类任务,就用响应蒸馏;想让 student 学得更深、连"思路"都学过来,就加上特征蒸馏;面对的是只有 API 的大模型,就用让 teacher 生成数据这条路——而且务必让它带上推理过程,因为 student 要学的是 teacher "怎么想",不只是"想出了什么"。下面这张图,把一次靠谱的蒸馏流程串起来:
六、工程坑:温度、分词器与独立评估
五块设计之外,还有几个工程坑,不处理就会让蒸馏白做或踩雷。坑 1:温度不是越高越好。温度太低(接近 1),软标签太尖,暗知识暴露不出来,蒸馏几乎退化成硬标签训练;温度太高,分布过度平缓,所有类别的概率糊成一团,连"哪个才是正确答案"这个最基本的信号都被冲淡了。温度通常在一个适中的区间里(经验上 3 到 5 附近)取值,而且该当成超参数去调,不能拍脑袋定死。坑 2:teacher 和 student 的分词器必须一致。这是蒸 LLM 时极容易踩的雷。如果 teacher 和 student 用的是不同的分词器,那它们输出的 logits 对应的根本不是同一套词表——你拿 teacher 第 5 个位置的概率去对齐 student 第 5 个位置的概率,两个 5 号位代表的是不同的 token,这种对齐从根上就是错的。做 logits 级蒸馏,务必确认两个模型共用同一个分词器和词表。坑 3:评估必须用独立测试集,绝不能看蒸馏 loss。这是最不能省的一步,也是我第一版栽得最惨的地方——蒸馏 loss 低,只说明 student 把 teacher 模仿得像,不说明它真的学到了能力:
def evaluate_distillation(teacher, student, test_set) -> dict:
"""蒸馏后必须在独立测试集上对比,而不是看蒸馏 loss。"""
def accuracy(model):
correct = sum(int(np.argmax(model.forward(x)) == y)
for x, y in test_set)
return correct / len(test_set)
t_acc = accuracy(teacher)
s_acc = accuracy(student)
return {
"teacher_acc": round(t_acc, 4),
"student_acc": round(s_acc, 4),
"retained": round(s_acc / t_acc, 4), # student 保住了 teacher 几成能力
"acceptable": s_acc / t_acc >= 0.95,
}
evaluate_distillation 给出的那个 retained,才是蒸馏真正的成绩单:student 用小得多的体量,保住了 teacher 几成的能力。这个数字,必须在一份 student 训练时从没见过的独立测试集上算出来。坑 4:蒸馏数据要覆盖 teacher 的能力边界。student 只能学到蒸馏数据里出现过的那部分能力。如果你的蒸馏数据全是简单样本,那 student 在简单样本上可能很像 teacher,可一遇到难题就露馅——因为 teacher 应对难题的能力,压根没机会通过数据传给它。坑 5:别指望蒸馏是无损的。蒸馏本质上是一种有损压缩——一个小模型,不可能完全等价于一个大它几十倍的模型。蒸馏能做到的,是让 student 在你关心的那个特定任务上,尽可能逼近 teacher;它做不到让 student 在所有方面都和 teacher 一样。所以蒸馏前要想清楚:我要 student 保住的,到底是哪一块能力——盯准那一块去蒸,而不是幻想把 teacher 整个人格都搬过来。
关键概念速查
| 概念 / 手段 | 说明 |
|---|---|
| 知识蒸馏 | 把大模型的能力迁移到小模型,本质是有损压缩 |
| 硬标签 | 取 argmax 后的最终答案,丢掉了 teacher 的分布信息 |
| 软标签 | teacher 输出的完整概率分布,编码了类别相似度 |
| 暗知识 | 软标签里那些非最大的概率,藏着 teacher 的判断细节 |
| 温度 T | logits 除以 T 再 softmax,T 越大分布越软越平缓 |
| 蒸馏损失 | 用 KL 散度对齐软分布,需乘 T 平方补偿梯度缩放 |
| 损失配比 alpha | 蒸馏损失与真实标签损失的加权,teacher 越可靠 alpha 越大 |
| 响应蒸馏 | student 只学 teacher 最终输出层,最经典常用 |
| 特征蒸馏 | 对齐中间层表示,让 student 连解题中间步骤都学 |
| student 容量 | 压缩比太激进会装不下知识,蒸馏也救不回来 |
避坑清单
- 对 teacher 输出取 argmax 当标签训 student,等于没蒸馏,知识全丢了。
- 真正的知识在 teacher 的完整概率分布里,尤其是非最大的那些概率。
- 训练好的 teacher 分布很尖,要用温度软化才能让暗知识显形。
- 蒸馏损失用 KL 散度,且要乘温度的平方补偿被缩小的梯度。
- 总损失要配比蒸馏损失和真实标签损失,teacher 不可靠就调小 alpha。
- 蒸馏前筛掉 teacher 预测错或不自信的样本,别把错误教给 student。
- student 容量太小装不下知识,压缩比太激进蒸馏也救不回来。
- logits 级蒸馏 teacher 和 student 必须用同一个分词器和词表。
- 温度选适中区间并当超参数调,太低暴露不出暗知识太高糊成一团。
- 评估必须用独立测试集对比保留率,绝不能看蒸馏 loss 低就以为成了。
总结
回头看那串"student 只会照搬答案、teacher 的错也照学、训练 loss 低却一上测试就崩"的问题,以及我后来在蒸馏上接连踩的坑,最该记住的不是某一段损失函数代码,而是我动手前那个想当然的判断——"蒸馏就是让小模型去模仿大模型的输出"。这句话错在它把"知识"等同于了"答案"。我以为 teacher 值钱的东西,就是它最后吐出来的那个结论;于是我拿那个结论去训 student,自以为完成了"知识的传递"。可 teacher 真正值钱的,从来不是它给出的答案,而是它得出这个答案时,对所有可能性的那一整套细腻的、带着分寸感的判断——它有多确定、它觉得还有哪些选项也沾点边、它认为这些选项之间谁和谁更像。这套判断,藏在它输出的完整概率分布里,而我一个 argmax,就把它全抹掉了。
所以做知识蒸馏,真正的工程量不在"拿 teacher 打个标签、训一下 student"那一步操作上。那一步,和普通的模型训练没什么两样。真正的工程量,在于你要理解"知识到底以什么形式存在、又该怎么搬运":知识藏在软分布里,你就得用温度把它软化、放大出来;搬运的过程会失真,你就得用 KL 散度精确地对齐分布,还要用真实标签做一根纠偏的锚;teacher 不是神,你就得筛掉它的错误;student 是个有限的容器,你就得给它留够容量;而蒸完之后,你必须在一份独立的测试集上,老老实实算出"到底保住了几成能力"。这篇文章的几节,其实就是顺着这条思路展开的:先想清楚"拿硬标签训小模型"为什么不算蒸馏,再把软标签和温度的机制讲透,用 KL 散度和损失配比接住"怎么对齐分布",权衡好 teacher 质量与 student 容量,理清蒸馏的几种类型,最后是温度、分词器、独立评估这几个把蒸馏做扎实的工程细节。
你会发现,知识蒸馏的思路,和现实里"一位老师傅带徒弟"完全相通。一个不会带徒弟的师傅,会怎么教?他只把每道工序的标准答案甩给徒弟——"这一步就这么做,记住"。徒弟把答案背得滚瓜烂熟,可一遇到书上没有的新情况,立刻抓瞎。这正是我那个"硬标签蒸馏"的第一版。而一个真正会带徒弟的师傅怎么教?他不只给答案,还会把自己心里的那杆秤摊开给徒弟看:"这种情况我倾向于这么做,但那么做其实也有七八分道理,而另外那种做法就差得远了"(这就是带温度的软标签——把判断的分寸感传下去)。他不会把自己偶尔的失手也当经验传授(这是筛掉 teacher 的错误)。他清楚徒弟的资质,不会硬塞徒弟根本接不住的东西(这是 student 容量)。最关键的——他会让徒弟去做几道全新的、自己从没演示过的题,以此检验徒弟是真懂了还是只会模仿(这是独立测试集评估)。带徒弟的成败,从来不在于你把答案讲了多少遍,而在于你有没有把答案背后那套"怎么判断"的东西,真正传下去。
最后想说,蒸馏做没做对,差距永远不会在"student 能不能训出来"这一步暴露——它当然能训出来,蒸馏 loss 也当然会降下去,你会觉得"模仿一下 teacher"这件事已经成了。它只在真实的、需要 student 独当一面去解决新问题的场景里才显形。那时候它会用最让人尴尬的方式给你结账:做不好,你会像我一样,得到一个"像但不会"的小模型——它在你蒸馏过的样本上表现得有模有样,可一碰到真实世界里千变万化的新情况就原形毕露,你查遍了训练日志,loss 曲线漂亮得无可挑剔,可模型就是不顶用;而做对了,你会得到一个又小又能打的模型:它的体量只有 teacher 的零头,跑得飞快、省显存,而在你真正关心的那个任务上,它的表现逼近 teacher、退步小到可以接受。所以别等"像但不会"的模型摆在面前,在你决定"蒸馏一下"的那一刻就该想清楚:我要从 teacher 那里搬运的,究竟是它的"答案",还是它的"判断力"?我搬运的通道(温度、损失、数据),够不够把这份判断力完整地送过去?这两个问题有了答案,你的蒸馏才不只是一次"让小模型看起来像大模型"的模仿秀,而是一次真正把能力浓缩进小体量、既省成本又不丢本事的可靠工程。
—— 别看了 · 2026