Files
vllm-omni/tests/diffusion/models/cosmos3/test_cosmos3_pipeline.py
T
2026-07-30 11:27:32 +08:00

2309 lines
85 KiB
Python

# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
from __future__ import annotations
import sys
import types
from dataclasses import dataclass
from types import SimpleNamespace
from typing import Any
import numpy as np
import pytest
import torch
from PIL import Image
from torch import nn
from vllm_omni.diffusion.worker.request_batch import DiffusionRequestBatch
from vllm_omni.platforms import current_omni_platform
pytestmark = [pytest.mark.core_model, pytest.mark.cpu, pytest.mark.diffusion]
def test_pipeline_declares_layerwise_offload_components() -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import Cosmos3OmniDiffusersPipeline
assert Cosmos3OmniDiffusersPipeline._dit_modules == ["transformer.language_model", "transformer"]
assert Cosmos3OmniDiffusersPipeline._encoder_modules == []
assert Cosmos3OmniDiffusersPipeline._vae_modules == ["vae"]
assert Cosmos3OmniDiffusersPipeline._resident_modules == []
assert hasattr(Cosmos3OmniDiffusersPipeline, "enable_omni_model_cpu_offload")
class StubScheduler:
def __init__(
self,
timesteps: list[int] | None = None,
*,
flow_shift: float = 1.0,
) -> None:
self.timesteps = torch.tensor(timesteps or [9, 3], dtype=torch.int64)
self.config = SimpleNamespace(
num_train_timesteps=1000,
flow_shift=flow_shift,
)
self.set_timesteps_calls: list[dict[str, Any]] = []
self.step_calls: list[tuple[torch.Tensor, torch.Tensor, torch.Tensor]] = []
def set_timesteps(
self,
num_inference_steps: int | None = None,
device: str | torch.device | None = None,
*,
shift: float | None = None,
sigmas: list[float] | None = None,
) -> None:
self.set_timesteps_calls.append(
{
"num_inference_steps": num_inference_steps,
"device": device,
"shift": shift,
"sigmas": sigmas,
}
)
if sigmas is not None:
self.timesteps = torch.tensor(sigmas, device=device)
else:
assert num_inference_steps is not None
self.timesteps = torch.arange(num_inference_steps, 0, -1, dtype=torch.int64, device=device)
def step(self, noise_pred: torch.Tensor, timestep: torch.Tensor, latents: torch.Tensor, **kwargs):
del kwargs
self.step_calls.append((noise_pred.clone(), timestep.clone(), latents.clone()))
return (latents + noise_pred,)
class _ModeLatentDist:
def __init__(self, latents: torch.Tensor) -> None:
self._latents = latents
def mode(self) -> torch.Tensor:
return self._latents
class StubCosmos3VAE:
dtype = torch.float32
def __init__(self, z_dim: int = 2, *, temporal: int = 4, spatial: int = 8) -> None:
self.config = SimpleNamespace(
z_dim=z_dim,
scale_factor_temporal=temporal,
scale_factor_spatial=spatial,
latents_mean=[0.0] * z_dim,
latents_std=[1.0] * z_dim,
)
self.encode_input_shapes: list[tuple[int, ...]] = []
def encode(self, video: torch.Tensor):
self.encode_input_shapes.append(tuple(video.shape))
latent_frames = (video.shape[2] - 1) // self.config.scale_factor_temporal + 1
latent_height = video.shape[-2] // self.config.scale_factor_spatial
latent_width = video.shape[-1] // self.config.scale_factor_spatial
latents = torch.ones(
video.shape[0],
self.config.z_dim,
latent_frames,
latent_height,
latent_width,
dtype=video.dtype,
device=video.device,
)
return SimpleNamespace(latent_dist=_ModeLatentDist(latents))
def decode(self, latents: torch.Tensor, return_dict: bool = False):
del return_dict
return (latents,)
class StubCosmos3AVAE:
def __init__(self, **kwargs: Any) -> None:
self.kwargs = kwargs
self.sample_rate = int(kwargs["sample_rate"])
self.audio_channels = int(kwargs["audio_channels"])
self.latent_ch = int(kwargs["io_channels"])
self.temporal_compression_factor = int(kwargs["hop_size"])
def get_latent_num_samples(self, num_audio_samples: int) -> int:
return int(num_audio_samples) // self.temporal_compression_factor
def get_audio_num_samples(self, num_latent_samples: int) -> int:
return int(num_latent_samples) * self.temporal_compression_factor
def decode(self, latents: torch.Tensor) -> torch.Tensor:
return torch.zeros(latents.shape[0], self.audio_channels, 8)
class StubCosmos3Transformer(nn.Module):
def __init__(
self,
*,
latent_channel_size: int = 2,
sound_gen: bool = False,
sound_dim: int = 3,
sound_latent_fps: float = 25.0,
action_gen: bool = False,
action_dim: int = 4,
) -> None:
super().__init__()
self.latent_channel_size = latent_channel_size
self.sound_gen = sound_gen
self.sound_dim = sound_dim
self.sound_latent_fps = sound_latent_fps
self.action_gen = action_gen
self.action_dim = action_dim
self.cached_kv: Any | None = None
self.cached_freqs_gen: Any | None = None
self.calls: list[dict[str, Any]] = []
self.reset_calls = 0
def reset_cache(self) -> None:
self.reset_calls += 1
self.cached_kv = None
self.cached_freqs_gen = None
def forward(
self,
*,
hidden_states: torch.Tensor,
timestep: torch.Tensor,
text_ids: torch.Tensor,
text_mask: torch.Tensor,
**kwargs: Any,
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
token = int(text_ids.reshape(-1)[0].item()) if text_ids.numel() else 0
sound_latents = kwargs.get("sound_latents")
control_latents = kwargs.get("control_latents")
control_bonus = 100 if control_latents is not None else 0
self.calls.append(
{
"token": token,
"has_control": control_latents is not None,
"timestep": timestep.clone(),
"text_mask": text_mask.clone(),
"cache_before": self.cached_kv,
"kwargs": dict(kwargs),
}
)
if self.cached_kv is None:
marker = torch.tensor([token], dtype=torch.float32)
self.cached_kv = [(marker, marker + 100)]
self.cached_freqs_gen = (marker + 200, marker + 300)
action_latents = kwargs.get("action_latents")
outputs: list[torch.Tensor] = [torch.full_like(hidden_states, float(token + control_bonus))]
if action_latents is not None:
outputs.append(torch.full_like(action_latents, float(token + 20)))
if sound_latents is not None:
outputs.append(torch.full_like(sound_latents, float(token + 10)))
return outputs[0] if len(outputs) == 1 else tuple(outputs)
def passthrough_progress_bar(iterable):
return iterable
@pytest.fixture(autouse=True)
def fake_cosmos3_guardrails(monkeypatch: pytest.MonkeyPatch):
module = types.ModuleType("vllm_omni.diffusion.models.cosmos3.guardrails")
module.is_guardrails_enabled = lambda od_config, sampling_params=None: False
module.ensure_initialized = lambda od_config: None
module.check_text_safety = lambda text: None
module.check_video_safety = lambda video: video
monkeypatch.setitem(sys.modules, module.__name__, module)
return module
@pytest.fixture
def make_cosmos3_pipeline():
def _make():
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import (
COSMOS3_VIDEO_DEFAULT_FLOW_SHIFT,
Cosmos3OmniDiffusersPipeline,
)
pipeline = object.__new__(Cosmos3OmniDiffusersPipeline)
nn.Module.__init__(pipeline)
pipeline.od_config = SimpleNamespace()
pipeline.device = torch.device("cpu")
pipeline.dtype = torch.float32
pipeline.transformer = StubCosmos3Transformer(latent_channel_size=2)
pipeline.vae = StubCosmos3VAE(z_dim=2)
pipeline.vae_scale_factor_temporal = 4
pipeline.vae_scale_factor_spatial = 8
pipeline.scheduler = StubScheduler([9, 3], flow_shift=1.0)
pipeline._engine_init_flow_shift = COSMOS3_VIDEO_DEFAULT_FLOW_SHIFT
pipeline._current_flow_shift = COSMOS3_VIDEO_DEFAULT_FLOW_SHIFT
pipeline.is_distilled_model = False
pipeline.is_edge_model = False
pipeline._guidance_scale = None
pipeline._num_timesteps = None
pipeline._cosmos3_branch_caches = None
pipeline._cache_dit_requires_paired_cfg = False
pipeline._sound_tokenizer = None
pipeline.progress_bar = passthrough_progress_bar
return pipeline
return _make
@pytest.fixture
def sequential_cfg_parallel(monkeypatch: pytest.MonkeyPatch) -> None:
from vllm_omni.diffusion.distributed import cfg_parallel
monkeypatch.setattr(cfg_parallel, "get_classifier_free_guidance_world_size", lambda: 1)
def make_sampling_params(**overrides: Any) -> SimpleNamespace:
values = {
"height": None,
"width": None,
"num_frames": None,
"num_inference_steps": None,
"guidance_scale": None,
"guidance_scale_provided": False,
"generator": None,
"seed": 123,
"num_outputs_per_prompt": 1,
"frame_rate": None,
"resolved_frame_rate": None,
"max_sequence_length": None,
"extra_args": {},
}
values.update(overrides)
return SimpleNamespace(**values)
def make_request_batch(prompt: Any, sampling_params: SimpleNamespace) -> DiffusionRequestBatch:
if isinstance(prompt, list):
return DiffusionRequestBatch(
requests=[
SimpleNamespace(
prompt=item,
request_id=f"cosmos3-test-{idx}",
sampling_params=sampling_params,
kv_sender_info=None,
)
for idx, item in enumerate(prompt)
]
)
return DiffusionRequestBatch(
requests=[
SimpleNamespace(
prompt=prompt,
request_id="cosmos3-test",
sampling_params=sampling_params,
kv_sender_info=None,
)
]
)
def _ids(value: int) -> torch.Tensor:
return torch.tensor([[value]], dtype=torch.long)
def _mask() -> torch.Tensor:
return torch.ones(1, 1, dtype=torch.long)
def _capture_tokenize_calls(pipeline: Any) -> list[dict[str, Any]]:
calls: list[dict[str, Any]] = []
def _tokenize(
text: str,
max_sequence_length: int,
use_system_prompt: bool = False,
system_prompt: str | None = None,
) -> tuple[torch.Tensor, torch.Tensor]:
index = len(calls) + 1
calls.append(
{
"text": text,
"max_sequence_length": max_sequence_length,
"use_system_prompt": use_system_prompt,
"system_prompt": system_prompt,
}
)
return _ids(index), torch.full((1, 1), index, dtype=torch.long)
pipeline._tokenize_prompt = _tokenize
return calls
@pytest.mark.parametrize(
("provided", "value", "default", "is_distilled", "expected"),
[
(False, 1.0, 7.0, False, 7.0),
(True, 1.0, 7.0, False, 1.0),
(True, 4.5, 7.0, False, 4.5),
(False, 1.0, 7.0, True, 1.0),
(True, 4.5, 7.0, True, 1.0),
],
)
def test_resolve_guidance_scale(
make_cosmos3_pipeline,
provided: bool,
value: float,
default: float,
is_distilled: bool,
expected: float,
) -> None:
pipeline = make_cosmos3_pipeline()
pipeline.is_distilled_model = is_distilled
sp = make_sampling_params(
guidance_scale=value,
guidance_scale_provided=provided,
)
assert pipeline._resolve_guidance_scale(sp, default) == expected
def test_distilled_generation_accepts_t2i_and_i2v(make_cosmos3_pipeline) -> None:
pipeline = make_cosmos3_pipeline()
pipeline.is_distilled_model = True
common = {
"action_enabled": False,
"transfer_config": None,
"is_v2v": False,
"sound_enabled": False,
}
pipeline._validate_distilled_generation_mode(
is_t2i=True,
image_tensor=None,
**common,
)
pipeline._validate_distilled_generation_mode(
is_t2i=False,
image_tensor=torch.zeros(1),
**common,
)
@pytest.mark.parametrize(
("overrides", "message"),
[
({"action_enabled": True}, "action requests are unsupported"),
({"transfer_config": SimpleNamespace()}, "transfer requests are unsupported"),
({"is_v2v": True}, "video-to-video requests are unsupported"),
({"sound_enabled": True}, "sound generation is unsupported"),
(
{"is_t2i": False, "image_tensor": None},
"text-to-video requests are unsupported",
),
(
{"is_t2i": True, "image_tensor": torch.zeros(1)},
"image-conditioned image generation is unsupported",
),
],
)
def test_distilled_generation_rejects_unsupported_modes(
make_cosmos3_pipeline,
overrides: dict[str, Any],
message: str,
) -> None:
pipeline = make_cosmos3_pipeline()
pipeline.is_distilled_model = True
kwargs = {
"is_t2i": True,
"image_tensor": None,
"action_enabled": False,
"transfer_config": None,
"is_v2v": False,
"sound_enabled": False,
}
kwargs.update(overrides)
with pytest.raises(ValueError, match=message):
pipeline._validate_distilled_generation_mode(**kwargs)
def test_distilled_generation_rejects_robolab_policy(make_cosmos3_pipeline) -> None:
pipeline = make_cosmos3_pipeline()
pipeline.is_distilled_model = True
with pytest.raises(ValueError, match="RoboLab/action policy requests are unsupported"):
pipeline._forward_robolab_policy(make_sampling_params(), None, 0.0)
@pytest.mark.parametrize(
("prompt", "sampling_params", "message"),
[
(
{"prompt": "x", "modalities": ["video"], "generate_sound": True},
make_sampling_params(),
"do not support sound generation",
),
(
{"prompt": "x", "modalities": ["video"]},
make_sampling_params(extra_args={"edge": {"control_path": "/tmp/control.mp4"}}),
"do not support transfer inference",
),
(
{
"prompt": "x",
"modalities": ["video"],
"additional_information": {
"preprocessed_video": torch.zeros(1, 3, 5, 16, 16),
},
},
make_sampling_params(height=16, width=16, num_frames=5),
"do not support video-to-video generation",
),
],
)
def test_edge_forward_rejects_unsupported_modes(
make_cosmos3_pipeline,
prompt: dict[str, Any],
sampling_params: SimpleNamespace,
message: str,
) -> None:
pipeline = make_cosmos3_pipeline()
pipeline.is_edge_model = True
with pytest.raises(ValueError, match=message):
pipeline.forward(SimpleNamespace(prompts=[prompt], sampling_params=sampling_params))
def test_pipeline_registered_and_exported() -> None:
from vllm_omni.diffusion.cache.cachedit import CUSTOM_DIT_ENABLERS
from vllm_omni.diffusion.models import cosmos3
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import Cosmos3OmniDiffusersPipeline
from vllm_omni.diffusion.models.progress_bar import ProgressBarMixin
from vllm_omni.diffusion.registry import (
_DIFFUSION_IR_OP_PRIORITY_FUNCS,
_DIFFUSION_MODELS,
_DIFFUSION_POST_PROCESS_FUNCS,
_DIFFUSION_PRE_PROCESS_FUNCS,
)
assert issubclass(Cosmos3OmniDiffusersPipeline, nn.Module)
assert issubclass(Cosmos3OmniDiffusersPipeline, ProgressBarMixin)
assert Cosmos3OmniDiffusersPipeline.support_image_input is True
assert "Cosmos3OmniDiffusersPipeline" in cosmos3.__all__
for pipeline_name in ("Cosmos3OmniDiffusersPipeline", "Cosmos3OmniPipeline"):
assert _DIFFUSION_MODELS[pipeline_name] == (
"cosmos3",
"pipeline_cosmos3",
"Cosmos3OmniDiffusersPipeline",
)
assert _DIFFUSION_PRE_PROCESS_FUNCS[pipeline_name] == "get_cosmos3_pre_process_func"
assert _DIFFUSION_POST_PROCESS_FUNCS[pipeline_name] == "get_cosmos3_post_process_func"
assert _DIFFUSION_IR_OP_PRIORITY_FUNCS[pipeline_name] == "get_cosmos3_ir_op_priority_func"
assert pipeline_name in CUSTOM_DIT_ENABLERS
@pytest.mark.parametrize(
"pipeline_name",
["Cosmos3OmniDiffusersPipeline", "Cosmos3OmniPipeline"],
)
def test_cosmos3_model_index_resolves_pipeline(
tmp_path,
pipeline_name: str,
) -> None:
import json
from vllm_omni.diffusion.data import OmniDiffusionConfig
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import (
Cosmos3OmniDiffusersPipeline,
)
from vllm_omni.diffusion.registry import DiffusionModelRegistry
(tmp_path / "model_index.json").write_text(json.dumps({"_class_name": pipeline_name}))
config = OmniDiffusionConfig(model=str(tmp_path))
config.enrich_config()
assert config.model_class_name == pipeline_name
resolved_pipeline_cls = DiffusionModelRegistry._try_load_model_cls(config.model_class_name)
assert resolved_pipeline_cls is Cosmos3OmniDiffusersPipeline
@pytest.fixture
def stub_real_pipeline_init(monkeypatch: pytest.MonkeyPatch):
from vllm_omni.diffusion.models.cosmos3 import pipeline_cosmos3
class _StubAutoTokenizer:
@classmethod
def from_pretrained(cls, *args, **kwargs):
return SimpleNamespace()
class _StubDiffusersVAE:
config = SimpleNamespace(scale_factor_temporal=4, scale_factor_spatial=8)
@classmethod
def from_pretrained(cls, *args, **kwargs):
return cls()
def to(self, _device):
return self
class _StubDiffusersScheduler:
load_config_calls: list[dict[str, Any]] = []
from_config_calls: list[dict[str, Any]] = []
def __init__(self, *, flow_shift: float = 1.0) -> None:
self.config = SimpleNamespace(flow_shift=flow_shift)
@classmethod
def load_config(cls, *args, **kwargs):
cls.load_config_calls.append({"args": args, "kwargs": dict(kwargs)})
return {
"_class_name": "UniPCMultistepScheduler",
"flow_shift": 1.0,
}
@classmethod
def from_config(cls, config, **kwargs):
cls.from_config_calls.append({"config": config, "kwargs": dict(kwargs)})
return cls(flow_shift=kwargs.get("shift", config.get("flow_shift", 1.0)))
class _StubVideoProcessor:
def __init__(self, *args, **kwargs) -> None:
pass
monkeypatch.setattr(pipeline_cosmos3, "AutoTokenizer", _StubAutoTokenizer)
monkeypatch.setattr(pipeline_cosmos3, "DistributedAutoencoderKLWan", _StubDiffusersVAE)
monkeypatch.setattr(pipeline_cosmos3, "FlowUniPCMultistepScheduler", _StubDiffusersScheduler)
monkeypatch.setattr(pipeline_cosmos3, "VideoProcessor", _StubVideoProcessor)
monkeypatch.setattr(pipeline_cosmos3, "get_local_device", lambda: torch.device("cpu"))
return _StubDiffusersScheduler
def _make_od_config(
*,
sound_gen: bool,
tf_model_config_overrides: dict[str, Any] | None = None,
model_config: dict[str, Any] | None = None,
) -> SimpleNamespace:
tf_model_config = {
"hidden_size": 8,
"num_hidden_layers": 0,
"num_attention_heads": 2,
"num_key_value_heads": 2,
"head_dim": 4,
"intermediate_size": 16,
"vocab_size": 32,
"latent_patch_size": 1,
"latent_channel": 2,
"rope_scaling": {"mrope_section": [1, 1, 0]},
}
if sound_gen:
tf_model_config["sound_gen"] = True
if tf_model_config_overrides:
tf_model_config.update(tf_model_config_overrides)
return SimpleNamespace(
enable_cpu_offload=False,
enable_diffusion_pipeline_profiler=False,
model="/nonexistent/model/path",
dtype=torch.float32,
flow_shift=None,
quantization_config=None,
custom_pipeline_args={},
model_config=model_config or {},
tf_model_config=tf_model_config,
)
def test_pipeline_init_skips_tokenizer_when_sound_disabled(stub_real_pipeline_init) -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import Cosmos3OmniDiffusersPipeline
pipeline = Cosmos3OmniDiffusersPipeline(od_config=_make_od_config(sound_gen=False))
assert pipeline._sound_tokenizer is None
assert pipeline.transformer.sound_gen is False
assert not hasattr(pipeline.transformer, "audio_proj_in")
assert not hasattr(pipeline.transformer, "audio_proj_out")
def test_pipeline_init_uses_flow_unipc_with_cosmos3_defaults(stub_real_pipeline_init) -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import Cosmos3OmniDiffusersPipeline
od_config = _make_od_config(sound_gen=False)
od_config.flow_shift = 2.5
pipeline = Cosmos3OmniDiffusersPipeline(od_config=od_config)
assert len(stub_real_pipeline_init.load_config_calls) == 1
assert len(stub_real_pipeline_init.from_config_calls) == 1
call = stub_real_pipeline_init.from_config_calls[0]
assert call["config"]["_class_name"] == "UniPCMultistepScheduler"
assert call["kwargs"] == {
"shift": 1.0,
"use_dynamic_shifting": False,
"prediction_type": "flow_prediction",
}
assert pipeline.is_distilled_model is False
assert pipeline._engine_init_flow_shift == 2.5
@pytest.mark.parametrize(
("scheduler_class_name", "expected_distilled"),
[
("FlowMatchEulerDiscreteScheduler", True),
("UniPCMultistepScheduler", False),
],
)
def test_pipeline_resolves_scheduler_class_from_checkpoint_file(
tmp_path,
stub_real_pipeline_init,
monkeypatch: pytest.MonkeyPatch,
scheduler_class_name: str,
expected_distilled: bool,
) -> None:
import json
from vllm_omni.diffusion.models.cosmos3 import pipeline_cosmos3
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import Cosmos3OmniDiffusersPipeline
from vllm_omni.diffusion.models.schedulers.scheduling_flow_unipc_multistep import (
FlowUniPCMultistepScheduler as RealFlowUniPCMultistepScheduler,
)
t_list = [1.0, 0.75, 0.5, 0.25]
scheduler_dir = tmp_path / "scheduler"
scheduler_dir.mkdir()
scheduler_config = {"_class_name": scheduler_class_name}
if expected_distilled:
scheduler_config["fixed_step_sampler_config"] = {"sample_type": "sde", "t_list": t_list}
(scheduler_dir / "scheduler_config.json").write_text(json.dumps(scheduler_config))
class StubFlowUniPCScheduler(StubScheduler):
from_config_calls: list[tuple[Any, dict[str, Any]]] = []
@classmethod
def load_config(cls, *args, **kwargs):
return RealFlowUniPCMultistepScheduler.load_config(*args, **kwargs)
@classmethod
def from_config(cls, config, **kwargs):
cls.from_config_calls.append((config, dict(kwargs)))
return cls()
class StubFlowMatchScheduler(StubScheduler):
from_config_calls: list[tuple[Any, dict[str, Any]]] = []
@classmethod
def from_config(cls, config, **kwargs):
cls.from_config_calls.append((config, dict(kwargs)))
scheduler = cls()
scheduler.config.fixed_step_sampler_config = config["fixed_step_sampler_config"]
return scheduler
monkeypatch.setattr(pipeline_cosmos3, "FlowUniPCMultistepScheduler", StubFlowUniPCScheduler)
monkeypatch.setattr(
pipeline_cosmos3,
"FlowMatchEulerDiscreteScheduler",
StubFlowMatchScheduler,
)
od_config = _make_od_config(sound_gen=False)
od_config.model = str(tmp_path)
pipeline = Cosmos3OmniDiffusersPipeline(od_config=od_config)
assert pipeline.is_distilled_model is expected_distilled
if expected_distilled:
assert len(StubFlowMatchScheduler.from_config_calls) == 1
assert StubFlowMatchScheduler.from_config_calls[0][1] == {"stochastic_sampling": True}
assert StubFlowUniPCScheduler.from_config_calls == []
assert pipeline._scheduler_init_t_list == t_list
else:
assert len(StubFlowUniPCScheduler.from_config_calls) == 1
assert StubFlowMatchScheduler.from_config_calls == []
assert not hasattr(pipeline, "_scheduler_init_t_list")
def test_distilled_pipeline_initializes_sde_scheduler(
stub_real_pipeline_init,
monkeypatch: pytest.MonkeyPatch,
) -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import (
Cosmos3OmniDiffusersPipeline,
FlowMatchEulerDiscreteScheduler,
)
t_list = [1.0, 0.9375, 0.8333333333333334, 0.625]
scheduler_config = {
"_class_name": "FlowMatchEulerDiscreteScheduler",
"shift": 1.0,
"stochastic_sampling": False,
"fixed_step_sampler_config": {
"sample_type": "sde",
"t_list": t_list,
},
}
monkeypatch.setattr(
stub_real_pipeline_init,
"load_config",
classmethod(lambda cls, *args, **kwargs: scheduler_config),
)
pipeline = Cosmos3OmniDiffusersPipeline(od_config=_make_od_config(sound_gen=False))
assert pipeline.is_distilled_model is True
assert isinstance(pipeline.scheduler, FlowMatchEulerDiscreteScheduler)
assert pipeline.scheduler.config.stochastic_sampling is True
assert pipeline._scheduler_init_t_list == t_list
@pytest.mark.parametrize(
("fixed_step_config", "error_pattern"),
[
pytest.param(
{"t_list": [1.0, 0.5]},
r"fixed_step_sampler_config\.sample_type=sde",
id="missing-sample-type",
),
pytest.param(
{"sample_type": "ode", "t_list": [1.0, 0.5]},
r"fixed_step_sampler_config\.sample_type=sde",
id="unsupported-sample-type",
),
pytest.param(
{"sample_type": "sde"},
r"non-empty fixed_step_sampler_config\.t_list",
id="missing-t-list",
),
pytest.param(
{"sample_type": "sde", "t_list": []},
r"non-empty fixed_step_sampler_config\.t_list",
id="empty-t-list",
),
],
)
def test_distilled_scheduler_validates_fixed_step_config(
stub_real_pipeline_init,
monkeypatch: pytest.MonkeyPatch,
fixed_step_config: dict[str, Any],
error_pattern: str,
) -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import (
Cosmos3OmniDiffusersPipeline,
)
scheduler_config = {
"_class_name": "FlowMatchEulerDiscreteScheduler",
"fixed_step_sampler_config": fixed_step_config,
}
monkeypatch.setattr(
stub_real_pipeline_init,
"load_config",
classmethod(lambda cls, *args, **kwargs: scheduler_config),
)
with pytest.raises(ValueError, match=error_pattern):
Cosmos3OmniDiffusersPipeline(od_config=_make_od_config(sound_gen=False))
def test_pipeline_init_selects_edge_transformer_from_backbone_type(stub_real_pipeline_init) -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import (
COSMOS3_EDGE_VIDEO_DEFAULT_FLOW_SHIFT,
Cosmos3OmniDiffusersPipeline,
)
from vllm_omni.diffusion.models.cosmos3.transformer_cosmos3_edge import (
COSMOS3_EDGE_BACKBONE_TYPE,
Cosmos3EdgeVFMTransformer,
)
pipeline = Cosmos3OmniDiffusersPipeline(
od_config=_make_od_config(
sound_gen=False,
tf_model_config_overrides={
"backbone_type": COSMOS3_EDGE_BACKBONE_TYPE,
"qk_norm_for_text": False,
"latent_channel": 48,
"latent_patch_size": 2,
"temporal_compression_factor": 4,
"layer_norm_epsilon": 1e-5,
},
)
)
assert isinstance(pipeline.transformer, Cosmos3EdgeVFMTransformer)
assert pipeline.is_edge_model is True
assert pipeline._engine_init_flow_shift == COSMOS3_EDGE_VIDEO_DEFAULT_FLOW_SHIFT
def test_pipeline_init_does_not_select_edge_from_model_index_class_name(stub_real_pipeline_init) -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import Cosmos3OmniDiffusersPipeline
from vllm_omni.diffusion.models.cosmos3.transformer_cosmos3 import Cosmos3VFMTransformer
from vllm_omni.diffusion.models.cosmos3.transformer_cosmos3_edge import Cosmos3EdgeVFMTransformer
pipeline = Cosmos3OmniDiffusersPipeline(
od_config=_make_od_config(
sound_gen=False,
model_config={"_class_name": "Cosmos3EdgeOmniDiffusersPipeline"},
)
)
assert isinstance(pipeline.transformer, Cosmos3VFMTransformer)
assert not isinstance(pipeline.transformer, Cosmos3EdgeVFMTransformer)
def test_flow_unipc_reuses_scheduler_and_forwards_each_request_shift(make_cosmos3_pipeline) -> None:
pipeline = make_cosmos3_pipeline()
scheduler = pipeline.scheduler
assert pipeline._engine_init_flow_shift == 10.0
assert pipeline._current_flow_shift == 10.0
assert scheduler.config.flow_shift == 1.0
for shift in (3.0, 10.0):
pipeline._set_flow_shift(shift)
pipeline._set_timesteps(4, torch.device("cpu"), shift=pipeline._current_flow_shift)
assert pipeline.scheduler is scheduler
assert pipeline._current_flow_shift == 10.0
assert [call["shift"] for call in scheduler.set_timesteps_calls] == [3.0, 10.0]
assert all(call["num_inference_steps"] == 4 for call in scheduler.set_timesteps_calls)
assert all(call["sigmas"] is None for call in scheduler.set_timesteps_calls)
@pytest.mark.skipif(
current_omni_platform.is_rocm(),
reason="Pytorch shipped with vLLM does not built with LAPACK support",
)
def test_flow_unipc_reproducible_with_same_seed(make_cosmos3_pipeline) -> None:
from vllm_omni.diffusion.models.schedulers.scheduling_flow_unipc_multistep import (
FlowUniPCMultistepScheduler,
)
pipeline = make_cosmos3_pipeline()
pipeline.scheduler = FlowUniPCMultistepScheduler(
shift=1.0,
use_dynamic_shifting=False,
prediction_type="flow_prediction",
)
pipeline._format_and_tokenize_prompts = lambda *args, **kwargs: (
_ids(1),
_mask(),
_ids(0),
_mask(),
)
def run(seed: int) -> torch.Tensor:
request = make_request_batch(
{"prompt": "A test video.", "modalities": ["video"]},
make_sampling_params(
seed=seed,
guidance_scale=1.0,
guidance_scale_provided=True,
num_inference_steps=4,
num_frames=5,
height=16,
width=16,
extra_args={"flow_shift": 3.0},
),
)
output = pipeline.forward(request)
return output.output["video"]
first = run(123)
second = run(123)
different_seed = run(456)
torch.testing.assert_close(first, second)
assert not torch.equal(first, different_seed)
def test_distilled_set_timesteps_uses_fixed_sigma_schedule(make_cosmos3_pipeline) -> None:
pipeline = make_cosmos3_pipeline()
pipeline.is_distilled_model = True
pipeline._scheduler_init_t_list = [1.0, 0.75, 0.5, 0.25]
pipeline._set_timesteps(
num_inference_steps=99,
device=torch.device("cpu"),
shift=7.0,
)
assert pipeline.scheduler.set_timesteps_calls == [
{
"num_inference_steps": None,
"device": torch.device("cpu"),
"shift": None,
"sigmas": pipeline._scheduler_init_t_list,
}
]
def test_pipeline_init_passes_tokenizer_attrs_into_transformer(
stub_real_pipeline_init,
monkeypatch: pytest.MonkeyPatch,
) -> None:
from vllm_omni.diffusion.models.cosmos3 import sound_tokenizer
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import Cosmos3OmniDiffusersPipeline
stub_tokenizer = sound_tokenizer.Cosmos3SoundTokenizer(
StubCosmos3AVAE(sample_rate=32000, audio_channels=2, io_channels=5, hop_size=800)
)
monkeypatch.setattr(
sound_tokenizer.Cosmos3SoundTokenizer,
"from_config",
classmethod(lambda cls, od_config: stub_tokenizer),
)
pipeline = Cosmos3OmniDiffusersPipeline(od_config=_make_od_config(sound_gen=True))
assert pipeline._sound_tokenizer is stub_tokenizer
assert pipeline.transformer.sound_gen is True
assert pipeline.transformer.sound_dim == pipeline._sound_tokenizer.latent_ch == 5
assert pipeline.transformer.sound_latent_fps == pipeline._sound_tokenizer.latent_fps == 40.0
assert pipeline.transformer.audio_proj_in.in_features == 5
assert pipeline.transformer.audio_proj_out.out_features == 5
def test_preprocess_i2v_image_and_action_video_inputs() -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import get_cosmos3_pre_process_func
preprocess = get_cosmos3_pre_process_func(SimpleNamespace())
i2v = SimpleNamespace(
prompt={"prompt": "A slow camera push.", "multi_modal_data": {"image": Image.new("RGB", (320, 160))}},
sampling_params=make_sampling_params(height=None, width=None, extra_args={}),
)
result = preprocess(i2v)
assert (result.sampling_params.height, result.sampling_params.width) == (672, 1344)
assert tuple(result.prompt["additional_information"]["preprocessed_image"].shape[-2:]) == (672, 1344)
frames = [Image.new("RGB", (8, 4), color) for color in ("red", "green", "blue")]
action = SimpleNamespace(
prompt={"prompt": "Move.", "multi_modal_data": {"video": frames}},
sampling_params=make_sampling_params(height=16, width=32, extra_args={"action_mode": "forward_dynamics"}),
)
additional = preprocess(action).prompt["additional_information"]
assert tuple(additional["preprocessed_image"].shape) == (1, 3, 16, 32)
assert tuple(additional["preprocessed_video"].shape) == (1, 3, 3, 16, 32)
frames = [Image.new("RGB", (8, 4), color) for color in ("red", "green", "blue", "yellow", "purple", "black")]
v2v = SimpleNamespace(
prompt={"prompt": "Continue.", "multi_modal_data": {"video": frames}},
sampling_params=make_sampling_params(
height=16,
width=32,
extra_args={"condition_frame_indexes_vision": [0, 1], "condition_video_keep": "last"},
),
)
additional = preprocess(v2v).prompt["additional_information"]
assert tuple(additional["preprocessed_video"].shape) == (1, 3, 5, 16, 32)
assert additional["condition_frame_indexes_vision"] == [0, 1]
def test_transfer_config_media_helpers_and_preprocess_budget(monkeypatch: pytest.MonkeyPatch) -> None:
from vllm_omni.diffusion.models.cosmos3 import transfer
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import (
Cosmos3OmniDiffusersPipeline,
get_cosmos3_pre_process_func,
)
cfg = transfer.resolve_transfer_config(make_sampling_params(extra_args={"edge": True}))
assert cfg is not None
assert list(cfg.hints) == ["edge"]
assert cfg.guidance_scale == 3.0
assert cfg.control_guidance == 1.5
assert cfg.flow_shift == 10.0
assert cfg.num_video_frames_per_chunk == 93
assert cfg.share_vision_temporal_positions is True
# fps omitted (no fps/frame_rate on the sampling params) -> wsm preset default (10) applies.
defaulted_fps_cfg = transfer.resolve_transfer_config(make_sampling_params(extra_args={"wsm": True}))
assert defaulted_fps_cfg is not None
assert defaulted_fps_cfg.fps == 10
# fps provided (frame_rate set) -> the user value wins over the preset default.
explicit_fps_cfg = transfer.resolve_transfer_config(make_sampling_params(frame_rate=24.0, extra_args={"wsm": True}))
assert explicit_fps_cfg is not None
assert explicit_fps_cfg.fps == 24.0
assert (
Cosmos3OmniDiffusersPipeline.reference_video_decode_spec(extra_args={"edge": True, "max_frames": 4}).max_frames
== 4
)
frames_for_pad = torch.arange(3 * 3, dtype=torch.uint8).reshape(1, 3, 1, 3)
assert transfer.pad_temporal_frames(frames_for_pad, 5)[0, :, 0, 0].tolist() == [0, 3, 6, 6, 3]
real_import_module = transfer.importlib.import_module
def raise_missing_cv2(name: str, *args: Any, **kwargs: Any):
if name == "cv2":
raise ImportError("missing cv2")
return real_import_module(name, *args, **kwargs)
monkeypatch.setattr(transfer.importlib, "import_module", raise_missing_cv2)
with pytest.raises(ImportError, match="opencv-python"):
transfer.load_or_compute_control_frames(
cfg.hints["edge"],
height=8,
width=8,
max_frames=1,
input_frames=torch.zeros(3, 1, 8, 8, dtype=torch.uint8),
)
precomputed = torch.zeros(3, 2, 8, 8, dtype=torch.uint8)
precomputed_cfg = transfer.resolve_transfer_config(
make_sampling_params(extra_args={"edge": {"control": precomputed}})
)
assert precomputed_cfg is not None
loaded = transfer.load_or_compute_control_frames(
precomputed_cfg.hints["edge"],
height=8,
width=8,
max_frames=2,
input_frames=None,
)
assert tuple(loaded.shape) == (3, 2, 8, 8)
preprocess = get_cosmos3_pre_process_func(SimpleNamespace())
class FramesWithFps(list):
fps = 12.5
frames = FramesWithFps(Image.new("RGB", (8, 4), color) for color in ("red", "green", "blue", "yellow", "black"))
prompt = {"prompt": "transfer", "multi_modal_data": {"video": frames}}
request = SimpleNamespace(
prompt=prompt,
sampling_params=SimpleNamespace(
height=16,
width=32,
extra_args={"edge": True, "max_frames": 4, "resolution": "256"},
),
)
additional = preprocess(request).prompt["additional_information"]
assert (request.sampling_params.height, request.sampling_params.width) == (192, 320)
assert tuple(additional["preprocessed_transfer_video"].shape) == (1, 3, 4, 192, 320)
assert additional["transfer_input_fps"] == 12.5
assert "preprocessed_video" not in additional
def test_transfer_fps_matches_resolved_frame_rate_precedence() -> None:
"""When fps and frame_rate differ, transfer must pick frame_rate -- the same
precedence as OmniDiffusionSamplingParams.resolved_frame_rate. Uses the real
sampling-params dataclass so the resolved_frame_rate property is exercised."""
from vllm_omni.diffusion.models.cosmos3 import transfer
from vllm_omni.inputs.data import OmniDiffusionSamplingParams
sp = OmniDiffusionSamplingParams(fps=24, frame_rate=12.0, extra_args={"edge": True})
assert sp.resolved_frame_rate == 12.0
cfg = transfer.resolve_transfer_config(sp)
assert cfg is not None
# edge has no preset fps default, so cfg.fps comes straight from fps resolution.
assert cfg.fps == sp.resolved_frame_rate == 12.0
def test_transfer_edge_uses_rgb_canny(monkeypatch: pytest.MonkeyPatch) -> None:
from vllm_omni.diffusion.models.cosmos3 import transfer
class FakeCv2:
def __init__(self) -> None:
self.canny_inputs: list[np.ndarray] = []
def Canny(self, image, lower, upper):
assert (lower, upper) == (100, 200)
self.canny_inputs.append(image.copy())
return np.zeros(image.shape[:2], dtype=np.uint8)
fake_cv2 = FakeCv2()
monkeypatch.setattr(transfer, "_import_cv2", lambda _hint_key: fake_cv2)
frames = torch.zeros(3, 1, 4, 5, dtype=torch.uint8)
frames[0] = 255
edge = transfer.make_edge_control(frames, "medium")
assert tuple(edge.shape) == (3, 1, 4, 5)
assert len(fake_cv2.canny_inputs) == 1
assert fake_cv2.canny_inputs[0].shape == (4, 5, 3)
def test_transfer_blur_uses_scaled_bilateral(monkeypatch: pytest.MonkeyPatch) -> None:
from vllm_omni.diffusion.models.cosmos3 import transfer
class FakeCv2:
INTER_AREA = 1
INTER_LINEAR = 2
INTER_CUBIC = 3
def __init__(self) -> None:
self.bilateral_calls: list[tuple[tuple[int, int, int], int, float, float]] = []
def resize(self, image, size, interpolation):
del interpolation
width, height = size
return np.zeros((height, width, image.shape[2]), dtype=image.dtype)
def bilateralFilter(self, image, diameter, sigma_color, sigma_space):
self.bilateral_calls.append((image.shape, diameter, sigma_color, sigma_space))
return image
def GaussianBlur(self, *args, **kwargs):
raise AssertionError("Cosmos3 transfer blur should use bilateralFilter, not GaussianBlur.")
fake_cv2 = FakeCv2()
monkeypatch.setattr(transfer, "_import_cv2", lambda _hint_key: fake_cv2)
frames = torch.zeros(3, 1, 72, 72, dtype=torch.uint8)
blurred = transfer.make_blur_control(frames, "high")
assert tuple(blurred.shape) == (3, 1, 72, 72)
assert fake_cv2.bilateral_calls == [((72, 72, 3), 3, 15.0, 10.0)]
def test_postprocess_handles_image_video_audio_and_validation() -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import get_cosmos3_post_process_func
func = get_cosmos3_post_process_func(SimpleNamespace())
video = torch.zeros(1, 3, 1, 4, 4)
assert func(video, output_type="latent") is video
assert func({"image": video})[0].size == (4, 4)
# Video-only postprocess returns the bare processed video (not a dict),
# matching the image/latent branches and peer audio-capable pipelines.
assert not isinstance(func({"video": video}), dict)
assert (
func(
{"video": video, "audio": torch.ones(1, 2, 16), "audio_sample_rate": 48000},
sampling_params=SimpleNamespace(extra_args={"resolved_frame_rate": 12}),
)["audio_sample_rate"]
== 48000
)
with pytest.raises(ValueError, match="text-to-image postprocess expects"):
func({"image": torch.zeros(1, 3, 2, 4, 4)})
with pytest.raises(ValueError, match="both image and video"):
func({"image": video, "video": video})
def test_action_postprocess_handles_robolab_policy_outputs() -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import (
RoboLabPolicyInputs,
get_cosmos3_post_process_func,
make_robolab_action_postprocess_inputs,
)
func = get_cosmos3_post_process_func(SimpleNamespace())
inputs = RoboLabPolicyInputs(
prompt="Pick the cube.",
video_tensor=torch.zeros(1, 3, 3, 16, 16),
action_tensor=torch.zeros(2, 2),
action_condition_indexes=[0],
action_start_frame_offset=1,
raw_action_dim=2,
domain_id=7,
fps=15.0,
height=16,
width=16,
image_size=None,
num_frames=3,
num_inference_steps=4,
guidance_scale=3.0,
flow_shift=5.0,
seed=11,
history_length=1,
action_space="joint_pos",
observation={},
)
action = torch.tensor([[[0.0, 0.25], [1.0, 0.75]]])
processed = func(
{
"payload": {
"actions": action,
},
"metadata": {
"actions": {
"raw_action_dim": 2,
"action_mode": "policy",
"domain_id": 7,
},
"common": {
"action_only_output": True,
},
"internal": {
"robolab_action_postprocess": make_robolab_action_postprocess_inputs(inputs),
},
},
}
)
processed_action = processed["payload"]["actions"]
assert processed_action.shape == (1, 2)
assert processed_action.dtype == torch.zeros((), dtype=torch.float32).numpy().dtype
torch.testing.assert_close(torch.from_numpy(processed_action), torch.tensor([[1.0, 0.25]]))
assert processed["metadata"] == {
"actions": {
"raw_action_dim": 2,
"action_mode": "policy",
"domain_id": 7,
},
"common": {
"action_only_output": True,
},
}
def test_ir_op_priority_hook_preserves_platform_fields(monkeypatch: pytest.MonkeyPatch) -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import get_cosmos3_ir_op_priority_func
@dataclass
class FakeIrOpPriorityConfig:
rms_norm: list[str]
fused_add_rms_norm: list[str]
custom_op: list[str]
fake_kernel = types.ModuleType("vllm.config.kernel")
fake_kernel.IrOpPriorityConfig = FakeIrOpPriorityConfig
monkeypatch.setitem(sys.modules, fake_kernel.__name__, fake_kernel)
func = get_cosmos3_ir_op_priority_func(SimpleNamespace())
default_priority = FakeIrOpPriorityConfig(
rms_norm=["vllm_c", "native"],
fused_add_rms_norm=["vllm_c", "native"],
custom_op=["platform_kernel", "native"],
)
merged = func(default_priority, vllm_config=SimpleNamespace())
assert merged.rms_norm == ["native"]
assert merged.fused_add_rms_norm == ["native"]
assert merged.custom_op == ["platform_kernel", "native"]
def test_format_and_tokenize_prompts_leaves_plain_prompts_unchanged_by_default(make_cosmos3_pipeline) -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import COSMOS3_SYSTEM_PROMPT
pipeline = make_cosmos3_pipeline()
calls = _capture_tokenize_calls(pipeline)
result = pipeline._format_and_tokenize_prompts(
" A robot. ",
" bad. ",
num_frames=48,
frame_rate=24,
height=720,
width=1280,
max_sequence_length=32,
sp=SimpleNamespace(extra_args={}),
use_system_prompt=False,
is_t2i=False,
)
assert [call["text"] for call in calls] == ["A robot.", "bad."]
assert all(call["max_sequence_length"] == 32 for call in calls)
assert all(call["use_system_prompt"] is False for call in calls)
assert all(call["system_prompt"] == COSMOS3_SYSTEM_PROMPT for call in calls)
assert [tensor.item() for tensor in result] == [1, 1, 2, 2]
def test_format_and_tokenize_prompts_applies_video_templates_and_system_override(make_cosmos3_pipeline) -> None:
pipeline = make_cosmos3_pipeline()
calls = _capture_tokenize_calls(pipeline)
pipeline._format_and_tokenize_prompts(
"A robot",
"bad",
num_frames=48,
frame_rate=24,
height=720,
width=1280,
max_sequence_length=32,
sp=SimpleNamespace(
system_prompt="direct system prompt",
extra_args={
"use_duration_template": True,
"use_resolution_template": True,
"system_prompt": "API system prompt",
},
),
use_system_prompt=True,
is_t2i=False,
)
assert calls == [
{
"text": ("A robot. The video is 2.0 seconds long and is of 24 FPS. This video is of 720x1280 resolution."),
"max_sequence_length": 32,
"use_system_prompt": True,
"system_prompt": "API system prompt",
},
{
"text": (
"bad. The video is not 2.0 seconds long and is not of 24 FPS. This video is not of 720x1280 resolution."
),
"max_sequence_length": 32,
"use_system_prompt": True,
"system_prompt": "API system prompt",
},
]
def test_format_and_tokenize_prompts_uses_image_templates_for_t2i(make_cosmos3_pipeline) -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import COSMOS3_T2I_SYSTEM_PROMPT
pipeline = make_cosmos3_pipeline()
calls = _capture_tokenize_calls(pipeline)
pipeline._format_and_tokenize_prompts(
"A robot",
"bad",
num_frames=1,
frame_rate=24,
height=1024,
width=768,
max_sequence_length=64,
sp=SimpleNamespace(
extra_args={
"use_duration_template": True,
"use_resolution_template": True,
}
),
use_system_prompt=True,
is_t2i=True,
)
assert [call["text"] for call in calls] == [
"A robot. This image is of 1024x768 resolution.",
"bad. This image is not of 1024x768 resolution.",
]
assert all("seconds" not in call["text"] and "FPS" not in call["text"] for call in calls)
assert all(call["system_prompt"] == COSMOS3_T2I_SYSTEM_PROMPT for call in calls)
def test_format_and_tokenize_prompts_rewrites_json_object_metadata(make_cosmos3_pipeline) -> None:
import json
pipeline = make_cosmos3_pipeline()
calls = _capture_tokenize_calls(pipeline)
pipeline._format_and_tokenize_prompts(
('{"caption": "A robot", "duration": "old", "fps": 1, "resolution": {"H": 1, "W": 2}, "aspect_ratio": "1:1"}'),
"bad",
num_frames=48,
frame_rate=24,
height=720,
width=1280,
max_sequence_length=32,
sp=SimpleNamespace(
extra_args={
"aspect_ratio": "16:9",
"use_duration_template": True,
"use_resolution_template": True,
}
),
is_t2i=False,
)
assert json.loads(calls[0]["text"]) == {
"caption": "A robot",
"duration": "2s",
"fps": 24.0,
"resolution": {"H": 720, "W": 1280},
"aspect_ratio": "16:9",
}
assert "The video is 2.0 seconds long" not in calls[0]["text"]
assert calls[1]["text"] == (
"bad. The video is not 2.0 seconds long and is not of 24 FPS. This video is not of 720x1280 resolution."
)
def test_format_and_tokenize_prompts_removes_video_metadata_from_t2i_json(make_cosmos3_pipeline) -> None:
import json
pipeline = make_cosmos3_pipeline()
calls = _capture_tokenize_calls(pipeline)
pipeline._format_and_tokenize_prompts(
'{"caption": "A robot", "duration": "2s", "fps": 24}',
"",
num_frames=1,
frame_rate=24,
height=1024,
width=768,
max_sequence_length=32,
sp=SimpleNamespace(extra_args={}),
is_t2i=True,
)
assert json.loads(calls[0]["text"]) == {
"caption": "A robot",
"resolution": {"H": 1024, "W": 768},
}
@pytest.mark.parametrize(
"prompt",
[
"{malformed",
'["A robot"]',
],
)
def test_format_and_tokenize_prompts_falls_back_for_non_object_json(
make_cosmos3_pipeline,
prompt: str,
) -> None:
pipeline = make_cosmos3_pipeline()
calls = _capture_tokenize_calls(pipeline)
pipeline._format_and_tokenize_prompts(
prompt,
"",
num_frames=48,
frame_rate=24,
height=720,
width=1280,
max_sequence_length=32,
sp=SimpleNamespace(
extra_args={
"use_duration_template": True,
"use_resolution_template": True,
}
),
is_t2i=False,
)
assert calls[0]["text"] == (
f"{prompt}. The video is 2.0 seconds long and is of 24 FPS. This video is of 720x1280 resolution."
)
def test_checkpoint_key_remap() -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import Cosmos3OmniDiffusersPipeline
remaps = {
"embed_tokens.weight": "transformer.language_model.embed_tokens.weight",
"model.embed_tokens.weight": "transformer.language_model.embed_tokens.weight",
"norm.weight": "transformer.language_model.norm.weight",
"norm_moe_gen.weight": "transformer.norm_moe_gen.weight",
"proj_in.weight": "transformer.proj_in.weight",
"proj_out.bias": "transformer.proj_out.bias",
"layers.3.self_attn.to_q.weight": "transformer.language_model.layers.3.self_attn.to_q.weight",
"layers.3.self_attn.to_out.weight": "transformer.language_model.layers.3.self_attn.to_out.weight",
"layers.3.self_attn.norm_q.weight": "transformer.language_model.layers.3.self_attn.norm_q.weight",
"layers.3.self_attn.k_norm_und_for_gen.weight": (
"transformer.language_model.layers.3.self_attn.k_norm_und_for_gen.weight"
),
"layers.3.self_attn.add_q_proj.weight": "transformer.gen_layers.3.cross_attention.to_q.weight",
"layers.3.self_attn.to_add_out.weight": "transformer.gen_layers.3.cross_attention.to_out.weight",
"layers.3.self_attn.norm_added_q.weight": "transformer.gen_layers.3.cross_attention.norm_q.weight",
"layers.3.mlp_moe_gen.up_proj.weight": "transformer.gen_layers.3.mlp.up_proj.weight",
"layers.3.mlp_moe_gen.down_proj.weight": "transformer.gen_layers.3.mlp.down_proj.weight",
"transformer.model.layers.3.self_attn.add_k_proj.weight": (
"transformer.gen_layers.3.cross_attention.to_k.weight"
),
}
assert {key: Cosmos3OmniDiffusersPipeline._remap_ckpt_key(key) for key in remaps} == remaps
def test_prepare_latents_for_video_image_sound_and_action(make_cosmos3_pipeline) -> None:
pipeline = make_cosmos3_pipeline()
latents = pipeline._prepare_latents(16, 24, 5, torch.Generator(device="cpu").manual_seed(0))
assert latents.shape == (1, 2, 2, 2, 3)
pipeline._encode_conditioning_image_latent = lambda *args, **kwargs: torch.full((1, 2, 1, 2, 3), 5.0)
i2v_latents, velocity_mask, image_latent = pipeline._prepare_latents_i2v(
torch.zeros(1, 3, 16, 24), 16, 24, 5, torch.Generator(device="cpu").manual_seed(0)
)
torch.testing.assert_close(i2v_latents[:, :, 0], torch.full((1, 2, 2, 3), 5.0))
assert velocity_mask.tolist() == [[[[[0.0]], [[1.0]]]]]
assert image_latent.shape == (1, 2, 1, 2, 3)
pipeline._encode_video_tensor = lambda *args, **kwargs: torch.full((1, 2, 3, 2, 3), 6.0)
v2v_latents, v2v_velocity_mask, v2v_condition = pipeline._prepare_latents_v2v(
torch.zeros(1, 3, 5, 16, 24),
16,
24,
9,
torch.Generator(device="cpu").manual_seed(0),
[0, 1],
)
torch.testing.assert_close(v2v_latents[:, :, 0:2], torch.full((1, 2, 2, 2, 3), 6.0))
assert v2v_velocity_mask.tolist() == [[[[[0.0]], [[0.0]], [[1.0]]]]]
assert v2v_condition.shape == (1, 2, 3, 2, 3)
pipeline.transformer = pipeline.transformer.__class__(latent_channel_size=2, sound_gen=True, sound_dim=3)
pipeline._sound_tokenizer = SimpleNamespace(
sample_rate=10,
latent_ch=3,
hop_size=4,
decode=lambda x: torch.ones(x.shape[0], 2, 24),
)
assert pipeline._resolve_sound_target_samples(SimpleNamespace(extra_args={"sound_duration": 2.0}), 9, 3.0) == (
20,
2.0,
10,
)
sound_latents, latent_frames = pipeline._prepare_sound_latents(21, torch.Generator(device="cpu").manual_seed(0))
assert (sound_latents.shape, latent_frames) == (torch.Size([1, 3, 6]), 6)
assert pipeline._decode_sound_latents(torch.zeros(1, 3, 6), target_audio_samples=21).shape == (1, 2, 21)
pipeline.transformer = pipeline.transformer.__class__(action_gen=True, action_dim=4)
action, action_mask, clean, raw_dim = pipeline._prepare_action_latents(
mode="forward_dynamics",
action_chunk_size=2,
raw_action_dim=None,
generator=torch.Generator(device="cpu").manual_seed(0),
sp=SimpleNamespace(extra_args={"action": [[1.0, 2.0], [3.0, 4.0]]}),
)
assert raw_dim == 2
assert action_mask.tolist() == [[[0.0], [0.0]]]
torch.testing.assert_close(action, clean)
def test_prepare_latents_i2v_encodes_only_conditioning_frame(make_cosmos3_pipeline) -> None:
pipeline = make_cosmos3_pipeline()
calls: list[tuple[str, tuple[int, ...]]] = []
def record_to_vae_device(tensor: torch.Tensor, *, pin_cpu: bool = False) -> torch.Tensor:
assert pin_cpu is True
calls.append(("to_vae_device", tuple(tensor.shape)))
return tensor
class RecordingVAE(StubCosmos3VAE):
def encode(self, video: torch.Tensor):
calls.append(("encode", tuple(video.shape)))
return super().encode(video)
pipeline._to_vae_device = record_to_vae_device
pipeline.vae = RecordingVAE(z_dim=2)
generator = torch.Generator(device="cpu").manual_seed(0)
latents, velocity_mask, image_latent = pipeline._prepare_latents_i2v(
torch.zeros(1, 3, 16, 24),
16,
24,
9,
generator,
)
assert calls == [
("to_vae_device", (1, 3, 16, 24)),
("encode", (1, 3, 1, 16, 24)),
]
assert pipeline.vae.encode_input_shapes[-1] == (1, 3, 1, 16, 24)
assert latents.shape == (1, 2, 3, 2, 3)
assert image_latent.shape == (1, 2, 1, 2, 3)
torch.testing.assert_close(latents[:, :, 0:1], image_latent)
assert not torch.allclose(latents[:, :, 1:], image_latent.expand(-1, -1, 2, -1, -1))
assert velocity_mask.tolist() == [[[[[0.0]], [[1.0]], [[1.0]]]]]
@pytest.mark.parametrize("mode", ["policy", "forward_dynamics"])
def test_prepare_action_video_latents_encodes_only_conditioning_frame(make_cosmos3_pipeline, mode: str) -> None:
pipeline = make_cosmos3_pipeline()
video = torch.zeros(1, 3, 9, 24, 32)
latents, velocity_mask, condition_latents = pipeline._prepare_latents_action_video(
video,
mode,
24,
32,
9,
torch.Generator(device="cpu").manual_seed(0),
image_size=torch.tensor([1, 3, 16, 24]),
)
assert pipeline.vae.encode_input_shapes == [(1, 3, 1, 24, 32)]
assert latents.shape == (1, 2, 3, 2, 3)
assert condition_latents.shape == latents.shape
torch.testing.assert_close(condition_latents[:, :, 0], torch.ones(1, 2, 2, 3))
assert torch.count_nonzero(condition_latents[:, :, 1:]) == 0
torch.testing.assert_close(latents[:, :, 0:1], condition_latents[:, :, 0:1])
assert velocity_mask.tolist() == [[[[[0.0]], [[1.0]], [[1.0]]]]]
def test_prepare_inverse_dynamics_latents_encodes_full_video(make_cosmos3_pipeline) -> None:
pipeline = make_cosmos3_pipeline()
video = torch.zeros(1, 3, 9, 16, 24)
latents, velocity_mask, condition_latents = pipeline._prepare_latents_action_video(
video,
"inverse_dynamics",
16,
24,
9,
torch.Generator(device="cpu").manual_seed(0),
)
assert pipeline.vae.encode_input_shapes == [(1, 3, 9, 16, 24)]
assert condition_latents.shape == (1, 2, 3, 2, 3)
torch.testing.assert_close(latents, condition_latents)
assert torch.count_nonzero(velocity_mask) == 0
def test_diffuse_covers_cfg_i2v_and_multimodal_steps(make_cosmos3_pipeline) -> None:
pipeline = make_cosmos3_pipeline()
latents = torch.zeros(1, 2, 1, 1, 1)
result = pipeline.diffuse(
latents=latents,
timesteps=torch.tensor([900, 100]),
cond_ids=_ids(2),
cond_mask=_mask(),
uncond_ids=_ids(1),
uncond_mask=_mask(),
guidance_scale=3.0,
shared_kwargs={"video_shape": (1, 1, 1), "fps": 24.0},
guidance_interval=(500.0, 1000.0),
)
assert [call["token"] for call in pipeline.transformer.calls] == [2, 1, 2]
torch.testing.assert_close(result, torch.full_like(latents, 6.0))
i2v = pipeline.diffuse(
latents=torch.zeros(1, 2, 2, 1, 1),
timesteps=torch.tensor([7]),
cond_ids=_ids(2),
cond_mask=_mask(),
uncond_ids=_ids(1),
uncond_mask=_mask(),
guidance_scale=1.0,
shared_kwargs={"video_shape": (2, 1, 1), "fps": 24.0},
velocity_mask=torch.tensor([[[[[0.0]], [[1.0]]]]]),
image_latent=torch.full((1, 2, 1, 1, 1), 7.0),
)
torch.testing.assert_close(i2v[:, :, 0:1], torch.full((1, 2, 1, 1, 1), 7.0))
i2v_noise = pipeline.scheduler.step_calls[-1][0]
torch.testing.assert_close(i2v_noise[:, :, 0:1], torch.zeros(1, 2, 1, 1, 1))
torch.testing.assert_close(i2v_noise[:, :, 1:2], torch.full((1, 2, 1, 1, 1), 2.0))
pipeline.transformer = pipeline.transformer.__class__(latent_channel_size=2, action_gen=True, action_dim=4)
video_result, action_result = pipeline.diffuse(
latents=latents,
action_latents=torch.zeros(1, 3, 4),
action_velocity_mask=torch.ones(1, 3, 1),
action_condition_latents=torch.zeros(1, 3, 4),
timesteps=torch.tensor([7, 3]),
cond_ids=_ids(2),
cond_mask=_mask(),
uncond_ids=_ids(1),
uncond_mask=_mask(),
guidance_scale=1.0,
shared_kwargs={"video_shape": (1, 1, 1), "fps": 24.0, "action_domain_ids": torch.tensor([0])},
)
torch.testing.assert_close(video_result, torch.full_like(latents, 4.0))
torch.testing.assert_close(action_result, torch.full((), 44.0).expand_as(action_result))
def test_diffuse_transfer_applies_control_cfg(make_cosmos3_pipeline, sequential_cfg_parallel) -> None:
pipeline = make_cosmos3_pipeline()
latents = torch.zeros(1, 2, 1, 1, 1)
velocity_mask = torch.ones(1, 1, 1, 1, 1)
result = pipeline.diffuse_transfer(
latents=latents,
timesteps=torch.tensor([7]),
cond_ids=_ids(2),
cond_mask=_mask(),
uncond_ids=_ids(1),
uncond_mask=_mask(),
guidance_scale=3.0,
control_guidance=1.5,
control_guidance_interval=None,
control_latents=[torch.zeros_like(latents)],
shared_kwargs={"video_shape": (1, 1, 1), "fps": 24.0, "noisy_frame_mask": velocity_mask},
velocity_mask=velocity_mask,
condition_latents=torch.zeros_like(latents),
)
assert [(call["token"], call["has_control"]) for call in pipeline.transformer.calls] == [
(2, True),
(2, False),
(1, True),
]
torch.testing.assert_close(result, torch.full_like(latents, 254.0))
def test_diffuse_transfer_skips_idle_cfg_branches(make_cosmos3_pipeline, sequential_cfg_parallel) -> None:
latents = torch.zeros(1, 2, 1, 1, 1)
velocity_mask = torch.ones(1, 1, 1, 1, 1)
control_only = make_cosmos3_pipeline()
control_result = control_only.diffuse_transfer(
latents=latents,
timesteps=torch.tensor([7]),
cond_ids=_ids(2),
cond_mask=_mask(),
uncond_ids=_ids(1),
uncond_mask=_mask(),
guidance_scale=1.0,
control_guidance=1.5,
control_guidance_interval=None,
control_latents=[torch.zeros_like(latents)],
shared_kwargs={"video_shape": (1, 1, 1), "fps": 24.0, "noisy_frame_mask": velocity_mask},
velocity_mask=velocity_mask,
condition_latents=torch.zeros_like(latents),
)
assert [(call["token"], call["has_control"]) for call in control_only.transformer.calls] == [
(2, True),
(2, False),
]
torch.testing.assert_close(control_result, torch.full_like(latents, 152.0))
text_only = make_cosmos3_pipeline()
text_result = text_only.diffuse_transfer(
latents=latents,
timesteps=torch.tensor([7]),
cond_ids=_ids(2),
cond_mask=_mask(),
uncond_ids=_ids(1),
uncond_mask=_mask(),
guidance_scale=3.0,
control_guidance=1.0,
control_guidance_interval=None,
control_latents=[torch.zeros_like(latents)],
shared_kwargs={"video_shape": (1, 1, 1), "fps": 24.0, "noisy_frame_mask": velocity_mask},
velocity_mask=velocity_mask,
condition_latents=torch.zeros_like(latents),
)
assert [(call["token"], call["has_control"]) for call in text_only.transformer.calls] == [
(2, True),
(1, True),
]
torch.testing.assert_close(text_result, torch.full_like(latents, 104.0))
def test_diffuse_transfer_interval_switches_branch_counts(make_cosmos3_pipeline, sequential_cfg_parallel) -> None:
pipeline = make_cosmos3_pipeline()
latents = torch.zeros(1, 2, 1, 1, 1)
velocity_mask = torch.ones(1, 1, 1, 1, 1)
result = pipeline.diffuse_transfer(
latents=latents,
timesteps=torch.tensor([900, 500, 100]),
cond_ids=_ids(2),
cond_mask=_mask(),
uncond_ids=_ids(1),
uncond_mask=_mask(),
guidance_scale=3.0,
control_guidance=1.5,
control_guidance_interval=(400.0, 1000.0),
control_latents=[torch.zeros_like(latents)],
shared_kwargs={"video_shape": (1, 1, 1), "fps": 24.0, "noisy_frame_mask": velocity_mask},
velocity_mask=velocity_mask,
condition_latents=torch.zeros_like(latents),
guidance_interval=(800.0, 1000.0),
)
assert [(call["token"], call["has_control"]) for call in pipeline.transformer.calls] == [
(2, True),
(2, False),
(1, True),
(2, True),
(2, False),
(2, True),
]
torch.testing.assert_close(result, torch.full_like(latents, 508.0))
@pytest.mark.parametrize(("hint_key", "expected_fps"), [("edge", 8.0), ("wsm", 10.0)])
def test_forward_transfer_uses_source_fps_except_wsm(make_cosmos3_pipeline, hint_key: str, expected_fps: float) -> None:
pipeline = make_cosmos3_pipeline()
captured: dict[str, Any] = {}
def fake_format(prompt, negative_prompt, num_frames, frame_rate, height, width, *args, **kwargs):
del prompt, negative_prompt, num_frames, height, width, args, kwargs
captured["format_frame_rate"] = frame_rate
return _ids(2), _mask(), _ids(1), _mask()
def fake_encode(video: torch.Tensor) -> torch.Tensor:
latent_frames = (video.shape[2] - 1) // pipeline.vae_scale_factor_temporal + 1
return torch.ones(
1,
2,
latent_frames,
max(1, video.shape[-2] // pipeline.vae_scale_factor_spatial),
max(1, video.shape[-1] // pipeline.vae_scale_factor_spatial),
)
def fake_prepare(target_norm, current_conditional_frames, generator):
del current_conditional_frames, generator
latent = fake_encode(target_norm)
velocity_mask = torch.ones(1, 1, latent.shape[2], 1, 1)
return torch.zeros_like(latent), velocity_mask, torch.zeros_like(latent)
def fake_diffuse_transfer(**kwargs):
captured["shared_kwargs"] = kwargs["shared_kwargs"]
return kwargs["latents"]
pipeline._transfer_bucket_size = lambda sp, source_hw: (16, 16)
pipeline._format_and_tokenize_prompts = fake_format
pipeline._encode_video_tensor = fake_encode
pipeline._prepare_transfer_latents = fake_prepare
pipeline.diffuse_transfer = fake_diffuse_transfer
def fake_set_flow_shift(target):
captured.setdefault("flow_shifts", []).append(target)
pipeline._current_flow_shift = float(target)
pipeline._set_flow_shift = fake_set_flow_shift
pipeline._decode_latents = lambda latents: torch.zeros(1, 3, 5, 16, 16, device="meta")
control = torch.zeros(3, 5, 16, 16, dtype=torch.uint8)
request = SimpleNamespace(
prompts=[
{
"prompt": "transfer",
"modalities": ["video"],
"additional_information": {
"preprocessed_transfer_video": torch.zeros(1, 3, 5, 16, 16),
"transfer_input_fps": 8.0,
},
}
],
sampling_params=make_sampling_params(
height=16,
width=16,
# fps omitted (no frame_rate) -> non-wsm uses the source video fps (8), wsm uses its preset (10).
extra_args={
hint_key: {"control": control},
"max_frames": 5,
"num_video_frames_per_chunk": 5,
"show_control_condition": True,
},
),
)
output = pipeline.forward(request)
assert captured["format_frame_rate"] == expected_fps
assert captured["shared_kwargs"]["fps"] == expected_fps
assert captured["flow_shifts"] == [10.0]
# Transfer applies the V2V flow shift when building its timestep schedule.
assert [call["shift"] for call in pipeline.scheduler.set_timesteps_calls] == [10.0]
assert output.output["metadata"]["video"]["fps"] == expected_fps
assert output.output["payload"]["video"].device.type == "meta"
def test_forward_transfer_runs_multichunk_overlap_path(
make_cosmos3_pipeline,
sequential_cfg_parallel,
) -> None:
pipeline = make_cosmos3_pipeline()
captured: dict[str, Any] = {"targets": [], "conditional_frames": []}
pipeline._transfer_bucket_size = lambda sp, source_hw: (16, 16)
pipeline._format_and_tokenize_prompts = lambda *args, **kwargs: (_ids(2), _mask(), _ids(1), _mask())
pipeline._set_flow_shift = lambda target, **_kwargs: captured.setdefault("flow_shifts", []).append(target)
original_prepare = pipeline._prepare_transfer_latents
def recording_prepare(target_norm, current_conditional_frames, generator):
captured["targets"].append(target_norm.detach().clone())
captured["conditional_frames"].append(current_conditional_frames)
return original_prepare(target_norm, current_conditional_frames, generator)
pipeline._prepare_transfer_latents = recording_prepare
decoded_chunks = [
torch.tensor([-0.6, -0.5, -0.4, -0.3, -0.2], dtype=torch.float32),
torch.tensor([0.1, 0.2, 0.3, 0.4, 0.5], dtype=torch.float32),
]
def fake_decode(latents):
chunk_values = decoded_chunks[len(captured.setdefault("decode_calls", []))]
captured["decode_calls"].append(latents.detach().clone())
return chunk_values.view(1, 1, 5, 1, 1).expand(1, 3, 5, 16, 16).clone()
pipeline._decode_latents = fake_decode
transfer_video = torch.zeros(1, 3, 8, 16, 16)
transfer_video[:, :, 1] = 1.0
control = torch.zeros(3, 8, 16, 16, dtype=torch.uint8)
request = SimpleNamespace(
prompts=[
{
"prompt": "transfer",
"modalities": ["video"],
"additional_information": {
"preprocessed_transfer_video": transfer_video,
"transfer_input_fps": 8.0,
},
}
],
sampling_params=make_sampling_params(
height=16,
width=16,
num_inference_steps=1,
guidance_scale=1.0,
extra_args={
"edge": {"control": control},
"control_guidance": 1.0,
"max_frames": 8,
"num_video_frames_per_chunk": 5,
"num_conditional_frames": 1,
"num_first_chunk_conditional_frames": 2,
},
),
)
output = pipeline.forward(request)
assert captured["conditional_frames"] == [2, 1]
assert len(captured["decode_calls"]) == 2
assert output.output["payload"]["video"].shape == (1, 3, 8, 16, 16)
torch.testing.assert_close(
output.output["payload"]["video"][0, 0, :, 0, 0],
torch.tensor([-0.6, -0.5, -0.4, -0.3, -0.2, 0.2, 0.3, 0.4]),
)
assert output.output["metadata"]["transfer"]["controls"]["edge"].shape == (1, 3, 8, 16, 16)
torch.testing.assert_close(captured["targets"][0][:, :, 0], torch.full((1, 3, 16, 16), -1.0))
torch.testing.assert_close(captured["targets"][0][:, :, 1], torch.full((1, 3, 16, 16), 1.0))
torch.testing.assert_close(captured["targets"][0][:, :, 2:], torch.full((1, 3, 3, 16, 16), 1.0))
torch.testing.assert_close(captured["targets"][1][:, :, 0], torch.full((1, 3, 16, 16), -0.2))
def test_diffuse_keeps_paired_cfg_when_cache_dit_active(make_cosmos3_pipeline) -> None:
"""With cache-dit active the uncond pass is kept even outside the guidance
interval (so cache-dit's has_separate_cfg parity stays in phase), and the
output is numerically identical to the skip path.
Contrast with ``test_diffuse_covers_cfg_and_i2v_steps`` (no marker), where
the same inputs skip the out-of-interval uncond pass: calls == [2, 1, 2].
"""
pipeline = make_cosmos3_pipeline()
# Marker normally set by ``enable_cache_for_cosmos3`` when cache-dit is on.
pipeline._cache_dit_requires_paired_cfg = True
latents = torch.zeros(1, 2, 1, 1, 1)
result = pipeline.diffuse(
latents=latents,
timesteps=torch.tensor([900, 100]),
cond_ids=_ids(2),
cond_mask=_mask(),
uncond_ids=_ids(1),
uncond_mask=_mask(),
guidance_scale=3.0,
shared_kwargs={"video_shape": (1, 1, 1), "fps": 24.0},
guidance_interval=(500.0, 1000.0),
)
# t=900 is inside the interval (cond+uncond); t=100 is outside but the
# uncond pass is still issued -> paired cond/uncond at every step.
assert [call["token"] for call in pipeline.transformer.calls] == [2, 1, 2, 1]
# Identical result to the skip path: out-of-interval combine uses scale=1.0,
# so combine_cfg_noise(cond=2, uncond=1, 1.0) == 2 == the skipped cond value.
torch.testing.assert_close(result, torch.full_like(latents, 6.0))
class TestForwardRouting:
def _install_forward_stubs(self, pipeline):
captured: dict[str, object] = {"diffuse_calls": [], "prepare_calls": []}
def fake_format(
prompt,
negative_prompt,
num_frames,
frame_rate,
height,
width,
max_sequence_length,
sp,
use_system_prompt=False,
is_t2i=False,
):
captured["format"] = {
"prompt": prompt,
"negative_prompt": negative_prompt,
"num_frames": num_frames,
"frame_rate": frame_rate,
"height": height,
"width": width,
"use_system_prompt": use_system_prompt,
"is_t2i": is_t2i,
}
return _ids(2), _mask(), _ids(1), _mask()
def fake_prepare(height, width, num_frames, generator):
captured["prepare_calls"].append((height, width, num_frames, generator.initial_seed()))
return torch.zeros(1, 2, 1, 1, 1)
def fake_diffuse(**kwargs):
captured["diffuse_calls"].append(kwargs)
outputs = [kwargs["latents"] + len(captured["diffuse_calls"])]
if kwargs.get("action_latents") is not None:
outputs.append(kwargs["action_latents"] + 3.0)
if kwargs.get("sound_latents") is not None:
outputs.append(kwargs["sound_latents"] + 2.0)
return outputs[0] if len(outputs) == 1 else tuple(outputs)
pipeline._format_and_tokenize_prompts = fake_format
pipeline._prepare_latents = fake_prepare
def fake_set_flow_shift(target):
captured.setdefault("flow_shifts", []).append(target)
pipeline._current_flow_shift = float(target)
pipeline._set_flow_shift = fake_set_flow_shift
pipeline.diffuse = fake_diffuse
pipeline._decode_latents = lambda latents: latents
return captured
@pytest.mark.parametrize(
("prompt", "sampling_params", "expected"),
[
(
{"prompt": "A painted robot", "modalities": ["image"]},
make_sampling_params(num_outputs_per_prompt=2),
{
"key": "image",
"is_t2i": True,
"flow": [3.0],
"steps": [50, 50],
"frames": 1,
},
),
(
"A warehouse robot",
make_sampling_params(),
{
"key": "video",
"is_t2i": False,
"flow": [10.0],
"steps": [35],
"frames": 189,
},
),
],
)
def test_forward_defaults_and_mode_selection(
self,
make_cosmos3_pipeline,
prompt,
sampling_params,
expected,
) -> None:
pipeline = make_cosmos3_pipeline()
captured = self._install_forward_stubs(pipeline)
output = pipeline.forward(make_request_batch(prompt, sampling_params))
assert expected["key"] in output.output
assert captured["format"]["is_t2i"] is expected["is_t2i"]
assert captured["format"]["num_frames"] == expected["frames"]
assert captured["flow_shifts"] == expected["flow"]
assert [call["num_inference_steps"] for call in pipeline.scheduler.set_timesteps_calls] == expected["steps"]
assert all(call["shift"] == expected["flow"][0] for call in pipeline.scheduler.set_timesteps_calls)
def test_forward_i2v_sound_and_action_routes(self, make_cosmos3_pipeline) -> None:
pipeline = make_cosmos3_pipeline()
captured = self._install_forward_stubs(pipeline)
image_tensor = torch.zeros(1, 3, 16, 16)
velocity_mask = torch.ones(1, 1, 1, 1, 1)
pipeline._prepare_latents_i2v = lambda *args, **kwargs: (
torch.zeros(1, 2, 1, 1, 1),
velocity_mask,
torch.zeros(1, 2, 1, 1, 1),
)
pipeline.forward(
make_request_batch(
{
"prompt": "move",
"modalities": ["video"],
"additional_information": {"preprocessed_image": image_tensor},
},
make_sampling_params(height=16, width=16, num_frames=5),
)
)
assert captured["diffuse_calls"][-1]["shared_kwargs"]["noisy_frame_mask"] is velocity_mask
video_tensor = torch.zeros(1, 3, 5, 16, 16)
v2v_condition = torch.full((1, 2, 2, 1, 1), 4.0)
v2v_mask = torch.tensor([[[[[0.0]], [[1.0]]]]])
pipeline._prepare_latents_v2v = lambda *args, **kwargs: (
torch.zeros(1, 2, 2, 1, 1),
v2v_mask,
v2v_condition,
)
pipeline.forward(
make_request_batch(
{
"prompt": "continue",
"modalities": ["video"],
"additional_information": {
"preprocessed_video": video_tensor,
"condition_frame_indexes_vision": [0],
},
},
make_sampling_params(height=16, width=16, num_frames=5),
)
)
assert captured["flow_shifts"][-1] == 10.0
assert captured["format"]["negative_prompt"] == ""
assert captured["diffuse_calls"][-1]["shared_kwargs"]["noisy_frame_mask"] is v2v_mask
assert captured["diffuse_calls"][-1]["condition_latents"] is v2v_condition
pipeline.transformer = pipeline.transformer.__class__(latent_channel_size=2, sound_gen=True, sound_dim=3)
sound_latents = torch.zeros(1, 3, 4)
pipeline._resolve_sound_target_samples = lambda *args: (20, 2.0, 10)
pipeline._prepare_sound_latents = lambda *args, **kwargs: (sound_latents, 4)
pipeline._decode_sound_latents = lambda *args: torch.ones(1, 2, 20)
output = pipeline.forward(
make_request_batch(
{"prompt": "A robot", "modalities": ["video"], "generate_sound": True},
make_sampling_params(num_frames=9, frame_rate=3.0),
)
)
assert captured["diffuse_calls"][-1]["sound_latents"] is sound_latents
assert output.output["audio_sample_rate"] == 10
pipeline.transformer = pipeline.transformer.__class__(latent_channel_size=2, action_gen=True, action_dim=4)
output = pipeline.forward(
make_request_batch(
{
"prompt": "Pick the block.",
"modalities": ["video"],
"additional_information": {"preprocessed_image": image_tensor},
},
make_sampling_params(
height=16,
width=16,
extra_args={
"action_mode": "policy",
"action_chunk_size": 2,
"raw_action_dim": 2,
"domain_name": "bridge_orig_lerobot",
},
),
)
)
assert captured["diffuse_calls"][-1]["shared_kwargs"]["action_domain_ids"].tolist() == [7]
assert output.output["payload"]["actions"].shape == (1, 2, 2)
assert output.output["metadata"]["actions"] == {
"raw_action_dim": 2,
"action_mode": "policy",
"domain_id": 7,
}
assert "common" not in output.output["metadata"]
def test_forward_dispatches_robolab_policy_flow(
self,
make_cosmos3_pipeline,
monkeypatch: pytest.MonkeyPatch,
) -> None:
from vllm_omni.diffusion.models.cosmos3 import pipeline_cosmos3
pipeline = make_cosmos3_pipeline()
pipeline.transformer = pipeline.transformer.__class__(latent_channel_size=2, action_gen=True, action_dim=4)
captured = self._install_forward_stubs(pipeline)
video_latents = torch.zeros(1, 2, 1, 1, 1)
velocity_mask = torch.ones(1, 1, 1, 1, 1)
condition_latents = torch.zeros_like(video_latents)
inputs = pipeline_cosmos3.RoboLabPolicyInputs(
prompt="Pick the cube.",
video_tensor=torch.zeros(1, 3, 3, 16, 16),
action_tensor=torch.zeros(2, 2),
action_condition_indexes=[0],
action_start_frame_offset=1,
raw_action_dim=2,
domain_id=7,
fps=15.0,
height=16,
width=16,
image_size=None,
num_frames=3,
num_inference_steps=4,
guidance_scale=3.0,
flow_shift=5.0,
seed=11,
history_length=1,
action_space="joint_pos",
observation={},
)
def fake_prepare_action_latents(**kwargs):
captured["prepare_action"] = kwargs
action_chunk_size = kwargs["action_chunk_size"]
raw_action_dim = int(kwargs["raw_action_dim"])
return (
torch.zeros(1, action_chunk_size, 4),
torch.ones(1, action_chunk_size, 1),
torch.zeros(1, action_chunk_size, 4),
raw_action_dim,
)
def fake_prepare_action_video(*args, **kwargs):
captured["prepare_action_video"] = {"args": args, "kwargs": kwargs}
return video_latents, velocity_mask, condition_latents
monkeypatch.setattr(
pipeline_cosmos3,
"build_robolab_unipc_scheduler",
lambda num_steps, shift, device: StubScheduler(list(range(num_steps, 0, -1)), flow_shift=shift),
)
pipeline._build_robolab_policy_inputs = lambda sp, prompt_data, request_id=None: inputs
pipeline._prepare_action_latents = fake_prepare_action_latents
pipeline._prepare_latents_action_video = fake_prepare_action_video
pipeline._decode_latents = lambda latents: (_ for _ in ()).throw(
AssertionError("RoboLab should not decode video")
)
output = pipeline.forward(make_request_batch("ignored", make_sampling_params()))
assert captured["format"] == {
"prompt": "Pick the cube.",
"negative_prompt": "",
"num_frames": 3,
"frame_rate": 15.0,
"height": 16,
"width": 16,
"use_system_prompt": False,
"is_t2i": False,
}
assert "flow_shifts" not in captured
assert pipeline.scheduler.set_timesteps_calls == []
assert captured["prepare_action"]["clean_action"] is inputs.action_tensor
assert captured["prepare_action"]["condition_indexes"] == [0]
assert captured["prepare_action_video"]["kwargs"] == {"image_size": None}
assert captured["diffuse_calls"][-1]["shared_kwargs"]["action_domain_ids"].tolist() == [7]
assert captured["diffuse_calls"][-1]["timesteps"].tolist() == [4, 3, 2, 1]
assert output.output["payload"]["actions"].shape == (1, 2, 2)
assert output.output["metadata"]["actions"] == {
"raw_action_dim": 2,
"action_mode": "policy",
"domain_id": 7,
}
assert output.output["metadata"]["common"]["action_only_output"] is True
assert "robolab_action_postprocess" in output.output["metadata"]["internal"]
assert "robolab_policy_inputs" not in output.output["metadata"]
@pytest.mark.parametrize(
("prompt", "sampling_params", "message"),
[
(["one", "two"], make_sampling_params(), "single prompt"),
({"prompt": "one", "modalities": ["image", "video"]}, make_sampling_params(), "both image and video"),
(
{"prompt": "x", "modalities": ["image"], "generate_sound": True},
make_sampling_params(),
"only for video",
),
(
{"prompt": "x", "modalities": ["image"]},
make_sampling_params(extra_args={"edge": {"control_path": "/tmp/control.mp4"}}),
"transfer inference is supported only for video outputs",
),
(
{"prompt": "x", "modalities": ["video"], "generate_sound": True},
make_sampling_params(extra_args={"edge": {"control_path": "/tmp/control.mp4"}}),
"cannot be combined with sound generation",
),
(
{"prompt": "x", "modalities": ["video"]},
make_sampling_params(
extra_args={
"edge": {"control_path": "/tmp/control.mp4"},
"action_mode": "policy",
}
),
"cannot be combined with action generation",
),
],
)
def test_forward_rejects_invalid_public_requests(
self,
make_cosmos3_pipeline,
prompt,
sampling_params,
message,
) -> None:
pipeline = make_cosmos3_pipeline()
pipeline.transformer = pipeline.transformer.__class__(latent_channel_size=2, sound_gen=True, sound_dim=3)
with pytest.raises(ValueError, match=message):
pipeline.forward(make_request_batch(prompt, sampling_params))