[LingBot World] Shard the streaming VAE decode across the Ulysses ranks (#7651)

Signed-off-by: tzhouam <tzhouam@connect.ust.hk>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Zhou TaichangandClaude Fable 5.1 authored and GitHub committed 2026-09-21 19:00:46 +08:00
1 parent 8efd3c2f6d
commit 5356357cf0
5 files changed
+378 -11

No files matched your search

@@ -493,6 +493,84 @@ def test_dist_zero_pad_only_applies_global_width_edges(monkeypatch: pytest.Monke
assert last.shape == (1, 1, 2, 3)
@pytest.mark.core_model
@pytest.mark.cpu
class _PlainDecoder(torch.nn.Module):
"""A decoder with nothing to patch, so the install only wraps ``forward``."""
def __init__(self):
super().__init__()
self.calls: list[dict] = []
def forward(self, x, feat_cache=None, feat_idx=None, first_chunk=False):
self.calls.append({"feat_cache": feat_cache, "feat_idx": feat_idx, "first_chunk": first_chunk})
return x
@pytest.mark.core_model
@pytest.mark.cpu
@pytest.mark.parametrize("world_size, dst", [(4, -1), (4, 4), (4, 5), (1, 1), (4, 1.5)])
def test_install_rejects_invalid_destination_before_mutating_decoder(monkeypatch, world_size, dst):
monkeypatch.setattr(wan_spatial_shard, "_rank_world", lambda group: (0, world_size))
vae = SimpleNamespace(decoder=torch.nn.Identity())
original_forward = vae.decoder.forward
def unexpected_patch(*args, **kwargs):
pytest.fail("invalid destination must fail before patching modules")
monkeypatch.setattr(wan_spatial_shard, "_patch_decoder_modules", unexpected_patch)
with pytest.raises(ValueError, match="dst must be None or an integer"):
wan_spatial_shard.install_wan_spatial_shard_decode(vae, object(), dst=dst)
assert vae.decoder.forward == original_forward
assert not getattr(vae, "_vllm_omni_wan_spatial_shard_installed", False)
def _install_on_plain_decoder(monkeypatch: pytest.MonkeyPatch, *, dst):
monkeypatch.setattr(wan_spatial_shard, "_rank_world", lambda group: (1, 2))
monkeypatch.setattr(
wan_spatial_shard,
"split_for_parallel_decode",
lambda x, *, upsample_count, split_dim, group: (x, x.shape[wan_spatial_shard._spatial_dim(split_dim)]),
)
gathers: list[dict] = []
def gather(x, *, expected_extent, split_dim, group, dst=None):
gathers.append({"expected_extent": expected_extent, "split_dim": split_dim, "dst": dst})
return x
monkeypatch.setattr(wan_spatial_shard, "gather_and_trim_extent", gather)
vae = SimpleNamespace(decoder=_PlainDecoder())
wan_spatial_shard.install_wan_spatial_shard_decode(vae, object(), split_dim="width", dst=dst)
return vae, gathers
@pytest.mark.core_model
@pytest.mark.cpu
@pytest.mark.parametrize("dst", [0, 1, None])
def test_install_passes_the_assembling_rank_through_to_the_gather(monkeypatch: pytest.MonkeyPatch, dst):
vae, gathers = _install_on_plain_decoder(monkeypatch, dst=dst)
cache = [None]
out = vae.decoder(torch.zeros(1, 3, 1, 4, 6), feat_cache=cache, feat_idx=[0], first_chunk=True)
assert out.shape == (1, 3, 1, 4, 6)
assert gathers == [{"expected_extent": 6, "split_dim": "width", "dst": dst}]
# The streaming arguments reach the wrapped decoder untouched.
assert vae.decoder.calls == [{"feat_cache": cache, "feat_idx": [0], "first_chunk": True}]
assert vae._vllm_omni_wan_spatial_shard_dst == dst
@pytest.mark.core_model
@pytest.mark.cpu
def test_install_refuses_to_change_the_assembling_rank(monkeypatch: pytest.MonkeyPatch):
vae, _ = _install_on_plain_decoder(monkeypatch, dst=None)
# Same settings again: a no-op, as before.
wan_spatial_shard.install_wan_spatial_shard_decode(vae, object(), split_dim="width", dst=None)
with pytest.raises(ValueError, match="already patched to assemble on None"):
wan_spatial_shard.install_wan_spatial_shard_decode(vae, object(), split_dim="width", dst=0)
@pytest.mark.core_model
@pytest.mark.cpu
def test_spatial_shard_height_gate_falls_back_for_partial_group(monkeypatch: pytest.MonkeyPatch):
@@ -626,6 +704,105 @@ def _spatial_shard_decode_worker(rank: int, split_dim: str, return_dict, master_
dist.destroy_process_group()
_STREAMING_SHARD_CHUNKS = 3
def _streaming_shard_worker(rank: int, return_dict, master_port: str) -> None:
"""Sharded streaming decode with every rank keeping the frame, against an unsharded streaming reference.
Two sessions are interleaved chunk by chunk, so the per-session temporal cache
and the halo exchange are exercised across successive calls, then one session
is reset and must reproduce its opening chunk. Every rank checks every chunk.
"""
from vllm_omni.diffusion.distributed.parallel_state import (
destroy_model_parallel,
get_sp_group,
init_distributed_environment,
initialize_model_parallel,
)
from vllm_omni.experimental.ar_diffusion.streaming_decode import WanStreamingDecoder
os.environ["MASTER_ADDR"] = "127.0.0.1"
os.environ["MASTER_PORT"] = master_port
device = current_omni_platform.get_torch_device(rank)
current_omni_platform.set_device(device)
dtype = torch.float32
backend = current_omni_platform.dist_backend
init_distributed_environment(world_size=_SPATIAL_SHARD_WORLD_SIZE, rank=rank, local_rank=rank, backend=backend)
initialize_model_parallel(
sequence_parallel_size=_SPATIAL_SHARD_WORLD_SIZE, ulysses_degree=_SPATIAL_SHARD_WORLD_SIZE, backend=backend
)
# VLLM_OMNI_TEST_WAN_VAE may point at a local diffusers checkpoint (with or
# without a ``vae`` subfolder) for machines without hub access.
model = os.environ.get("VLLM_OMNI_TEST_WAN_VAE", _SPATIAL_SHARD_MODEL)
local_vae_only = os.path.isdir(model) and not os.path.isdir(os.path.join(model, "vae"))
load = {"torch_dtype": dtype} if local_vae_only else {"subfolder": _SPATIAL_SHARD_SUBFOLDER, "torch_dtype": dtype}
try:
reference_vae = DistributedAutoencoderKLWan.from_pretrained(model, **load).to(device=device, dtype=dtype).eval()
sharded_vae = DistributedAutoencoderKLWan.from_pretrained(model, **load).to(device=device, dtype=dtype).eval()
wan_spatial_shard.install_wan_spatial_shard_decode(
sharded_vae, get_sp_group().device_group, split_dim="width", dst=None
)
reference = WanStreamingDecoder(reference_vae, bytes_per_pixel_fp32=1.0)
sharded = WanStreamingDecoder(sharded_vae, bytes_per_pixel_fp32=1.0)
generator = torch.Generator(device=device).manual_seed(0)
# Width 104 latents = 832 px: not divisible by two ranks' halo-padded shards without padding.
shape = (1, reference_vae.config.z_dim, 1, _SPATIAL_SHARD_LATENT_HEIGHT, _SPATIAL_SHARD_LATENT_WIDTH)
chunks = {
name: [
torch.randn(shape, generator=generator, device=device, dtype=dtype)
for _ in range(_STREAMING_SHARD_CHUNKS)
]
for name in ("a", "b")
}
max_diff = 0.0
with torch.inference_mode():
ref_states = {name: reference.new_decode_state(name) for name in chunks}
shard_states = {name: sharded.new_decode_state(name) for name in chunks}
for index in range(_STREAMING_SHARD_CHUNKS):
for name in ("a", "b"):
expected = reference.decode_chunk(chunks[name][index], ref_states[name]).float()
got = sharded.decode_chunk(chunks[name][index], shard_states[name]).float()
if got.shape != expected.shape:
raise AssertionError(
f"rank {rank} {name}[{index}]: {tuple(got.shape)} != {tuple(expected.shape)}"
)
max_diff = max(max_diff, (got - expected).abs().max().item())
# Reset session a: a fresh state must reproduce its opening chunk, on this rank too.
shard_states["a"].release()
ref_states["a"].release()
shard_states["a"] = sharded.new_decode_state("a")
ref_states["a"] = reference.new_decode_state("a")
expected = reference.decode_chunk(chunks["a"][0], ref_states["a"]).float()
got = sharded.decode_chunk(chunks["a"][0], shard_states["a"]).float()
max_diff = max(max_diff, (got - expected).abs().max().item())
return_dict[f"max_abs_diff_rank{rank}"] = max_diff
return_dict[f"shape_rank{rank}"] = tuple(got.shape)
finally:
destroy_model_parallel()
if dist.is_initialized():
dist.destroy_process_group()
@pytest.mark.full_model
@pytest.mark.diffusion
@pytest.mark.parallel
@hardware_test(res={"cuda": ["H100", "B200"]}, num_cards=_SPATIAL_SHARD_WORLD_SIZE)
def test_streaming_shard_decode_matches_unsharded_streaming_on_every_rank():
manager = mp.get_context("spawn").Manager()
return_dict = manager.dict()
mp.spawn(_streaming_shard_worker, args=(return_dict, "29510"), nprocs=_SPATIAL_SHARD_WORLD_SIZE, join=True)
for rank in range(_SPATIAL_SHARD_WORLD_SIZE):
assert f"max_abs_diff_rank{rank}" in return_dict, f"rank {rank} did not report"
diff = return_dict[f"max_abs_diff_rank{rank}"]
shape = return_dict[f"shape_rank{rank}"]
print(f"streaming shard rank {rank}: max_abs_diff={diff:.6e} shape={shape}")
assert shape[-1] == _SPATIAL_SHARD_LATENT_WIDTH * 8 and shape[-2] == _SPATIAL_SHARD_LATENT_HEIGHT * 8
assert diff <= _SPATIAL_SHARD_TOLERANCE, f"rank {rank}: {diff} exceeds {_SPATIAL_SHARD_TOLERANCE}"
@pytest.mark.full_model
@pytest.mark.diffusion
@pytest.mark.parallel