ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

蒸馏与微调结合:将大模型能力浓缩为轻量可部署模型

蒸馏与微调结合:将大模型能力浓缩为轻量可部署模型

很多刚接触大模型的朋友会有一个错觉:参数量越大,模型就越聪明。但实际上,部署一个百亿级参数模型和训练一个百亿级参数模型是两件完全不同的事情。你需要的可能只是一个能准确识别几十类工业缺陷的轻量模型,却被迫端着一个大模型的架子,推理慢、显存吃紧、上线周期长。我早期做项目时也踩过类似的坑,后来把模型蒸馏和微调结合起来用,才算真正把"大模型的能力"和"小模型的体积"这对矛盾给调顺了。

这篇文章不打算给你讲一堆花哨的理论,我会直接把这些年在实际任务里蒸馏与微调结合应用的思路、流程、参数细节和踩坑记录都摊开来说。包括知识蒸馏的软标签到底怎么用,微调阶段的损失权重怎么配,以及在图像分类、文本分类这类常见场景里,怎么把两条技术路线合在一起还能稳定收敛。如果你手头正好有一个预训练大模型,想把它浓缩成能上线的轻量模型,这篇文章应该能帮你少走不少弯路。

需要先明确一点:蒸馏和微调不是竞争关系,而是两个可以叠加的技术手段。蒸馏负责把大模型的泛化能力转移到小模型,微调负责让小模型在特定任务上有更好的表现。两者结合的时候,顺序、权重、数据配比都会影响最终效果。下面我用自己的实操经验,把这套组合拳拆开讲。

1. 蒸馏与微调:两个概念的正确打开方式

1.1 知识蒸馏是什么:不是压缩,是"传承"

很多人把知识蒸馏单纯理解成"把小模型压扁",这是不对的。蒸馏的核心在于把大模型输出概率分布中的知识提取出来,传给小模型。比如一个图像分类模型,你给它一张猫的照片,它的输出不只是"猫=0.9,狗=0.1",可能还有"狐狸=0.4,兔子=0.2"这样的暗信息。这些暗信息里包含了大模型对类别相似性的理解,这种理解比单纯的正确标签要丰富得多。

蒸馏就是让小模型去模仿大模型的概率分布,而不仅仅是模仿最终的硬标签。为了实现这一点,通常会在Softmax里加一个温度系数T,先把输出概率变得平滑,让小模型能看清大模型在类别之间微妙的排序。温度越高,概率分布越平缓,暗信息越明显;温度越低,越接近one-hot。实际操作中,我们会同时计算小模型和教师模型在高温下的软标签损失,再加上小模型和真实硬标签的损失,两者按权重混合。

我在第一次做蒸馏时犯过一个典型错误:只盯着硬标签的正确率,忽略了软标签里的排序信息。后来发现模型在某些容易混淆的类别上总是出错,比如区分狼和哈士奇。加了软标签损失后,学生模型学到了教师模型对这两个类别的犹豫程度,准确率直接上了一个台阶。

1.2 微调的本质:让预训练模型"换岗"

微调则是另一个层面的技术。预训练模型在大量通用数据上学会了语言或视觉的基本规律,但你要让它做某个专属任务,比如识别医疗器械上的批号、判断客服工单的情感倾向,就需要用这个任务的标注数据去调整它。微调的妙处在于,不需要从头训练,只需要在预训练权重的基础上继续迭代,用很少的数据量就能达到不错的效果。

这背后的逻辑是,预训练阶段学到的特征表示是通用的,比如边缘、纹理、语法结构;微调阶段则激活这些通用特征中与目标任务相关的部分。我用某开源视觉模型做实验时,原本在通用数据集上只做分类头微调,准确率不算理想。后来把整个骨干网络都放开微调,虽然训练时间变久了,但模型确实更贴合我自己的数据分布。

微调最怕的是数据量太小导致过拟合,或者学习率设置太大导致预训练知识被冲刷掉。所以微调通常在较低学习率下进行,一般只有预训练阶段的十分之一甚至百分之一。这也是后面蒸馏与微调结合时需要注意的关键点。

1.3 为什么要结合:蒸馏解决效率,微调解决适配

