flowchart LR
TokenIn["Token 激活向量"] --> Router["门控路由网络 Top-K 评分"]
Router --> Scatter["Token 重排与专家分组 (Permute/Scatter)"]
Scatter --> GroupGEMM["分专家并行 Grouped GEMM 计算"]
GroupGEMM --> Gather["加权聚合与逆重排 (Unpermute/Gather)"]
Gather --> Output["输出融合后激活向量"]
第 5 课:稀疏推理:权重、MoE、Sparse Attention 与 HiSparse
参考答案版:包含完整代码实现与问答题深度参考解析。建议先独立完成练习题后再展开核对。
本课目标与通过标准
本课产出:能区分三类稀疏性的数学对象、kernel/通信前提和质量风险,并从 SGLang HiSparse 源码解释稀疏 attention 为什么仍需完整逻辑索引与多级 KV 状态。
通过要求:唯一代码填空题通过全部断言;Q1~Q3 都能沿源码对象给出因果链;能指出一个正确性不变量、一个性能边界和一个需要 benchmark 才能确认的结论;总分至少 8/10。
源码版本与阅读方法
本课程使用固定 commit 的永久链接保证行号可复现,同时链接 current docs 供核对最新变化。阅读时先画调用图和状态所有权,再进入分支;不要从大文件第一行机械顺读。
源码与论文阅读路线:
SGLang
scheduler.py搜索enable_hisparse:看 prefill staging 如何转入 sparse decode。mem_cache/allocator/hisparse.py:区分 full logical indices、compressed indices 与 sparse device buffer。hisparse_memory_pool.py:追 index translation 与 KV transfer。NSA 论文:只读三分支结构、hardware-aligned block selection 与训练方式。
SparseGPT/Wanda:比较权重评分和重构;再核对目标 runtime 是否真的有 sparse GEMM。
MoE/DeepEP:把“每 token 激活少量专家”与 all-to-all dispatch/combine 一起分析。
源码快照:SGLang 9deb6952afa4。
核心概念与运行机制
1. 它是什么,解决什么问题
随着大模型参数量向千亿甚至万亿规模迈进、以及上下文窗口扩展至 128K~1M Tokens,传统“全密集(Dense)”计算范式面临两大约束构成的物理天花板:
显存容量与带宽墙(Memory Capacity & Bandwidth Wall):Decode 阶段属于极度访存受限(Memory-Bound)场景,每生成一个 Token 都需要将数百 GB 的全模型权重及线性膨胀的全部历史 KV Cache 从 HBM 搬运进 SRAM。
长序列计算复杂度墙( Complexity Wall):Prefill 与长上下文推理中,标准 Attention 的矩阵乘与 Softmax 计算量和显存占用随序列长度 呈二次方增长。
稀疏推理(Sparse Inference)旨在利用大模型表征中的自然冗余,在几乎不损失模型精度的前提下跳过无关计算与访存。如图 5-1 所示,现代工业级推理系统构建了四维协同的稀疏优化矩阵: - 权重稀疏(Weight Sparsity):对静态模型权重矩阵剪枝,利用 2:4 半结构化稀疏匹配硬件 Tensor Core; - 激活/专家稀疏(MoE / Expert Sparsity):参数总量极大,但每个 Token 前向时仅动态激活 Top- 个专家网络; - 注意力稀疏(Sparse Attention / NSA):Query 仅对相关性极高的局部或被选中的关键 Token 块计算注意力; - 系统级分层稀疏(HiSparse):将算法级动态稀疏注意力与运行时多级存储(Host 内存与 GPU 显存流式换入换出)深度协同。
2. 它如何工作
稀疏化优化跨越了模型算法、编译器内核与分布式运行时三个层面:
- MoE 动态路由与跨卡打散聚合(Router, Dispatch & Combine):
- 如图 5-2 所示,每个 Token 的隐藏向量 经过门控网络计算专家得分:
图 5-2:MoE 动态路由、专家分组计算与跨卡打散聚合流程
$$g(x) = \text{Softmax}(\text{TopK}(x \cdot W_{\text{gate}}, K))$$
- 随后通过
Scatter/Permute算子按目标专家对 Token 进行排序并分组打包;在专家并行(Expert Parallelism, EP)拓扑下,跨节点/跨 GPU 通过高带宽 All-to-All 通信(如 DeepEP)将 Token 分发给宿主专家卡; - 各卡调用优化的 Grouped GEMM 或 Batched GEMM 算子并行执行专家 FFN 计算;
- 计算完成后再次执行 All-to-All 通信与
Gather/Unpermute算子,按原始顺序还原 Token 并加权累加。
- 块稀疏 Attention 与三分支架构(NSA Architecture):
- 以 Native Sparse Attention (NSA) 为代表的前沿稀疏注意力,摒弃了难以被 GPU 并行硬件加速的细粒度逐 Token 随机稀疏,转向硬件友好的粗粒度 Block 稀疏。
- 算法通常解耦为三个互补分支:
- 压缩分支(Compressed Branch):对连续 Key-Value 块执行池化摘要,以极低显存代价捕捉全序列的长程全局上下文;
- 选择分支(Selected Branch):计算 Query 与各个 Block 摘要的注意力得分,利用 Top- 算子动态筛选出高信息量的少数关键 Block,进行硬件连续对齐的细粒度精确计算;
- 滑动窗口分支(Sliding Window Branch):始终保留紧邻当前 Query 的局部因果窗口(Local Window)以及最开头的注意力汇元(Attention Sinks),确保局部语法连贯性与语义基准。
- HiSparse 多级 KV 管理与状态映射:
- 在 SGLang HiSparse 架构中,调度器与内存分配器解耦出三层状态视图:全量逻辑索引(Full Logical Indices)、压缩索引(Compressed Indices)与设备稀疏缓冲区(Sparse Device Buffer)。
- Prefill 阶段保留全量状态以支撑全局选择器;进入 Decode 阶段后,仅将当前步及其窗口所需的活跃 KV 驻留在高速 GPU 显存,未命中块则驻留或分流至主机内存或压缩池,实现极高的 KV 显存压缩比。
3. 正确性条件与常见误区
- 因果掩码截断与未来信息泄露(Causal Boundary Invariant):
- 在展开被选中的 Block 时,即使某个 Block 的物理边界涵盖区间 ,若该 Block 跨越了当前的因果位置(即 ),则该 Block 内部位于
query_pos之后的 Token 绝对禁止纳入计算: 越界访问将导致自回归时序因果性破坏,引发灾难性的训练-推理不一致。
- 在展开被选中的 Block 时,即使某个 Block 的物理边界涵盖区间 ,若该 Block 跨越了当前的因果位置(即 ),则该 Block 内部位于
- 动态稀疏不可逆丢弃的误区:
- 致命误区:误以为当前 Token 没有选中的 KV 块,未来生成的 Token 也绝不需要,因此可以直接从显存中彻底销毁。
- 实际情况:注意力的重要性分布随上下文生成呈动态漂移。当前步未被选中的背景块,完全可能在数十步后被后续 Query 重新激活。若物理销毁,后续步骤将发生无法补救的注意力缺失,模型输出崩溃。因此,HiSparse 必须维持逻辑全生命周期的元数据索引与分级换入机制。
- “参数稀疏度 = 性能加速比”的思维陷阱:
- 许多研究人员误以为 50% 的稀疏度就能带来 2 倍的吞吐。事实上,若未采用匹配硬件加速指令的稀疏格式(如 NVIDIA Ampere 架构以来的 2:4 Structured Sparse Tensor Core),稀疏带来的非连续内存跳跃访问与索引开销,会导致性能不仅无法提升,反而因破坏 Memory Coalescing 与 Warp Divergence 而显著劣化。
4. 性能与工程取舍
- 非结构化稀疏 vs. 2:4 结构化稀疏:
- 非结构化剪枝(Unstructured Pruning)由于不限制非零元素位置,模型精度极高;但通用 GPU 无法高效执行随机稀疏矩阵乘,通常沦为“零加速”。
- 2:4 结构化稀疏强制每连续 4 个权重元素中必须有 2 个为零,硬件 Tensor Core 可直接提供 2 倍峰值计算算力,但面临模型精度的再训练恢复挑战。
- MoE 专家并行中的通信与计算比(Arithmetic Intensity vs. All-to-All):
- MoE 架构将参数量扩展了数倍,激活计算量仅增加少量。但在低并发 Decode 阶段,每个专家分配到的 Token 数极少(甚至每卡仅 1~2 个 Token),矩阵乘计算时间极短,跨卡跨节点的 All-to-All 通信时延完全暴露在关键路径上;
- 只有在超高并发或搭配深度优化的跨卡通信重叠调度库(如 DeepEP 异步重叠)时,MoE 的吞吐优势才能完全释放。
具体演示
设当前 Query 位于位置 (即正在生成第 16 个 Token,从 0 计),配置 block_size = 4,local_window = 3,sink_tokens = 2。Top- 路由选择器选出了 Block 索引集合 [1, 3]:
Sink 分支:访问序列头部锚点 Token 集合 ;
Selected Blocks 分支:
- Block 1:跨度为 ,包含 Token ,均满足因果约束;
- Block 3:跨度为 ,受因果边界限制 ,包含 Token ;
Local Window 分支:覆盖 ,包含 Token ;
最终合并去重:各分支集合取并集并排序: 总共仅需读取 10 个历史 Token 的 KV 向量,相比于全量 Dense 访问(16 个 Tokens)节省了近 40% 的访存带宽与计算,且严格遵循因果一致性。
实践任务:唯一代码填空题
实现一个硬件友好的 block-sparse raw-KV 访问计划,合并 sink、selected blocks 和 local window,并严格保持 causal。
只能修改 TODO/______ 位置,不得删除断言或放宽通过条件。
Code
def sparse_raw_kv_indices(query_pos, selected_blocks, block_size,
local_window, sink_tokens=0):
if query_pos < 0 or block_size <= 0 or local_window < 0 or sink_tokens < 0:
raise ValueError("invalid sparse attention geometry")
indices = set(range(min(sink_tokens, query_pos + 1)))
# TODO:展开选中 block,但不得访问 query_pos 之后的 token。
for block in selected_blocks:
if block < 0:
raise ValueError("negative block")
start = block * block_size
end = ______
indices.update(______)
local_start = max(0, query_pos - local_window + 1)
indices.update(range(local_start, query_pos + 1))
return sorted(indices)
assert sparse_raw_kv_indices(15, [1, 3], 4, 3, 2) == [0, 1, 4, 5, 6, 7, 12, 13, 14, 15]
assert sparse_raw_kv_indices(2, [1], 4, 2, 1) == [0, 1, 2]检查方法
运行断言;加入重复 block 和完全位于未来的 block,确认去重且不越过 causal 边界。
Q1
为什么 50% unstructured weight sparsity 不等于 GEMM 快 2 倍?
你的答案:
Q2
NSA/HiSparse 为什么不能简单删除未选中的 KV cache?
你的答案:
Q3
MoE 每 token 只激活 top-2 experts,为什么高并发 decode 仍可能比 dense 慢?
你的答案:
评分规则
- 代码 4 分:主路径 2 分、边界条件 1 分、能映射回源码对象 1 分;
- Q1~Q3 各 2 分:必须包含对象、状态变化、正确性或成本链;
- 一票否决:把论文峰值写成普遍生产结论;把源码支持写成所有模型/硬件可用;混淆算法正确性与性能;只背类名而说不清状态所有权。