教师模型必须用torch.no_grad()和eval()模式防止显存爆炸与梯度错误;KL散度需用F.kl_div(),学生输入log_softmax、教师输入softmax,温度T一致且reduction='batchmean';蒸馏与CE损失按α=0.7加权,CE必须用真实标签;学生与教师logits维度及类别顺序须严格对齐。

教师模型输出要加 torch.no_grad(),否则显存爆炸
学生模型训练时,教师模型只做前向推理,不参与反向传播。但 PyTorch 默认会为所有张量构建计算图,如果教师模型的参数没被冻结、又没用 torch.no_grad() 包裹,梯度会一路回传到教师网络,显存占用翻倍,还可能报 RuntimeError: Trying to backward through the graph a second time。
- 必须在教师前向调用前加
with torch.no_grad(): - 教师模型本身也要设为
eval()模式,避免 Dropout/BatchNorm 影响输出稳定性 - 别直接写
teacher(x).detach()——detach()只断开梯度,不省显存;no_grad才真正跳过计算图构建
KL 散度损失要用 F.kl_div(),且输入顺序和温度要对齐
F.kl_div() 的第一个参数是学生 logits(log-probabilities),第二个是教师 logits(probabilities),不是反过来。而且它默认要求学生侧先过 log_softmax,教师侧过 softmax,温度 T 要两边一致,否则 KL 值发散、loss 不降。
- 学生侧:
F.log_softmax(student_logits / T, dim=1) - 教师侧:
F.softmax(teacher_logits / T, dim=1) - 调用时写成
F.kl_div(student_logprobs, teacher_probs, reduction='batchmean') - 别漏掉
reduction='batchmean',否则 loss 值随 batch size 缩放,难调 learning rate
蒸馏 loss 和原始任务 loss 要加权混合,权重不是越小越好
纯蒸馏 loss(KL)容易让学生过早放弃拟合真实标签,尤其当教师不准或数据噪声大时。但加太多原始 cross-entropy loss(CE),蒸馏就失效。常见错误是固定用 alpha=0.5 或直接设 0.1,结果要么学生学不像教师,要么欠拟合任务。
- 推荐起始值:
alpha = 0.7(KL 占 70%,CE 占 30%),再根据验证集准确率微调 - CE loss 必须用原始 label 计算,不是教师 soft label —— 否则学生彻底丢失监督信号
- 温度
T通常取 3–7;T=1等价于不用蒸馏;T>10会让教师输出太平滑,细节丢失严重
学生模型结构比教师浅/窄时,logits 维度可能不匹配
比如教师是 ResNet-50(1000 类),学生是 MobileNetV2(也是 1000 类),没问题;但如果学生是自定义 head,最后一层输出维度不对,F.kl_div() 会直接报 size mismatch。更隐蔽的是类别顺序不一致(比如 ImageNet 子集重映射后索引错位)。
- 务必检查
student_logits.shape == teacher_logits.shape,尤其 batch 维之后的维度 - 如果学生输出维度少(如只训 10 类),不能简单截取教师前 10 个 logit —— 要确保教师输出也按相同类别索引重排
- 调试时可打印
teacher_logits.max(), student_logits.max(),数值量级差太大说明 softmax/T 没对齐
温度缩放和梯度隔离是两个最常被跳过的细节,一漏就卡在 loss 不降或显存 OOM,而不是模型能力问题。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











