[Test] Unify L2/L3 test layout, Buildkite steps, and test helpers (#2556)
Signed-off-by: wangyu <410167048@qq.com> Signed-off-by: Huang, Zeyu <11222265+fhfuih@users.noreply.github.com> Signed-off-by: wangyu <53896905+yenuo26@users.noreply.github.com> Co-authored-by: Huang, Zeyu <11222265+fhfuih@users.noreply.github.com>
This commit is contained in:
1 parent
b85833eeec
commit
6f2ad7b403
134 files changed
+4904
-4185
No files matched your search
@@ -0,0 +1,90 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
|
||||
"""Offline E2E test for InternVLA-A1 open-loop inference."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.helpers.mark import hardware_test
|
||||
|
||||
os.environ["VLLM_TEST_CLEAN_GPU_MEMORY"] = "1"
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
EXAMPLE_SCRIPT = REPO_ROOT / "examples" / "offline_inference" / "internvla_a1" / "end2end.py"
|
||||
|
||||
|
||||
def _required_env(name: str) -> str:
|
||||
value = os.getenv(name)
|
||||
if not value:
|
||||
pytest.skip(f"{name} is not set")
|
||||
return value
|
||||
|
||||
|
||||
@pytest.mark.core_model
|
||||
@pytest.mark.advanced_model
|
||||
@pytest.mark.diffusion
|
||||
@hardware_test(res={"cuda": "H100", "rocm": "MI325"})
|
||||
def test_internvla_a1_offline_open_loop(run_level: str) -> None:
|
||||
if run_level != "advanced_model":
|
||||
pytest.skip("InternVLA-A1 offline evaluation requires real local checkpoints and dataset.")
|
||||
|
||||
model_dir = _required_env("INTERNVLA_A1_MODEL_DIR")
|
||||
dataset_dir = _required_env("INTERNVLA_A1_DATASET_DIR")
|
||||
processor_dir = _required_env("INTERNVLA_A1_PROCESSOR_DIR")
|
||||
cosmos_dir = _required_env("INTERNVLA_A1_COSMOS_DIR")
|
||||
|
||||
env = os.environ.copy()
|
||||
env["INTERNVLA_A1_PROCESSOR_DIR"] = processor_dir
|
||||
env["INTERNVLA_A1_COSMOS_DIR"] = cosmos_dir
|
||||
|
||||
with tempfile.TemporaryDirectory(prefix="internvla_a1_e2e_") as tmpdir:
|
||||
output_dir = Path(tmpdir) / "outputs"
|
||||
cmd = [
|
||||
sys.executable,
|
||||
str(EXAMPLE_SCRIPT),
|
||||
"--model-dir",
|
||||
model_dir,
|
||||
"--dataset-dir",
|
||||
dataset_dir,
|
||||
"--output-dir",
|
||||
str(output_dir),
|
||||
"--num-samples",
|
||||
"1",
|
||||
"--num-episodes",
|
||||
"1",
|
||||
"--dtype",
|
||||
"float32",
|
||||
"--attn-implementation",
|
||||
"eager",
|
||||
"--skip-plots",
|
||||
]
|
||||
subprocess.run(cmd, check=True, env=env)
|
||||
|
||||
summary_path = output_dir / "summary.json"
|
||||
assert summary_path.exists(), f"Missing summary file: {summary_path}"
|
||||
|
||||
with open(summary_path, encoding="utf-8") as f:
|
||||
summary = json.load(f)
|
||||
|
||||
assert summary["mode"] == "registry"
|
||||
assert summary["attn_implementation"] == "eager"
|
||||
assert summary["dtype"] == "float32"
|
||||
assert len(summary["results"]) == 1
|
||||
assert "registry" in summary["eval_summaries"]
|
||||
|
||||
eval_summary = summary["eval_summaries"]["registry"]
|
||||
assert eval_summary["num_episodes"] == 1
|
||||
assert eval_summary["average_mse"] is not None
|
||||
assert eval_summary["average_mae"] is not None
|
||||
|
||||
log_path = output_dir / "registry" / "log.json"
|
||||
assert log_path.exists(), f"Missing evaluation log: {log_path}"
|
||||
@@ -0,0 +1,243 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from PIL import Image
|
||||
|
||||
from tests.helpers.mark import hardware_test
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[3]
|
||||
T2V_EXAMPLE = REPO_ROOT / "examples" / "offline_inference" / "text_to_video" / "text_to_video.py"
|
||||
I2V_EXAMPLE = REPO_ROOT / "examples" / "offline_inference" / "image_to_video" / "image_to_video.py"
|
||||
|
||||
T2V_PROMPT = (
|
||||
"At sunrise, a glowing paper lantern boat drifts through a narrow canal between mossy stone walls, "
|
||||
"soft fog above the water, the camera slowly gliding forward as golden reflections shimmer across "
|
||||
"the ripples, cinematic, realistic, highly detailed."
|
||||
)
|
||||
T2V_NEGATIVE_PROMPT = "worst quality, blurry, jittery motion, distorted, oversaturated, artifacts"
|
||||
I2V_PROMPT = "A cinematic dolly shot of a boat drifting on calm water at sunset"
|
||||
I2V_NEGATIVE_PROMPT = "worst quality, blurry, jittery motion"
|
||||
|
||||
os.environ["VLLM_WORKER_MULTIPROC_METHOD"] = "spawn"
|
||||
|
||||
|
||||
def _get_ltx2_model() -> str:
|
||||
return "Lightricks/LTX-2"
|
||||
|
||||
|
||||
def _md5(path: Path) -> str:
|
||||
digest = hashlib.md5(usedforsecurity=False)
|
||||
with path.open("rb") as f:
|
||||
for chunk in iter(lambda: f.read(1024 * 1024), b""):
|
||||
digest.update(chunk)
|
||||
return digest.hexdigest()
|
||||
|
||||
|
||||
def _make_deterministic_test_image(path: Path) -> None:
|
||||
"""Create a deterministic 256x256 test image for I2V tests."""
|
||||
rng = np.random.RandomState(42)
|
||||
img = Image.fromarray(rng.randint(0, 255, (256, 256, 3), dtype=np.uint8))
|
||||
img.save(path)
|
||||
|
||||
|
||||
def _run_and_check(cmd: list[str], env: dict, output_path: Path, expected_md5: str) -> None:
|
||||
result = subprocess.run(cmd, cwd=REPO_ROOT, env=env, capture_output=True, text=True, check=False)
|
||||
assert result.returncode == 0, (
|
||||
f"Command failed (exit {result.returncode}).\nstdout:\n{result.stdout}\nstderr:\n{result.stderr}"
|
||||
)
|
||||
generated_md5 = _md5(output_path)
|
||||
assert generated_md5 == expected_md5, (
|
||||
f"Unexpected output md5: {generated_md5} != {expected_md5}.\nstdout:\n{result.stdout}\nstderr:\n{result.stderr}"
|
||||
)
|
||||
|
||||
|
||||
# ── T2V tests ──
|
||||
|
||||
|
||||
@pytest.mark.full_model
|
||||
@pytest.mark.diffusion
|
||||
@pytest.mark.parallel
|
||||
@pytest.mark.slow
|
||||
@hardware_test(res={"cuda": "L4"}, num_cards=2)
|
||||
def test_ltx2_t2v_cfg_parallel(tmp_path: Path):
|
||||
"""T2V with CFG=4.0, cfg-parallel-size=2."""
|
||||
output = tmp_path / "t2v_cfg4.mp4"
|
||||
env = os.environ.copy()
|
||||
env.setdefault("CUDA_VISIBLE_DEVICES", "0,1")
|
||||
cmd = [
|
||||
sys.executable,
|
||||
str(T2V_EXAMPLE),
|
||||
"--model",
|
||||
_get_ltx2_model(),
|
||||
"--prompt",
|
||||
T2V_PROMPT,
|
||||
"--negative-prompt",
|
||||
T2V_NEGATIVE_PROMPT,
|
||||
"--height",
|
||||
"256",
|
||||
"--width",
|
||||
"256",
|
||||
"--num-frames",
|
||||
"145",
|
||||
"--num-inference-steps",
|
||||
"6",
|
||||
"--guidance-scale",
|
||||
"4.0",
|
||||
"--frame-rate",
|
||||
"24",
|
||||
"--fps",
|
||||
"24",
|
||||
"--seed",
|
||||
"42",
|
||||
"--cfg-parallel-size",
|
||||
"2",
|
||||
"--enforce-eager",
|
||||
"--output",
|
||||
str(output),
|
||||
]
|
||||
_run_and_check(cmd, env, output, expected_md5="08e606b9c522fee4b6f30cee8b77db40")
|
||||
|
||||
|
||||
@pytest.mark.full_model
|
||||
@pytest.mark.diffusion
|
||||
@pytest.mark.slow
|
||||
@hardware_test(res={"cuda": "L4"}, num_cards=1)
|
||||
def test_ltx2_t2v_no_cfg(tmp_path: Path):
|
||||
"""T2V with CFG=1.0 (no classifier-free guidance)."""
|
||||
output = tmp_path / "t2v_nocfg.mp4"
|
||||
env = os.environ.copy()
|
||||
env.setdefault("CUDA_VISIBLE_DEVICES", "0")
|
||||
cmd = [
|
||||
sys.executable,
|
||||
str(T2V_EXAMPLE),
|
||||
"--model",
|
||||
_get_ltx2_model(),
|
||||
"--prompt",
|
||||
T2V_PROMPT,
|
||||
"--height",
|
||||
"256",
|
||||
"--width",
|
||||
"256",
|
||||
"--num-frames",
|
||||
"145",
|
||||
"--num-inference-steps",
|
||||
"6",
|
||||
"--guidance-scale",
|
||||
"1.0",
|
||||
"--frame-rate",
|
||||
"24",
|
||||
"--fps",
|
||||
"24",
|
||||
"--seed",
|
||||
"42",
|
||||
"--enforce-eager",
|
||||
"--output",
|
||||
str(output),
|
||||
]
|
||||
_run_and_check(cmd, env, output, expected_md5="a83994b94b6e67c54a524e0383c45ce8")
|
||||
|
||||
|
||||
# ── I2V tests ──
|
||||
|
||||
|
||||
@pytest.mark.full_model
|
||||
@pytest.mark.diffusion
|
||||
@pytest.mark.parallel
|
||||
@pytest.mark.slow
|
||||
@hardware_test(res={"cuda": "L4"}, num_cards=2)
|
||||
def test_ltx2_i2v_cfg_parallel(tmp_path: Path):
|
||||
"""I2V with CFG=4.0, cfg-parallel-size=2."""
|
||||
test_image = tmp_path / "test_input.png"
|
||||
_make_deterministic_test_image(test_image)
|
||||
output = tmp_path / "i2v_cfg4.mp4"
|
||||
env = os.environ.copy()
|
||||
env.setdefault("CUDA_VISIBLE_DEVICES", "0,1")
|
||||
cmd = [
|
||||
sys.executable,
|
||||
str(I2V_EXAMPLE),
|
||||
"--model",
|
||||
_get_ltx2_model(),
|
||||
"--model-class-name",
|
||||
"LTX2ImageToVideoPipeline",
|
||||
"--image",
|
||||
str(test_image),
|
||||
"--prompt",
|
||||
I2V_PROMPT,
|
||||
"--negative-prompt",
|
||||
I2V_NEGATIVE_PROMPT,
|
||||
"--height",
|
||||
"256",
|
||||
"--width",
|
||||
"256",
|
||||
"--num-frames",
|
||||
"73",
|
||||
"--num-inference-steps",
|
||||
"6",
|
||||
"--guidance-scale",
|
||||
"4.0",
|
||||
"--frame-rate",
|
||||
"24",
|
||||
"--fps",
|
||||
"24",
|
||||
"--seed",
|
||||
"42",
|
||||
"--cfg-parallel-size",
|
||||
"2",
|
||||
"--enforce-eager",
|
||||
"--output",
|
||||
str(output),
|
||||
]
|
||||
_run_and_check(cmd, env, output, expected_md5="aed7e56084b36373244d8f839b16d115")
|
||||
|
||||
|
||||
@pytest.mark.full_model
|
||||
@pytest.mark.diffusion
|
||||
@pytest.mark.slow
|
||||
@hardware_test(res={"cuda": "L4"}, num_cards=1)
|
||||
def test_ltx2_i2v_no_cfg(tmp_path: Path):
|
||||
"""I2V with CFG=1.0 (no classifier-free guidance)."""
|
||||
test_image = tmp_path / "test_input.png"
|
||||
_make_deterministic_test_image(test_image)
|
||||
output = tmp_path / "i2v_nocfg.mp4"
|
||||
env = os.environ.copy()
|
||||
env.setdefault("CUDA_VISIBLE_DEVICES", "0")
|
||||
cmd = [
|
||||
sys.executable,
|
||||
str(I2V_EXAMPLE),
|
||||
"--model",
|
||||
_get_ltx2_model(),
|
||||
"--model-class-name",
|
||||
"LTX2ImageToVideoPipeline",
|
||||
"--image",
|
||||
str(test_image),
|
||||
"--prompt",
|
||||
I2V_PROMPT,
|
||||
"--height",
|
||||
"256",
|
||||
"--width",
|
||||
"256",
|
||||
"--num-frames",
|
||||
"73",
|
||||
"--num-inference-steps",
|
||||
"6",
|
||||
"--guidance-scale",
|
||||
"1.0",
|
||||
"--frame-rate",
|
||||
"24",
|
||||
"--fps",
|
||||
"24",
|
||||
"--seed",
|
||||
"42",
|
||||
"--enforce-eager",
|
||||
"--output",
|
||||
str(output),
|
||||
]
|
||||
_run_and_check(cmd, env, output, expected_md5="81b21ede12753e9e14a357a6c548b666")
|
||||
@@ -133,5 +133,5 @@ def test_lora_001(omni_server: OmniServer, example_output_dir: Path, tmp_path: P
|
||||
# --- ### Using curl with LoRA (Images API) ---
|
||||
|
||||
|
||||
@pytest.mark.skip(reason="Covered by tests/e2e/online_serving/test_images_generations_lora.py")
|
||||
@pytest.mark.skip(reason="Covered by tests/diffusion/lora/test_images_generations_lora.py")
|
||||
def test_lora_002(): ...
|
||||
Reference in new issue
Block a user