模型剪枝与稀疏推理:结构化、非结构化、2:4 稀疏与大模型压缩(分层式精讲)

核心结论

模型剪枝不是把一些参数设成 0 这么简单,而是把训练好的模型改造成更小、更快或更省显存的部署形态。真正的收益取决于四件事:剪掉的结构是否能从计算图中删除,稀疏模式是否适合目标硬件,推理框架是否调用了对应 kernel,以及剪枝后的质量能否通过回归评估。

更准确的一句话是:

text 复制代码
剪枝收益 = 可删除结构 × 稀疏模式 × 推理后端支持 × 质量回归可控

原稿里"模型缩小 50-90%、推理速度提升 2-5 倍、精度损失 <1%"不能作为通用结论。某些模型、数据集和硬件上确实可能达到类似效果,但参数变少、理论 FLOPs 变少和真实端到端延迟下降是三件不同的事。非结构化稀疏如果仍然走普通 dense Conv/Linear kernel,通常不会自动加速;结构化剪枝更容易变成更小的 dense 模型,因此更容易在 CPU、移动端、NPU 和普通 GPU 后端上获得稳定收益。

第 0 层:30 秒理解

模型像一座工厂,剪枝是在不明显影响产出的前提下关掉低价值设备。

方法 可以怎么理解 部署含义
非结构化剪枝 关掉单个螺丝级别的零件 压缩率高,但需要稀疏 kernel 才可能加速
结构化剪枝 拆掉整条产线、整组机器或整层模块 更容易变成小模型,硬件友好
2:4 半结构化稀疏 每 4 个零件固定保留 2 个 压缩率受限,但适合特定 GPU 稀疏加速
稀疏推理 运行时真的跳过被剪掉的计算 依赖格式、kernel、编译器和硬件

核心判断式:

text 复制代码
如果剪枝结果仍走 dense kernel:可能只省 checkpoint,不一定省延迟
如果剪枝结果改变模型结构:更可能获得通用加速
如果稀疏模式匹配硬件:才有机会把非结构化/半结构化稀疏转成真实加速

第 1 层:基础概念

1.1 为什么需要剪枝

剪枝主要解决四类部署问题:

问题 表现 剪枝可能带来的收益
模型太大 checkpoint、显存、内存占用高 权重减少,加载和存储成本下降
推理太慢 Conv、GEMM、attention 或 MLP 计算重 删除通道、头、层或使用稀疏 kernel
能耗太高 端侧电池消耗、服务器功耗 降低内存访问和计算量
端侧部署困难 CPU/NPU/移动端后端限制多 结构化剪枝后导出更小 dense 图

剪枝的本质是一个受约束优化问题:

text 复制代码
在质量下降不超过阈值的前提下,最大化模型压缩、延迟下降和能耗下降

1.2 四种常见稀疏形态

类型 剪什么 优点 风险 典型场景
非结构化剪枝 单个权重 最高自由度,通常压缩率高 不规则稀疏难加速,元数据开销高 checkpoint 压缩、支持稀疏 kernel 的 GPU
结构化剪枝 通道、filter、head、层、block 生成更小 dense 模型,通用硬件友好 粒度粗,精度更容易受影响 CPU、移动端、边缘设备、NPU
半结构化剪枝 2:4、N:M、block sparse 在压缩率和硬件友好之间折中 必须满足固定模式,训练和导出受约束 NVIDIA Ampere+ GPU、部分专用加速器
动态稀疏 输入不同,激活或路由不同 计算可随样本变化 控制流、负载均衡和延迟稳定性复杂 MoE、token pruning、early exit

1.3 剪枝流程

一个可靠的剪枝流程通常是:

text 复制代码
训练好模型
-> 选目标:体积、延迟、显存、能耗或吞吐
-> 选剪枝粒度:权重、通道、头、层、block、2:4
-> 用校准数据评估重要性
-> 剪枝并修复计算图
-> 微调、蒸馏或短期恢复训练
-> 导出到目标后端
-> 端到端评估质量和延迟

