Skip to content

Pass one process-group collection through the pretrain loop - #8037

Closed
Connor-XY wants to merge 3 commits into
NVIDIA:mainfrom
Connor-XY:yx/pstate-b2-train-one-collection
Closed

Connor-XY wants to merge 3 commits into
NVIDIA:mainfrom
Connor-XY:yx/pstate-b2-train-one-collection

Conversation

@Connor-XY

@Connor-XY Connor-XY commented Oct 9, 2026 •

Copy link
Copy Markdown
Contributor

Why

pretrain() builds the model on a ProcessGroupCollection, but the rest of the loop used the global grid: standard DDP and Torch FSDP2 got no collection, get_megatron_optimizer read the globals, the schedule was chosen from the global PP/VP sizes and ran on a default collection and communicator built from parallel_state, and the parameter norm got None. A collection passed to pretrain() reached only the model, and --create-all-gather-group did nothing under pretrain().

What

  • Build the collection once after initialize_megatron and pass it to every DDP wrapper (Torch FSDP2 gets its DP x CP group), the optimizer when Gloo groups are off, schedule selection and the schedules (with a P2PCommunicator over its PP group), and the parameter norm.
  • Add the all-gather groups to that collection; reject them if their ranks differ from the data-parallel groups.

Tests

  • New tests/unit_tests/training/test_training_pg_collection.py (8 cases, all fail on main).
  • Integration run (main 77391e7 with all [TRACKING] Deprecate parallel_state: explicit process groups in megatron/core #6307 PRs and the main-based gap fixes merged, against main), 4 GPUs: test_training_pg_collection.py passes all 11 cases it holds there: 6 of this PR's 8, plus 5 added by later [TRACKING] Deprecate parallel_state: explicit process groups in megatron/core #6307 PRs, one of which replaces the two all-gather rank-mismatch cases. main has no such file. In the integration run, this PR's test file shows no regressions against main.
  • Before the sync with main 77391e7, on 4 GPUs, mock data, --deterministic-mode: loss, grad norm, params norm and evaluation loss are bit-identical to main over 12 iterations for TP2 PP2 SP, PP2 VPP2, MoE EP2 PP2, distributed optimizer (PP2; 2 instances), Megatron-FSDP with --create-all-gather-group (dense, MoE) and Torch FSDP2, via both the model-builder and model_provider paths. The schedules' default builder is no longer reached.
  • Before the sync, with GTP-remat 2, every group the schedules and finalize_model_grads read is unchanged.

Compatibility

No API change; train()/evaluate() without a collection behave as before. With Gloo groups (default), the optimizer still builds its groups from parallel_state until the collection carries them.

Synced with main 77391e7 on 2026-11-01 by a merge commit that lists each conflict and its resolution, so existing commits and review links stay valid.

Part of #6307.

🤖 Generated with Claude Code

@Connor-XY

Copy link
Copy Markdown
Contributor Author

/ok to test 614a403

@copy-pr-bot

copy-pr-bot Bot commented Oct 9, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

Connor-XY and others added 2 commits October 26, 2026 11:04
pretrain() built the model on a ProcessGroupCollection, but the rest of
the loop reached Megatron Core's fallbacks to the global grid. Standard
DDP and Torch FSDP2 were wrapped without the collection (only
Megatron-FSDP received it), get_megatron_optimizer read the global
groups, the schedule was selected from the global pipeline sizes and ran
on a default collection and communicator that the schedules build from
parallel_state, and the parameter norm used the train() argument, which
is None in the stock path. A collection passed to pretrain() was
therefore honored only by the model. --create-all-gather-group was also
inert: get_model() created the all-gather groups only when it received
no collection, and pretrain() always passes one.

Build the collection once, right after initialize_megatron, and pass it
to every Megatron Core entry point of the loop: all DDP wrappers (Torch
FSDP2 shards over the collection's DP x CP group), the optimizer when
Gloo groups are off (the collection carries no Gloo groups yet), the
schedule selection and the schedules together with a P2PCommunicator
over the collection's pipeline group, and the parameter norm. The
collection carries the all-gather groups when they are requested, and a
check rejects all-gather groups that do not span the data-parallel
ranks.

On the standard grid every consumer gets the same group objects as
before, so training is bit-identical.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yan Xu <yxu1@nvidia.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yan Xu <yxu1@nvidia.com>
@Connor-XY
Connor-XY force-pushed the yx/pstate-b2-train-one-collection branch from 614a403 to 0c6841b Compare October 26, 2026 22:26
@Connor-XY

Copy link
Copy Markdown
Contributor Author

/ok to test 0c6841b

Connor-XY added a commit to Connor-XY/Megatron-LM that referenced this pull request Nov 1, 2026
The end-to-end seeding test that follows checks that the collection
pretrain builds after initialize_megatron holds the same groups as the
collection the RNG was seeded from. It builds that collection with
training._build_pg_collection_from_parallel_state, the helper that
NVIDIA#8037 adds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yan Xu <yxu1@nvidia.com>
Connor-XY added a commit to Connor-XY/Megatron-LM that referenced this pull request Nov 1, 2026
NVIDIA#8031, NVIDIA#8037 and NVIDIA#8039 each refreshed the allowlist against main.
Merging them keeps the total of 195 that NVIDIA#8031 and NVIDIA#8037 share, since
NVIDIA#8039's total equals main's, while the merged entries record 194 reads.
Regenerate the file so that its total matches its entries. No entry
changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yan Xu <yxu1@nvidia.com>
Connor-XY added a commit to Connor-XY/Megatron-LM that referenced this pull request Nov 1, 2026
The optimizer change follows the one collection that NVIDIA#8037 passes
through pretrain into setup_model_and_optimizer, and its test extends
NVIDIA#8037's training collection test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yan Xu <yxu1@nvidia.com>
Connor-XY added a commit to Connor-XY/Megatron-LM that referenced this pull request Nov 1, 2026
NVIDIA#8738 passes the training collection to the optimizer with Gloo groups
on, on top of NVIDIA#6259, NVIDIA#8037 and NVIDIA#8055 (which carries NVIDIA#8049 and NVIDIA#6293).
The training loop's changes that follow call NVIDIA#8037's collection
builder, warn through NVIDIA#6293's and NVIDIA#8049's fallback helpers, and extend
NVIDIA#8037's training collection test.

NVIDIA#8737, merged above, now carries NVIDIA#8037 as well, so the allowlist
conflicts on its total: NVIDIA#8737's side records 194 reads and NVIDIA#8738's 158.
It takes 158, which matches the merged entries.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yan Xu <yxu1@nvidia.com>
Connor-XY added a commit to Connor-XY/Megatron-LM that referenced this pull request Nov 1, 2026
The data-parallel group helper that follows replaces the DP x CP helper
that NVIDIA#8741 adds to the training loop, and the training utilities'
warnings extend NVIDIA#8741's packed-sequence statistics and GPT builder code.

NVIDIA#8741 is based on main, without NVIDIA#8037's and NVIDIA#8048's neighbouring lines,
so three files conflict. They are resolved as follows:
- training.py: keep NVIDIA#8037's _build_pg_collection_from_parallel_state and
  _get_forward_backward_func next to NVIDIA#8741's _get_model_pg_collection
  and _get_data_parallel_world_size. train_step's pg_collection
  docstring takes NVIDIA#8037's text plus NVIDIA#8741's sentence on the single-grid
  fallback; its p2p_communicator docstring and evaluate's keep NVIDIA#8037's
  text. train's docstring also keeps NVIDIA#8037's text, with NVIDIA#8741's sentence
  that a multi-module collection rejects the GPU sniff test and its
  Raises section.
- models/gpt.py: default_layer_spec takes (config, vp_stage,
  pp_rank=None, pg_collection=None), and GPTModelBuilder passes both
  NVIDIA#8048's pp_rank and NVIDIA#8741's pg_collection.
- test_gpt_builder.py: keep NVIDIA#8741's ModelOpt CP test and expect
  default_layer_spec(config, 3, 1, pg_collection=pg).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yan Xu <yxu1@nvidia.com>
Conflicts:
- megatron/training/training.py: Main adds the tensor metric observer,
  the run_train_loop_without_updates argument, the batch-size transition
  helper, new train() docstring entries, and moves the RL inference-model
  setup out of pretrain() (NVIDIA#4264). The PR builds the process-group
  collection once right after initialization and passes it everywhere.
  The result keeps both sides. The setup_model_and_optimizer call passes
  pg_collection directly, without main's use_mpu_process_groups()
  fallback, and also passes run_train_loop_without_updates. The
  docstrings combine main's new entries with the PR's pg_collection and
  p2p_communicator wording.

The process-group allowlist records the reads main added since this PR
was written.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Yan Xu <yxu1@nvidia.com>
@Connor-XY

Copy link
Copy Markdown
Contributor Author

Superseded by #8891, which carries this change as commit da47509 under the same title, with "Originally #8037." in its message. Closing so review happens in one place. The branch stays on the fork.

@Connor-XY Connor-XY closed this Nov 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant