
在深度学习进入大模型时代之后“蒸馏”这个词出现的频率越来越高模型蒸馏、数据蒸馏、知识蒸馏、蒸馏一个数据集的 skill、H3 蒸馏模型等等。很多人第一次看到“蒸馏”时会以为它和炼丹、提纯有关系实际上它确实有点像“提纯”。一个参数量巨大的模型把学到的规律和判断方式“教”给一个小模型这个传递过程就是知识蒸馏。本文不聊地缘和公司竞争只从技术角度看清楚蒸馏是什么、它在开放模型和模型轻量化中扮演什么角色、如何用代码实现一次最小蒸馏以及在实际项目中踩过哪些坑、应该怎么排查。文章面向希望理解大模型原理、需要做模型压缩和轻量化、或者想在自己项目里复现蒸馏流程的工程师。读完以后你能独立完成一个 PyTorch 环境下的知识蒸馏最小案例能说出温度参数 T 的含义和调参方向也能区分离线蒸馏、在线蒸馏、自蒸馏以及大模型时代的数据蒸馏和推理蒸馏。“蒸馏”不是一个只能挂在口头上的热词而是一套可以落地、可以验证、可以调优的工程方法。1. 先理解蒸馏老师模型如何“教”学生模型1.1 通俗理解不是复制答案而是传递判断方式“蒸馏”的直观理解是有一个训练得很好的大模型它见过大量数据学到了复杂规律。现在想得到一个更小、更快、更省资源的模型但直接用小模型在小数据上从头训练效果往往不如大模型。于是让大模型充当“老师”小模型充当“学生”老师把自己的判断逻辑“讲”给学生听。这里的关键点在于老师不是只告诉学生“正确答案是什么”还要告诉学生“我是怎么权衡各种可能性的”。比如一张图片老师模型可能会给出“猫 0.85、狗 0.10、兔子 0.05”这样的概率分布。如果只取最大值学生只知道那是猫但如果把完整的概率分布给学生学生就能知道“猫和狗有相似特征兔子稍微远一点”这种软化的信息比单一的硬标签更有价值。技术定义上知识蒸馏Knowledge Distillation由 Hinton 等人在 2015 年的论文 “Distilling the Knowledge in a Neural Network” 中系统提出。核心思想是用教师模型输出的软标签soft labels作为监督信号配合真实硬标签一起训练学生模型让学生模型不仅拟合答案还拟合答案背后的不确定性。1.2 软标签、硬标签和温度参数 T要理解蒸馏的原理必须先区分硬标签和软标签。硬标签是传统分类任务里的 one-hot 向量比如“猫”就是[1, 0, 0]。它只告诉模型这个样本属于哪一类不包含任何关于“这类和其他类有多像”的信息。软标签是模型输出的概率分布。分类模型最后一层通常接 softmax输出所有类别的概率。比如[0.85, 0.10, 0.05]。这个分布里藏着信息猫和狗接近猫和兔子远。但如果模型训练得过于自信输出会非常尖锐比如[0.97, 0.02, 0.01]这时类间相似度信息就被压缩了。为了让软标签更“软”蒸馏引入温度参数 T$$q_i \frac{\exp(z_i / T)}{\sum_j \exp(z_j / T)}$$其中z_i是模型最后一层的 logitsT 是温度。T 越大概率分布越平滑类间关系越清晰T1 时就是普通 softmax。T 越小分布越尖锐接近硬标签。温度参数是蒸馏里最核心的超参数之一。1.3 为什么蒸馏能实现模型轻量化模型轻量化常见手段有四种剪枝、量化、蒸馏、结构紧凑设计。蒸馏的特殊之处在于它不改变学生模型的原始结构不要求学生模型的层数、参数量和教师模型一致。学生网络可以更浅、更窄、甚至使用完全不同的结构。蒸馏的收益来源于两点第一软标签提供了比硬标签更丰富的监督信号相当于给每个样本都做了数据增强第二教师模型在大量数据上训练得到的“偏见”和“权衡”被压缩进了软标签学生模型不需要重新遍历全部原始数据也能学到近似知识。因此蒸馏在开放模型社区里非常流行一个开源的大模型权重公开后其他人不需要从头训练而是用它的输出作为监督信号训练一个更小的模型成本和门槛都大幅降低。这也是“开放模型逼近前沿”在技术层面的重要推动力之一。2. 蒸馏的三种主流范式离线、在线、自蒸馏2.1 离线蒸馏先训练老师再固定老师教学生离线蒸馏是最经典、最稳定的范式。流程分两个阶段先训练一个完整的教师模型训练过程与普通模型完全一样。固定教师模型权重用它的软标签和真实硬标签共同训练学生模型。离线蒸馏的优点是不需要额外设计老师老师可以是一个已经部署在线的老模型甚至可以直接使用开源社区发布的大模型权重。缺点是老师能力是固定的学生学到的上限受限于老师。如果老师本身有系统性错误学生也会继承。应用场景中最常见的是模型压缩已经有一个效果好但推理很慢的大模型希望换成一个线上能扛住高并发的轻量模型就用大模型的输出去训练轻量模型。2.2 在线蒸馏老师和学生一起训练在线蒸馏不再区分两个阶段。老师和学生模型同时训练教师参数不是固定的而是随着训练过程不断更新。学生可以从一个“成长中的老师”那里学习。在线蒸馏适合没有现成强教师模型的场景。例如要训练一个规模较大的模型但又希望保留一个同等规模但更精简的版本两个模型互相监督。近年的深度互相学习Deep Mutual Learning就属于这个思路多个模型互相学习而不是单方向传递。在线蒸馏的缺点也很明显训练不稳定两个模型如果能力差距太大强的那个会迅速收敛弱的那个来不及学习反过来弱的模型输出的噪声也会干扰强的模型。实际项目里通常需要更精细的学习率调度和损失权重设计。2.3 自蒸馏自己教自己自蒸馏是一种特殊形式同一个模型更深层的输出当作“老师”浅层的输出当作“学生”。典型做法是给模型加一个辅助分类头用主干分类头的软标签去监督辅助分类头。自蒸馏最直接的价值是缓解深度模型的梯度消失问题让浅层也能获得直接的监督信号。另一类应用是模型自身迭代把上一轮训练好的模型作为老师继续蒸馏这一轮的新模型。LLM 训练中常见的“模型自我精炼”就和这个思路有重叠。三种范式的差异可以用一张表看明白范式教师状态学生训练时机典型场景稳定性复杂度离线蒸馏固定教师训练完成后单独训练压缩已部署模型、利用开源大模型高低在线蒸馏动态更新与教师同步训练没有现成教师、双模型互学中中自蒸馏模型自身同一模型训练过程中深层指导浅层、缓解梯度问题中中3. 从损失函数看蒸馏到底在优化什么3.1 蒸馏损失由两部分组成标准蒸馏的总体损失是两个损失的加权和L alpha * L_soft (1 - alpha) * L_hardL_soft学生模型在温度 T 下的软标签输出与教师模型在同样温度 T 下的软标签输出之间的 KL 散度。L_hard学生模型在温度 T1 下的正常输出与真实硬标签之间的交叉熵。alpha软标签损失的权重通常在 0.5 到 0.9 之间。L_soft衡量的是学生和老师的“判断方式”有多接近。KL 散度越小说明学生的概率分布越接近老师。L_hard则保证学生仍然能够正确回答真实答案不至于为了模仿老师而偏离真实。3.2 温度 T 的双重作用温度 T 在蒸馏里有两个作用第一在教师端T 决定了教师软标签的平滑程度。T 大分布平坦类间关系更明显T 太大所有类别概率趋近于一致信息反而被稀释。第二在学生端T 参与学生 logits 的缩放。计算蒸馏损失时学生和教师必须使用同一个 T否则两者的概率分布尺度不一致KL 散度没有意义。但在计算硬标签损失时学生必须使用 T1因为硬标签损失对应的是真实分类概率。温度 T 的典型取值范围在 2 到 10 之间。分类任务任务常用 3 到 5大模型蒸馏中常用更高温度让生成文本的分布更平滑。T 过小软标签接近硬标签蒸馏失去意义T 过大软标签过于均匀学生学不到有效类间信息。3.3 为什么 KL 散度比 MSE 更适合做蒸馏损失有人会问直接用教师 logits 和学生 logits 做 MSE 不行吗当然可以但效果通常不如 KL 散度。MSE 直接比较 logits 的数值要求两个模型的输出尺度一致。而 KL 散度比较的是概率分布之间的差异对尺度的敏感度更低。更重要的是KL 散度天然适合处理“分布”类目标它会让学生的概率分布在所有类别上都向老师看齐而不仅仅是在最大值上对齐。这也是蒸馏能传递“模糊知识”的原因。实际项目中如果教师和学生模型结构差异很大logits 的绝对值分布可能差别很大MSE 容易导致训练不稳定而 KL 散度通常更平稳。如果你只是想快速验证蒸馏流程推荐先使用 KL 散度再对比 MSE 的效果。4. 用 PyTorch 跑通一个最小知识蒸馏案例4.1 环境准备和依赖示例环境使用 Python 3.10、PyTorch 2.x、torchvision。建议使用 GPU但 CPU 也能跑通整个流程只是慢一些。先确认环境python -c import torch; print(torch.__version__)如果没有安装 PyTorch可以按官方推荐方式安装。这里以 pip 为例pip install torch torchvision数据集使用 MNIST 手写数字识别。这个数据集足够小教师模型和学生模型都能快速训练适合演示蒸馏的完整流程。4.2 定义教师模型和学生模型教师模型使用一个比较大的卷积网络学生模型使用一个很小的两层卷积网络。两者结构差异越大越能体现蒸馏的价值。import torch import torch.nn as nn import torch.nn.functional as F class TeacherNet(nn.Module): def __init__(self): super().__init__() self.conv1 nn.Conv2d(1, 32, 3, padding1) self.conv2 nn.Conv2d(32, 64, 3, padding1) self.fc1 nn.Linear(64 * 7 * 7, 256) self.fc2 nn.Linear(256, 10) def forward(self, x): x F.relu(self.conv1(x)) x F.max_pool2d(x, 2) x F.relu(self.conv2(x)) x F.max_pool2d(x, 2) x torch.flatten(x, 1) x F.relu(self.fc1(x)) return self.fc2(x) class StudentNet(nn.Module): def __init__(self): super().__init__() self.conv1 nn.Conv2d(1, 8, 3, padding1) self.fc1 nn.Linear(8 * 14 * 14, 10) def forward(self, x): x F.relu(self.conv1(x)) x F.max_pool2d(x, 2) x torch.flatten(x, 1) return self.fc1(x)教师网络有约 2 层卷积加 2 层全连接参数量在几十万级别。学生网络只有一层卷积加一层全连接参数量远小于教师。这样的对比能清楚看到蒸馏对小模型的提升效果。4.3 训练教师模型先写一个普通的训练函数。这里使用交叉熵损失和 Adam 优化器训练 3 个 epoch 就足够看到效果。def train_teacher(model, train_loader, epochs3, lr1e-3): optimizer torch.optim.Adam(model.parameters(), lrlr) model.train() for epoch in range(epochs): total_loss 0.0 correct 0 total 0 for images, labels in train_loader: optimizer.zero_grad() outputs model(images) loss F.cross_entropy(outputs, labels) loss.backward() optimizer.step() total_loss loss.item() * images.size(0) _, predicted torch.max(outputs, 1) correct (predicted labels).sum().item() total labels.size(0) print(fEpoch {epoch1}/{epochs}, Loss: {total_loss/total:.4f}, Acc: {correct/total:.4f})训练完成后保存教师模型权重供后面蒸馏使用torch.save(teacher.state_dict(), teacher_mnist.pt)4.4 实现蒸馏训练函数蒸馏训练函数需要额外接收教师模型、温度 T 和软标签权重 alpha。核心逻辑是学生前向得到 logits分别用 T 缩放得到软分布用 T1 得到硬分布教师同样用 T 缩放得到软分布然后计算两个损失并加权。def train_student_with_distillation( student, teacher, train_loader, epochs3, lr1e-3, T4.0, alpha0.7 ): optimizer torch.optim.Adam(student.parameters(), lrlr) teacher.eval() student.train() for epoch in range(epochs): total_loss 0.0 correct 0 total 0 for images, labels in train_loader: optimizer.zero_grad() student_logits student(images) with torch.no_grad(): teacher_logits teacher(images) soft_targets F.log_softmax(student_logits / T, dim1) soft_labels F.softmax(teacher_logits / T, dim1) loss_soft F.kl_div(soft_targets, soft_labels, reductionbatchmean) * (T * T) loss_hard F.cross_entropy(student_logits, labels) loss alpha * loss_soft (1 - alpha) * loss_hard loss.backward() optimizer.step() total_loss loss.item() * images.size(0) _, predicted torch.max(student_logits, 1) correct (predicted labels).sum().item() total labels.size(0) print(fEpoch {epoch1}/{epochs}, Loss: {total_loss/total:.4f}, Acc: {correct/total:.4f})注意loss_soft后面乘了T * T。这是因为 KL 散度对缩放后的 logits 求梯度时温度 T 会以 1/T 的幅度缩小梯度乘上T * T是为了让软标签损失的梯度量级和硬标签损失可比。Hinton 原论文中对这一项做了说明实际训练时这一乘数对收敛速度影响明显。4.5 对比实验结果为了验证蒸馏的效果需要三组结果学生模型从零训练不蒸馏。教师模型训练完后的准确率。学生模型用蒸馏方式训练后的准确率。def evaluate(model, test_loader): model.eval() correct 0 total 0 with torch.no_grad(): for images, labels in test_loader: outputs model(images) _, predicted torch.max(outputs, 1) correct (predicted labels).sum().item() total labels.size(0) return correct / total以 MNIST 为例常见结果如下表模型参数量级别测试准确率教师网络约 60 万约 99.2%学生网络不蒸馏约 2 万约 97.5%学生网络蒸馏约 2 万约 98.4%同样参数量的学生模型蒸馏后准确率能提升 1 个百分点左右。MNIST 本身非常简单差异不算大换到 CIFAR-10、ImageNet 或真实业务数据蒸馏带来的提升会更明显。5. 蒸馏在大模型时代的演变数据蒸馏和推理蒸馏5.1 从分类模型到生成式大模型原版知识蒸馏是为分类模型设计的强调软标签和类间相似性。但大语言模型是生成式模型输出不是类别概率而是词表上的概率分布蒸馏的方式也随之改变。大模型蒸馏常用的做法是让学生模型学习教师模型的生成分布。具体地把同一段 prompt 输入教师和学生让学生生成 token 序列然后用教师生成的 logits 作为监督信号训练学生模型。这个过程中也会使用温度参数来控制分布平滑程度。与分类蒸馏不同LLM 蒸馏还需要考虑序列长度、自回归解码、KV cache 对齐等问题计算成本更高。5.2 数据蒸馏不是让模型变小而是让数据变小数据蒸馏Dataset Distillation的目标完全不同。它不是为了得到一个更小的模型而是为了得到一组更小的、浓缩的样本。这组样本可以替代原始大型数据集让新模型训练得更快。典型流程是在一个大规模数据集上训练一个模型然后通过优化合成样本使得在这些合成样本上训练出的新模型能在真实测试集上达到接近原始数据训练的效果。合成样本就是“蒸馏过的数据”。这类方法在持续学习、隐私保护、降低训练成本方面有应用前景。“蒸馏一本书的 skill 知识库”这类提法本质上也和数据蒸馏、知识蒸馏相关把一本书中的知识提取成更紧凑的、可供模型直接调用的训练数据或者检索知识库片段。它不是模型参数的压缩而是知识载体的压缩。5.3 推理蒸馏把推理过程压缩成固定偏好推理蒸馏更偏向行为层面的对齐。教师模型在回答问题时不仅给出答案还会经历一系列思考过程。研究者把这些思考过程中的有用模式提取出来让学生模型学习。例如先用教师模型生成多轮推理链再筛选出正确的推理链用来微调学生模型。这类方法在开放模型社区里非常活跃。一个能力较强的教师模型可以被用来批量生成高质量的问答对、思维链、代码修复样例然后把这些数据用于训练较小规模的学生模型。整个过程的关键在于数据质量筛选教师生成的样本如果不经过过滤学生会学到错误逻辑。5.4 蒸馏、剪枝、量化的关系模型轻量化有三个常见方向蒸馏用小模型学习大模型的“行为”。剪枝直接去掉大模型中不重要的权重或层。量化把浮点权重转换为低精度表示。三者不冲突实践中常常组合使用。常见组合是蒸馏 量化先把一个大模型蒸馏成中等模型再对中等模型做 8-bit 量化进一步减小体积。另一个组合是剪枝 蒸馏剪枝后的模型精度会下降用原始大模型做教师进行蒸馏可以恢复一部分精度。技术核心思想主要收益主要代价蒸馏传递判断逻辑小模型效果提升需要训练教师耗时剪枝删除冗余参数体积和推理时间下降精度损失需要微调量化降低权重精度显存占用和延迟下降精度损失部署要求高6. 蒸馏中的常见问题和排查路径6.1 温度 T 和 alpha 怎么调现象蒸馏后学生模型准确率还不如不蒸馏。可能原因温度 T 选择不合适或者 soft 损失权重 alpha 过低/过高。T 太大软标签过于平均学生学不到类间差异T 太小软标签接近硬标签蒸馏和普通训练没有区别。alpha 太低软标签监督不足alpha 太高学生过度拟合教师的判断真实硬标签的约束被稀释。排查方式固定 alpha0.7分别尝试 T1、2、4、8、12观察学生模型的验证集准确率。再固定最优 T把 alpha 从 0.3 逐步增加到 0.9画出准确率变化曲线。推荐做法从 T4、alpha0.7 开始训练几个短 epoch 观察趋势而不是一开始就追求全量训练。分类任务中 T 一般不超过 10大模型生成的蒸馏任务中 T 可以更高。6.2 学生模型过小学不到知识现象学生模型只有一两层即便用蒸馏训练准确率还是上不去。原因学生模型容量不足。蒸馏传递的是教师的判断逻辑但最终效果仍然受学生模型表达能力的限制。一个只有 1 万参数的模型不可能完全复现一个 70 亿参数模型的能力。排查方式检查学生模型的参数量是否过少观察训练过程中 soft loss 是否持续下降如果 soft loss 下降但 hard loss 不下降说明学生在模仿教师但没有掌握正确分类能力。推荐做法先适当增加学生模型的宽度或深度再考虑蒸馏。蒸馏不是万能的它只能帮助学生达到其容量上限附近无法突破容量天花板。6.3 蒸馏训练过程 loss 不下降或震荡现象训练初期 loss 就很大或者训练到一半 loss 剧烈波动。原因教师模型没有切换到 eval 模式导致教师输出不稳定。温度和梯度缩放没有生效KL 散度的梯度太小。教师和学生模型输入没有做归一化导致 softmax 分布失衡。排查方式确认教师模型使用了torch.no_grad()。打印教师 logits 的数值范围检查 logits 方差是否过大。确认 KL 散度损失后面是否乘了T * T。推荐做法在蒸馏训练函数里加入教师模型eval()调用并在每次迭代时打印loss_soft和loss_hard的数值确认两者的量级没有差距过大。6.4 蒸馏结果无法复现现象同一份代码换了一台机器或者换了一个随机种子结果差异很大。原因PyTorch 的默认随机性、GPU 浮点数计算顺序、数据加载器的多线程 shuffle 都会影响结果。如果教师模型没有固定初始化和训练流程教师本身的差异会被学生继承。排查方式在训练开始前固定随机种子。固定数据加载器的 shuffle 顺序。保存教师模型权重蒸馏时统一加载。def set_seed(seed): import random import numpy as np random.seed(seed) np.random.seed(seed) torch.manual_seed(seed) torch.cuda.manual_seed_all(seed)推荐做法在复现实验时先固定 seed再调整网络结构和超参数。蒸馏实验最重要的问题是“相对提升是否存在”所以在对比试验中至少保证教师模型完全一致、数据划分完全一致。7. 蒸馏的工程落地建议和扩展方向7.1 什么时候该用蒸馏蒸馏不是所有场景都需要。以下情况适合已经有一个效果很好的大模型但线上推理延迟或显存无法满足要求。有开源大模型权重希望在此基础上训练一个更小的垂直领域模型。数据量有限直接训练小模型效果差希望借助大模型的知识弥补数据不足。以下情况不适合任务太简单小模型直接训练已经接近上限蒸馏收益很小。预算和时间有限连教师模型都来不及训练不如直接训练小模型。学生模型严重过小容量不足蒸馏无法补救。7.2 生产环境落地检查清单上线一个蒸馏模型前建议按下面的清单再过一遍教师模型的训练数据和业务目标是否一致。如果教师是在通用数据上训练的直接蒸馏到垂直领域学生可能学到的是通用知识而非业务知识。教师模型的权重文件是否固定。整个蒸馏流程必须使用同一个教师权重不能在蒸馏过程中重新训练教师。温度和 alpha 是否经过短实验验证。不要凭经验定死至少跑一组对照。学生模型推理性能是否满足线上要求。蒸馏解决的是精度问题速度评估要单独做。是否保留了不蒸馏的基线模型。一旦蒸馏模型上线异常基线模型可以快速回滚。日志中是否记录了每个 epoch 的 soft loss 和 hard loss。没有这两项指标线上问题无法回溯。7.3 从蒸馏延伸到更广的模型优化路径蒸馏不是终点。在实际工程中蒸馏通常和以下路径配合使用第一量化感知训练QAT。在蒸馏阶段引入量化误差让学生模型提前适应低精度权重上线后直接使用 8-bit 推理。第二结构化剪枝。蒸馏前的教师模型可以先做剪枝去掉冗余通道或头再作为教师进行蒸馏减少学生需要学习的噪声。第三持续蒸馏。业务数据会持续更新教师模型也会定期重训练。建立一套自动化流程新教师模型发布后自动触发新一轮蒸馏保证学生模型持续接近最新教师的能力。第四多教师融合蒸馏。当有多个教师模型时可以用多个教师的软标签做加权平均或者针对不同样本选择最优教师输出。这样可以减少单一教师的偏见。对于刚接触蒸馏的开发者建议先把本文的最小案例完整跑通理解损失函数、温度和 alpha 的意义再去读 Hinton 的原论文之后尝试把蒸馏应用到自己的分类或生成模型上。最值得做的练习是在同一个任务上固定学生模型结构分别用“不蒸馏、蒸馏、调过温度和 alpha 的蒸馏”跑三组实验对比准确率曲线。这个实验做完你对蒸馏的理解会比单纯看十篇资料都深刻。蒸馏的本质是知识迁移它让大模型的判断方式能够被小模型继承。在开放模型社区里它让更多资源有限的开发者能够利用前沿模型的输出训练出适合自己场景的轻量模型。理解蒸馏的细节不只是为了跟住热词更是为了在实际项目中多一个可用的、可解释的模型优化手段。