4. 模型轻量化技术(上):通道剪枝原理、结构化剪枝 vs 非结构化剪枝、我在剪枝项目中踩过的坑
模型剪枝,说白了就是给神经网络“瘦身”。你想想看,一个训练好的大模型里,其实有很多参数是冗余的。去掉它们,模型照样能跑,而且跑得更快。我在做嵌入式部署时,剪枝几乎是必过的一关。
但剪枝不是简单地把权重砍掉。砍错了地方,精度会断崖式下跌。这一讲,我们先从最基础的通道剪枝原理讲起,再对比两种主流剪枝策略,最后聊聊我踩过的那些坑。
4.1 通道剪枝:最实用的轻量化手段
通道剪枝,也叫滤波器剪枝。它直接干掉卷积层里不重要的输出通道。为什么说它实用?因为剪掉一个通道,后续所有层的计算量都会减少,硬件实现也特别友好。
核心思路就三步:
- 评估重要性:给每个通道打个分,判断它对最终结果贡献多大。
- 剪掉低分通道:设定一个阈值或比例,把不重要的通道移除。
- 微调恢复:剪完后模型精度会掉,需要小学习率再训几轮。
评估重要性有很多方法。我个人习惯用 BN 层的缩放因子 γ。训练时给每个通道的 γ 加一个 L1 正则,训练结束后 γ 值小的通道就是不重要的。这个方法简单,效果也不错。
通道剪枝的关键公式
BN 层输出:y = γ * (x - μ) / √(σ² + ε) + β
γ 越小,说明该通道对后续层的影响越弱,优先剪掉。
4.2 结构化剪枝 vs 非结构化剪枝
这两种剪枝方式,本质区别在于“剪完后的模型结构是否规整”。
| 对比维度 | 结构化剪枝 | 非结构化剪枝 |
|---|---|---|
| 剪枝粒度 | 通道、滤波器、层 | 单个权重 |
| 模型结构 | 保持规整,通道数减少 | 变得稀疏,不规则 |
| 硬件加速 | 直接支持,无需特殊库 | 需要稀疏矩阵库或专用硬件 |
| 压缩率上限 | 中等(通常 2x-4x) | 高(可达 10x 以上) |
| 精度恢复难度 | 较低,微调几轮即可 | 较高,需要更精细的微调策略 |
| 嵌入式部署 | 推荐,兼容性好 | 不推荐,除非有专用 NPU |
结构化剪枝,剪完后的模型还是规整的卷积层,只是通道数变少了。你直接拿剪完的模型去推理,速度立竿见影。非结构化剪枝,剪完后模型里到处都是零权重,虽然参数少了,但计算时还得做一堆判断,普通 CPU 和 GPU 反而更慢。
我建议:做嵌入式部署,优先选结构化剪枝。除非你的目标芯片有专门的稀疏计算单元,否则非结构化剪枝带来的收益远小于麻烦。
我的经验
在 Jetson Nano 上部署 YOLOv5s,我用结构化剪枝剪掉了 30% 的通道,推理速度提升了 40%,精度只掉了 0.5%。换成非结构化剪枝,同样压缩率,速度反而慢了 10%。
4.3 剪枝流程:从评估到微调
一个完整的剪枝项目,我一般按下面几步走:
- 预训练基线模型:先训一个精度达标的模型,作为剪枝起点。
- 稀疏化训练:在 BN 层 γ 上加 L1 正则,让不重要的通道 γ 趋近于零。
- 评估通道重要性:统计每个通道的 γ 值,排序。
- 设定剪枝率并剪枝:比如剪掉 γ 值最小的 30% 通道。
- 微调恢复精度:用原始训练数据,小学习率训 10-20 个 epoch。
- 验证并迭代:如果精度掉太多,降低剪枝率重试。
这里有个细节:剪枝率不是越高越好。我见过有人一上来就剪 50%,结果精度直接崩了,后面怎么微调都救不回来。建议从 10% 开始,逐步往上加。
注意
剪枝后的模型结构变了,导出时一定要重新计算 FLOPs 和参数量。不要拿剪枝前的指标来评估剪枝后的性能。
4.4 我在剪枝项目中踩过的坑
做剪枝这几年,我踩过的坑真不少。挑几个典型的说说,希望能帮你少走弯路。
坑一:剪枝后精度掉太多,微调也救不回来
我曾经在一个 YOLOv4 项目里,剪掉了 40% 的通道,结果 mAP 从 0.85 掉到了 0.72。微调了 50 个 epoch 也只回到 0.78。后来发现,问题出在稀疏化训练阶段——L1 正则的权重设得太大了,导致很多重要通道的 γ 也被压到了零。解决办法:把 L1 正则系数从 0.001 降到 0.0001,重新训一遍,剪枝后精度只掉了 1.2%。
坑二:剪枝后模型推理速度没提升
有一次我在一个 ARM 设备上做剪枝,剪掉了 30% 的通道,但推理时间几乎没变。排查后发现,剪枝后的模型虽然通道数少了,但内存访问模式变得不连续,缓存命中率下降。解决办法:剪枝后做一次 通道重排,把连续的通道放在一起,让内存访问更规整。
坑三:非结构化剪枝在 CPU 上反而更慢
这个坑我踩得最早。当时觉得非结构化剪枝压缩率高,就试了一把。剪完后模型文件确实小了,但推理时 CPU 要处理大量零权重,计算效率极低。后来我查了资料才知道,普通 CPU 没有稀疏矩阵加速指令,零权重反而成了负担。从那以后,我在 CPU 上只做结构化剪枝。
避坑总结
- 稀疏化训练时,L1 正则系数不要太大,0.0001 是个不错的起点。
- 剪枝后做通道重排,提升内存访问效率。
- 嵌入式 CPU 上只用结构化剪枝,别碰非结构化。
4.5 剪枝效果可视化
下面这张图展示了结构化剪枝和非结构化剪枝在模型结构上的区别。你可以直观地看到,结构化剪枝保持了规整的矩阵形状,而非结构化剪枝则变得稀疏零散。
从图上可以清楚看到,结构化剪枝是“整块移除”,而非结构化剪枝是“打孔”。对于嵌入式设备来说,规整的结构意味着更高的计算效率。
4.6 小结
通道剪枝是嵌入式部署中最实用的轻量化技术之一。结构化剪枝和非结构化剪枝各有优劣,但考虑到硬件兼容性,我强烈建议你在嵌入式场景下优先选择结构化剪枝。剪枝流程中的每一步都很关键,尤其是稀疏化训练和微调阶段,参数设置不当很容易翻车。