4. 软标签与硬标签:知识蒸馏的“双轨制”监督

好,我们进入第四章。前面我们讲了蒸馏的整体框架,说白了就是让一个小模型(学生)去模仿一个大模型(老师)的行为。那模仿什么呢?核心就是两个东西:软标签和硬标签。

很多人刚开始接触蒸馏,觉得不就是拿老师模型的输出当标签去训练学生吗?其实没那么简单。这里面的门道,在于怎么用好这两种标签,以及怎么平衡它们之间的关系。我当年在落地第一个蒸馏项目时,就因为在权重调优上踩了坑,模型精度死活上不去。今天我们就把这套“双轨制”监督彻底讲透。

4.1 软标签:老师模型的“思考过程”

先说说软标签。它到底是什么?

你想想看,一个分类模型,比如 ResNet-50,训练好后,它最后一层 softmax 输出的不只是“猫”或者“狗”这样的最终判断,而是一个概率分布。比如输入一张猫的图片,模型可能输出:猫 0.95,狗 0.03,兔子 0.01,老虎 0.01。

这个概率分布,就是软标签。它包含了老师模型对样本的“理解”——不仅仅是“这是猫”,还知道“它有点像狗,但绝对不是老虎”。这种类间相似性的信息,是硬标签(比如 one-hot 编码的 [0, 1, 0, 0])完全无法提供的。

核心观点:软标签传递的是“知识”,硬标签传递的是“答案”。学生模型从软标签中学到的,是老师模型的泛化能力,而不仅仅是记忆训练数据。

4.1.1 软标签的生成:温度参数 T 的作用

软标签不是直接拿 softmax 的输出就完事了。这里有一个关键的超参数——温度 T。

原始的 softmax 公式是:

q_i = exp(z_i) / Σ_j exp(z_j)

加入温度 T 后,变成:

q_i = exp(z_i / T) / Σ_j exp(z_j / T)

当 T=1 时,就是标准的 softmax。当 T > 1 时,概率分布会变得更“平滑”,也就是各类别之间的差距会缩小。当 T 很大时,分布趋近于均匀分布。当 T < 1 时,分布会变得更“尖锐”,趋近于 one-hot。

为什么要调这个温度?

我个人习惯在生成软标签时,把 T 设置在 3 到 10 之间。这样做的好处是,老师模型对“非目标类”的预测概率会被放大,学生模型能学到更多关于类间关系的信息。比如上面那个猫的例子,T=5 时,猫的概率可能降到 0.4,狗的概率升到 0.2,兔子和老虎各 0.1 左右。学生模型就能看到:“哦,原来猫和狗在特征空间里离得更近。”

温度 T 分布特点 适用场景
T = 1 标准 softmax,分布较尖锐 常规分类任务
T > 1(常用 3-10) 分布平滑,类间信息丰富 知识蒸馏的软标签生成
T < 1 分布极尖锐,接近 one-hot 极少使用,会丢失软标签优势

4.1.2 软标签的存储:一个容易被忽视的工程问题

生成软标签不难,难的是怎么存。我在项目中遇到过一个问题:老师模型参数量大,推理一次要几百毫秒。如果每个 epoch 都重新生成一次软标签,训练时间直接翻好几倍。

我的做法是:预生成 + 离线存储。

具体来说,在训练开始前,用老师模型对整个训练集做一次前向推理,把每个样本的软标签(logits 或概率分布)保存下来。训练学生模型时,直接从磁盘读取,不再重复推理老师模型。

存储格式我推荐两种:

  • HDF5:适合大规模数据,支持分块读取,压缩率高。
  • TFRecord / RecordIO:适合 TensorFlow 或 MXNet 生态,与数据管道无缝集成。

存储内容一般包括:样本 ID、硬标签(ground truth)、软标签(logits 或概率向量)。注意,如果存储的是 logits,训练时需要在学生模型侧重新计算带温度的 softmax。

工程建议:如果数据集太大(比如上千万张图片),可以只存储 top-K 的软标签值,其余置为 0。这样能大幅减少存储空间,且对蒸馏效果影响很小。我一般取 K=20 或 K=50。

4.2 硬标签:不可替代的“地面真相”

说完软标签,再来看硬标签。硬标签就是原始的 one-hot 标签,比如 [0, 1, 0, 0]。它代表的是“标准答案”。

有人可能会问:既然软标签包含了那么多信息,为什么还要用硬标签?

原因很简单:软标签也可能出错。老师模型不是万能的,它也有预测错误的时候。如果完全依赖软标签,学生模型会继承老师模型的错误。硬标签的作用,就是提供一个“纠偏”的锚点。

我曾经在一个医疗影像项目里做过对比实验:只用软标签训练的学生模型,在某个罕见病类别上的准确率只有 60%;加入硬标签后,提升到了 82%。原因就是老师模型在那个类别上本身就不太准,软标签带偏了学生。

