6.2 温度、权重与学习率:调参手记 本节摘要:蒸馏训练有三组旋钮:温度、软硬权重、学习率与调度。第三章讲过前两者的机理,本节把它们与学习率合成一张可执行的操作序——先定温度带、再配权重、最后收拾学习率——配场景化默认值表、观察指标与一套"十分钟体检"训练监控代码。读完本节,调参从玄学变成流程。 第三章把温度与配比的机理讲透了,本节做的是工程收口:机理翻译成固定顺序的操作步骤与一张默认值表。调参的本质不是找到最优值,而是用最少的实验次数落到甜点区。 操作序:三步走,别乱序 第一步:定温度带。 温度决定软损失的实际量级(梯度按温度平方缩放),它变了后面全变,所以必须先定。按 3.1 的经验带选起点(同族分类任务 4;过自信教师升到 6 到 8;
本节摘要:蒸馏训练有三组旋钮:温度、软硬权重、学习率与调度。第三章讲过前两者的机理,本节把它们与学习率合成一张可执行的操作序——先定温度带、再配权重、最后收拾学习率——配场景化默认值表、观察指标与一套"十分钟体检"训练监控代码。读完本节,调参从玄学变成流程。
第三章把温度与配比的机理讲透了,本节做的是工程收口:机理翻译成固定顺序的操作步骤与一张默认值表。调参的本质不是找到最优值,而是用最少的实验次数落到甜点区。
第一步:定温度带。 温度决定软损失的实际量级(梯度按温度平方缩放),它变了后面全变,所以必须先定。按 3.1 的经验带选起点(同族分类任务 4;过自信教师升到 6 到 8;NLP 从 1 起步),跑一次单变量扫描确认平台区间,锁定一个值不再动。
第二步:配权重。 温度锁定后扫 alpha,粗扫三个点(0.5、0.7、0.9)即可区分方向,再向最优侧细扫一个点。配比检查的硬前提:软硬两分量的数值量级已打印核对(3.2 的代码),量级失衡先修分量再谈权重。
第三步:收拾学习率。 蒸馏训练的地形比直接训练平滑(3.3 机制二),学习率可以用与教师训练相同的初值起步;唯一要留意的是 4.6 场景——伪量化前向的地形粗糙,学习率降十倍。调度策略沿用原任务的最佳实践,余弦退火或阶梯衰减都不与蒸馏冲突。
三步的顺序不可颠倒:alpha 在温度未定时扫出来的最优值,温度一变就作废——这是调参返工的头号来源。
第一步的温度扫描同样可以半自动化——跑一串短程实验,按"平台区间"而非单点最优选值(单点最优对随机种子太敏感):
# 温度带扫描器:短程实验 + 平台区间判定 def temperature_sweep(train_fn, eval_fn, temps=(1, 2, 3, 4, 6, 8, 12), seeds=(0, 1)): """train_fn(T, seed) 返回训好的学生;eval_fn 返回精度。""" acc = {t: [] for t in temps} for t in temps: for s in seeds: acc[t].append(eval_fn(train_fn(t, s))) print(f"T={t:>2}: 平均 {sum(acc[t])/len(acc[t]):.4f}") avg = {t: sum(v) / len(v) for t, v in acc.items()} best = max(avg.values()) # 平台判定:与最优差 0.3 个点以内的温度都算"平台成员" plateau = [t for t, a in avg.items() if best - a < 0.003] print(f"平台区间: {plateau},取中位 {sorted(plateau)[len(plateau)//2]} 锁定") return plateau # 输出示例(分类任务、两随机种子): # T= 1: 平均 0.9021 # T= 2: 平均 0.9068 # T= 3: 平均 0.9090 # T= 4: 平均 0.9094 # T= 6: 平均 0.9087 # T= 8: 平均 0.9052 # T=12: 平均 0.8979 # 平台区间: [3, 4, 6],取中位 4 锁定 # 平台比单点更抗种子噪声——下次复跑大概率还在平台上。

| 场景 | 温度 T | alpha(软损失权重) | 学习率处理 |
|---|---|---|---|
| 图像分类,同族师生 | 4 | 0.9 | 沿用原任务 |
| 教师 过自信 | 6 到 8 | 0.9 | 沿用 |
| 标签噪声大 | 4 | 0.95 | 沿用 |
| NLP token 蒸馏 | 1 到 3 | 0.7 到 0.9 | 沿用 |
| 排序 / 推荐分数 | 6 起步 | 0.7 | 沿用 |
| 容量鸿沟边缘学生 | 3 到 4 | 0.5 到 0.7(课程表递增) | 沿用 |
| 量化感知蒸馏 | 4 | 0.85 | 降十倍 |
| 自蒸馏代际传递 | 2 到 3 | 0.8 | 沿用 |
这张表的用法是"起点不是终点":每个值都是历史实验的常见落点,用于省掉第一轮盲扫;进入正式实验后仍按三步序校准。
# 十分钟体检:训练循环里输出的最小监控面板 import torch import torch.nn.functional as F def kd_train_step_with_dashboard(student, teacher, x, y, T, alpha): teacher.eval() s_logits = student(x) with torch.no_grad(): t_logits = teacher(x) hard = F.cross_entropy(s_logits, y) soft = F.kl_div(F.log_softmax(s_logits / T, dim=-1), F.softmax(t_logits / T, dim=-1), reduction="batchmean") * T * T loss = alpha * soft + (1 - alpha) * hard loss.backward() return { "total": loss.item(), "hard": hard.item(), "soft": soft.item(), "soft_hard_ratio": (alpha * soft).item() / max((1 - alpha) * hard).item() if False else (alpha * soft).item() / max((1 - alpha) * hard.item(), 1e-6), "teacher_entropy": F.softmax(t_logits / T, dim=-1).entropy().mean().item(), } # 输出示例(每 N 步打印一次): # {'total': 1.872, 'hard': 0.412, 'soft': 1.622, # 'soft_hard_ratio': 3.54, 'teacher_entropy': 1.19} # 读法:soft_hard_ratio 与 alpha/(1-alpha) 的设计值偏离过大, # 说明分量量级失衡;teacher_entropy 异常走低说明教师分布退化。
背景。 团队新任务(十二类工牌检测)第一次上蒸馏,实验预算只有单卡三天。
操作。 若按老办法温度乘权重乘学习率全网格扫描,72 个组合跑不完。改走三步序:第一步温度扫描 5 个短程实验(每个约 2 小时);第二步 alpha 粗扫 3 加细扫 1(4 个实验);第三步学习率不扫,直接沿用上一项目的值并在第一个正式实验里盯曲线。剩余时间全部投入正式训练与一次复跑。
结果。 三天里完成选温、配比与两次正式训练,最终学生 mAP 与后来补做的粗网格扫描(两周后跑的对照组)最优值只差 0.2 个点,而实验次数是网格法的十二分之一。
解读。 序贯调参的省时来自"减少联动的无效组合":温度未定时扫 alpha,一半实验会因温度后续变动作废;学习率与蒸馏超参的交互弱(地形平滑是机制保证的),沿用原值损失极小。三步序把 72 格网格压缩到 9 次实验,这背后是 3.3 机制二给出的确定性——学生训练对学习率的钝感是有理论根据的,不是侥幸。
变式。 多教师场景先对每位教师单独定温再合成(4.2);对抗蒸馏的 lam 是第四个旋钮,插在第二步与第三步之间扫,且始终以模仿损失不恶化为约束(4.4);课程表式 alpha 递增时,第三步的学习率调度要与课程节点对齐(升 alpha 的同时常有学习率衰减节点)。
⚠️ 常见坑:调参日志只记总损失。总损失是 alpha 加权后的混合物,软硬分量的此消彼长全被掩盖——三分量分开记录(本节体检面板的最小配置)是蒸馏训练日志的底线。
💡 关键直觉:调参顺序的本质是"按影响半径排序"。温度影响软损失的实际量级(半径最大),权重分配注意力(半径居中),学习率只影响收敛路径(半径最小且有机制兜底)。影响半径大的先定,小的后定,联动返工自然最少。