Skip to content

feat(sglang): mxfp8 quantized rollout and refit - #3614

Open
Kh4L wants to merge 14 commits into
NVIDIA-NeMo:mainfrom
Kh4L:recut/sglang-mxfp8
Open

Kh4L wants to merge 14 commits into
NVIDIA-NeMo:mainfrom
Kh4L:recut/sglang-mxfp8

Conversation

@Kh4L

@Kh4L Kh4L commented Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Original work: #3188 by @xiuhu17. Re-cut at his request; the original authorship and sign-offs are preserved.

Add MXFP8 SGLang rollouts with Megatron weight refit. Startup and refit share precision exclusions and weight/scale grouping; MoE router weights remain BF16. Startup requires a local checkpoint produced by the explicit offline GPU converter.

#3613 is merged. This PR contains the MXFP8 increment against main; #3615 builds on it.

Current main refresh

Head 321e18808b8b249ef2ae15f015a51262fdfbdddb incorporates main cfd9de9902bde17e93d6f7514b0789b907606a13. The merge is clean. The quantization core, checkpoint-selection and grouping modules are unchanged from the previous PR head. Dependency files and submodule pins match main.

  • 88 focused CPU tests pass: quantization, checkpoint selection, weight grouping and configuration.
  • Repository-pinned Ruff 0.9.9 lint, import sorting, formatting and syntax checks pass across all 21 Python feature files.
  • These are normal-import macOS checks with project conftest/config disabled. Real serving tests require the SGLang/GPU runtime and remain part of native CI.

Historical GPU evidence: HSG job 6588661 completed four Nemotron-3-Nano optimizer steps and four MXFP8 broadcast refits on three nodes / 12 GPUs, with decode CUDA graphs and the expected 2688-to-2816 hidden-size padding. That run predates this main refresh and does not validate the current head.

Fresh CI is requested for the current commit. Maintainer review remains required.

@copy-pr-bot

copy-pr-bot Bot commented Aug 12, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@Kh4L
Kh4L marked this pull request as ready for review August 13, 2026 01:33
@Kh4L
Kh4L requested review from a team as code owners August 13, 2026 01:33
@Kh4L
Kh4L force-pushed the recut/sglang-mxfp8 branch 4 times, most recently from cf8ef21 to a30d34a Compare August 14, 2026 05:40

@Kh4L Kh4L left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-review (/review-pr-team), per the contributor self-review policy

Scoped to this PR's own increment (be5015649..8f6003694 as reviewed — the mxfp8 commit plus its ruff-format fix). The two layers below have their own posted self-reviews and were not re-reviewed.

The headline: the bf16 default path is a strict no-op and is safe, but the mxfp8 path could not complete setup() on any config in this repo, and on the model this work targets it quantized the MoE router. Four findings are fixed in a30d34a; six are left inline for your judgement because each needs a design decision I did not want to make unilaterally on someone else's design.

Fixed in a30d34a

  1. MoE routers were being quantized. SKIP_WEIGHT_SUBSTRINGS held "router" and "mlp.gate.", which between them miss most router spellings. A top-k router is a discrete argmax, so quantization error flips expert selection — a rollout/trainer policy divergence, the one failure an RL run can't absorb. Widened to .gate. + shared_expert_gate., covering mlp.gate. (Qwen3-MoE, DeepSeek), block_sparse_moe.gate. (Mixtral), mixer.gate. (NemotronH/nanov3) and Qwen2-MoE's separate gate, while leaving gate_proj / gate_up_proj / shared_expert.gate_proj quantized. The repo already draws this line in DEFAULT_NVFP4_IGNORE and the nanov3 recipe's real_quant_ignore.
  2. CONVERTER_VERSION → 5, mandatory given (1). _quantization_fingerprint hashes the config knobs but not the module-level selection constants, so changing the skip list without bumping it silently reuses a cached checkpoint whose router is already quantized — while the refit, now skipping it, sends BF16 into a slot the engine loaded as MXFP8. See the inline comment on the fingerprint for the durable fix.
  3. convert_mxfp8 required model.safetensors.index.json. That's every shipped SGLang recipe: all five run Qwen2.5-Math-1.5B-Instruct, which ships a single model.safetensors and no index. _checkpoint_weight_names in the same module already handled both layouts; the converter now takes the same branch.
  4. test_quantized_refit_requires_megatron_backend asserted nothing — only the two non-raising cases. Neutering the guard to a bare return left all 17 tests green. Plus ruff check failures (two unused imports, three import-ordering) that the earlier ruff-format commit didn't cover but lint-check would have caught, and a 2025 copyright header on two files added in a 2026 commit.

Process disclosure

The adversarial pass ran but was unreliable to reach; several rounds produced nothing before it reported. It ultimately delivered, and it earned its place — it overturned my own fix. My first version of finding (1) enumerated block_sparse_moe.gate. and shared_expert_gate., which still left backbone.layers.N.mixer.gate.weight quantized — the router of NVIDIA-Nemotron-3-Nano-30B-A3B, the model this work targets. It caught that by fetching the real checkpoint's safetensors header and running should_quantize against the actual tensor names and shapes. The committed fix is its .gate. widening, not mine.

