mirror of
https://github.com/deepseek-ai/DeepInfer.git
synced 2026-10-31 00:36:20 +08:00
`DEEPINFER_ENABLE_FLAGGEMS=1` turns it on. Verified on all 8 DP ranks: exit=0, 8/8 ranks agreeing, no kernel fallbacks, `hard failures: none`, correct answers. 19 ops actually dispatched, 152 call sites, 43 registrations from 37 requested names. The default is `flag_gems.only_enable(include=[...])`, not `enable()`, and that is the whole design: * allow-list -- every intermediate state is safe (unproven ops stay on PyTorch, which is correct by construction); an incomplete list costs throughput, not correctness. * deny-list -- I tried it first. Five full engine runs, one new defect each: `cat` (e8m0 dtype), `mul` (broadcast shape), `topk` (compile blowup), `rms_norm` (signature), `mm` (compile assert). The method requires being bitten before it can exclude, and every state along the way is unsafe. That matches the instruction this was built to: use what works, leave the rest. Where it is called is not incidental. `import flag_gems` initialises a CUDA context -- measured, `torch.cuda.is_initialized()` flips on the import alone, before `enable()`. A `sitecustomize` injector therefore put all 8 ranks on device 0 and NCCL refused with "Multiple Ranks are using the same GPU". It now runs inside `create_llm`, after `setup_cuda_visible_devices`, which is the same hazard already documented there for the profiler. Defects found and documented rather than worked around, because each one is worth knowing: * `mul` returns the *first operand's shape* when broadcasting expands it: (1,64,8)*(4,1,8) gives (1,64,8), and (64,1)*(1,128) gives (64,1). Silent, no error, fewer elements computed. It made `engram_hash_ref` disagree with PyTorch during a real run. add/sub/div/maximum/minimum all broadcast correctly, so it is mul's own bug. * `cumsum` drifts by up to 1.0 over a 512-element bf16 row (tolerance ~0.17) -- bf16 accumulation. * `topk`'s compile time explodes with k: 4.8 s at k=8, 19 s at k=64, >180 s at k=512, and the sampler asks for 4096. py-spy put all 8 ranks at 100% CPU inside `make_llir` with every GPU idle. * `cat` raises `KeyError: 'float8_e8m0fnu'` on the model's UE8M0 scale tensors during weight load. * `mm` passes every isolated probe yet fails inside the engine at `general_mm`; trigger unknown, so GEMMs stay on cuBLAS, which is faster anyway. Two methodological errors in my own measurements, both fixed and both recorded: 1. After `enable()`, `torch.mul` *is* `flag_gems.mul`, so the first version of the mul A/B compared FlagGems with itself and reported a perfect score. All references are now computed before enable. 2. "ok" did not mean FlagGems ran. `torch.bitwise_xor` has no FlagGems registration at all, so that "match" was PyTorch against PyTorch. `screen_ops.py` now checks registration first and reports such cases as `skip` rather than pass. Name mismatch is its own trap: FlagGems registers `add` bare but `eq.Scalar`, `where.self`, `repeat_interleave.self_int`, `_softmax` (not `softmax`), `div.true_divide`. Asking for `softmax` silently registers nothing. The bootstrap now expands names against `flag_gems._FULL_CONFIG` and warns on anything unresolved -- which is how `softmax` was found to need `_softmax`. Output is not token-identical to the no-FlagGems build (diverges at the first token), but two runs of the same FlagGems config are bit-identical, so the difference is Triton-versus-eager accumulation order, not nondeterminism. Answers stay correct and coherent.
4.1 KiB
4.1 KiB
分支记录(SM90 / H20 这条线)
截止 2026-10-25 14:40。所有分支都已推到 tonyh168/DeepInfer。
一句话地图
main (8b16149)
└── h20-sm90-support 5004c77 TileLang PR 版:SM90 attention 用 TileLang 实现
└── h20-sm90-triton 73b8090 把引擎 kernel 换成 Triton 后端
└── h20-sm90-triton-flagtree c6a65fe 同上,在 flagtree 镜像里重编 vendor 库
└── h20-sm90-sparse-mla-triton 6d337a8 再换掉 attention:无 tilelang 端到端
└── h20-sm90-flaggems ← 当前 HEAD,全面接入 FlagGems(见 H20-FLAGGEMS-PLAN.md)
另一条独立的线:h20-sm90-lossless-requant(74ba468),做无损 requant 与 debug_dump 挪位,不在这条链上。
逐个说明
| 分支 | HEAD | 这条分支解决了什么 | 关键限制 |
|---|---|---|---|
h20-sm90-support |
5004c77 |
上游 PR #180 的基础:FlashMLA 是 SM100-only,SM90 上按 patch_imports 钩子换成自己实现的 attention |
attention 仍是 TileLang |
h20-sm90-triton |
73b8090 |
引擎侧 29 个 kernel 加 Triton 实现(17 个可用),DEEPINFER_OPS_BACKEND=triton 切换 |
融合算子库 tile_kernels 仍要 TileLang |
h20-sm90-triton-flagtree |
c6a65fe |
在 flagtree 镜像(torch 2.11 + cu13)里重编 deepinfer._C / deep_gemm / deep_ep / deep_select;tile_kernels 加 compat 层走 torch 参考,从而不 import TileLang;修掉参考实现在 sync 守卫下抛错的问题 |
attention 仍要 TileLang |
h20-sm90-sparse-mla-triton |
6d337a8 |
attention 也换成 FlagGems 的 Triton kernel,于是「屏蔽 tilelang 也能端到端」成立 | 采样器的 rejection-sampling 变体仍要 TileLang(关 MTP 可绕);不与 TileLang 版逐 token 一致 |
h20-sm90-flaggems |
进行中 | FlagGems 白名单启用已端到端跑通(19 算子、8/8 DP、0 回退);per-token quant 已验证逐位相同 | 只覆盖点状/reduction 算子;GEMM 留 cuBLAS;token 级与不用时不同但确定性 |
h20-sm90-sparse-mla-triton 到底做了什么
新增三个文件、改一处 import:
| 文件 | 作用 |
|---|---|
deepinfer/h20_ops/vendor/flashmla_sparse.py |
内联 PyPI flag_gems 5.0.2 的 sparse MLA Triton kernel(329 行,Apache-2.0,文件头记了 md5 和两处本地改动) |
deepinfer/h20_ops/sparse_mla_triton.py |
适配层:(out, max_logits, lse) → (out, lse);lse 自然对数 → log2;两种调用约定(共享 KV / 每 query 独立 KV) |
deepinfer/h20_ops/sparse_mla.py |
分发层:DEEPINFER_SPARSE_MLA_BACKEND=tilelang|triton,不设则能 import tilelang 就用它 |
deepinfer/h20_ops/attn_sm90.py |
只改一行 import,两个调用点未动 |
验证(每步先过再往下):
| 步 | 内容 | 结果 |
|---|---|---|
| 1 | 内联 kernel vs TileLang,7 形状 | ALL_MATCH,≤2 bf16 ULP |
| 2 | decode 形态(fp8 cache,含 SWA+full 双缓存),5 用例 | ALL_MATCH |
| 3 | 适配层契约,5 组 | ALL_PASSED |
| 4 | 分发层 + attn_sm90 两个入口,4 组 |
ALL_PASSED |
| 5 | 屏蔽 tilelang 端到端 | exit=0,0 回退,8/8 DP 一致 |
| 6 | 有 tilelang 对照 | exit=0,0 回退 |
复现:
DEEPINFER_SIMULATE_NO_TILELANG=1 DEEPINFER_KERNELS=ref DEEPINFER_OPS_STRICT=1 \
DEEPINFER_USE_NEXTN_DECODE=0 bash scripts/h20_e2e_report.sh
怎么切分支
git fetch tonyh168
git checkout h20-sm90-sparse-mla-triton # 最新最全
git checkout h20-sm90-triton-flagtree # 只要 engine kernel 是 Triton、attention 留 TileLang
git checkout h20-sm90-support # 只要 SM90 能跑(attention=TileLang,工程最省)
已知未做
- 性能一次没测(prefill/decode 吞吐、TTFT)。所有结论都是「能跑、数值对」,不是「跑得快」。
- 与 TileLang 版不逐 token 一致(prompt A 前 15 个 token 相同、第 16 分叉)。控制实验已证明非采样噪声。
fused_sample的 rejection-sampling 变体仍依赖 TileLang,故纯 Triton 需关投机解码。