设想这样一个处境:设备是离线的,识别效果已经调到能用,唯一的麻烦是内存里腾不出位置给完整模型。产品那边问的是“能不能砍掉一半”,工程师心里清楚,砍掉的部分可能包含边缘口音的识别能力,也可能只是一些从来不起作用的冗余权重。这两者的区别,决定了压缩之后是勉强能用,还是当场崩掉。
「模型压缩」听起来像是把文件打包变小,实际更像一次关于误差的重新分配:从哪儿省、省多少、把代价挪到哪一段输入上。
先分清冗余和有用
剪枝的直觉很简单——权重里存在大量接近零的值,去掉似乎无伤大雅。但决定成败的往往不是“去掉多少”,而是去掉之后有没有重新训练。一次性硬剪,网络结构被破坏却来不及适应,效果掉得比预想快;剪完再微调,剩下的参数被推着去接管原来的分工,能补回一部分损失。结构化的剪枝对硬件更友好,压缩率却更保守;细粒度剪枝压得狠,很多推理框架未必领情,省下的稀疏度可能换不来实际加速。
量化省下的是带宽
把浮点权重换成低位整数,最直接的好处通常不是算力,而是内存带宽和缓存的占用。移动端推理常常卡在数据搬运上,权重变小,访存压力随之下降。麻烦在于激活值里的离群点:个别数值特别大,量化尺度被它们撑开,其余数值就挤在很窄的区间里,精度损失集中在这类位置。校准集挑得不对,量化后的模型在实验室里跑得好,换一批真实输入就开始飘。
蒸馏转移的是行为
让小模型去学大模型的输出分布,本质上是把“答案”连同“犹豫的程度”一起搬过去。软标签携带的信息比硬标签多,但这份信息与大模型见过的数据分布绑定。学生模型的容量若撑不住,学到的可能只是表面模仿;下游任务的数据分布一变,原来被压平的错误就会重新冒出来。
这几条路经常被当成互斥选项,工程里更多是叠加使用:先蒸馏得到小结构,再量化降低访存,最后视部署框架决定要不要剪枝。模型压缩很少是一次性动作,每一次叠加都要重新评估,因为误差会累积,而累积的方式并不线性。
压缩之前先问清楚约束
延迟、内存、功耗、精度,这四个约束里通常只能优先照顾一两个。想清楚哪个是硬指标,再挑手段,比先定一个压缩比例然后硬凑要省事。评测集也值得重新看一遍:如果线上输入以方言、噪声、短句为主,用标准测试集挑出来的配置,参考价值有限。
模型压缩真正难的地方,不在算法本身,而在于判断哪些能力可以放弃。这个判断没法完全交给工具,还得有人对着真实场景一条条翻错误样本。