NVFP4 RL - #1261
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces comprehensive support for NVFP4 quantization, including utility functions for environment synchronization, integration with FlashInfer and TransformerEngine, and updates to conversion tools, run scripts, and end-to-end tests. The review feedback highlights two important improvements in miles/utils/nvfp4.py: first, adding a check to fall back to the TransformerEngine reference implementation when weights are on the CPU to prevent FlashInfer from crashing; second, moving the environment synchronization call inside the try block of the context manager to ensure that environment variables are properly restored even if synchronization fails.
|
Root cause update for the NVFP4 4over6 bitwise mismatch: The mismatch is not coming from the Miles quantizer plumbing. Miles is comparing FlashInfer NVFP4 quantization against the TE/FourOverSix-style reference. TE and FourOverSix compute the 4over6 candidate error by dequantizing with the original tensor amax expression, effectively: The current FlashInfer installation computes the same error-domain quantity through the global decode scale path instead. That is algebraically equivalent, but not bitwise identical. On near-tie blocks this changes the strict 4-vs-6 candidate selection, so the packed NVFP4 values and scale bytes can differ from the TE reference. Because of that, |
def88c0 to
59716d8
Compare
Signed-off-by: Ziang Li <ziangli@umich.edu>
Signed-off-by: Ziang Li <ziangli@umich.edu>
Signed-off-by: Ziang Li <ziangli@umich.edu>
Signed-off-by: Ziang Li <ziangli@umich.edu>
Squash of zianglih:fp4 @ f9da769 onto main: TE-direct NVFP4 quantizer with paired gate/up amax handling, the nvfp4 dispatch in quantize_params, flashinfer env forwarding, conversion tool updates, and the GLM5.2 nvfp4 e2e. Carried on this branch until the PR merges upstream. Co-authored-by: Ziang Li <ziangli@umich.edu> Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019ucT9vHENjhVatxSvsT1Mq
* Remove dead and speculative code from the core library - generate_rollout compatibility wrapper and the unreachable per-request version-pinning branch (the live hook contract never supplies rollout_id); the request hook now does only what runs: retry budget + session affinity - test-only helpers: transition_artifact_paths, parse_extra_key_version, validate_policy (redundant with request_context) - register_routes extension point nothing passes - version error helpers inlined into evaluate_version_policy - unused top-level re-export facade in stitch/__init__.py * Remove dangling cookbook artifacts - unreachable per-request version-pin branch in the standalone slime hook (the hook contract never supplies rollout_id; announce_and_wait already gates staleness) + its helper, config knob, and tests - megatron_r3_num_out_tokens.patch: never applied, the fix is baked inline * Dedup the slime/miles twin adapter modules - bulletin_hooks reads generic DELTA_APP_NAME / DELTA_SERVER_CLS_NAME env fallbacks; per-recipe hooks.py become pure re-export shims kept only because configs reference them by dotted string - per-recipe helpers.py shrink to the real per-recipe axes (sidecar module, model-script attr, wake mode) + one-line wrappers; miles-only materialize_node_local_yaml and start_host_mem_monitor move out of the shared trainer_helpers into miles_disagg/helpers - serving wrappers take the shared trainer_repo_* kwarg names; the shared builder computes the cookbook mount dir itself * De-noise prose: drop provenance labels, war stories, and docstring essays Keep the behavioral fact, drop the provenance: external PR/issue labels (slime PR #5, radixark/miles#1261, P0.1), incident anecdotes, milestone roadmap prose (M1/M2/M3), and layout/design essays compressed to what the code needs the reader to know. Pinned SHAs stay; their changelog trailers go. * Trim READMEs and packaging - root README: document all four cookbook recipes; fix the nonexistent slime extra claim - miles_disagg README: compress the fork changelog and bring-up checklist, fold the GLM-4.5-Air section into a variant note, point at the fork for the convert tools, document _spawn_into_deployed - standalone_rollouts README: compress the compatibility spec-dump and the SLIME-harness tail - slime_disagg README: merge the redundant Protocol notes into the run section - pyproject: drop uvicorn from the sglang extra (packaged code never imports it; Modal images install it explicitly)
- transformer_engine / transformer_engine_cu13 / transformer_engine_torch 2.12.0 -> 2.17.0 - update te_fa2_sm103_whitelist.patch for TE 2.17 source layout - add te_dequantized_backward_override.patch (hot fix from NVIDIA/TransformerEngine#3141; drop after TE v2.18)
# Conflicts: # docker/patch/cu13/te_dequantized_backward_override.patch # docker/patch/cu13/te_fa2_sm103_whitelist.patch
torch_memory_saver 0.0.9.post1 ships CUDA-major-suffixed preload binaries (torch_memory_saver_hook_mode_preload_cu13.abi3.so), but actor_factory hardcoded the old unsuffixed name and asserted it exists, breaking every offload_train megatron run. Use the package's get_binary_path_from_package helper to resolve the right variant.
The NVFP4 quantize kernels are gated to sm_100+ (Blackwell); the test is
registered on stage-b-2-gpu-h200 (Hopper) where tex.quantize hits
NVTE_DEVICE_ERROR("sm_100 or higher is required"). Mark disabled, matching
the GLM5.2 NVFP4 e2e test, until miles CI has a B-card suite.
# Conflicts: # docker/Dockerfile
|
For accurate reproduction, need to make sure the flashinfer is after flashinfer-ai/flashinfer#3448 to include the bit-exact 4over6 NVFP4 quantization. That is at least https://github.com/flashinfer-ai/flashinfer/releases/tag/v0.6.13rc1 . |
@HumansAnd
Blog post: https://humansand.ai/blog/nvfp4-rl
Summary
This PR adds NVFP4 rollout/train support for Blackwell Miles with TE-compatible NVFP4 checkpoint conversion, Megatron-to-HF weight export, Qwen3 launch-script wiring, and GLM5.2 e2e coverage.
The current production quantization path is TE-direct rather than a FlashInfer/reference wrapper: Miles constructs
transformer_engine.pytorch.tensor.nvfp4_tensor.NVFP4Quantizerin rowwise-only mode and extracts the rowwise NVFP4 payload fields needed by ModelOpt/SGLang (weight,weight_scale,weight_scale_2). FlashInfer remains the serving backend path via SGLang TRTLLM routed MoE, and Miles forwards relevantFLASHINFER_*andNVTE_*env vars so precision behavior is controlled by the backend libraries rather than new Miles CLI flags.Implementation
NVTE_*/FLASHINFER_*, and disabled-by-default GLM5.2 Blackwell e2e coverage.Validation
Fast-gpu test after syncing this branch:
python3 -m pytest tests/fast-gpu/test_nvfp4_quantizer.py::test_nvfp4_quantize_params_omits_static_input_scale -q1 passed, 25 warnings in 4.48sQwen3-30B-A3B B200 NVFP4 after syncing this branch:
train/train_rollout_logprob_abs_diff=0.030812,train/kl_loss=0.007849Earlier branch validation before the latest cleanup/rebase series: