第2章:知识蒸馏核心原理
好,咱们直接进入正题。知识蒸馏这个概念,说白了就是「让大模型教小模型」。我在做模型压缩的时候,经常遇到一个尴尬的情况:模型太大,手机跑不动;模型太小,精度又掉得厉害。蒸馏技术就是来解决这个矛盾的。
2.1 教师-学生网络架构
这个架构其实很好理解。教师网络(Teacher)是一个大模型,学生网络(Student)是一个小模型。训练的时候,教师网络不动,学生网络去学教师网络的输出。
我刚开始接触这个架构时,总觉得有点奇怪——为什么不直接用小模型去学真实标签呢?后来在项目里踩了坑才明白:教师网络的输出里,藏着很多「暗知识」。比如一张猫的图片,教师网络不仅知道它是猫,还知道它「有60%像老虎,30%像豹子」。这些信息,真实标签是给不了的。
核心流程:
- 训练一个大的教师网络(精度高,但参数量大)
- 用教师网络对训练数据做推理,得到软标签
- 学生网络同时学习软标签和硬标签
- 调整温度系数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 蒸馏的完整流程
好了,把上面三个概念串起来,就是完整的蒸馏流程:
- 准备阶段:训练好教师网络,冻结参数
- 生成软标签:用教师网络对训练数据做推理,保存logits
- 训练学生网络:
- 前向传播得到学生网络的logits
- 计算软标签损失(学生vs教师,带温度T)
- 计算硬标签损失(学生vs真实标签)
- 加权求和得到总损失
- 反向传播更新学生网络参数
- 验证:在验证集上评估学生网络精度
我个人习惯在训练过程中动态调整T。刚开始用较大的T(比如6),让学生网络先学类别间的相对关系。训练到一半时降低T到3,让学生网络更关注类别间的细微差异。最后去掉温度,直接用硬标签微调几轮。这个方法在我做过的几个项目里都有效果。
小技巧:如果教师网络和学生网络的结构差异很大,建议先用知识蒸馏做预训练,再用真实标签做微调。我在一个NLP项目里试过,这样比直接蒸馏的效果好2-3个点。
嗯,这一章的内容就到这里。核心就是记住三件事:教师-学生架构怎么搭,软硬标签怎么用,温度系数怎么调。下一章我们会讲具体的蒸馏算法实现,包括离线蒸馏和在线蒸馏的区别。
本章要点回顾:
- 教师网络提供暗知识,学生网络学习这些知识
- 软标签包含类别间关系,比硬标签信息更丰富
- 温度系数T控制软标签的平滑程度,一般取2-8
- 损失函数是软标签损失和硬标签损失的加权组合
公众号:蓝海资料掘金营,微信deep3321