分开看,蒸馏能解决模型体积和推理效率问题,微调能解决任务适配问题。但把它们放在一起用,有一个很实际的好处:如果你先把大模型在目标任务上微调好,再蒸馏给学生模型,那么学生模型学到的不只是通用知识,还包括了大模型针对这个任务专门调整过的决策偏好。这种思路特别适合那些"大模型很好用,但就是跑不动"的场景。

反过来,如果你先蒸馏再微调,也就是先让学生模型在通用数据上学习大模型的软标签,然后再用任务数据微调,这种方式更省钱。但问题在于,学生模型从大模型那里继承的知识是通用的,针对具体任务的判别能力可能不足,微调时需要更多任务数据来补偿。

我自己的体会是,大多数实际项目应该采用"先微调教师,再蒸馏学生,最后视情况微调学生"的组合路线。因为真正的瓶颈通常有两个:一是大模型不够贴合业务,二是小模型学不到大模型业务化之后的知识。只做蒸馏不做教师微调,等于让老师教学生一套和考试大纲无关的内容。

2. 结合应用的主流技术路线解析

2.1 先蒸馏后微调:小模型的拟合困境与补偿

先蒸馏后微调是一条看起来顺理成章的路线:第一步,用大模型作为教师,在通用数据或者无标注数据上指导学生模型蒸馏;第二步,用目标任务的数据微调学生模型。这样做的好处是阶段清晰、算力消耗容易控制,但现实往往不这么美好。

由于蒸馏阶段用的是通用数据,小模型学到的是大模型在广泛分布上的先验知识。可一旦进入微调阶段,任务数据的分布通常比较窄,比如你的任务只包含医疗影像中的病灶区域,或者客服对话里的特定意图,通用先验和任务分布会出现明显偏差。如果微调数据足够多,学生模型还能强行调整过来;如果数据量只有几千条,学生模型很容易被任务数据带偏,甚至把蒸馏阶段学到的通用特征覆盖掉,最终表现还不如直接微调一个大模型。

我做过一组对比实验:同一个学生模型,一条路径是先在大规模无标注数据上蒸馏,再在五千条任务数据上微调;另一条路径是直接用这五千条任务数据微调教师模型,再把教师模型的软标签蒸馏给学生。结果前者的分类准确率比后者低了大约3个百分点。原因就是纯蒸馏阶段没有接触到任务分布,学生模型在特征空间里离任务决策边界太远。

如果非要走先蒸馏后微调,我的建议是蒸馏阶段最好混入一部分目标任务的数据。哪怕是没标注的数据也行,蒸馏本来就不需要硬标签,只要有教师模型的软输出就够了。这样能让学生模型在蒸馏阶段就提前感知目标域的特性,后续微调时不会觉得数据陌生。

2.2 先微调后蒸馏:学生学什么更关键

先微调后蒸馏是我更推荐的做法。这里的"先微调"指的是微调教师模型,而不是学生模型。你先把大模型在目标任务上微调,让它变成这个领域的专家,然后再用它做教师,去蒸馏学生模型。这样学生模型学到的知识直接就是教师模型在目标域上提炼后的决策逻辑,自然更贴合任务。

但这条路线有个关键点:教师模型的微调质量决定了蒸馏的上限。微调得太狠,教师模型会过拟合训练集,输出概率分布过于尖锐,软标签里几乎没有暗信息;微调得太轻,教师模型对目标域的偏好又不够鲜明,学生模型学到的东西和平淡的通用教师没什么区别。我一般在微调教师时保留一个验证集,看教师模型在验证集上的置信度分布,如果是那种大多数样本都以接近1的概率给出单一类别,我反而会降低训练轮数或者调高温度来重新生成软标签。

学生模型在这个阶段要学什么也很讲究。它不是简单复现教师模型的预测结果,而是要学到教师模型在类别边界上的"不确定性分布"。例如,教师模型在区分两个相近类别时,即便最后选了A,但它给B的概率可能也有0.3,这个0.3对小模型来说就是宝贵的线索。我会把软标签损失权重设置得比硬标签损失更高,通常取0.8比0.2,这样学生模型会更认真地模仿教师的不确定性,而不是急着去拟合常规标注。

2.3 在线蒸馏与微调同步进行:一步到位的增量训练

除了前面两条离线路线,还有一条更激进的在线路线:教师模型和学生模型同时训练,一边训练一边蒸馏。这种方式适合知识蒸馏数据流实时更新或标签不断变化的场景。比如一个新的推荐系统,用户反馈在实时回流,教师模型每小时甚至每分钟都在更新,蒸馏标签也在变,离线蒸馏根本跟不上节奏。