注意最后两步非常关键。只在 Python 里看到参数为 0,不代表部署模型已经变快。

第 2 层:剪枝重要性怎么判断

2.1 幅度剪枝

幅度剪枝认为绝对值小的权重更不重要:

text 复制代码
importance(w_i) = |w_i|

它简单、便宜、常作为基线。Han 等人的早期剪枝工作、后续大量 CNN 和 Transformer 压缩实验都把幅度作为重要参考。但幅度只看权重本身,不直接看任务损失、激活分布和硬件约束。

2.2 激活与通道统计

结构化剪枝常看通道输出是否活跃:

text 复制代码
importance(channel c) = ||activation_c|| 或 ||weight_filter_c||

如果某个通道在代表性数据上长期输出很小,删除它通常更安全。问题是激活统计依赖校准数据,校准集若不覆盖真实分布,剪枝会对长尾样本造成损害。

2.3 梯度与 Taylor 准则

更贴近任务损失的做法是估计删除参数后的损失变化。对参数 w_i 做一阶近似:

text 复制代码
ΔL_i ≈ |g_i · w_i|

其中 g_i 是损失对权重的梯度。通道剪枝也可以用激活和激活梯度估计:

text 复制代码
importance(channel c) ≈ |∂L/∂y_c · y_c|

Taylor 方法比纯幅度更关注任务影响,但需要反向传播和代表性数据,成本更高。

2.4 二阶信息:OBD、OBS 到 SparseGPT

经典的 Optimal Brain Damage 和 Optimal Brain Surgeon 用 Hessian 二阶信息估计删除权重造成的损失变化。二阶方法理论上更精细,但完整 Hessian 太贵,所以实际会使用对角近似、块近似或近似逆 Hessian。

LLM 场景中的 SparseGPT 继承了这种思路:用少量校准数据和近似二阶信息,对大模型权重做一次性剪枝,并在每层内补偿误差。它说明了一点:大模型剪枝不能只按"权重小就删"理解,校准数据和误差补偿非常重要。

2.5 Movement Pruning 与训练中稀疏

Movement Pruning 不只看权重大小,而看权重在微调过程中朝向 0 还是远离 0。RigL 等动态稀疏训练方法则在训练中周期性删除低价值连接、重新生长可能有用的连接。

这类方法适合有训练预算的场景;如果只能拿到已训练 checkpoint 并且没有大规模数据,通常会优先考虑 PTQ 式的一次性剪枝、少量校准数据剪枝或短微调恢复。

第 3 层:结构化剪枝

3.1 结构化剪枝剪什么

结构化剪枝的目标是让模型结构真的变小。

模型 常见剪枝对象 需要同步处理
CNN filter、输出通道、stage、block BatchNorm、残差分支、concat、depthwise/group conv
ViT attention head、MLP hidden dimension、token、block LayerNorm、残差、投影矩阵、位置编码
Transformer LLM attention head、KV head、MLP neuron、层、行列 RoPE、GQA/MQA、残差、权重 tying、导出格式
检测/分割模型 backbone、neck、head 通道 FPN/PAN 多尺度连接、anchor/head shape

结构化剪枝的难点不是"切掉一个张量维度",而是保持整张计算图一致。比如 ResNet 的一个残差 block,如果主分支剪了通道,shortcut 分支、BatchNorm 和后续卷积都必须一致;YOLO 类网络还要处理 neck 中的 concat 和多尺度 head。

3.2 通道剪枝的工程要点

通道剪枝应至少做四件事:

  1. 用代表性数据计算通道重要性。
  2. 根据全局或分层约束选择要删除的通道。
  3. 通过图级依赖分析同步修改相邻层。
  4. 导出后重新评估 shape、精度和延迟。