It also corrected the review in three other directions worth recording: it disputed a confidence-90 finding of chained .get() at grpo.py:1402 as a style note on code matching pre-existing house style exactly (dropped); it downgraded a coverage claim after showing three independent hand-rolled measurements disagreed on the denominator (so no percentage appears below); and it found one agent's cited test artifact did not exist, so that agent's numbers are not cited here.

Environment caveats

No GPU and no sglang/flashinfer installed, so nothing involving SGLang's or flashinfer's runtime behaviour was executed by anyone. Findings are marked traced-vs-executed inline. pytest could not run the repo suite (uv.lock is Linux-only on this machine); the new test file's assertions were verified by executing the real should_quantize against them, and the file will collect normally in CI, where transformers is a core dependency.

What would take this from "unexercised" to "shippable"

The PR body is candid that no mxfp8 run exists. In rough order of cost:

  1. One smoke run — GRPO + Megatron + SGLang + scheme: mxfp8, 2–3 steps, on a sharded model. This alone exercises everything fixed above.
  2. Round-trip correctness — per-token logprob agreement between the mxfp8 SGLang rollout and the Megatron policy on a fixed prompt batch. The existing sglang recipes already gate on median(token_mult_prob_error) < 1.1, so the same number under mxfp8 vs the bf16 baseline is the natural A/B with no new tooling.
  3. ≥3 refits, not 1, with the importance-sampling ratio logged per step — drift from quantizing during refit only shows after several updates.
  4. Throughput and memory A/B, bf16 vs mxfp8, same model/TP/batch. Without this there is no stated benefit.
  5. A run with num_layers_at_start_in_bf16 > 0 where the emitted config.json is inspected — the cheapest possible check, and it would have caught the layer-band issue flagged inline.

No docs/ page accompanies seven new user-facing config keys. docs/fp8.md is the natural home — it already documents the vLLM FP8 story including the equivalent layer-band knobs.

Generated by Claude Code

Comment thread nemo_rl/algorithms/grpo.py Resolved
@Kh4L
Kh4L force-pushed the recut/sglang-mxfp8 branch 5 times, most recently from fdd2c03 to 84713d6 Compare August 18, 2026 19:24
@Kh4L
Kh4L requested a review from a team as a code owner August 18, 2026 19:24
@Kh4L
Kh4L force-pushed the recut/sglang-mxfp8 branch from 84713d6 to f60ca44 Compare August 18, 2026 19:29
@github-actions github-actions Bot added the Documentation Improvements or additions to documentation label Aug 18, 2026
@Kh4L
Kh4L force-pushed the recut/sglang-mxfp8 branch from f60ca44 to 3c88ad3 Compare August 25, 2026 03:29
@Kh4L
Kh4L requested a review from a team as a code owner August 25, 2026 03:29
@Kh4L

Kh4L commented Aug 25, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 3c88ad3

@Kh4L
Kh4L force-pushed the recut/sglang-mxfp8 branch from 3c88ad3 to 2e2bffe Compare August 26, 2026 03:24
@Kh4L Kh4L added the CI:L2 Run doctests, unit tests, functional tests, and convergence tests label Aug 26, 2026
@Kh4L

Kh4L commented Aug 26, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 2e2bffe

@Kh4L

Kh4L commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test b7a6731

@Kh4L

Kh4L commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 532df8f

@Kh4L
Kh4L force-pushed the recut/sglang-mxfp8 branch from 532df8f to bfa0eaf Compare August 27, 2026 07:05
@Kh4L

Kh4L commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test bfa0eaf

@Kh4L

Kh4L commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test

@copy-pr-bot

copy-pr-bot Bot commented Aug 27, 2026

Copy link
Copy Markdown

/ok to test

@Kh4L, there was an error processing your request: E1

See the following link for more information: https://docs.gha-runners.nvidia.com/cpr/e/1/

@Kh4L

Kh4L commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 54e9be4

@Kh4L

Kh4L commented Aug 27, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test f777ea0

@Kh4L

Kh4L commented Aug 27, 2026 •

Copy link
Copy Markdown
Contributor Author

Current head f777ea03137ec1d2747392c9a54fe25c12249342 fixes all four stale plain-BF16 SGLang test fixtures. Compared with HSG-validated 54e9be45c46ed9d33d245d1c9032c6cec6cc8653, only those unit-test fixtures changed; runtime, recipes, and dependencies are identical. Fresh CI is triggered on the exact head.

@Kh4L

Kh4L commented Sep 17, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 7f9f520

xiuhu17 and others added 12 commits October 3, 2026 00:35
Enable scheme=mxfp8 under policy.generation.sglang_cfg.quantization:

- mxfp8_setup.py: offline HF->MXFP8 checkpoint conversion with cache
  fingerprinting (ensure_mxfp8_checkpoint), run before SGLang boot
