3. 模型剪枝技术
模型剪枝,说白了就是给神经网络「减肥」。
我刚开始接触剪枝时,觉得这玩意儿挺玄乎——把模型里的参数砍掉一部分,精度居然还能保住?后来踩过几次坑才明白,剪枝的本质是剔除冗余连接。神经网络里很多参数其实贡献很小,就像公司里混日子的员工,裁掉他们,公司照样运转。
3.1 非结构化剪枝:细粒度但难落地
非结构化剪枝,也叫权重级剪枝。它直接干掉单个权重值。
举个例子,一个卷积核是 3x3 的矩阵:
原始权重:
[[0.8, 0.1, 0.6],
[0.0, 0.9, 0.2],
[0.7, 0.0, 0.5]]
剪枝后(阈值 0.3):
[[0.8, 0.0, 0.6],
[0.0, 0.9, 0.0],
[0.7, 0.0, 0.5]]
看到没?小于 0.3 的权重直接变零。这种剪枝粒度最细,理论上压缩率可以很高。
优点:精度损失小,灵活度高。
缺点:权重变成稀疏矩阵,普通硬件加速不了。你得用专门的稀疏计算库,比如 NVIDIA 的 cuSPARSE。
我在项目中遇到过一个问题:非结构化剪枝后模型文件确实变小了,但推理速度反而变慢。为什么?因为 CPU/GPU 对密集矩阵计算做了深度优化,稀疏矩阵反而破坏了缓存局部性。嗯,这里要注意——非结构化剪枝更适合学术研究,工业落地慎用。
3.2 结构化剪枝:工业界的宠儿
结构化剪枝是整块整块地砍。常见的有:
- 通道级剪枝:直接干掉整个通道(比如 64 个通道砍成 32 个)
- 层级剪枝:直接删掉整个网络层
- 滤波器级剪枝:砍掉整个卷积核
你想想看,通道级剪枝后,网络结构还是规整的,矩阵运算依然密集。硬件跑起来毫无压力。
我的建议:工业项目首选通道级剪枝。它平衡了压缩率和加速效果,而且实现起来不复杂。
我曾经在一个目标检测项目里试过层级剪枝,直接把 ResNet 的某个 block 删掉了。结果精度掉了 15 个点,回炉重造了一周。后来我学乖了——层级剪枝风险太大,除非你的网络确实冗余严重,否则别碰。
3.3 剪枝的粒度对比
| 粒度 | 压缩率 | 加速效果 | 精度损失 | 硬件友好度 |
|---|---|---|---|---|
| 权重级 | 高 | 低(需稀疏加速) | 低 | 差 |
| 通道级 | 中 | 高 | 中 | 好 |
| 层级 | 高 | 高 | 高 | 好 |
从表格能看出来,通道级剪枝是「性价比之王」。我个人习惯优先考虑它。
3.4 剪枝后的微调策略
剪枝完不微调?那精度大概率崩给你看。
微调的核心思路是:让剩下的参数重新适应数据分布。我常用的策略有三种:
- 全局微调:用原始学习率的 1/10,对整个网络训练几个 epoch。适合剪枝率不高的情况。
- 逐层微调:先固定其他层,只微调被剪的那一层。我试过,收敛更快,但操作麻烦。
- 知识蒸馏辅助:用原始大模型当老师,剪枝后的小模型当学生。精度恢复效果最好,但训练成本高。
注意:微调时千万别用太大的学习率。我曾经设了 0.01,结果 loss 直接飞到天上,模型彻底废了。建议从 1e-4 起步,慢慢试探。
3.5 我在项目中遇到的剪枝失效案例
讲个真实案例吧。
去年做一个语音识别模型,我用了非结构化剪枝,剪掉了 70% 的权重。模型大小从 200MB 降到了 60MB,心里美滋滋。结果一上手机端推理,延迟反而从 50ms 涨到了 120ms。
排查了两天,发现原因:
- 手机端的 CPU 不支持稀疏矩阵加速
- 权重虽然稀疏了,但存储格式没变,计算时还是按密集矩阵处理
- 大量的零值乘加操作白白浪费了算力
后来我换成通道级剪枝,剪掉 50% 的通道,模型大小降到 100MB,延迟降到 30ms。精度只掉了 0.5%。
这个教训让我明白:剪枝方案一定要跟部署硬件匹配。别光看压缩率,还得看实际推理速度。
3.6 知识体系总览
下面这张图总结了本章的核心逻辑:
这张图把剪枝技术分成了三大块:非结构化、结构化和微调策略。你顺着箭头看,就能理清它们之间的关系。
一句话总结:剪枝不是玄学,是工程。选对粒度、配好微调、测准硬件,你也能做出又快又准的模型。