Signed-off-by: lishunyang12 <lishunyang12@users.noreply.github.com> Signed-off-by: Armaan Amatya <armaanamatya2014@gmail.com> Co-authored-by: lishunyang12 <lishunyang12@users.noreply.github.com> Co-authored-by: Armaan Amatya <38102001+armaanamatya@users.noreply.github.com>
128 lines
5.3 KiB
Python
128 lines
5.3 KiB
Python
# SPDX-License-Identifier: Apache-2.0
|
|
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
|
"""Real vLLM projection/collective parity without loading an H3 checkpoint."""
|
|
|
|
from datetime import timedelta
|
|
|
|
import pytest
|
|
import torch
|
|
import torch.multiprocessing as mp
|
|
|
|
from tests.helpers.mark import hardware_marks
|
|
from vllm_omni.platforms import current_omni_platform
|
|
|
|
pytestmark = [pytest.mark.core_model, pytest.mark.diffusion, pytest.mark.cuda]
|
|
|
|
|
|
def _projection_worker(rank, world_size, rendezvous):
|
|
from vllm.config import DeviceConfig, VllmConfig, set_current_vllm_config
|
|
from vllm.distributed.parallel_state import (
|
|
cleanup_dist_env_and_memory,
|
|
init_distributed_environment,
|
|
initialize_model_parallel,
|
|
)
|
|
|
|
from vllm_omni.diffusion.models.minimax_h3.adaln_cache import MiniMaxH3RuntimeAdalnCache
|
|
from vllm_omni.diffusion.models.minimax_h3.minimax_h3_transformer import (
|
|
MiniMaxH3AdalnProj,
|
|
MiniMaxH3DiTArchConfig,
|
|
)
|
|
|
|
torch.set_num_threads(1)
|
|
device = torch.device("cuda", rank)
|
|
current_omni_platform.set_device(device)
|
|
config = VllmConfig(device_config=DeviceConfig(device="cuda"))
|
|
with set_current_vllm_config(config):
|
|
init_distributed_environment(
|
|
world_size=world_size,
|
|
rank=rank,
|
|
local_rank=rank,
|
|
distributed_init_method=f"file://{rendezvous}",
|
|
backend="nccl",
|
|
timeout=timedelta(seconds=45),
|
|
)
|
|
initialize_model_parallel(tensor_model_parallel_size=world_size)
|
|
try:
|
|
arch = MiniMaxH3DiTArchConfig(hidden_size=256, time_embed_dim=128)
|
|
cache = MiniMaxH3RuntimeAdalnCache()
|
|
generator = torch.Generator(device=device).manual_seed(11)
|
|
for name, expansion, modalities in (("blocks.0", 6, 3), ("final_layer", 2, 1)):
|
|
cache.clear()
|
|
projection = MiniMaxH3AdalnProj(
|
|
arch,
|
|
arch.hidden_size * expansion * modalities,
|
|
None,
|
|
expand_ratio=expansion,
|
|
modality_num=modalities,
|
|
prefix=name + ".adaln_proj",
|
|
adaln_cache=cache,
|
|
).to(device)
|
|
with torch.no_grad():
|
|
for parameter in projection.parameters():
|
|
parameter.normal_(std=0.05, generator=generator)
|
|
with torch.inference_mode():
|
|
for width in (1, 2, 3, 4):
|
|
embedding = torch.randn(width, arch.time_embed_dim, device=device, generator=generator)
|
|
# No prepared input: run the original vLLM projector.
|
|
cache.clear()
|
|
expected = projection(embedding)
|
|
cache.prepare(embedding)
|
|
first = projection(embedding)
|
|
hits = cache.hits
|
|
second = projection(embedding)
|
|
assert cache.hits == hits + 1
|
|
for reference, cold, warm in zip(expected, first, second, strict=True):
|
|
assert torch.equal(reference, cold)
|
|
assert torch.equal(reference, warm)
|
|
|
|
# Only one rank loses its entry. All ranks must execute
|
|
# the gather again; a local-only hit would deadlock.
|
|
if rank == world_size - 1:
|
|
cache.clear()
|
|
cache.prepare(embedding)
|
|
misses = cache.misses
|
|
rebuilt = projection(embedding)
|
|
assert cache.misses == misses + 1
|
|
for reference, actual in zip(expected, rebuilt, strict=True):
|
|
assert torch.equal(reference, actual)
|
|
|
|
if rank == world_size - 1:
|
|
projection.linear.weight.add_(0.01)
|
|
misses = cache.misses
|
|
changed = projection(embedding)
|
|
assert cache.misses == misses + 1
|
|
cache.clear()
|
|
reference = projection(embedding)
|
|
for actual, original in zip(changed, reference, strict=True):
|
|
assert torch.equal(actual, original)
|
|
finally:
|
|
cleanup_dist_env_and_memory()
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"world_size",
|
|
[
|
|
pytest.param(1, marks=hardware_marks(res={"cuda": ["H100", "B200"]}, num_cards=1)),
|
|
pytest.param(2, marks=hardware_marks(res={"cuda": ["H100", "B200"]}, num_cards=2)),
|
|
],
|
|
)
|
|
def test_real_projection_cache_parity_and_rank_local_invalidation(tmp_path, world_size):
|
|
if not current_omni_platform.is_cuda():
|
|
pytest.skip("Requires CUDA")
|
|
context = mp.spawn(
|
|
_projection_worker,
|
|
args=(world_size, str(tmp_path / "rendezvous")),
|
|
nprocs=world_size,
|
|
join=False,
|
|
)
|
|
try:
|
|
if not context.join(timeout=90):
|
|
# ProcessContext may reap one successful worker per join.
|
|
if not context.join(timeout=30):
|
|
pytest.fail("AdaLN projection workers timed out")
|
|
finally:
|
|
for process in context.processes:
|
|
if process.is_alive():
|
|
process.terminate()
|
|
process.join(timeout=5)
|