[feature] Reduce memory usage with SP (#7728)

Signed-off-by: Maciej Bala <mbala@nvidia.com>
This commit is contained in:
MaciejBalaNV authored and GitHub committed 2026-10-07 22:36:32 +08:00
1 parent 3dc35694b3
commit e54e185593
7 files changed
+475 -17

No files matched your search

@@ -1182,6 +1182,9 @@ class _GenPrepared(NamedTuple):
use_multi_control_attention: bool
multi_control_token_sizes: tuple[int, ...] | None
multi_control_weights: tuple[float, ...] | None
# Execution-layout state; set only by Cosmos3VFMTransformer._shard_gen_prep.
freqs_gen: tuple[torch.Tensor, torch.Tensor] | None = None
defer_gen_gather: bool = False
class Cosmos3VFMTransformer(nn.Module):
@@ -1242,7 +1245,13 @@ class Cosmos3VFMTransformer(nn.Module):
_sp_plan = {
"gen_sp_prepare": {
0: SequenceParallelInput(split_dim=1, expected_dims=3, split_output=True, auto_pad=True),
0: SequenceParallelInput(
split_dim=1,
expected_dims=3,
split_output=True,
auto_pad=True,
clone_shard=True,
),
1: SequenceParallelInput(split_dim=1, expected_dims=4, split_output=True, auto_pad=True),
2: SequenceParallelInput(split_dim=1, expected_dims=4, split_output=True, auto_pad=True),
},
@@ -1769,6 +1778,8 @@ class Cosmos3VFMTransformer(nn.Module):
self,
hidden_gen: torch.Tensor,
*,
freqs_gen: tuple[torch.Tensor, torch.Tensor],
gather_output: bool,
s_video: int,
s_control: int,
s_action: int,
@@ -1781,13 +1792,10 @@ class Cosmos3VFMTransformer(nn.Module):
multi_control_token_sizes: tuple[int, ...] | None,
multi_control_weights: tuple[float, ...] | None,
) -> torch.Tensor:
"""Run the complete GEN decoder between full-layout boundaries."""
if self.cached_kv is None or self.cached_freqs_gen is None:
"""Run the complete GEN decoder on inputs already in the execution layout."""
if self.cached_kv is None:
raise RuntimeError("Cosmos3 GEN cache was not initialized before running GEN layers.")
freqs_cos, freqs_sin = self.cached_freqs_gen
if not use_multi_control_attention:
hidden_gen, freqs_cos, freqs_sin = self.gen_sp_prepare(hidden_gen, freqs_cos, freqs_sin)
freqs_gen = (freqs_cos, freqs_sin)
freqs_cos, freqs_sin = freqs_gen
if len(self.gen_layers) == len(self.cached_kv):
for layer, (k_und, v_und) in zip(self.gen_layers, self.cached_kv, strict=True):
@@ -1816,7 +1824,7 @@ class Cosmos3VFMTransformer(nn.Module):
if isinstance(hidden_gen, tuple):
hidden_gen = hidden_gen[0]
if not use_multi_control_attention:
if gather_output and not use_multi_control_attention:
hidden_gen = self.gen_sp_gather(hidden_gen)
return hidden_gen
@@ -1863,8 +1871,33 @@ class Cosmos3VFMTransformer(nn.Module):
control_weights=control_weights,
transfer_share_vision_temporal_positions=transfer_share_vision_temporal_positions,
)
prep = self._shard_gen_prep(prep)
return self._gen_postprocess(self._run_gen_stack(prep), prep)
def _shard_gen_prep(self, prep: _GenPrepared, *, defer_gather: bool = False) -> _GenPrepared:
"""Move prepared GEN inputs into the execution layout.
Callers must rebind their ``prep`` to the result before running the
stack: keeping the original would pin the full embedding even though
the sharded ``hidden_gen`` owns separate storage.
``defer_gather`` keeps the stack output rank-local and moves the SP
gather into ``_gen_postprocess``, so cache residuals stay sharded.
"""
if prep.freqs_gen is not None or prep.defer_gen_gather:
raise RuntimeError("Cosmos3 GEN inputs are already in the execution layout.")
if self.cached_freqs_gen is None:
raise RuntimeError("Cosmos3 GEN cache was not initialized before running GEN layers.")
if prep.use_multi_control_attention:
# Multi-control attention runs unsharded, so there is nothing to gather.
return prep._replace(freqs_gen=self.cached_freqs_gen)
hidden_gen, freqs_cos, freqs_sin = self.gen_sp_prepare(prep.hidden_gen, *self.cached_freqs_gen)
return prep._replace(
hidden_gen=hidden_gen,
freqs_gen=(freqs_cos, freqs_sin),
defer_gen_gather=defer_gather,
)
def _gen_preprocess(
self,
hidden_states: torch.Tensor,
@@ -2132,9 +2165,13 @@ class Cosmos3VFMTransformer(nn.Module):
)
def _run_gen_stack(self, prep: _GenPrepared) -> torch.Tensor:
"""Execute the cacheable full-layout GEN stack, including final norm."""
"""Execute the cacheable GEN stack, including final norm."""
if prep.freqs_gen is None:
raise RuntimeError("Cosmos3 GEN inputs must go through _shard_gen_prep before the stack.")
hidden_gen = self._run_gen_layers(
prep.hidden_gen,
freqs_gen=prep.freqs_gen,
gather_output=not prep.defer_gen_gather,
s_video=prep.s_video,
s_control=prep.s_control,
s_action=prep.s_action,
@@ -2155,6 +2192,8 @@ class Cosmos3VFMTransformer(nn.Module):
prep: _GenPrepared,
) -> torch.Tensor | tuple[torch.Tensor, ...]:
"""Project an already-normalized packed GEN state to model outputs."""
if prep.defer_gen_gather:
hidden_gen = self.gen_sp_gather(hidden_gen)
if not prep.has_action and not prep.has_sound and not prep.has_control:
return self.unpatchify(self.proj_out(hidden_gen), prep.t, prep.h, prep.w)