Repository navigation
feat(megatron): zero train-gen mismatch with non-colocated Megatron inference - #3208
Conversation
|
@YigongQin can you elaborate more on this MR ? maybe attach some sample runs that you did , how the performance changes etc. |
02f811b to
8db6804
Compare
5fa42ec to
7589e71
Compare
|
zero mismatch between training and rollouts is important feature for RL debugging, please submit for review |
|
There are lots of patches do you think we can minimize these and only keep the ones are really necessary? Otherwise it would be really hard to maintain in the long run. Plus non-patch global mutations: RouterReplay.global_router_replay_instances (rebuild), metadata.routing_indices_buffer = None, cg_utils.cuda_graph_attr_cache.pop(), and three env vars (CUBLAS_WORKSPACE_CONFIG=:0:0, CUBLASLT_WORKSPACE_SIZE=0, MAMBA_DETERMINISTIC=1). Grouped by goal:
Three observations that fall out of the table: 3 of 14 patch NeMo-RL's own code (2, 11, 12), which should be plain hooks or edits; #14 is unrelated to zero-KL and belongs in its own PR; and only 3, 4, 5 are genuinely novel — the rest is scaffolding around them. |
ZhiyuLi-Nvidia
left a comment
There was a problem hiding this comment.
Zero-KL config is validated and built inside workers after GPU allocation; suggest building + validating once in setup() before the cluster.
ZhiyuLi-Nvidia
left a comment
There was a problem hiding this comment.
flash-attn-4 in the mcore extra switches default TE flash attention to FA4; suggest pinning flash_attention_version: 2 in base configs and 4 only in the zero-KL recipe.
ZhiyuLi-Nvidia
left a comment
There was a problem hiding this comment.
Batch-invariant mode silently ignores temperature/top_p/top_k; suggest validating sampling config instead of overwriting.
Signed-off-by: YigongQin <yigongq@nvidia.com>
Signed-off-by: YigongQin <yigongq@nvidia.com>
Signed-off-by: YigongQin <yigongq@nvidia.com>
Signed-off-by: YigongQin <yigongq@nvidia.com>
|
/ok to test 9877780 |
|
/ok to test 72d1b84 |
ZhiyuLi-Nvidia
left a comment
There was a problem hiding this comment.
Thank you @YigongQin. LGTM!
Signed-off-by: YigongQin <yigongq@nvidia.com>
|
/ok to test b6bd602 |
|
/ok to test de3330e |
What does this PR do ?
Add
policy.megatron_cfg.zero_train_gen_mismatch: a gate that validates, and then enables, a configuration that puts Megatron training and Megatron Inference (M-Inf) generation on the same batch-invariant kernel stack, so that in a synchronous (on-policy) GRPO loop the generation logprobs and the training-side logprobs of the same tokens are bitwise identical (train/gen_kl_error == 0,train/token_mult_prob_error == 1).The recipe sets every required value; the module only checks them (one
ValueErrorlists every violation) and switches the MCore batch-invariant kernels on at worker init.Scope of this PR: BF16, Blackwell, TP=1/CP=1, non-colocated Megatron generation (
inference_optimized). See "Support status" for exactly what is and is not covered.Issues
Support status
inference_optimized, CUDA graphs on). 5 GRPO steps:train/gen_kl_errorexactly 0 andtrain/token_mult_prob_errorexactly 1 at every step (W&B).megatron_cfg:batch_invariant_mode=true,batch_invariant_backend=te_native,batch_invariant_collective=ordered,attention_backend=flash,flash_attention_version=4,moe_permute_fusion=false,env_varsCUBLASLT_WORKSPACE_SIZE=0andCUBLAS_WORKSPACE_CONFIG=:0:0. Generation:backend=megatron, mergedtransformer_impl=inference_optimized,logprobs_mode=raw_logprobs,enable_chunked_prefill=false, andtemperature=1.0,top_p=1.0,top_k=null(raw logprobs are scored).policy.precision=bfloat16and no FP8 on either side;tensor_model_parallel_size=1andcontext_parallel_size=1;sequence_packingoff;use_fused_linear_logprobsoff;make_sequence_length_divisible_by(anddynamic_batching.sequence_length_roundwhen enabled) a multiple of MCore's batch-invariant token multiple; train and generation agree on TP/CP and allbatch_invariant_*,attention_backend,flash_attention_versionfields. The resolved model provider must not be MLA, an experimental attention variant, or an SSM/Mamba hybrid. The driver runs the config-only checks; workers also check packages and the GPU.batch_invariant_*/flash_attention_versionconfig fields,transformer_engine>=2.18,flash_attn>=2.8.1,flash-attn-4(pinned4.0.0b19),nvidia-cutlass-dsl>=4.6.0.dev0.transformer_impl=transformer_enginegeneration. Hopper / FA3. Dense models and other MoE models have not been run.gen_kl_errorcompares generation logprobs with the trainer's current-weights logprobs, so policy lag shows up as KL even with bit-exact kernels. Use the synchronous loop.What changed
nemo_rl/models/megatron/zero_train_gen_mismatch.py(new):validate_zero_train_gen_kl(config, *, check_environment)validates the train + generation configs (plusvalidate_batch_invariant_modefor the batch-invariant requirements, andvalidate_zero_train_gen_model_providerfor the resolved architecture), andenable_batch_invariant_kernelsturns the MCore kernels on and lets an installedflash-attn-4below MCore's version gate be used (the pinned b19 vs MCore's>=b20flag).nemo_rl/models/megatron/setup.py:enable_batch_invariant_mode()(validate withcheck_environment=True, then enable the kernels), the provider check, and plumbing of the batch-invariant fields onto the MCore model config.flash_attention_versiondefaults to 2 when unset.nemo_rl/distributed/model_utils.py: when the TP group has a single rank, scoring uses the same fusedlog_softmaxas Megatron Inference instead of the distributed max/exp/sum/log decomposition (mathematically equal, not bitwise equal). This closes the log-softmax gap between train and generation for TP=1.nemo_rl/models/megatron/batch_invariant.py+nemo_rl/models/policy/lm_policy.py: align the eager scoring token count with MCore's batch-invariant token rounding so TE kernels see the same shape class as generation buckets. The cuBLAS workspace variables are required in the recipe'senv_varsand checked by the validator.nemo_rl/models/generation/megatron/megatron_worker.py: raw logprobs under batch-invariant mode and no fused RoPE.nemo_rl/models/policy/__init__.py,generation/megatron/config.py: new config fields (batch_invariant_*,flash_attention_version,zero_train_gen_mismatch, generationtransformer_impl/logprobs_mode).grpo_math_1B,ppo_math_1B,sft,dpo,distillation_math,vlm_mpo) and their reference configs pinflash_attention_version: 2:flash-attn-4is now installed, so TE would otherwise pick FA4. Zero-KL recipes set 4 explicitly.pyproject.toml/uv.lock:flash-attn-4==4.0.0b19(b20+ needapache-tvm-ffi>=0.1.12, but the shared override keeps 0.1.11).examples/configs/recipes/llm/grpo-qwen3-30ba3b-2n4g-megatron_generation-noncolocated-zero-kl.yamland GB200 nightly testtests/test_suites/llm/grpo-qwen3-30ba3b-2n4g-megatron_generation-noncolocated-zero-kl.sh(listed innightly_gb200.txt).Usage
Use the recipe above as the template: it sets every required value. The switch and the main settings:
Run the nightly test with
tools/launch tests/test_suites/llm/grpo-qwen3-30ba3b-2n4g-megatron_generation-noncolocated-zero-kl.sh(needs a worker environment that hasflash-attn-4).Validation
[zero_train_gen_mismatch] batch-invariant kernels enabled: backend=te_native collective=ordered flash_attention_version=4), finite loss / grad norm,min == max == 0fortrain/gen_kl_errorandmin == max == 1fortrain/token_mult_prob_error. Passing run: Qwen3-30B-A3B, 2 nodes x 4 GB200, 5 steps, 32 valid samples per step, all checks exact.tests/unit/models/megatron/test_zero_train_gen_mismatch.py(resolver and validator, including that the shipped recipe validates, that the driver check does not touch the GPU, and that TP>1 / packing / FP8 / Hopper are rejected). CI passes.Known issues / follow-ups
gen_kl_error0.35 / 0.42,token_mult_prob_error~1e15) while the rest stayed exact. Root cause not identified; leading suspect is the colocated refit / sleep-wake path (MCoreswap_model_weightsand the persisted inference state), not the kernels. The recipe is not shipped here. (Colocated on one node also needs the optimizer kept on the GPU to avoid a host-RAM OOM.)Before your PR is "Ready for review"
Pre checks:
Additional Information