1. 稀疏计算基础:什么是稀疏性?为什么大模型需要稀疏计算?

大家好,我是你们这趟旅程的向导。今天咱们聊聊稀疏计算。

说实话,我第一次接触「稀疏」这个概念,是在做推荐系统的时候。那时候模型里有个几百亿的特征交叉矩阵,一加载就爆内存。后来才发现,矩阵里99%的元素都是0。嗯,这就是典型的稀疏场景。

那稀疏性到底是什么?说白了,就是数据里「空」的地方远多于「有」的地方。比如一张黑白图,大部分区域是白色背景,只有几个黑点——这就是稀疏的。

核心定义: 如果一个数据结构中,零值(或无效值)占比超过50%,我们就认为它是稀疏的。大模型里,这个比例经常高达99%以上。

1.1 为什么大模型需要稀疏计算?

你想想看,现在的大模型动不动就是几百亿参数。每次推理都要把所有参数算一遍?那太浪费了。

我举个例子。你在做一道数学题时,大脑里几千亿个神经元不会全部激活。只有跟解题相关的几个区域在「工作」。大模型也一样——对于给定的输入,大部分神经元其实处于「静默」状态。

这就是稀疏计算的用武之地:

  • 节省内存:只存储非零元素,而不是整个矩阵。我见过一个70B模型,用稀疏格式存储后,显存占用从140GB降到了不到30GB。
  • 加速计算:跳过那些0值,只算有用的部分。推理速度能提升3-5倍。
  • 降低功耗:少算一个0,就少一次乘加操作。数据中心里,这能省下不少电费。
我的经验: 刚开始做稀疏优化时,我总想着把所有层都稀疏化。后来发现,有些层(比如embedding层)稀疏化收益很小,反而增加了复杂度。建议先从attention层和FFN层入手。

1.2 稀疏矩阵的存储格式

既然要跳过0值,那怎么存这些非零元素呢?总不能还用一个完整的矩阵吧。这里介绍三种最常用的格式。

COO格式(Coordinate Format)

COO是最直观的格式。它用三个数组来存储:

  • 行索引:记录每个非零元素的行号
  • 列索引:记录每个非零元素的列号
  • 数值:记录每个非零元素的值
# 假设有一个 4x4 的稀疏矩阵
# 非零元素在 (0,1)=5, (2,3)=8, (3,0)=3

# COO格式
row_indices = [0, 2, 3]
col_indices = [1, 3, 0]
values      = [5, 8, 3]

# 重建矩阵时,把值填到对应位置,其余补0

COO的优点是简单,容易理解。缺点呢?做矩阵乘法时效率不高,因为行索引是乱序的。

避坑指南: 我曾经在项目中直接用COO格式做矩阵乘法,结果比稠密计算还慢。后来才发现,COO适合构建和转换,不适合计算。要加速计算,得用CSR或CSC。

CSR格式(Compressed Sparse Row)

CSR是工业界最常用的格式。它把COO的行索引做了压缩:

  • 行偏移:记录每行第一个非零元素在values数组中的起始位置
  • 列索引:记录每个非零元素的列号
  • 数值:记录每个非零元素的值
# 同样的矩阵
# 非零元素: (0,1)=5, (2,3)=8, (3,0)=3

# CSR格式
row_ptr = [0, 1, 1, 2, 3]  # 第0行有1个元素,第1行0个,第2行1个,第3行1个
col_indices = [1, 3, 0]
values      = [5, 8, 3]

# 要获取第2行的非零元素:
# 从 row_ptr[2]=1 到 row_ptr[3]=2
# 所以第2行有 col_indices[1]=3, values[1]=8

CSR的好处是行访问非常快。大模型推理时,我们经常按行做矩阵乘法,CSR就很合适。

CSC格式(Compressed Sparse Column)

CSC和CSR是对称的。它压缩的是列索引:

  • 列偏移:记录每列第一个非零元素的位置
  • 行索引:记录每个非零元素的行号
  • 数值:记录每个非零元素的值
# 同样的矩阵
# CSC格式
col_ptr = [0, 1, 1, 1, 2]  # 第0列有1个元素,第1列0个,第2列0个,第3列1个
row_indices = [3, 2]
values      = [3, 8]

# 注意:这里(0,1)=5在CSC中属于第1列,但第1列没有非零元素?
# 不对,我写错了。重新来:
# 非零元素: (0,1)=5, (2,3)=8, (3,0)=3
# 第0列: (3,0)=3 → 1个元素
# 第1列: (0,1)=5 → 1个元素
# 第2列: 无 → 0个元素
# 第3列: (2,3)=8 → 1个元素
# 所以 col_ptr = [0, 1, 2, 2, 3]
# row_indices = [3, 0, 2]
# values = [3, 5, 8]

CSC适合按列访问的场景。比如在反向传播中,我们经常需要按列计算梯度。

1.3 三种格式对比

格式 存储空间 行访问 列访问 矩阵乘法 适用场景
COO 3N 构建、转换
CSR 2N + R 前向推理
CSC 2N + C 反向传播

(N为非零元素个数,R为行数,C为列数)

我的建议: 做推理优化时,优先用CSR。做训练优化时,考虑CSC。如果只是做原型验证,COO就够了,别在格式转换上花太多时间。

1.4 知识体系总览

下面这张图,帮你把本章的核心逻辑串起来:

稀疏计算知识体系 稀疏性 为什么需要稀疏计算? 节省内存 加速计算 降低功耗 核心概念 零值占比 > 50% 非零元素存储 跳过零值计算 存储格式 COO:简单直观 CSR:行访问快 CSC:列访问快 目标:用最少的计算,达到最好的效果

这张图把本章的三个核心问题串在了一起:稀疏性是什么为什么需要它怎么存储它。后面的章节,我们会一步步深入这些技术细节。


公众号:蓝海资料掘金营,微信deep3321