From e353630b57d7e6b24efd2611f495b7f34d0abdc4 Mon Sep 17 00:00:00 2001 From: Makcum888e <79456407+Makcum888e@users.noreply.github.com> Date: Fri, 17 Apr 2026 04:09:44 +0300 Subject: [PATCH] [Diffusion] [NPU] Fix multimodal gen CI (#22879) --- .github/workflows/pr-test-npu.yml | 6 +- .../sglang/multimodal_gen/test/run_suite.py | 13 +- .../multimodal_gen/test/run_suite_npu.py | 299 ++++++++ .../test/server/accuracy_testcase_configs.py | 4 +- .../server/ascend/perf_baselines_npu.json | 4 +- .../server/ascend/testcase_configs_npu.py | 1 + .../multimodal_gen/test/server/gpu_cases.py | 639 ++++++++++++++++++ .../test/server/test_server_1_gpu.py | 6 +- .../test/server/test_server_2_gpu.py | 6 +- .../test/server/test_server_c.py | 6 +- .../test/server/testcase_configs.py | 616 ----------------- 11 files changed, 956 insertions(+), 644 deletions(-) create mode 100644 python/sglang/multimodal_gen/test/run_suite_npu.py create mode 100644 python/sglang/multimodal_gen/test/server/gpu_cases.py diff --git a/.github/workflows/pr-test-npu.yml b/.github/workflows/pr-test-npu.yml index de68be0f1..0e49e0d65 100644 --- a/.github/workflows/pr-test-npu.yml +++ b/.github/workflows/pr-test-npu.yml @@ -322,7 +322,7 @@ jobs: run: | export PATH="/usr/local/Ascend/8.3.RC1/compiler/bishengir/bin:${PATH}" cd python - python3 sglang/multimodal_gen/test/run_suite.py --suite 1-npu + python3 sglang/multimodal_gen/test/run_suite_npu.py --suite 1-npu multimodal-gen-test-2-npu-a3: needs: [check-changes, pr-gate] @@ -369,7 +369,7 @@ jobs: run: | export PATH="/usr/local/Ascend/8.3.RC1/compiler/bishengir/bin:${PATH}" cd python - python3 sglang/multimodal_gen/test/run_suite.py --suite 2-npu + python3 sglang/multimodal_gen/test/run_suite_npu.py --suite 2-npu multimodal-gen-test-8-npu-a3: needs: [check-changes, pr-gate] @@ -415,7 +415,7 @@ jobs: STREAMS_PER_DEVICE: 32 run: | cd python - python3 sglang/multimodal_gen/test/run_suite.py --suite 8-npu + python3 sglang/multimodal_gen/test/run_suite_npu.py --suite 8-npu pr-test-npu-finish: needs: diff --git a/python/sglang/multimodal_gen/test/run_suite.py b/python/sglang/multimodal_gen/test/run_suite.py index 9cccf3f24..491d3ebcc 100644 --- a/python/sglang/multimodal_gen/test/run_suite.py +++ b/python/sglang/multimodal_gen/test/run_suite.py @@ -20,10 +20,12 @@ from pathlib import Path import tabulate from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger -from sglang.multimodal_gen.test.server.testcase_configs import ( - BASELINE_CONFIG, +from sglang.multimodal_gen.test.server.gpu_cases import ( ONE_GPU_CASES, TWO_GPU_CASES, +) +from sglang.multimodal_gen.test.server.testcase_configs import ( + BASELINE_CONFIG, DiffusionTestCase, ) @@ -67,13 +69,6 @@ FILE_SUITES = { ], } -suites_ascend = { - "1-npu": ["ascend/test_server_1_npu.py"], - "2-npu": ["ascend/test_server_2_npu.py"], - "8-npu": ["ascend/test_server_8_npu.py"], -} -FILE_SUITES.update(suites_ascend) - PARAMETRIZED_CASE_GROUPS = { "1-gpu": [ ("test_server_1_gpu.py", ONE_GPU_CASES), diff --git a/python/sglang/multimodal_gen/test/run_suite_npu.py b/python/sglang/multimodal_gen/test/run_suite_npu.py new file mode 100644 index 000000000..ae31de20f --- /dev/null +++ b/python/sglang/multimodal_gen/test/run_suite_npu.py @@ -0,0 +1,299 @@ +""" +Test runner for multimodal_gen that manages test suites and parallel execution. + +Usage: + python3 run_suite_npu.py --suite --partition-id --total-partitions + +Example: + python3 run_suite_npu.py --suite 1-npu --partition-id 0 --total-partitions 4 +""" + +import argparse +import os +import subprocess +import sys +from pathlib import Path + +import tabulate + +from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger + +logger = init_logger(__name__) + +SUITES = { + "1-npu": [ + "ascend/test_server_1_npu.py", + # add new 1-npu test files here + ], + "2-npu": [ + "ascend/test_server_2_npu.py", + # add new 2-npu test files here + ], + "8-npu": [ + "ascend/test_server_8_npu.py", + # add new 8-npu test files here + ], +} + + +def parse_args(): + parser = argparse.ArgumentParser(description="Run multimodal_gen test suite") + parser.add_argument( + "--suite", + type=str, + required=True, + choices=list(SUITES.keys()), + help="The test suite to run (valid names are defined in SUITES)", + ) + parser.add_argument( + "--partition-id", + type=int, + default=0, + help="Index of the current partition (for parallel execution)", + ) + parser.add_argument( + "--total-partitions", + type=int, + default=1, + help="Total number of partitions", + ) + parser.add_argument( + "--base-dir", + type=str, + default="server", + help="Base directory for tests relative to this script's parent", + ) + parser.add_argument( + "-k", + "--filter", + type=str, + default=None, + help="Pytest filter expression (passed to pytest -k)", + ) + parser.add_argument( + "--continue-on-error", + action="store_true", + default=False, + help="Continue running remaining tests even if one fails (for CI consistency; pytest already continues by default)", + ) + return parser.parse_args() + + +def collect_test_items(files, filter_expr=None): + """Collect test item node IDs from the given files using pytest --collect-only.""" + cmd = [sys.executable, "-m", "pytest", "--collect-only", "-q"] + if filter_expr: + cmd.extend(["-k", filter_expr]) + cmd.extend(files) + + print(f"Collecting tests with command: {' '.join(cmd)}") + result = subprocess.run(cmd, capture_output=True, text=True) + + # Check for collection errors + # pytest exit codes: + # 0: success + # 1: tests collected but some had errors during collection + # 2: test execution interrupted + # 3: internal error + # 4: command line usage error + # 5: no tests collected (may be expected with filters) + if result.returncode not in (0, 5): + error_msg = ( + f"pytest --collect-only failed with exit code {result.returncode}\n" + f"Command: {' '.join(cmd)}\n" + ) + if result.stderr: + error_msg += f"stderr:\n{result.stderr}\n" + if result.stdout: + error_msg += f"stdout:\n{result.stdout}\n" + logger.error(error_msg) + raise RuntimeError(error_msg) + + if result.returncode == 5: + print( + "No tests were collected (exit code 5). This may be expected with filters." + ) + + # Parse the output to extract test node IDs + # pytest -q outputs lines like: test_file.py::TestClass::test_method[param] + test_items = [] + for line in result.stdout.strip().split("\n"): + line = line.strip() + # Skip empty lines and summary lines + if line and "::" in line and not line.startswith(("=", "-", " ")): + # Handle lines that might have extra info after the test ID + test_id = line.split()[0] if " " in line else line + if "::" in test_id: + test_items.append(test_id) + + print(f"Collected {len(test_items)} test items") + return test_items + + +def run_pytest(files, filter_expr=None, exitfirst=False): + if not files: + print("No files to run.") + return 0 + + base_cmd = [sys.executable, "-m", "pytest", "-s", "-v"] + if exitfirst: + base_cmd.append("-x") + + # Add pytest -k filter if provided + if filter_expr: + base_cmd.extend(["-k", filter_expr]) + + max_retries = 6 + # retry if the perf assertion failed, for {max_retries} times + for i in range(max_retries + 1): + cmd = list(base_cmd) + if i > 0: + cmd.append("--last-failed") + # Always include files to constrain test discovery scope + # This prevents pytest from scanning the entire rootdir and + # discovering unrelated tests that may have missing dependencies + cmd.extend(files) + + if i > 0: + print( + f"Performance assertion failed. Retrying ({i}/{max_retries}) with --last-failed..." + ) + + print(f"Running command: {' '.join(cmd)}") + + process = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + bufsize=0, + ) + + output_bytes = bytearray() + while True: + chunk = process.stdout.read(4096) + if not chunk: + break + sys.stdout.buffer.write(chunk) + sys.stdout.buffer.flush() + output_bytes.extend(chunk) + + process.wait() + returncode = process.returncode + + if returncode == 0: + return 0 + + # Exit code 5 means no tests were collected/selected - treat as success + # when using filters, since some partitions may have all tests filtered out + if returncode == 5: + print( + "No tests collected (exit code 5). This is expected when filters " + "deselect all tests in a partition. Treating as success." + ) + return 0 + + # check if the failure is due to an assertion in test_server_utils.py + full_output = output_bytes.decode("utf-8", errors="replace") + is_perf_assertion = ( + "multimodal_gen/test/server/test_server_utils.py" in full_output + and "AssertionError" in full_output + ) + + is_flaky_ci_assertion = ( + "SafetensorError" in full_output + or "FileNotFoundError" in full_output + or "TimeoutError" in full_output + ) + + is_oom_error = ( + "out of memory" in full_output.lower() + or "oom killer" in full_output.lower() + ) + + if not (is_perf_assertion or is_flaky_ci_assertion or is_oom_error): + return returncode + + print(f"Max retry exceeded") + return returncode + + +def main(): + args = parse_args() + + # 1. resolve base path + current_file_path = Path(__file__).resolve() + test_root_dir = current_file_path.parent + target_dir = test_root_dir / args.base_dir + + if not target_dir.exists(): + print(f"Error: Target directory {target_dir} does not exist.") + sys.exit(1) + + # 2. get files from suite + suite_files_rel = SUITES[args.suite] + + suite_files_abs = [] + for f_rel in suite_files_rel: + f_abs = target_dir / f_rel + if not f_abs.exists(): + msg = f"Test file {f_rel} not found in {target_dir}." + print(f"Warning: {msg} Skipping.") + continue + suite_files_abs.append(str(f_abs)) + + if not suite_files_abs: + print(f"No valid test files found for suite '{args.suite}'.") + sys.exit(0) + + # 3. collect all test items and partition by items (not files) + all_test_items = collect_test_items(suite_files_abs, filter_expr=args.filter) + + if not all_test_items: + print(f"No test items found for suite '{args.suite}'.") + sys.exit(0) + + # Partition by test items + my_items = [ + item + for i, item in enumerate(all_test_items) + if i % args.total_partitions == args.partition_id + ] + + # Print test info at beginning (similar to test/run_suite.py pretty_print_tests) + partition_info = f"{args.partition_id + 1}/{args.total_partitions} (0-based id={args.partition_id})" + headers = ["Suite", "Partition"] + rows = [[args.suite, partition_info]] + msg = tabulate.tabulate(rows, headers=headers, tablefmt="psql") + "\n" + msg += f"✅ Enabled {len(my_items)} test(s):\n" + for item in my_items: + msg += f" - {item}\n" + print(msg, flush=True) + print( + f"Suite: {args.suite} | Partition: {args.partition_id}/{args.total_partitions}" + ) + print(f"Selected {len(suite_files_abs)} files:") + for f in suite_files_abs: + print(f" - {os.path.basename(f)}") + + if not my_items: + print("No items assigned to this partition. Exiting success.") + sys.exit(0) + + print(f"Running {len(my_items)} items in this shard: {', '.join(my_items)}") + + # 4. execute with the specific test items + # Fast-fail: stop on first failure unless --continue-on-error is set + exit_code = run_pytest(my_items, exitfirst=not args.continue_on_error) + + # Print tests again at the end for visibility + msg = "\n" + tabulate.tabulate(rows, headers=headers, tablefmt="psql") + "\n" + msg += f"✅ Executed {len(my_items)} test(s):\n" + for item in my_items: + msg += f" - {item}\n" + print(msg, flush=True) + + sys.exit(exit_code) + + +if __name__ == "__main__": + main() diff --git a/python/sglang/multimodal_gen/test/server/accuracy_testcase_configs.py b/python/sglang/multimodal_gen/test/server/accuracy_testcase_configs.py index ed7900219..fedec989d 100644 --- a/python/sglang/multimodal_gen/test/server/accuracy_testcase_configs.py +++ b/python/sglang/multimodal_gen/test/server/accuracy_testcase_configs.py @@ -1,10 +1,10 @@ from __future__ import annotations -from sglang.multimodal_gen.test.server.testcase_configs import ( +from sglang.multimodal_gen.test.server.gpu_cases import ( ONE_GPU_CASES, TWO_GPU_CASES, - DiffusionTestCase, ) +from sglang.multimodal_gen.test.server.testcase_configs import DiffusionTestCase def _select_accuracy_cases( diff --git a/python/sglang/multimodal_gen/test/server/ascend/perf_baselines_npu.json b/python/sglang/multimodal_gen/test/server/ascend/perf_baselines_npu.json index b4703c95a..47e16b5c4 100644 --- a/python/sglang/multimodal_gen/test/server/ascend/perf_baselines_npu.json +++ b/python/sglang/multimodal_gen/test/server/ascend/perf_baselines_npu.json @@ -12,7 +12,7 @@ "TimestepPreparationStage": 53.52, "LatentPreparationStage": 0.39, "DenoisingStage": 19423.39, - "DecodingStage": 40.14 + "DecodingStage": 196.62 }, "denoise_step_ms": { "0": 123.16, @@ -265,7 +265,7 @@ "LatentPreparationStage": 0.69, "TimestepPreparationStage": 35.29, "DenoisingStage": 30529.83, - "DecodingStage": 74.25 + "DecodingStage": 428.21 }, "denoise_step_ms": { "0": 477.43, diff --git a/python/sglang/multimodal_gen/test/server/ascend/testcase_configs_npu.py b/python/sglang/multimodal_gen/test/server/ascend/testcase_configs_npu.py index 71cdd95ff..0acadac21 100644 --- a/python/sglang/multimodal_gen/test/server/ascend/testcase_configs_npu.py +++ b/python/sglang/multimodal_gen/test/server/ascend/testcase_configs_npu.py @@ -63,6 +63,7 @@ EIGHT_NPU_CASES: list[DiffusionTestCase] = [ model_path="/root/.cache/modelscope/hub/models/Eco-Tech/Wan2.2-T2V-A14B-Diffusers-w8a8", num_gpus=8, tp_size=4, + ulysses_degree=2, ), DiffusionSamplingParams( prompt=T2V_PROMPT, diff --git a/python/sglang/multimodal_gen/test/server/gpu_cases.py b/python/sglang/multimodal_gen/test/server/gpu_cases.py new file mode 100644 index 000000000..fc8f70dd5 --- /dev/null +++ b/python/sglang/multimodal_gen/test/server/gpu_cases.py @@ -0,0 +1,639 @@ +from sglang.multimodal_gen.runtime.platforms import current_platform +from sglang.multimodal_gen.test.server.testcase_configs import ( + MODELOPT_FLUX1_FP8_TRANSFORMER, + MODELOPT_FLUX1_NVFP4_TRANSFORMER, + MODELOPT_FLUX2_FP8_TRANSFORMER, + MODELOPT_FLUX2_NVFP4_MODEL, + MODELOPT_NVFP4_B200_ENV_VARS, + MODELOPT_WAN22_FP8_TRANSFORMER, + MODELOPT_WAN22_NVFP4_TRANSFORMER, + T2V_PROMPT, + DiffusionSamplingParams, + DiffusionServerArgs, + DiffusionTestCase, + HUNYUAN3D_SHAPE_sampling_params, + MODELOPT_T2I_CI_sampling_params, + MODELOPT_T2V_CI_sampling_params, + MULTI_FRAME_I2I_sampling_params, + MULTI_IMAGE_TI2I_sampling_params, + MULTI_IMAGE_TI2I_UPLOAD_sampling_params, + T2I_sampling_params, + T2V_sampling_params, + TI2I_sampling_params, + TI2V_sampling_params, + _make_modelopt_ci_case, + _with_default_num_gpus, +) +from sglang.multimodal_gen.test.test_utils import ( + DEFAULT_FLUX_1_DEV_MODEL_NAME_FOR_TEST, + DEFAULT_FLUX_2_DEV_MODEL_NAME_FOR_TEST, + DEFAULT_FLUX_2_KLEIN_4B_MODEL_NAME_FOR_TEST, + DEFAULT_MOVA_360P_MODEL_NAME_FOR_TEST, + DEFAULT_QWEN_IMAGE_EDIT_2509_MODEL_NAME_FOR_TEST, + DEFAULT_QWEN_IMAGE_EDIT_2511_MODEL_NAME_FOR_TEST, + DEFAULT_QWEN_IMAGE_EDIT_MODEL_NAME_FOR_TEST, + DEFAULT_QWEN_IMAGE_LAYERED_MODEL_NAME_FOR_TEST, + DEFAULT_QWEN_IMAGE_MODEL_NAME_FOR_TEST, + DEFAULT_SMALL_MODEL_NAME_FOR_TEST, + DEFAULT_WAN_2_1_I2V_14B_480P_MODEL_NAME_FOR_TEST, + DEFAULT_WAN_2_1_I2V_14B_720P_MODEL_NAME_FOR_TEST, + DEFAULT_WAN_2_1_T2V_1_3B_MODEL_NAME_FOR_TEST, + DEFAULT_WAN_2_1_T2V_14B_MODEL_NAME_FOR_TEST, + DEFAULT_WAN_2_2_I2V_A14B_MODEL_NAME_FOR_TEST, + DEFAULT_WAN_2_2_T2V_A14B_MODEL_NAME_FOR_TEST, + DEFAULT_WAN_2_2_TI2V_5B_MODEL_NAME_FOR_TEST, +) + +# All test cases with clean default values +# To test different models, simply add more DiffusionCase entries +ONE_GPU_CASES_A: list[DiffusionTestCase] = [ + # === Text to Image (T2I) === + DiffusionTestCase( + "qwen_image_t2i", + DiffusionServerArgs( + model_path=DEFAULT_QWEN_IMAGE_MODEL_NAME_FOR_TEST, + ), + T2I_sampling_params, + ), + DiffusionTestCase( + "qwen_image_t2i_cache_dit_enabled", + DiffusionServerArgs( + model_path=DEFAULT_QWEN_IMAGE_MODEL_NAME_FOR_TEST, + enable_cache_dit=True, + ), + T2I_sampling_params, + ), + DiffusionTestCase( + "flux_image_t2i", + DiffusionServerArgs(model_path=DEFAULT_FLUX_1_DEV_MODEL_NAME_FOR_TEST), + T2I_sampling_params, + ), + # TODO: modeling of flux different from official flux, so weights can't be loaded + # consider opting for a different quantized hf-repo + # DiffusionTestCase( + # "flux_image_t2i_override_transformer_weights_path_fp8", + # DiffusionServerArgs( + # model_path="black-forest-labs/FLUX.1-dev", + # extras=["--transformer-weights-path black-forest-labs/FLUX.1-dev-FP8"] + # ), + # T2I_sampling_params, + # ), + DiffusionTestCase( + "flux_2_image_t2i", + DiffusionServerArgs(model_path=DEFAULT_FLUX_2_DEV_MODEL_NAME_FOR_TEST), + T2I_sampling_params, + ), + DiffusionTestCase( + "flux_2_klein_image_t2i", + DiffusionServerArgs( + model_path=DEFAULT_FLUX_2_KLEIN_4B_MODEL_NAME_FOR_TEST, + ), + T2I_sampling_params, + ), + # TODO: replace with a faster model to test the --dit-layerwise-offload + # TODO: currently, we don't support sending more than one request in test, and setting `num_outputs_per_prompt` to 2 doesn't guarantee the denoising be executed twice, + # so we do one warmup and send one request instead + DiffusionTestCase( + "layerwise_offload", + DiffusionServerArgs( + model_path=DEFAULT_SMALL_MODEL_NAME_FOR_TEST, + dit_layerwise_offload=True, + dit_offload_prefetch_size=2, + ), + T2I_sampling_params, + ), + DiffusionTestCase( + "zimage_image_t2i", + DiffusionServerArgs(model_path=DEFAULT_SMALL_MODEL_NAME_FOR_TEST), + T2I_sampling_params, + ), + DiffusionTestCase( + "zimage_image_t2i_fp8", + DiffusionServerArgs( + model_path=DEFAULT_SMALL_MODEL_NAME_FOR_TEST, + extras=["--transformer-path MickJ/Z-Image-Turbo-fp8"], + ), + T2I_sampling_params, + ), + # Multi-LoRA test case for Z-Image-Turbo + DiffusionTestCase( + "zimage_image_t2i_multi_lora", + DiffusionServerArgs( + model_path=DEFAULT_SMALL_MODEL_NAME_FOR_TEST, + lora_path="reverentelusarca/elusarca-anime-style-lora-z-image-turbo", + second_lora_path="tarn59/pixel_art_style_lora_z_image_turbo", + ), + T2I_sampling_params, + run_lora_basic_api_check=True, + run_lora_dynamic_switch_check=True, + run_multi_lora_api_check=True, + ), + # === Text and Image to Image (TI2I) === + DiffusionTestCase( + "qwen_image_edit_ti2i", + DiffusionServerArgs(model_path=DEFAULT_QWEN_IMAGE_EDIT_MODEL_NAME_FOR_TEST), + TI2I_sampling_params, + ), + DiffusionTestCase( + "qwen_image_edit_2509_ti2i", + DiffusionServerArgs( + model_path=DEFAULT_QWEN_IMAGE_EDIT_2509_MODEL_NAME_FOR_TEST, + ), + MULTI_IMAGE_TI2I_sampling_params, + ), + DiffusionTestCase( + "qwen_image_edit_2511_ti2i", + DiffusionServerArgs( + model_path=DEFAULT_QWEN_IMAGE_EDIT_2511_MODEL_NAME_FOR_TEST, + ), + TI2I_sampling_params, + ), + DiffusionTestCase( + "qwen_image_layered_i2i", + DiffusionServerArgs( + model_path=DEFAULT_QWEN_IMAGE_LAYERED_MODEL_NAME_FOR_TEST, + ), + MULTI_FRAME_I2I_sampling_params, + ), + # Upscaling (Real-ESRGAN 4×) for T2I + DiffusionTestCase( + "flux_2_image_t2i_upscaling_4x", + DiffusionServerArgs( + model_path="black-forest-labs/FLUX.2-dev", + ), + DiffusionSamplingParams( + prompt="Doraemon is eating dorayaki", + output_size="1024x1024", + extras={"enable_upscaling": True, "upscaling_scale": 4}, + ), + ), +] + +ONE_GPU_CASES_B: list[DiffusionTestCase] = [ + # === Text to Video (T2V) === + DiffusionTestCase( + "wan2_1_t2v_1.3b", + DiffusionServerArgs( + model_path=DEFAULT_WAN_2_1_T2V_1_3B_MODEL_NAME_FOR_TEST, + ), + T2V_sampling_params, + ), + DiffusionTestCase( + "wan2_1_t2v_1.3b_text_encoder_cpu_offload", + DiffusionServerArgs( + model_path=DEFAULT_WAN_2_1_T2V_1_3B_MODEL_NAME_FOR_TEST, + text_encoder_cpu_offload=True, + ), + T2V_sampling_params, + ), + # TeaCache acceleration test for Wan video model + DiffusionTestCase( + "wan2_1_t2v_1.3b_teacache_enabled", + DiffusionServerArgs( + model_path=DEFAULT_WAN_2_1_T2V_1_3B_MODEL_NAME_FOR_TEST, + ), + DiffusionSamplingParams( + prompt=T2V_PROMPT, + extras={"enable_teacache": True}, + ), + ), + # Frame interpolation (2× / exp=1) + # Uses the same 1.3B model already in the suite; + DiffusionTestCase( + "wan2_1_t2v_1.3b_frame_interp_2x", + DiffusionServerArgs( + model_path="Wan-AI/Wan2.1-T2V-1.3B-Diffusers", + ), + DiffusionSamplingParams( + prompt=T2V_PROMPT, + extras={"enable_frame_interpolation": True, "frame_interpolation_exp": 1}, + ), + ), + # Upscaling (Real-ESRGAN 4×) + # Uses the same 1.3B model already in the suite; + DiffusionTestCase( + "wan2_1_t2v_1.3b_upscaling_4x", + DiffusionServerArgs( + model_path="Wan-AI/Wan2.1-T2V-1.3B-Diffusers", + ), + DiffusionSamplingParams( + prompt=T2V_PROMPT, + extras={"enable_upscaling": True, "upscaling_scale": 4}, + ), + ), + # Combined: Frame interpolation (2×) + Upscaling (4×) + # Verifies that both post-processing steps compose correctly. + DiffusionTestCase( + "wan2_1_t2v_1.3b_frame_interp_2x_upscaling_4x", + DiffusionServerArgs( + model_path="Wan-AI/Wan2.1-T2V-1.3B-Diffusers", + ), + DiffusionSamplingParams( + prompt=T2V_PROMPT, + extras={ + "enable_frame_interpolation": True, + "frame_interpolation_exp": 1, + "enable_upscaling": True, + "upscaling_scale": 4, + }, + ), + ), + # LoRA test case for single transformer + merge/unmerge API test + # Note: Uses dynamic_lora_path instead of lora_path to test LayerwiseOffload + set_lora interaction + # Server starts WITHOUT LoRA, then set_lora is called after startup (Wan models auto-enable layerwise offload) + DiffusionTestCase( + "wan2_1_t2v_1_3b_lora_1gpu", + DiffusionServerArgs( + model_path=DEFAULT_WAN_2_1_T2V_1_3B_MODEL_NAME_FOR_TEST, + num_gpus=1, + dynamic_lora_path="Cseti/Wan-LoRA-Arcane-Jinx-v1", + ), + DiffusionSamplingParams( + prompt="csetiarcane Nfj1nx with blue hair, a woman walking in a cyberpunk city at night", + ), + run_lora_basic_api_check=True, + run_lora_dynamic_load_check=True, + ), + # NOTE(mick): flaky + # DiffusionTestCase( + # "hunyuan_video", + # DiffusionServerArgs( + # model_path="hunyuanvideo-community/HunyuanVideo", + # ), + # DiffusionSamplingParams( + # prompt=T2V_PROMPT, + # ), + # ), + DiffusionTestCase( + "flux_2_ti2i", + DiffusionServerArgs(model_path=DEFAULT_FLUX_2_DEV_MODEL_NAME_FOR_TEST), + TI2I_sampling_params, + ), + DiffusionTestCase( + "flux_2_t2i_customized_vae_path", + DiffusionServerArgs( + model_path=DEFAULT_FLUX_2_DEV_MODEL_NAME_FOR_TEST, + extras=["--vae-path=fal/FLUX.2-Tiny-AutoEncoder"], + ), + T2I_sampling_params, + run_perf_check=False, + ), + DiffusionTestCase( + "fast_hunyuan_video", + DiffusionServerArgs( + model_path="FastVideo/FastHunyuan-diffusers", + ), + T2V_sampling_params, + ), + # === Text and Image to Video (TI2V) === + DiffusionTestCase( + "wan2_2_ti2v_5b", + DiffusionServerArgs( + model_path=DEFAULT_WAN_2_2_TI2V_5B_MODEL_NAME_FOR_TEST, + ), + TI2V_sampling_params, + ), + DiffusionTestCase( + "fastwan2_2_ti2v_5b", + DiffusionServerArgs( + model_path="FastVideo/FastWan2.2-TI2V-5B-FullAttn-Diffusers", + ), + TI2V_sampling_params, + ), + # flaky + # === Helios T2V === + # DiffusionTestCase( + # "helios_base_t2v", + # DiffusionServerArgs( + # model_path="BestWishYsh/Helios-Base", + # ), + # DiffusionSamplingParams( + # prompt=T2V_PROMPT, + # output_size="640x384", + # num_frames=33, + # ), + # ), + # DiffusionTestCase( + # "helios_mid_t2v", + # DiffusionServerArgs( + # model_path="BestWishYsh/Helios-Mid", + # ), + # DiffusionSamplingParams( + # prompt=T2V_PROMPT, + # output_size="640x384", + # num_frames=33, + # ), + # ), + # DiffusionTestCase( + # "helios_distilled_t2v", + # DiffusionServerArgs( + # model_path="BestWishYsh/Helios-Distilled", + # ), + # DiffusionSamplingParams( + # prompt=T2V_PROMPT, + # output_size="640x384", + # num_frames=33, + # ), + # ), +] + +# Skip hunyuan3d on AMD: marching_cubes surface extraction produces invalid SDF on ROCm. +if not current_platform.is_hip(): + ONE_GPU_CASES_B.append( + DiffusionTestCase( + "hunyuan3d_shape_gen", + DiffusionServerArgs( + model_path="tencent/Hunyuan3D-2", + enable_warmup=False, + ), + HUNYUAN3D_SHAPE_sampling_params, + run_consistency_check=False, + ), + ) +# Skip turbowan on AMD: Triton requires 81920 shared memory, but AMD only has 65536. +if not current_platform.is_hip(): + ONE_GPU_CASES_B.append( + DiffusionTestCase( + "turbo_wan2_1_t2v_1.3b", + DiffusionServerArgs( + model_path="IPostYellow/TurboWan2.1-T2V-1.3B-Diffusers", + ), + T2V_sampling_params, + ) + ) +ONE_GPU_CASES_C = [ + _make_modelopt_ci_case( + "flux1_modelopt_fp8_t2i", + model_path=DEFAULT_FLUX_1_DEV_MODEL_NAME_FOR_TEST, + modality="image", + sampling_params=MODELOPT_T2I_CI_sampling_params, + extras=["--transformer-path", MODELOPT_FLUX1_FP8_TRANSFORMER], + ), + _make_modelopt_ci_case( + "flux2_modelopt_fp8_t2i", + model_path=DEFAULT_FLUX_2_DEV_MODEL_NAME_FOR_TEST, + modality="image", + sampling_params=MODELOPT_T2I_CI_sampling_params, + extras=["--transformer-path", MODELOPT_FLUX2_FP8_TRANSFORMER], + ), + _make_modelopt_ci_case( + "wan22_modelopt_fp8_t2v", + model_path=DEFAULT_WAN_2_2_T2V_A14B_MODEL_NAME_FOR_TEST, + modality="video", + sampling_params=MODELOPT_T2V_CI_sampling_params, + extras=["--transformer-path", MODELOPT_WAN22_FP8_TRANSFORMER], + ), + _make_modelopt_ci_case( + "flux1_modelopt_nvfp4_t2i", + model_path=DEFAULT_FLUX_1_DEV_MODEL_NAME_FOR_TEST, + modality="image", + sampling_params=MODELOPT_T2I_CI_sampling_params, + extras=["--transformer-path", MODELOPT_FLUX1_NVFP4_TRANSFORMER], + env_vars=MODELOPT_NVFP4_B200_ENV_VARS, + ), + _make_modelopt_ci_case( + "flux2_modelopt_nvfp4_t2i", + model_path=MODELOPT_FLUX2_NVFP4_MODEL, + modality="image", + sampling_params=MODELOPT_T2I_CI_sampling_params, + extras=[], + env_vars=MODELOPT_NVFP4_B200_ENV_VARS, + ), + _make_modelopt_ci_case( + "wan22_modelopt_nvfp4_t2v", + model_path=DEFAULT_WAN_2_2_T2V_A14B_MODEL_NAME_FOR_TEST, + modality="video", + sampling_params=MODELOPT_T2V_CI_sampling_params, + extras=["--transformer-path", MODELOPT_WAN22_NVFP4_TRANSFORMER], + env_vars=MODELOPT_NVFP4_B200_ENV_VARS, + ), +] + +TWO_GPU_CASES_A = [ + DiffusionTestCase( + "wan2_2_i2v_a14b_2gpu", + DiffusionServerArgs( + model_path=DEFAULT_WAN_2_2_I2V_A14B_MODEL_NAME_FOR_TEST, + ), + TI2V_sampling_params, + ), + DiffusionTestCase( + "wan2_2_t2v_a14b_2gpu", + DiffusionServerArgs( + model_path=DEFAULT_WAN_2_2_T2V_A14B_MODEL_NAME_FOR_TEST, + extras=["--ulysses-degree=2"], + ), + T2V_sampling_params, + ), + # TeaCache bring-up test for Wan2.2 T2V A14B — verifies enable_teacache=True + # doesn't crash. Perf check disabled because Wan2.2-specific TeaCache + # coefficients are not yet calibrated (teacache_params=None, so no speedup). + DiffusionTestCase( + "wan2_2_t2v_a14b_teacache_2gpu", + DiffusionServerArgs( + model_path=DEFAULT_WAN_2_2_T2V_A14B_MODEL_NAME_FOR_TEST, + extras=["--ulysses-degree=2"], + ), + DiffusionSamplingParams( + prompt=T2V_PROMPT, + extras={"enable_teacache": True}, + ), + run_perf_check=False, + ), + # LoRA test case for transformer_2 support + DiffusionTestCase( + "wan2_2_t2v_a14b_lora_2gpu", + DiffusionServerArgs( + model_path=DEFAULT_WAN_2_2_T2V_A14B_MODEL_NAME_FOR_TEST, + lora_path="Cseti/wan2.2-14B-Arcane_Jinx-lora-v1", + extras=[ + "--lora-weight-name", + "985347-wan22_14B-low-Nfj1nx-e65.safetensors", + ], + ), + DiffusionSamplingParams( + prompt="Nfj1nx with blue hair, a woman walking in a cyberpunk city at night", + ), + run_lora_basic_api_check=True, + ), + DiffusionTestCase( + "wan2_1_t2v_14b_2gpu", + DiffusionServerArgs( + model_path=DEFAULT_WAN_2_1_T2V_14B_MODEL_NAME_FOR_TEST, + ), + DiffusionSamplingParams( + prompt=T2V_PROMPT, + output_size="832x480", + ), + ), + DiffusionTestCase( + "wan2_1_t2v_1.3b_cfg_parallel", + DiffusionServerArgs( + model_path=DEFAULT_WAN_2_1_T2V_1_3B_MODEL_NAME_FOR_TEST, + cfg_parallel=True, + ), + T2V_sampling_params, + ), + DiffusionTestCase( + "fsdp-inference", + DiffusionServerArgs( + model_path=DEFAULT_SMALL_MODEL_NAME_FOR_TEST, + extras=["--use-fsdp-inference"], + ), + T2I_sampling_params, + ), + DiffusionTestCase( + "mova_360p_tp2", + DiffusionServerArgs( + model_path=DEFAULT_MOVA_360P_MODEL_NAME_FOR_TEST, + tp_size=2, + dit_layerwise_offload=True, + ), + TI2V_sampling_params, + run_perf_check=False, + ), + DiffusionTestCase( + "mova_360p_ring1_uly2", + DiffusionServerArgs( + model_path=DEFAULT_MOVA_360P_MODEL_NAME_FOR_TEST, + ring_degree=1, + ulysses_degree=2, + dit_layerwise_offload=True, + ), + TI2V_sampling_params, + run_perf_check=False, + ), + DiffusionTestCase( + "ltx_2_two_stage_t2v", + DiffusionServerArgs( + model_path="Lightricks/LTX-2", + ulysses_degree=2, + dit_layerwise_offload=True, + extras=["--pipeline-class-name LTX2TwoStagePipeline"], + ), + T2V_sampling_params, + ), + DiffusionTestCase( + "ltx_2_3_two_stage_ti2v_2gpus", + DiffusionServerArgs( + model_path="Lightricks/LTX-2.3", + extras=["--pipeline-class-name LTX2TwoStagePipeline"], + ), + TI2V_sampling_params, + ), +] + +TWO_GPU_CASES_B = [ + DiffusionTestCase( + "wan2_1_i2v_14b_480P_2gpu", + DiffusionServerArgs( + model_path=DEFAULT_WAN_2_1_I2V_14B_480P_MODEL_NAME_FOR_TEST, + extras=["--ulysses-degree=2"], + ), + TI2V_sampling_params, + ), + DiffusionTestCase( + "ltx_2.3_two_stage_t2v_2gpus", + DiffusionServerArgs( + model_path="Lightricks/LTX-2.3", + extras=["--pipeline-class-name LTX2TwoStagePipeline"], + ), + T2V_sampling_params, + ), + # I2V LoRA test case + DiffusionTestCase( + "wan2_1_i2v_14b_lora_2gpu", + DiffusionServerArgs( + model_path=DEFAULT_WAN_2_1_I2V_14B_720P_MODEL_NAME_FOR_TEST, + lora_path="starsfriday/Wan2.1-Divine-Power-LoRA", + extras=["--ulysses-degree=2"], + ), + TI2V_sampling_params, + run_lora_basic_api_check=True, + ), + DiffusionTestCase( + "wan2_1_i2v_14b_720P_2gpu", + DiffusionServerArgs( + model_path=DEFAULT_WAN_2_1_I2V_14B_720P_MODEL_NAME_FOR_TEST, + extras=["--ulysses-degree=2"], + ), + TI2V_sampling_params, + ), + DiffusionTestCase( + "qwen_image_t2i_2_gpus", + DiffusionServerArgs( + model_path=DEFAULT_QWEN_IMAGE_MODEL_NAME_FOR_TEST, + # test ring attn + ulysses_degree=1, + ring_degree=2, + ), + T2I_sampling_params, + ), + DiffusionTestCase( + "zimage_image_t2i_2_gpus", + DiffusionServerArgs( + model_path=DEFAULT_SMALL_MODEL_NAME_FOR_TEST, + ulysses_degree=2, + ), + T2I_sampling_params, + ), + DiffusionTestCase( + "zimage_image_t2i_2_gpus_non_square", + DiffusionServerArgs( + model_path=DEFAULT_SMALL_MODEL_NAME_FOR_TEST, + ulysses_degree=2, + ), + DiffusionSamplingParams( + prompt=T2I_sampling_params.prompt, + output_size="1280x720", + ), + run_perf_check=False, + ), + DiffusionTestCase( + "flux_image_t2i_2_gpus", + DiffusionServerArgs( + model_path=DEFAULT_FLUX_1_DEV_MODEL_NAME_FOR_TEST, + ), + T2I_sampling_params, + ), + DiffusionTestCase( + "flux_2_image_t2i_2_gpus", + DiffusionServerArgs( + model_path=DEFAULT_FLUX_2_DEV_MODEL_NAME_FOR_TEST, + tp_size=2, + ), + T2I_sampling_params, + ), + DiffusionTestCase( + "flux_2_klein_ti2i_2_gpus", + DiffusionServerArgs( + model_path="black-forest-labs/FLUX.2-klein-4B", + ), + TI2I_sampling_params, + ), + DiffusionTestCase( + "ltx_2.3_one_stage_ti2v", + DiffusionServerArgs( + model_path="Lightricks/LTX-2.3", + ), + TI2V_sampling_params, + ), +] + +if not current_platform.is_hip(): + # Flux2 multi-image edit with cache-dit, regression test + ONE_GPU_CASES_B.append( + DiffusionTestCase( + "flux_2_ti2i_multi_image_cache_dit", + DiffusionServerArgs( + model_path="black-forest-labs/FLUX.2-dev", + enable_cache_dit=True, + ), + MULTI_IMAGE_TI2I_UPLOAD_sampling_params, + ) + ) + +ONE_GPU_CASES = [*ONE_GPU_CASES_A, *ONE_GPU_CASES_B, *ONE_GPU_CASES_C] +TWO_GPU_CASES_A = _with_default_num_gpus(TWO_GPU_CASES_A, 2) +TWO_GPU_CASES_B = _with_default_num_gpus(TWO_GPU_CASES_B, 2) +TWO_GPU_CASES = [*TWO_GPU_CASES_A, *TWO_GPU_CASES_B] diff --git a/python/sglang/multimodal_gen/test/server/test_server_1_gpu.py b/python/sglang/multimodal_gen/test/server/test_server_1_gpu.py index 54ca6ee5d..33f6a20cc 100644 --- a/python/sglang/multimodal_gen/test/server/test_server_1_gpu.py +++ b/python/sglang/multimodal_gen/test/server/test_server_1_gpu.py @@ -10,14 +10,12 @@ from __future__ import annotations import pytest from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger +from sglang.multimodal_gen.test.server.gpu_cases import ONE_GPU_CASES from sglang.multimodal_gen.test.server.test_server_common import ( # noqa: F401 DiffusionServerBase, diffusion_server, ) -from sglang.multimodal_gen.test.server.testcase_configs import ( - ONE_GPU_CASES, - DiffusionTestCase, -) +from sglang.multimodal_gen.test.server.testcase_configs import DiffusionTestCase logger = init_logger(__name__) diff --git a/python/sglang/multimodal_gen/test/server/test_server_2_gpu.py b/python/sglang/multimodal_gen/test/server/test_server_2_gpu.py index 5b4e5f37d..20fd1b658 100644 --- a/python/sglang/multimodal_gen/test/server/test_server_2_gpu.py +++ b/python/sglang/multimodal_gen/test/server/test_server_2_gpu.py @@ -6,14 +6,12 @@ from __future__ import annotations import pytest +from sglang.multimodal_gen.test.server.gpu_cases import TWO_GPU_CASES from sglang.multimodal_gen.test.server.test_server_common import ( # noqa: F401 DiffusionServerBase, diffusion_server, ) -from sglang.multimodal_gen.test.server.testcase_configs import ( - TWO_GPU_CASES, - DiffusionTestCase, -) +from sglang.multimodal_gen.test.server.testcase_configs import DiffusionTestCase class TestDiffusionServerTwoGpu(DiffusionServerBase): diff --git a/python/sglang/multimodal_gen/test/server/test_server_c.py b/python/sglang/multimodal_gen/test/server/test_server_c.py index 831360ef9..7e4b070a0 100644 --- a/python/sglang/multimodal_gen/test/server/test_server_c.py +++ b/python/sglang/multimodal_gen/test/server/test_server_c.py @@ -7,14 +7,12 @@ from __future__ import annotations import pytest from sglang.multimodal_gen.runtime.utils.logging_utils import init_logger +from sglang.multimodal_gen.test.server.gpu_cases import ONE_GPU_CASES_C from sglang.multimodal_gen.test.server.test_server_common import ( # noqa: F401 DiffusionServerBase, diffusion_server, ) -from sglang.multimodal_gen.test.server.testcase_configs import ( - ONE_GPU_CASES_C, - DiffusionTestCase, -) +from sglang.multimodal_gen.test.server.testcase_configs import DiffusionTestCase logger = init_logger(__name__) diff --git a/python/sglang/multimodal_gen/test/server/testcase_configs.py b/python/sglang/multimodal_gen/test/server/testcase_configs.py index cb181ad7a..25016e47b 100644 --- a/python/sglang/multimodal_gen/test/server/testcase_configs.py +++ b/python/sglang/multimodal_gen/test/server/testcase_configs.py @@ -29,27 +29,7 @@ from typing import Sequence from sglang.multimodal_gen.configs.pipeline_configs.base import ModelTaskType from sglang.multimodal_gen.registry import get_model_info -from sglang.multimodal_gen.runtime.platforms import current_platform from sglang.multimodal_gen.runtime.utils.perf_logger import RequestPerfRecord -from sglang.multimodal_gen.test.test_utils import ( - DEFAULT_FLUX_1_DEV_MODEL_NAME_FOR_TEST, - DEFAULT_FLUX_2_DEV_MODEL_NAME_FOR_TEST, - DEFAULT_FLUX_2_KLEIN_4B_MODEL_NAME_FOR_TEST, - DEFAULT_MOVA_360P_MODEL_NAME_FOR_TEST, - DEFAULT_QWEN_IMAGE_EDIT_2509_MODEL_NAME_FOR_TEST, - DEFAULT_QWEN_IMAGE_EDIT_2511_MODEL_NAME_FOR_TEST, - DEFAULT_QWEN_IMAGE_EDIT_MODEL_NAME_FOR_TEST, - DEFAULT_QWEN_IMAGE_LAYERED_MODEL_NAME_FOR_TEST, - DEFAULT_QWEN_IMAGE_MODEL_NAME_FOR_TEST, - DEFAULT_SMALL_MODEL_NAME_FOR_TEST, - DEFAULT_WAN_2_1_I2V_14B_480P_MODEL_NAME_FOR_TEST, - DEFAULT_WAN_2_1_I2V_14B_720P_MODEL_NAME_FOR_TEST, - DEFAULT_WAN_2_1_T2V_1_3B_MODEL_NAME_FOR_TEST, - DEFAULT_WAN_2_1_T2V_14B_MODEL_NAME_FOR_TEST, - DEFAULT_WAN_2_2_I2V_A14B_MODEL_NAME_FOR_TEST, - DEFAULT_WAN_2_2_T2V_A14B_MODEL_NAME_FOR_TEST, - DEFAULT_WAN_2_2_TI2V_5B_MODEL_NAME_FOR_TEST, -) @dataclass @@ -445,329 +425,11 @@ TURBOWAN_I2V_sampling_params = DiffusionSamplingParams( fps=4, ) -# All test cases with clean default values -# To test different models, simply add more DiffusionCase entries -ONE_GPU_CASES_A: list[DiffusionTestCase] = [ - # === Text to Image (T2I) === - DiffusionTestCase( - "qwen_image_t2i", - DiffusionServerArgs( - model_path=DEFAULT_QWEN_IMAGE_MODEL_NAME_FOR_TEST, - ), - T2I_sampling_params, - ), - DiffusionTestCase( - "qwen_image_t2i_cache_dit_enabled", - DiffusionServerArgs( - model_path=DEFAULT_QWEN_IMAGE_MODEL_NAME_FOR_TEST, - enable_cache_dit=True, - ), - T2I_sampling_params, - ), - DiffusionTestCase( - "flux_image_t2i", - DiffusionServerArgs(model_path=DEFAULT_FLUX_1_DEV_MODEL_NAME_FOR_TEST), - T2I_sampling_params, - ), - # TODO: modeling of flux different from official flux, so weights can't be loaded - # consider opting for a different quantized hf-repo - # DiffusionTestCase( - # "flux_image_t2i_override_transformer_weights_path_fp8", - # DiffusionServerArgs( - # model_path="black-forest-labs/FLUX.1-dev", - # extras=["--transformer-weights-path black-forest-labs/FLUX.1-dev-FP8"] - # ), - # T2I_sampling_params, - # ), - DiffusionTestCase( - "flux_2_image_t2i", - DiffusionServerArgs(model_path=DEFAULT_FLUX_2_DEV_MODEL_NAME_FOR_TEST), - T2I_sampling_params, - ), - DiffusionTestCase( - "flux_2_klein_image_t2i", - DiffusionServerArgs( - model_path=DEFAULT_FLUX_2_KLEIN_4B_MODEL_NAME_FOR_TEST, - ), - T2I_sampling_params, - ), - # TODO: replace with a faster model to test the --dit-layerwise-offload - # TODO: currently, we don't support sending more than one request in test, and setting `num_outputs_per_prompt` to 2 doesn't guarantee the denoising be executed twice, - # so we do one warmup and send one request instead - DiffusionTestCase( - "layerwise_offload", - DiffusionServerArgs( - model_path=DEFAULT_SMALL_MODEL_NAME_FOR_TEST, - dit_layerwise_offload=True, - dit_offload_prefetch_size=2, - ), - T2I_sampling_params, - ), - DiffusionTestCase( - "zimage_image_t2i", - DiffusionServerArgs(model_path=DEFAULT_SMALL_MODEL_NAME_FOR_TEST), - T2I_sampling_params, - ), - DiffusionTestCase( - "zimage_image_t2i_fp8", - DiffusionServerArgs( - model_path=DEFAULT_SMALL_MODEL_NAME_FOR_TEST, - extras=["--transformer-path MickJ/Z-Image-Turbo-fp8"], - ), - T2I_sampling_params, - ), - # Multi-LoRA test case for Z-Image-Turbo - DiffusionTestCase( - "zimage_image_t2i_multi_lora", - DiffusionServerArgs( - model_path=DEFAULT_SMALL_MODEL_NAME_FOR_TEST, - lora_path="reverentelusarca/elusarca-anime-style-lora-z-image-turbo", - second_lora_path="tarn59/pixel_art_style_lora_z_image_turbo", - ), - T2I_sampling_params, - run_lora_basic_api_check=True, - run_lora_dynamic_switch_check=True, - run_multi_lora_api_check=True, - ), - # === Text and Image to Image (TI2I) === - DiffusionTestCase( - "qwen_image_edit_ti2i", - DiffusionServerArgs(model_path=DEFAULT_QWEN_IMAGE_EDIT_MODEL_NAME_FOR_TEST), - TI2I_sampling_params, - ), - DiffusionTestCase( - "qwen_image_edit_2509_ti2i", - DiffusionServerArgs( - model_path=DEFAULT_QWEN_IMAGE_EDIT_2509_MODEL_NAME_FOR_TEST, - ), - MULTI_IMAGE_TI2I_sampling_params, - ), - DiffusionTestCase( - "qwen_image_edit_2511_ti2i", - DiffusionServerArgs( - model_path=DEFAULT_QWEN_IMAGE_EDIT_2511_MODEL_NAME_FOR_TEST, - ), - TI2I_sampling_params, - ), - DiffusionTestCase( - "qwen_image_layered_i2i", - DiffusionServerArgs( - model_path=DEFAULT_QWEN_IMAGE_LAYERED_MODEL_NAME_FOR_TEST, - ), - MULTI_FRAME_I2I_sampling_params, - ), - # Upscaling (Real-ESRGAN 4×) for T2I - DiffusionTestCase( - "flux_2_image_t2i_upscaling_4x", - DiffusionServerArgs( - model_path="black-forest-labs/FLUX.2-dev", - ), - DiffusionSamplingParams( - prompt="Doraemon is eating dorayaki", - output_size="1024x1024", - extras={"enable_upscaling": True, "upscaling_scale": 4}, - ), - ), -] - HUNYUAN3D_SHAPE_sampling_params = DiffusionSamplingParams( prompt="", image_path="https://raw.githubusercontent.com/sgl-project/sgl-test-files/main/diffusion-ci/consistency_gt/1-gpu/hunyuan3d_2_0/hunyuan3d.png", ) -ONE_GPU_CASES_B: list[DiffusionTestCase] = [ - # === Text to Video (T2V) === - DiffusionTestCase( - "wan2_1_t2v_1.3b", - DiffusionServerArgs( - model_path=DEFAULT_WAN_2_1_T2V_1_3B_MODEL_NAME_FOR_TEST, - ), - T2V_sampling_params, - ), - DiffusionTestCase( - "wan2_1_t2v_1.3b_text_encoder_cpu_offload", - DiffusionServerArgs( - model_path=DEFAULT_WAN_2_1_T2V_1_3B_MODEL_NAME_FOR_TEST, - text_encoder_cpu_offload=True, - ), - T2V_sampling_params, - ), - # TeaCache acceleration test for Wan video model - DiffusionTestCase( - "wan2_1_t2v_1.3b_teacache_enabled", - DiffusionServerArgs( - model_path=DEFAULT_WAN_2_1_T2V_1_3B_MODEL_NAME_FOR_TEST, - ), - DiffusionSamplingParams( - prompt=T2V_PROMPT, - extras={"enable_teacache": True}, - ), - ), - # Frame interpolation (2× / exp=1) - # Uses the same 1.3B model already in the suite; - DiffusionTestCase( - "wan2_1_t2v_1.3b_frame_interp_2x", - DiffusionServerArgs( - model_path="Wan-AI/Wan2.1-T2V-1.3B-Diffusers", - ), - DiffusionSamplingParams( - prompt=T2V_PROMPT, - extras={"enable_frame_interpolation": True, "frame_interpolation_exp": 1}, - ), - ), - # Upscaling (Real-ESRGAN 4×) - # Uses the same 1.3B model already in the suite; - DiffusionTestCase( - "wan2_1_t2v_1.3b_upscaling_4x", - DiffusionServerArgs( - model_path="Wan-AI/Wan2.1-T2V-1.3B-Diffusers", - ), - DiffusionSamplingParams( - prompt=T2V_PROMPT, - extras={"enable_upscaling": True, "upscaling_scale": 4}, - ), - ), - # Combined: Frame interpolation (2×) + Upscaling (4×) - # Verifies that both post-processing steps compose correctly. - DiffusionTestCase( - "wan2_1_t2v_1.3b_frame_interp_2x_upscaling_4x", - DiffusionServerArgs( - model_path="Wan-AI/Wan2.1-T2V-1.3B-Diffusers", - ), - DiffusionSamplingParams( - prompt=T2V_PROMPT, - extras={ - "enable_frame_interpolation": True, - "frame_interpolation_exp": 1, - "enable_upscaling": True, - "upscaling_scale": 4, - }, - ), - ), - # LoRA test case for single transformer + merge/unmerge API test - # Note: Uses dynamic_lora_path instead of lora_path to test LayerwiseOffload + set_lora interaction - # Server starts WITHOUT LoRA, then set_lora is called after startup (Wan models auto-enable layerwise offload) - DiffusionTestCase( - "wan2_1_t2v_1_3b_lora_1gpu", - DiffusionServerArgs( - model_path=DEFAULT_WAN_2_1_T2V_1_3B_MODEL_NAME_FOR_TEST, - num_gpus=1, - dynamic_lora_path="Cseti/Wan-LoRA-Arcane-Jinx-v1", - ), - DiffusionSamplingParams( - prompt="csetiarcane Nfj1nx with blue hair, a woman walking in a cyberpunk city at night", - ), - run_lora_basic_api_check=True, - run_lora_dynamic_load_check=True, - ), - # NOTE(mick): flaky - # DiffusionTestCase( - # "hunyuan_video", - # DiffusionServerArgs( - # model_path="hunyuanvideo-community/HunyuanVideo", - # ), - # DiffusionSamplingParams( - # prompt=T2V_PROMPT, - # ), - # ), - DiffusionTestCase( - "flux_2_ti2i", - DiffusionServerArgs(model_path=DEFAULT_FLUX_2_DEV_MODEL_NAME_FOR_TEST), - TI2I_sampling_params, - ), - DiffusionTestCase( - "flux_2_t2i_customized_vae_path", - DiffusionServerArgs( - model_path=DEFAULT_FLUX_2_DEV_MODEL_NAME_FOR_TEST, - extras=["--vae-path=fal/FLUX.2-Tiny-AutoEncoder"], - ), - T2I_sampling_params, - run_perf_check=False, - ), - DiffusionTestCase( - "fast_hunyuan_video", - DiffusionServerArgs( - model_path="FastVideo/FastHunyuan-diffusers", - ), - T2V_sampling_params, - ), - # === Text and Image to Video (TI2V) === - DiffusionTestCase( - "wan2_2_ti2v_5b", - DiffusionServerArgs( - model_path=DEFAULT_WAN_2_2_TI2V_5B_MODEL_NAME_FOR_TEST, - ), - TI2V_sampling_params, - ), - DiffusionTestCase( - "fastwan2_2_ti2v_5b", - DiffusionServerArgs( - model_path="FastVideo/FastWan2.2-TI2V-5B-FullAttn-Diffusers", - ), - TI2V_sampling_params, - ), - # flaky - # === Helios T2V === - # DiffusionTestCase( - # "helios_base_t2v", - # DiffusionServerArgs( - # model_path="BestWishYsh/Helios-Base", - # ), - # DiffusionSamplingParams( - # prompt=T2V_PROMPT, - # output_size="640x384", - # num_frames=33, - # ), - # ), - # DiffusionTestCase( - # "helios_mid_t2v", - # DiffusionServerArgs( - # model_path="BestWishYsh/Helios-Mid", - # ), - # DiffusionSamplingParams( - # prompt=T2V_PROMPT, - # output_size="640x384", - # num_frames=33, - # ), - # ), - # DiffusionTestCase( - # "helios_distilled_t2v", - # DiffusionServerArgs( - # model_path="BestWishYsh/Helios-Distilled", - # ), - # DiffusionSamplingParams( - # prompt=T2V_PROMPT, - # output_size="640x384", - # num_frames=33, - # ), - # ), -] - -# Skip hunyuan3d on AMD: marching_cubes surface extraction produces invalid SDF on ROCm. -if not current_platform.is_hip(): - ONE_GPU_CASES_B.append( - DiffusionTestCase( - "hunyuan3d_shape_gen", - DiffusionServerArgs( - model_path="tencent/Hunyuan3D-2", - enable_warmup=False, - ), - HUNYUAN3D_SHAPE_sampling_params, - run_consistency_check=False, - ), - ) -# Skip turbowan on AMD: Triton requires 81920 shared memory, but AMD only has 65536. -if not current_platform.is_hip(): - ONE_GPU_CASES_B.append( - DiffusionTestCase( - "turbo_wan2_1_t2v_1.3b", - DiffusionServerArgs( - model_path="IPostYellow/TurboWan2.1-T2V-1.3B-Diffusers", - ), - T2V_sampling_params, - ) - ) - MODELOPT_FLUX1_FP8_TRANSFORMER = "BBuf/flux1-dev-modelopt-fp8-sglang-transformer" MODELOPT_FLUX2_FP8_TRANSFORMER = "BBuf/flux2-dev-modelopt-fp8-sglang-transformer" MODELOPT_WAN22_FP8_TRANSFORMER = "BBuf/wan22-t2v-a14b-modelopt-fp8-sglang-transformer" @@ -803,279 +465,6 @@ def _make_modelopt_ci_case( ) -ONE_GPU_CASES_C = [ - _make_modelopt_ci_case( - "flux1_modelopt_fp8_t2i", - model_path=DEFAULT_FLUX_1_DEV_MODEL_NAME_FOR_TEST, - modality="image", - sampling_params=MODELOPT_T2I_CI_sampling_params, - extras=["--transformer-path", MODELOPT_FLUX1_FP8_TRANSFORMER], - ), - _make_modelopt_ci_case( - "flux2_modelopt_fp8_t2i", - model_path=DEFAULT_FLUX_2_DEV_MODEL_NAME_FOR_TEST, - modality="image", - sampling_params=MODELOPT_T2I_CI_sampling_params, - extras=["--transformer-path", MODELOPT_FLUX2_FP8_TRANSFORMER], - ), - _make_modelopt_ci_case( - "wan22_modelopt_fp8_t2v", - model_path=DEFAULT_WAN_2_2_T2V_A14B_MODEL_NAME_FOR_TEST, - modality="video", - sampling_params=MODELOPT_T2V_CI_sampling_params, - extras=["--transformer-path", MODELOPT_WAN22_FP8_TRANSFORMER], - ), - _make_modelopt_ci_case( - "flux1_modelopt_nvfp4_t2i", - model_path=DEFAULT_FLUX_1_DEV_MODEL_NAME_FOR_TEST, - modality="image", - sampling_params=MODELOPT_T2I_CI_sampling_params, - extras=["--transformer-path", MODELOPT_FLUX1_NVFP4_TRANSFORMER], - env_vars=MODELOPT_NVFP4_B200_ENV_VARS, - ), - _make_modelopt_ci_case( - "flux2_modelopt_nvfp4_t2i", - model_path=MODELOPT_FLUX2_NVFP4_MODEL, - modality="image", - sampling_params=MODELOPT_T2I_CI_sampling_params, - extras=[], - env_vars=MODELOPT_NVFP4_B200_ENV_VARS, - ), - _make_modelopt_ci_case( - "wan22_modelopt_nvfp4_t2v", - model_path=DEFAULT_WAN_2_2_T2V_A14B_MODEL_NAME_FOR_TEST, - modality="video", - sampling_params=MODELOPT_T2V_CI_sampling_params, - extras=["--transformer-path", MODELOPT_WAN22_NVFP4_TRANSFORMER], - env_vars=MODELOPT_NVFP4_B200_ENV_VARS, - ), -] - -TWO_GPU_CASES_A = [ - DiffusionTestCase( - "wan2_2_i2v_a14b_2gpu", - DiffusionServerArgs( - model_path=DEFAULT_WAN_2_2_I2V_A14B_MODEL_NAME_FOR_TEST, - ), - TI2V_sampling_params, - ), - DiffusionTestCase( - "wan2_2_t2v_a14b_2gpu", - DiffusionServerArgs( - model_path=DEFAULT_WAN_2_2_T2V_A14B_MODEL_NAME_FOR_TEST, - extras=["--ulysses-degree=2"], - ), - T2V_sampling_params, - ), - # TeaCache bring-up test for Wan2.2 T2V A14B — verifies enable_teacache=True - # doesn't crash. Perf check disabled because Wan2.2-specific TeaCache - # coefficients are not yet calibrated (teacache_params=None, so no speedup). - DiffusionTestCase( - "wan2_2_t2v_a14b_teacache_2gpu", - DiffusionServerArgs( - model_path=DEFAULT_WAN_2_2_T2V_A14B_MODEL_NAME_FOR_TEST, - extras=["--ulysses-degree=2"], - ), - DiffusionSamplingParams( - prompt=T2V_PROMPT, - extras={"enable_teacache": True}, - ), - run_perf_check=False, - ), - # LoRA test case for transformer_2 support - DiffusionTestCase( - "wan2_2_t2v_a14b_lora_2gpu", - DiffusionServerArgs( - model_path=DEFAULT_WAN_2_2_T2V_A14B_MODEL_NAME_FOR_TEST, - lora_path="Cseti/wan2.2-14B-Arcane_Jinx-lora-v1", - extras=[ - "--lora-weight-name", - "985347-wan22_14B-low-Nfj1nx-e65.safetensors", - ], - ), - DiffusionSamplingParams( - prompt="Nfj1nx with blue hair, a woman walking in a cyberpunk city at night", - ), - run_lora_basic_api_check=True, - ), - DiffusionTestCase( - "wan2_1_t2v_14b_2gpu", - DiffusionServerArgs( - model_path=DEFAULT_WAN_2_1_T2V_14B_MODEL_NAME_FOR_TEST, - ), - DiffusionSamplingParams( - prompt=T2V_PROMPT, - output_size="832x480", - ), - ), - DiffusionTestCase( - "wan2_1_t2v_1.3b_cfg_parallel", - DiffusionServerArgs( - model_path=DEFAULT_WAN_2_1_T2V_1_3B_MODEL_NAME_FOR_TEST, - cfg_parallel=True, - ), - T2V_sampling_params, - ), - DiffusionTestCase( - "fsdp-inference", - DiffusionServerArgs( - model_path=DEFAULT_SMALL_MODEL_NAME_FOR_TEST, - extras=["--use-fsdp-inference"], - ), - T2I_sampling_params, - ), - DiffusionTestCase( - "mova_360p_tp2", - DiffusionServerArgs( - model_path=DEFAULT_MOVA_360P_MODEL_NAME_FOR_TEST, - tp_size=2, - dit_layerwise_offload=True, - ), - TI2V_sampling_params, - run_perf_check=False, - ), - DiffusionTestCase( - "mova_360p_ring1_uly2", - DiffusionServerArgs( - model_path=DEFAULT_MOVA_360P_MODEL_NAME_FOR_TEST, - ring_degree=1, - ulysses_degree=2, - dit_layerwise_offload=True, - ), - TI2V_sampling_params, - run_perf_check=False, - ), - DiffusionTestCase( - "ltx_2_two_stage_t2v", - DiffusionServerArgs( - model_path="Lightricks/LTX-2", - ulysses_degree=2, - dit_layerwise_offload=True, - extras=["--pipeline-class-name LTX2TwoStagePipeline"], - ), - T2V_sampling_params, - ), - DiffusionTestCase( - "ltx_2_3_two_stage_ti2v_2gpus", - DiffusionServerArgs( - model_path="Lightricks/LTX-2.3", - extras=["--pipeline-class-name LTX2TwoStagePipeline"], - ), - TI2V_sampling_params, - ), -] - -TWO_GPU_CASES_B = [ - DiffusionTestCase( - "wan2_1_i2v_14b_480P_2gpu", - DiffusionServerArgs( - model_path=DEFAULT_WAN_2_1_I2V_14B_480P_MODEL_NAME_FOR_TEST, - extras=["--ulysses-degree=2"], - ), - TI2V_sampling_params, - ), - DiffusionTestCase( - "ltx_2.3_two_stage_t2v_2gpus", - DiffusionServerArgs( - model_path="Lightricks/LTX-2.3", - extras=["--pipeline-class-name LTX2TwoStagePipeline"], - ), - T2V_sampling_params, - ), - # I2V LoRA test case - DiffusionTestCase( - "wan2_1_i2v_14b_lora_2gpu", - DiffusionServerArgs( - model_path=DEFAULT_WAN_2_1_I2V_14B_720P_MODEL_NAME_FOR_TEST, - lora_path="starsfriday/Wan2.1-Divine-Power-LoRA", - extras=["--ulysses-degree=2"], - ), - TI2V_sampling_params, - run_lora_basic_api_check=True, - ), - DiffusionTestCase( - "wan2_1_i2v_14b_720P_2gpu", - DiffusionServerArgs( - model_path=DEFAULT_WAN_2_1_I2V_14B_720P_MODEL_NAME_FOR_TEST, - extras=["--ulysses-degree=2"], - ), - TI2V_sampling_params, - ), - DiffusionTestCase( - "qwen_image_t2i_2_gpus", - DiffusionServerArgs( - model_path=DEFAULT_QWEN_IMAGE_MODEL_NAME_FOR_TEST, - # test ring attn - ulysses_degree=1, - ring_degree=2, - ), - T2I_sampling_params, - ), - DiffusionTestCase( - "zimage_image_t2i_2_gpus", - DiffusionServerArgs( - model_path=DEFAULT_SMALL_MODEL_NAME_FOR_TEST, - ulysses_degree=2, - ), - T2I_sampling_params, - ), - DiffusionTestCase( - "zimage_image_t2i_2_gpus_non_square", - DiffusionServerArgs( - model_path=DEFAULT_SMALL_MODEL_NAME_FOR_TEST, - ulysses_degree=2, - ), - DiffusionSamplingParams( - prompt=T2I_sampling_params.prompt, - output_size="1280x720", - ), - run_perf_check=False, - ), - DiffusionTestCase( - "flux_image_t2i_2_gpus", - DiffusionServerArgs( - model_path=DEFAULT_FLUX_1_DEV_MODEL_NAME_FOR_TEST, - ), - T2I_sampling_params, - ), - DiffusionTestCase( - "flux_2_image_t2i_2_gpus", - DiffusionServerArgs( - model_path=DEFAULT_FLUX_2_DEV_MODEL_NAME_FOR_TEST, - tp_size=2, - ), - T2I_sampling_params, - ), - DiffusionTestCase( - "flux_2_klein_ti2i_2_gpus", - DiffusionServerArgs( - model_path="black-forest-labs/FLUX.2-klein-4B", - ), - TI2I_sampling_params, - ), - DiffusionTestCase( - "ltx_2.3_one_stage_ti2v", - DiffusionServerArgs( - model_path="Lightricks/LTX-2.3", - ), - TI2V_sampling_params, - ), -] - -if not current_platform.is_hip(): - # Flux2 multi-image edit with cache-dit, regression test - ONE_GPU_CASES_B.append( - DiffusionTestCase( - "flux_2_ti2i_multi_image_cache_dit", - DiffusionServerArgs( - model_path="black-forest-labs/FLUX.2-dev", - enable_cache_dit=True, - ), - MULTI_IMAGE_TI2I_UPLOAD_sampling_params, - ) - ) - - def _with_default_num_gpus( cases: list[DiffusionTestCase], num_gpus: int ) -> list[DiffusionTestCase]: @@ -1085,11 +474,6 @@ def _with_default_num_gpus( ] -ONE_GPU_CASES = [*ONE_GPU_CASES_A, *ONE_GPU_CASES_B, *ONE_GPU_CASES_C] -TWO_GPU_CASES_A = _with_default_num_gpus(TWO_GPU_CASES_A, 2) -TWO_GPU_CASES_B = _with_default_num_gpus(TWO_GPU_CASES_B, 2) -TWO_GPU_CASES = [*TWO_GPU_CASES_A, *TWO_GPU_CASES_B] - # Load global configuration BASELINE_CONFIG = BaselineConfig.load( Path(__file__).with_name("perf_baselines.json")