2.2 思考的过程:基于特征的蒸馏 本节摘要:特征蒸馏让学生对齐教师中间层的特征表示——不只学结论,还学推导过程。本节讲清 hint 层与引导层的配对方式、维度适配层的用法、对齐位置的选择,以及特征蒸馏相对响应蒸馏多教了什么、何时值得上。 响应蒸馏只用教师最后一句话,本节走进师傅的书房,看他草稿纸上的中间演算。在全册知识形态序列里,特征蒸馏是第二站:教材从输出层下沉到中间层。 草稿纸上的知识 教师的中间层特征是它对输入的"阶段性理解":浅层记录边缘纹理,中层记录部件模式,深层记录整图语义。学生如果只对齐最终输出,等于只看老师的结论;对齐中间特征,则是把老师每个推导步骤都临一遍。
本节摘要:特征蒸馏让学生对齐教师中间层的特征表示——不只学结论,还学推导过程。本节讲清 hint 层与引导层的配对方式、维度适配层的用法、对齐位置的选择,以及特征蒸馏相对响应蒸馏多教了什么、何时值得上。
响应蒸馏只用教师最后一句话,本节走进师傅的书房,看他草稿纸上的中间演算。在全册知识形态序列里,特征蒸馏是第二站:教材从输出层下沉到中间层。
教师的中间层特征是它对输入的"阶段性理解":浅层记录边缘纹理,中层记录部件模式,深层记录整图语义。学生如果只对齐最终输出,等于只看老师的结论;对齐中间特征,则是把老师每个推导步骤都临一遍。对检测、分割这类输出依赖丰富空间结构的任务,中间特征的质量直接决定下游头部的成色,特征蒸馏的收益因此比分类任务上更显著。
经典方案 FitNets 给了两个沿用至今的术语:从教师中间挑出来当教学材料的层叫 hint 层,学生侧负责模仿它的层叫引导层。两者维度往往不同——教师 256 通道、学生 64 通道是常态——中间插一层适配(1x1 卷积或线性投影)把引导层的输出投到 hint 层的形状上,再算均方误差。
import torch import torch.nn as nn import torch.nn.functional as F class FeatureDistill(nn.Module): """带适配层的特征蒸馏组件。""" def __init__(self, s_channels, t_channels): super().__init__() # 适配层:把学生通道数投到教师通道数,1x1 卷积保持空间尺寸不变 self.adapt = nn.Conv2d(s_channels, t_channels, kernel_size=1) self.mse = nn.MSELoss() def forward(self, s_feat, t_feat): # s_feat、t_feat 分别来自学生引导层与教师 hint 层 # 形状均为 B x C x H x W,空间尺寸需一致 return self.mse(self.adapt(s_feat), t_feat) s_feat = torch.randn(8, 64, 28, 28) # 学生某中间层 t_feat = torch.randn(8, 256, 28, 28) # 教师 hint 层 crit = FeatureDistill(64, 256) print("特征蒸馏损失:", crit(s_feat, t_feat).item()) # 输出示例: # 特征蒸馏损失: 0.9998
hint 层选在哪一层,决定了教材的抽象粒度。太靠前,教的是边缘纹理这类"小学算术",学生自己也能学;太靠后,特征已经高度任务化、与输出几乎重合,信息增量有限。经验做法有两条路:
还有一个工程判断:不必逐点强求一致,改学"统计面貌"。注意力迁移(AT)把特征图的空间平方和当作教师的"注意力地图"让学生学;正交性、Gram 矩阵等统计量也在同类方法中使用。它们对师生结构差异更宽容,往往比裸 MSE 更稳。

背景。 团队有一个服务端检测模型,mAP 52.3,要为边缘盒子产出一个轻量学生,目标 mAP 不低于 46。检测任务输出依赖空间特征,判断特征蒸馏比纯响应蒸馏更对症。
操作。 响应蒸馏在检测任务上没有天然的单点分布可对齐,方案改走特征路:在教师与学生各自的骨干网络中按深度取三段 hint 引导配对,浅段权重 1、中段 4、深段 8(越深越贴近任务语义),每段先做 1x1 适配再算 MSE;另叠加检测头输出的分类分支软化(任务内响应蒸馏),温度 2。训练数据为常规检测集,alpha 设为特征损失占 0.6、任务损失占 0.4。
结果。 学生先只做任务训练得 mAP 42.1;加响应式分类分支蒸馏到 43.8;再加三段特征对齐到 46.2,达标。特征蒸馏单独贡献 2.4 个 mAP,超过响应部分。
解读。 检测与分类的对比印证了开头的判断:输出结构越复杂、越依赖空间表示,中间特征的教材价值越高。另外注意浅段权重的处理——纹理层面的对齐信息量低且容易与任务损失打架,压低权重(本例浅段 1 对深段 8)是常见做法;全段等权训练时学生 mAP 反而掉了 0.4。
变式。 师生结构差异过大(如 Transformer 教卷积学生)时,空间尺寸与通道都难对齐,可改学统计面貌:把特征图的空间注意力图(通道平方和)作为对齐目标,尺寸无关;多段对齐段数从 3 加到 5 通常收益递减,别贪多;特征归一化(按通道做 L2 归一化再算距离)能缓解师生特征幅值不一致的问题。
# 注意力迁移(AT)损失:学"教师看哪里",不逐点抄特征值 import torch import torch.nn.functional as F def attention_transfer_loss(s_feat, t_feat): # 空间注意力图:通道维平方求和,得到 B x H x W 的显著图 a_s = s_feat.pow(2).sum(dim=1) # 学生注意力 a_t = t_feat.pow(2).sum(dim=1) # 教师注意力 # 各自归一化成和为 1 的分布,消除幅值差异 a_s = a_s.flatten(1) a_s = a_s / a_s.sum(dim=1, keepdim=True).clamp_min(1e-8) a_t = a_t.flatten(1) a_t = a_t / a_t.sum(dim=1, keepdim=True).clamp_min(1e-8) return (a_s - a_t).pow(2).mean() # 输出说明:返回标量损失。即使师生特征图尺寸不同, # 也可以在 flatten 前先做一次插值缩放对齐,比逐点 MSE 宽容得多。
⚠️ 常见坑:学生与教师的特征幅值尺度差数倍时直接算 MSE,损失会被幅值差主导,学生把全部容量花在"把特征放大到教师那个量级"上。先归一化再对齐,或把 hint 层换成 BN 之后的输出。
💡 关键直觉:特征蒸馏教的是"在哪个区域看什么"。如果你能说出任务里"看哪里"很重要(检测的物体区域、分割的前景边缘),特征蒸馏大概率值得上;如果任务只看整体类别,响应蒸馏通常够用。