Prhub

#38611 [docs] Add the NVIDIA NVFP4 export to the Qwen3.8-27B cookbook

原始 PR 作者 zijiexia 合并时间 2026-09-12 02:58 文件变更 3 提交数 9 评论 1 代码增减 +283 / -96

执行摘要

cookbook 新增 NVIDIA NVFP4 导出并修复 5090 启动参数

PR body 的 Motivation 段写明:NVIDIA 官方发布了 ModelOpt NVFP4 导出 nvidia/Qwen3.8-27B-NVFP4,而 cookbook 页面已内置两个 RadixArk NVFP4 checkpoint,导致拉取 NVIDIA 导出的读者没有可复制的启动命令 cell。由于它与 RadixArk FP4-head 导出是同一 W4A4 权重体,可以逐字复用现有配方(reuse those recipes verbatim rather than needing its own operating point),不需要另设操作点。

值得 cookbook / 文档系统维护者精读:① 用逐字节对比 config.json 证明两个 checkpoint 等价从而合法复用配方的验证方法;② 前缀测试 vs 显式枚举的教训——String(quant).startsWith("nvfp4") 在新增导出后静默出错;③ 文档配置中 stripPrefixes 与 flags 必须成对维护的设计约束。对普通用户,重点是确认新导出的可用性结论(202 cell 全量 GSM8K 实测,NVIDIA 导出在全部三张卡上是得分最高的 NVFP4 checkpoint)。

讨论亮点

本 PR 没有产生实质性的 review 交锋:唯一评论是 mintlify bot 的 preview 部署通知,最终由 wisclmy0611 APPROVED(无评语)。所有设计权衡都由作者沉淀在 PR body 与 config 注释中,例如:

Same footprint and same quantization layout, so the mem-fraction pins, the 32 GB RTX 5090 fit and the DGX Spark earlyoom headroom all hold.(两个导出等价性的核心论证)

The Mamba ratio calculator inferred the auto KV precision from a String(quant).startsWith("nvfp4") test, which would have reported half the real kv_bytes_per_token for this checkpoint.(前缀测试误判的教训)

实现拆解

  1. 新增 NVIDIA 导出选项与 4 个 cell(docs/src/snippets/configs/Qwen/qwen3.8-27b.jsx):在 matchDims.quant 中新增 nvfp4-nvidia(NVFP4-NVIDIA),映射到 nvidia/Qwen3.8-27B-NVFP4。作者先逐字节对比两个导出的 config.json / hf_quant_config.json / safetensors index,确认 401 层量化、2,194 张量、21.92 GB、FP4 打包 lm_head 完全一致,因此 4 个新 cell(RTX PRO 6000、RTX 5090、DGX Spark、GB300)的 flags 与 nvfp4-fp4-head 对应 cell 逐字相同。overlay 行基于 String(sel.quant).startsWith("nvfp4") 的禁用逻辑自动让新选项继承 32 GB RTX 5090 上的可用性包络。
  2. 修复 RTX 5090 上的内存池自洽问题:测量发现 DSPARK 行原本只 pin --max-running-requests 1,但 KV 池按 127,332 token 自举(单请求 8192 in / 1024 out 只需 9,216 token),且 draft 模型 3.64 GB 权重计入 --mem-fraction-static 后 GDN 状态池默认拆分不足,启动报 max_mamba_cache_size=0 ... max_num_reqs=0。DSPARK 行因此扩展 stripPrefixes 并新增 --max-total-tokens 16384,以及按 quant / ssmDtype / tier 三轴区分的 --mem-fraction-static、--chunked-prefill-size、--mamba-full-memory-ratio 固定值;DFLASH2 与 dense-lm_head 的 MTP float32 组合也补上同样的 pool pin。
  3. 修正 Mamba ratio 计算器的 KV 精度推断(docs/src/snippets/_qwen38_mamba_ratio_calculator.jsx):原实现用 String(quant).startsWith("nvfp4") 推断 auto 精度为 fp8_e4m3,但 NVIDIA 导出不带 kv_cache_scheme,auto 实际落 bf16,前缀测试会把 kv_bytes_per_token 少算一半。改为显式匹配两个 RadixArk id(nvfp4-bf16-head / nvfp4-fp4-head),并在注释中说明前缀测试不安全的理由。同时删除了"fp8 KV 池携带 checkpoint 校准 scale"的错误陈述——两个 RadixArk 导出并未发布 k_scale / v_scale,实际回退为 1.0。
  4. 文档正文与版本基线对齐(docs/cookbook/autoregressive/Qwen/Qwen3.8-27B.mdx):checkpoint 表格新增 NVIDIA 行;部署 Note 与 SM121 段落从"boot-and-serve 弱标准"升级为"202 cell 全量 GSM8K 实测"口径;安装说明经历 pin v0.5.19 → unpin 到 latest 的演进(最后一轮 commit),并同步修正 DSPARK 0.89→0.91 的陈旧注释与"DFLASH2 是唯一需要小 prefill chunk"的过时陈述。
  5. 验证配套:无自动化测试文件变更,依赖 node docs/scripts/check_cookbook_configs.mjs 做配置结构校验;另以 sgl-eval 对 202 个 cell 逐个跑完整 1319 题 GSM8K 作为人工验证,覆盖 5 个 checkpoint × 4 种 spec 选项 × 2 个 serving tier × 2 种 GDN state dtype。
文件 模块 状态 重要度
docs/src/snippets/configs/Qwen/qwen3.8-27b.jsx 启动配置 modified 7.16
docs/src/snippets/_qwen38_mamba_ratio_calculator.jsx 比例计算 modified 5.23
docs/cookbook/autoregressive/Qwen/Qwen3.8-27B.mdx 菜谱文档 modified 4.56

关键符号

Qwen38MambaRatioCalculator

关键源码片段

docs/src/snippets/configs/Qwen/qwen3.8-27b.jsx configuration

本 PR 核心:新增 nvfp4-nvidia 量化选项与 4 个 cell,并重构 RTX 5090 上 EAGLE / DSPARK / DFLASH2 三行的 stripPrefixes 与 flags 逻辑,修复原配方无法启动的问题。

// matchDims 中的量化选项:新增 NVIDIA 官方导出,复用 FP4-head 配方。
{ id: "quant", title: "Quantization", options: [
  { id: "bf16", label: "BF16" },
  { id: "fp8", label: "FP8" },
  { id: "nvfp4-bf16-head", label: "NVFP4-BF16-Head" },
  { id: "nvfp4-fp4-head", label: "NVFP4-FP4-Head" },
  // NVIDIA 的 ModelOpt 导出与 RadixArk FP4-head 是同一 W4A4 权重体:
  // 401 层量化、同样的张量集合、21.9 GB 磁盘占用、同样 FP4 打包的
  // lm_head,所以每条 cell 都逐字复用 FP4-head 配方的参数。
  // 唯一差异是它不声明 kv_cache_scheme,`--kv-cache-dtype auto`
  // 在这里会落到 bf16 而不是 fp8_e4m3;而页面所有 cell 都显式
  // pin 了 fp8_e4m3,所以最终启动命令与 KV 池完全一致。
  { id: "nvfp4-nvidia", label: "NVFP4-NVIDIA" },
] },
​
// DSPARK overlay:在 32 GB RTX 5090 上由本行完全接管内存池。
// 原先只 pin --max-running-requests 1,KV 池却按 127,332 token
// 自举(单请求 8192 in / 1024 out 只需 9,216),draft 模型
// 3.64 GB 计入 --mem-fraction-static 后 GDN 状态池又默认拆分不足,
// 启动直接报 max_mamba_cache_size=0 ... max_num_reqs=0。
stripPrefixes: (sel) =>
  sel.hw === "rtx5090"
    ? ["--mem-fraction-static", "--mamba-full-memory-ratio",
       "--chunked-prefill-size", "--max-total-tokens"]
    : [],
