Batch-invariant train/inference logprob parity#5897
Conversation
|
This PR has been automatically converted to draft because all PRs must start as drafts. When you are ready for review, click Ready for Review to begin the review process. This will:
See the contribution guide for more details. |
|
/ok to test de53103 |
de53103 to
0762c9f
Compare
|
/ok to test 0762c9f |
yobibyte
left a comment
There was a problem hiding this comment.
Looks good to me, left some small comments!
0762c9f to
661f235
Compare
Make --batch-invariant-mode produce train-side logprobs that match the dynamic inference engine bitwise, so importance-sampling / off-policy RL sees zero train-vs-inference logprob mismatch. Four fixes: 1. Pin the FlashAttention generation. The training (TransformerEngine) and inference (mcore dynamic-batching) attention paths select a FlashAttention version independently based on what is installed. When they diverge -- e.g. on Blackwell, where inference runs FA4 while TE falls back to FA2 -- their logits differ bitwise past ~48 KV tokens (different tile sizes and softmax accumulation orders). Add a flash_attention_version TransformerConfig field (--flash-attention-version, choices 2/3/4) that pins the generation for both paths: training disables the other versions via TransformerEngine's NVTE_FLASH_ATTN_V2/V3/V4 selection env vars in LanguageModule._set_attention_backend, and inference honors it directly in Attention.flash_decode_and_prefill. Batch-invariant mode now requires --attention-backend flash and --flash-attention-version 3 or 4 (FA2 lacks the fixed num_splits schedule the batch-invariant kernels need). 2. Route TransformerEngine's fused-module normalization through the batch-invariant RMSNorm. TE's fused LayerNormLinear / LayerNormMLP call apply_normalization instead of RMSNorm.forward, bypassing the existing batch-invariant patch; TE's tex RMSNorm kernel changes its within-row reduction with the total row count (observed: identical rows, 1 bf16 ulp different output at 928 vs 2274 rows), which amplifies across depth. The decode CUDA graph pads every step to max_requests (~4548 rows from the KV buffer), so this fired at scale even though small forwards matched. 3. Compare packed inference logprobs in the training dtype. The packed inference-vs-train stats compared bf16 training logprobs against fp32 engine logprobs, showing rounding noise even when both sides were bitwise identical. 4. Only compare engine-reported positions. pack_inference_logprobs zero-filled positions the engine never reported (e.g. the train-side EOD append), each contributing a spurious |p_old - 1| term to the mismatch stats. Return a filled-position mask and restrict the stats to it. Enable the GPT batch-invariance unit tests on FlashAttention-4 (previously skipped without FA3) so they run on Blackwell. Signed-off-by: wdykas <wdykas@nvidia.com>
661f235 to
aacf1bd
Compare
| # which honors config.flash_attention_version directly. | ||
| if self.config.flash_attention_version is not None: | ||
| for version in (2, 3, 4): | ||
| if version != self.config.flash_attention_version: |
There was a problem hiding this comment.
Would it make sense to have the else case explicitly set version = 1? So
else:
check_and_set_env_variable(
f"NVTE_FLASH_ATTN_V{version}", 1, self.config.attention_backend
)
|
/ok to test aacf1bd |
|
🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/29982749312 |
|
🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/29983602174 |
|
🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/29988909160 |
|
🔄 Merge queue validation started! You can track the progress here: https://github.com/NVIDIA/Megatron-LM/actions/runs/30009974612 |
making batch invariance more robust and fixing a few other corner cases
What does this PR do?
Issue tracking
For PRs from open-source community contributors:
Linked issue:
Contribution process
Pre-checks
Code review
Feel free to message or comment @NVIDIA/mcore-oncall to help accelerate your merge into main. The less complex your PR is, the faster it will be approved and merged!
All PRs start as draft. If you open a non-draft PR, it will be automatically converted to draft.
Step 1: Mark PR as "Ready for Review"
.github/CODEOWNERS.Final Review might get declined if these requirements are not fulfilled.
Step 2: Final Review
For PRs that change
megatron/core, once all expert reviewers have approved, theFinal Reviewlabel is applied automatically and final reviewers are assigned.For PRs outside
megatron/core, this step is skipped.Step 3: Approved
Once all required reviewers have approved, the
Approvedlabel is applied automatically.Merge
Any member of mcore-engineers will be able to merge your PR.