4. 教师模型选择与训练:如何选择教师模型,教师模型的预训练与微调技巧

教师模型选得好不好,直接决定了蒸馏的「天花板」。我见过不少团队,花了大把时间调蒸馏参数,结果教师模型本身就不够强,最后效果自然上不去。说白了,教师模型就是学生的「导师」——导师水平不行,学生再努力也有限。

这一章,我就把教师模型的选择逻辑、预训练策略和微调技巧掰开揉碎了讲。都是我在实际项目中踩过的坑和总结的经验。

4.1 教师模型的选择逻辑

选教师模型,不是越大越好。你得考虑几个关键因素:

  • 能力差距:教师和学生之间的能力鸿沟不能太大。我试过用 ResNet-152 蒸馏 MobileNetV2,结果学生根本学不到什么,因为教师的知识太「深」了,学生理解不了。
  • 架构相似性:教师和学生的架构越接近,蒸馏效果越好。CNN 蒸馏 CNN 比 CNN 蒸馏 Transformer 容易得多。
  • 部署约束:教师模型的大小和推理速度,决定了你能不能在实际场景中用它生成软标签。

核心原则:教师模型的能力应该是学生模型的 2-5 倍(按参数量或 FLOPs 估算)。差距太小,蒸馏收益有限;差距太大,学生学不动。

下面这张图,是我常用的教师模型选择决策流程:

教师模型选择决策流程 开始:定义学生模型 学生参数量 < 5M ? 部署环境有 GPU ? 任务难度高 ? 推荐教师:ResNet-50 / EfficientNet-B3 参数量 10-25M,FLOPs 适中 轻量教师 MobileNetV3-L 强教师 ViT-B / ResNeXt 否 → 轻量教师 是 → 强教师 💡 经验之谈 教师参数量 = 学生 × 3~5 倍时,蒸馏收益最明显 架构差异大时,建议先做特征对齐

4.2 常见教师模型对比

我整理了一份常用教师模型的对比表,方便你根据场景快速选择:

模型 参数量 Top-1 准确率 推理速度 适合场景
ResNet-50 25.6M 76.1% 快 通用图像分类
EfficientNet-B3 12.0M 81.1% 中 移动端蒸馏
ViT-B/16 86.0M 81.1% 慢 高精度需求
ConvNeXt-T 28.0M 82.1% 中 现代 CNN 蒸馏
MobileNetV3-L 5.4M 75.2% 极快 轻量教师

我的建议:如果学生模型是 MobileNet 系列,教师优先选 EfficientNet 或 ConvNeXt。架构差异小,蒸馏时特征对齐更容易。我在一个安防项目里用 EfficientNet-B3 蒸馏 MobileNetV3-S,Top-1 提升了 4.2 个百分点。

4.3 教师模型的预训练策略

教师模型最好用预训练权重初始化。为什么?因为蒸馏的本质是「知识迁移」,而不是「从头学习」。

我常用的预训练策略有三种:

  1. ImageNet 预训练:最通用,适合大多数场景。直接用 torchvision 或 timm 库加载即可。
  2. 自监督预训练:适合数据量少或标签噪声大的场景。我用过 DINO 和 MAE,效果不错。
  3. 领域预训练:如果目标数据集和 ImageNet 差异很大(比如医学影像、卫星图),先在领域数据上做自监督预训练会更好。

注意:不要用蒸馏后的学生模型作为教师。我曾经犯过这个错——用蒸馏后的 MobileNet 去蒸馏另一个更小的模型,结果精度反而下降了。教师模型必须保持「纯净」。

4.4 教师模型的微调技巧

教师模型不是拿来就能直接用。微调这一步,很多人忽略了,结果蒸馏效果大打折扣。

我总结了几条微调技巧:

  • 先冻结 backbone,只训练分类头:前 5-10 个 epoch 只训练全连接层,让分类头适应目标数据集的类别分布。
  • 使用更小的学习率:教师模型已经很强了,学习率太大容易破坏预训练特征。我一般用 1e-4 到 5e-5。
  • 加入标签平滑:标签平滑能让教师模型的软标签更「软」,学生学起来更容易。
  • 微调后做一次温度校准:找到最优的蒸馏温度 T。我通常用验证集搜索 T 在 [2, 8] 之间的最佳值。

微调后的教师模型,软标签质量会明显提升。我在一个细粒度分类项目里,微调后的教师模型软标签的 KL 散度降低了 30%,学生模型精度提升了 1.8%。

4.5 实战:教师模型微调代码示例

下面是我常用的教师模型微调代码片段。嗯,这里要注意数据加载和优化器的选择:

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import models

# 加载预训练教师模型
teacher = models.resnet50(pretrained=True)
num_classes = 100  # 目标数据集类别数
teacher.fc = nn.Linear(teacher.fc.in_features, num_classes)

# 冻结 backbone,只训练分类头
for param in teacher.parameters():
    param.requires_grad = False
for param in teacher.fc.parameters():
    param.requires_grad = True

# 优化器:只更新分类头
optimizer = optim.Adam(teacher.fc.parameters(), lr=1e-4)
criterion = nn.CrossEntropyLoss(label_smoothing=0.1)

# 训练 10 个 epoch 后解冻 backbone
for epoch in range(30):
    if epoch == 10:
        for param in teacher.parameters():
            param.requires_grad = True
        optimizer = optim.Adam(teacher.parameters(), lr=5e-5)
    
    # 训练循环(省略 dataloader)
    for inputs, labels in train_loader:
        outputs = teacher(inputs)
        loss = criterion(outputs, labels)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

# 温度校准:搜索最优 T
best_T = 4.0
best_kl = float('inf')
for T in [2, 3, 4, 5, 6, 7, 8]:
    kl = compute_kl_divergence(teacher, val_loader, T)
    if kl < best_kl:
        best_kl = kl
        best_T = T
print(f"最优温度 T = {best_T}")

避坑指南:我曾经在微调时忘记解冻 backbone,结果教师模型只更新了分类头,特征提取能力完全没变。蒸馏后学生模型精度只提升了 0.3%。后来解冻 backbone 再微调 20 个 epoch,精度直接提升了 2.1%。

4.6 教师模型的质量评估

微调完成后,怎么判断教师模型是否合格?我一般看三个指标:

指标 合格标准 说明
Top-1 准确率 ≥ 学生模型 × 1.2 教师必须显著强于学生
软标签熵 适中(0.5-1.5) 熵太低说明太「硬」,熵太高说明太「模糊」
特征多样性 特征图方差大 特征图方差小说明模型「偷懒」

如果教师模型的软标签熵偏低,可以适当提高温度 T,或者重新微调时加大标签平滑系数。

一句话总结:教师模型的选择和微调,决定了蒸馏的「上限」。选对模型、微调到位,蒸馏就成功了一半。