Skip to content

Wire witness support inside Megatron - #21

Merged
fzyzcjy merged 33 commits into
miles-mainfrom
trainer_ft/dev
Jul 9, 2026
Merged

Wire witness support inside Megatron#21
fzyzcjy merged 33 commits into
miles-mainfrom
trainer_ft/dev

Conversation

@fzyzcjy

@fzyzcjy fzyzcjy commented Apr 2, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

fzyzcjy added 3 commits April 1, 2026 22:53
Add _pre_decoder_hooks list and register_pre_decoder_hook() method.
Hooks are called between _preprocess and decoder, allowing external code
to transform decoder_input without Megatron knowing specifics.
Already initialized in __init__, no need for getattr fallback.
@fzyzcjy fzyzcjy changed the title Add register_pre_decoder_hook [DO NOT MERGE] trainer ft Apr 2, 2026
@fzyzcjy
fzyzcjy marked this pull request as draft April 2, 2026 02:28
fzyzcjy added 25 commits April 2, 2026 10:36
Remove _pre_decoder_hooks list and register_pre_decoder_hook() method.
Add witness_ids parameter to forward() and build_schedule_plan().
Witness logic is inline: hasattr(self, 'head_witness') check + add to
decoder_input or decoder.input_tensor depending on PP stage.
- build_schedule_plan: accept witness_ids, pass to schedule plan
- TransformerModelChunkSchedulePlan: store witness_ids in chunk_state
- PreProcessNode.forward_impl: apply witness after _preprocess
  (same logic as GPTModel.forward)
- GPTModel.forward: add tail_witness after decoder, before _postprocess
- build_schedule_plan: revert witness_ids param (not supported)
- model_chunk_schedule_plan: revert witness_ids in chunk_state
- fine_grained_callables: revert witness logic in Pre/PostProcessNode
_DataWitness.forward returns [b, s, 1] but Megatron's decoder_input
is in [s, b, h] format after the embedding layer. Without transposing,
broadcasting [s, b, h] + [b, s, 1] creates a [s, s, h] tensor,
causing OOM (648 GiB for s=18432).
When sequence parallel is active, decoder_input and hidden_states
are scattered along the sequence dimension ([s/tp, b, h]). The
witness output must also be scattered to match, otherwise shapes
mismatch (e.g. [18432, 1, 1] vs [9216, 1, h] with TP=2).
…ptimizer

The distributed optimizer replaces optimizer param_groups with shard
main params (fp32 copies). get_main_grads_for_grad_norm checks
_is_witness_param on these main params, but the flag was only set on
the original model params. Copy the flag when building main param
groups for both float16→fp32 and fp32 paths.
…ixes)

Brings in: true-on-policy init (mappings.py _tree_all_reduce_sum +
_DeterministicReduceFromModelParallelRegion, miles_megatron_plugins/true_on_policy,
gpt_layer_specs use_true_on_policy_backend) + plugin packaging (#49, #50) + fixes
(param dtype before DDP wrap #24, attention_output_gate TP slice #22, fp32 shard
detach).
Debug/test-only helper that replaces order-sensitive SUM collectives with
an all-gather plus a fixed local fold. For power-of-two world sizes it reuses
the pairwise tree of _tree_reduce_sum_from_gathered; non-power-of-two falls
back to an ascending-rank sequential fold. The all-gather is pure data
movement, so the local sum order is the only arithmetic order, making the
result bitwise deterministic and independent of NCCL.
When deterministic collectives are enabled, start_grad_sync folds each
bucket's full grad_data with deterministic_sum_inplace over the same
communication group the normal path selects, then returns early (skipping
_coalescing_manager). The full reduced sum lands in grad_data on every rank,
a superset of reduce-scatter, so the distributed optimizer's shard views read
correct values. Synchronous semantics only: asserts overlap_grad_reduce is
off and a single DistOpt instance; grad_reduce_handle stays None as in the
existing non-overlap path.
Gate every order-sensitive SUM all_reduce that feeds the deterministic FT
comparison behind is_deterministic_collectives_enabled(), preserving the
original call on the else branch:
- finalize_model_grads: conditional-embedding (pp), embedding (embd),
  non-tensor-parallel SUM grads (tp; the AVG entry is left untouched), and
  num_tokens (dp_cp).
- moe_utils.get_updated_expert_bias: the router tokens-per-expert reduce
  (local import to avoid a circular import with megatron.core.distributed).
- clip_grads.get_grad_norm_fp32: the two squared-norm SUM reduces; the inf-norm
  MAX reduce is left untouched.
Cover: deterministic_sum_inplace equals the true sum, bitwise-identical
results across two process-group objects over the same ranks, chunked folding
matching a single-shot fold, power-of-two tree vs non-power-of-two ascending
fold selection, world-size-one no-op, and the contiguous-input assertion. The
all_gather is faked in-process, so the test runs without GPUs.
Reuse _is_power_of_two from tensor_parallel.mappings; make fold_gathered_sum public
(consumed by miles indep_dp) and let it reuse the first gathered buffer instead of
clone+reallocate in the ascending fold; extract deterministic_sum_inplace_with_gather
(injectable all_gather) so non-c10d process groups share the exact chunk/fold code;
drop the redundant .contiguous() on contiguous 1-D slices; comment the SUM-only gate
next to the AVG entry; cover the injectable-gather variant in the unit test.
fzyzcjy added 4 commits June 5, 2026 19:44
…iguous input, group-ranks log)

M1: the shared _patch_all_gather fake copied the full per-rank tensor into
each sub-tensor chunk, which crashes for chunked folds. Slice by a running
per-call offset like _fake_gather, so chunked and single-shot tests both work.

m1: deterministic_sum_inplace_with_gather previously asserted contiguity, but
finalize_model_grads' embedding-grad path may pass non-contiguous tensors that
plain all_reduce accepted. Fold a contiguous copy and write back via copy_;
never fall back to NCCL all_reduce. Contiguous fast path stays allocation-free.
The unit test now asserts the correct summed values instead of an assertion.

I2: add log_group_ranks_once helper and call it from the gated branch in
start_grad_sync so each run logs the actual dp x cp member ranks once, enabling
in-pod cp-inner bracketing verification.
…l backend)

Reverts c30d54d, 336dd33, 02b995b, 85c2ce9, bb8aa73, 3998005. The
deterministic SUM fold now lives entirely in miles as a custom torch.distributed
backend (miles.utils.det_process_group, registered as det_nccl), so Megatron needs
no gated call sites, no deterministic_collectives module, and carries zero extra
divergence beyond upstream miles-main.
When MILES_EXPERIMENTAL_FT_TRAINER=1, assert CUDA_DEVICE_MAX_CONNECTIONS != 1 instead of == 1: the
FT (indep_dp) trainer deadlocks a freshly respawned cell's concurrent intra-cell comms on rejoin
under a single hardware queue.
@fzyzcjy
fzyzcjy marked this pull request as ready for review June 17, 2026 11:04
@fzyzcjy fzyzcjy changed the title [DO NOT MERGE] trainer ft Wire witness support inside Megatron Jun 17, 2026
@fzyzcjy fzyzcjy changed the title Wire witness support inside Megatron [ONLY MERGE AFTER PR64] Wire witness support inside Megatron Jul 8, 2026
@fzyzcjy fzyzcjy changed the title [ONLY MERGE AFTER PR64] Wire witness support inside Megatron Wire witness support inside Megatron Jul 8, 2026
@fzyzcjy
fzyzcjy merged commit 4716f75 into miles-main Jul 9, 2026
2 checks passed
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.

3 participants