Repository navigation
Conversation
Signed-off-by: YigongQin <yigongq@nvidia.com>
YigongQin
force-pushed
the
yigongq/mega-training-forward
branch
from
October 12, 2026 21:15
d50fd00 to
44bf60c
Compare
6 of 9 tasks
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What does this PR do?
Add
flashinfer_megaas aninference_grouped_gemm_backend, and as a backend ofmoe_inference_training_forward(from ). The backend runs FlashInfer'smoe_epmegakernel, a single fused kernel that does the EP token transport and the SwiGLU expert MLP. With this PR, a training step's value-producing MoE forward can run the same megakernel that generation runs, while the backward still comes from the TE recompute pass. A training log-prob and a generation log-prob of the same token then come from the same kernel.Precisions:
bf16,mxfp8,nvfp4andfp8_fp4are available for generation. Onlybf16andmxfp8can drive the training forward, because they are the ones whose kernel weights Megatron can rebuild from the parameters. Undermxfp8the value is quantized and the gradient is that of the BF16 function (straight-through), as for the other backends of the mode.Motivation: RL
Same goal as the base PR: a zero train/generation log-prob gap for on-policy rollouts. The base PR provides the generic mechanism, with the
vllmandtorchexpert kernels. This PR adds a backend whose kernel fuses dispatch, expert compute and combine, so there is no separate dispatcher or grouped GEMM left to keep bitwise-aligned between training and generation.1. Mega backend for generation
megatron/core/inference/moe/mega/(new):adapter.py:MegatronMegaMoEAdapterwraps FlashInfer'sMoEEpMegaLayer. Expert ids are sorted into a canonical order before the combine, because the kernel accumulatesprob * expert_outin the order given and float addition is not associative. Generation's top-k order and the training router's mask order would otherwise differ in the last bit.registry.py,_deps.py: the per-precision kernel registry (module-import guarded, so Megatron imports on builds withoutflashinfer.moe_ep) and the install check.weights.py,training_weights.py: the kernel weight layout (gate/up interleaved in blocks of 32, K-major transpose), and, formxfp8, quantization through FlashInfer's ownmxfp8_quantize_per_block_32and swizzle, so the bytes match what FlashInfer'spreprocess_mega_weightsproduces.InferenceGroupedMLP(experts.py):_mega_forward, and a caller-owned kernel-weight buffer forbf16andmxfp8. FlashInfer's own preprocessing snapshots the weights at construction, so a refit would not reach the kernel. Owning the buffer lets a refit rewrite it in place, with no teardown, EP collective or recompile.resharding/refit.py: the refit callsrefresh_mega_weights()on every module that defines it, not only under an MXFP8 transform, because the megakernel keeps a transformed copy under every precision, bf16 included. The refit's final synchronize is scoped to the current stream.MegaLocalPassthroughDispatcher(token_dispatcher_inference.py): the megakernel owns EP transport, so every dispatch stage is a pass-through.DynamicInferenceContextskips the NCCL/NVLS per-step buffers for this backend.TransformerConfig:inference_mega_precisionandinference_mega_max_tokens_per_rank, with construction-time checks that reject what the kernels cannot run: SwiGLU only (no squared-ReLU or other non-gated activations), no tanh-clamped activation, per-precisionhidden_size/moe_ffn_hidden_sizealignment, experts divisible by EP, no latent MoE, no Megatron-side MXFP8 expert weights. The backend composes withbatch_invariant_modeand is exempt from that mode's NVLS requirement, because the megakernel does not use the NVLS dispatcher.pyproject.toml:flashinfer-pythonadmitted up to<0.8.0(flashinfer.moe_epships in 0.7.x).2. Mega backend for the training value pass
InferenceGroupedMLP._mega_training_forward_passis theflashinfer_megaentry of the base PR's_inference_training_forward_pass. The kernel's weight layout is a permutation of the parameters, not a view, so unlike thevllm/torchBF16 path the layout cannot alias the parameters. It is repacked into a scratch buffer on every forward, so the kernel always reads the weights the optimizer last wrote.moe_inference_training_forwardacceptsflashinfer_mega, restricted tobf16andmxfp8.MoELayerselects the pass-through dispatcher for the value pass, so it never allocates the NVLS symmetric heap.Tests
tests/unit_tests/inference/test_flashinfer_mega_moe.py: config validation (backend, alignment, SwiGLU-only, tanh clamp, EP divisibility, precisions), the mega-specific restrictions onmoe_inference_training_forward, and a smoke forward.tests/unit_tests/inference/test_mega_training_weights.py: the kernel-layout packers against FlashInfer's ownpreprocess_mega_weights, byte for byte, forbf16andmxfp8; the shared scratch (stale-owner and mixed-geometry rejection); the MXFP8 requantization follows parameter updates.tests/unit_tests/inference/test_mega_training_forward.py(distributed, Blackwell, needs FlashInfermoe_ep):TestValuePassRuns: fwd+bwd runs; the value pass reaches the megakernel exactly once; the same undereval().TestTrainGenParity: bitwise train/generation parity forbf16andmxfp8, in train and eval mode, and after a weight update.TestTokenCountParity: under batch-invariant mode, a token's output does not depend on how many tokens shared the launch (generation wide vs chunked, and training wide vs generation chunked).TestKernelDeterminism: repeated launches return identical bits.TestAgainstStandardBf16: forward and gradients stay within tolerance of the TE bf16 path.TestGenerationWeightOwnership: the owned repack equals FlashInfer's own preprocessing; a refit withoutrefresh_mega_weights()is stale (negative control) and with it equals a freshly built layer;refitcan find the hook; per-layer buffers are independent; unowned precisions refuse a refresh.TestWholeTransformerLayer: the MoE layer inside a fullTransformerLayertakes the megakernel and gives matching train/eval forwards.tests/unit_tests/determinism/kernels/):test_mega_value_pass_replays(bf16, mxfp8; fwd+bwd with the shared-scratch repack under racing-stream contention); manifest notes updated formoe_expertsandmoe_token_dispatchers.Test results: <FILL IN: unit + determinism results on Blackwell from the container (EP = world size), and the CI run link>
End-to-end validation: NeMo-RL GRPO
Tested on the RL side with both mega precisions:
bf16mega andmxfp8mega GRPO runs (training forward on the megakernel, generation on the megakernel) match the originalbf16path (<FILL IN: what the original bf16 path is, e.g. the zero-KL BF16 baseline from Batch-invariance generation with vLLM fused-MoE backend at improved performance #6521, withvllm/TE experts>).<FILL IN: model, cluster and parallelism (e.g. nodes x GPUs, EP, TP, colocated or not), number of steps, batch/sequence sizes, which metrics were compared and the observed numbers, job IDs / W&B links>
<FILL IN: figures, e.g.
Generation KL Errorand reward vs step for original bf16 / mega bf16 / mega mxfp8, with the axes labeled>Scope and known limits
flashinfer_megais a newinference_grouped_gemm_backendvalue, andmoe_inference_training_forwardstays off by default.bf16andmxfp8only.nvfp4andfp8_fp4generation still lets FlashInfer preprocess and snapshot the weights, sorefresh_mega_weights()raisesNotImplementedErrorfor them instead of serving pre-refit weights silently.flashinfer-python>= 0.7 withflashinfer.moe_ep. On other builds the backend raises a clearRuntimeErrorat construction, and the rest of Megatron imports unchanged.uv.lockrecords the oldflashinfer-pythonspecifier: <FILL IN: refreshed in the container withuv lock, or left to the CI lockfile job>.Issue tracking
Linked issue: none. This is a feature PR from an NVIDIA contributor; the design and the related work are tracked in the PRs below.
Related PRs
moe_inference_training_forward(value pass on the inference kernel, TE recompute backward) withvllm/torchbackendsflashinfer_megabackend.main; the MXFP8 mega generation is checked against batch invariance in the same way.Contribution process
Pre-checks
jit_fuser/torch.compile, CUDA extension, TE or external-library dispatch, or a scatter/index accumulation), I have added or updated its bit-exact determinism test and registered it intests/unit_tests/determinism/kernels/manifest.py