Extend Cosmos3 CPU offloading to component and layerwise paths (#4695)

This commit is contained in:
Rahul Steiger authored and GitHub committed 2026-07-13 09:48:53 +00:00
1 parent 98229b08ba
commit 66b9ad287a
11 files changed
+653 -160

No files matched your search

@@ -149,6 +149,40 @@ class MultiVaePipeline(nn.Module, SupportsComponentDiscovery):
self.audio_vae = nn.Linear(10, 10)
class SiblingDiTsPipeline(nn.Module, SupportsComponentDiscovery):
"""Two independent DiTs (e.g. a MoE transformer pair)."""
_dit_modules: ClassVar[list[str]] = ["transformer", "transformer_2"]
_encoder_modules: ClassVar[list[str]] = []
_vae_modules: ClassVar[list[str]] = ["vae"]
def __init__(self):
super().__init__()
self.transformer = nn.Linear(10, 10)
self.transformer_2 = nn.Linear(10, 10)
self.vae = nn.Linear(10, 10)
class NestedDiTPipeline(nn.Module, SupportsComponentDiscovery):
"""Cosmos3-like: a DiT plus one of its own submodules listed as a DiT.
The nested entry exists so offloading can treat the inner stack as an
independent ring; the outer DiT's _hsdp_shard_conditions still own all
nested blocks for sharding. Order is nested-first, matching Cosmos3.
"""
_dit_modules: ClassVar[list[str]] = ["transformer.language_model", "transformer"]
_encoder_modules: ClassVar[list[str]] = []
_vae_modules: ClassVar[list[str]] = ["vae"]
def __init__(self):
super().__init__()
self.transformer = nn.Module()
self.transformer.language_model = nn.Linear(10, 10)
self.transformer.gen_layers = nn.Linear(10, 10)
self.vae = nn.Linear(10, 10)
# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------
@@ -238,3 +272,35 @@ class TestProtocolDiscovery:
assert len(result.vaes) == 2
assert result.vaes[0] is pipeline.vae
assert result.vaes[1] is pipeline.audio_vae
class TestOutermostDits:
"""PipelineModules.outermost_dits() drops DiTs nested inside another DiT.
HSDP shards each returned DiT via its own _hsdp_shard_conditions, so a DiT
nested inside another discovered DiT must be excluded: it is already covered
by its ancestor's conditions and may not declare conditions of its own.
"""
def test_keeps_independent_sibling_dits(self):
result = ModuleDiscovery.discover(SiblingDiTsPipeline())
names, modules = result.outermost_dits()
assert names == ["transformer", "transformer_2"]
assert [id(m) for m in modules] == [id(m) for m in result.dits]
def test_drops_nested_dit_keeping_only_ancestor(self):
pipeline = NestedDiTPipeline()
result = ModuleDiscovery.discover(pipeline)
# Discovery sees both, nested-first (matches Cosmos3's _dit_modules order).
assert result.dit_names == ["transformer.language_model", "transformer"]
names, modules = result.outermost_dits()
# Only the ancestor survives; sharding the nested condition-less stack
# again would double-wrap its blocks and raise in apply_hsdp_to_model.
assert names == ["transformer"]
assert len(modules) == 1
assert modules[0] is pipeline.transformer
@@ -7,7 +7,8 @@ import pytest
import torch
from torch import nn
from vllm_omni.diffusion.offloader.sequential_backend import SequentialOffloadHook
from vllm_omni.diffusion.offloader.base import OffloadConfig, OffloadStrategy
from vllm_omni.diffusion.offloader.sequential_backend import ModelLevelOffloadBackend, SequentialOffloadHook
from vllm_omni.platforms import current_omni_platform
pytestmark = [pytest.mark.diffusion, pytest.mark.cpu, pytest.mark.core_model]
@@ -41,6 +42,40 @@ def _track_pin_memory_calls():
return tracker, mock
def test_model_level_backend_delegates_to_custom_pipeline_offload() -> None:
class CustomPipeline(nn.Module):
def __init__(self) -> None:
super().__init__()
self.enable_args = None
self.disable_called = False
def enable_omni_model_cpu_offload(self, **kwargs) -> None:
self.enable_args = kwargs
def disable_omni_model_cpu_offload(self) -> None:
self.disable_called = True
pipeline = CustomPipeline()
backend = ModelLevelOffloadBackend(
OffloadConfig(strategy=OffloadStrategy.MODEL_LEVEL, pin_cpu_memory=False),
torch.device("cpu"),
)
backend.enable(pipeline)
assert backend.enabled is True
assert pipeline.enable_args == {
"device": torch.device("cpu"),
"pin_memory": False,
"use_hsdp": False,
}
backend.disable()
assert backend.enabled is False
assert pipeline.disable_called is True
class TestMoveParamsPinMemory:
def test_dtensor_skips_pin_memory(self, accelerator_device, monkeypatch: pytest.MonkeyPatch):
"""DTensor should skip pin_memory to avoid RuntimeError."""