4. 模型轻量化技术(上):通道剪枝原理、结构化剪枝 vs 非结构化剪枝、我在剪枝项目中踩过的坑

模型剪枝,说白了就是给神经网络“瘦身”。你想想看,一个训练好的大模型里,其实有很多参数是冗余的。去掉它们,模型照样能跑,而且跑得更快。我在做嵌入式部署时,剪枝几乎是必过的一关。

但剪枝不是简单地把权重砍掉。砍错了地方,精度会断崖式下跌。这一讲,我们先从最基础的通道剪枝原理讲起,再对比两种主流剪枝策略,最后聊聊我踩过的那些坑。

4.1 通道剪枝:最实用的轻量化手段

通道剪枝,也叫滤波器剪枝。它直接干掉卷积层里不重要的输出通道。为什么说它实用?因为剪掉一个通道,后续所有层的计算量都会减少,硬件实现也特别友好。

核心思路就三步:

  1. 评估重要性:给每个通道打个分,判断它对最终结果贡献多大。
  2. 剪掉低分通道:设定一个阈值或比例,把不重要的通道移除。
  3. 微调恢复:剪完后模型精度会掉,需要小学习率再训几轮。

评估重要性有很多方法。我个人习惯用 BN 层的缩放因子 γ。训练时给每个通道的 γ 加一个 L1 正则,训练结束后 γ 值小的通道就是不重要的。这个方法简单,效果也不错。

通道剪枝的关键公式

BN 层输出:y = γ * (x - μ) / √(σ² + ε) + β

γ 越小,说明该通道对后续层的影响越弱,优先剪掉。

4.2 结构化剪枝 vs 非结构化剪枝

这两种剪枝方式,本质区别在于“剪完后的模型结构是否规整”。

对比维度 结构化剪枝 非结构化剪枝
剪枝粒度 通道、滤波器、层 单个权重
模型结构 保持规整,通道数减少 变得稀疏,不规则
硬件加速 直接支持,无需特殊库 需要稀疏矩阵库或专用硬件
压缩率上限 中等(通常 2x-4x) 高(可达 10x 以上)
精度恢复难度 较低,微调几轮即可 较高,需要更精细的微调策略
嵌入式部署 推荐,兼容性好 不推荐,除非有专用 NPU

结构化剪枝,剪完后的模型还是规整的卷积层,只是通道数变少了。你直接拿剪完的模型去推理,速度立竿见影。非结构化剪枝,剪完后模型里到处都是零权重,虽然参数少了,但计算时还得做一堆判断,普通 CPU 和 GPU 反而更慢。

我建议:做嵌入式部署,优先选结构化剪枝。除非你的目标芯片有专门的稀疏计算单元,否则非结构化剪枝带来的收益远小于麻烦。

我的经验

在 Jetson Nano 上部署 YOLOv5s,我用结构化剪枝剪掉了 30% 的通道,推理速度提升了 40%,精度只掉了 0.5%。换成非结构化剪枝,同样压缩率,速度反而慢了 10%。

4.3 剪枝流程:从评估到微调

一个完整的剪枝项目,我一般按下面几步走:

  1. 预训练基线模型:先训一个精度达标的模型,作为剪枝起点。
  2. 稀疏化训练:在 BN 层 γ 上加 L1 正则,让不重要的通道 γ 趋近于零。
  3. 评估通道重要性:统计每个通道的 γ 值,排序。
  4. 设定剪枝率并剪枝:比如剪掉 γ 值最小的 30% 通道。
  5. 微调恢复精度:用原始训练数据,小学习率训 10-20 个 epoch。
  6. 验证并迭代:如果精度掉太多,降低剪枝率重试。

这里有个细节:剪枝率不是越高越好。我见过有人一上来就剪 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 剪枝效果可视化

下面这张图展示了结构化剪枝和非结构化剪枝在模型结构上的区别。你可以直观地看到,结构化剪枝保持了规整的矩阵形状,而非结构化剪枝则变得稀疏零散。

结构化剪枝 vs 非结构化剪枝 结构化剪枝 剪掉的通道 保留的通道 剪掉整列通道,结构规整 非结构化剪枝 剪掉单个权重,结构稀疏 结构化剪枝:剪掉整列 → 规整矩阵 → 硬件友好 非结构化剪枝:剪掉单个权重 → 稀疏矩阵 → 需要特殊支持

从图上可以清楚看到,结构化剪枝是“整块移除”,而非结构化剪枝是“打孔”。对于嵌入式设备来说,规整的结构意味着更高的计算效率。

4.6 小结

通道剪枝是嵌入式部署中最实用的轻量化技术之一。结构化剪枝和非结构化剪枝各有优劣,但考虑到硬件兼容性,我强烈建议你在嵌入式场景下优先选择结构化剪枝。剪枝流程中的每一步都很关键,尤其是稀疏化训练和微调阶段,参数设置不当很容易翻车。