flags: (sel) => [
  "--speculative-algorithm DSPARK",
  "--speculative-draft-model-path RadixArk/Qwen3.8-27B-DSpark",
  // 以下取值都在 v0.5.19 上以 ISL 8192 / OSL 1024、并发 1 实测。
  // 两个 FP4-head 导出共用一组 pin;dense-lm_head 导出因运行时
  // 多占约 3.2 GB,需要自己的 mem-fraction 与 chunk 组合。
  ...(sel.hw === "rtx5090"
    ? [
        "--max-total-tokens 16384",
        ...(sel.quant === "nvfp4-bf16-head"
          ? ["--mem-fraction-static 0.92",
             "--chunked-prefill-size 512",
             sel.tier === "low-latency"
               ? "--mamba-full-memory-ratio 3.38"
               : "--mamba-full-memory-ratio 2.71"]
          : sel.ssmDtype === "float32"
            ? ["--mem-fraction-static 0.91",
               "--chunked-prefill-size 1024",
               sel.tier === "low-latency"
                 ? "--mamba-full-memory-ratio 6.94"
                 : "--mamba-full-memory-ratio 5.56"]
            : ["--mem-fraction-static 0.88",
               sel.tier === "low-latency"
                 ? "--mamba-full-memory-ratio 3.38"
                 : "--mamba-full-memory-ratio 3.12"]),
      ]
    : []),
],
docs/src/snippets/_qwen38_mamba_ratio_calculator.jsx core-logic

修复 KV dtype 推断的前缀误判,避免新导出下计算器少算一半 kv_bytes_per_token;是整个 PR 中最具方法论意义的一处小改动。

// 推断 --kv-cache-dtype 未显式指定时(auto)实际落到的 KV 精度。
// 两个 RadixArk NVFP4 导出声明了 kv_cache_quant_algo: FP8,auto
// 会落到 fp8_e4m3;BF16 / FP8 以及 NVIDIA 导出都没有声明 KV 方案,
// auto 会留在 bf16。这里不能沿用 String(quant).startsWith("nvfp4")
// 前缀测试——NVIDIA 导出的 id 是 nvfp4-nvidia,前缀相同但行为不同,
// 前缀测试会把它的 kv_bytes_per_token 少算一半。
// 显式 flag 永远优先于 checkpoint 声明。
const kvFlag = flagArg("--kv-cache-dtype");
const kvDtype =
  kvFlag === "fp8_e4m3"
    ? "fp8_e4m3"
    : kvFlag === "bfloat16" || kvFlag === "bf16"
      ? "bfloat16"
      : quant === "nvfp4-bf16-head" || quant === "nvfp4-fp4-head"
        ? "fp8_e4m3"
        : "bfloat16";

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

  1. 回归风险(计算器逻辑):_qwen38_mamba_ratio_calculator.jsx 的 kvDtype 分支改为显式 id 枚举。虽然修复了 NVIDIA 导出的误判,但该分支没有任何自动化测试保护(PR 只靠 check_cookbook_configs.mjs 做结构校验),未来新增第三个 NVFP4 导出时若忘记同步更新此处,会再次静默算错内存比例。
  2. 启动配置复杂度:qwen3.8-27b.jsx 中 DSPARK 的 pin 已按 quant × ssmDtype × tier 三轴嵌套出 12 种取法,且 stripPrefixes 与 flags 必须保持同步——strip 列表一旦漏掉新 flag,覆盖逻辑就会失效。这种"配置即逻辑"的写法对后续维护者要求很高。
  3. 版本基线漂移:最后一轮 commit 把安装命令从 pin v0.5.19 改为 uv pip install --prerelease=allow sglang 与 lmsysorg/sglang:latest,而全部测量数据都基于 v0.5.19。新版本若改变内存布局或默认值,页面上的 pin 可能失效且无人感知。
  4. 行为语义风险:NVFP4-NVIDIA 导出不带 kv_cache_scheme,若读者把 Playground 的 KV Cache Precision 切回 Auto,KV 池会以 bf16 运行,与其它 NVFP4 cell 的 fp8_e4m3 行为不同——文档已明确提示,但用户体验差异仍可能造成困惑。

用户影响:NVIDIA 导出用户获得可直接复制的启动命令;RTX 5090 上 DSPARK / DFLASH2 / MTP + fp32 状态组合的读者不再拿到必然 boot 失败的配方。影响范围限于阅读该 cookbook 页面的 Qwen3.8-27B 用户。系统影响:零,纯文档仓库改动,不触及任何运行时代码。团队影响:新增 12 种 DSPARK pin 组合与 3 处 overlay 的 strip 逻辑,后续维护和再测量成本上升;但同时也建立了"202 cell 全量 GSM8K"的验证基线,为同类 cookbook 页树立了测量口径。

文档配置逻辑变更 缺少自动化测试覆盖 版本基线漂移风险

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论