☰ DSv4.1 Flash 架构导读

8. 训练与部署:三个阶段、两个口径、三个时钟域

8.1 三个阶段,不是一个

前七章把结构拆完了。结构里有两种机制是报告选择放到后训练才引入的:FP4 的缓存和 HSI 的候选池。它们在原理上并非不能从头训练,只是稳定性、成本或效果上的理由让报告没有这么做;而引入时机本身就是设计的一部分。

  1. 预训练:从头就用稀疏注意力,先在 64K 序列上训,到 34T token 时扩到 1M。此时没有 HSI——Reindex 层在全历史里选 Top-K,没有候选池限制。主 KV 也还是高精度。
  2. DSpark 的专门阶段:预训练之后单独训草稿模型,主干冻结。理由是草稿模型要匹配"当前策略"的分布,和主干一起从头训会互相拖。
  3. 后训练:同时引入三样东西——HSI(候选池限制)、FP4 的主 KV(QAT)、以及继续训练 DSpark(梯度不回传主干);此外还模拟一遍 SWA bounded replay,让模型适应它。
判断方法

为什么 HSI 和 FP4 都放后训练?因为它们都是改变推理时的数值/搜索域的操作。训练时若用"完整历史 + 高精度",上线时换成"候选池 + FP4",模型面对的就是一个它没见过的输入分布。放在后训练、且训练与推理施加完全相同的限制,才叫"训练感知"(training-aware)。

8.2 Indexer 怎么训:报告没说,这一节是外推

先说结论:报告没有披露 Indexer 的训练目标。它只在 2.4.4 提到 V4 起就对 Indexer 的 Q/K 用了 FP4 QAT,没有给出任何损失函数、教师信号或系数。所以这一节不是报告内容,而是按上一代 DSA 的公开做法做的外推;只想了解本报告的人可以直接跳到 8.3。

外推的出发点是:Top-K 是离散的,几乎处处零梯度,所以主任务梯度到不了 Indexer,它必须有一条自己的监督信号。最自然的写法是让 Indexer 的打分分布去拟合主注意力的权重分布:

\[ \mathcal L=\mathcal L_{\text{task}}(\theta) +\lambda_I\sum_{\ell\in\mathcal I}\frac{1}{|\mathcal Q_\ell|} \sum_{t\in\mathcal Q_\ell} \] \[ D_{\mathrm{KL}}\!\Big(\operatorname{sg}\big[\mathbf p^{(\ell)}_{t,\mathcal U}\big] \,\Big\|\,\mathbf q^{I,(\ell)}_{t,\mathcal U}\Big), \]

其中 \(\operatorname{sg}[\cdot]\) 是停止梯度:教师(主注意力)被固定,只有学生(Indexer)被推着走。\(\mathcal U\) 是明确指定的监督支持集,\(\mathcal Q_\ell\) 是该层有有效监督的查询集合,\(\lambda_I\) 是辅助系数,\(\mathcal I\) 是要监督的那几层(对应 8 个索引来源层)。

这条式子解释了三个设计:

再强调一次:\(\lambda_I\)、监督支持集 \(\mathcal U\)、是否对 Full 与 Reindex 层分别监督,报告一个字都没写。上面只是"如果要这么做,长什么样"的模板,不能当作报告的设定引用。

8.3 FP4 的 QAT:为什么必须训练

第 4.5 节算了这个 FP4 格式的动态范围够(上界 2688,实测最大约 10),但"不溢出"不等于"白送"。把一个 512 维向量截断到 4 bit 会引入量化误差,而注意力对键值的相对大小敏感。所以需要一个量化感知训练(QAT)阶段:前向用"假装量化过"的值,反向按直通估计器(STE)把梯度原样传回去,让模型学会把信息放到量化后仍能分辨的位置上。

报告给的两个工程细节:

8.4 部署:两个口径

报告给了两个不同的倍数,很多人读的时候会混:运行时约 1/4、持久化约 1/8(都以 V4-Flash 为分母)。报告在 3.2.1 明确给出了这个差额的来源,是两个相乘的因子:

\[ \frac{1}{8} =\underbrace{\frac{1}{2}}_{\text{持久化不再存 SWA KV}} \times \underbrace{\frac{1}{4}}_{\text{全局 KV 的压缩}} . \]

于是 1/4(架构 + 精度)再乘 1/2(去掉 SWA KV 的持久化),就是 1/8。SWA KV 改为放进一个从每台机器 10% 主机内存划出的分布式内存池,TTL 只有几分钟,靠高周转服务活跃会话;真正缺失时用 3.2.2 的 Encoder SWA Bounded Replay 补,只重放 128 个位置,而不是 \(L\times n_{\text{win}}\)。这就是"为什么持久化比运行时更省"的完整解释,不需要再猜。

三个和"存得下"直接相关的工程点:

8.5 一个类比:三种模式就是三种缓存状态

这一节的框架是本篇的类比,报告里没有 AGU / TLB / 三级缓存这套语言;报告 3.2 讲的其实是持久化缓存管理与两级 replay。把它当"帮助记忆的比喻"用,不要当报告结论引。

把那层 CSA2 当成一台小计算机来读,三个部件各归其位:

执行单元   新算的 Q 与本地 KV
片上缓存   主 KV / Indexer K / Top-K
大容量后端 MoE 与 FFN

关键对应是"什么是可缓存状态":Q 与本地 KV 永远是新鲜操作数(像每条指令新取的寄存器值),不进共享缓存;主 KV、Indexer K、Top-K 索引是可缓存状态,是否重算取决于命中与否。于是三种模式的读写模式就是一张缓存访问表:

模式      主 KV   Indexer K   Top-K
Full      写      写          算
Reindex   读      读          重算
Reuse     读      不访问      读

Indexer 在这套语言里是地址生成单元 + TLB:它不搬数据,只产出"读哪些条目"的地址集合。Full 层让地址单元全速跑一遍;Reindex 只在受限范围内重新翻译;Reuse 直接把上次的地址向量拿来用——等于对最贵的地址计算做了一次公共子表达式消除。

HSI 的候选池则是一张工作集约束:Decoder 的第一个 Full 层(第 21 层)选出 2048 块共 16384 个位置,等于为后续层立了一张"只能在页内寻址"的页表。两级 Top-K(先块后位置)就是两级页表:先用块级最大分选页,再在页内选具体条目。这也解释了为什么"池外位置根本不可寻址"——不是"分数低",是地址空间里没有它。

8.6 三个刷新次数:4 / 8 / 40

三种可刷新状态沿深度的刷新次数依次增加,可以读作三层嵌套的调度;"三个时钟域"是本篇的说法,报告没有用这个词(它讲的是 HBM / 主机内存 / SSD 这一套真实的存储层次):

\[ \underbrace{\text{Content } C}_{\text{刷新 }4\text{ 次}} \ \supset\ \underbrace{\text{Address } S}_{\text{刷新 }8\text{ 次}} \] \[ \supset\ \underbrace{\text{Query } q}_{\text{刷新 }40\text{ 次}} . \]

这三个数不是"时钟频率":4 → 8 是 2 倍,8 → 40 是 5 倍,并不都是"差一个数量级"。它们是沿深度的刷新次数,读作三层嵌套调度的节奏,而不是三个独立的周期。

越靠近执行单元的状态,刷新越快、越便宜;越靠近共享后端的状态,刷新越慢、越贵。CSA2 的模式调度说白了就是把每类状态放到与它重算成本匹配的刷新率上:如果每层都刷内容(40 次),成本爆炸;如果 40 层都复用同一份地址(1 次),召回就退化成"全模型一次检索",第 5.6 节的三个缺口会同时出现。

结论

整篇报告的结构可以压成一行:4 份内容 × 8 份地址 × 40 份查询。读的时候记住这是嵌套的——一份内容被若干层共用,其中某些层各刷地址,所有层各刷查询——不是三个可以自由组合的维度。

8.7 容易算错的地方

常见错误
  • 用 1/8 去算显存。1/8 是持久化口径;显存里常驻的是运行时那份,约 1/4(890 B/token)。
  • 以为 HSI 在预训练里就有。预训练是全历史选择;候选池是后训练才加的,训推同构是它的前提。
  • 把"4 次内容刷新"读成"只有 4 层有 KV"。是所有层都读,只有 4 层写;Reuse 层读的正是这 4 份。
  • 把 Indexer 的损失当成报告内容。报告完全没写 Indexer 怎么训(只提到对它的 Q/K 做了 FP4 QAT);8.2 节整节是外推模板,不是报告设定。
  • 把 1/8 拆错。它 = 1/2(持久化不再存 SWA KV)× 1/4(全局 KV 压缩),不是"窗口占一半"。
  • 把 FP4 当成推理期的矩阵乘格式。它只用于存储,计算前反量化(第 4.5 节)。