注意:硬标签的监督作用不是“锦上添花”,而是“雪中送炭”。尤其是在类别不均衡或老师模型精度不高的情况下,硬标签的权重必须足够大,否则学生模型会学到错误的偏置。

4.3 联合损失函数设计:α 与 β 的博弈

好,现在我们有两条监督信号:软标签和硬标签。怎么把它们组合起来?

答案就是联合损失函数。它的形式很简单:

L_total = α * L_soft + β * L_hard

其中:

  • L_soft:学生模型输出与软标签之间的损失,通常用 KL 散度或交叉熵。
  • L_hard:学生模型输出与硬标签之间的损失,通常用交叉熵。
  • α 和 β:两个损失的权重系数。

看起来简单吧?但真正调起来,坑不少。

4.3.1 α 与 β 的调优策略

我个人的经验是,α 和 β 的调优没有一个“万能公式”,但有几条可循的规律:

  1. 先固定 β=1,调 α。β 作为硬标签的权重,设为 1 相当于保留完整的 ground truth 监督。然后从 α=0.1 开始,逐步增大,观察验证集精度。
  2. α 通常在 0.1 到 1.0 之间。如果老师模型精度很高(比如 95% 以上),α 可以取大一些,比如 0.7-1.0。如果老师模型本身一般(比如 85%),α 取小一些,0.3-0.5 比较安全。
  3. 注意损失量级的匹配。L_soft 和 L_hard 的量级可能差很多。比如 KL 散度的值通常比交叉熵小。这时候需要对 α 和 β 做归一化,或者对其中一个损失做缩放。
场景 老师模型精度 推荐 α 推荐 β 说明
高精度老师 > 95% 0.7 - 1.0 1.0 充分信任老师,软标签主导
中等精度老师 85% - 95% 0.3 - 0.7 1.0 软硬兼顾,平衡监督
低精度老师 < 85% 0.1 - 0.3 1.0 硬标签为主,软标签辅助
类别不均衡 任意 0.1 - 0.5 1.0 + 类别权重 硬标签加权,防止少数类被忽略

4.3.2 一个实用的调参流程

我记得有一次做电商场景的蒸馏,老师模型精度 97%,学生模型只有 3MB。我一开始把 α 设成 0.5,β 设成 1.0,结果学生模型精度只有 88%。后来我把 α 调到 0.8,精度直接跳到 92%。

为什么会这样?因为老师模型足够强,软标签里包含的信息远比硬标签丰富。学生模型需要更多地“听老师的话”。

下面是我常用的调参流程,你可以直接拿去用:

  1. 第一步:固定 β=1,α 从 0.1 开始,以 0.1 为步长,遍历到 1.0。每个配置训练 5 个 epoch,观察验证集精度。
  2. 第二步:找到精度最高的 α 值后,在它附近做细调(比如 ±0.05)。
  3. 第三步:如果精度仍然不理想,尝试调整温度 T。T 和 α 是耦合的——T 越大,软标签越平滑,α 可以适当增大。

经验之谈:α 和 T 是一对“好基友”。我一般先固定 T=5,调 α;找到最优 α 后,再微调 T。不要同时调两个参数,否则搜索空间太大,容易过拟合验证集。

4.4 知识体系总览

下面这张图,把本章的核心逻辑串起来了。你可以看到软标签和硬标签各自的作用,以及它们如何通过联合损失函数共同指导学生模型。

知识蒸馏双轨监督体系 老师模型 学生模型 带温度 Softmax 生成软标签 原始 Ground Truth 硬标签 联合损失函数 L_total = α·L_soft + β·L_hard 💡 核心逻辑: 软标签传递老师模型的“知识”(类间关系),硬标签提供“标准答案”(纠偏锚点)。 α 和 β 的平衡,决定了学生模型是更“像老师”还是更“忠于数据”。

4.5 避坑指南与实战建议

最后,分享几个我在实际项目中踩过的坑,希望能帮你少走弯路。

  • 坑一:软标签存储精度丢失。我曾经为了省空间,把软标签从 float32 转成 float16 存储,结果学生模型精度掉了 1.5 个点。后来发现是精度丢失导致梯度计算不稳定。建议至少用 float32 存储 logits。
  • 坑二:α 和 β 同时调。我见过有人用网格搜索同时调 α 和 β,搜索空间 100 个点,跑了三天三夜。其实没必要,先固定一个,调另一个,效率高得多。
  • 坑三:忽略温度 T 与 α 的耦合。T 越大,软标签越平滑,L_soft 的值会变小。如果不调整 α,软标签的贡献会被稀释。我一般会在调完 α 后,再微调 T,确保两者匹配。

一句话总结:软标签教学生“怎么想”,硬标签教学生“答什么”。α 和 β 就是这两者的“话语权”分配。调好了,学生模型既能继承老师的泛化能力,又能保持对 ground truth 的忠诚。