正在获取所在地区…
正在读取天气
音乐
暂未播放
DeepSeek-V3.2 技术报告精读:DSA 的成本账、双模实现与稀疏注意力的质量验证
这份报告在 DeepSeek 路线里的位置
DeepSeek-AI 于 2025 年 12 月 2 日把 DeepSeek-V3.2 的技术报告挂上 arXiv(arXiv:2512.02556)。报告有 23 页,只有第 2 章讲架构,其余篇幅给了续训数据、后训练、Agent 任务合成与评测。对关心推理的人来说,真正值得逐字读的是 2.1 节的 DSA、2.2 节的”持平评测”和 2.3 节的推理成本,外加附录 A 里关于 MLA 两种模式的说明。
先说清楚这篇报告和前作的关系,很多讨论把它讲混了。2025 年 9 月 29 日 DeepSeek 开源了 DeepSeek-V3.2-Exp,那是一份 6 页的简短报告,把 DSA(DeepSeek Sparse Attention)作为唯一的架构改动发了出去。12 月的 V3.2 报告在 2.1 节开篇给两者定了性:
DeepSeek-V3.2 uses exactly the same architecture as DeepSeek-V3.2-Exp. Compared with DeepSeek-V3.1-Terminus … the only architectural modification of DeepSeek-V3.2 is the introduction of DeepSeek Sparse Attention (DSA) through continued training.
也就是说,从 V3.1-Terminus 到 V3.2,结构上的改动只有 DSA 一项,而且是在已有权重上通过继续预训练”长”出来的,不是重新训练一个新架构。其余的工作——续训算力的扩张、专家蒸馏、混合 RL、Agent 任务合成——都发生在后训练阶段。这给推理侧一个重要推论:V3.2 与 V3.2-Exp 可以共用同一套推理实现,任何为 V3.2-Exp 写好的索引器 kernel、稀疏 MLA kernel、KV 布局,都可以原样用在 V3.2 上。报告后半段对 agentic 任务的投入再多,也不会改变一次前向的算子图。
站内已经有两篇把 DSA 的索引器公式、dI/HI/k 三个参数与 vLLM 中的算子实现拆得很细的文章:DSA 稀疏注意力完全拆解:从 DeepSeek-V3.2 的闪电索引器到 vLLM 的算子实现,以及 GLM-5.3 推理全链路(一):一个请求在 SGLang 里经过哪些算子、哪些通信。本篇不再复述 kernel 级的代码细节,而是回到这份 23 页报告本身,把它对推理侧真正给出的东西逐条拆开:复杂度账本是怎么算的、那两条成本曲线读出来是多少、“masked MHA 模式”到底改了什么、索引器缓存这笔第二本 KV 账怎么记、以及”稀疏没伤质量”这个结论靠什么证据支撑。
顺带把架构改造的代价交代清楚,因为它是”推理侧收益”的另一半。DSA 不是在原模型上外挂一个筛选器,而是让主干模型重新适应稀疏模式:报告的做法是在 V3.1-Terminus 的 128K 基座上做两段继续预训练(索引器单独热身,随后联合适配),合计约 943.7B token,索引器的优化目标与主模型相互分离。训练流程的细节属于报告 2.1.1 节,与推理无关,这里只需记住一句话:这类稀疏化无法在部署时临时打开,只能在模型发布时固定,部署侧能调的只有 k、缓存和调度。
DSA 的两个组件:报告原文的公式与符号
报告对 DSA 的定义只有两个组件,原文措辞是 “a lightning indexer and a fine-grained token selection mechanism”。前者负责打分,后者负责挑 token。
闪电索引器(lightning indexer)计算查询 token ht 与前序 token hs 之间的索引分数:
It,s=j=1∑HIwt,jI⋅ReLU(qt,jI⋅ksI)逐项解释符号:
- ht∈Rd、hs∈Rd 是查询 token 与前序 token 的隐状态,这里 d 是模型隐层宽度,对 V3.2 是 7168。
- HI 是索引器头数,开源配置里是 64。
- qt,jI∈RdI 是第 j 个索引器头的查询向量,由 ht 投影得到;ksI∈RdI 是前序 token hs 投影出的索引器 key,注意它不带 j 下标——索引器的 key 在所有头之间共享,这是 MQA 式的结构。
- dI 是索引器头维度,配置里是 128。
- wt,jI∈R 是从 ht 投影出的逐头权重,是一个标量。这相当于让每个头带一个可学习的”话语权”,而不是简单地对 64 个头的分数求平均。报告没有细说这个权重的初始化与训练细节,从形式上看它起到的是对各头打分的加权求和。
- ReLU 作为激活函数,报告给的理由只有一个词:throughput。线性整流比 sigmoid 便宜,而且它的一个可观察后果是:分数对各头是线性求和,某个头对某个历史 token 的点积为负时,该头的贡献被精确截断为 0 而不是保留一个小负数。从结果上看这会让索引分数更接近”少数头投票”的形态,但报告并没有把注意力集中度当作设计理由,它只说了吞吐。另一个配套事实是索引器”头数少、可以用 FP8 实现”,所以即便保留了平方项,算术开销仍然很小。
拿到每个查询 token 对所有历史位置的索引分数 It,: 之后,细粒度 token 选择机制只保留 It,s 排进 Top-k 的那些 KV 条目 cs:
ut=Attn(ht,{cs∣It,s∈Top-k(It,:)})这里的 cs 是 MLA 的潜向量(latent vector),不是完整还原的 K/V。ut 是这一个注意力头的注意力输出集合。k 是每个查询 token 看的 KV 条目数,配置里 index_topk=2048。
把三个参数放在一起,可以得到一个有用的对比:索引器用 64 个 128 维的头对全序列打分,每个位置只读 128 维的共享 key;而主注意力每层只有 128 个查询头、每个潜向量 576 维(512 维内容潜向量加 64 维 RoPE 分量)。索引器在全序列上的单次打分开销,大约是主注意力在同样位置上的 128/576 再乘以头数比例 64/128,即约 1/9。这个粗略比例解释了为什么报告说索引器的 O(L2) 虽然还在,“computational efficiency is remarkable”。
k 与 L 的比例才是真正的稀疏度
k=2048 这个数字单独看没有意义,它的含义取决于上下文长度。把两者相除:
| 上下文长度 L | 选择比例 k/L | 被跳过的历史 | 主注意力计算相对稠密的残余比例 | 索引器计算相对稠密的残余比例 |
|---|---|---|---|---|
| 8K | 25% | 75% | 25% | 11% |
| 16K | 12.5% | 87.5% | 12.5% | 11% |
| 32K | 6.25% | 93.75% | 6.25% | 11% |
| 64K | 3.1% | 96.9% | 3.1% | 11% |
| 128K | 1.6% | 98.4% | 1.6% | 11% |
后两列是这张表真正的信息所在。主注意力的残余比例随 L 线性下降——这是线性化带来的收益;索引器的残余比例则是一个不随长度变化的常数,约 11%(前面按维度与头数算的 128/576×64/128,且假设 FP8)。两列放在一起,就能看出 DSA 的边际收益在哪里递减:L 越长,主注意力那一项越接近 0,总计算量就越被那个常数约 11% 的索引器项主导。
这张表也解释了为什么短上下文下 DSA 的端到端收益有限。当 L 只有 8K 时,主注意力这一项还剩 25%,与索引器的 11% 相加是 36%——单看乘加次数确实省掉了三分之二,但这只是”理论计算量”。真正花掉的时间还要加上 Top-K 排序、索引数组构造、按索引 gather 的访存碎化,以及索引器这套 kernel 的启动开销;在短序列上,这些固定成本摊不开,于是理论上接近 3 倍的计算节省在墙钟时间上可能只剩很小的优势,甚至为负。到 128K 时,两项相加约 12.7%,固定成本被长度摊薄,“稀疏”才真正变成数量级的节省。这正是 Figure 3 起始段两条线几乎重合、而长上下文段迅速分叉的原因:理论计算量的比值是一条曲线,端到端成本是另一条曲线,两者只在长上下文处收敛。
这张表也解释了为什么前 3 层保持稠密是合理的:如果前几层的注意力模式本来就比较局部,稀疏筛选在这些层上收益不大,反而增加索引器开销。first_k_dense_replace=3 的具体层数选择报告没有给出消融,但从结构上看,它把”稀疏化”推迟到浅层的表示已经稳定之后。
这张架构图应该怎么看
报告 Figure 2 把 DSA 在 MLA 下的实例化画成了一张数据流图。这张图信息密度很高,值得逐块拆开讲,因为后面所有关于”稀疏落在哪一个寻址单位上”的讨论都建立在它的结构上。

