知识蒸馏进阶:迁移推理习惯而非最终分数 知识蒸馏这几年已经从一个“用教师输出的 soft label 去训练学生模型”的小技巧慢慢变成了大模型压缩和加速的主流手段。很多人一提到知识蒸馏第一反应就是拿教师模型的分数作为监督信号只要学生模型的准确率逼近教师模型就认为蒸馏成功了。但我在实际跑过多个蒸馏项目之后更倾向于一个判断教师模型真正能传给学生的不是最终分数而是它在处理输入时形成的推理习惯。这里的推理习惯包括中间层的特征分布、注意力分布、对模糊样本的决策方式甚至是错误模式。这篇文章会围绕这个判断先讲清楚为什么分数不是最重要的再给出可以照着做的蒸馏实验流程、参数设置和排查思路。适合正在做模型压缩、学生模型训练、或者想把手头大模型能力迁移到小模型上的同学尤其是那些已经跑通简单蒸馏但发现学生模型“分数接近、一到复杂样本就露馅”的人。1. 先确定核心问题蒸馏到底该传什么蒸馏的本质是知识迁移。传统做法把教师模型在训练集上的输出概率分布或者中间层特征作为额外监督信号来训练学生模型。这个思路本身没有问题但如果只看最终分数很容易忽略一个重要事实教师模型在输出分数之前已经经历了很多层特征变换、注意力计算和候选决策最终分数只是这一系列过程的压缩结果。1.1 为什么只盯 soft label 会丢失信息soft label 蒸馏经典做法是把教师的输出 logits 除以温度 T再做 softmax得到软化的概率分布然后让学生模型去拟合这个分布。这个做法在小模型时代很有效因为教师和学生的类别空间、输入形式基本一致最终的逻辑输出已经够用。但在大模型场景下这个方案有三个明显问题。第一信息瓶颈。logits 是一个固定长度的向量它虽然比 one-hot 标签包含更多信息但无法完整表达教师模型在隐藏层里学到的结构。比如教师模型在倒数第二层已经形成了某种语义聚簇这种聚簇关系在 logits 里很可能被压缩到几乎看不见。第二异常样本的指导价值被低估。教师模型在训练过程中会对某些困难样本产生比较有趣的内部响应这些响应可能决定了它最终是否预测正确。但 soft label 只能告诉学生“这个样本最终概率分布长这样”学生很难从里面反推出“教师模型是怎么一步步走到这个分布的”。第三输出校准问题。教师模型的 logits 不一定天然适合蒸馏。如果教师模型本身校准很差温度调不好学生可能学到过度自信或者过度模糊的分布最终表现还不如直接拿真实标签训练。所以从经验上看只依赖分数层面的蒸馏适合快速上线和基线对比但想让学生模型真正继承教师模型的泛化能力就必须往更深的层去看。1.2 推理习惯到底指什么我理解的推理习惯不是某个单一指标而是几个层次的组合。第一层是特征分布。教师模型在某一层输出的特征向量包含了它对输入的结构化理解。比如在图像任务里教师可能在某个中间层学会了边缘、纹理、部件这样的层级表示在文本任务里教师模型可能在某个 Transformer 层的隐藏状态里编码了句法或语义信息。学生模型如果能在对应层对齐这种特征分布就更容易学出类似的中间表示。第二层是注意力模式。对 Transformer 类模型来说注意力权重反映的是模型在不同 token 或图像 patch 之间建立关联的方式。教师模型在阅读一句话时可能更关注关键实体、修饰关系或指代关系学生模型如果只学最终输出很难自发形成同样的注意力偏好。有些蒸馏工作会把注意力图作为匹配目标就是希望学生能学到这种“看哪里”的习惯。第三层是决策边界。教师模型对一些边界样本怎么处理比如两个类别高度相似时教师模型是否保持保守、是否给出比较平滑的置信度这些判断方式和最终分数有关联但又不完全等于最终分数。从蒸馏角度看更好的方式是用教师模型在不同样本上的输出分布去影响学生模型的决策边界而不是让学生简单模仿一个最可能的答案。所以结论很清楚蒸馏的核心是把教师模型的中间过程作为监督信号而不是只看最终分数。这也就是我标题里说的“推理习惯比分数更重要”的真正含义。2. 可行的蒸馏路线与实验前置条件既然要传推理习惯就需要一套能“提取教师模型中间过程”的实验方案。下面按我实际使用的路线来做说明不涉及具体框架的偏门用法所有操作以通用流程为主。2.1 三条蒸馏路线怎么选蒸馏路线大体可以分成三类logits 蒸馏、特征蒸馏、关系蒸馏。logits 蒸馏就是前面说的 soft label实现简单只需要拿到教师模型的输出概率分布。优点是对模型改动小缺点是信息密度低。特征蒸馏需要指定教师和学生的对应层然后把中间特征做对齐。常见做法是计算两个特征图之间的 L2 距离或者用注意力图做匹配。这条路更贴合“学习推理习惯”的目标但需要解决一个关键问题教师模型和学生模型的层数、维度往往不一样怎么选对应层、怎么对齐维度直接决定效果。关系蒸馏更进一步不再强迫学生匹配教师某一层的绝对特征而是匹配样本之间的相对关系。比如在一个 batch 里计算样本间的余弦相似度矩阵让学生模型学到教师模型眼中的“样本远近亲疏”。这种做法对特征维度不匹配的问题更宽容也更接近“学习决策习惯”的思路。我的建议是如果只是做一个基线先用 logits 蒸馏如果想验证“推理习惯更重要”这个假设至少要做特征蒸馏如果训练资源允许可以再叠加关系蒸馏作为辅助损失。蒸馏路线监督信号实现难度对推理习惯的传递能力适用场景logits 蒸馏最终概率分布低一般快速基线、类别数少的任务特征蒸馏中间层特征、注意力图中较强图像分类、语义分割、多模态关系蒸馏样本间相似度矩阵中高强检索、表征学习、大模型场景2.2 实验环境怎么确认在动手之前先确认几件事。第一教师模型必须是可推理的。意思是它不仅能输出最终预测还能暴露中间层输出。大多数主流深度学习框架和模型库都支持这类操作但需要确认你拿到的权重文件不是被纯封装的推理引擎导出的。如果教师模型只能拿到最终 logits特征蒸馏就没法做只能退回 logits 蒸馏。第二依赖版本要提前锁定。蒸馏实验经常出现“换个版本结果差异很大”的情况尤其是 CUDA、PyTorch/TensorFlow 这类底层框架。建议在项目根目录里固定依赖版本不要用“最新版”作为默认安装方式。第三显存和内存规划。教师模型通常比较大训练时还要同时加载学生模型、计算中间特征、保存梯度。低配置机器也能跑但要把 batch size 调小同时减少特征对齐的层数。如果显存只有 8GB 左右建议先用小模型或者小分辨率做规则验证再切到目标模型。注意不要一上来就开最大 batch size。知识蒸馏实验里最容易出现的不是模型不收敛而是显存不足导致实验中段崩溃浪费大量时间。第四数据分布。蒸馏训练的数据不一定要和教师模型的原始训练数据完全一致但至少要覆盖目标场景的主要模式。如果你的任务数据分布和教师模型的训练分布差异很大教师模型本身的输出就不可靠这时传下来的推理习惯也大概率是错的。3. 把“推理习惯”落到训练流程里的实操方法这一部分按实际实验顺序展开。先跑最小样例再逐步加特征对齐、关系蒸馏和温度调整。3.1 最小样例先跑通 logits 蒸馏不管最终要不要做特征蒸馏我都建议先用 logits 蒸馏把整个训练链路跑通。这样能确认数据加载、模型前向、损失计算、反向传播链路都是通的。伪代码如下import torch import torch.nn.functional as F def kl_loss(student_logits, teacher_logits, temperature4.0): # 软化教师和学生输出 teacher_soft F.log_softmax(teacher_logits / temperature, dim-1) student_soft F.log_softmax(student_logits / temperature, dim-1) # KL散度注意两个都是log softmax或一个log一个softmax loss F.kl_div(student_soft, teacher_soft.exp(), reductionbatchmean) return loss * temperature * temperature这里有两个容易出错的地方。第一KL 散度的输入顺序。PyTorch 的kl_div第一个参数是 log-probabilities第二个参数是 probabilities顺序写反会导致损失量级异常。第二温度平方缩放。因为 logits 被温度除过梯度会变小通常要乘回temperature * temperature来保持梯度量级。最小样例里只需要保证这一步能正常跑完一个 epochloss 有下降学生模型准确率能超过从头训练的基线就说明蒸馏有效。3.2 加入特征对齐让学生看见教师的中间过程跑通 logits 蒸馏后再插入特征对齐。核心步骤是指定教师模型要导出的层通常是倒数第二层或者每个 Transformer 块的输出。在学生模型里选择对应层。如果维度不一致加一个投影层把学生特征映射到教师特征维度。计算特征之间的 L2 损失叠加到原来的蒸馏损失和真实标签损失上。代码逻辑大致是def feature_loss(student_feature, teacher_feature, proj_layer): # 先投影对齐维度 aligned_student proj_layer(student_feature) # 可以先用归一化避免尺度影响 student_norm F.normalize(aligned_student, dim-1) teacher_norm F.normalize(teacher_feature, dim-1) return F.mse_loss(student_norm, teacher_norm)这里有几个关键选择。第一个是选哪一层。经验上倒数第二层通常最容易对齐因为它既包含高层语义又不像最后一层那样和具体类别耦合太强。如果你想让学生学到更丰富的局部模式可以再加一个中前层的特征对齐但要小心中前层的特征包含大量底层细节如果学生模型容量不够强行对齐反而会压制它的学习能力。第二个是投影层不要做得太复杂。用一层线性层加激活函数就够了投影层的作用只是维度适配不是重新学习一遍特征。第三个是特征损失权重。我一般从 0.1 到 0.5 之间搜索优先从 0.1 开始。权重太大学生会把精力放在模仿教师中间特征上最终分类任务反而学不好权重太小特征对齐几乎没有作用。3.3 用注意力图辅助传递“看哪里”的习惯对 Transformer 模型来说注意力图是最直观的推理习惯载体。它反映了模型在处理一个序列时把多少注意力分配给不同位置。这个方法在文本分类、图像分类、视觉语言任务里都可以用。做法是把教师某一层的注意力权重矩阵取出来让学生对应层的注意力权重去逼近它。常见损失是 MSE 或 KL 散度。如果学生模型的注意力头数和教师不一致可以把多个头做平均或者加权合并后再对齐。需要提醒的是注意力图对齐不是越多越好。浅层注意力图包含较多局部语法或低级视觉关系深层注意力图才更接近语义决策。实际项目里对齐最后两到三层的注意力图通常就够了。3.4 验证是否真的学到了推理习惯验证阶段不要只看测试集准确率。准确率接近只能说明最终决策效果接近不能说明推理方式接近。我一般会额外看三个指标特征分布相似度把教师和学生模型的中间特征都降维比如用 t-SNE 或 UMAP 可视化看类别分布是否接近。注意力图相似度在同样的输入下计算教师和学生注意力图之间的余弦相似度。困难样本的决策一致性专门构造或收集一些模型容易出错的样本看教师和学生是否表现出相似的犹豫模式比如预测置信度偏低、标签概率分布更加平滑。如果这三个指标有明显接近说明学生模型确实继承了教师的推理习惯而不只是最终分数看起来像。4. 参数权衡哪些设置会直接影响推理习惯的传递效果蒸馏项目里参数选择比模型结构更折腾人。下面这组参数是实际项目中反复调过、影响最明显的项目。4.1 温度 T温度决定了 soft label 的平滑程度。低温让分布更尖锐接近 hard label高温让分布更平滑能暴露类别之间的相对关系。实验里如果温度太低soft label 几乎变成 one-hot学生学到的只是硬标签没起到软标签的作用温度太高分布太均匀类别间差异被抹平学生只能学到模糊的分布。文本分类任务里我常用的起始值是 4.0图像分类里可以试 3.0 到 6.0 之间。对于大模型蒸馏温度还需要结合教师模型本身的对数输出量级来调。如果教师模型的 logits 数值普遍偏大温度要适度提高否则 softmax 之后还是接近 one-hot。4.2 损失权重组合损失通常由三部分组成真实标签的交叉熵、soft label 的 KL 损失、特征对齐损失。我的建议是把真实标签损失权重固定为 1.0然后调整其他权重。soft label 损失可以从 0.5 起步特征对齐损失从 0.1 起步。如果训练集比较小可以增大 soft label 损失因为额外信息能缓解数据不足的问题如果训练集很大真实标签损失已经能提供足够信号就不需要让蒸馏损失喧宾夺主。4.3 特征对齐层选择可以构建一个简单的对比表对齐层位置传递的信息优点风险浅层局部纹理、语法结构让学生快速建立基础特征信息过于细碎学生容量不够时容易过拟合中层语义组成、局部关系能传递较丰富的结构信息需要处理维度差异和选择对应层深层类别决策、全局语义最接近推理终点可能变成特征复制缺少泛化多层组合完整推理链路最能体现“推理习惯”训练成本高调参难度大4.4 Batch Size 和优化器蒸馏时的 batch size 通常比普通训练更小因为教师模型也要占显存。如果显存允许batch size 尽量保持在 32 以上不然 BatchNorm 的统计量不稳定。优化器建议继续用平时训练学生模型使用的优化器不需要为了蒸馏单独换优化器。学习率可以比正常训练稍低一些因为特征对齐损失和 KL 损失会带来额外的梯度噪声。遇到 loss 反复震荡时先检查学习率和 batch size再去怀疑模型结构。调整学习率衰减策略有时比换蒸馏方法更管用。5. 当学生输出看起来合理但不稳定时的排查顺序蒸馏项目最让人头疼的情况是训练 loss 正常下降验证集准确率也不算差但把学生模型放到真实场景里发现它对某些输入的处理方式和教师模型差异很大或者在不同随机种子下结果波动明显。遇到这类问题我建议按下面的顺序排查。5.1 先确认教师模型的输出分布没有污染教师模型不是全知全能的。如果教师模型在训练数据上的输出已经存在明显偏置比如对某些类别过度自信、对某些长尾类别几乎不响应学生模型只会把这种偏置学得更彻底。排查方法很简单单独分析一次教师模型在训练集和验证集上的输出分布看类别概率均值、置信度分布。如果发现教师模型本身已经出现某类样本置信度极端集中就要考虑先对教师模型做校准或者对训练数据做重采样。5.2 再看特征对齐是不是变成了“硬模仿”特征对齐不是让学生输出和教师一模一样。如果学生在某些中间层特征上和教师过于接近反而可能失去自身结构的优势。一个典型的错误是教师和学生模型层数差异很大时强行把学生的某个浅层特征对齐到教师的深层特征导致学生模型把大量容量消耗在“复制教师特征”上而忽略了类别判别。这种情况的排查方法是把特征对齐损失单独输出观察它下降的曲线。如果特征损失快速降到接近 0但整体准确率没有同步提升那就是对齐目标选得太死板。解决方案通常是对特征做归一化之后再计算损失或者改用相似度矩阵、注意力图这类相对结构作为监督信号而不是直接匹配绝对特征值。5.3 检查温度、缩放和任务间的梯度冲突温度设置不合理时soft label 的梯度会主导整个训练过程真实标签的梯度被稀释。这种情况在训练曲线里表现为loss 下降很快但验证指标的提升很慢甚至不提升。我的排查顺序是先把 KL 损失和真实标签损失分开记录看各自量级。如果 KL 损失比真实标签损失大一个数量级以上先降低温度或 KL 损失权重。如果特征对齐损失一直不下降看投影层是否正常工作特征维度选择是否合理。如果多个损失叠加后训练不稳定可以尝试逐步加热损失第一个 epoch 只计算真实标签损失第二个 epoch 再加入 soft label 损失第三个 epoch 再加入特征损失。5.4 检查数据加载和增强方式的一致性这个问题最容易被忽视。教师模型在蒸馏时接收到的输入增强方式和学生模型单独部署时的输入预处理可能不一样。比如教师训练时用随机裁剪、色彩抖动学生模型部署时只做了 Resize 和归一化这会导致学生模型学习到的推理习惯虽然和教师一致但在真实输入上不匹配。解决方法是在蒸馏训练的数据增强环节尽量模拟最终部署时的预处理方式至少保证归一化参数、输入尺寸和通道顺序一致。蒸馏过程中使用的数据增强不要过度复杂否则会引入额外的优化难度。5.5 最后检查随机性和整体训练稳定性如果所有设置都合理学生模型的最终效果还是不稳定可以考虑几个方向固定随机种子先排查是否只是训练随机性造成的结果波动。把训练轮数适当增加蒸馏常常需要比普通训练更长的轮数尤其是特征蒸馏学生需要更多时间去模仿教师模型的过程。尝试使用更强的正则化手段比如 weight decay、标签平滑、dropout但要注意这些方法和蒸馏损失之间的交互。我个人更建议先把单模型、单条蒸馏链路稳定跑通再考虑多教师蒸馏、自我蒸馏、在线蒸馏这些变体。前面这些变体虽然可以进一步提升效果但它们都建立在“已经能稳定传递推理习惯”这个基础之上。6. 不同场景下的处理边界和优化空间6.1 什么时候只需做 logits 蒸馏如果学生模型和教师模型的规模差异不大或者任务是简单的分类问题soft label 蒸馏通常已经能拿到不错的结果。特征蒸馏和关系蒸馏虽然更有潜力但会增加实现成本和调参时间。对快速验证、模型压缩效果不敏感的中间版本logits 蒸馏是稳妥选择。6.2 什么时候必须做特征蒸馏或关系蒸馏当学生模型远小于教师模型比如参数量只有教师的十分之一甚至更少时只靠 logits 很难把复杂知识教给学生。这时需要通过特征蒸馏传递中间层表示或者通过关系蒸馏传递样本间结构。多模态场景里尤其明显只对齐最终分类头往往忽略了模态交互细节。6.3 原始材料没有给出明确版本支持时的处理如果是做研究和长期维护建议先记录当前实验环境的依赖版本包括深度学习框架、CUDA、GPU 驱动、数据处理库。因为特征蒸馏往往要 hack 模型内部结构依赖版本一变导出中间层的接口就可能不兼容。我在项目里会先写好一个环境检查脚本把框架版本、GPU 型号、显存大小、教师模型可导出层数确认之后再启动训练。6.4 未来可以继续优化的方向从“分数蒸馏”转向“推理习惯蒸馏”之后可以继续尝试这些方向从固定教师蒸馏改成在线蒸馏学生和教师一起更新教师可以从学生那里学到更容易被模仿的表达方式。使用多教师蒸馏让多个教师从不同角度提供推理信号学生更容易学到稳定的全局结构。引入更细粒度的对齐目标比如匹配 token 级别或 patch 级别的表征而不是只匹配整句或整图的特征。对于大模型场景可以考虑把教师模型的 CoT 推理路径作为监督信号让学生在生成过程中学习教师的中间推理步骤。这些方向本质上都是在扩大“推理过程”的监督范围而不是单纯提高训练迭代次数。最后一个建议是在实验记录里不仅要记录最终指标还要保存教师模型在若干样例上的中间特征和注意力图。这个习惯能帮你快速定位是蒸馏参数问题还是学生模型容量问题。真正落地时最值得盯住的一直是输入分布、中间层对齐和损失权重的组合关系。