模型剪枝基础:剪枝的分类、数学原理与评估指标

各位同学,欢迎来到模型剪枝的实战环节。说实话,我第一次接触剪枝是在一个移动端部署的项目里。模型太大,手机跑不动,老板又催得紧。那时候我就在想:能不能把模型里「不那么重要」的部分砍掉?嗯,这就是剪枝的初衷。

今天咱们聊聊剪枝的三个核心问题:怎么分类、数学上怎么算、以及怎么评估效果。我尽量用大白话讲清楚,但该有的公式和代码,一个都不会少。

一、剪枝的分类:结构化 vs 非结构化

剪枝的分类,说白了就是看你怎么「砍」模型。我个人习惯把它分成两大类:结构化剪枝非结构化剪枝。这两者的区别,直接决定了你的模型能不能在硬件上跑得快。

1. 非结构化剪枝

非结构化剪枝,就是把单个权重砍掉。比如一个卷积核里有 3x3=9 个参数,你觉得其中 3 个不重要,直接把它们设成 0。这就是非结构化剪枝。

特点:

  • 剪枝粒度细,可以保留更多有效参数
  • 但权重变成稀疏矩阵,普通硬件加速困难
  • 需要专门的稀疏计算库(如 cuSPARSE)才能提速

我在项目中遇到过一个问题:非结构化剪枝后,模型精度确实没怎么掉,但推理速度反而变慢了。为什么?因为普通 GPU 对稀疏矩阵的计算并不友好。你想想看,把一堆 0 和有效值混在一起,硬件还得一个个判断,能不慢吗?

2. 结构化剪枝

结构化剪枝,就是整块整块地砍。比如直接砍掉一个卷积核(channel pruning),或者砍掉一层(layer pruning)。这种剪枝方式,砍完之后模型结构还是规整的,硬件可以直接跑。

我的建议:如果你要在手机或嵌入式设备上部署,优先考虑结构化剪枝。虽然精度损失可能大一点,但加速效果立竿见影。

举个例子,假设你有一个 64 通道的卷积层,结构化剪枝后变成 32 通道。那计算量直接减半,而且不需要任何特殊库支持。我曾经在一个语音识别模型上试过,剪掉 30% 的通道,精度只掉了 0.5%,但推理速度快了将近一倍。

对比项 非结构化剪枝 结构化剪枝
剪枝粒度 单个权重 通道/层/块
硬件加速 需要特殊库 直接加速
精度保留 较好 可能稍差
部署难度 较高 较低

二、剪枝的数学原理

剪枝不是瞎砍,得有依据。数学上,我们通常用重要性指标来判断一个权重或通道该不该留。这里我介绍两种最常用的方法。

1. 基于权重大小的剪枝

这是最直观的方法:权重绝对值越小,越不重要。为什么?因为权重小,对输出的贡献就小。你想想看,一个接近 0 的权重,乘上输入后几乎不影响结果,砍掉它影响不大。

数学上,我们定义一个掩码矩阵 M:

M[i] = 1  if |W[i]| > threshold
M[i] = 0  if |W[i]| <= threshold

然后剪枝后的权重就是 W' = W * M。这里的 threshold 可以是一个固定值,也可以是按比例设定的(比如保留 top-80% 的权重)。

注意:千万不要一次性剪太多。我曾经在一个 ResNet 上试过,一次剪掉 90% 的权重,结果模型直接崩了,精度掉到随机猜测的水平。后来我改成逐步剪枝,每次剪 10%,然后微调一下,效果就好多了。

2. 基于梯度的重要性评估

光看权重大小有时候不够。有些权重虽然小,但梯度很大,说明它对 loss 的敏感度很高。这时候砍掉它,loss 可能会猛涨。

所以更靠谱的方法是结合权重和梯度

Importance = |W * grad|

这个公式的意思是:一个权重的重要性,等于它的绝对值乘上它对 loss 的梯度绝对值。如果权重小但梯度大,说明它虽然现在贡献小,但稍微调整一下就能显著影响 loss,这种权重最好留着。

我记得在 BERT 模型上做剪枝时,纯看权重大小剪枝,精度掉了 3%。换成基于梯度的方法后,同样剪枝率下精度只掉了 1.2%。嗯,这个差距在实际项目中还是挺明显的。

三、剪枝的评估指标

剪枝完怎么知道好不好?不能光看模型变小了,还得看实际效果。我一般用以下几个指标来评估。

1. 压缩率

压缩率是最直接的指标:

压缩率 = 剪枝后参数量 / 剪枝前参数量

比如原来模型有 100M 参数,剪完后剩 30M,压缩率就是 30%。但注意,压缩率不等于加速比。结构化剪枝的压缩率和加速比基本一致,但非结构化剪枝可能压缩了 70%,推理速度只快了 20%。

2. 精度损失

这个不用多说,剪枝后模型在验证集上的精度变化。我给自己定的标准是:精度损失不超过 1% 就算成功。如果超过 2%,就得考虑调整剪枝策略了。

避坑指南:我曾经犯过一个错误——只看 top-1 精度。后来发现剪枝后的模型虽然 top-1 精度没怎么掉,但在某些类别上完全失效了。所以建议同时看 top-5 精度和每个类别的召回率,确保没有「偏科」。

3. 推理速度

这是最终目标。我习惯在剪枝前后分别跑 1000 次推理,取平均时间。注意要在目标硬件上测。你在 GPU 上测出来的加速比,在手机上可能完全不一样。

指标 计算公式 我的经验阈值
压缩率 剪枝后参数量 / 剪枝前参数量 30%-50% 比较合理
精度损失 剪枝前精度 - 剪枝后精度 < 1% 优秀,< 2% 可接受
加速比 剪枝前推理时间 / 剪枝后推理时间 结构化剪枝期望 > 1.5x

4. 能量消耗

这个指标在移动端和边缘设备上特别重要。剪枝后模型小了,计算量少了,耗电量自然就降了。我一般在手机上用 Android Profiler 测功耗,剪枝后如果能省电 20% 以上,那就算很成功了。

好了,关于剪枝的基础知识就讲到这里。下一章咱们会动手实现一个简单的剪枝工具,到时候我会带着大家一步步写代码。记住,剪枝不是一锤子买卖,多试几次,找到最适合你模型的剪枝策略,才是关键。