图片来源:DeepSeek-V3.2 技术报告 Figure 2。绿色部分标出 DSA 按索引器分数选出 Top-k 个 KV 条目的那条路径。
图的左端是输入隐状态 ht,它分出两条主路:一条进入主注意力(图上方标注 Multi-Query Attention (Core Attention)),一条进入闪电索引器(图右侧 Lightning Indexer)。
主注意力这一路先对 ht 做两次下投影,得到查询的内容分量 {qt,iC} 与潜向量 ctKV;再单独投影出带 RoPE 的查询位置分量 {qt,iR} 与 key 位置分量 ktR。图上方那条 “concatenate” 把 {[qt,iA;qt,iR]} 拼接成完整的每头查询,把 {[ctKV;ktR]} 拼接成每 token 的一个寻址单位。注意这里 cKV 与 kR 是拼在一起的:一个位置在显存里占 512 + 64 = 576 个元素,所有查询头共享这一份。这就是 MQA 模式的具体形态,也是 DSA 能让”选出位置”等价于”选出潜向量”的原因。
索引器这一路从 ht 投影出 {qt,jI}(j 遍历 64 个索引器头)和 {wt,jI} 这组逐头权重。图右侧那行 “partially apply RoPE” 是索引器与主注意力的一个呼应:索引器只对其查询的一部分维度应用 RoPE,与主注意力”部分维度带位置”的设计保持一致。被查询的 key 侧 ktI 也由 ht 投影,并且同样只部分带 RoPE。
绿色区域是这条图的重点。Top-k Selector 接收索引器给出的分数,在每个查询 token 上选出 k 个位置,然后这些选中位置的潜向量被送进主注意力的点积。图里绿色箭头直接横跨了左右两路——说明”选”这个动作发生在索引器与主注意力之间,而不是在主注意力内部。这意味着在内核实现上,主注意力必须能够接收一个外部的”位置列表”,而不是按因果掩码自己遍历。这是稀疏 MLA kernel 与稠密 MLA kernel 在接口上最大的区别,也是站内另一篇拆解 vLLM 算子时着重讲的”索引数组如何被消费”的起点。
输出侧,每头输出 {ot,i} 被 concatenate 并经过上投影还原成隐状态 ut。在 MQA 模式下这一步相当于把 WUV 与输出投影合并——因为注意力是在潜空间完成的,输出并不需要先还原成完整维度的 V。
把这张图与”为什么必须挂在 MLA 的 MQA 模式上”连起来看,逻辑是闭合的:绿色选择落在潜向量这一层,潜向量是所有查询头共享的最小寻址单位,所以一次 gather 读进来的 576 维数据可以被全部 128 个查询头重复使用;索引器本身用的则是另一套 128 维、64 头共享的 key,两者互不混用。如果换成 MHA 形态,选中的”位置”在每个头下都是不同的数据,一次 gather 只服务一个头,稀疏带来的带宽节省会被 gather 的访存碎化吃掉。
索引器一次打分的算术强度
理解了结构,可以再算一笔索引器打分的算术强度,用它判断这一步在 GPU 上是算力受限还是带宽受限。
每个历史位置、每个索引器头,做一次 128 维点积再取 ReLU:约 256 FLOP(以乘加计 2 FLOP)。64 个头合计约 16,384 FLOP。每读入一个位置的索引器 key 是 128 个 FP8 字节(加 scale 约 132 字节)。所以索引器的算术强度大约是
132 B16,384 FLOP≈124 FLOP/BH800 的 FP8 算力相对显存带宽的比例远高于这个数(FP8 稠密算力约 1979 TFLOPS,HBM 带宽约 3.35 TB/s,比值约 590 FLOP/B)。也就是说,仅看单次打分,索引器在解码阶段是带宽受限的:GPU 的算力单元有大量空闲,时间几乎全花在把索引器 key 从显存拉进来。
这个结论与成本曲线的形状可以互相印证。解码时稀疏路径的成本线不是水平的,而是随 L 缓慢上升:每多一个历史 token,就要多读一份索引器 key(约 132 字节)来打分,主注意力那部分不多读。斜率对应的正正是索引器 key 的线性增长。前面量出的 96K 对 16K、成本从 0.14 涨到 0.20 美元——约 43% 的涨幅——可以被解释为索引器 key 的读取量增长在总成本中的占比逐渐变大,而主注意力那 k=2048 条潜向量的读取是常数。
prefill 时情况相反:索引器要对 L×L 个 (查询, 位置) 对打分,算术量正比于 L2⋅HI⋅dI,而读入的 key 只正比于 L(同一份 key 被 L 个查询复用)。这时索引器的算术强度是 Θ(L),在长序列下变成算力受限。这就是为什么报告说 prefill 侧仍然保留了一个平方项,以及为什么框架里会出现”索引器预填充工作区约 825 MB”这样的大小——那其实是给这些中间结果留的空间。
复杂度从 O(L2) 到 O(Lk):被合并同类项掩盖的那部分
报告 2.3 节的原文是:
DSA reduces the core attention complexity of the main model from O(L2) to O(Lk) … Although the lightning indexer still has a complexity of O(L2), it requires much less computation compared with MLA in DeepSeek-V3.1-Terminus.
这句话信息量很大,但常被读成”索引器被忽略了”。它没有被忽略,它是被当作一个常数更小的平方项来处理。要理解 DSA 到底省了什么,需要把开销拆成两个互相独立的阶段,这一点决定了后续所有工程判断。
Prefill:平方项没消失,只是系数变了
在 prefilling 阶段,L 个查询 token 一次性对 L 个历史位置做注意力。稠密 MLA 的核心注意力计算量正比于 L2dcH,其中 dc 是潜向量维度(每 token 每层的实际读取单位)。DSA 的主注意力部分变成 L⋅k⋅dc⋅H,因为每个查询只处理 k 个被选中的位置。
但索引器这一项仍然是完整的 L×L 打分:
Cindex∝L2⋅HI⋅dI把两项相加,DSA 的 prefill 复杂度其实是
Cprefill,DSA=O(L2HIdI)+O(L2)+O(LkdcH)逐项对应:第一项是索引器对 L×L 个 (查询, 位置) 对打分——L2 个对、每个对 HI 个头、每头点积 dI 维;第二项是 Top-K 选择与索引数组构造,它在每个查询上都要对 L 个分数做一遍比较与排序,同样是 L2 量级但常数更小(只是比较,没有乘加);第三项才是主注意力在 k 个位置上的计算。只有最后一项真正线性化了。
所以报告说”从 O(L2) 到 O(Lk)“,严格讲是指主注意力这一项,而不是整条注意力路径。把三项按开源配置代进去,就能看出 prefill 的真正常数:HIdI=64×128=8192,而主注意力线性项在 k=2048 时是 kdcH=2048×512×128≈1.34×108。后者比前者大了约 1.6 万倍——也就是说,在 2.1 节说过的主注意力 O(Lk) 与索引器 O(L2) 之间,只有当 L≳1.6×104 时,两块的量级才接近。这给出了一个具体判断:在 16K 以下做 prefill,索引器那一项是可以忽略的零头;在 128K 时,它变成同等量级的支出,prefill 的吞吐上限由”索引器打分 + 主注意力”两部分共同决定,而不只是主注意力。这就是为什么框架侧为索引器单独准备了一块近乎 1 GB 的预填充工作区——它不是零头。
Decode:这才是 O(L) 字节搬运被砍成 O(k) 的地方
解码时每步只有 1 个查询 token,对 L 个历史位置做注意力。这时两阶段的变化就完全不同了:
| 阶段 | V3.1-Terminus(稠密 MLA) | V3.2(DSA) |
|---|---|---|
| 索引器打分 | — | 对全部 L 位置打分:HIdI 维的读 + 写 L 个分数 |
| Top-K 选择 | — | 在 L 个分数里取出 k 个(配置 2048) |
| 主注意力 | 读全部 L×576 字节 | 只读 k×576 字节 |
解码是访存受限的:GPU 的算术单元大部分时间在等 HBM。解码时稠密 MLA 每步要从显存里把整段历史 KV 拉一遍,DSA 只拉 k 个潜向量。真正带来解码加速的不是”少算”,而是”少读”。稠密路每 token 读的是 576 个元素,稀疏路则是 576 个元素乘 k(主注意力)加上 128 个元素乘 L(索引器 key),而 k=2048≪L 时这两项差别会非常大。举个例子,上下文到 128K 时:稠密路要读 128K×576 个元素;稀疏路要读 2048×576+128K×128 个元素,两者之比约 0.24。也就是说,仅看在解码时每步的 KV 读取量,稀疏路只占稠密路的四分之一左右——这与成本曲线中段 96K 处约 7 倍的差距并不完全吻合(端到端成本还包含权重读、MoE、索引器打分中的计算部分等),但方向一致:解码加速的来由是 KV 读取量的结构性下降,而不是算力使用率的提高。
这个拆分也解释了报告 2.3 里对”短序列预填充”的特殊处理为什么存在:prefill 时那个平方项(索引器打分)在短上下文下占比会急剧上升,而主注意力本来就不贵,整条路径算下来可能反而更慢。下一节讨论的 masked MHA 模式,正是对这个问题的直接回应。
双模实现:长序列走索引器,短序列走 masked MHA
报告 2.3 节末尾有一句话单独成段,很容易被略过:
Note that for short-sequence prefilling, we specially implement a masked MHA mode to simulate DSA, which can achieve higher efficiency under short-context conditions.
“masked MHA mode to simulate DSA”——这句话需要从两个层面理解:它在算力上模拟了 DSA 的输出,但在实现上走的是一条不同的 kernel 路径。
为什么要”模拟”而不是”跑稀疏”
DSA 的输出定义是:每个查询只对 Top-k 的历史位置做注意力。如果 L≤k,那么 Top-k 选出来的就是全部 L 个位置,稀疏选择在语义上等价于全注意力。但实现路径不同:
- 稀疏路径:索引器打完分 → 做 Top-K → 生成长度为 k 的索引数组 → 稀疏 MLA kernel 按索引 gather 读取。
- 全注意力路径:不做打分、不做选择,直接按因果掩码(causal mask)跑 MLA kernel。
短序列时,稀疏路径多做了一次全量打分、一次排序、一次索引数组构造,而主注意力本来要算的 L 个位置也就那么点。索引器那一整套固定开销摊在很小的序列上,就成了负收益。论文选择在模型侧直接准备一条稠密回退路径,而不是让框架在 kernel 侧自己判断。
“masked MHA”里的 masked 和 MHA 各指什么
这两个词要分开看。
masked 指因果掩码,即每个查询只能看到自己及之前的位置。短序列 prefill 时,整段提示是第一次被编码,所以严格需要因果掩码防止看到未来 token。这一点与稀疏路径不同:稀疏路径里 Top-K 选出的位置天然是因果的(索引器打分只看前序),掩码不必单独叠加。全掩码 MHA 内核本身对掩码有成熟处理,所以直接用。
MHA 指这一路径使用 MLA 的 MHA 模式,而不是解码时用的 MQA 模式。附录 A 有一张图专门画了这两种模式的区别,报告的原话是:
For DeepSeek-V3.1-Terminus, the MHA mode is used for training and prefilling, while the MQA mode is used for decoding.