- mxfp8_quantization_core.py: quantize_mxfp8 (flashinfer), dynamic
  skip-substring policy, scale-key helpers shared by offline conversion
  and online refit
- MegatronSGLangHfWeightIterator: quantize eligible tensors during the
  AutoBridge walk, emitting (weight, weight_scale_inv) pairs sized into
  post-transformation buckets
- wire target_precision/sglang_quantization_cfg through the megatron
  refit paths; SglangQuantizationConfig type + exemplar YAML block

Signed-off-by: zhihaow6 <zhihaow6@illinois.edu>
(cherry picked from commit d0cf391)
Same gate as the equivalent commit lower in this stack: the mxfp8 quantization
modules and their tests fail `ruff format --check` under the version pinned in
.pre-commit-config.yaml (v0.9.9), which breaks lint-check and therefore the
whole pipeline.

Signed-off-by: Serge Panev <spanev@nvidia.com>
…ts, pass ruff

Four self-review findings on the mxfp8 increment.

`SKIP_WEIGHT_SUBSTRINGS` held "router" and "mlp.gate.", which between them
miss most MoE router spellings. A top-k router is a discrete argmax, so
quantization error flips expert selection outright -- a rollout/trainer
policy divergence, which is the one failure an RL run cannot absorb.
Widened to `.gate.` plus `shared_expert_gate.`, which covers the class
rather than the families we happened to notice: `mlp.gate.` (Qwen3-MoE,
DeepSeek), `block_sparse_moe.gate.` (Mixtral), `mixer.gate.`
(NemotronH/nanov3) and Qwen2-MoE's separate `shared_expert_gate`. The
dots are load-bearing -- `gate_proj`, `gate_up_proj` and
`shared_expert.gate_proj` are ordinary MLP weights and stay quantized.

Worth stating why the narrow version of this fix was wrong: it enumerated
`block_sparse_moe.gate.` and `shared_expert_gate.`, which left
`backbone.layers.N.mixer.gate.weight` -- the router of
`NVIDIA-Nemotron-3-Nano-30B-A3B`, the model this work targets -- still
quantized. Verified against that checkpoint's real tensor names and
shapes, and the repo already draws the same line in
`DEFAULT_NVFP4_IGNORE` and the nanov3 recipe's `real_quant_ignore`.

`CONVERTER_VERSION` goes to 5 because of that skip-list change. The cache
directory hashes the config knobs via `_quantization_fingerprint`, but not
the module-level selection constants, so without the bump a checkpoint
converted under the old list would be reused with its router already
quantized -- while the refit, now skipping it, sends BF16 into a slot the
engine loaded as MXFP8.

`convert_mxfp8` opened `model.safetensors.index.json` unconditionally, so
any checkpoint whose BF16 weights fit in one file died with a bare
FileNotFoundError. That is every shipped SGLang recipe: all five run
Qwen2.5-Math-1.5B-Instruct, which ships a single `model.safetensors` and
no index. `_checkpoint_weight_names` in the same module already handles
both layouts; the converter now takes the same branch and derives its
shard list from the directory when there is no index.

`test_quantized_refit_requires_megatron_backend` called only the two
non-raising cases, so the branch the guard exists for was never
exercised -- neutering the function to a bare return left the whole suite
green. The rejecting case is now its own test.

Also: `ruff check` was failing on the increment (unused `Iterable` and
`pytest` imports, three import-ordering violations). The earlier
`chore(sglang): satisfy the repo-pinned ruff formatter` commit only
covered `ruff-format`, so `lint-check` -- which the whole pipeline
`needs` -- would still have failed. And two of the three new modules
carried a 2025 copyright header in a 2026 commit.

Signed-off-by: Serge Panev <spanev@nvidia.com>
Signed-off-by: Serge Panev <spanev@nvidia.com>
Signed-off-by: Serge Panev <spanev@nvidia.com>
Signed-off-by: Serge Panev <spanev@nvidia.com>
Signed-off-by: Serge Panev <spanev@nvidia.com>
Signed-off-by: Serge Panev <spanev@nvidia.com>
Signed-off-by: Serge Panev <spanev@nvidia.com>
Signed-off-by: Serge Panev <spanev@nvidia.com>
Signed-off-by: Serge Panev <spanev@nvidia.com>
Signed-off-by: Serge Panev <spanev@nvidia.com>
@Kh4L
Kh4L force-pushed the recut/sglang-mxfp8 branch from 7f9f520 to 5babc80 Compare October 4, 2026 07:07
@Kh4L

Kh4L commented Oct 4, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 5babc80

Kh4L added 2 commits October 28, 2026 10:46
Signed-off-by: Serge Panev <spanev@nvidia.com>
Signed-off-by: Serge Panev <spanev@nvidia.com>
@Kh4L

Kh4L commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

/ok to test 321e188

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CI:L2 Run doctests, unit tests, functional tests, and convergence tests Documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants