Files
vllm-omni/tests/diffusion/models/cosmos3/test_cosmos3_pipeline.py
T

2652 lines
97 KiB
Python
Raw Normal View History

2026-06-01 22:04:31 +02:00
# 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
2026-06-01 22:04:31 +02:00
from types import SimpleNamespace
from typing import Any
2026-06-21 03:59:18 +02:00
import numpy as np
2026-06-01 22:04:31 +02:00
import pytest
import torch
from PIL import Image
from torch import nn
from vllm_omni.diffusion.worker.request_batch import DiffusionRequestBatch
from vllm_omni.experimental.world_models.session_state import SessionStateManager
2026-06-01 22:04:31 +02:00
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")
2026-06-01 22:04:31 +02:00
class StubScheduler:
2026-06-24 03:03:34 +02:00
def __init__(
self,
timesteps: list[int] | None = None,
*,
flow_shift: float = 1.0,
) -> None:
2026-06-01 22:04:31 +02:00
self.timesteps = torch.tensor(timesteps or [9, 3], dtype=torch.int64)
2026-06-24 03:03:34 +02:00
self.config = SimpleNamespace(
num_train_timesteps=1000,
flow_shift=flow_shift,
)
self.set_timesteps_calls: list[dict[str, Any]] = []
2026-06-01 22:04:31 +02:00
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)
2026-06-01 22:04:31 +02:00
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, ...]] = []
2026-06-01 22:04:31 +02:00
def encode(self, video: torch.Tensor):
self.encode_input_shapes.append(tuple(video.shape))
2026-06-01 22:04:31 +02:00
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,)
2026-06-03 02:51:44 +02:00
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)
2026-06-01 22:04:31 +02:00
class StubCosmos3Transformer(nn.Module):
def __init__(
self,
*,
latent_channel_size: int = 2,
2026-06-03 02:51:44 +02:00
sound_gen: bool = False,
sound_dim: int = 3,
sound_latent_fps: float = 25.0,
2026-06-03 21:30:39 +02:00
action_gen: bool = False,
action_dim: int = 4,
2026-06-01 22:04:31 +02:00
) -> None:
super().__init__()
self.latent_channel_size = latent_channel_size
2026-06-03 02:51:44 +02:00
self.sound_gen = sound_gen
self.sound_dim = sound_dim
self.sound_latent_fps = sound_latent_fps
2026-06-03 21:30:39 +02:00
self.action_gen = action_gen
self.action_dim = action_dim
2026-06-01 22:04:31 +02:00
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,
2026-06-03 02:51:44 +02:00
) -> torch.Tensor | tuple[torch.Tensor, torch.Tensor]:
2026-06-01 22:04:31 +02:00
token = int(text_ids.reshape(-1)[0].item()) if text_ids.numel() else 0
2026-06-03 02:51:44 +02:00
sound_latents = kwargs.get("sound_latents")
2026-06-21 03:59:18 +02:00
control_latents = kwargs.get("control_latents")
control_bonus = 100 if control_latents is not None else 0
2026-06-01 22:04:31 +02:00
self.calls.append(
{
"token": token,
2026-06-21 03:59:18 +02:00
"has_control": control_latents is not None,
2026-06-01 22:04:31 +02:00
"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)
2026-06-03 21:30:39 +02:00
action_latents = kwargs.get("action_latents")
2026-06-21 03:59:18 +02:00
outputs: list[torch.Tensor] = [torch.full_like(hidden_states, float(token + control_bonus))]
2026-06-03 21:30:39 +02:00
if action_latents is not None:
outputs.append(torch.full_like(action_latents, float(token + 20)))
2026-06-03 02:51:44 +02:00
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)
2026-06-01 22:04:31 +02:00
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,
2026-06-01 22:04:31 +02:00
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
2026-06-01 22:04:31 +02:00
pipeline._guidance_scale = None
pipeline._num_timesteps = None
2026-06-21 03:59:18 +02:00
pipeline._cosmos3_branch_caches = None
2026-06-01 22:04:31 +02:00
pipeline._cache_dit_requires_paired_cfg = False
2026-06-03 02:51:44 +02:00
pipeline._sound_tokenizer = None
2026-06-01 22:04:31 +02:00
pipeline.progress_bar = passthrough_progress_bar
return pipeline
return _make
2026-06-21 03:59:18 +02:00
@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)
2026-06-01 22:04:31 +02:00
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,
2026-06-01 22:04:31 +02:00
"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,
)
]
)
2026-06-01 22:04:31 +02:00
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)
def test_forward_threads_request_id_to_robolab(make_cosmos3_pipeline) -> None:
pipeline = make_cosmos3_pipeline()
robolab_inputs = object()
captured: dict[str, Any] = {}
expected = object()
pipeline._build_robolab_policy_inputs = lambda sp, prompt, request_id: robolab_inputs
def fake_forward_robolab(sp, inputs, pipeline_start, session_id=None):
del sp, inputs, pipeline_start
captured["session_id"] = session_id
return expected
pipeline._forward_robolab_policy = fake_forward_robolab
request = SimpleNamespace(
prompts=["policy"],
sampling_params=make_sampling_params(),
request_id="robolab-request-7",
)
assert pipeline.forward(request) is expected
assert captured["session_id"] == "robolab-request-7"
@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))
2026-06-01 22:04:31 +02:00
def test_pipeline_registered_and_exported() -> None:
from vllm_omni.diffusion.cache.cachedit import CUSTOM_DIT_ENABLERS
2026-06-01 22:04:31 +02:00
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,
2026-06-01 22:04:31 +02:00
_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
2026-06-01 22:04:31 +02:00
2026-06-03 02:51:44 +02:00
@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]] = []
2026-06-21 16:20:30 +02:00
from_config_calls: list[dict[str, Any]] = []
def __init__(self, *, flow_shift: float = 1.0) -> None:
self.config = SimpleNamespace(flow_shift=flow_shift)
2026-06-03 02:51:44 +02:00
@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,
}
2026-06-03 02:51:44 +02:00
2026-06-21 16:20:30 +02:00
@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)))
2026-06-21 16:20:30 +02:00
2026-06-03 02:51:44 +02:00
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)
2026-06-03 02:51:44 +02:00
monkeypatch.setattr(pipeline_cosmos3, "VideoProcessor", _StubVideoProcessor)
monkeypatch.setattr(pipeline_cosmos3, "get_local_device", lambda: torch.device("cpu"))
2026-06-21 16:20:30 +02:00
return _StubDiffusersScheduler
2026-06-03 02:51:44 +02:00
def _make_od_config(
*,
sound_gen: bool,
tf_model_config_overrides: dict[str, Any] | None = None,
model_config: dict[str, Any] | None = None,
) -> SimpleNamespace:
2026-06-03 02:51:44 +02:00
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)
2026-06-03 02:51:44 +02:00
return SimpleNamespace(
enable_cpu_offload=False,
enable_diffusion_pipeline_profiler=False,
enable_session_state_manager=False,
2026-06-03 02:51:44 +02:00
model="/nonexistent/model/path",
dtype=torch.float32,
flow_shift=None,
quantization_config=None,
custom_pipeline_args={},
model_config=model_config or {},
2026-06-03 02:51:44 +02:00
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:
2026-06-21 16:20:30 +02:00
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
2026-06-21 16:20:30 +02:00
assert pipeline._engine_init_flow_shift == 2.5
2026-06-24 03:03:34 +02:00
@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,
2026-06-24 03:03:34 +02:00
monkeypatch: pytest.MonkeyPatch,
scheduler_class_name: str,
expected_distilled: bool,
2026-06-24 03:03:34 +02:00
) -> None:
import json
2026-06-24 03:03:34 +02:00
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,
)
2026-06-24 03:03:34 +02:00
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))
2026-06-24 03:03:34 +02:00
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)
2026-06-24 03:03:34 +02:00
@classmethod
def from_config(cls, config, **kwargs):
cls.from_config_calls.append((config, dict(kwargs)))
return cls()
2026-06-24 03:03:34 +02:00
class StubFlowMatchScheduler(StubScheduler):
from_config_calls: list[tuple[Any, dict[str, Any]]] = []
2026-06-24 03:03:34 +02:00
@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,
},
2026-06-24 03:03:34 +02:00
}
monkeypatch.setattr(
stub_real_pipeline_init,
"load_config",
classmethod(lambda cls, *args, **kwargs: scheduler_config),
)
2026-06-24 03:03:34 +02:00
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
2026-06-24 03:03:34 +02:00
@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)
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,
}
]
2026-06-21 16:20:30 +02:00
2026-06-03 02:51:44 +02:00
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
2026-06-03 21:30:39 +02:00
def test_preprocess_i2v_image_and_action_video_inputs() -> None:
2026-06-01 22:04:31 +02:00
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={}),
2026-06-01 22:04:31 +02:00
)
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)
2026-06-01 22:04:31 +02:00
2026-06-03 21:30:39 +02:00
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"}),
2026-06-03 21:30:39 +02:00
)
additional = preprocess(action).prompt["additional_information"]
2026-06-03 21:30:39 +02:00
assert tuple(additional["preprocessed_image"].shape) == (1, 3, 16, 32)
assert tuple(additional["preprocessed_video"].shape) == (1, 3, 3, 16, 32)
2026-06-08 21:04:05 +02:00
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(
2026-06-08 21:04:05 +02:00
height=16,
width=32,
extra_args={"condition_frame_indexes_vision": [0, 1], "condition_video_keep": "last"},
),
)
additional = preprocess(v2v).prompt["additional_information"]
2026-06-08 21:04:05 +02:00
assert tuple(additional["preprocessed_video"].shape) == (1, 3, 5, 16, 32)
assert additional["condition_frame_indexes_vision"] == [0, 1]
2026-06-01 22:04:31 +02:00
2026-06-21 03:59:18 +02:00
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"]
2026-08-20 20:40:51 +02:00
assert cfg.hints["edge"].control_weight == 1.0
assert cfg.normalized_control_weights == [1.0]
2026-06-21 03:59:18 +02:00
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
2026-08-20 20:40:51 +02:00
assert cfg.emphasize_control_in_prompt is True
prompt_ablation_cfg = transfer.resolve_transfer_config(
make_sampling_params(extra_args={"edge": True, "emphasize_control_in_prompt": False})
)
assert prompt_ablation_cfg is not None
assert prompt_ablation_cfg.emphasize_control_in_prompt is False
2026-06-21 03:59:18 +02:00
# 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}}
2026-06-21 03:59:18 +02:00
request = SimpleNamespace(
prompt=prompt,
2026-06-21 03:59:18 +02:00
sampling_params=SimpleNamespace(
height=16,
width=32,
extra_args={"edge": True, "max_frames": 4, "resolution": "256"},
),
)
additional = preprocess(request).prompt["additional_information"]
2026-06-21 03:59:18 +02:00
assert (request.sampling_params.height, request.sampling_params.width) == (192, 320)
assert request.sampling_params.extra_args["_cosmos3_transfer_requested_size"] == {"width": 32, "height": 16}
2026-06-21 03:59:18 +02:00
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
2026-08-20 20:40:51 +02:00
def test_transfer_control_weight_validation_and_normalization() -> None:
from vllm_omni.diffusion.models.cosmos3 import transfer
single = transfer.resolve_transfer_config(make_sampling_params(extra_args={"edge": {"control_weight": 0.4}}))
assert single is not None
assert single.hints["edge"].control_weight == 0.4
assert single.normalized_control_weights == [1.0]
multiple = transfer.resolve_transfer_config(
make_sampling_params(
extra_args={
"edge": {"control_weight": 1.0},
"depth": {"control_weight": 3.0, "control": torch.zeros(3, 1, 8, 8, dtype=torch.uint8)},
}
)
)
assert multiple is not None
assert multiple.normalized_control_weights == [0.25, 0.75]
with pytest.raises(ValueError, match="Unsupported.*weight"):
transfer.resolve_transfer_config(make_sampling_params(extra_args={"edge": {"weight": 0.5}}))
with pytest.raises(ValueError, match="finite and non-negative"):
transfer.resolve_transfer_config(make_sampling_params(extra_args={"edge": {"control_weight": -0.5}}))
with pytest.raises(ValueError, match="positive sum"):
transfer.resolve_transfer_config(
make_sampling_params(
extra_args={
"edge": {"control_weight": 0.0},
"depth": {"control_weight": 0.0, "control": torch.zeros(3, 1, 8, 8, dtype=torch.uint8)},
}
)
)
2026-06-21 03:59:18 +02:00
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)]
2026-06-03 02:51:44 +02:00
def test_postprocess_handles_image_video_audio_and_validation() -> None:
2026-06-01 22:04:31 +02:00
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)
2026-06-03 02:51:44 +02:00
# 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
)
2026-06-01 22:04:31 +02:00
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
2026-06-01 22:04:31 +02:00
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)
2026-06-01 22:04:31 +02:00
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",
},
]
2026-08-20 20:40:51 +02:00
def test_format_and_tokenize_prompts_applies_transfer_prompt_contract(make_cosmos3_pipeline) -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import (
COSMOS3_TRANSFER_CONTROL_DIRECTIVE_TEMPLATE,
COSMOS3_TRANSFER_SYSTEM_PROMPT,
)
pipeline = make_cosmos3_pipeline()
calls = _capture_tokenize_calls(pipeline)
directive = COSMOS3_TRANSFER_CONTROL_DIRECTIVE_TEMPLATE.format(hint_names="edge")
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_resolution_template": True,
"system_prompt": "request-level system prompt",
}
),
use_system_prompt=True,
is_t2i=False,
system_prompt=COSMOS3_TRANSFER_SYSTEM_PROMPT,
prompt_suffix=directive,
use_duration_template=True,
use_resolution_template=True,
negative_metadata_mode="same",
)
metadata = "The video is 2.0 seconds long and is of 24 FPS. This video is of 720x1280 resolution."
assert calls[0]["text"] == f"A robot. {metadata} {directive}"
assert calls[1]["text"] == f"bad. {metadata}"
assert all(call["use_system_prompt"] is True for call in calls)
assert all(call["system_prompt"] == COSMOS3_TRANSFER_SYSTEM_PROMPT for call in calls)
def test_format_and_tokenize_prompts_rejects_unknown_negative_metadata_mode(make_cosmos3_pipeline) -> None:
pipeline = make_cosmos3_pipeline()
with pytest.raises(ValueError, match="negative_metadata_mode"):
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={}),
negative_metadata_mode="unexpected",
)
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,
2026-06-01 22:04:31 +02:00
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,
}
),
2026-06-01 22:04:31 +02:00
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_transfer_aspect_ratio_override(make_cosmos3_pipeline) -> None:
import json
pipeline = make_cosmos3_pipeline()
calls = _capture_tokenize_calls(pipeline)
pipeline._format_and_tokenize_prompts(
'{"caption": "A robot", "aspect_ratio": "4,3"}',
"",
num_frames=48,
frame_rate=24,
height=480,
width=832,
max_sequence_length=32,
sp=SimpleNamespace(extra_args={"aspect_ratio": "4:3"}),
is_t2i=False,
aspect_ratio_override="16,9",
)
assert json.loads(calls[0]["text"])["aspect_ratio"] == "16,9"
@pytest.mark.parametrize("rank_zero", [True, False])
def test_format_and_tokenize_prompts_corrects_conflicting_aspect_ratio_metadata_on_every_rank(
make_cosmos3_pipeline,
monkeypatch: pytest.MonkeyPatch,
mocker,
rank_zero: bool,
) -> None:
import json
from vllm_omni.diffusion.models.cosmos3 import pipeline_cosmos3
pipeline = make_cosmos3_pipeline()
calls = _capture_tokenize_calls(pipeline)
monkeypatch.setattr(pipeline_cosmos3, "_is_rank_zero", lambda: rank_zero)
warning = mocker.patch.object(pipeline_cosmos3.logger, "warning")
pipeline._format_and_tokenize_prompts(
'{"caption": "A robot", "aspect_ratio": "4,3"}',
"",
num_frames=48,
frame_rate=24,
height=720,
width=1280,
max_sequence_length=32,
sp=SimpleNamespace(extra_args={}),
is_t2i=False,
)
assert json.loads(calls[0]["text"])["aspect_ratio"] == "16,9"
if rank_zero:
rendered_warning = warning.call_args.args[0] % warning.call_args.args[1:]
assert "JSON prompt aspect_ratio='4,3' conflicts with the generated 1280x720 canvas" in rendered_warning
else:
warning.assert_not_called()
@pytest.mark.parametrize(
("width", "height", "aspect_ratio"),
[
(1104, 816, "4,3"),
(832, 468, "16,9"),
],
)
def test_format_and_tokenize_prompts_keeps_nearest_canonical_aspect_ratio(
make_cosmos3_pipeline,
mocker,
width: int,
height: int,
aspect_ratio: str,
) -> None:
import json
from vllm_omni.diffusion.models.cosmos3 import pipeline_cosmos3
pipeline = make_cosmos3_pipeline()
calls = _capture_tokenize_calls(pipeline)
warning = mocker.patch.object(pipeline_cosmos3.logger, "warning")
pipeline._format_and_tokenize_prompts(
json.dumps({"caption": "A robot", "aspect_ratio": aspect_ratio}),
"",
num_frames=48,
frame_rate=24,
height=height,
width=width,
max_sequence_length=32,
sp=SimpleNamespace(extra_args={}),
is_t2i=False,
)
assert json.loads(calls[0]["text"])["aspect_ratio"] == aspect_ratio
warning.assert_not_called()
def test_transfer_bucket_selection_warns_on_size_and_aspect_ratio_conflicts(
make_cosmos3_pipeline,
mocker,
) -> None:
from vllm_omni.diffusion.models.cosmos3 import pipeline_cosmos3
pipeline = make_cosmos3_pipeline()
warning = mocker.patch.object(pipeline_cosmos3.logger, "warning")
sp = make_sampling_params(
width=832,
height=480,
extra_args={
"resolution": "480",
"aspect_ratio": "4:3",
"_cosmos3_transfer_requested_size": {"width": 1280, "height": 720},
},
)
height, width, aspect_ratio = pipeline._transfer_bucket_size(sp, (480, 832))
assert (height, width, aspect_ratio) == (480, 832, "16,9")
pipeline._warn_transfer_bucket_conflicts(
sp,
"A transfer prompt",
source_hw=(480, 832),
height=height,
width=width,
aspect_ratio=aspect_ratio,
)
rendered_warnings = [call.args[0] % call.args[1:] for call in warning.call_args_list]
assert any("ignores requested size=1280x720 (WxH)" in message for message in rendered_warnings)
assert any(
"requested aspect_ratio='4:3' conflicts with the control-selected 16,9 bucket" in message
for message in rendered_warnings
)
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
2026-06-01 22:04:31 +02:00
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"
),
2026-06-01 22:04:31 +02:00
"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",
2026-06-01 22:04:31 +02:00
"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
2026-06-03 21:30:39 +02:00
def test_prepare_latents_for_video_image_sound_and_action(make_cosmos3_pipeline) -> None:
2026-06-01 22:04:31 +02:00
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)
2026-06-01 22:04:31 +02:00
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)
2026-06-08 21:04:05 +02:00
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)
2026-06-03 02:51:44 +02:00
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)
2026-06-01 22:04:31 +02:00
2026-06-03 21:30:39 +02:00
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)
2026-06-03 02:51:44 +02:00
2026-06-03 21:30:39 +02:00
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
2026-06-03 21:30:39 +02:00
def test_diffuse_covers_cfg_i2v_and_multimodal_steps(make_cosmos3_pipeline) -> None:
2026-06-01 22:04:31 +02:00
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))
2026-06-01 22:04:31 +02:00
2026-06-03 21:30:39 +02:00
pipeline.transformer = pipeline.transformer.__class__(latent_channel_size=2, action_gen=True, action_dim=4)
video_result, action_result = pipeline.diffuse(
2026-06-03 02:51:44 +02:00
latents=latents,
2026-06-03 21:30:39 +02:00
action_latents=torch.zeros(1, 3, 4),
action_velocity_mask=torch.ones(1, 3, 1),
action_condition_latents=torch.zeros(1, 3, 4),
2026-06-03 02:51:44 +02:00
timesteps=torch.tensor([7, 3]),
cond_ids=_ids(2),
cond_mask=_mask(),
uncond_ids=_ids(1),
uncond_mask=_mask(),
guidance_scale=1.0,
2026-06-03 21:30:39 +02:00
shared_kwargs={"video_shape": (1, 1, 1), "fps": 24.0, "action_domain_ids": torch.tensor([0])},
2026-06-03 02:51:44 +02:00
)
torch.testing.assert_close(video_result, torch.full_like(latents, 4.0))
2026-06-03 21:30:39 +02:00
torch.testing.assert_close(action_result, torch.full((), 44.0).expand_as(action_result))
2026-06-03 02:51:44 +02:00
2026-06-01 22:04:31 +02:00
def test_diffuse_drops_session_when_progress_iteration_fails(make_cosmos3_pipeline) -> None:
pipeline = make_cosmos3_pipeline()
pipeline._use_session_state = True
pipeline._memory_manager = SessionStateManager()
class FailingProgress:
def __iter__(self):
raise RuntimeError("progress failed before first step")
pipeline.progress_bar = lambda timesteps: FailingProgress()
with pytest.raises(RuntimeError, match="progress failed"):
pipeline.diffuse(
latents=torch.zeros(1, 2, 1, 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": (1, 1, 1), "fps": 24.0},
session_id="request-that-fails",
)
assert "request-that-fails" not in pipeline._memory_manager
2026-06-21 03:59:18 +02:00
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)],
2026-08-20 20:40:51 +02:00
control_weights=[1.0],
2026-06-21 03:59:18 +02:00
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),
]
2026-08-20 20:40:51 +02:00
assert pipeline.transformer.calls[0]["kwargs"]["control_weights"] == [1.0]
assert "control_weights" not in pipeline.transformer.calls[1]["kwargs"]
assert pipeline.transformer.calls[2]["kwargs"]["control_weights"] == [1.0]
2026-06-21 03:59:18 +02:00
torch.testing.assert_close(result, torch.full_like(latents, 254.0))
def test_diffuse_transfer_rejects_session_state_manager(make_cosmos3_pipeline) -> None:
pipeline = make_cosmos3_pipeline()
pipeline._use_session_state = True
with pytest.raises(NotImplementedError, match="richer cache keys"):
pipeline.diffuse_transfer(
latents=torch.zeros(1, 2, 1, 1, 1),
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.0,
control_guidance_interval=None,
control_latents=[],
shared_kwargs={},
velocity_mask=torch.ones(1, 1, 1, 1, 1),
condition_latents=torch.zeros(1, 2, 1, 1, 1),
)
2026-06-21 03:59:18 +02:00
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))
2026-08-20 20:40:51 +02:00
@pytest.mark.parametrize(
("hint_key", "emphasize_control", "expected_fps", "negative_prompt"),
[
("edge", None, 8.0, None),
("wsm", None, 10.0, ""),
("edge", False, 8.0, "custom negative"),
],
)
def test_forward_transfer_uses_transfer_prompt_contract_and_source_fps_except_wsm(
make_cosmos3_pipeline,
hint_key: str,
emphasize_control: bool | None,
expected_fps: float,
negative_prompt: str | None,
) -> None:
from vllm_omni.diffusion.models.cosmos3.pipeline_cosmos3 import (
COSMOS3_TRANSFER_CONTROL_DIRECTIVE_TEMPLATE,
COSMOS3_TRANSFER_SYSTEM_PROMPT,
)
2026-06-21 03:59:18 +02:00
pipeline = make_cosmos3_pipeline()
captured: dict[str, Any] = {}
def fake_format(prompt, negative_prompt, num_frames, frame_rate, height, width, *args, **kwargs):
2026-08-20 20:40:51 +02:00
del num_frames, height, width, args
captured["prompt"] = prompt
captured["negative_prompt"] = negative_prompt
2026-06-21 03:59:18 +02:00
captured["format_frame_rate"] = frame_rate
2026-08-20 20:40:51 +02:00
captured["format_kwargs"] = kwargs
captured["format_aspect_ratio"] = kwargs["aspect_ratio_override"]
2026-06-21 03:59:18 +02:00
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, "1,1")
2026-06-21 03:59:18 +02:00
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
2026-06-24 03:03:34 +02:00
def fake_set_flow_shift(target):
2026-06-24 03:03:34 +02:00
captured.setdefault("flow_shifts", []).append(target)
pipeline._current_flow_shift = float(target)
2026-06-24 03:03:34 +02:00
pipeline._set_flow_shift = fake_set_flow_shift
2026-06-21 03:59:18 +02:00
pipeline._decode_latents = lambda latents: torch.zeros(1, 3, 5, 16, 16, device="meta")
control = torch.zeros(3, 5, 16, 16, dtype=torch.uint8)
2026-08-20 20:40:51 +02:00
extra_args = {
hint_key: {"control": control},
"max_frames": 5,
"num_video_frames_per_chunk": 5,
"show_control_condition": True,
}
if emphasize_control is not None:
extra_args["emphasize_control_in_prompt"] = emphasize_control
prompt_data = {
"prompt": "transfer",
"modalities": ["video"],
"additional_information": {
"preprocessed_transfer_video": torch.zeros(1, 3, 5, 16, 16),
"transfer_input_fps": 8.0,
},
}
if negative_prompt is not None:
prompt_data["negative_prompt"] = negative_prompt
2026-06-21 03:59:18 +02:00
request = SimpleNamespace(
2026-08-20 20:40:51 +02:00
prompts=[prompt_data],
2026-06-21 03:59:18 +02:00
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).
2026-08-20 20:40:51 +02:00
extra_args=extra_args,
2026-06-21 03:59:18 +02:00
),
)
output = pipeline.forward(request)
assert captured["format_frame_rate"] == expected_fps
assert captured["format_aspect_ratio"] == "1,1"
2026-08-20 20:40:51 +02:00
expected_negative_prompt = "" if negative_prompt is None else negative_prompt
assert captured["negative_prompt"] == expected_negative_prompt
assert captured["format_kwargs"]["use_system_prompt"] is True
assert captured["format_kwargs"]["system_prompt"] == COSMOS3_TRANSFER_SYSTEM_PROMPT
assert captured["format_kwargs"]["use_duration_template"] is True
assert captured["format_kwargs"]["use_resolution_template"] is True
assert captured["format_kwargs"]["negative_metadata_mode"] == "same"
expected_suffix = (
None if emphasize_control is False else COSMOS3_TRANSFER_CONTROL_DIRECTIVE_TEMPLATE.format(hint_names=hint_key)
)
assert captured["format_kwargs"]["prompt_suffix"] == expected_suffix
2026-06-21 03:59:18 +02:00
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"
2026-06-21 03:59:18 +02:00
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, "1,1")
2026-06-21 03:59:18 +02:00
pipeline._format_and_tokenize_prompts = lambda *args, **kwargs: (_ids(2), _mask(), _ids(1), _mask())
2026-06-24 03:03:34 +02:00
pipeline._set_flow_shift = lambda target, **_kwargs: captured.setdefault("flow_shifts", []).append(target)
2026-06-21 03:59:18 +02:00
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)
2026-06-21 03:59:18 +02:00
torch.testing.assert_close(
output.output["payload"]["video"][0, 0, :, 0, 0],
2026-06-21 03:59:18 +02:00
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)
2026-06-21 03:59:18 +02:00
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))
2026-06-01 22:04:31 +02:00
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": []}
2026-06-21 16:20:30 +02:00
def fake_format(
prompt,
negative_prompt,
num_frames,
frame_rate,
height,
width,
max_sequence_length,
sp,
use_system_prompt=False,
is_t2i=False,
):
2026-06-01 22:04:31 +02:00
captured["format"] = {
"prompt": prompt,
"negative_prompt": negative_prompt,
"num_frames": num_frames,
"frame_rate": frame_rate,
"height": height,
"width": width,
2026-06-21 16:20:30 +02:00
"use_system_prompt": use_system_prompt,
"is_t2i": is_t2i,
2026-06-01 22:04:31 +02:00
}
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)
2026-06-03 02:51:44 +02:00
outputs = [kwargs["latents"] + len(captured["diffuse_calls"])]
2026-06-03 21:30:39 +02:00
if kwargs.get("action_latents") is not None:
outputs.append(kwargs["action_latents"] + 3.0)
2026-06-03 02:51:44 +02:00
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)
2026-06-01 22:04:31 +02:00
pipeline._format_and_tokenize_prompts = fake_format
pipeline._prepare_latents = fake_prepare
2026-06-24 03:03:34 +02:00
def fake_set_flow_shift(target):
2026-06-24 03:03:34 +02:00
captured.setdefault("flow_shifts", []).append(target)
pipeline._current_flow_shift = float(target)
2026-06-24 03:03:34 +02:00
pipeline._set_flow_shift = fake_set_flow_shift
2026-06-01 22:04:31 +02:00
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),
2026-06-21 16:20:30 +02:00
{
"key": "image",
"is_t2i": True,
"flow": [3.0],
"steps": [50, 50],
"frames": 1,
},
2026-06-01 22:04:31 +02:00
),
(
"A warehouse robot",
make_sampling_params(),
2026-06-21 16:20:30 +02:00
{
"key": "video",
"is_t2i": False,
"flow": [10.0],
2026-06-21 16:20:30 +02:00
"steps": [35],
"frames": 189,
},
2026-06-01 22:04:31 +02:00
),
],
)
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))
2026-06-01 22:04:31 +02:00
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)
2026-06-01 22:04:31 +02:00
2026-06-03 21:30:39 +02:00
def test_forward_i2v_sound_and_action_routes(self, make_cosmos3_pipeline) -> None:
2026-06-01 22:04:31 +02:00
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),
2026-06-01 22:04:31 +02:00
)
)
assert captured["diffuse_calls"][-1]["shared_kwargs"]["noisy_frame_mask"] is velocity_mask
2026-06-08 21:04:05 +02:00
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),
2026-06-08 21:04:05 +02:00
)
)
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
2026-06-03 02:51:44 +02:00
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)
2026-06-03 02:51:44 +02:00
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),
2026-06-03 02:51:44 +02:00
)
)
assert captured["diffuse_calls"][-1]["sound_latents"] is sound_latents
assert output.output["audio_sample_rate"] == 10
2026-06-03 21:30:39 +02:00
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(
2026-06-03 21:30:39 +02:00
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,
2026-06-21 16:20:30 +02:00
"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"]
2026-06-03 21:30:39 +02:00
2026-06-01 22:04:31 +02:00
@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"),
2026-06-03 02:51:44 +02:00
(
{"prompt": "x", "modalities": ["image"], "generate_sound": True},
2026-06-03 02:51:44 +02:00
make_sampling_params(),
"only for video",
),
2026-06-21 03:59:18 +02:00
(
{"prompt": "x", "modalities": ["image"]},
2026-06-21 03:59:18 +02:00
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},
2026-06-21 03:59:18 +02:00
make_sampling_params(extra_args={"edge": {"control_path": "/tmp/control.mp4"}}),
"cannot be combined with sound generation",
),
(
{"prompt": "x", "modalities": ["video"]},
2026-06-21 03:59:18 +02:00
make_sampling_params(
extra_args={
"edge": {"control_path": "/tmp/control.mp4"},
"action_mode": "policy",
}
),
"cannot be combined with action generation",
),
2026-06-01 22:04:31 +02:00
],
)
def test_forward_rejects_invalid_public_requests(
self,
make_cosmos3_pipeline,
prompt,
sampling_params,
message,
) -> None:
pipeline = make_cosmos3_pipeline()
2026-06-03 02:51:44 +02:00
pipeline.transformer = pipeline.transformer.__class__(latent_channel_size=2, sound_gen=True, sound_dim=3)
2026-06-01 22:04:31 +02:00
with pytest.raises(ValueError, match=message):
pipeline.forward(make_request_batch(prompt, sampling_params))