[diffusion] feat: support multi-frame image output (#15878)

Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
chhnb
2025-12-31 13:50:02 +08:00
committed by GitHub
co-authored by gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
parent db6b51a838
commit 3619ec61b4
7 changed files with 157 additions and 37 deletions
@@ -788,6 +788,69 @@
"expected_avg_denoise_ms": 1267.96,
"expected_median_denoise_ms": 1273.46
},
"qwen_image_layered_i2i": {
"stages_ms": {
"QwenImageLayeredBeforeDenoisingStage": 3240.24,
"TimestepPreparationStage": 3.14,
"DenoisingStage": 41551.18,
"DecodingStage": 312.93
},
"denoise_step_ms": {
"0": 809.93,
"1": 836.69,
"2": 834.98,
"3": 826.84,
"4": 827.15,
"5": 827.28,
"6": 830.97,
"7": 827.7,
"8": 829.4,
"9": 832.14,
"10": 825.99,
"11": 831.65,
"12": 829.31,
"13": 829.46,
"14": 828.33,
"15": 831.14,
"16": 830.44,
"17": 831.6,
"18": 829.18,
"19": 831.64,
"20": 828.21,
"21": 831.02,
"22": 831.39,
"23": 830.16,
"24": 832.21,
"25": 831.04,
"26": 830.48,
"27": 831.88,
"28": 833.5,
"29": 837.31,
"30": 828.16,
"31": 832.24,
"32": 833.56,
"33": 829.08,
"34": 833.11,
"35": 831.07,
"36": 832.71,
"37": 833.12,
"38": 830.65,
"39": 831.59,
"40": 833.24,
"41": 831.92,
"42": 832.77,
"43": 830.88,
"44": 833.75,
"45": 831.29,
"46": 834.48,
"47": 832.6,
"48": 835.24,
"49": 832.49
},
"expected_e2e_ms": 45109.63,
"expected_avg_denoise_ms": 830.86,
"expected_median_denoise_ms": 831.34
},
"fastwan2_2_ti2v_5b": {
"stages_ms": {
"InputValidationStage": 88.86,
@@ -103,6 +103,7 @@ def diffusion_server(case: DiffusionTestCase) -> ServerContext:
model=server_args.model_path,
prompt=sampling_params.prompt or "A colorful raccoon icon",
output_size=output_size,
output_format=sampling_params.output_format,
)
warmup.run_text_warmups(server_args.warmup_text)
@@ -455,6 +455,7 @@ class WarmupRunner:
model: str,
prompt: str,
output_size: str,
output_format: str = None,
):
self.client = OpenAI(
api_key="sglang-anything",
@@ -463,6 +464,7 @@ class WarmupRunner:
self.model = model
self.prompt = prompt
self.output_size = output_size
self.output_format = output_format
def run_text_warmups(self, count: int) -> None:
"""Run text-to-image warmup requests."""
@@ -511,6 +513,7 @@ class WarmupRunner:
n=1,
size=self.output_size,
response_format="b64_json",
output_format=self.output_format,
)
finally:
for img in images:
@@ -898,7 +901,9 @@ def get_generate_fn(
image_paths = new_image_paths
# Request parameters that affect output format
req_output_format = None # Not specified in current request
req_output_format = (
sampling_params.output_format
) # Not specified in current request
req_background = None # Not specified in current request
images = [open(image_path, "rb") for image_path in image_paths]
@@ -910,6 +915,8 @@ def get_generate_fn(
n=n,
size=output_size,
response_format="b64_json",
output_format=req_output_format,
extra_body={"num_frames": sampling_params.num_frames},
)
finally:
for img in images:
@@ -954,7 +961,6 @@ def get_generate_fn(
"""TI2I: Text + Image ? Image edit using direct URL transfer (no pre-download)."""
if not sampling_params.prompt or not sampling_params.image_path:
pytest.skip(f"{id}: no edit config")
# Handle both single URL and list of URLs
image_urls = sampling_params.image_path
if not isinstance(image_urls, list):
@@ -968,7 +974,9 @@ def get_generate_fn(
)
# Request parameters that affect output format
req_output_format = None # Not specified in current request
req_output_format = (
sampling_params.output_format
) # Not specified in current request
req_background = None # Not specified in current request
response = client.images.with_raw_response.edit(
@@ -978,7 +986,8 @@ def get_generate_fn(
n=n,
size=sampling_params.output_size,
response_format="b64_json",
extra_body={"url": image_urls},
output_format=req_output_format,
extra_body={"url": image_urls, "num_frames": sampling_params.num_frames},
)
result = response.parse()
@@ -173,6 +173,9 @@ class DiffusionSamplingParams:
# URL direct test flag - if True, don't pre-download URL images
direct_url_test: bool = False
# output format
output_format: str | None = None # "png", "jpeg", "mp4", etc.
num_outputs_per_prompt: int = 1
@@ -269,6 +272,15 @@ MULTI_IMAGE_TI2I_sampling_params = DiffusionSamplingParams(
],
direct_url_test=True,
)
MULTI_FRAME_I2I_sampling_params = DiffusionSamplingParams(
prompt="a high quality, cute halloween themed illustration, consistent style and lighting",
image_path=[
"https://raw.githubusercontent.com/QwenLM/Qwen-Image-Layered/main/assets/test_images/4.png"
],
num_frames=4,
direct_url_test=True,
output_format="png",
)
T2V_PROMPT = "A curious raccoon"
@@ -356,6 +368,16 @@ ONE_GPU_CASES_A: list[DiffusionTestCase] = [
),
MULTI_IMAGE_TI2I_sampling_params,
),
DiffusionTestCase(
"qwen_image_layered_i2i",
DiffusionServerArgs(
model_path="Qwen/Qwen-Image-Layered",
modality="image",
warmup_text=0,
warmup_edit=1,
),
MULTI_FRAME_I2I_sampling_params,
),
]
ONE_GPU_CASES_B: list[DiffusionTestCase] = [