在线蒸馏的做法是让教师模型和学生模型共享同一个训练批次:教师模型用自己的预测软标签指导学生模型,同时教师和学生各自又根据真实标签计算硬损失。训练过程中还可以动态调整蒸馏损失的权重,一开始让学生多学教师,后期逐步减少蒸馏权重,让学生自己探索任务边界。我在序列推荐任务里试过这种策略,效果比固定权重稳定很多。

不过在线蒸馏对工程实现的要求更高。教师模型和学生模型同时前向和反向传播,显存占用会明显增加,训练速度也会变慢。实际部署时,我通常会用梯度累积和混合精度来缓解显存压力。另外,教师模型最好定期做指数滑动平均,避免教师模型参数剧烈波动导致蒸馏标签噪声过大。同步进行的模式适合训练资源比较充足、数据动态变化的场景;如果数据是静态的,离线蒸馏的性价比通常更高。

3. 实操:一个轻量级图像分类场景的完整案例

3.1 场景设定与教师模型选择

为了把前面这些思路落到可操作的层面,这里我拿一个完全虚构的工业质检图像分类任务来演示。假设生产线上有六种不同外观的零部件,我们需要让一个轻量级模型在嵌入式设备上实时完成分类。硬件上只有大约1GB内存,单张图片推理时间不能超过15毫秒。直接部署大模型不现实,所以我决定采用蒸馏加微调的组合方案。

第一阶段,我会选择一个在大型公开数据集上预训练的图像分类模型作为教师。选型时优先要考虑三点:一是模型在通用特征上的表征能力要强;二是模型参数尽量不超过500MB,因为还要在训练服务器上留出微调和蒸馏的资源;三是模型的输出层要和任务类别数兼容,如果不兼容,可以替换掉分类头再做微调。我通常用某公司发布的视觉Transformer和某经典的卷积网络都试一遍,以验证集准确率和推理速度的平衡作为选择标准。

最终我选用了一个参数量约三百万的轻量卷积网络作为学生模型,教师模型则是参数量约二千万的视觉Transformer。这个差距挺大,但正好符合"大模型做老师,小模型做学生"的实际设定。教师模型在目标任务验证集上的准确率能达到98.6%,学生模型从头训练只有91.2%,差别很明显,所以蒸馏的价值空间也非常大。

3.2 数据准备与软标签生成细节

数据准备阶段,我总共收集了多少条图像呢?这里我假设有两万张已标注图片和八万张无标注图片。已标注图片用于微调教师模型和最后微调学生模型,无标注图片用于蒸馏阶段让学生模型模仿教师模型的输出。这个设计很关键:如果只有两万张标注图,直接去训练小模型很难泛化;但加上八万张无标注图,相当于教师模型给这些图片打上了软标签,学生模型的训练数据瞬间多了四倍。

软标签生成不是简单让教师模型推断一次就行。我在生成软标签时设置了温度T=3,让概率分布足够平滑。以六分类为例,一张图教师模型给出的硬标签是类别2,但它的原始输出可能是类别2为0.7、类别5为0.2、类别3为0.08,其他类别加起来约0.02。使用T=3后,这些概率差距会被拉平一些,学生模型就能捕捉到"类别2和类别5有点相似"这种信息。

具体实现时,我会把推断过程写成批量处理,并且加上数据增强。同一张图片做旋转、裁剪、色彩抖动之后,教师模型的软标签可能会略有变化,这些变化其实相当于一种自洽的正则化,能帮助学生模型学到更稳健的特征。不过操作时要注意,数据增强的强度不能太大,否则教师模型对严重变形的图片给出的软标签也会失真。

3.3 学生模型架构选择与损失函数设计

学生模型的选择上,"轻量"不等于"随便缩水"。我踩过用过于简单的两层卷积网络做学生模型的坑,那种模型根本没有足够容量去拟合教师模型的软标签,蒸馏损失会一直降不下去。通常我会选择MobileNetV2、EfficientNet-lite或者轻量ViT这类专门为边缘端设计的架构。

