The dump hooks live in five platform-neutral files -- `sampler.py`, `mlp.py`, `deepseek.py`, `decoder_layer.py`, `model_runner.py` -- and all of them imported `deepinfer.h20_ops.debug_dump`. That is wrong on every platform except SM90: `h20_ops/__init__.py` calls `extend_import_patches(override=True, ...)` at module scope, so importing it from shared code installs the SM90 import shims globally. On an SM100 machine that replaces `flash_mla.decode_mla_mqa_sparse`, `flash_mla.prefill_attn_varlen_sparse` and `deep_select.interface.topk` with the Hopper implementations, and on NPU it would do the same before the Ascend shims get a chance to matter. `debug_dump` itself has nothing platform-specific in it -- `os`, `pathlib`, `numpy`, `torch` -- so it moves to `deepinfer/debug_dump.py` and the five imports follow. Verified that importing it no longer pulls `h20_ops` into `sys.modules`, and re-ran the end-to-end check on H20: same output token for token, `[17607, 2793, 3139, 666, 6127, 666, 320, 1]`. This bug is already in the open PR, so it needs to land before that PR is worth reviewing further.
22 KiB
H20 / SM90 数值正确性排查计划
目标:让 DeepInfer 在 8×H20 上对同一个小 case 给出和官方参考一致的输出。
固定用例(每次测试都用它,约 4~5 分钟/次,权重加载占大部分):
prompt : 问题:中国的首都是哪里?\n答案: (token ids: [2056,768,17607,2793,3139,12108,6692,7624,768])
greedy : temperature = 0
length : max_new_tokens = 6
期望 : 北京 (6127) 开头
当前 : 'EVAL - 暂时不会 - ' = [33795,2570,565,223,22807,4555] ❌
- 我方入口:
scripts/h20_ask.py --max_tokens 6 - 参考入口:官方
/data/models/DeepSeek-V4.1-Flash-1017/inference/generate.py(TP8 权重 +config_fp8.json;其generate()是 argmax,天然 greedy、可复现)
P0 固化基准(已完成)
- P0.1 官方
generate.py跑通:Completion: 中国的首都是北京。 - P0.2 发现官方套了 chat 模板(
encode_messages),两侧输入其实不同, 直接比文本是无效对比。已拿到官方真实输入 ids:[0,128803,2056,768,17607,2793,3139,12108,1148,128804,128822](11 token,chat 模式) - P0.3 新增
scripts/ref_next_token.py:吃任意 ids、输出 greedy next token + top5, 绕开 prompt 形式差异。我方scripts/h20_ask.py --ids ...对称。 - P0.4 顺手清理磁盘:
/tmp曾 100% 满导致 nvcc JIT 失败;删旧容器+未用镜像后 0 → 75GB 可用。
结论:官方 greedy 目标 = [17607, 2793, 3139, 6127, 320] = 「中国的首都是北京。」
已完成:P1 prefill 因果掩码 —— 已修,首 token 变对
现象(修复前 → 修复后,同为 11-token 官方输入):
| tokens | 文本 | |
|---|---|---|
| 官方 | 17607, 2793, 3139, 6127, 320 |
中国的首都是北京。 |
| 我方(修 P1 前) | 33795, 2570, ... |
EVAL - 暂时不会 - |
| 我方(修 P1 后) | 17607, 41175, 389, 666 |
中国的首都是** |
首 token 17607(中国的)已与官方一致 ⇒ prefill 主路径通了。
前 3 个 token 只是分词不同(首/都是 vs 首都/是),拼起来都是「中国的首都是」。
关键新证据(已确认,不靠推测):把 14 个 token 直接当 prefill 输入
(官方前缀 + 17607,2793,3139),我方预测 666(**),而官方在同样前缀下
生成的是 6127(北京)。说明分歧发生在 prefill 内,不是 decode 累积的,
且发生在第 12~14 个位置附近(11 token 时还对)。
👉 下一步收敛为:逐层 dump,找首个偏离层,见 P2。
P2 分层对拍 —— 已完成,定位到第 0 层的 FFN 阶段
方法:scripts/ref_layer_dump.py(官方,forward hook)+ DEEPINFER_DUMP_LAYERS(我方,
h20_ops/debug_dump.py),两侧都取最后位置、都按 hc_mult 求均值,用
scripts/compare_layers.py 对比。输入固定为那条 14-token ids。
踩过的两个坑(重要,否则会得出错误结论):
- 我方
decoder_layer返回的hidden_states只是子层输出(2D),完整残差流在residual(HCLazyPostData,hc_mult=4)里。必须hc_post(hidden_states, residual)之后再比, 否则第一版对比得到的 cos≈0.02 是假的。 - 引擎在分配 KV cache 前会跑一次 dummy profile forward,token 数与真实 prompt 不同。
必须用
DEEPINFER_DUMP_TOKENS=<n>门控,否则 dump 到的是 dummy 输入。
结果(14-token 输入,cos / rel_err / 范数比):
| 位置 | cos | rel_err | ‖mine‖/‖ref‖ |
|---|---|---|---|
| layer0 attention 子层输出 | 0.99897 | 4.71e-02 | 0.986 |
| layer0 整层输出 | 0.99190 | 1.27e-01 | 1.000 |
| layer1 整层 | 0.97707 | 2.29e-01 | 1.062 |
| layer1 attention 子层 | 0.99324 | 1.21e-01 | 0.959 |
| layer2 | 0.96411 | 2.76e-01 | 1.039 |
| layer5 | 0.93275 | 3.61e-01 | 0.943 |
| layer11 | 0.86515 | 5.28e-01 | 1.030 |
结论:
- 稀疏 MLA attention 本身是对的:第 0 层 attention 子层 cos=0.999,误差 4.7%, 在 FP8/量化口径下属于合理量级。之前怀疑的 TileLang kernel 可以排除。
- 误差主要在第 0 层的 FFN/MoE 阶段引入:attention 4.7% → 整层 12.7%, 即 FFN 贡献了主要偏差。
- 误差单调累积,到第 11 层 cos 已降到 0.865,最终把 top-1 从「北京」翻成「**」。
下一步:在 layer0 的 FFN 内再切一刀 —— 分别 dump routed_experts_forward 的输出、
shared expert 输出、以及 swiglu/route 权重,看是路由(top-6 选中了不同专家)还是
专家计算本身偏。engram 在第 1/14 层,本轮已可排除其为首个偏离点。
P3 已完成:根因是专家权重量化的 scale 广播错误 —— 已修复,答案正确
根因
h20_ops/quant.py::requant_expert_fp4 里用了 _expand_blocks(sf, n_out, k, 32) 去展开
UE8M0 scale。但两者的布局前提不同:
| scale 形状 | 需要展开的维度 | |
|---|---|---|
dense 权重(requant_dense_fp8) |
(n_out/32, k/32) |
两个维度 |
专家权重(requant_expert_fp4) |
(n_out, k/32) |
只有 k 维度 |
_expand_blocks 对两个维度都做 repeat_interleave(32) 再截断,于是
(2304, 160) 被当成 (72, 5) 来展开 —— 全部 2304 个输出通道都拿到了前 72 行的 scale,
整个专家权重被打乱。这精确解释了 P2 观察到的「shared 对、routed 错」的非对称:
shared expert 走 requant_dense_fp8(用法正确),routed experts 走这条错误路径。
修复:只沿 contraction 轴展开,并加断言锁住布局。
assert tuple(sf.shape) == (n_out, k // FP4_BLOCK)
x = _unpack_fp4(packed) * sf.to(torch.float32).repeat_interleave(FP4_BLOCK, dim=1)
验证(scripts/h20_expert_weight_check.py,与官方 inference/convert.py
的 cast_e2m1fn_to_e4m3fn 逐元素对拍)
| 权重 | 修复前 cos / rel_err | 修复后 cos / rel_err |
|---|---|---|
| w1 | 0.8936 / 5.35e-1 | 1.0000 / 2.84e-2 |
| w3 | 0.8960 / 5.26e-1 | 0.9997 / 2.69e-2 |
| w2 | 0.8964 / 5.20e-1 | 0.9996 / 2.65e-2 |
剩余 2.7% 是 per-32 → per-128 的量化损失(FP8 e4m3 三位尾数,理论量级 ~3%),
不是 bug。官方 cast_e2m1fn_to_e4m3fn 是无损的(把 per-32 的相对 offset 折进 FP8 数值),
如果要进一步压掉这 2.7% 可以照搬,见下方 P3.6。
端到端结果
修复前: [17607, 41175, 389, 666] -> 中国的首都是**
修复后: [17607, 2793, 3139, 666, 6127, 666, 320, 1] -> 中国的首都是**北京**。
官方: [17607, 2793, 3139, 6127, 320] -> 中国的首都是北京。
语义已正确(「北京」),前 3 个 token 与官方逐 token 一致。差异只剩 markdown 加粗
**(我方多出 666/666 两个 token),说明仍有残余数值差异让 top-1 在个别位置偏移。
下一步(可选,按收益排序)
- P3.6 改用官方无损重化:照
cast_e2m1fn_to_e4m3fn的做法,把 per-32 e8m0 相对 offset 折进 FP8、scale 保持 e8m0 per-32,理论上可把 2.7% 降到 0。需要确认 SM90 DeepGEMM 是否接受 e8m0 per-32 的 expert scale(当前配方是 fp32 per-128)。 - P3.7 重跑 P2 分层对拍:确认 layer0 整层 rel_err 从 1.27e-1 降到 ~3e-2 量级。
- P3.8
**的来源:定位是哪个位置翻的 top-1,判断是否还有别的量化口径差异。
后续跟踪(P3.6 起)已迁移到
H20-PORTING-JOURNAL.md第 6 节,那里有完整的 漂移量化数据、建议顺序和前置条件。本文件的 P4 / P5 保留为方法清单。
P4 decode 专项 —— 完成:** 已定量解释为量化噪声,非缺陷
为什么锁定 decode
P3 之后重跑对拍(H20-DRIFT-ANALYSIS.md 有完整数据):
| top-1 | margin(6127 北京 − 666 **) |
|
|---|---|---|
| 官方,14 token prefill | 6127 | +3.112 |
| 我方,14 token prefill | 6127 ✅ | +0.256 |
prefill 选中了正确的 token,误差只把 margin 压缩了 12 倍。但端到端跑 (11 token 起,增量 decode 到第 14 个位置)给的是 666。
同一个 14-token 上下文,一次 prefill 给 6127,增量 decode 给 666。
当时的推断是「剩余漂移在 decode 路径」。P4.2~P4.4 做完后,这个推断需要精确化为: 差额确实只在 decode 出现,但原因不是 decode 有 bug,而是 decode 经过量化 KV cache 往返、噪声略增,恰好碰上模型自己在那个位置只有 1.64 的 margin。
判据(先定死,避免事后解释;P4.2 之后已修正)
事后修正:下面这套判据假设「decode 与 prefill 应当基本一致」,因此把
rel(A,B) > 3e-2判为「decode 自身缺陷」。P4.2 证明这个前提错了 —— 官方自己 prefill→decode 也让 margin 变化约 2 倍,因为 KV cache 走量化往返。 真正有效的判据是Δmargin 的量级 vs 该位置的 margin,而不是 rel_err 的绝对值。 判据保留在下面作为过程记录,最终结论见「最终结论」一节。
设第 14 个位置上:
A= 我方 prefill 路径的 logitsB= 我方 decode 路径的 logitsR= 官方 decode 路径的 logits
| 量 | 含义 | 阈值 |
|---|---|---|
rel(A, B) |
我方两条路径自身是否一致 | > 3e-2 即为 decode 自身缺陷 |
rel(A, R) |
prefill 残余误差 | 已知约 3e-2(量化地板) |
rel(B, R) |
decode 总误差 | 明显大于 rel(A,R) 说明 decode 额外引入误差 |
- 若
rel(A,B)很小而rel(B,R)大 → decode 没有额外缺陷,是量化误差累积,**属可接受 - 若
rel(A,B)大 → decode 有 bug,按 P4.3 → P4.4 往下查
步骤
-
P4.1 同位置 prefill vs decode 对拍 —— 完成(结论已被 P4.2 修正,见下)
四条路径走到同一个 14-token 上下文 `[0,128803,2056,768,17607,2793,3139,12108,1148,128804,128822,17607,2793,3139]`: | 路径 | 下一个 token | 结果 | |---|---|---| | 官方 prefill(一次喂 14 个) | 6127 = 北京 | ✅ | | 官方 decode(喂 11 + 逐 token forward) | 6127 = 北京 | ✅ | | **我方 prefill(一次喂 14 个)** | **6127 = 北京** | ✅ | | **我方 decode(喂 11 + 增量)** | **666 = `**`** | ❌ | 前两条来自 `ref_next_token.py`(prefill 一次 / `--force_ids` 增量),后两条来自 `h20_ask.py`:`--ids <14个> --max_tokens 1` 给 `6127`,`--ids <11个> --max_tokens 7` 的第 4 个 token 是 `666`。 **结论:prefill 路径正确,差额只由 decode 引入。**(注意:P4.3/P4.4 之后已知 decode 的 KV cache 与 indexer 都精确,所以「差额由 decode 引入」不等于「decode 有 离散 bug」——见下方「量化后的真实图景」。) 这把 P3 之后「margin 被压缩到 0.256,decode 再推一把就翻」的推断变成了实证。 补充:官方自己 prefill 与 decode 的 margin 也不同(3.112 vs 1.638),所以 「两条路径不完全相等」是框架固有特性(KV cache 量化往返),但**方向不该翻**。 - 路径 1:直接 14 token prefill(`--ids <14个>`,dump `logits_prompt`)—— 已有 - 路径 2:11 token prefill + 3 步贪心 decode(贪心本来就给对了 17607/2793/3139,不需要强制喂 token),dump 第 3 步 decode 的 logits - 参考侧同样跑增量:`ref_next_token.py` 逐步喂 11→12→13→14 个 token, 每一步的记录就是官方 decode 路径的 logits 产出:三条曲线的 margin 与 top-1 逐步对照。 -
P4.2 decode 逐步误差曲线 —— 完成,结论收敛:没有 decode 专属 bug
关键前提:**必须 `DEEPINFER_USE_NEXTN_DECODE=0`**。它默认是 `5`,MTP 投机解码默认开启, 每步产生多行 draft/verify,`logits[0]` 不再对应你以为的那个位置(我第一次跑就是因此 错位,把 pos15 的向量当成 pos14 的,白折腾了一轮)。关掉之后一步一行,完全对齐。 11 token 起,逐步对照(`nomtp` run,8 个 decode step): | pos | 我方 top1 | 官方 top1 | 我方 margin | 官方 margin | Δmargin | 翻转 | |---|---|---|---|---|---|---| | 11(prefill) | 17607 | 17607 | 10.695 | 9.861 | +0.835 | | | 12 | 2793 | 2793 | 8.448 | 10.328 | −1.880 | | | 13 | 3139 | 3139 | 15.276 | 11.946 | +3.330 | | | **14** | **666** | **6127** | **1.480** | **1.638** | −0.157 | **翻转** | | 15 | 6127 | 6127 | 15.950 | 15.109 | +0.842 | | | 16 | 666 | 666 | 20.118 | 17.874 | +2.244 | | | 17 | 320 | 320 | 9.829 | 10.402 | −0.573 | | | 18 | 1 | 1 | 12.262 | 11.091 | +1.171 | | **Δmargin:mean +0.711,std 1.628,|max| 3.330。** 7/8 位置 top-1 正确, 唯一的翻转在 pos14 —— 而那里的**官方 margin 只有 1.638**,其余位置是 9.9~17.9。 换句话说:**噪声幅度(std 1.63)和那个位置的 margin(1.64)一样大,是硬币。** 这不是 decode 的 bug,是量化噪声碰上模型自己也没把握的位置。 官方在 pos14 选了 `6127`(北京),我方选了 `666`(`**`),于是渲染成 `**北京**` —— 语义完全等价,只是 markdown 加粗的位置不同。 顺带排除:MTP 不是原因。`DEEPINFER_USE_NEXTN_DECODE=0` 前后输出完全相同 (`[17607, 2793, 3139, 666, 6127, 666, 320, 1]`)。而官方 `generate.py` 本来 就没有 MTP,所以把 MTP 关掉才是与参考对等的比法。 从第 1 步到第 8 步,每步记 `margin`、`top-1 是否与官方一致`、`rel(B_t, R_t)`。 用来判断误差是「一开始就有」还是「某一步突然放大」——后者意味着踩到了某个 batch/位置相关的边界(例如 page 边界、SWA window 回绕)。 -
P4.3 KV cache 写入/读回一致性 —— 完成,干净,排除
两层验证,都通过。 其一,仓库自带的单测(`store_kv_cache.py` / `load_paged_kv_cache.py`,与各自的 ref 逐元素比),过滤 SM90 实际使用的 fp32-sf index 布局:**各 6 passed**。 全布局跑一遍是 48 passed / 12 failed,失败**全部**落在 `ue8m0` 的 index 布局 (`FP4_INDEX_KV_FORMAT`、`MXFP8_INDEX_KV_FORMAT`),而 SM90 不用这两个。失败点在 ref 自身:它用 `PLATFORM.fp8_sf_type`(SM90 是 fp32)去重解释 ue8m0 字节, `index_copy_` 撞 dtype。属 SM90 上 ue8m0 分支的遗留缺口,不影响本任务。 其二,闭环 round-trip(`scripts/h20_kv_roundtrip.py`):写入已知 bf16 → 读回 → 与 原值比,不依赖任何 ref 实现。覆盖 SM90 实际用的两种布局、block 32/64、1/233/1029 token: | 布局 | bytes/token | rel_err | cos | |---|---|---|---| | `V41_FORMAT`(main/swa KV) | 528 | 0.0266–0.0295 | 0.9996 | | `FP8_FLOAT32_SF_INDEX_KV_FORMAT`(index KV) | **132** | 0.0266–0.0327 | 0.9996 | 正是 FP8 的理论地板,与权重那 2.7% 同量级。**KV cache 不是 decode 误差的来源。** P3.9 遗留的 132B 字节布局问题就此关闭。 坑:这个脚本第一版把「原始 fp8 值」直接和 bf16 比,得到 rel=126 —— 因为 index 布局 的 load **不解量化**(文档写明「返回量化值 + scale」,消费方是 kernel)。 按 `量化值 × scale` 解量化后才是 0.027。差 127 倍的假警报来自测试脚本,不是实现。 -
P4.4
_decode_p_sum_sm90vs 参考实现 —— 完成,数值精确,排除`scripts/h20_index_decode_check.py` 用一份**刻意不共享代码**的 float64 参考实现 (按显式偏移逐 token 切片,而非 strided view)对照: ``` page=32 lens=[1,64] rel=1.4e-07 cos=1.00000 page=32 lens=[31,32] rel=1.5e-07 cos=1.00000 (页边界) page=32 lens=[96,65] rel=1.2e-07 cos=1.00000 (跨页) page=32 lens=[7,33,159] rel=9.4e-08 cos=1.00000 (3 行 32 头) page=64 ... rel≈1.3e-07 cos=1.00000 ``` rel 就是 fp32 舍入量级。Q 的解量化用 `q_sf.reshape(rows, heads, -1)[..., :1]` 也没问题: `head_dim == 128 == gran`,每个 (row, head) 恰好一个 scale(源码里有 `assert self.n_head <= 32 and self.head_dim == 128` 兜住)。 **decode 的 indexer 路径不是误差来源。** -
P4.5 采样器 / logits processor 排除 —— 无需再查
pos14 我方 top1=666、top2=6127,差值 1.480。如果 6127 被任何 mask / blacklist 抑制, 它就不会是第二名。所以 pos14 的差异来自 logits 本身,不是采样后处理。 (`token_logprobs` 恒为 0 的 P5 问题仍然独立存在,与本题无关。)
最终结论:** 是量化噪声在「模型自己也没把握」的位置上的一次抛硬币
三条线索合起来:
- 噪声幅度是恒定的约 1.6 logit(Δmargin std = 1.63,跨 7 个 decode step), 与 prefill 的残余误差同量级(pos11 的 Δmargin +0.835,14-token prefill 的 top-1 误差 −3.30)。它来自 per-128 量化的累积 —— SM90 的 DeepGEMM 强制的那条路。
- 参考模型的 margin 分布很宽:9.86 / 10.33 / 11.95 / 1.64 / 15.11 / 17.87 / 10.40 / 11.09。 只有 1.64 那个位置会被 1.6 的噪声翻掉。
- 只有 pos14 翻转,其余全部正确。 而 pos14 正是 1.64 那个。
所以:
- 不是 KV cache 的问题(P4.3 闭环 round-trip 通过,rel≈0.027)
- 不是 decode indexer 的问题(P4.4 与独立 float64 参考 rel≈1e-7)
- 不是 MTP 的问题(开关 MTP 输出相同)
- 不是采样后处理的问题(6127 在 pos14 是第二名,没被 mask)
是「在 SM90 上必须用 per-128 量化」这件事本身。它在多数位置无感,只在模型自己
接近 50/50 的地方改变结果。而模型在这里确实接近 50/50 —— **北京** 的两个位置
(先 ** 还是先 北京)在语义上没有区别,参考模型也只是略偏一边。
要继续压这个噪声,唯一的杠杆是回到 P3.6 那条路,而它在 SM90 上被 DeepGEMM 的
gran_k == 128 断言封死了(见 H20-DRIFT-ANALYSIS.md)。所以本项调查到此收敛:
剩余差异是硬件量化口径的必然结果,不是实现缺陷。
P4.1 的工具坑(都已修,但 dump 仍建议配合黑盒交叉验证)
| 坑 | 现象 | 修法 |
|---|---|---|
| 多 DP 进程写同一文件 | 8 个 engine 都是单进程组,RANK 全为 0,互相覆盖 |
文件名带 _rank<R>_pid<P> |
| decode 的 batch 有 padding 行 | 取 logits[-1] 读到占位 token 的垃圾(恒定 top1=69) |
取第 0 行(第一个真实请求) |
| follower rank 的 logits 是占位值 | 同一向量被重复记录几十次,淹没真实步 | 判据 driver_inputs is not None |
| profile forward 用合成 token | 抓到 profile 的数据 | debug_dump.profiling() 挂起 |
即便都修了,逐 step dump 与端到端 token 序列仍无法可靠对齐(max_tokens=7 的 run 里
出现 75 次 sampler 调用)。所以 P4.1 的结论以黑盒四格对照为准,dump 只作辅助。
另一个必须记住的坑:max_tokens > 1 的运行里,logits_prompt 也会被污染 ——
mysteps6(max_tokens=7)的 logits_prompt 算出 cos=0.68、top-1 误差 16.5,
而 mylogits3(max_tokens=1)同一输入是 cos=0.9846、误差 3.30。差 5 倍。
比较 prefill logits 只能用 max_tokens=1 的运行。
已备好的工具
debug_dump.record(..., once=True)+logits_prompt/logits_decode两个键debug_dump.profiling():profile forward 期间整体挂起,避免抓到合成 tokenref_next_token.py:吃 token ids,给官方 greedy next token + top5;--force_ids走增量 decode,--logits_out存每一步的完整 logitsscripts/h20_kv_roundtrip.py:KV cache 闭环 round-trip(不依赖 ref)scripts/h20_index_decode_check.py:_decode_p_sum_sm90的独立数值对照
P5 logprob 异常(已排查,未修,非阻塞)
当前 8 个 token 的 token_logprobs 全是 0.0(概率=1),不正常。
已排除(约 20 分钟静态排查 + 单测)
| 嫌疑 | 结论 |
|---|---|
map_lookup kernel |
无罪。单测 6 passed,by_key + float32 + force_topk=4096 全覆盖,与 map_lookup_ref 逐元素相等 |
| sampler 全部 kernel | 无罪。sampler.py -m "not benchmark" → 74 passed / 0 failed |
SampledInfo.from_reqcnt 的 torch.zeros |
死代码,全仓库无调用点;update(is_final, candidate) 也无调用点 |
| sampler→engine 字段传递 | 直通,llm_engine.py:747 原样传 output.token_logprobs |
一个反向线索:map_lookup 里 out = torch.empty,键未命中时本应写 -inf 而不是 0。
所以 0.0 更像「上层根本没把值带下来」,而不是「查表查空了」。
剩余候选与判定路径
process_sampling返回的logprobs本身为 0(fused_sample的 logprob 输出路径; 现有单测只覆盖 kernel 本身,没有覆盖「整个 forward 的 logprob 输出」)build_request_outputs里逐 token 对象的属性回填
判定只需跑 1 次整机(~5 min):在 sampler 里打印 logprobs.max() 与 token_logprobs_cur。
sampler 层就是 0 → 定位在 fused_sample;sampler 层正常 → 定位在 output 回填。
为什么留着不修
不影响推理正确性,只影响 logprob 字段的可用性(AIME 打分、perplexity 这类评估用途)。 预估典型 1 h、最坏 2 h(若牵涉 MTP 异步 logprob 回填),与本次 SM90 支持的目标无关。
备注:当前生效的绕过项(都会影响数值,需在收尾时复核)
| 绕过 | 原因 | 对数值的影响 |
|---|---|---|
DEEPINFER_ENFORCE_EAGER=1 |
CUDA graph capture 期断言失败 | 无 |
DeepSelect topk → torch.topk |
SM90 launch 失败 | 无(契约等价) |
decode indexer → _decode_p_sum_sm90 |
SM90 paged kernel 要求 64-token page | 需 P3.2 验证 |
| 关闭共享层候选块优化 | fp8_fp4_sparse_mqa_logits SM100-only |
无(稠密等价) |
mega_mhc / mega_moe 关闭 |
SM100-only | 无 |