Skip to content

Commit fff3669

Browse files
committed
Merge remote-tracking branch 'origin/main' into codex/pr5479-hybrid-model
Signed-off-by: yaoyu-33 <yaoyu.094@gmail.com> # Conflicts: # src/megatron/bridge/training/model_load_save.py # tests/unit_tests/training/test_checkpointing.py
2 parents a80ab57 + b6f31d6 commit fff3669

68 files changed

Lines changed: 3340 additions & 433 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.dev.commit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
b3b1e2d793c596c2fa61076d001ab93f294e4e87
1+
2f2f8ebaef90f4d62a18a43808398223b1fc5809

.github/scripts/test_docker_dependency_layers.sh

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -252,9 +252,18 @@ if ! grep -Fq \
252252
echo "Bridge's lock metadata must preserve the MCore TE extra" >&2
253253
exit 1
254254
fi
255-
if grep -q 'transformer-engine @ git+https://github.com/NVIDIA/TransformerEngine.git@' pyproject.toml || \
256-
grep -q '^name = "transformer-engine"$' pyproject.toml; then
257-
echo "Bridge must inherit the TransformerEngine source and metadata from the selected MCore ref" >&2
255+
if grep -q 'transformer-engine @ git+https://github.com/NVIDIA/TransformerEngine.git@' pyproject.toml; then
256+
echo "Bridge must inherit the TransformerEngine source from the selected MCore ref" >&2
257+
exit 1
258+
fi
259+
260+
if ! grep -Fq ' NVTE_SKIP_SUBMODULE_CHECKS_DURING_BUILD=1 \' "$dockerfile"; then
261+
echo "CI builds must disable TransformerEngine's recursive build-time submodule fetch" >&2
262+
exit 1
263+
fi
264+
if grep -R -qE 'git submodule update.*--recursive|git submodule update --init --recursive' \
265+
"$dockerfile" docker .github/actions; then
266+
echo "CI build surfaces must not fetch recursive submodules at build time" >&2
258267
exit 1
259268
fi
260269

.main.commit

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2a75ac12c54ba6a42b34024756820bf819a2e25f
1+
731b791469004f8fdcb896e65d610d6b1b0ebb32

3rdparty/Megatron-LM

Submodule Megatron-LM updated 320 files

docker/Dockerfile.ci

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ ENV PATH="/opt/venv/bin:/usr/local/bin:$PATH" \
5555
UV_VERSION="0.7.2" \
5656
UV_HTTP_TIMEOUT=120 \
5757
NVTE_BUILD_NUM_PHILOX_ROUNDS=3 \
58+
NVTE_SKIP_SUBMODULE_CHECKS_DURING_BUILD=1 \
5859
HYBRID_EP_MULTINODE=1 \
5960
RDMA_CORE_HOME=/opt/rdma-core/build \
6061
LD_LIBRARY_PATH="/usr/local/cuda/lib64/:$LD_LIBRARY_PATH"
@@ -192,7 +193,7 @@ COPY --chown=1000:1000 . /opt/Megatron-Bridge
192193
# prepared environment, and uses /nemo_run for runtime outputs. Keep those paths owned by the
193194
# existing unprivileged base-image user instead of relying on a root final user.
194195
RUN install -d -o 1000 -g 1000 -m 0755 /nemo_run /home/ubuntu/.cache && \
195-
chown 1000:1000 /opt/Megatron-Bridge
196+
chown -R 1000:1000 /opt/Megatron-Bridge
196197

197198
ENV HOME=/home/ubuntu
198199
USER 1000:1000

docs/training/packed-sequences.md

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ enablement through context parallelism:
2222
| Path | Use case | Key config |
2323
|---|---|---|
2424
| Offline packed SFT | Text-only finetuning | `enable_offline_packing=True` plus `offline_packing_specs` |
25-
| Direct-HF/VLM in-batch packing | Direct Hugging Face and supported VLM finetuning | `enable_in_batch_packing=True` |
25+
| Runtime in-batch packing | GPT-SFT JSONL, Direct Hugging Face, and supported VLM finetuning | `enable_in_batch_packing=True` |
2626
| Energon online packing | Qwen-VL data using the model-owned Energon collator | `packing_buffer_size=<candidate samples per worker>` |
2727
| Long-context (CP) | Pretrain / finetune at 16K-128K+ | `context_parallel_size > 1` |
2828

2929
These are related but they are not the same knob. Offline packed SFT and
30-
Direct-HF/VLM in-batch packing solve padding waste; long-context training
30+
runtime in-batch packing solve padding waste; long-context training
3131
primarily addresses activation memory and communication tradeoffs at larger
3232
sequence lengths.
3333

@@ -40,6 +40,15 @@ non-packed padding remains in `megatron.bridge.data.collators`. Use
4040
`scripts/training/prepare_gpt_sft_packed_data.py` when packed GPT SFT artifacts
4141
should be prepared before launching training.
4242

43+
For `GPTSFTDatasetConfig`, in-batch packing works with both local mmap JSONL
44+
schemas: prompt/completion (`GPTSFTDataset`) and chat
45+
(`GPTSFTChatDataset`). Tokenization remains lazy: workers mmap the JSONL and
46+
read, parse, and tokenize only the rows selected for the current logical
47+
microbatch. Collation then concatenates those rows into one physical THD batch
48+
row; it does not materialize an offline dataset or load the full source into
49+
RAM. Use a microbatch-yielding `single` or `cyclic` dataloader; GPT-SFT
50+
in-batch packing does not support the global-batch `batch` dataloader.
51+
4352
## When to Use It
4453

4554
Packed sequences are a good fit when all of the following are true:
@@ -103,13 +112,34 @@ when using CUDA graphs. CUDA graphs additionally require
103112
`pad_cu_seqlens=true` and packing metadata. Ordinary eager offline packing
104113
does not universally require fixed-width padding.
105114

115+
## Choosing Runtime In-Batch Packing
116+
117+
Use GPT-SFT in-batch packing when retaining the original JSONL is preferable
118+
to generating packed Parquet artifacts. Enable it directly on the dataset
119+
config and use a logical micro-batch larger than one:
120+
121+
```text
122+
dataset.enable_in_batch_packing=true
123+
dataset.dataloader_type=single
124+
train.micro_batch_size=4
125+
```
126+
127+
The collator preserves each sample's prompt/completion or chat loss mask and
128+
emits current MCore packed metadata (`cu_seqlens_q`, `cu_seqlens_kv`, and the
129+
corresponding padded boundaries when CP/SP alignment is required). The model
130+
sees one physical THD row. `enable_in_batch_packing` and
131+
`enable_offline_packing` are mutually exclusive. The `batch` dataloader is not
132+
supported for GPT-SFT in-batch packing; use `single` or `cyclic`.
133+
106134
## Stable Constraints
107135

108136
The durable constraints for packed sequences in Bridge are:
109137

110138
- offline packed SFT requires configured `micro_batch_size == 1`
111-
- Direct-HF/VLM in-batch packing requires configured `micro_batch_size > 1`;
139+
- GPT-SFT/Direct-HF/VLM in-batch packing requires configured `micro_batch_size > 1`;
112140
collation flattens those input rows into one physical THD batch row
141+
- GPT-SFT in-batch packing requires `dataloader_type="single"` or `"cyclic"`;
142+
the global-batch `"batch"` dataloader is not supported
113143
- Energon online packing currently supports the eager Qwen-VL collator path,
114144
requires physical `micro_batch_size == 1`, the generic `vlm_step`, per-token loss, and
115145
`ddp.average_in_collective=False`
@@ -130,7 +160,7 @@ The durable constraints for packed sequences in Bridge are:
130160
overlap is disabled with a warning so training uses the non-overlapped path
131161
- when context parallelism is used, sequence length must satisfy the standard
132162
CP divisibility constraints
133-
- Direct-HF sequence length must also satisfy the LCM of the training and
163+
- GPT-SFT and Direct-HF sequence length must also satisfy the LCM of the training and
134164
evaluation CP constraints and `CP * TP` when sequence parallelism is enabled
135165
- for fine-tuning with CP enabled, per-token loss behavior and reduction
136166
settings matter

examples/conversion/compare_hf_and_megatron/compare.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ def __init__(
279279
pixel_values=None,
280280
image_grid_thw=None,
281281
inference_context=None,
282+
mm_token_type_ids=None,
282283
):
283284
self.batch = dict(
284285
tokens=input_ids,
@@ -292,6 +293,8 @@ def __init__(
292293
self.batch["pixel_values"] = pixel_values
293294
if image_grid_thw is not None:
294295
self.batch["image_grid_thw"] = image_grid_thw
296+
if mm_token_type_ids is not None:
297+
self.batch["mm_token_type_ids"] = mm_token_type_ids
295298

296299
self._yielded = False
297300

@@ -332,6 +335,8 @@ def vlm_forward_step(data_iterator, model, **kwargs) -> torch.Tensor:
332335
forward_args["pixel_values"] = batch["pixel_values"]
333336
if "image_grid_thw" in batch:
334337
forward_args["image_grid_thw"] = batch["image_grid_thw"]
338+
if "mm_token_type_ids" in batch:
339+
forward_args["mm_token_type_ids"] = batch["mm_token_type_ids"]
335340

336341
def loss_func(x, **kwargs):
337342
return x
@@ -441,7 +446,8 @@ def process_inputs(tokenizer, processor, image_path: Optional[str], prompt: str,
441446
tp_size: Tensor parallel size for padding sequence length
442447
443448
Returns:
444-
Tuple of (input_ids, pixel_values, image_grid_thw, token_type_ids)
449+
Tuple of (input_ids, pixel_values, image_grid_thw, token_type_ids,
450+
mm_token_type_ids)
445451
"""
446452
if is_vl_model and image_path:
447453
messages = [
@@ -465,11 +471,15 @@ def process_inputs(tokenizer, processor, image_path: Optional[str], prompt: str,
465471
token_type_ids = inputs.get("token_type_ids")
466472
if token_type_ids is not None:
467473
token_type_ids = pad_input_ids_to_tp_multiple(token_type_ids, tp_size, 0)
474+
mm_token_type_ids = inputs.get("mm_token_type_ids")
475+
if mm_token_type_ids is not None:
476+
mm_token_type_ids = pad_input_ids_to_tp_multiple(mm_token_type_ids, tp_size, 0)
468477
return (
469478
input_ids,
470479
inputs.get("pixel_values"),
471480
inputs.get("image_grid_thw"),
472481
token_type_ids,
482+
mm_token_type_ids,
473483
)
474484
else:
475485
# Text-only processing for both VL models without images and regular LLMs
@@ -480,7 +490,7 @@ def process_inputs(tokenizer, processor, image_path: Optional[str], prompt: str,
480490
# Use tokenizer for regular LLMs
481491
inputs = tokenizer(prompt, return_tensors="pt")
482492
input_ids = pad_input_ids_to_tp_multiple(inputs.input_ids, tp_size, tokenizer.pad_token_id or 0)
483-
return input_ids, None, None, None
493+
return input_ids, None, None, None, None
484494

485495

486496
def _load_hf_model(args, is_vl_model: bool):
@@ -573,7 +583,16 @@ def _get_hf_forward_model(hf_model, pixel_values):
573583
return hf_model
574584

575585

576-
def _run_hf_inference(hf_model, input_ids, pixel_values, image_grid_thw, tokenizer, *, token_type_ids=None):
586+
def _run_hf_inference(
587+
hf_model,
588+
input_ids,
589+
pixel_values,
590+
image_grid_thw,
591+
tokenizer,
592+
*,
593+
token_type_ids=None,
594+
mm_token_type_ids=None,
595+
):
577596
"""Run HuggingFace model inference and return results.
578597
579598
Args:
@@ -582,7 +601,8 @@ def _run_hf_inference(hf_model, input_ids, pixel_values, image_grid_thw, tokeniz
582601
pixel_values: Pixel values for vision models (optional).
583602
image_grid_thw: Image grid dimensions (optional).
584603
tokenizer: Tokenizer for decoding.
585-
token_type_ids: Multimodal token type IDs (optional).
604+
token_type_ids: Legacy multimodal token type IDs (optional).
605+
mm_token_type_ids: Multimodal token type IDs used for M-RoPE (optional).
586606
587607
Returns:
588608
Tuple of (hf_logits, hf_next_token, hf_logits_stats, hf_top5_info, logits_shape).
@@ -613,6 +633,8 @@ def _run_hf_inference(hf_model, input_ids, pixel_values, image_grid_thw, tokeniz
613633
hf_inputs["image_grid_thw"] = image_grid_thw.to(hf_device)
614634
if token_type_ids is not None:
615635
hf_inputs["token_type_ids"] = token_type_ids.to(hf_device)
636+
if mm_token_type_ids is not None:
637+
hf_inputs["mm_token_type_ids"] = mm_token_type_ids.to(hf_device)
616638

617639
hf_output = hf_forward_model(**hf_inputs)
618640

@@ -875,7 +897,7 @@ def compare_models_one_step(args) -> None:
875897

876898
# Process inputs
877899
print_rank_0(f"Processing inputs - Prompt: '{args.prompt}', Image: {args.image_path}")
878-
input_ids, pixel_values, image_grid_thw, token_type_ids = process_inputs(
900+
input_ids, pixel_values, image_grid_thw, token_type_ids, mm_token_type_ids = process_inputs(
879901
tokenizer, processor, args.image_path, args.prompt, is_vl_model, args.tp
880902
)
881903

@@ -887,6 +909,8 @@ def compare_models_one_step(args) -> None:
887909
image_grid_thw = image_grid_thw.cuda()
888910
if token_type_ids is not None:
889911
token_type_ids = token_type_ids.cuda()
912+
if mm_token_type_ids is not None:
913+
mm_token_type_ids = mm_token_type_ids.cuda()
890914

891915
print_rank_0(f"Input shape: {input_ids.shape}")
892916
print_rank_0(f"Pixel values shape: {pixel_values.shape if pixel_values is not None else 'None'}")
@@ -904,6 +928,7 @@ def compare_models_one_step(args) -> None:
904928
image_grid_thw,
905929
tokenizer,
906930
token_type_ids=token_type_ids,
931+
mm_token_type_ids=mm_token_type_ids,
907932
)
908933

909934
del hf_model
@@ -949,6 +974,7 @@ def compare_models_one_step(args) -> None:
949974
attention_mask,
950975
pixel_values,
951976
image_grid_thw,
977+
mm_token_type_ids=mm_token_type_ids,
952978
)
953979
megatron_output = fwd_bwd_function(
954980
forward_step_func=vlm_forward_step,

0 commit comments

Comments
 (0)