Repository navigation
feat(data): intra-microbatch reordering for MegatronMIMO scalable reads #6306
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
cuichenx
merged 13 commits into
NVIDIA-NeMo:main
from
going-song:feat/megatron-mimo-intra-microbatch-reorder
Oct 10, 2026
Merged
Changes from all commits
Commits
Show all changes
13 commits
Select commit
Hold shift + click to select a range
ce55b79
feat(data): intra-microbatch reordering for MegatronMIMO scalable reads
going-song 4e2de5c
fix(data): reject intra-microbatch reorder with pad_to_seq_length=Fal…
going-song 4058f1b
refactor(data): name the serialization byte alignment; trim reorder c…
going-song 67d27f9
docs(training): add MegatronMIMO intra-microbatch reordering page
going-song 0477a8d
fix(training): unblock MegatronMIMO Qwen3.5 training on current MCore
going-song 4a241bb
fix(data): refuse intra-microbatch reorder overlap under CUDA_DEVICE_…
going-song aeab43d
refactor(data): trim MegatronMIMO reorder docstrings and comments
going-song 5cb4faa
fix(data): ship input_ids and attention_mask to MIMO ranks only when …
going-song 329a5e4
fix(training): read cuda_graph_warmup_steps with getattr in the memor…
going-song 94bc3e9
refactor(training): drop the reorder shutdown hook from the MegatronM…
going-song d2d23ac
docs(training): add metric expectations and validation patterns to th…
going-song da5b14e
test(data): cover real_token_lengths and the overlapped reorder exchange
going-song c55ce2c
docs(training): correct test coverage and validation statements on th…
going-song File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,168 @@ | ||
| # MegatronMIMO Intra-Microbatch Reordering | ||
|
|
||
| Intra-microbatch reordering rebalances the per-sample vision load of each | ||
| micro-batch across a module's data-parallel ranks in non-colocated | ||
| MegatronMIMO training. It removes the straggler that appears when one | ||
| data-parallel rank happens to draw the heaviest images every step. | ||
|
|
||
| This page is the stable overview of what the feature does, how to enable it, | ||
| and which constraints are durable. The implementation lives in | ||
| `megatron.bridge.data.megatron_mimo.reorder_buffer`; the Qwen3.5-VL example | ||
| under `examples/megatron_mimo/qwen35_vl/` wires it end to end. | ||
|
|
||
| ## What It Is | ||
|
|
||
| In a non-colocated MegatronMIMO run the vision encoder and the language model | ||
| run on disjoint rank groups, each with its own data-parallel size. With | ||
| scalable data parallelism (`megatron_mimo_scalable_dp`), every rank reads only | ||
| its own shard of each global micro-batch, so the images a rank must encode are | ||
| whatever the sampler happened to assign to it. Image sizes vary widely, so the | ||
| per-rank vision work varies too, and the slowest rank gates every step. | ||
|
|
||
| The reorder buffer wraps the training data iterator and, for each micro-batch | ||
| (or window of micro-batches), does three things: | ||
|
|
||
| 1. Computes a per-sample cost on every rank from fields that are identical on | ||
| the vision and language modules: the image-placeholder token count in | ||
| `input_ids` (proportional to the number of vision patches) and, optionally, | ||
| the real token count from `attention_mask`. | ||
| 2. All-gathers the costs over the module's data-parallel group and computes one | ||
| balanced assignment of samples to ranks. The assignment is a deterministic | ||
| function of the costs, so the vision and language modules compute the same | ||
| one without talking to each other. | ||
| 3. Exchanges samples with a single ragged `all_to_all` so each rank ends up | ||
| holding its assigned samples in a canonical order. | ||
|
|
||
| Because both modules apply the same assignment, sample *i* on vision replica | ||
| *r* is still sample *i* on language replica *r*, and the `BridgeCommunicator` | ||
| fan-out stays aligned. Balancing is done over the canonical grid (the least | ||
| common multiple of the module data-parallel sizes), so modules with different | ||
| data-parallel sizes, including a module with data-parallel size 1, agree on | ||
| the same order. A data-parallel-1 module has nothing to exchange and simply | ||
| permutes its whole micro-batch locally; that permutation runs synchronously on | ||
| the training thread (about 14 ms per micro-batch of 4 samples on A100) because | ||
| there is no exchange to overlap. | ||
|
|
||
| By default the exchange for the next window runs on a background thread with a | ||
| dedicated NCCL process group, overlapping with the current window's compute. | ||
|
|
||
| ## When to Use It | ||
|
|
||
| Reordering is a good fit when all of the following are true: | ||
|
|
||
| - the run is non-colocated MegatronMIMO with `megatron_mimo_scalable_dp=True` | ||
| - at least one module has data-parallel size 2 or more | ||
| - image load varies across samples (document, receipt, or mixed text-and-image | ||
| SFT data), so per-rank vision time is the per-step straggler | ||
|
|
||
| It does not help text-only training, colocated single-module runs, or data | ||
| where every sample carries the same number of similarly sized images. | ||
|
|
||
| ## Bridge Configuration | ||
|
|
||
| All fields live on `DirectHFSFTDatasetConfig` and default to off. | ||
|
|
||
| | Field | Default | Meaning | | ||
| |---|---|---| | ||
| | `megatron_mimo_scalable_dp` | `False` | Read only this rank's canonical-grid shard. Required by reordering. | | ||
| | `megatron_mimo_intra_microbatch_reorder` | `False` | Enable the reorder buffer. | | ||
| | `megatron_mimo_reorder_encoder_cost_weight` | `1.0` | Cost weight per vision patch. | | ||
| | `megatron_mimo_reorder_language_cost_weight` | `0.0` | Cost weight per real language token; `0.0` balances on vision load only. | | ||
| | `megatron_mimo_reorder_overlap` | `True` | Exchange the next window on a background thread. | | ||
| | `megatron_mimo_reorder_window_size` | `1` | Micro-batches balanced together in one exchange. | | ||
|
|
||
| Only the ratio of the two cost weights matters; at least one must be positive. | ||
|
|
||
| The Qwen3.5-VL example exposes the same fields as `--scalable-dp`, | ||
| `--intra-microbatch-reorder`, `--reorder-encoder-cost-weight`, | ||
| `--reorder-language-cost-weight`, `--no-overlap-intra-microbatch-reorder`, and | ||
| `--reorder-window-size`: | ||
|
|
||
| ```bash | ||
| python examples/megatron_mimo/qwen35_vl/finetune_qwen35_vl.py \ | ||
| --component "language=tp=1,pp=1,dp=2,rank_offset=0" \ | ||
| --component "images=tp=1,dp=2,rank_offset=2" \ | ||
| --scalable-dp --intra-microbatch-reorder \ | ||
| ... | ||
| ``` | ||
|
|
||
| Overlap is refused under `CUDA_DEVICE_MAX_CONNECTIONS=1`: with a single | ||
| hardware queue the prefetch thread's all-to-all and the DDP all-reduce execute | ||
| in issue order, that order differs across ranks, and training deadlocks | ||
| (reproduced on a 4-rank run and on a 6-rank TP=2 run). Use | ||
| `--no-overlap-intra-microbatch-reorder` in that case; it issues both | ||
| collectives from the training thread and completed 1500 iterations under the | ||
| same setting. Megatron Bridge does not require the variable for tensor | ||
| parallelism; it is a Megatron-LM sequence-parallel performance setting, so TP | ||
| users choose between that setting with the non-overlapped reorder, or overlap | ||
| with the variable unset. | ||
|
|
||
| ## Stable Constraints | ||
|
|
||
| | Configuration | Status | | ||
| |---|---| | ||
| | Heterogeneous module data parallelism (for example vision dp 1 or 2 with language dp 2 or 4) | Supported. Balancing uses the canonical grid; a dp-1 module reorders locally. The encoder data-parallel size must not exceed the language data-parallel size: Megatron Core's bridge fan-in with variable per-sample image-token counts is not implemented and asserts on the first forward step. | | ||
| | Language pipeline parallelism > 1 | Supported. Every language stage receives `input_ids` so all stages compute the same assignment. | | ||
| | Encoder pipeline parallelism > 1 | Not supported; the example raises before training starts. | | ||
| | `--pad-to-seq-length false` (variable batch width) | Not supported with reordering; the example raises before training starts. Exchanged samples are concatenated back into one micro-batch, so all ranks must pad to the same length. | | ||
| | `micro_batch_size` not divisible by the canonical grid size | Rejected by the canonical loader. | | ||
| | `drop_last=False`, or a dataloader type other than `single` / `cyclic` | Rejected by scalable data parallelism. | | ||
| | Expert tensor parallelism > 1 | Rejected by scalable data parallelism. | | ||
| | Tensor parallelism > 1 | Validated (language tp 2 with and without vision tp 2). | | ||
| | Context parallelism > 1 | Untested. | | ||
|
|
||
| A full MIMO run with an exchanging module needs at least three GPUs, which | ||
| exceeds the two-GPU functional-test budget. CI covers the balancing and | ||
| serialization logic with CPU-emulated unit tests, and the real Gloo/NCCL | ||
| exchange, including the overlapped prefetch thread, with a two-rank functional | ||
| test; full MIMO runs are validated manually. | ||
|
|
||
| ## Expected Metric Changes | ||
|
|
||
| | Metric | Expected Change | Conditions | Evidence | | ||
| |---|---|---|---| | ||
| | per-rank vision load spread | down | module data-parallel size 2 or more, varied image sizes | measured | | ||
| | `step_time` | flat to slightly down | every module has data-parallel size 2 or more, overlap on | measured | | ||
| | `step_time` | slightly up | a module has data-parallel size 1 (its local permutation is synchronous) | measured | | ||
| | `step_time` | up | overlap off (`--no-overlap-intra-microbatch-reorder`) | measured | | ||
| | `peak_memory` | up by up to two extra windows of micro-batches per data rank | overlap on; grows with `megatron_mimo_reorder_window_size` | expected | | ||
|
|
||
| Balancing cannot remove the imbalance entirely: every rank keeps the same | ||
| number of samples, so with few samples per rank and a bimodal image-size | ||
| distribution the reachable spread is bounded by the largest single image. | ||
|
|
||
| ## Representative Validation Patterns | ||
|
|
||
| On one 8×A100 node with Qwen3.5-0.8B on cord-v2 (sequence length 2048, | ||
| bf16), language dp 4 with vision dp 4 at micro-batch 8 cut the mean | ||
| max-minus-min image-token spread across vision ranks from `643` to `421` and | ||
| lowered iteration time by about 2% with overlap on. A 3-rank run with vision | ||
| dp 1 was about 5% slower with overlap and 10% slower without, because the dp-1 | ||
| module's permutation is synchronous. In the dp 4 run the per-micro-batch sum | ||
| of image tokens over all vision ranks matched the unreordered run for all 40 | ||
| micro-batches. On language dp 2 + vision dp 2 the reorder off/on pair had | ||
| identical iteration-1 and iteration-2 losses, checkpoint resume reproduced the | ||
| continuous run, and an overlapped run completed 3000 iterations. Under | ||
| `CUDA_DEVICE_MAX_CONNECTIONS=1` without overlap, language tp 2 dp 2 + vision | ||
| dp 2 completed 10000 iterations; language tp 2, pp 2, and tp 2 with vision tp 2 | ||
| each completed 1000 iterations. Treat these as patterns to reproduce on the | ||
| target model and data, not as fixed gains. | ||
|
|
||
| ## Feature Interactions | ||
|
|
||
| - **In-batch sequence packing** (`enable_in_batch_packing`): reordering runs in | ||
| the data iterator, before the forward step packs each language shard, so the | ||
| two compose. Packing drops padding, so the exchange transfers padded rows but | ||
| model compute is unaffected. | ||
| - **Checkpoint resume**: reordering changes which rank holds a sample, not how | ||
| many samples are consumed, so the resume arithmetic of the canonical sampler | ||
| is unchanged. | ||
| - **Cost weights and the language term**: setting | ||
| `megatron_mimo_reorder_language_cost_weight > 0` counts real tokens from | ||
| `attention_mask`; the example ships `attention_mask` on every stage for this | ||
| purpose and the forward step drops it before the model. | ||
|
|
||
| ## Related Docs | ||
|
|
||
| - [Packed Sequences](packed-sequences.md) | ||
| - Example: `examples/megatron_mimo/qwen35_vl/finetune_qwen35_vl.py` |
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
Oops, something went wrong.
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gated on the canonical grid, not this rank's DP size, so dp-1 ranks also enter the collective process-group setup below.