图片来源:DeepSeek-V3.2 技术报告附录 A Figure 7。(a) 为 MHA 模式:每个头的查询分别与经由上投影还原出的完整 K/V 做注意力;(b) 为 MQA 模式:各头的查询先吸收 WUK,直接在共享的潜向量 c 上做注意力,V 的上投影被吸收进输出投影。
这张图里最关键的是”上投影发生在哪里”:
- MHA 模式(图 a):查询只带自己的内容分量与 RoPE 分量;key 与 value 都经过上投影 WUK、WUV 还原成完整维度后,每个头使用其中一段。潜向量 c 不直接参与注意力的点积,而是先被展开成每头独立的 K/V。
- MQA 模式(图 b):查询向量在进入注意力前被 WUK 吸收(图中写的是 {qt,iI} 经 WUK 变换的那条分支),key 侧直接使用共享的潜向量 c,所有头共用同一个 c;输出侧 WUV 被吸收进输出投影。所以 MQA 模式下内存中只读一个潜向量,所有头共享。
对稀疏注意力来说,MQA 模式是更自然的选择:Top-K 选出的是”潜向量位置”,只要所有头读的是同一份潜向量,选出来的 k 个位置就可以被所有 128 个头共享——报告 2.1 节给出的理由正是 “each key-value entry must be shared across multiple queries for computational efficiency”,并引用了 NSA 在 kernel 层的同一结论。而 MHA 模式下每个头的 key 是独立还原出来的,稀疏选择要是按位置选,每个头都要去 gather 自己那份数据,访问模式会变得零碎。
也就是说,masked MHA 模式这条路根本不做 token 选择:它不做索引器打分,直接用因果掩码跑 MHA 形态的 MLA。这在短上下文下成立,因为 L≤k 时 Top-k 覆盖了全部历史位置,稀疏路径的”选择”在语义上没有产生任何筛选。所以用稠密注意力去”模拟”它,输出是一致的(或者说在所有可选位置都看了的情况下是一致的)。
MHA 与 MQA 的选择:用算力换带宽与用带宽换算力
附录 A 那张图回答了另一个问题:为什么 prefill 用 MHA 模式、decode 用 MQA 模式,而不是统一成一种。
MQA 模式的优势在带宽。 解码时每步只有 1 个查询,历史上所有位置都要被读一遍。MQA 模式下内存里只存 576 维的潜向量,读进来之后所有 128 个头共用;而 MHA 模式要先把潜向量经上投影还原成每头独立的 K/V,相当于在读取阶段多了一次矩阵乘,并且每个头读到的数据不同,读带宽按头数放大。解码是带宽受限的,所以必须选 MQA。报告的 Figure 7 文字部分也明确:V3.1-Terminus 的 MQA 模式用于 decoding。
MHA 模式的优势在算力利用率。 预填充时有一整段查询,算术强度高,瓶颈在算力而不在带宽。MHA 模式把每个查询头与它自己的完整 K/V 做点积,没有”先吸收再计算”那一步额外的矩阵乘;而且 K/V 的还原可以在高并发的 prefill 中与查询侧的计算重叠。用 MQA 模式做 prefill,反而会因为查询侧要先经过 WUK 的吸收变换而多一些常量开销。
这两句话合起来是同一枚硬币的两面:MHA 用更大的 KV 读带宽换取更直接的算力路径,MQA 用额外的吸收矩阵乘换取更小的读带宽。DSA 的稀疏选择挂在哪一种模式上,取决于该阶段的主要矛盾。prefill 的稀疏主注意力如果按”位置”选,在 MHA 模式下每头都要各自 gather,访存会碎;这也是为什么论文在实例化 DSA 时明确选择了 MQA 模式,而 short-prefill 的稠密回退可以用 MHA 模式——因为它根本不做稀疏选择,不需要共享寻址单位。
这条路径在框架里的对应物
站内的 DSA 稀疏注意力完全拆解:从 DeepSeek-V3.2 的闪电索引器到 vLLM 的算子实现 里记录过 vLLM 侧的对应判据:K->ne[1] >= max(4096, 2*n_gather),即当上下文长度太短(小于 4096 或小于两倍 k)时,稀疏路径切换为稠密路径。模型侧的 masked MHA 与框架侧的这条门槛是同一件事的两个层次:模型作者知道短上下文下稀疏不划算,所以在推理实现上专门准备了稠密回退。
这也给部署者一个可以直接量测的假设:在自己的服务上,把上下文长度从 2K 一路扫到 16K,看 DSA 路径的每 token 时间在哪个长度开始低于稠密路径的对应值。论文没有给出这个交叉点的数字,但 masked MHA 模式的存在本身就说明了交叉点确实存在,而且位于”短”这一侧。
成本曲线:每百万 token 的账单随位置怎么变
报告的 Figure 3 是全文唯一一处把”DSA 省了多少”直接量纲化的地方。口径原文写得很清楚:在 H800 集群上对实际部署的服务做基准测试,算力单价按 2 美元每 GPU 小时计价,纵轴是每百万 token 的成本(美元),横轴是 token 在序列中的位置(0K 到 128K)。


图片来源:DeepSeek-V3.2 技术报告 Figure 3。蓝线 DeepSeek-V3.1-Terminus(稠密 MLA),橙线 DeepSeek-V3.2(DSA)。
曲线的形状本身是最重要的信息,两句话能概括:
稠密路径的成本随位置线性上升,稀疏路径近乎水平。 解码侧最能说明这一点:按图读取,V3.1-Terminus 在 16K、32K、64K、96K 位置处的每百万 token 成本大约分别是 0.3、0.53、0.99、1.45 美元,而 V3.2 对应的是 0.14、0.15、0.18、0.20 美元。稠密路径从 16K 到 96K 涨了近 5 倍,稀疏路径只从 0.14 涨到 0.20,多了 43%。这个形状是”每步只读 k=2048 个潜向量”的直接后果:不论 token 在第几千位还是第几十万位,要读的条目数不变,多出来的只是索引器 key 读的长度(每 token 132 字节,随 L 线性但系数很小)。
两条曲线在短上下文一侧反而靠得很近,稀疏甚至更高。 预填充侧按图读取,16K 处稠密约 0.11、稀疏约 0.095;24K 处稠密约 0.15、稀疏约 0.10;32K 处稠密约 0.18、稀疏约 0.105。也就是说两条线的交叉点落在十几 K 的位置,再往前稠密上升更快、差距逐渐拉开。稀疏线的起始高度,就是索引器打分、Top-K、地址翻译加上 k 个条目注意力这整套固定开销之和。它本身也随 L 缓缓上升(因为索引器的平方项仍在),只是在 16K 到 96K 的区间里上升速率远低于稠密线——96K 处约 0.15,相对 16K 的 0.095 仅涨了约 58%,而同时段的稠密线涨了 4 倍。这才是 masked MHA 模式存在的量化理由:交叉点确实存在,而且在十几 K 这个区间。
把两个阶段放在一起,可以得到一个对容量规划有用的结论:DSA 的核心收益在解码侧、在长上下文侧。预填充侧两条线差得没有那么悬殊(96K 处约 0.45 对 0.15,3 倍左右),因为索引器那个平方项仍然存在;解码侧在 96K 处的差距约 7 倍,因为稠密路径要按字节搬整段历史,而稀疏路径只搬 k 条。
索引器缓存:第二本 KV 账
DSA 在推理时引入了一笔新的显存开销,报告没有单独开一节讲,但它散落在”索引器 key 来自 hs”、“索引器用 FP8”和成本曲线里。把它单独拎出来算一笔账,对部署很关键。
索引器 key 每 token 存多少
索引器的 key:ksI∈RdI 是一个 128 维向量,没有头维(MQA 式共享),也不做 MLA 的那种低秩压缩。按 FP8 存储,每 token 每层是 128 字节加一个逐 token 的缩放因子(dequant scale),实际约 132 字节/token/层。
主注意力的 KV 每 token 每层是多少?MLA 的潜向量是 kv_lora_rank=512,加上 qk_rope_head_dim=64 的 RoPE 分量,共 576 个元素。在 FP8 下约 576 字节,再加缩放。
所以索引器缓存的开销量级是主 KV 的 约 132/576≈23%。这个比例不随上下文变化,是一个结构性的常数项。对 128K 上下文、61 层、FP8 存储来说,索引器缓存大约是 132×61≈8 KB/token,一段 128K 的上下文就是约 1 GB 量级的额外显存——和主 KV 池是同一数量级的东西,不能当零头忽略。
它在推理时的作用不同
主 KV 是”只读”的:解码时只追加不改写,前缀缓存可以长期保留。索引器 key 也是这样,同样的前缀可以被重新使用。但两者有一个差别:主注意力只读 k 个位置,索引器 key 要读全部 L 个位置。所以索引器缓存的读带宽不随 k 下降,而是随 L 线性增长——这就是成本曲线里稀疏线不是完全水平、而是缓慢上升的那个斜率。
这带来一个工程推论:前缀缓存系统必须同时缓存两套东西。站内的 GLM-5.3 推理全链路(一):一个请求在 SGLang 里经过哪些算子、哪些通信 记录过 SGLang 处理 DSA 模型时索引器缓存与主 KV 分池管理的情况,GLM-5.3 推理全链路(三):1M 上下文的 Prefill——分块预填、上下文并行与索引器的二次方账 则算了 prefill 分块时索引器需要重复打分的那笔账。对 V3.2 来说,前缀命中时如果只命中主 KV、没命中索引器 key,就得为命中段重新跑索引器打分——这比重新跑主注意力还贵,因为打分是平方项。反过来,如果索引器缓存命中、主 KV 没命中,稀疏选择是对的,但主注意力没有数据可读。两本账必须一起命中才有意义。
与 GQA 的对比:同样是共享,压缩的对象不同
索引器 key 的”所有索引器头共享一份 128 维 key”是 MQA 形态。它与 GQA 的区别值得单独说一句,因为两者都常被简称为”共享 KV”。
GQA 是把查询头分组,每组共享一套 K/V:头部数从 H 个降到 G 组,KV 容量按 H/G 下降,但每组的 K/V 仍是完整维度 dh。索引器这里则是 HI=64 个查询头共享 1 份 key,比率是 64:1,且 key 的维度也从主注意力那边的 576 维降到了 128 维。也就是说索引器同时做了两件事:共享(64 个头读同一份 key)与降维(576 → 128)。前者是 GQA/MQA 式的思想,后者是 MLA 式的思想。
这个双层压缩正好服务于索引器的目的:它需要在 L2 个 (查询, 位置) 对上打分,所以每个位置的数据要越小越好;它需要 64 个头提供足够的表达能力来近似主注意力的分布,所以头数不能太少;但它并不需要像主注意力那样精准,所以头维度可以小。把”共享一份 key”与”低维 key”叠加,每个位置的读入带宽被压到正好 128 个 FP8 字节——这大概也是 dI=128 这个具体数字的来源:它是 FP8 下一个完整的 128 字节读事务,在 HBM 上能够对齐高效地读取,不会因为非对齐而多读。
两本账在时间上不同步
缓存的第二层问题不是容量,而是寿命。主 KV 与索引器 key 都由同一个前缀产生,命中和失效的粒度理应一致;但在实际系统里,它们往往不是同时写入、也不是同时被驱逐的。
一个具体场景是 prefill 分块。128K 的提示被切成若干块送进 GPU 时,主 KV 每算完一块就写一块;索引器 key 也每块写一块。只要块边界一致,两本账的末尾位点就是对齐的。但如果系统为了节省索引器的工作区,把索引器打分改成”只在块边界处对整段历史一次性做”,那么第二块的索引器 key 可能晚于主 KV 写入——在这一小段时间里,前缀缓存命中主 KV 却查不到对应的索引器 key,稀疏路径无法启动。反过来,如果驱逐策略按”块引用计数”回收主 KV,而索引器缓存按”层”整体驱逐,也可能出现只有索引器 key 被清掉的情况。
这些不同步在多请求共享前缀时会被放大。前面提到的站内文章分析过前缀共享的扇出问题:同一个长前缀同时被多个请求命中时,主 KV 的引用计数会瞬间很高,而索引器 key 若没有被纳入同一个计数体系,就可能被误判为冷数据。对 DSA 模型来说,这类错误的代价比普通模型高:重新算主 KV 只是线性开销,重新算索引器分数是平方开销。
前 3 层是稠密注意力
开源配置里还有一个细节:first_k_dense_replace=3。这意味着前 3 层不做 DSA,走的是普通稠密注意力。这几层不产生索引器 key,也就不需要索引器缓存;它们的 KV 是常规的。这对统一 KV 池的实现有影响——池子里的层要按”是否有索引器缓存”分成两类来管理,块大小与布局都可能不同。
质量验证:三层口径如何证明稀疏没有伤到模型
“稀疏没伤到质量”是 DSA 最大的卖点,也是最容易被轻信的结论。报告 2.2 节用了三层口径来证,每一层验证的假设不同,值得逐层拆开看它到底能排除什么、不能排除什么。
先说清楚三层评测各自在测什么
在逐层拆开之前,先把三层评测的假设逻辑讲清楚,否则容易把”持平”理解成”等价”。
任何一次架构改动对模型能力的影响,都可以拆成两个来源:一是表示能力的损失——稀疏注意力让每个查询只看一部分历史,理论上可能丢掉一些需要远距离信息才能完成的任务;二是优化路径的变化——继续预训练+后训练的分布与原来的训练过程不同,可能让模型学到的东西有偏差。三层评测分别想排除的来源并不一样:
- 标准基准主要排第二项:它用的是常规评测集,短上下文下两模型的注意力覆盖几乎没有差别,所以如果分数持平,说明优化路径的变化没有引入系统性偏差。
- 人类偏好同样排第二项,但用控制变量的方式(共享后训练),并且引入的是”用户实际偏好”这一外部信号,而不只是评测集分数。
- 独立长上下文评测才是唯一直接检验第一项的:它用长序列,让稀疏选择真正开始筛选,然后看模型是否退步。
换句话说,前两层是”证明没有坏”,第三层是”证明真的没坏”。这个分工解释了为什么报告对第三层投入单独一段、强调”此前未见过”与”独立”。
V3.2-Exp 与 V3.2 是两个不同的验证对象
读 2.2 节时有一个很容易忽略的口径问题:这三层评测大部分是在 V3.2-Exp 上做的,而不是最终的 V3.2。 报告原文里 AA-LCR 与 Fiction.liveBench 的讨论明确指向 V3.2-Exp,ChatbotArena 的 Elo 也是 V3.2-Exp 与 V3.1-Terminus 的对照。原因不难理解:架构从 V3.1-Terminus 换到 V3.2 时,真正需要验证的是”换成 DSA 之后模型有没有变形”,V3.2-Exp 正好是这个切换点上的产物;而 V3.2 相对 V3.2-Exp 的改进来自后训练,被放在第 3 章与第 4 章的评测里,属于另一套口径。
这对引用时的影响是:如果想论证”稀疏注意力没有伤到质量”,应该指向 2.2 节的 V3.2-Exp 数据;如果想论证”V3.2 这个模型整体有多强”,应该指向第 4 章的评测表。两层数据和两种问题,混在一起引用会得出错误的结论。
第一层:标准基准——证明短上下文能力没有退化
报告原文说 2025 年 9 月用一套覆盖多种能力的基准评测了 V3.2-Exp,与 V3.1-Terminus 对比,“we do not observe substantial performance degradation … on both short- and long-context tasks”。
这一层验证的是:在常规评测集上,加入了稀疏选择后模型的基础能力没有系统性下滑。 但它的盲区也很清楚——这些评测集大多是短上下文的;即便有长上下文任务,它们的上下文长度也远小于 128K,稀疏路径在这些长度下与稠密路径的差异本来就不大(L 接近 k 时 Top-k 几乎覆盖全部历史)。它证明的是”没变坏”,无法区分”稀疏机制本身是否足够好”。
一个自然的反问是:每个查询只保留 1.6% 的历史位置,凭什么质量不掉?这与注意力分数的分布形态有关。站内分析过的 H2O 完全拆解:抓住 KV Cache 里的「重击者」,20% 预算无损生成(NeurIPS 2023) 与 Quest 完全拆解:查询感知的页级稀疏注意力,让长上下文解码只读有用的 KV 都观察到同一件事:在长上下文里,每个查询对历史位置的注意力分数高度不均衡,少数位置拿走绝大部分权重,其余位置贡献接近零。DSA 的 k=2048 相当于把这个经验事实写进架构,并训练模型适应它。1.6% 的选择比例之所以够,是因为真正参与加权的位置本来就远少于 1.6%——剩下的选择更多是在”不重要之中挑一些备用”。
但这里有一个必须分清的点:注意力权重集中是”观察”,而索引器能否在每层、每个查询上都选出那个集中的集合,是”能力”。前者是数据分布的性质,后者要靠索引器训练来保证——报告 2.1.1 节那段稠密热身训练做的就是这件事,对推理侧不必展开。
第二层:人类偏好——证明后训练链路没有被打乱
报告指出,V3.1-Terminus 与 V3.2-Exp 共享同一套后训练策略,用 ChatbotArena 做间接评估,2025 年 11 月 10 日取得的 Elo 分数”closely matched”。
这一层设计的巧妙之处在于控制变量:如果两个模型的后训练策略一样,两者 Elo 接近,就说明基础 checkpoint 的能力没有因为 DSA 而改变——因为后训练能放大的能力上限是由基座决定的。同时也排除了”性能看起来好是因为后训练补了上来”这种解释。它排除不了的,是 ChatbotArena 本身对长上下文的不敏感性——普通用户的对话几乎没有 128K 长度的场景。
第三层:独立长上下文评测——证明真正的稀疏场景没有回退
这一层是前三层里最重要的,因为它是唯一直接测”DSA 在长上下文下是否退化”的。报告说,V3.2-Exp 发布后若干独立的长上下文评测用的是此前未见过的测试集,并给出两个代表:
- AA-LCR(Artificial Analysis Long Context Reasoning):V3.2-Exp 在推理模式下比 V3.1-Terminus 高 4 分。
- Fiction.liveBench:V3.2-Exp 在多个指标上持续优于 V3.1-Terminus。
“此前未见过”这个限定很重要:它意味着这些分数不是训练数据的记忆效应能解释的。AA-LCR 那 4 分的提升尤其有说服力——因为它在长上下文推理上是独立的第三方评测,而不是 DeepSeek 自己挑的榜。如果 DSA 每 token 只看 1.6% 的历史、质量却在独立长上下文榜单上上升,那么”token 级的稀疏选择在这个规模上是对的”这一假设就有了实质性证据。
三层合起来看,报告的质量论证结构是:短上下文能力不变(标准基准)→ 基座能力没变(人类偏好)→ 长上下文能力不降甚至上升(独立评测)。三层分别对应 L 短、L 中等、L 长三个区间。它没有回答的问题是:L 在 k 附近到数万之间的过渡带质量如何——那是稀疏选择开始真正起筛选作用的区间。报告对此只字未提,也未见公开的 k 扫描曲线。这也是部署者最该自己量测的区间:在真实业务数据上,把上下文从 4K 拉长到 32K,逐档观察质量与延迟。
从 V3.2-Exp 到 V3.2:架构不变意味着什么
报告开头”exactly the same architecture”那句是全文对推理工程最有价值的承诺。它的推论很具体:
- 推理代码零改动。 任何为 V3.2-Exp 写好的索引器 kernel、稀疏 MLA kernel、KV 布局、TP 切分方式,可以原样适用于 V3.2。站内那些基于 V3.2-Exp 代码拆的算子实现,对 V3.2 也同样成立。
- 评测口径可比。 因为架构相同,V3.2 相对 V3.2-Exp 的进步可以干净地归因到后训练(专家蒸馏、混合 RL、Agent 任务合成),而不是”换了架构顺便改了推理特性”。
- 成本模型可迁移。 Figure 3 给出的成本曲线口径(H800、2 美元/GPU 小时)对 V3.2 的每次前向仍然适用——因为它本质上只与”每步读多少潜向量、索引器读多少 key”有关,而与后训练出的权重数值无关。这也意味着,任何人对 V3.2-Exp 做的本地推理 benchmark,对 V3.2 仍然可以参考。
一个需要注意的边界:架构不变说的是计算图不变,不是行为不变。V3.2 的权重分布变了(后训练更充分),索引器打出的分数分布也可能因此改变,从而影响 Top-k 的选择集中度。这一点报告没有直接给出数据,但从 2.2 节的”持平评测”可以间接推断:后训练没有把索引器推向一个更分散或更集中的分布,因为长上下文质量没有掉。
部署视角的检查清单
把上面的内容收敛成一份部署时可以直接对照的清单,每一项都对应报告里的一处原文或派生出的数字。
-
上下文门槛。短上下文走稠密回退。报告说模型作者实现了 masked MHA 模式,框架侧对应的是长度阈值判据(站内 vLLM 侧记录的判据是 4096 或两倍 k)。部署时要监控两条路径的调度比例,而不是假设永远走 DSA。
-
两套缓存都要预分配。索引器 key 每 token 每层约 132 字节(FP8),是主 KV 的约 23%。128K 上下文下这是 GB 级别的额外显存。前缀缓存系统必须对两者的命中状态分别记账;只有一起命中,稀疏路径的收益才会兑现。
-
前 3 层是稠密。
first_k_dense_replace=3,这几层没有索引器缓存,KV 布局与稀疏层不同。统一块池时层类型要分开。站内 vLLM 源码完全拆解(二十三):混合 KV Cache 的组账本——KVCacheCoordinator 如何让全注意力、滑窗与 Mamba 层共用一个块池 讲的正是这种”多种层型共用一块池”时的记账方法,DSA 模型的”稠密前三层 + 稀疏其余层”是同类问题的又一种形态。 -
k=2048 是被写死的。vLLM 侧的 CuteDSL Top-K 选择器只支持 512/1024/2048 三档(因为它用固定桶宽的基数排序),而训练侧的 k 也是 2048。如果业务需要在更短上下文的场景下省算力,靠调 k 来实现会碰到 kernel 硬约束,而不是一个简单的配置项。
-
索引器的工作区内存。prefill 时索引器需要临时空间来存放 L×L 的分数与 Top-K 中间态。站内记录过 128K 上下文下约 825 MB 的工作区量级——这部分不是常驻缓存,但会影响最大可同时 prefill 的请求数。
-
TP 切分对索引器是复制。索引器的头数(64)与注意力头数(128)不相等,按 TP 切分查询时索引器会被复制到每个 TP rank 上,Top-K 结果也是每 rank 各自算一遍。站内那篇 GLM-5.3 全链路的文章记录过这一细节,它对通信账本有影响。
报告没有回答的问题
把这份 23 页报告读完,有几处空白是推理侧的人会感到缺口的。
第一,质量与 k 的扫描曲线缺失。 报告只给出 k=2048 这一个工作点,没有”把 k 往下调,质量在哪里开始掉”的数据。这个曲线是所有部署者做参数取舍时最想要的,也被站内此前分析 DSA 的文章点出过。没有它,任何在 k 上的非默认取值都缺乏质量依据。
第二,短上下文两个模式的交叉点没有数字。 masked MHA 模式的存在说明作者知道交叉点存在,但报告没有给交叉点的上下文长度,也没有给两条路径在短上下文下的对比性能。这与 Figure 3 起始区间的读数可以间接估算,但精确值需要自己量。
第三,索引器缓存的独立成本没有拆出来。 Figure 3 给的是端到端的每百万 token 成本,把索引器打分、Top-K、稀疏主注意力、索引器 key 读全部打包在了一起。站内的成本曲线解读里有过这种”平坦但非零”的分析,但论文本身没有分项拆解,所以很难回答”如果换到别的硬件上,索引器那一项是变重还是变轻”。
第四,V3.2 与 V3.2-Exp 在推理行为上的差异没有给出。 架构相同,但权重重训过,索引器分数分布会不会变、Top-k 选中的位置分布会不会变、前缀缓存命中的收益会不会变——这些都没有数据。这是报告因为篇幅限制(前半部分几乎全给了后训练)留下的空档。
第五,masked MHA 在推理引擎里的实际调度方式没有公开。 报告只提到”我们专门实现”,没有说是在模型服务框架层、还是在 kernel 层、还是靠调度器的启发式切换。从站内已有对 vLLM/SGLang 的源码拆解看,这种切换往往发生在 kernel 选择与 batch 组织这两个层面,具体实现因框架而异。
这几处空白恰好是”论文给架构与成本,系统给实现细节”的分工体现。报告把注意力机制与成本曲线交给了研究者,把工程实现留给了开源的推理代码。
和同代其他稀疏路线比,DSA 站在哪一格
报告没有做横向对比,但把 DSA 放进近两年出现的一批稀疏注意力方案里,可以看出它的定位。按”稀疏作用在哪一层”来分,大致有三格:
- 训练无关的解码期稀疏。 比如 Quest 完全拆解:查询感知的页级稀疏注意力,让长上下文解码只读有用的 KV 按页维护 min/max 元数据,解码时按查询选页;H2O 完全拆解:抓住 KV Cache 里的「重击者」,20% 预算无损生成(NeurIPS 2023) 按累计注意力权重驱逐 KV。这类方案不改模型,只改框架与缓存,代价是质量依赖数据分布,而且通常按”块/页”选,粒度较粗。
- 原生训练的块级稀疏。 比如 NSA 原生稀疏注意力(一):压缩-选择-滑窗三分支架构 让模型在训练时就适应”块级选择 + 滑窗 + 压缩”三条分支。优势是质量由训练保证,劣势是 kernel 与分块粒度绑定,且块级选择天然偏粗。
- 原生训练的 token 级稀疏。 DSA 在这一格。它把选择单位下放到单个 token(潜向量),k=2048 个位置可以是任意离散的,所以不会像块级方案那样出现”块内有用 token 被整块带上、块间稀疏度固定”的问题。代价是索引器的平方项仍在,以及必须挂在能共享寻址单位的 MLA MQA 模式上。
这三格的取舍关系可以概括为一句话:粒越细,选择的能力越强,但对模型本身的依赖越深。 训练无关的方案只能选”块或页”,因为它不能改模型的注意力计算;原生训练的块级方案能选块,因为训练让模型适应了块;token 级方案能选任意位置,代价是必须从头适配整个注意力结构。DSA 之所以必须走两段继续预训练,就在于它选了最细的那一格。
从”训练无关”这一格还有另一条演进路线,站内的 LongCat Sparse Attention(LSA)完全拆解:驯服闪电索引器的三件套——相比 NSA/DSA 真的改进了吗 分析过它在闪电索引器基础上所做的改动(流式预算、跨层索引、层级索引)。这说明 DSA 的索引器结构已经被后续方案当作基线来改进,而对推理侧来说,这些改进多半落在”索引器计算量”与”索引器缓存”这两项上,正好对应本篇反复强调的两个瓶颈。
小结
- 架构只改了一处。 V3.2 与 V3.2-Exp 架构完全相同,相对 V3.1-Terminus 的唯一结构改动是 DSA,且通过继续预训练长出来。推理实现可以互通,成本曲线可以迁移。
- 复杂度账要分阶段算。 “从 O(L2) 到 O(Lk)“描述的是核注意力这一项。prefill 仍有一个系数更小的平方项(索引器打分与 Top-K),decode 侧才是真正把 O(L) 字节搬运砍成 O(k) 的地方——这也是 DSA 收益的主要来源。
- 双模实现是设计的一部分。 短序列 prefill 用 masked MHA(因果掩码 + MLA 的 MHA 形态)绕过稀疏路径,因为在 L 接近 k 时选择没有筛选作用、固定开销反而更贵。框架侧对应的是”长度低于阈值就切稠密”的判据。
- 成本曲线读出来是:解码侧、长上下文侧收益最大。 按报告口径(H800,2 美元/GPU·小时),解码每百万 token 成本在 96K 位置处约 0.20 对 1.45 美元,相差约 7 倍;预填充侧约 3 倍。短上下文处稀疏并不占优。
- 索引器缓存是第二本账。 约 132 字节/token/层,约为主 KV 的 23%,且要随 L 全量读取。前缀缓存必须两套一起命中。
- 质量论证分三层。 标准基准证明短上下文不变,共享后训练的人类偏好证明基座能力不变,独立长上下文评测(AA-LCR 高 4 分、Fiction.liveBench 多项更优)证明真正的长上下文场景没有回退。没有覆盖的是 k 附近到数万之间的过渡带。
参考资料
- DeepSeek-V3.2: Pushing the Frontier of Open Large Language Models(技术报告)
- DeepSeek-V3.2-Exp 模型配置(Hugging Face)
- DeepSeek-V3.2-Exp 官方推理代码
- DeepSeek-V3 技术报告(MLA 与 MQA/MHA 模式)
- Native Sparse Attention: Hardware-Aligned and Natively Trainable Sparse Attention(NSA)
- DeepSeek-V2 技术报告(MLA 的低秩 KV 压缩)
- Artificial Analysis Long Context Reasoning 评测
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
评论区
分享你的想法,与大家交流讨论
正在获取所在地区…
正在读取天气
音乐
暂未播放