不建议在真实项目里使用"遍历 Conv2d 然后直接切 module.weight"的玩具代码作为结构化剪枝实现。它很容易漏掉 BatchNorm、残差、分组卷积和多分支连接。工程中更适合使用已有压缩框架、模型库内置剪枝工具,或在明确掌握模型拓扑后写专用转换脚本。

3.3 层剪枝、头剪枝与 block 剪枝

结构化剪枝不只剪通道。

方法 含义 优点 风险
层剪枝 删除整个层或 Transformer block 延迟收益直接,图更简单 对深度和表示能力影响大
attention head 剪枝 删除低价值注意力头 适合 Transformer 多头之间存在冗余,但不是所有任务都稳
MLP neuron 剪枝 删除 FFN 中间维度 LLM/ViT 参数量大头常在 MLP 需同步 up/down/gate 投影
block 剪枝 删除成块权重或结构 更适合硬件和缓存 粒度粗,压缩率受限

对 LLM 来说,MLP 中间维度、attention heads 和层深度往往是结构化剪枝重点。剪掉后模型可以变成更小的 dense Transformer,这比不规则稀疏更容易被通用推理引擎接受。

第 4 层:非结构化剪枝与稀疏训练

4.1 非结构化剪枝的价值

非结构化剪枝的优点是自由度高,可以在较高稀疏率下保持模型质量。早期 Deep Compression 就把剪枝、量化和 Huffman 编码组合起来,大幅压缩模型存储。

但部署时要分清三种收益:

收益 是否容易获得 说明
checkpoint 变小 比较容易 稀疏存储或压缩编码可减少文件体积
显存下降 取决于运行时 如果加载后变回 dense tensor,显存不一定下降
延迟下降 最难 必须有适合稀疏模式的 kernel 和硬件

4.2 迭代幅度剪枝

迭代幅度剪枝通常比一次性高比例剪枝更稳:

text 复制代码
训练好的模型
-> 剪掉一小部分低幅度权重
-> 短微调恢复
-> 提高稀疏率
-> 重复直到目标稀疏率

它的优势是每轮扰动较小,模型有机会恢复;代价是训练预算更高。

4.3 彩票假设

彩票假设认为,在一个随机初始化的 dense 网络中,存在某个稀疏子网络,在合适初始化下可以训练到接近原网络的效果。这个方向对理解"为什么稀疏子网络可行"很重要,但在大规模 LLM 部署中,更多时候我们面对的是已经训练好的 checkpoint,需要做 post-training pruning 或短微调恢复,而不是从头寻找中奖彩票。

4.4 动态稀疏训练

RigL 等方法让稀疏连接在训练过程中动态更新:删掉低价值连接,同时重新激活可能有用的位置。这类方法能在训练阶段节省部分计算,但需要训练框架、稀疏 kernel 和优化器支持。对于只做部署压缩的团队,结构化剪枝、2:4 稀疏和量化组合往往更直接。

第 5 层:2:4 半结构化稀疏

2:4 稀疏是一种硬件友好的稀疏模式:在指定方向上,每 4 个连续元素中保留 2 个非零值,另外 2 个为 0。

text 复制代码
[a, b, c, d] -> 保留其中 2 个,例如 [a, 0, c, 0]

它的意义在于:完全不规则稀疏很难让 GPU 高效执行,而固定模式的半结构化稀疏可以让硬件提前知道跳零规则。NVIDIA Ampere 架构引入 Sparse Tensor Cores 后,2:4 结构化稀疏成为 GPU 推理和训练优化中的重要路线;cuSPARSELt、TensorRT 等后端也围绕这类模式提供支持。

2:4 的优点和限制都很清楚:

方面 说明
优点 模式规则,元数据少,更容易被 Sparse Tensor Core 利用
限制 理论稀疏率固定在 50% 左右,不能像非结构化剪枝那样随意达到 80-90%
训练要求 通常需要稀疏感知训练、蒸馏或恢复微调
部署要求 必须确认导出后的 GEMM/Conv 真的走了 2:4 sparse kernel

