第2章:知识蒸馏核心原理

好,咱们直接进入正题。知识蒸馏这个概念,说白了就是「让大模型教小模型」。我在做模型压缩的时候,经常遇到一个尴尬的情况:模型太大,手机跑不动;模型太小,精度又掉得厉害。蒸馏技术就是来解决这个矛盾的。

2.1 教师-学生网络架构

这个架构其实很好理解。教师网络(Teacher)是一个大模型,学生网络(Student)是一个小模型。训练的时候,教师网络不动,学生网络去学教师网络的输出。

我刚开始接触这个架构时,总觉得有点奇怪——为什么不直接用小模型去学真实标签呢?后来在项目里踩了坑才明白:教师网络的输出里,藏着很多「暗知识」。比如一张猫的图片,教师网络不仅知道它是猫,还知道它「有60%像老虎,30%像豹子」。这些信息,真实标签是给不了的。

核心流程:

  1. 训练一个大的教师网络(精度高,但参数量大)
  2. 用教师网络对训练数据做推理,得到软标签
  3. 学生网络同时学习软标签和硬标签
  4. 调整温度系数T,控制软标签的平滑程度

嗯,这里要注意:教师网络和学生网络的结构可以完全不同。我在一个OCR项目里,教师用的是ResNet-152,学生用的是MobileNet-V3,照样能蒸馏。结构不同没关系,关键是输出空间要一致。

2.2 软标签与硬标签

这两个概念是蒸馏的核心。硬标签就是one-hot向量,比如[0,0,1,0,0]。软标签是教师网络输出的概率分布,比如[0.02, 0.05, 0.85, 0.06, 0.02]。

你想想看,硬标签只告诉你「这是猫」,但软标签告诉你「这像猫,也有点像老虎」。后者包含的信息量大多了。我曾经做过一个实验:只用硬标签训练学生网络,精度掉了5个点;加上软标签后,只掉了1个点。差距就是这么明显。

我的经验:软标签的维度不要太高。如果分类数超过1000,建议先做聚类或者降维。否则学生网络学起来很吃力,反而影响效果。

那损失函数怎么设计?蒸馏的损失函数通常由两部分组成:

# 蒸馏损失函数伪代码
def distillation_loss(y_student, y_teacher, y_true, T, alpha):
    # 软标签损失:学生和教师的KL散度
    soft_loss = KL_divergence(
        softmax(y_student / T), 
        softmax(y_teacher / T)
    ) * (T ** 2)
    
    # 硬标签损失:学生和真实标签的交叉熵
    hard_loss = cross_entropy(y_student, y_true)
    
    # 加权组合
    total_loss = alpha * soft_loss + (1 - alpha) * hard_loss
    return total_loss

这里alpha是平衡系数,我一般设0.7。T是温度系数,后面会细说。

2.3 温度系数T的作用

温度系数T,是蒸馏里最微妙的一个超参数。它的作用是什么?说白了,就是控制软标签的「软硬程度」。

当T=1时,就是正常的softmax输出。当T变大时,概率分布变得更平滑,类别之间的差异变小。当T趋近于0时,软标签就变成了硬标签。

T值 效果 适用场景
T < 1 分布尖锐,接近硬标签 类别差异明显时
T = 1 标准softmax 默认设置
T > 1 分布平滑,类别间信息丰富 类别相似度高时
T >> 1 分布接近均匀分布 几乎不用,信息稀释严重

为什么会这样?我举个例子。假设教师网络对一张图片的输出是[0.9, 0.05, 0.03, 0.02]。当T=2时,softmax计算变成:

# 温度系数作用示例
import numpy as np

logits = np.array([0.9, 0.05, 0.03, 0.02])
T = 2.0

# 带温度的softmax
soft_with_T = np.exp(logits / T) / np.sum(np.exp(logits / T))
print(soft_with_T)
# 输出: [0.38, 0.24, 0.20, 0.18]

# 不带温度的softmax
soft_without_T = np.exp(logits) / np.sum(np.exp(logits))
print(soft_without_T)
# 输出: [0.52, 0.22, 0.14, 0.12]

看到区别了吗?T=2时,概率分布更均匀,类别间的相对关系保留得更完整。学生网络能学到「第二类是第三类的两倍」这种信息。

避坑指南:我曾经在一个细粒度分类项目里,把T设成了10。结果学生网络学出来跟随机猜差不多。后来才意识到,T太大时,软标签的信息被稀释得太厉害,学生网络根本学不到有用的东西。一般T的取值范围是2-8,我习惯从4开始调。

2.4 蒸馏的完整流程

好了,把上面三个概念串起来,就是完整的蒸馏流程:

  1. 准备阶段:训练好教师网络,冻结参数
  2. 生成软标签:用教师网络对训练数据做推理,保存logits
  3. 训练学生网络:
    • 前向传播得到学生网络的logits
    • 计算软标签损失(学生vs教师,带温度T)
    • 计算硬标签损失(学生vs真实标签)
    • 加权求和得到总损失
    • 反向传播更新学生网络参数
  4. 验证:在验证集上评估学生网络精度

我个人习惯在训练过程中动态调整T。刚开始用较大的T(比如6),让学生网络先学类别间的相对关系。训练到一半时降低T到3,让学生网络更关注类别间的细微差异。最后去掉温度,直接用硬标签微调几轮。这个方法在我做过的几个项目里都有效果。

小技巧:如果教师网络和学生网络的结构差异很大,建议先用知识蒸馏做预训练,再用真实标签做微调。我在一个NLP项目里试过,这样比直接蒸馏的效果好2-3个点。

嗯,这一章的内容就到这里。核心就是记住三件事:教师-学生架构怎么搭,软硬标签怎么用,温度系数怎么调。下一章我们会讲具体的蒸馏算法实现,包括离线蒸馏和在线蒸馏的区别。

本章要点回顾:

  • 教师网络提供暗知识,学生网络学习这些知识
  • 软标签包含类别间关系,比硬标签信息更丰富
  • 温度系数T控制软标签的平滑程度,一般取2-8
  • 损失函数是软标签损失和硬标签损失的加权组合

公众号:蓝海资料掘金营,微信deep3321