从一个不太体面的现场说起
把训练好的模型搬到实际设备上,往往是整条链路里最琐碎的一环。训练时占着几张大卡的东西,落到产线机器、车载盒子或者一台旧笔记本上,跑不动就是跑不动。这时候工程师会打开工具箱:剪枝、量化、蒸馏,统称模型压缩。动作很快,参数少了一截,推理稳了,看上去问题解决了。
麻烦通常在之后几周才显形。有些请求答得和原来一样,有些却开始莫名其妙地出错,而且错得没什么规律。
误差不是均匀撒下去的
压缩的直觉是去掉不重要的部分,难点在于什么叫不重要。剪枝按权重绝对值挑,删掉数值小的连接,逻辑上说得通;但一个权重小,可能只是因为它接的那个输入很少被激活,一旦遇到没见过的输入,它也许刚好是关键的那根线。于是压缩带来的退化常常不是整体降一档,而是集中在某些边角场景里。
量化是另一回事。把浮点数换成低精度整数,等于给每个数字换了一把刻度粗一些的尺子,原本靠细微差别区分的输入,可能落到同一个刻度上。对结果离散的任务,这不算大问题;对需要输出连续数值或者长文本的任务,误差会一层层累加。
蒸馏绕不开的那个前提
知识蒸馏让小模型去模仿大模型的输出分布,常被当成把能力搬过去的办法。它的前提是:老师在这些样本上的判断值得学。如果训练数据覆盖不到真实场景,学生学到的其实是老师的偏好,连同偏好里的偏差。压缩不会凭空造出能力,它只能重新分配。
先想清楚哪类错误可以接受
所以做模型压缩,第一步不是挑算法,而是把失败成本摊开看。同一个模型,用在自动生成的商品描述上,错一句顶多尴尬;用在对账、告警或者设备控制上,错一次的代价完全不同。前者可以压得激进,后者得留足余量,甚至接受体积压不下来。
- 先定场景:哪些输入一定会出现,哪些只是理论上可能出现。
- 再定指标:不只看平均准确率,要看边角样本上的表现。
- 最后定回退:压缩版本出问题时能不能切回原模型,或者给低置信度的结果加一道人工确认。
它是一门取舍的手艺
模型压缩真正难的地方,不在于把体积做小,而在于说清楚小了之后这个版本还能干什么。很多部署事故不是因为压得太狠,而是因为没人写过这句话,于是一个在实验室指标上过得去的版本,被直接推到了它没见过的输入面前。
我倾向于把压缩看成一次重新声明边界的机会:模型能做什么、不能做什么,在这时候被迫写清楚。省下来的显存和延迟是真的,丢掉的那部分能力也是真的,只是它不会在第一步就告诉你。