PyTorch 也提供了半结构化稀疏相关能力,但这类能力的可用算子、dtype、形状和后端路径会随版本变化。工程上不能只看 API 存在,要在目标环境实测。

第 6 层:稀疏推理栈

稀疏推理要解决两个问题:怎么存,以及怎么算。

6.1 稀疏存储格式

格式 适合什么 风险
COO 简单坐标存储,便于构造 索引冗余,计算效率通常不高
CSR 按行压缩,适合稀疏矩阵乘 列访问不友好,动态 shape 复杂
CSC 按列压缩 行访问不友好
BSR/Blocked 分块稀疏,硬件和缓存更友好 需要块级稀疏,灵活性低
2:4/N:M 固定局部模式 依赖特定 kernel 和硬件

非结构化稀疏在数学上可以把 MACs 降到 dense_macs × (1 - sparsity),但这只是理论上限。真实推理还要读取索引、解码元数据、处理不规则访存,并且受 batch size 和算子融合影响。

6.2 dense kernel 与 sparse kernel

如果一个 Linear 层的权重有 80% 为 0,但仍然以普通 dense GEMM 执行,那么计算单元会照常处理这些 0。只有当模型转换成稀疏张量、图编译器保留稀疏算子、运行时调用稀疏 kernel,并且硬件适合这种稀疏模式时,才可能获得真实延迟收益。

因此剪枝报告必须写清楚:

必填项 为什么重要
稀疏率 说明参数层面的压缩程度
稀疏模式 非结构化、block、2:4、通道等决定 kernel 可用性
导出后端 PyTorch、ONNX Runtime、TensorRT、cuSPARSELt、ExecuTorch、NPU SDK 等
kernel path 确认是否走了 sparse kernel
端到端延迟 反映真实用户体验

第 7 层:大模型剪枝的新重点

2023 年以后,LLM 剪枝形成了几条重要路线。

7.1 SparseGPT

SparseGPT 使用少量校准数据和近似二阶信息,对大语言模型做一次性剪枝,并在层内做误差补偿。它适合解释为什么"post-training pruning"在大模型上可行:大模型有冗余,但剪枝需要考虑输入激活和误差传播。

7.2 Wanda

Wanda 的核心思路更简单:结合权重大小和输入激活大小进行剪枝评分。它不需要反向传播,适合低成本 LLM 剪枝基线。它提醒我们,大模型权重重要性不应只看 |w|,还要看该权重对应输入通道在真实数据中的活跃程度。

7.3 LLM-Pruner

LLM-Pruner 关注结构化剪枝:删除注意力头、MLP 维度等结构,让 LLM 变成更小的 dense 模型。它更贴近通用部署需求,因为很多推理引擎对小 dense 模型的支持比不规则稀疏更成熟。

7.4 SliceGPT

SliceGPT 通过删除 Transformer 权重矩阵中的行列方向来压缩模型,并保持结构可部署。它代表了一类"让压缩后的模型仍像一个普通 dense Transformer"的思路。

7.5 LLM 剪枝与量化要一起考虑

LLM 推理常见瓶颈包括权重带宽、KV cache、attention 复杂度、batch 调度和长上下文。剪枝只解决其中一部分问题。因此实际部署常把剪枝与以下技术组合:

技术 解决什么
INT8/INT4 权重量化 降低权重存储和带宽
FP8/INT8 激活或 GEMM 提升低精度计算效率
KV cache 量化 降低长上下文显存
蒸馏或 LoRA 恢复 弥补剪枝后的质量下降
speculative decoding 改善生成吞吐
continuous batching 提升服务端利用率

剪枝不是 LLM 推理优化的唯一按钮。一个剪枝模型如果让困惑度下降不多,但破坏了指令遵循、安全拒答或长上下文稳定性,也不应上线。

第 8 层:策略选择

8.1 按部署场景选方法

场景 推荐优先级 说明
CPU、移动端、边缘设备 结构化剪枝 > 量化 > 非结构化稀疏 通用后端更容易跑小 dense 模型
NVIDIA Ampere/Hopper/Blackwell GPU 2:4 半结构化、稀疏 GEMM、量化组合 需要 TensorRT、cuSPARSELt 或相应 kernel 支持
服务器 LLM 服务 结构化 LLM 剪枝 + 权重量化 + KV cache 优化 真瓶颈常在带宽、KV 和调度
只想压缩文件 非结构化剪枝 + 稀疏存储/编码 可减少 checkpoint,但不保证推理变快
精度极敏感任务 轻度剪枝、渐进剪枝、蒸馏恢复 先做层敏感度分析
检测/分割/多分支模型 框架化结构化剪枝 需要处理 FPN、concat、head shape

8.2 参数建议不是固定答案

可以把下面当作起点,而不是结论:

参数 起点 调整方向
结构化剪枝率 20-50% 通道或维度 精度稳定后再提高
非结构化稀疏率 50-80% 超过 80% 要更谨慎验证
2:4 稀疏 固定 50% 局部稀疏 重点验证后端是否利用
微调预算 从短微调开始 质量下降大时增加数据、蒸馏或降低剪枝率
校准数据 覆盖真实输入分布 长尾、长上下文、多语言/多领域要覆盖

如果目标是端到端加速,建议先用 10-20% 的轻度结构化剪枝建立可复现评估,再逐步增加压缩率,而不是直接追求 80-90% 稀疏。

第 9 层:评估与代码骨架

9.1 稀疏率报告

下面的代码只能报告权重中有多少 0,不能证明模型会加速。

python 复制代码
def tensor_sparsity(x):
    return (x == 0).sum().item() / max(1, x.numel())


def module_sparsity_report(model):
    report = {}
    for name, module in model.named_modules():
        weight = getattr(module, "weight", None)
        if weight is not None:
            w = weight.detach()
            report[name] = {
                "shape": tuple(w.shape),
                "sparsity": tensor_sparsity(w),
            }
    return report

9.2 理论 MACs 不是真实延迟

python 复制代码
def theoretical_sparse_macs(dense_macs, sparsity):
    return dense_macs * (1.0 - sparsity)

这只能估计"如果每个 0 都能被免费跳过"的理想上限。实际延迟必须用目标硬件、目标 batch、目标输入长度和目标推理引擎实测。

9.3 发布闸门

python 复制代码
def pass_pruning_gate(metrics, limits):
    return (
        metrics["quality_drop"] <= limits["max_quality_drop"]
        and metrics["p95_latency_ms"] <= limits["max_p95_latency_ms"]
        and metrics["peak_memory_gb"] <= limits["max_peak_memory_gb"]
        and metrics["kernel_path_verified"]
    )

推荐至少记录:

指标 说明
quality_drop 分类精度、mAP、困惑度、BLEU、人工偏好、任务成功率等
p50/p95 latency 端到端延迟,不只算单层
throughput images/s、tokens/s、requests/s
peak memory 权重、激活、KV cache、workspace
energy 端侧或服务器能耗
kernel_path_verified 是否真的走了 sparse/2:4/低精度 kernel
regression_cases 长尾样例、安全样例、长上下文样例

9.4 延迟评估注意事项

评估剪枝模型时要固定:

  1. 硬件型号、驱动、CUDA/cuDNN/TensorRT/PyTorch 版本。
  2. batch size、输入分辨率或序列长度分布。
  3. warmup 次数和重复次数。
  4. 是否开启编译、算子融合、量化、稀疏 kernel。
  5. 是否测端到端,包括数据搬运、tokenizer、后处理和调度。

第 10 层:落地工作流

10.1 CNN/检测模型

text 复制代码
确定部署端和延迟目标
-> 分析模型拓扑和多分支依赖
-> 做轻度通道剪枝
-> 同步 BN、shortcut、concat 和 head
-> 微调或蒸馏
-> 导出 ONNX/TensorRT/NPU 格式
-> 实测 mAP、p95 延迟和显存

检测模型尤其要小心 neck 和 head。只剪 backbone 往往收益有限;剪 neck/head 又容易破坏多尺度特征和输出 shape。

10.2 Transformer/LLM

text 复制代码
选校准集
-> 选择剪枝目标:head、MLP、层、行列、2:4 或非结构化
-> 剪枝并做短恢复训练
-> 与量化组合评估
-> 检查困惑度、下游任务、指令遵循、安全和长上下文
-> 导出到目标推理引擎

LLM 剪枝一定要避免只看困惑度。指令模型还要看对话格式、工具调用、安全拒答、多语言、代码和长上下文稳定性。

10.3 推荐路线

目标 推荐路线
快速减小端侧视觉模型 结构化通道剪枝 + QAT/PTQ INT8
降低 LLM 显存 INT4/INT8 权重量化优先,再评估结构化剪枝
利用 NVIDIA 稀疏硬件 2:4 稀疏训练/微调 + TensorRT/cuSPARSELt 验证
压缩 checkpoint 文件 非结构化剪枝 + 稀疏编码,但要说明不保证加速
极限压缩 剪枝 + 量化 + 蒸馏 + 架构搜索,但成本高

常见误区

误区 更准确的说法
稀疏率越高越好 高稀疏率可能让质量突然崩溃,也可能因稀疏 kernel 开销导致不加速
非结构化剪枝一定优于结构化剪枝 非结构化更灵活,结构化更容易部署
剪枝后只要微调几轮就行 微调预算必须由质量回归决定
理论 FLOPs 下降就是推理加速 真实延迟取决于 kernel、内存访问、batch 和编译器
LLM 剪枝只看困惑度 还要看指令遵循、安全、代码、数学、长上下文和工具调用
结构化剪枝代码很简单 真实模型需要图级依赖处理和导出验证

总结

模型剪枝与稀疏推理的关键不是追求一个漂亮的稀疏率,而是把剪枝结果变成目标硬件上真的更小、更快、更省、质量仍然可控的模型。

最稳的判断顺序是:

text 复制代码
先定部署目标
-> 再选剪枝粒度
-> 再确认后端支持
-> 最后用真实任务和真实硬件验收

结构化剪枝适合追求通用部署收益;非结构化剪枝适合高压缩率和有稀疏后端的场景;2:4 半结构化稀疏是硬件友好的折中;LLM 剪枝则必须与量化、蒸馏、KV cache 和推理引擎一起看。真正成熟的剪枝不是"少了多少参数",而是"上线后是否更快、更稳、更便宜"。

参考资料

相关推荐
kiros_wang1 小时前
Android 常见面试题
android
货拉拉技术2 小时前
Hook植入日志协助定位问题方案
android
FlightYe2 小时前
Android投屏MirrorCast全链路
android
Ehtan_Zheng2 小时前
Kotlin const val vs val:字节码、性能与隐藏陷阱详解
android·kotlin
墨狂之逸才2 小时前
Android TV 垃圾应用清理指南
android
源来猿往3 小时前
记ffmpeg-8.1.1 之Android库编译(window)
android·ffmpeg
zhangphil3 小时前
大日志文件截取,从指定日志文件中提取两个标记字符串之间的全部内容,Kotlin
kotlin
恋猫de小郭3 小时前
Android 17 正式版发布,全新 AI 和各种破坏性更新
android·前端·flutter
我命由我123453 小时前
Jetpack Room - Room 查询返回列表无需判空、LIKE 关键字
android·java·开发语言·java-ee·android jetpack·android-studio·android runtime
朝星4 小时前
Android开发[14]:网络优化之OkHttp
android·okhttp·kotlin