Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions examples/offline_inference/text_to_image/text_to_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -571,7 +571,6 @@ def main():
"vae_patch_parallel_size": args.vae_patch_parallel_size,
"enable_expert_parallel": args.enable_expert_parallel,
"enable_cpu_offload": args.enable_cpu_offload,
"mode": "text-to-image",
"log_stats": args.log_stats,
"enable_diffusion_pipeline_profiler": args.enable_diffusion_pipeline_profiler,
"profiler_config": args.profiler_config,
Expand Down Expand Up @@ -744,7 +743,10 @@ def main():
# stop-token-ids declaratively from the plain prompt + extra_body, so this
# example stays model-agnostic. Models without one are untouched.
ar_input_builder = get_ar_input_builder(model_class_name)
if ar_input_builder is not None:
# A model can also be deployed with only its diffusion stage. Keep those
# requests on the string-prompt path, as in the single-stage images API.
has_ar_stage = any(not isinstance(params, OmniDiffusionSamplingParams) for params in sampling_params_list)
if ar_input_builder is not None and has_ar_stage:
_apply_ar_stage_inputs(
ar_input_builder,
model=args.model,
Expand Down
25 changes: 11 additions & 14 deletions tests/e2e/accuracy/test_hunyuan_image3_pixel_accuracy.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def _baseline_path() -> Path:
return path


_OFFLINE_SCRIPT = _REPO_ROOT / "examples" / "offline_inference" / "hunyuan_image3" / "end2end.py"
_OFFLINE_SCRIPT = _REPO_ROOT / "examples" / "offline_inference" / "text_to_image" / "text_to_image.py"

# DiT-only deploy config with trust_remote_code (based on hunyuan_image3_dit.yaml).
_DEPLOY_CONFIG: dict[str, Any] = {
Expand Down Expand Up @@ -228,20 +228,17 @@ def _run_vllm_omni_hunyuan_image3_offline(*, model: str, deploy_config: str, out
import subprocess
import sys

output_dir = str(output_path.parent)
subprocess.run(
[
sys.executable,
str(_OFFLINE_SCRIPT),
"--modality",
"text2img",
"--deploy-config",
deploy_config,
"--prompts",
"--prompt",
PROMPT,
"--output",
output_dir,
"--steps",
str(output_path),
"--num-inference-steps",
str(NUM_INFERENCE_STEPS),
"--guidance-scale",
str(GUIDANCE_SCALE),
Expand All @@ -251,21 +248,21 @@ def _run_vllm_omni_hunyuan_image3_offline(*, model: str, deploy_config: str, out
str(HEIGHT),
"--width",
str(WIDTH),
"--bot-task",
"none",
"--sys-type",
"--use-system-prompt",
"en_unified",
"--extra-body",
'{"bot_task": "none"}',
"--trust-remote-code",
"--model",
model,
"--enforce-eager",
"--enable-expert-parallel",
],
check=True,
)
images = sorted(Path(output_dir).glob("output_*.png"))
assert images, f"No output image found in {output_dir}"
image = Image.open(images[0]).convert("RGB")
assert output_path.exists(), f"No output image at {output_path}"
image = Image.open(output_path).convert("RGB")
image.load()
image.save(output_path)
return image


Expand Down
101 changes: 94 additions & 7 deletions tests/model_extras/test_shared_script_ar_integration.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Integration coverage for the shared task examples' ``_apply_ar_stage_inputs``.
The unit tests in ``test_model_extras.py`` cover ``get_ar_input_builder`` and
Expand All @@ -25,6 +25,7 @@
import sys
from dataclasses import dataclass
from pathlib import Path
from types import SimpleNamespace
from typing import Any

import pytest
Expand All @@ -36,6 +37,96 @@
_REPO_ROOT = Path(__file__).resolve().parents[2]


@pytest.mark.parametrize("with_ar_stage", [False, True])
def test_text_to_image_only_builds_ar_inputs_for_ar_deployments(monkeypatch, tmp_path, with_ar_stage):
from PIL import Image
from vllm import SamplingParams

from vllm_omni.config.omni_config import normalize_and_validate_diffusion_engine_ingress_kwargs

module = _load_module("_shared_text_to_image_deploy", "examples/offline_inference/text_to_image/text_to_image.py")
tokenizer_calls = _patch_tokenizer_loader(monkeypatch, module)
monkeypatch.setattr(module, "get_ar_tokenizer_validator", lambda _: None)
monkeypatch.setattr(
module, "current_omni_platform", SimpleNamespace(device_type="cpu", pre_register_and_update=lambda parser: None)
)
monkeypatch.setattr(module, "is_nextstep_model", lambda _: False)
monkeypatch.setattr(module, "get_model_class_name", lambda _: "HunyuanImage3ForCausalMM")
defaults = [OmniDiffusionSamplingParams()]
if with_ar_stage:
defaults.insert(0, SamplingParams())
captured: dict[str, Any] = {}

def generate(prompt, *, sampling_params_list):
captured.update(prompt=prompt, params=sampling_params_list)
return [SimpleNamespace(images=[Image.new("RGB", (8, 8))])]

def create_omni(**kwargs):
# Exercise the real ingress validator so stale example-only options
# cannot silently pass this test while breaking model initialization.
normalize_and_validate_diffusion_engine_ingress_kwargs(kwargs, stage_id=0)
return SimpleNamespace(default_sampling_params_list=defaults, generate=generate)

monkeypatch.setattr(module, "Omni", create_omni)
output = tmp_path / "output.png"
monkeypatch.setattr(
sys,
"argv",
[
"text_to_image.py",
"--model",
"test-hunyuan",
"--prompt",
"A dog",
"--output",
str(output),
"--extra-body",
'{"bot_task": null}' if with_ar_stage else '{"bot_task": "none"}',
"--trust-remote-code",
],
)
module.main()

assert output.is_file()
assert bool(tokenizer_calls) == with_ar_stage
assert ("prompt_token_ids" in captured["prompt"]) == with_ar_stage
if with_ar_stage:
assert captured["params"][0].stop_token_ids
else:
assert captured["prompt"] == {"prompt": "A dog", "modalities": ["image"]}
assert captured["params"][0].extra_args["bot_task"] == "none"


def test_hunyuan_accuracy_offline_cli_contract(monkeypatch, tmp_path):
import subprocess

from PIL import Image

accuracy = _load_module("_hunyuan_accuracy", "tests/e2e/accuracy/test_hunyuan_image3_pixel_accuracy.py")
module = _load_module("_hunyuan_accuracy_cli", "examples/offline_inference/text_to_image/text_to_image.py")
output = tmp_path / "offline.png"

def run(argv, *, check):
assert check
assert Path(argv[1]).is_file()
monkeypatch.setattr(sys, "argv", argv[1:])
args = module.parse_args()
assert args.enable_expert_parallel
assert args.extra_body == {"bot_task": "none"}
assert args.use_system_prompt == "en_unified"
assert args.trust_remote_code
assert args.seed == accuracy.SEED
assert args.num_inference_steps == accuracy.NUM_INFERENCE_STEPS
assert args.output == str(output)
Image.new("RGB", (8, 8)).save(args.output)

monkeypatch.setattr(subprocess, "run", run)
image = accuracy._run_vllm_omni_hunyuan_image3_offline(
model="test-hunyuan", deploy_config="deploy.yaml", output_path=output
)
assert image.size == (8, 8)


def _load_module(name: str, relpath: str):
path = _REPO_ROOT / relpath
spec = importlib.util.spec_from_file_location(name, path)
Expand Down Expand Up @@ -75,9 +166,7 @@ def from_pretrained(model: str, trust_remote_code: bool = False) -> _FakeHunyuan
calls.append({"model": model, "trust_remote_code": trust_remote_code})
return _FakeHunyuanTokenizer()

fake_transformers = type(sys)("transformers")
fake_transformers.AutoTokenizer = _FakeAutoTokenizer
monkeypatch.setitem(sys.modules, "transformers", fake_transformers)
monkeypatch.setattr("transformers.AutoTokenizer.from_pretrained", _FakeAutoTokenizer.from_pretrained)
return calls


Expand All @@ -90,9 +179,7 @@ class _FailingAutoTokenizer:
def from_pretrained(model: str, trust_remote_code: bool = False) -> Any:
raise OSError("simulated tokenizer load failure")

fake_transformers = type(sys)("transformers")
fake_transformers.AutoTokenizer = _FailingAutoTokenizer
monkeypatch.setitem(sys.modules, "transformers", fake_transformers)
monkeypatch.setattr("transformers.AutoTokenizer.from_pretrained", _FailingAutoTokenizer.from_pretrained)


@pytest.mark.parametrize(
Expand Down
Loading