3、结构化剪枝基础:理解结构化剪枝与非结构化剪枝的区别,掌握通道剪枝与滤波器剪枝的原理
各位同学,今天我们来聊聊剪枝。说实话,剪枝这个概念在模型压缩里算是最经典的技术之一了。我最早接触剪枝是在2018年,那时候做移动端部署,模型太大跑不动,硬着头皮啃了几个月剪枝相关的。嗯,踩了不少坑,今天把这些经验分享给你们。
3.1 剪枝到底在干什么?
先问个问题:一个训练好的神经网络,里面所有参数都重要吗?
答案显然是否定的。你想想看,网络里有很多冗余的神经元、通道、甚至整个滤波器,它们对最终结果贡献很小。剪枝就是把这些「摸鱼」的组件去掉,让模型变轻。
我个人习惯把剪枝分成两大类:非结构化剪枝和结构化剪枝。这两者的区别,说白了就是一个「细粒度」一个「粗粒度」。
3.2 非结构化剪枝 vs 结构化剪枝
3.2.1 非结构化剪枝
非结构化剪枝,操作的是单个权重。比如一个卷积核有3×3=9个参数,我们根据某种准则(比如值大小)把其中几个置为0。
核心特点:剪枝粒度是单个参数,稀疏度高,但硬件不友好。
我在项目中遇到过这种情况:用非结构化剪枝把模型压缩了90%,结果在手机上跑,速度一点没变快。为什么?因为稀疏矩阵的加速需要专门的硬件支持,普通CPU/GPU根本吃不到红利。
注意:非结构化剪枝后的模型,如果不配合稀疏计算库(比如TensorRT、OpenBLAS),实际推理速度可能不降反升。我曾经在这个坑里待了两个月。
3.2.2 结构化剪枝
结构化剪枝就不一样了。它剪的是整个结构单元——比如一个通道、一个滤波器、甚至一整层。剪完之后,网络结构变了,但剩下的部分仍然是密集的矩阵运算。
核心特点:剪枝粒度是结构单元,硬件友好,可以直接获得加速效果。
你想想看,剪掉一个通道,意味着卷积层的输入或输出通道数减少了,矩阵乘法规模直接缩小。这在任何硬件上都能加速,不需要特殊支持。
3.3 通道剪枝的原理
通道剪枝,顾名思义,剪的是特征图的通道。具体来说,就是去掉某些通道对应的所有卷积核。
举个例子:假设一个卷积层有64个输出通道,每个输出通道对应一个3×3×C的卷积核。通道剪枝会评估这64个通道的重要性,把不重要的通道连同它对应的卷积核一起删掉。
怎么评估重要性?常见的方法有:
- 基于权重大小:计算每个通道对应的卷积核权重的L1/L2范数,范数小的认为不重要
- 基于激活值:统计每个通道输出特征图的均值、方差,激活值小的通道可以剪掉
- 基于BN层参数:利用Batch Normalization的缩放因子γ,γ接近0的通道可以剪掉
我的经验:在实际项目中,我比较推荐用BN层的γ值来做通道剪枝。原因很简单——不需要额外计算,训练过程中就有了。我曾经在一个分类模型上用这个方法,剪掉40%的通道,精度只掉了0.3%。
3.4 滤波器剪枝的原理
滤波器剪枝和通道剪枝其实是一体两面的。通道剪枝关注的是输出通道,滤波器剪枝关注的是卷积核本身。
每个滤波器(卷积核)对应一个输出通道。所以,剪掉一个滤波器,就等于剪掉一个输出通道。从实现角度看,两者是等价的。
但滤波器剪枝有一个独特的视角:它更关注卷积核内部的结构。比如一个3×3的卷积核,我们可以评估这个核的「能量」——也就是所有参数的平方和。能量低的核,对输出的贡献就小。
滤波器剪枝的典型流程:
- 计算每个滤波器的L2范数
- 按范数从小到大排序
- 设定剪枝比例(比如剪掉30%)
- 删除范数最小的那些滤波器
- 微调模型恢复精度
我记得有一次做MobileNetV2的剪枝,滤波器剪枝和通道剪枝我都试了。结果发现,对于深度可分离卷积,通道剪枝的效果更好。因为MobileNetV2的逐点卷积(1×1卷积)通道数很多,剪通道的收益更明显。
3.5 结构化剪枝的核心流程图
下面我用一张SVG图来展示结构化剪枝的整体流程,方便大家理解:
3.6 两种剪枝方式的对比
为了让大家看得更清楚,我整理了一个对比表格:
| 对比维度 | 非结构化剪枝 | 结构化剪枝 |
|---|---|---|
| 剪枝粒度 | 单个权重/参数 | 通道、滤波器、层 |
| 稀疏模式 | 不规则稀疏 | 规则稀疏(结构完整) |
| 硬件加速 | 需要专用硬件/库 | 通用硬件直接加速 |
| 压缩率 | 高(可达90%+) | 中等(通常30%-60%) |
| 精度损失 | 较小(可微调恢复) | 略大(需要更多微调) |
| 部署难度 | 高(需稀疏推理引擎) | 低(直接导出即可) |
| 典型应用 | 学术研究、特定加速器 | 移动端、嵌入式设备 |
3.7 实际项目中的选择建议
说了这么多,到底该用哪种?我个人的经验是:
- 做移动端部署,首选结构化剪枝。 因为手机芯片不支持稀疏计算,非结构化剪枝剪了也白剪。
- 如果目标平台支持稀疏加速(比如某些NPU、TPU),可以尝试非结构化剪枝,压缩率更高。
- 混合使用效果更好。 我最近的一个项目就是先做结构化剪枝去掉30%的通道,再做非结构化剪枝去掉50%的剩余参数,最终模型大小只有原来的1/4,精度只掉了0.5%。
避坑指南:我曾经在一个项目里,一上来就设了70%的剪枝比例,结果模型直接崩了,精度掉到随机水平。后来学乖了——从小比例开始试,比如10%、20%、30%,每次剪完都评估一下,找到精度下降的拐点。这个拐点就是你的最佳剪枝比例。
3.8 小结
结构化剪枝的核心就两句话:剪结构单元,保硬件效率。通道剪枝和滤波器剪枝本质上是同一件事的不同视角,理解其中一个,另一个自然就懂了。
下一节我们会深入代码层面,手把手实现一个通道剪枝的完整流程。到时候你们会发现,代码实现其实比理论简单得多。
可可精品资料库