4. 剪枝基础理论

聊剪枝之前,我们先想清楚一个问题:模型为什么能剪?

说白了,神经网络里有很多参数是冗余的。你想想看,一个训练好的 YOLOv11,可能有几千万个参数,但真正起决定性作用的,也许只有其中的 30%-40%。剩下的那些,贡献很小,甚至接近于零。把它们去掉,模型照样能跑,而且跑得更快。

这就是剪枝的核心逻辑——在精度不掉的前提下,把模型做「瘦」。

4.1 非结构化剪枝:细粒度,但依赖硬件

非结构化剪枝,也叫细粒度剪枝。它剪的是单个权重。

具体做法很简单:设定一个阈值,把值小于这个阈值的权重直接置为零。剩下的权重保持原样,继续参与计算。

我在项目中遇到过这种情况:用非结构化剪枝把 YOLOv5s 的参数量砍掉 70%,精度只掉了 0.3%。看起来很美对吧?但部署到 Jetson Nano 上一跑,推理速度几乎没变。

为什么会这样?因为硬件不认识「零」。GPU 和 NPU 在计算矩阵乘法时,仍然会把那些零权重当作普通数据加载、计算。除非硬件原生支持稀疏矩阵运算(比如 NVIDIA 的 Ampere 架构),否则非结构化剪枝带来的加速非常有限。

非结构化剪枝的特点:
  • 粒度细:每个权重独立判断去留
  • 压缩率高:理论上可以剪掉 80%-90% 的参数
  • 硬件不友好:普通 GPU 无法利用稀疏性加速
  • 需要特殊推理库:如 DeepSparse、TensorRT 的稀疏特性

4.2 结构化剪枝:粗粒度,立竿见影

结构化剪枝就不一样了。它剪的是整个结构单元——比如一个卷积核、一个通道、甚至一个层。

拿 YOLOv11 的 C2f 模块举例。每个卷积层有多个输出通道,每个通道对应一个卷积核。结构化剪枝会评估每个通道的重要性,把不重要的通道整个删掉。删掉之后,特征图的通道数就减少了,后续层的计算量也跟着降下来。

我个人的习惯是:优先用结构化剪枝。原因很简单——剪完就能看到效果。不需要特殊的硬件支持,不需要改推理代码,模型体积直接变小,推理速度直接变快。

我的经验:结构化剪枝的压缩率通常不如非结构化,一般在 30%-50% 之间。但它的「落地友好度」远高于非结构化剪枝。如果你做的是端侧部署,结构化剪枝是更稳妥的选择。

4.3 两种剪枝方式的对比

对比维度 非结构化剪枝 结构化剪枝
剪枝粒度 单个权重 通道 / 卷积核 / 层
压缩率 高(可达 90%) 中(30%-50%)
精度保持 较好 一般,需微调恢复
硬件加速 需专用硬件/库 通用硬件直接加速
部署难度 高 低
适用场景 云端大模型、稀疏推理库 端侧、边缘设备、实时推理

4.4 稀疏性原理:为什么零越多越好?

稀疏性,就是模型中零权重所占的比例。

假设一个卷积层有 100 万个参数,剪枝后变成了 30 万个非零参数和 70 万个零参数。那它的稀疏度就是 70%。

稀疏性带来的好处有两个:

  1. 存储压缩:零参数可以用稀疏格式存储(如 CSR、CSC),只存非零值的索引和数值,大幅减少模型体积。
  2. 计算加速:如果硬件或推理库支持稀疏计算,零参数可以直接跳过,不参与乘加运算。

但这里有个坑——稀疏性不是越高越好。我曾经试过把 YOLOv11 的某个层剪到 95% 稀疏度,结果精度直接崩了,从 52.3% mAP 掉到了 31.7%。

避坑指南:我曾经在剪枝时追求极致压缩率,把稀疏度推到了 90% 以上。结果模型在验证集上表现还行,一到实际场景就频繁漏检。后来发现,过度剪枝把一些关键特征通道给剪没了。所以我的建议是:稀疏度控制在 50%-70% 之间,留足安全边际。

4.5 稀疏性的度量与可视化

在剪枝过程中,我们需要实时监控每一层的稀疏度。常用的度量指标有两个:

  • 全局稀疏度:整个模型的零参数占比
  • 层稀疏度:每一层的零参数占比

我个人习惯把层稀疏度画成柱状图,一眼就能看出哪些层「剪过头了」,哪些层「还有余量」。

# 计算层稀疏度的示例代码
def compute_layer_sparsity(model):
    sparsity_dict = {}
    for name, param in model.named_parameters():
        if 'weight' in name:
            total = param.numel()
            zeros = (param == 0).sum().item()
            sparsity = zeros / total * 100
            sparsity_dict[name] = sparsity
    return sparsity_dict

# 输出示例
# {'model.0.conv.weight': 45.3, 'model.1.conv.weight': 62.1, ...}

4.6 结构化剪枝 vs 非结构化剪枝:如何选择?

这个问题没有标准答案。我根据项目经验总结了一个选择原则:

  • 如果你做云端部署,有 NVIDIA A100 或支持稀疏计算的硬件,可以用非结构化剪枝 + 稀疏推理库,压缩率更高。
  • 如果你做端侧部署,比如手机、边缘盒子、无人机,老老实实用结构化剪枝。兼容性好,加速效果稳定。
  • 如果你做量化前的预处理,结构化剪枝更合适。因为量化对权重分布敏感,非结构化剪枝产生的「空洞」会干扰量化参数的校准。
我的建议:初学者先从结构化剪枝入手。它更直观,更容易调试,也更容易看到效果。等把结构化剪枝玩熟了,再尝试非结构化剪枝去压榨极限性能。

4.7 本章知识结构图

下面这张图梳理了结构化剪枝与非结构化剪枝的核心区别,以及稀疏性原理在其中的作用:

剪枝基础理论结构图 剪枝基础理论:结构化 vs 非结构化 模型剪枝 非结构化剪枝 结构化剪枝 剪单个权重 需专用硬件/库支持 剪通道 / 卷积核 通用硬件直接加速 核心原理:稀疏性 零参数占比越高 → 压缩率越高 → 加速潜力越大

4.8 小结

剪枝不是玄学,它背后有清晰的数学原理和工程逻辑。非结构化剪枝追求极致压缩率,结构化剪枝追求落地友好度。两者没有优劣之分,只有场景之别。