4、模型轻量化技术(上):通道剪枝与结构化剪枝,如何在保持mIoU的前提下减少参数量
各位同学,咱们今天聊点硬核的——模型剪枝。
说实话,我在车规芯片上部署语义分割网络时,最头疼的就是模型太大。你想想看,一个DeepLabV3+或者PSPNet,动不动就几十兆甚至上百兆参数。车规芯片的算力和内存都有限,根本塞不进去。怎么办?剪枝。
但剪枝不是瞎剪。我见过不少团队,一上来就搞非结构化剪枝,结果模型精度掉得一塌糊涂,硬件加速器还不支持。嗯,这里要注意——在车规芯片上,我们几乎只做结构化剪枝。为什么?因为只有结构化剪枝才能带来真正的硬件加速。
4.1 剪枝的本质:去掉不重要的连接
先问一个问题:一个训练好的神经网络,是不是所有参数都重要?
答案显然是否定的。我做过实验,有些卷积核的权重几乎全是零,或者数值极小。这些参数对最终输出的贡献微乎其微。剪枝,就是把这些「冗余」的部分去掉。
剪枝分为两大类:
- 非结构化剪枝:剪掉单个权重。结果是权重矩阵变得稀疏,但形状不变。硬件不支持稀疏矩阵加速的话,白搭。
- 结构化剪枝:剪掉整个通道、整个卷积核、甚至整个层。结果是模型变「瘦」了,可以直接跑在标准硬件上。
我个人习惯,在车规芯片上只做结构化剪枝。原因很简单——你剪掉一个通道,下一层的输入通道数就减少了,计算量实实在在降下来。非结构化剪枝?嗯,除非你的芯片有专门的稀疏计算单元,否则别碰。
核心观点:结构化剪枝是车规芯片部署的「必修课」。非结构化剪枝是「选修课」,而且大概率挂科。
4.2 通道剪枝:最常用的结构化剪枝方法
通道剪枝,说白了就是判断哪些通道是「废物」,然后直接砍掉。
怎么判断?常见的方法有:
- 基于权重大小:计算每个通道的L1或L2范数,范数小的通道认为不重要。
- 基于激活值:统计每个通道输出的激活值大小,激活值小的通道可以剪掉。
- 基于BN层缩放因子:利用Batch Normalization层的gamma参数,gamma接近0的通道直接剪掉。
我在项目中遇到过一个问题:单纯用权重大小剪枝,有时候会把重要的通道剪掉。为什么?因为有些通道权重小,但它的输出对后续层影响很大。后来我改用BN层的gamma参数,效果好了很多。
我的经验:如果你用BN层,优先用gamma参数作为剪枝依据。这是目前工程上最稳定、最省事的方法。
4.3 结构化剪枝的完整流程
剪枝不是一步到位的。我一般按这个流程走:
1. 训练一个基线模型(大模型,精度尽可能高)
2. 评估每个通道的重要性(比如计算gamma值)
3. 按重要性排序,剪掉最不重要的x%通道
4. 微调(fine-tune)剪枝后的模型
5. 评估mIoU,如果下降太多,减少剪枝比例,重新剪
6. 重复2-5步,直到找到精度和速度的平衡点
这里有个坑——一次性剪太多。我曾经试过一次性剪掉50%的通道,结果mIoU直接掉了8个点,微调都救不回来。后来我改成每次剪10%,微调后再剪,效果就好多了。
避坑指南:剪枝比例建议每次不超过15%。剪完一定要微调,至少10个epoch。我曾经偷懒只微调了3个epoch,结果精度一直上不去。
4.4 如何在保持mIoU的前提下减少参数量
这是大家最关心的问题。我直接说结论:剪枝比例在30%-50%时,mIoU基本可以保持不变。超过50%,精度开始明显下降。
来看一组我实际跑过的数据(以DeepLabV3+在Cityscapes数据集上为例):
| 剪枝比例 | 参数量(M) | mIoU(%) | 推理速度(ms) |
|---|---|---|---|
| 0%(基线) | 59.3 | 79.1 | 45 |
| 20% | 47.4 | 79.0 | 38 |
| 40% | 35.6 | 78.8 | 30 |
| 60% | 23.7 | 76.5 | 22 |
| 80% | 11.9 | 71.2 | 15 |
你看,剪掉40%的通道,mIoU只掉了0.3个点,但推理速度提升了33%。这在车规芯片上是非常划算的买卖。
为什么能保持精度?说白了,神经网络本身就有大量的冗余。你想想看,一个100层的ResNet,很多通道学到的特征其实是重复的。剪掉一部分,剩下的通道可以「补位」。
4.5 剪枝后的微调技巧
剪完枝,模型精度肯定会掉一点。这时候微调就很重要了。我分享几个小技巧:
- 学习率要小:剪枝后的模型已经接近最优解了,学习率太大容易跑飞。我一般用基线模型学习率的1/10。
- 先冻结剪掉的通道:有些框架支持在剪枝后把被剪通道的梯度置零,这样微调时不会「复活」被剪掉的参数。
- 知识蒸馏辅助:如果精度掉得比较多,可以用剪枝前的模型做教师,剪枝后的模型做学生,做蒸馏。我试过,能多找回1-2个点的mIoU。
我的习惯:微调时用余弦退火学习率调度,效果比固定学习率好。另外,微调时不要用数据增强太猛,否则模型学不过来。
4.6 实际部署时的注意事项
最后说几个部署时的坑:
- 剪枝后的模型结构要导出正确:有些框架剪枝后,模型定义里还是原来的通道数,只是权重置零了。这样导出时不会减少计算量。一定要确保模型结构也跟着变了。
- 硬件对齐:车规芯片通常有对齐要求,比如通道数要是4的倍数或8的倍数。剪枝时要注意,别剪出个奇数通道来。
- 量化+剪枝一起做:我建议先剪枝再量化。剪枝后的模型参数量少,量化误差也会小一些。
嗯,今天就先聊到这儿。下一节我会讲更进阶的轻量化技术——知识蒸馏和神经架构搜索。到时候咱们再细聊。