去年我做过一个特别有意思的项目,要用一个7B的小模型,去复刻一个70B大模型的代码生成效果。一开始我以为蒸馏很简单,不就是让大模型生成一堆样本,然后喂给小模型学吗?结果跑了两周,出来的小模型写代码还是漏洞百出,和大模型的输出差了十万八千里,连很多基础的函数调用都能写错。
那段时间我天天泡在实验室里,把大模型和小模型的每一层输出都拿出来对比,才发现自己之前完全理解错了知识蒸馏。我之前只让小模型学大模型的最终输出结果,相当于只让学生抄最后的答案,根本没让他学老师解题的中间思路,这样学出来的小模型,只会死记硬背,稍微遇到一点没见过的代码需求,立刻就懵了。
后来我改了思路,不再只盯着最终输出,而是做了“分层蒸馏”:首先让小模型的嵌入层,去模仿大模型嵌入层输出的向量分布,保证最开始的语义理解就和大模型对齐;然后中间的每一个注意力层,我都把大模型的注意力分布作为软标签,让小模型一点点学,不要求它完全一样,但是核心的注意力权重分布必须接近;最后才是输出层,除了最终的token概率,我还让小模型学习大模型生成的中间推理步骤,比如写代码之前的思路注释、变量定义的逻辑顺序。
为了做这件事,我特意写了个脚本,把大模型生成代码时的每一步中间隐藏层输出都存下来,前前后后攒了近10万条带完整中间信息的样本。那段时间服务器的硬盘都快被存满了,同事笑我“你这哪是做蒸馏,你是把大模型的脑子一层层扒开给小模型看”。没想到这么折腾完,效果直接超出了我的预期,最后训练出来的7B小模型,在HumanEval测试集上的通过率,比之前直接学最终结果的版本高了28%,很多场景下生成的代码,甚至和70B大模型的输出几乎看不出区别。
中间还有个意外的小收获,我本来以为蒸馏的时候温度参数设得越高越好,结果试了一圈才发现,不同层适合的温度根本不一样:底层语义层温度设到10效果最好,能让小模型学到更细的语义差别;上层推理层温度设到3就够了,温度太高反而会让小模型学一堆没用的噪声。这种细节,你不去一层层试,根本不可能从论文里直接看到。
我见过太多人做蒸馏,上来就找一堆大模型的输出样本,直接扔给小模型做有监督微调,然后就抱怨“蒸馏没用,小模型永远打不过大模型”。其实根本不是蒸馏没用,是你用的方法太粗糙了。大模型最值钱的根本不是它最后输出的那几句话,而是它在推理过程中,每一层隐藏层里藏着的“软知识”——那些它没说出来的、对不同语义的权重分配、对推理步骤的优先级判断,这些东西才是小模型真正要学的精华。
后来我把这个方法分享给了一个做法律AI的朋友,他用同样的分层蒸馏思路,让一个13B的小模型,几乎复刻出了70B大模型的法条理解能力,推理速度直接快了5倍,成本降了80%。他跟我说,之前他们租大模型的API,一个月光调用费就要十几万,现在用自己蒸馏出来的小模型,成本直接降到了之前的十分之一。
其实蒸馏这件事,本质上根本不是“学生抄老师答案”,而是让学生完整地学习老师的思考过程。你跳过中间步骤,只给学生看最终答案,他永远只能学到皮毛;你把老师每一步的思路都拆解开来,一点点教给他,小模型才能真正把大模型的能力“内化”成自己的东西。很多技术的精髓,从来都不在表面的公式里,而在你一点点抠细节、慢慢摸索出来的实操经验里。