损失函数设计是蒸馏加微调和普通蒸馏最大的区别。在蒸馏阶段,我采用了两个损失之和:一个是学生模型经过温度T缩放后与教师模型软标签的KL散度,另一个是学生模型与真实硬标签的交叉熵。公式大致如下:

  • L_distill = KL(softmax(student_logits / T), softmax(teacher_logits / T)) * T²
  • L_task = CrossEntropy(student_logits, ground_truth)
  • L_total = α * L_distill + (1 - α) * L_task

其中T²这个系数需要特别注意,因为logits除以T之后,梯度会被缩放,乘回T²才能保证梯度量级与温度无关。我在实践里没有用T²的话,温度从1调到5时损失数值变化非常剧烈,模型非常不稳定;加上T²之后,不同温度下只要微调α就能顺利收敛。

关于α的取值,我的经验是蒸馏阶段α设为0.7到0.9,让模型优先模仿教师。到了微调阶段,如果仍然沿用蒸馏损失,α要降到0.2以下,因为此时更需要让模型集中拟合真实任务标签,防止教师模型的偶发错误被放大。

3.4 训练参数与调优经验

训练参数这块,我是这么设置的。教师模型微调阶段使用AdamW优化器,初始学习率5e-5,权重衰减0.01,批量大小64,训练20个epoch。由于教师模型参数量比较大,我在微调时冻结了前面三层特征提取层,只放开后面六层和分类头,这样既能保住通用特征,又能适应目标域。这种做法针对目标任务数据量不大时特别有效。

学生模型蒸馏阶段,初始学习率我设成1e-3,比教师微调阶段高不少,因为学生模型是从随机初始化开始,需要更快学习。但这里有个坑:学习率太大,学生模型会只顾着拟合硬标签,KL散度损失贡献很小;学习率太小,蒸馏温度较高时收敛又非常慢。我的做法是先跑10个epoch,观察KL散度和硬标签准确率的变化,如果硬标签准确率涨得很快但KL散度一动不动,我就把α升高、学习率适当降低。最终蒸馏阶段跑了40个epoch,KL散度从最初的0.8逐步降到0.12,硬标签准确率到了93%,但和教师模型的98.6%还有距离。

接着做学生模型微调阶段。此时学习率要降到2e-4,批量大小减到32,只训练15个epoch。因为蒸馏阶段已经把学生模型的基本特征训练出来了,微调更像是在原有基础上做精调整。我还会用早停法监控验证集准确率,防止微调后期过拟合训练集。最终量化到INT8后,模型在验证集上的准确率达到95.4%,推理时间单张图大概8毫秒,完全满足硬件要求。

下面是我在这个案例里的最终训练配置表,可以作为一个参考模板:

阶段教师微调学生蒸馏学生微调
模型视觉Transformer轻量卷积网络轻量卷积网络
优化器AdamWAdamAdamW
学习率5e-51e-32e-4
批量大小6412832
训练轮数204015
蒸馏温度131
蒸馏权重α-0.80.15
数据量2万标注图8万无标注图+2万标注图2万标注图

4. 我踩过的坑:蒸馏与微调结合时的常见问题与排查

4.1 教师模型过强导致学生崩塌

第一个坑就是教师模型比学生模型强太多,蒸馏效果反而变差。我在另一个项目里试着把百亿参数级别的教师模型蒸馏给一个只有几百万参数的模型,结果学生模型的最终准确率甚至不如直接用相同数据训练的小模型。原因在于教师模型的表达能力远超学生模型,它输出概率分布里的暗信息过于复杂,学生模型完全消化不了,只有勉强模仿的表面动作,反而丢了硬标签的确定性。

解决思路有两个。一是放宽蒸馏温度,把T从3调低到1或者2,让软标签更接近硬标签,降低学生模型的学习负担。二是缩短教师模型和学生模型之间的距离,比如先把教师模型削减到参数量是学生的三到五倍以内,再去做蒸馏。这听起来像"折中",但实际效果往往比直接蒸馏强很多。我在比较方案后,发现把教师模型从视觉Transformer换成更大的卷积网络之后,学生模型的收敛速度和最终精度都更好了。

4.2 微调数据与蒸馏数据分布不一致

第二个坑是教师微调用的数据和蒸馏阶段无标注数据的分布不一致。工业场景中,无标注图片可能来自不同型号的产品线,而有标注图片可能只来自其中一种型号。如果教师模型在型号A的标注数据上微调,但蒸馏阶段让学生模型去学习型号B的无标注图片的软标签,学生模型会被教师模型中关于型号B的泛化不足带偏,最终在型号A上表现也下降。

