稀疏化(Sparsification)技术介绍
一、基本概念
稀疏化,简单来说,就是通过适当的方法减少神经网络中的冗余成分,以降低网络对计算量和存储空间的需求。
神经网络推理的过程,本质上是"激活值"和"权重"不断做乘加运算。研究发现,大量参数(权重)接近于零,对最终输出结果贡献极小。稀疏化干的事,就是把这些"没用"的参数直接置为零,让模型变得更小、更快。
剪枝(Pruning)是实现稀疏化的核心手段。剪枝是在保证网络准确率下降较小的前提下,通过去除神经网络中部分组件(如权重、特征图、卷积核),降低网络的参数量,从而降低网络部署时的存储和计算代价。

二、技术原理与作用
2.1 怎么做:剪枝的工作流程
剪枝通常分为三个步骤:
- 训练一个普通(稠密)神经网络:先得到一个性能良好的完整模型。
- 选择阈值,剪掉不重要的连接:将绝对值小于阈值的权重置为零,得到一个稀疏网络。
- 微调(Fine-tuning):剪枝后网络性能通常会下降,需要对稀疏网络进行再训练,将性能恢复上来。
剪枝可以基于"幅值大小"(Magnitude Pruning)------绝对值越小的权重越不重要;也可以基于"梯度信息"或其他重要性评估标准。

