教师-学生架构详解:选对老师,设计好学生,调好温度

教师-学生架构,说白了就是知识蒸馏的骨架。没有它,蒸馏就无从谈起。我刚开始接触蒸馏时,以为随便找个大模型当老师,再搭个小模型当学生就能成。结果呢?效果惨不忍睹。后来才明白,选老师、设计学生、调温度,每一步都有门道。

教师模型的选择策略

教师模型不是越大越好。我见过有人拿千亿参数模型去蒸馏一个几百万参数的学生,结果学生根本学不动。为什么?因为老师知道的太多,学生消化不了。

选教师,我一般看三个维度:

维度 说明 我的建议
能力上限 教师模型在目标任务上的准确率 至少比学生高 5-10 个点,否则蒸馏没意义
模型容量 参数量、层数、计算量 教师参数量一般是学生的 5-20 倍
知识结构 教师是否在类似数据上训练过 最好用同领域预训练模型,别跨太远
小技巧: 如果教师模型太大,显存放不下,可以用 logits 离线存储。先跑一遍教师,把 soft label 存成文件,学生训练时直接读。这样能省不少 GPU 时间。

我个人习惯用 集成教师。就是把多个模型的结果平均一下,当作教师输出。这样做的好处是,学生的知识来源更稳定,不容易被单个模型的偏差带偏。我在一个图像分类项目里试过,用 3 个 ResNet-101 做集成教师,蒸馏给 MobileNet-V3,比用单个 ResNet-152 效果还好。

学生模型的设计原则

学生模型的设计,核心就一句话:在能力范围内,尽量贴近教师的知识表达方式。

你想想看,如果教师用的是 Transformer,学生用的是纯 CNN,那两者的特征空间差异太大,蒸馏时 loss 很难收敛。我踩过这个坑——当时硬要把 BERT 蒸馏给 TextCNN,调了一周温度,效果还是不如人意。

设计学生模型,我总结了三条原则:

  1. 结构对齐:学生尽量保留教师的核心模块。比如教师有 attention,学生可以减 head 数,但别把 attention 全砍了。
  2. 深度优先:在参数量固定的情况下,我倾向于让学生深一点、窄一点。深层网络更容易学到层次化特征。
  3. 输出层匹配:学生的输出维度必须和教师一致。这个看起来是废话,但有人真会搞错——特别是做多任务蒸馏时。
避坑指南: 我曾经把一个 12 层 BERT 蒸馏给 2 层 TinyBERT,中间层 loss 怎么调都不对。后来发现是 hidden size 差太多,教师 768 维,学生 128 维,映射矩阵根本学不好。后来我把学生 hidden size 提到 256,问题就解决了。

温度系数 T 的作用与调参

温度系数 T,是蒸馏里最微妙的一个超参数。它的作用,说白了就是控制教师输出的「软硬程度」。

T 越小,softmax 输出越接近 one-hot,学生学到的就是「正确答案」。T 越大,输出越平滑,学生能学到「类别之间的相似关系」。比如猫和狗的区别,T 大时,教师会说「这有点像猫,也有点像狗」,学生就能学到这种模糊知识。

那 T 到底怎么调?我一般按这个流程来:

  1. 先固定 T=1,跑一次 baseline,看学生能学到什么程度。
  2. 尝试 T=2, 4, 8,观察验证集准确率的变化。
  3. 如果 T 大效果好,说明类别间关系很重要,可以继续增大到 10-20。
  4. 如果 T 小效果好,说明任务本身 hard label 就够用了,T 不用太大。

下面这张图,是我自己项目里常用的温度调参流程:

温度系数 T 调参流程图 固定 T=1 跑 baseline 尝试 T=2, 4, 8 观察准确率 T 大效果好? 是 增大 T 到 10-20 否 保持 T=1-3 即可 T 越大,类别间关系越平滑;T 越小,越接近 hard label
注意: T 不是越大越好。T 超过 20 后,softmax 输出会变得过于平滑,所有类别的概率都差不多,学生反而学不到有效信息。我一般把 T 的上限设在 20,超过这个值效果就开始下降了。

另外,T 可以和训练阶段联动。我习惯用 动态温度:训练初期用大 T(比如 8),让学生先学类别间关系;训练后期用小 T(比如 2),让学生精调 hard label。这样效果往往比固定 T 好 1-2 个点。

嗯,关于教师-学生架构,核心就是这些。选老师要匹配,设计学生要对齐,调温度要试错。这三件事做好了,蒸馏就成功了一大半。