模型剪枝基础:结构化剪枝与非结构化剪枝原理、粒度与稀疏性
模型剪枝,说白了就是给神经网络“瘦身”。
我刚开始接触这个领域时,总觉得剪枝就是把权重砍掉一些,没什么技术含量。直到我在一个边缘AI项目里,要把一个ResNet-50塞进只有2MB SRAM的芯片里,才发现——剪枝的门道深着呢。
今天咱们就聊聊剪枝的两个核心流派:结构化剪枝和非结构化剪枝。以及它们背后的粒度与稀疏性概念。
一、剪枝的本质:砍掉冗余连接
神经网络里,很多权重其实接近于零。这些权重对最终结果贡献极小,砍掉它们,模型精度几乎不受影响。
为什么会这样?因为训练过程中,某些神经元或连接被“学废了”——它们要么输出恒定,要么权重极小。保留它们,只是浪费计算资源和存储空间。
核心思想:在保持模型精度的前提下,移除不重要的参数,从而减少计算量、降低存储需求、加速推理。
我习惯把剪枝分为两个维度:
- 按结构分:结构化剪枝 vs 非结构化剪枝
- 按粒度分:细粒度剪枝、向量级剪枝、核级剪枝、通道级剪枝、层级剪枝
这两个维度交叉组合,就构成了剪枝的完整技术图谱。
二、非结构化剪枝:精细但“难伺候”
非结构化剪枝,也叫细粒度剪枝。它直接对单个权重做判断——权重绝对值小于某个阈值,就把它置零。
举个例子:
# 非结构化剪枝示例(PyTorch风格)
import torch
import torch.nn.utils.prune as prune
model = torch.nn.Linear(10, 5)
# 对权重进行L1范数剪枝,保留30%的权重
prune.l1_unstructured(model, name='weight', amount=0.7)
# 查看剪枝后的权重
print(model.weight)
# 输出中很多权重变成了0.0
你看,代码很简单。但实际项目中,我踩过一个大坑——非结构化剪枝后的模型,在普通硬件上几乎跑不快。
避坑指南:我曾经在一个FPGA部署项目里,对卷积层做了50%的非结构化剪枝。结果呢?推理速度几乎没变。因为FPGA的乘加器是并行计算的,零权重并不会跳过计算——它依然占用一个乘法器周期。
非结构化剪枝的优点是精度损失小。因为它保留了模型原有的拓扑结构,只是把某些权重置零。但缺点也很明显:
- 权重矩阵变成稀疏矩阵,需要专门的稀疏计算库(如cuSPARSE)才能加速
- 对硬件不友好,通用处理器(CPU/GPU)很难利用这种稀疏性
- 模型文件大小可能不变(因为零值依然占用存储空间)
所以,非结构化剪枝更适合学术研究,或者你有专门的稀疏计算硬件。否则,我建议你慎重。
三、结构化剪枝:粗暴但实用
结构化剪枝,是直接砍掉整个结构单元——比如一个通道、一个卷积核、甚至一整层。
你想想看,如果某个卷积核的所有权重都很小,那这个卷积核基本就是废的。直接删掉它,模型结构就变小了。
举个例子:
# 结构化剪枝示例:按通道剪枝
# 假设我们有一个Conv2d层,输入通道64,输出通道128
# 我们对输出通道做剪枝,保留最重要的64个通道
import torch
import torch.nn as nn
# 计算每个通道的L2范数作为重要性指标
conv = nn.Conv2d(64, 128, kernel_size=3)
importance = torch.norm(conv.weight.view(128, -1), dim=1) # 每个输出通道的L2范数
# 保留前64个最重要的通道
_, indices = torch.topk(importance, 64)
# 然后根据indices重新构建一个更小的卷积层
结构化剪枝的好处是:
- 直接减少计算量——通道数减半,计算量也减半
- 硬件友好——剪枝后的模型依然是密集矩阵,通用硬件可以直接加速
- 模型体积缩小——参数数量实实在在减少了
但代价是精度损失更大。因为一刀切地砍掉整个通道,可能会误伤一些有用的特征。
我的经验:在实际项目中,我通常先用结构化剪枝把模型压缩到目标大小的80%,然后用知识蒸馏或微调来恢复精度。这样既保证了推理速度,又不会让精度掉得太难看。
四、粒度与稀疏性:剪枝的“精细度”
剪枝的粒度,决定了你砍掉的是“多大一块”。
| 粒度级别 | 描述 | 稀疏性类型 | 硬件友好度 |
|---|---|---|---|
| 细粒度(权重级) | 单个权重置零 | 非结构化稀疏 | 低 |
| 向量级 | 连续N个权重一起置零 | 半结构化稀疏 | 中 |
| 核级 | 整个卷积核置零 | 结构化稀疏 | 高 |
| 通道级 | 整个通道置零 | 结构化稀疏 | 高 |
| 层级 | 整层删除 | 结构化稀疏 | 最高 |
稀疏性,就是模型中零值参数的比例。比如一个模型有100万个参数,其中30万个是零,那稀疏度就是30%。
但要注意:稀疏度不等于加速比。非结构化剪枝达到90%稀疏度,在普通GPU上可能只加速1.2倍。而结构化剪枝达到50%稀疏度,加速比可能直接翻倍。
为什么会这样?因为硬件对“规则”的稀疏性更友好。你想想看,如果零值分布是随机的,硬件没法做批量跳过。但如果零值是以通道为单位的,硬件可以直接跳过整个通道的计算。
五、如何选择?我的建议
在实际项目中,我一般遵循这个原则:
- 目标硬件是GPU/CPU:优先用结构化剪枝。因为GPU的Tensor Core对密集矩阵优化得最好。
- 目标硬件是专用AI芯片:看芯片是否支持稀疏计算。如果支持,可以尝试非结构化剪枝+稀疏加速。
- 精度要求极高:先用非结构化剪枝做探索,找到精度-稀疏度的边界,再转为结构化剪枝。
- 模型太大,内存装不下:必须用结构化剪枝。因为非结构化剪枝不减少模型的内存占用(零值依然占位)。
一句话总结:结构化剪枝保速度,非结构化剪枝保精度。实际项目中,我通常两者结合——先用结构化剪枝砍到目标大小,再用非结构化剪枝微调恢复精度。
六、知识体系图
下面这张图,帮你理清剪枝的核心逻辑:
嗯,这张图把剪枝的脉络理得很清楚。左边是非结构化路线,右边是结构化路线。底部是它们的核心差异对比。
我个人习惯在项目初期,先用非结构化剪枝做个快速评估——看看模型在多大稀疏度下还能保持精度。然后根据目标硬件,选择合适的结构化剪枝策略。
记住一点:剪枝不是目的,部署才是。你剪得再漂亮,如果硬件跑不快,那就是白费功夫。
小技巧:如果你不确定该用哪种剪枝,先问自己三个问题:
- 我的目标硬件支持稀疏计算吗?
- 我的模型精度余量有多大?
- 我的部署时间窗口有多紧?
答案自然就有了。
公众号:蓝海资料掘金营,微信deep3321