Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
22752c0
refactor(distributed): introduce CPSharder, retire private CP batch keys
HuiyingLi Jul 5, 2026
07208d0
refactor(models): unify prepare_model_inputs_for_cp signature and inv…
HuiyingLi Jul 6, 2026
e5334ed
refactor(recipes): collapse CP dispatch into prepare_cp_forward (#2879)
HuiyingLi Jul 6, 2026
cd83f32
refactor(distributed): keep model-specific CP keys out of the shared …
HuiyingLi Jul 6, 2026
80ff840
refactor(distributed): move magi llm/vlm prep dispatch into MagiState
HuiyingLi Jul 6, 2026
79a5183
refactor(distributed): dispatch magi at the TE rung of make_cp_batch_…
HuiyingLi Jul 6, 2026
97b533d
refactor(distributed): drop the CP full-logits grad touch
HuiyingLi Jul 7, 2026
01f02d5
test: fix CP patch points missed by the dispatch refactor
HuiyingLi Jul 7, 2026
21d2c6a
refactor(models): drop the prepare_model_inputs_for_cp legacy-kwargs …
HuiyingLi Jul 7, 2026
545dc20
refactor(distributed): drop pre-embed no_grad wrappers and minimax de…
HuiyingLi Jul 7, 2026
7c4100c
refactor(distributed): pass the whole batch to the CP pre-embed hook
HuiyingLi Jul 7, 2026
929eae7
refactor(distributed): remove the deprecated _cp_make_batch_fn fallback
HuiyingLi Jul 8, 2026
e771af4
refactor(distributed): pass CPSharder as an explicit parameter, not a…
HuiyingLi Jul 8, 2026
f653fd6
refactor(models): drop the unused cp_style/cp_layout capability flags
HuiyingLi Jul 8, 2026
0a9e67a
refactor(distributed): prune dead surface from the CP dispatch and sh…
HuiyingLi Jul 8, 2026
be7aff4
refactor(distributed): make every CP backend a CPSharder
HuiyingLi Jul 8, 2026
664b900
refactor(distributed): move shard_batch_load_balanced next to its lay…
HuiyingLi Jul 8, 2026
df2b622
refactor(distributed): drop unused mesh params from the contiguous CP…
HuiyingLi Jul 8, 2026
749391a
feat(distributed): capture data-dependent CP index maps at shard time
HuiyingLi Jul 8, 2026
4af26cc
Merge remote-tracking branch 'origin/main' into huiyingl/refactor/cp-…
akoumpa Jul 10, 2026
58635aa
feat(distributed): return the resolved CPSharder from the CP dispatch
HuiyingLi Jul 10, 2026
c3014ad
Merge branch 'huiyingl/refactor/cp-unify' of https://github.com/NVIDI…
HuiyingLi Jul 10, 2026
3985a7c
fix(distributed): preserve CP preparation contracts
akoumpa Jul 10, 2026
78a987c
Revert "fix(distributed): preserve CP preparation contracts"
akoumpa Jul 10, 2026
3ae1c0e
feat(distributed): capture pad facts at shard time; token verbs take …
HuiyingLi Jul 10, 2026
f7d7027
feat(distributed): capture magi dispatch facts for the token verbs
HuiyingLi Jul 10, 2026
0403324
Merge remote-tracking branch 'origin/main' into huiyingl/refactor/cp-…
HuiyingLi Jul 18, 2026
adab5c6
refactor(distributed): shrink the CP dispatch surface
HuiyingLi Jul 18, 2026
f25bf35
test(distributed): multi-rank functional test for the CPSharder token…
HuiyingLi Jul 18, 2026
568c4e7
refactor(distributed): rename CPSharder to ContextParallelismSharder
HuiyingLi Jul 18, 2026
7c42b22
refactor(distributed): report shard facts as a return value, install …
HuiyingLi Jul 18, 2026
b697bef
refactor(distributed): store the shard layout whole; rename ShardFact…
HuiyingLi Jul 18, 2026
5846878
refactor(distributed): inline the contiguous shard helpers; drop dead…
HuiyingLi Jul 18, 2026
4e7e4ba
chore(distributed): fix stale wording in the no-layout placeholder co…
HuiyingLi Jul 18, 2026
78d00f5
fix(cp): allow kwargs-only pre-embed call on DSV4/GLM forwards
HuiyingLi Jul 19, 2026
7d9e4bc
fix(cp): restore minimax pre-embed detach - PP microbatches share the…
HuiyingLi Jul 19, 2026
37a10bb
fix(cp): fail loud when PP receives grad-carrying pre-embed inputs_em…
HuiyingLi Jul 19, 2026
4644a62
Revert "fix(cp): fail loud when PP receives grad-carrying pre-embed i…
HuiyingLi Jul 19, 2026
ab448de
feat(cp): aux-only shard_batch + in-forward sequence shard helper
HuiyingLi Jul 19, 2026
7fa3658
refactor(cp): sink minimax_m3_vl pre-embed into forward (per-microbat…
HuiyingLi Jul 19, 2026
e4cdb7d
refactor(cp): sink qwen3_5 pre-embed into forward (per-microbatch CP …
HuiyingLi Jul 19, 2026
377a5b9
refactor(cp): sink qwen3_5_moe pre-embed into forward (per-microbatch…
HuiyingLi Jul 19, 2026
2400f4b
refactor(cp): sink step3p7 pre-embed into forward (per-microbatch CP …
HuiyingLi Jul 19, 2026
63ad2f7
refactor(cp): sink nemotron_omni pre-embed into forward (per-microbat…
HuiyingLi Jul 19, 2026
c8abead
test(cp): GPU forward-equivalence for the minimax VL in-forward CP shard
HuiyingLi Jul 19, 2026
fa21112
test(cp): cp2xpp2 layer-2 verification for the in-forward pre-embed sink
HuiyingLi Jul 19, 2026
ee5ecaf
Merge remote-tracking branch 'origin/main' into huiyingl/refactor/cp-…
HuiyingLi Jul 19, 2026
558afcd
fix(cp): support minimax images under CP×PP via the media side channel
HuiyingLi Jul 19, 2026
08938bd
fix(cp): suspend the CP ring around vision/audio in qwen3_5, qwen3_5_…
HuiyingLi Jul 19, 2026
b01710d
fix(cp): stage VLM media for PP when CP pre-embed is sunk into forward
HuiyingLi Jul 19, 2026
649632a
fix(cp): invoke the sharder-only hook on every PP stage for sunk models
HuiyingLi Jul 19, 2026
479e8a9
debug(cp): TEMP NEMO_CP_DEBUG shape logging in minimax forward (REVER…
HuiyingLi Jul 19, 2026
0dce9da
feat(cp): contiguous aux-only shard + in-forward contiguous slice
HuiyingLi Jul 20, 2026
1b9de7d
refactor(cp): sink gemma4 pre-embed into forward (per-microbatch cont…
HuiyingLi Jul 20, 2026
98f4e39
fix(cp): keep the contiguous shard divisibility guard on the padded p…
HuiyingLi Jul 20, 2026
3241d94
refactor(cp): drop the _pre_embed_only __call__ pre-embed protocol
HuiyingLi Jul 20, 2026
48de5a6
refactor(cp): remove production-dead make_contiguous_shard_cp_batch_a…
HuiyingLi Jul 20, 2026
7b0515e
refactor(cp): remove the KD teacher-compat guard dead after the pre-e…
HuiyingLi Jul 20, 2026
8d51c2c
debug(cp): TEMP env-gated per-param grad dump for the 26b regression …
HuiyingLi Jul 20, 2026
6effec2
refactor(cp): revert TEMP debug + collapse the pre-embed PP gate
HuiyingLi Jul 20, 2026
122b80f
refactor(cp): collapse the vacuous recipe_level_cp_preembed PP gate
HuiyingLi Jul 20, 2026
b246487
refactor(cp): remove the now-zero-consumer cp_preembed_in_forward flag
HuiyingLi Jul 20, 2026
d1b5236
docs(cp): fix stale + shorten overlong branch-added CP comments
HuiyingLi Jul 20, 2026
23a071d
refactor(cp): collapse the contiguous-shard corridor to one public fu…
HuiyingLi Jul 20, 2026
93fef62
docs(cp): finish the ShardFacts->ShardLayout rename (facts->layout wo…
HuiyingLi Jul 21, 2026
2a5628f
refactor(cp): symmetric seq-shard names (round_robin / contiguous suf…
HuiyingLi Jul 21, 2026
f641013
fix(ci): move GLM CP recipe ci section last
HuiyingLi Jul 21, 2026
278f876
revert(ci): drop GLM 5.2 recipe CI config change
HuiyingLi Jul 21, 2026
f094026
fix(distributed): preserve CP hook batch metadata
HuiyingLi Jul 21, 2026
cb77375
style(gemma4): stabilize CP formatting for CI ruff
HuiyingLi Jul 21, 2026
2113f20
style(gemma4): avoid CP shard call formatter drift
HuiyingLi Jul 21, 2026
a590db4
style(gemma4): match CI ruff formatting
HuiyingLi Jul 21, 2026
6156c81
fix(glm-dsa): keep direct CP helper return stable
HuiyingLi Jul 21, 2026
49f897a
fix(cp): avoid re-enabling inactive CP dispatcher
HuiyingLi Jul 21, 2026
2751767
refactor(cp): sharder ownership (#3187)
akoumpa Jul 22, 2026
faec4aa
fix(cp): align packing with flash attention variants
HuiyingLi Jul 23, 2026
4d8970d
Merge remote-tracking branch 'origin/main' into huiyingl/refactor/cp-…
HuiyingLi Jul 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions nemo_automodel/_transformers/capabilities.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def _uses_magi_attention(model: "nn.Module") -> bool:
"""True when the model uses the MagiAttention (FFA / context-parallel) backend.

MagiAttention implements context parallelism via its own load-balancing
dispatch (see ``components/distributed/magi_attn_utils.py``), so it supports CP.
dispatch (see ``components/distributed/context_parallel/magi.py``), so it supports CP.
"""
backend = getattr(model, "backend", None)
return getattr(backend, "attn", None) == "magi"
Expand Down Expand Up @@ -336,7 +336,7 @@ def supports_cp_with_sequence_packing(self) -> bool:

MagiAttention dispatches the packed sequence across the CP group with its
own load-balancing solver and a per-document varlen mask, so it supports
CP + packing (see ``magi_attn_utils.magi_prepare_packed_cp``). Models
CP + packing (see ``context_parallel.magi.magi_prepare_packed_cp``). Models
with native THD support own their packed CP path in TileLang attention."""
model = self._model
if not self.supports_sequence_packing:
Expand Down
2 changes: 1 addition & 1 deletion nemo_automodel/_transformers/infrastructure.py
Original file line number Diff line number Diff line change
Expand Up @@ -748,7 +748,7 @@ def apply_model_infrastructure(
# is not excluded by the _uses_te_attention check, so gate on ep_size: only
# dense (non-MoE) models need this pass.
if mesh.cp_size > 1 and mesh.ep_size <= 1 and not _uses_te_attention(model):
from nemo_automodel.components.distributed.cp_utils import (
from nemo_automodel.components.distributed.context_parallel.utils import (
attach_context_parallel_hooks,
attach_cp_sdpa_hooks,
)
Expand Down
2 changes: 1 addition & 1 deletion nemo_automodel/components/attention/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ def attn_func(q: torch.Tensor, k: torch.Tensor, v: torch.Tensor, **call_kwargs:
)
# requires magi_attention; the guards above are exercised on CPU but the
# kernel build is not, so exclude it from coverage.
from nemo_automodel.components.distributed.magi_attn_utils import ( # pragma: no cover - requires magi_attention
from nemo_automodel.components.distributed.context_parallel.magi import ( # pragma: no cover - requires magi_attention
make_magi_attn_func,
)

Expand Down
7 changes: 7 additions & 0 deletions nemo_automodel/components/datasets/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,13 @@ def dataset_builds_on_all_ranks(self) -> bool:
"""Whether dataset construction must bypass rank-zero-first ordering."""
return isinstance(self.dataset_config, AllRanksDatasetConfig)

@property
def emits_thd(self) -> bool:
"""Whether this configuration produces THD-formatted batches."""
from nemo_automodel.components.datasets.utils import packed_sequence_thd_collater

return isinstance(self.packing, ThdPackingConfig) or self.collate_fn is packed_sequence_thd_collater

def _build_dataset(
self,
*,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Context-parallel batch sharding."""

from nemo_automodel.components.distributed.context_parallel.sharder import ContextParallelSharder

__all__ = ["ContextParallelSharder"]
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
import torch
import torch.distributed as dist

from nemo_automodel.components.distributed.cp_utils import make_cp_batch_and_ctx, make_cp_batch_for_te
from nemo_automodel.components.distributed.context_parallel.utils import _make_cp_batch_and_ctx, make_cp_batch_for_te

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -730,6 +730,8 @@ class MagiState:
custom: bool = False # custom-model factory backend (vs HF attn_implementation)
cp_group: Optional["dist.ProcessGroup"] = None
cp_size: int = 1
domain: str = "llm" # recipe domain ("llm" | "vlm"), bound at setup
device_mesh: Optional[Any] = None # full device mesh, bound at setup (cp=1 THD conversion)

@property
def hf_dispatch(self) -> bool:
Expand All @@ -746,8 +748,12 @@ def prepare_llm_batch(
): # pragma: no cover - requires GPU + magi_attention
"""Per-step batch prep for the LLM recipe (assumes ``enabled``).

Returns ``(train_ctx, batch)``. magi does its own CP, so ``train_ctx`` is
always ``nullcontext`` (no torch-native DTensor CP context).
Returns ``(train_ctx, batch, local_indices)``. magi does its own CP, so
``train_ctx`` is always ``nullcontext`` (no torch-native DTensor CP
context). ``local_indices`` is the global stream position of every
local token on the paths that dispatch the sequence (magi's
``get_position_ids``), None otherwise; the framework installs it on
the magi ContextParallelSharder for the token-tensor verbs.
"""
# cp=1 prefix-tree mask: the datasets layer cannot import this module (component
# independence), so the collate attaches the tree structure and the spec is built
Expand All @@ -771,21 +777,28 @@ def prepare_llm_batch(
node_lengths, sample_paths = prefix_tree if prefix_tree is not None else (None, None)
spec = AttnMaskSpec.prefix_tree(node_lengths, sample_paths)[0] if prefix_tree is not None else None
set_active_attn_spec(spec)
local_indices = None
if self.hf_dispatch:
# HF path: dispatch the (single causal) sequence across the CP group.
batch, _ = magi_prepare_batch(model, batch, self.cp_group)
# The dispatched position_ids ARE magi's get_position_ids(key): the
# global stream position of every local token.
local_indices = batch["position_ids"]
elif self.custom and self.cp_size > 1 and is_thd:
# Custom-model CP packed path: build the *global* THD layout (no TE
# sharding) then dispatch it with magi's own load-balancing solver.
batch = make_cp_batch_for_te(None, batch, qkv_format="thd", padding_token_id=pad_id, num_chunks=1)
batch, _ = magi_prepare_packed_cp(model, batch, self.cp_group)
local_indices = batch["position_ids"]
elif is_thd:
# cp=1 packing: THD conversion (no sharding) so the batch carries
# cu_seqlens -> the magi attn_func builds the per-document mask.
_, batch = make_cp_batch_and_ctx(
# position_ids here are per-document RoPE positions, not stream
# indices, so no index map is exposed.
_, batch, _ = _make_cp_batch_and_ctx(
device_mesh, batch, use_te=True, padding_token_id=pad_id, num_chunks=num_chunks
)
return nullcontext, batch
return nullcontext, batch, local_indices

def prepare_vlm_batch(self, model, batch):
"""Per-step batch prep for the VLM recipe (assumes ``enabled``).
Expand All @@ -798,8 +811,61 @@ def prepare_vlm_batch(self, model, batch):
batch, _ = magi_prepare_vlm(model, batch, self.cp_group)
return nullcontext, batch

def make_cp_batch(
self,
cp_mesh,
batch,
*,
padding_token_id: int = 0,
num_chunks: int = 1,
is_thd: bool = False,
model=None,
return_local_indices: bool = False,
):
"""Backend-owned per-step batch prep, shaped like ``make_cp_batch_for_te``.

Called by the CP dispatch at the same rung
as the TE path: magi manages its own CP transport, so the context is
implicitly ``nullcontext`` and only the prepped batch is returned.
Everything recipe-static (domain, cp group, device mesh, HF-vs-custom)
was bound at :func:`setup_magi`; ``model`` is passed opaquely for
per-step key/spec stamping on attention modules.

Args:
cp_mesh: The context-parallel submesh. Unused — magi owns its
bound ``cp_group``; accepted for signature symmetry with
``make_cp_batch_for_te``.
batch: The full-sequence batch.
padding_token_id: Pad sentinel for ``input_ids``.
num_chunks: THD chunk count.
is_thd: THD-packed collator is active.
model: The model part whose attention modules receive keys/specs.
return_local_indices: Also return the local-token global index map
from the dispatch that just ran (None on paths that do not
dispatch, e.g. cp=1 THD conversion and the VLM domain). Used
by the magi ContextParallelSharder's token verbs.

Returns:
The dispatched (magi-sharded) batch, or ``(batch, local_indices)``
when ``return_local_indices``.
"""
del cp_mesh
local_indices = None
if self.domain == "vlm":
_, batch = self.prepare_vlm_batch(model, batch)
else:
_, batch, local_indices = self.prepare_llm_batch(
model,
batch,
device_mesh=self.device_mesh,
is_thd=is_thd,
pad_id=padding_token_id,
num_chunks=num_chunks,
)
return (batch, local_indices) if return_local_indices else batch


def setup_magi(cfg, device_mesh, *, label: str = "") -> MagiState:
def setup_magi(cfg, device_mesh, *, domain: str = "llm", label: str = "") -> MagiState:
"""Resolve MagiAttention from config: register the backend and CP group.

Enabled when the model is configured with ``attn_implementation="magi"`` (HF) or
Expand All @@ -810,7 +876,7 @@ def setup_magi(cfg, device_mesh, *, label: str = "") -> MagiState:
custom = str(cfg.get("model.backend.attn", "")) == "magi"
enabled = custom or str(cfg.get("model.attn_implementation", "")) == "magi"
if not enabled:
return MagiState()
return MagiState(domain=domain)

if not is_magi_available():
raise RuntimeError(
Expand All @@ -833,4 +899,6 @@ def setup_magi(cfg, device_mesh, *, label: str = "") -> MagiState:
"custom-model factory" if custom else "HF backend",
cp_size,
)
return MagiState(enabled=True, custom=custom, cp_group=cp_group, cp_size=cp_size)
return MagiState(
enabled=True, custom=custom, cp_group=cp_group, cp_size=cp_size, domain=domain, device_mesh=device_mesh
)
Loading
Loading