2.2 有什么用:稀疏化的三大收益
| 收益 | 说明 |
|---|---|
| 减少存储 | 模型参数变少,文件体积缩小,便于部署到嵌入式设备 |
| 减少计算 | 0 × 任何数 = 0,跳过与零相关的无效乘加运算,加速推理 |
| 降低功耗 | 少算一次乘法、少搬一次数据,芯片功耗显著下降 |
三、稀疏化的分类
稀疏化按照"零值在矩阵中的分布规律",可以分为两大类:非结构化稀疏 和结构化稀疏 。区分这两类的核心标准是:零值在矩阵中是否有规律可循。有规律的硬件友好,没规律的硬件难办。
3.1 非结构化稀疏(Unstructured Sparsity)
非结构化稀疏是最直接的剪枝方式:将权重张量中绝对值最小的个体权重随机置零,不考虑任何位置或结构约束。
举例说明
假设训练好的一个4×4权重矩阵如下:
css
[ 0.5, 0.1, -0.3, 0.8]
[-0.2, 0.7, -0.1, 0.3]
[ 0.6, -0.4, 0.9, -0.2]
[ 0.4, -0.8, 0.2, -0.5]
设定阈值,把绝对值小于 0.3 的权重全部置零,剪枝后:
css
[ 0.5, 0, 0, 0.8]
[ 0, 0.7, 0, 0.3]
[ 0.6, -0.4, 0.9, 0 ]
[ 0.4, -0.8, 0, -0.5]
零值的位置完全随机,没有规律。稀疏率约 37.5%。
为什么对硬件不友好?
- 无法预取:硬件不知道下一个非零值在哪,必须先读索引再读值
- 负载不均衡:不同PE分配到的非零值数量不同,快的等慢的
- 内存访问不规则:非零值离散分布,无法利用连续读取的带宽优势
3.2 结构化稀疏(Structured Sparsity)
结构化稀疏的核心思想是:按固定模式移除权重,让零值呈规律性分布,从而适配硬件并行架构。
根据剪枝粒度可分为三个层次:
① Channel剪枝(通道剪枝) ------ 删除整个输入通道
如一个卷积层有4个输入通道、8个输出通道,每个卷积核尺寸为 3×3×4。 若删除第2个输入通道,每个卷积核从 3×3×4=36 个权重变为 3×3×3=27 个权重,总权重减少 25%。 输入特征图通道数从4变为3,后续层需相应调整。
② Filter剪枝(滤波器剪枝) ------ 删除整个卷积核(即输出通道)
删除后,输出特征图通道数直接减少,网络宽度被压缩。
③ Layer剪枝(层剪枝) ------ 删除整个网络层
粒度最粗,通常用于极深网络(如ResNet-50以上),计算量大幅下降但精度损失显著。
三种结构化剪枝对比
| 剪枝类型 | 删除单位 | 粒度 | 硬件友好度 | 精度影响 |
|---|---|---|---|---|
| Channel剪枝 | 单个输入通道 | 细 | 高 | 中等 |
| Filter剪枝 | 整个卷积核 | 中 | 高 | 较大 |
| Layer剪枝 | 整个网络层 | 粗 | 极高 | 很大 |
3.3 2:4 稀疏(2:4 Sparsity)
2:4 稀疏是 NVIDIA 在 Ampere 架构(A100 GPU)中引入的细粒度结构化稀疏技术。
核心规则
每连续 4 个元素为一组,强制保留 2 个非零值、剪掉 2 个。
举例:[0.5, 0.1, -0.3, 0.8] 经过2:4稀疏后,必须变成下列之一:
css
[0.5, 0, 0, 0.8] 或 [0, 0.1, -0.3, 0]
[0.5, 0.1, 0, 0 ] 或 [0, 0, -0.3, 0.8]
每4个中恰好2个非零、2个零,非零值在组内位置任意。
为什么硬件喜欢2:4稀疏?
- 每4个权重里一定有2个非零值 → 每个PE分到的有效计算量确定且均匀
- 索引信息仅需 2位 编码零值位置,开销极小
- 提供 确定性加速(NVIDIA Sparse Tensor Core可达2倍稠密吞吐量)
精度表现
通过一次幅值剪枝(保留绝对值最大的2个权重)后再训练,精度损失通常在 1%以内。
3.4 块稀疏(Block Sparsity)
块稀疏将权重矩阵划分为固定大小的块,每个块要么全部保留,要么全部置零。
举例说明
采用 2×2 块大小,一个4×4矩阵被分成4个2×2的块:
scss
块A (行0-1, 列0-1) 块B (行0-1, 列2-3)
[1, 2] [0, 0]
[3, 4] [0, 0]
块C (行2-3, 列0-1) 块D (行2-3, 列2-3)
[0, 0] [5, 6]
[0, 0] [7, 8]
块B和块C全零,被整体跳过;块A和块D有非零值,全部保留。
块大小选择:小块(2×2)精度损失小但索引开销大;大块(16×16)硬件收益大但精度损失大。2×2 或 4×4 是常见折中。
为什么硬件喜欢块稀疏?
- 控制逻辑极简:只需检查块头标志位(0跳过 / 1计算)
- 内存访问连续:块内数据连续存储,可突发读取
- 完美适配脉动阵列:可跳过整个零块,不产生流水线气泡
2:4稀疏 vs 块稀疏
| 对比维度 | 2:4稀疏 | 块稀疏 |
|---|---|---|
| 零值分布 | 每组4个中恰好2个零 | 整块全零或全非零 |
| 硬件复杂度 | 中等 | 极低 |
| 稀疏率 | 固定50% | 可调 |
| 脉动阵列适配 | 良好 | 极佳 |
| 工业界代表 | NVIDIA A100 | 学术界块稀疏研究 |
四、稀疏数据的硬件表示
稀疏化后的矩阵大部分是零,如果仍然按稠密方式存储,就浪费了存储空间和带宽。因此需要专门的数据格式来高效表示稀疏矩阵。
4.1 常见稀疏矩阵存储格式
| 格式 | 全称 | 原理 | 特点 |
|---|---|---|---|
| COO | Coordinate | 存储所有非零元素的(行, 列, 值)三元组 | 直观,但索引开销大 |
| CSR | Compressed Sparse Row | 按行压缩存储,用三个数组表示:非零值、列索引、行偏移(每行第一个非零值在 values 中的起始位置) | 行访问高效,最常用 |
| BCSR | Block CSR | CSR 的块版本,以块为单位存储 | 对块稀疏友好 |
| 位图(Bitmap) | --- | 用一个位图标记非零值的位置,压缩存储非零值本身 | 索引大小固定,适合硬件流水线,支持快速位运算 |
下面用一个具体的 4×4 稀疏矩阵,分别展示三种最常用的存储格式。
示例矩阵:
css
[ 1, 0, 0, 2 ]
[ 0, 3, 0, 0 ]
[ 0, 0, 4, 0 ]
[ 5, 0, 0, 6 ]
该矩阵共有 6 个非零值,稀疏率为 62.5%(16个元素中10个为零)。
4.1.1 COO(Coordinate,坐标格式)
原理 :存储所有非零元素的 (row, col, value) 三元组。
示例矩阵的 COO 表示:
| 行 | 列 | 值 |
|---|---|---|
| 0 | 0 | 1 |
| 0 | 3 | 2 |
| 1 | 1 | 3 |
| 2 | 2 | 4 |
| 3 | 0 | 5 |
| 3 | 3 | 6 |
特点:最直观,但索引开销最大(每个非零值需要存储行和列两个索引)。
4.1.2 CSR(Compressed Sparse Row,压缩稀疏行)
原理 :用三个数组表示 ------ 非零值(values)、列索引(col_index)、行偏移(row_ptr)。行偏移记录每行第一个非零值在 values 中的起始位置。
示例矩阵的 CSR 表示:
ini
values = [1, 2, 3, 4, 5, 6]
col_index = [0, 3, 1, 2, 0, 3]
row_ptr = [0, 2, 3, 4, 6]
解读:
- 第 0 行有 2 个非零值(
1, 2),从values[0]开始 - 第 1 行有 1 个非零值(
3),从values[2]开始 - 第 2 行有 1 个非零值(
4),从values[3]开始 - 第 3 行有 2 个非零值(
5, 6),从values[4]开始
特点:压缩了行索引,按行访问效率高,是 CPU/GPU 上最常用的格式。
4.1.3 Bitmap(位图索引)
原理:用一个位图标记非零值的位置,然后压缩存储非零值本身。
示例矩阵的 Bitmap 表示:
将矩阵按行展开成 16 个元素,非零标记为 1,零标记为 0:
ini
原始序列: [1, 0, 0, 2, 0, 3, 0, 0, 0, 0, 4, 0, 5, 0, 0, 6]
位图: [1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1]
values: [1, 2, 3, 4, 5, 6]
每 4 位一组转为十六进制:
1001→0x90100→0x40010→0x21001→0x9
特点 :索引大小固定(16 位),支持快速位运算(如 popcount 统计非零数量),最适合硬件加速。
4.2 对硬件设计的启示
在硬件中处理稀疏数据,核心挑战是如何高效地找到非零值并跳过零值。位图索引因其固定大小和快速位运算能力,在硬件设计中尤其受关注。
五、稀疏化与脉动阵列的关系
5.1 核心矛盾
脉动阵列依赖规则、同步、密集 的数据流,而稀疏化产生的数据是不规则的。直接让稀疏矩阵在脉动阵列上运行,会引发两个问题:
5.2 流水线气泡
什么是气泡?
脉动阵列是同步流水线------每个 PE 在每个时钟周期都在工作。当某个 PE 遇到零值时,它只是跳过本次乘法 (省功耗),但仍然要消耗一个时钟周期来传递数据,以保证下游 PE 的同步。
如果跳零导致下游 PE 收到零值"空洞",这种空闲状态会像气泡一样沿流水线传播,降低整体吞吐率。
结论:跳零能省功耗,但压缩不了总时长------该占的周期一个没少,只是少干了活。
5.3 负载不均衡
什么是不均衡?
不同 PE 分到的有效数据量不同------有的 PE 全是非零值,忙不过来;有的 PE 全是零值,反复跳零。但最忙的那个 PE 决定了整列的完成时间,其他 PE 的空闲无法转化为总吞吐的提升。
结论:快 PE 等慢 PE,整个阵列被最忙的 PE 拖住。

六、总结
稀疏化是继量化之后,深度神经网络压缩与加速的第二把利刃。它与量化相辅相成:
- 量化:把 32 位浮点数压缩成 4 位、8 位整数 → 减少数据位宽
- 稀疏化:把不重要的权重直接置零 → 减少数据数量
两者结合,可以将模型体积和计算量压缩一个数量级以上。
参考阅读:
- 《从英伟达A100 GPU说起,浅谈细粒度结构化稀疏》
- NVIDIA 2:4 Sparsity 技术解析
- SMASH:软硬件协同的稀疏矩阵索引与存储机制
- DenSparSA:兼顾稠密与稀疏的脉动阵列架构