我在实际项目里用领域差异检测工具对比了两批数据的特征分布,发现分布偏移很明显。后来我调整了采样策略,在蒸馏阶段按比例混入两个型号的数据,再根据负责的具体设备做针对性微调。经过这轮操作,学生模型在型号A和型号B上的准确率分别回升了4%和2%。所以无论走哪条蒸馏路线,都要先检查数据分布的一致性,实在不一致就分层采样,别让模型自己靠瞎猜去弥合差异。

4.3 损失函数配比失衡

蒸馏加微调其实包含了至少两个损失项,配比失衡非常常见。如果你把α设成0.9,学生模型会非常努力地模仿教师模型,甚至教师模型在个别样本上给出明显错误的高概率时,学生模型也会照单全收。但如果α设成0.2,学生模型又几乎放弃软标签,变成纯微调小模型,前期蒸馏就白做了。

我的调法比较笨但有效:先固定温度,然后对α做一个网格搜索。候选值是0.3、0.5、0.7、0.9,每个值训练5个epoch,看验证集准确率和KL散度变化。我最后一次项目里找到的合适配比是α=0.7,温度T=3。不过这个配比不是固定的,如果你发现验证集上模型对容易混淆的类别准确率很低,可以把α调高一些,强化教师暗信息的权重;如果你发现模型在硬标签上都无法收敛,说明α太高了,需要降低。

4.4 参数量差距过大时的冷启动技巧

还有一个比较隐蔽的坑:当教师模型和学生模型参数差距过大时,学生模型在蒸馏初期会出现冷启动困难。因为学生模型随机初始化时的输出概率分布非常均匀,和教师模型平滑的软标签分布差距反而没那么大,但随着训练推进,如果学习率过大,学生模型会先偏向硬标签拟合,把KL散度丢到一边。表现出来就是前几个epoch硬标签准确率上涨非常快,但KL散度卡在0.6以上不下来。

我的冷启动技巧是引入一个预热阶段:前几个epoch只做蒸馏损失,忽略硬标签损失,同时把学习率线性地从零升到目标值。这样学生模型先专注模仿教师模型的软标签,把特征空间的大致走向建立起来,然后再加硬标签损失,让模型更靠近任务决策边界。这个技巧在我之后多个蒸馏任务里都带来了明显提升,非常建议去试一次。

4.5 常见问题速查表

问题表现可能原因排查方向
学生模型蒸馏后准确率低于直接训练小模型教师模型过强/温度不当/蒸馏权重不合理调低温度、减小教师容量、网格搜索α
KL散度一直不降学习率过大或预热缺失降低学习率、引入蒸馏损失预热阶段
微调后期验证集准确率下降微调数据不足且学习率偏高导致过拟合降低学习率、加入早停、增加正则化
真实业务场景效果差,验证集却不错训练数据分布和真实分布不一致分层采样、补充边缘样本、用教师模型输出诊断
小模型在容易混淆类别上表现差蒸馏时暗信息没学好升高蒸馏温度、增大α、在相似类别上做难例挖掘
在线蒸馏训练显存不足教师和学生同时前向反向使用梯度累积、混合精度、降低批量大小

经验总结:这套组合拳的关键还是"适配"

把这个"AI模型蒸馏与微调的结合应用"做完整之后,我最大的感受是,所有技术细节最终都指向一个词:适配。蒸馏温度要适配教师模型和学生模型之间的差距,损失函数配比要适配数据分布,微调策略要适配任务本身的特点。没有一套固定参数能通吃所有场景,但掌握好了适配的逻辑,你就能在具体任务里快速找到属于自己的最优配置。

如果你现在正打算做蒸馏加微调,我的建议是先别急着写代码。花一天时间把你的教师模型、学生模型、数据分布、温度系数、损失权重这几个关键变量列出来,设计好验证实验,然后再动手。训练过程中一定要把每个阶段的软标签、准确率、KL散度曲线记录下来,哪怕最后效果不好,也能靠这些日志定位到具体环节的问题。最后再分享一个小技巧:在蒸馏阶段给学生模型的底层特征加一点特征对齐损失,也就是让学生模型中间层的特征和教师模型对应层的特征做L2距离约束。这个方法在很多任务里都能再帮你提一两个点的准确率,非常划算。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进