[Diffusion] Integrate no-AllGather DLO with Host Weight Runtime (#6486)
Signed-off-by: Hongsheng Liu <liuhongsheng4@huawei.com> Signed-off-by: hsliuustc0106 <hsliuustc0106@users.noreply.github.com> Co-authored-by: hsliuustc0106 <hsliuustc0106@users.noreply.github.com>
This commit is contained in:
1 parent
8fdb719a41
commit
8360346a66
27 files changed
+1640
-51
No files matched your search
@@ -38,6 +38,7 @@ from vllm_omni.diffusion.offloader.offload_plan import (
|
||||
OffloadPlan,
|
||||
get_offload_plan,
|
||||
)
|
||||
from vllm_omni.diffusion.offloader.startup import OffloadStartupState, attach_offload_startup_state
|
||||
from vllm_omni.platforms import current_omni_platform
|
||||
|
||||
pytestmark = [pytest.mark.diffusion, pytest.mark.cpu, pytest.mark.core_model]
|
||||
@@ -695,6 +696,67 @@ class _SingleBlockModel(nn.Module):
|
||||
self.blocks = nn.ModuleList([_DummyBlock() for _ in range(num_blocks)])
|
||||
|
||||
|
||||
class _HWRPipeline(nn.Module):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.transformer = _SingleBlockModel(num_blocks=3)
|
||||
|
||||
|
||||
class _FakeHostWeightLease:
|
||||
def __init__(self, resolution_id: str):
|
||||
self.closed = False
|
||||
self.provenance = SimpleNamespace(resolution_id=resolution_id)
|
||||
|
||||
def close(self):
|
||||
self.closed = True
|
||||
|
||||
|
||||
class _FakeLeaseCarrier:
|
||||
def __init__(self, lease: _FakeHostWeightLease):
|
||||
self.lease = lease
|
||||
self.taken = False
|
||||
|
||||
@property
|
||||
def closed(self):
|
||||
return self.taken or self.lease.closed
|
||||
|
||||
def take(self):
|
||||
if self.taken:
|
||||
raise RuntimeError("already taken")
|
||||
self.taken = True
|
||||
return self.lease
|
||||
|
||||
def close(self):
|
||||
if not self.taken:
|
||||
self.lease.close()
|
||||
|
||||
|
||||
def _fake_hwr_plan(resolution_id: str = "hwr-test"):
|
||||
lease = _FakeHostWeightLease(resolution_id)
|
||||
carrier = _FakeLeaseCarrier(lease)
|
||||
plan = HostWeightPlan(
|
||||
backing_kind="host_weight_runtime",
|
||||
bindings={},
|
||||
lease_carrier=carrier,
|
||||
)
|
||||
return plan, carrier, lease
|
||||
|
||||
|
||||
def _hwr_backend():
|
||||
plan, carrier, lease = _fake_hwr_plan()
|
||||
backend = DistributedLayerwiseOffloadBackend(
|
||||
OffloadConfig(
|
||||
strategy=OffloadStrategy.DISTRIBUTED_LAYER_WISE,
|
||||
pin_cpu_memory=False,
|
||||
dp_size=1,
|
||||
dlo_use_allgather=False,
|
||||
),
|
||||
torch.device("cpu"),
|
||||
host_weight_plan=plan,
|
||||
)
|
||||
return _HWRPipeline(), backend, carrier, lease
|
||||
|
||||
|
||||
class _MultiBlockModel(nn.Module):
|
||||
_layerwise_offload_blocks_attrs = ["transformer_blocks", "single_transformer_blocks"]
|
||||
|
||||
@@ -838,6 +900,47 @@ class TestMmapWeightLoading:
|
||||
assert all(hook.rank_local_mmap for group in backend._all_hook_groups for hook in group)
|
||||
backend.disable()
|
||||
|
||||
def test_hwr_carrier_is_taken_and_released_after_bounded_staging(self, patched_offload_runtime):
|
||||
"""A warm HWR plan uses the existing two-slot rank-local transport."""
|
||||
pipeline, backend, carrier, lease = _hwr_backend()
|
||||
model_bytes = sum(param.numel() * param.element_size() for param in pipeline.transformer.parameters())
|
||||
|
||||
backend.enable(pipeline)
|
||||
|
||||
assert carrier.taken
|
||||
assert backend._using_rank_local_mmap
|
||||
assert all(len(hook.cpu_staging_buffers) == 2 for group in backend._all_hook_groups for hook in group)
|
||||
staging_bytes = sum(
|
||||
buffer.numel() * buffer.element_size()
|
||||
for buffer in backend._all_hook_groups[0][0].cpu_staging_buffers[0].values()
|
||||
)
|
||||
assert staging_bytes * 2 < model_bytes
|
||||
assert not lease.closed
|
||||
|
||||
backend.disable()
|
||||
assert lease.closed
|
||||
|
||||
def test_hwr_backend_failure_drains_partial_setup_before_lease_close(
|
||||
self,
|
||||
monkeypatch,
|
||||
patched_offload_runtime,
|
||||
):
|
||||
pipeline, backend, carrier, lease = _hwr_backend()
|
||||
monkeypatch.setattr(
|
||||
backend,
|
||||
"_allocate_shared_buffers",
|
||||
lambda hooks: (_ for _ in ()).throw(RuntimeError("device buffer allocation failed")),
|
||||
)
|
||||
|
||||
with pytest.raises(RuntimeError, match="device buffer allocation failed"):
|
||||
backend.enable(pipeline)
|
||||
|
||||
assert carrier.taken
|
||||
assert lease.closed
|
||||
assert not backend.enabled
|
||||
assert not backend._blocks
|
||||
assert not backend._all_hook_groups
|
||||
|
||||
|
||||
class TestGetBlocksFromDit:
|
||||
def test_get_blocks_from_dit_single_block_attr(self):
|
||||
@@ -1504,6 +1607,48 @@ class TestMmapValidation:
|
||||
class TestConfigValidation:
|
||||
"""Tests for configuration validation in OffloadConfig / execute_request."""
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("dp", "sp", "tp", "use_allgather", "expected_dlo_group"),
|
||||
[
|
||||
(1, 1, 1, True, 1),
|
||||
(2, 1, 1, True, 2),
|
||||
(1, 4, 1, True, 4),
|
||||
(2, 2, 2, True, 2),
|
||||
(2, 2, 2, False, 1),
|
||||
(1, 4, 2, False, 1),
|
||||
],
|
||||
)
|
||||
def test_dlo_group_selection_covers_dp_sp_tp_matrix(
|
||||
self,
|
||||
dp,
|
||||
sp,
|
||||
tp,
|
||||
use_allgather,
|
||||
expected_dlo_group,
|
||||
):
|
||||
"""DLO sharding follows DP, falls back to SP, and never uses TP."""
|
||||
|
||||
config = OffloadConfig.from_od_config(
|
||||
SimpleNamespace(
|
||||
enable_cpu_offload=False,
|
||||
enable_layerwise_offload=False,
|
||||
enable_distributed_layerwise_offload=True,
|
||||
dlo_use_allgather=use_allgather,
|
||||
dlo_resident_layers=0,
|
||||
pin_cpu_memory=False,
|
||||
parallel_config=SimpleNamespace(
|
||||
data_parallel_size=dp,
|
||||
use_hsdp=False,
|
||||
hsdp_shard_size=-1,
|
||||
hsdp_replicate_size=1,
|
||||
sequence_parallel_size=sp,
|
||||
tensor_parallel_size=tp,
|
||||
),
|
||||
)
|
||||
)
|
||||
assert config.dp_size == expected_dlo_group
|
||||
assert config.dlo_use_allgather is use_allgather
|
||||
|
||||
def test_loader_plan_cannot_be_silently_dropped_on_unsupported_platform(self, monkeypatch):
|
||||
import vllm_omni.diffusion.offloader as offloader_module
|
||||
|
||||
@@ -1538,6 +1683,53 @@ class TestConfigValidation:
|
||||
host_weight_plan=plan,
|
||||
)
|
||||
|
||||
def test_startup_recovery_stays_inside_offloader_boundary(self, monkeypatch):
|
||||
import vllm_omni.diffusion.offloader as offloader_module
|
||||
|
||||
class FailingBackend:
|
||||
def __init__(self):
|
||||
self.disabled = False
|
||||
|
||||
def enable(self, pipeline):
|
||||
del pipeline
|
||||
raise RuntimeError("initial prefetch failed")
|
||||
|
||||
def disable(self):
|
||||
self.disabled = True
|
||||
|
||||
warm_pipeline = nn.Module()
|
||||
canonical_pipeline = nn.Module()
|
||||
plan, carrier, _lease = _fake_hwr_plan("hwr-recovery")
|
||||
failing_backend = FailingBackend()
|
||||
calls = []
|
||||
|
||||
def fake_backend(od_config, device, host_weight_plan):
|
||||
del od_config, device
|
||||
calls.append(host_weight_plan)
|
||||
return failing_backend if host_weight_plan is plan else None
|
||||
|
||||
attach_offload_startup_state(
|
||||
warm_pipeline,
|
||||
OffloadStartupState(
|
||||
host_weight_plan=plan,
|
||||
fresh_model_loader=lambda: canonical_pipeline,
|
||||
allow_fresh_retry=True,
|
||||
),
|
||||
)
|
||||
monkeypatch.setattr(offloader_module, "get_offload_backend", fake_backend)
|
||||
|
||||
recovered, backend = offloader_module.enable_offload_backend(
|
||||
SimpleNamespace(),
|
||||
warm_pipeline,
|
||||
device=torch.device("cpu"),
|
||||
)
|
||||
|
||||
assert recovered is canonical_pipeline
|
||||
assert backend is None
|
||||
assert failing_backend.disabled
|
||||
assert carrier.closed
|
||||
assert calls == [plan, None]
|
||||
|
||||
def test_hsdp_with_allgather_rejected(self):
|
||||
"""HSDP + DLO + AllGather should raise ValueError (double sharding)."""
|
||||
from vllm_omni.diffusion.offloader.base import OffloadConfig
|
||||
|
||||
Reference in new issue
Block a user