[Bugfix] Fix Qwen-Image min-size normalization for tiny requests (#2637)

Signed-off-by: David Chen <530634352@qq.com>
This commit is contained in:
WeiQing Chen authored and GitHub committed 2026-04-09 20:51:01 +08:00
1 parent 956f53b278
commit 85d63c47f9
6 files changed
+65 -18

No files matched your search

@@ -0,0 +1,26 @@
import pytest
from vllm_omni.diffusion.utils.size_utils import (
normalize_min_aligned_size,
)
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
@pytest.mark.parametrize(
("height", "width", "expected"),
[
(1, 1, (16, 16)),
(15, 15, (16, 16)),
(17, 17, (16, 16)),
(31, 33, (16, 32)),
(64, 80, (64, 80)),
],
)
def test_normalize_min_aligned_size_clamps_to_minimum_aligned_shape(height, width, expected):
assert normalize_min_aligned_size(height, width, alignment=16) == expected
def test_normalize_min_aligned_size_rejects_invalid_alignment():
with pytest.raises(ValueError, match="positive alignment"):
normalize_min_aligned_size(16, 16, alignment=0)
@@ -34,6 +34,9 @@ from vllm_omni.diffusion.models.qwen_image.qwen_image_transformer import (
)
from vllm_omni.diffusion.profiler.diffusion_pipeline_profiler import DiffusionPipelineProfilerMixin
from vllm_omni.diffusion.request import OmniDiffusionRequest
from vllm_omni.diffusion.utils.size_utils import (
normalize_min_aligned_size,
)
from vllm_omni.diffusion.utils.tf_utils import get_transformer_config_kwargs
if TYPE_CHECKING:
@@ -938,6 +941,7 @@ class QwenImagePipeline(nn.Module, QwenImageCFGParallelMixin, DiffusionPipelineP
height = req.sampling_params.height or self.default_sample_size * self.vae_scale_factor
width = req.sampling_params.width or self.default_sample_size * self.vae_scale_factor
height, width = normalize_min_aligned_size(height, width, self.vae_scale_factor * 2)
num_inference_steps = req.sampling_params.num_inference_steps or num_inference_steps
sigmas = req.sampling_params.sigmas or sigmas
max_sequence_length = req.sampling_params.max_sequence_length or max_sequence_length
@@ -37,6 +37,9 @@ from vllm_omni.diffusion.models.qwen_image.qwen_image_transformer import (
)
from vllm_omni.diffusion.profiler.diffusion_pipeline_profiler import DiffusionPipelineProfilerMixin
from vllm_omni.diffusion.request import OmniDiffusionRequest
from vllm_omni.diffusion.utils.size_utils import (
normalize_min_aligned_size,
)
from vllm_omni.diffusion.utils.tf_utils import get_transformer_config_kwargs
from vllm_omni.inputs.data import OmniTextPrompt
from vllm_omni.model_executor.model_loader.weight_utils import (
@@ -97,9 +100,7 @@ def get_qwen_image_edit_pre_process_func(
width = request.sampling_params.width or calculated_width
# Ensure dimensions are multiples of vae_scale_factor * 2
multiple_of = vae_scale_factor * 2
height = height // multiple_of * multiple_of
width = width // multiple_of * multiple_of
height, width = normalize_min_aligned_size(height, width, vae_scale_factor * 2)
# Store calculated dimensions in request
prompt["additional_information"]["calculated_height"] = calculated_height
@@ -661,9 +662,7 @@ class QwenImageEditPipeline(nn.Module, SupportImageInput, QwenImageCFGParallelMi
height = height or calculated_height
width = width or calculated_width
multiple_of = self.vae_scale_factor * 2
width = width // multiple_of * multiple_of
height = height // multiple_of * multiple_of
height, width = normalize_min_aligned_size(height, width, self.vae_scale_factor * 2)
if image is not None and not (isinstance(image, torch.Tensor) and image.size(1) == self.latent_channels):
image = self.image_processor.resize(image, calculated_height, calculated_width)
@@ -40,6 +40,9 @@ from vllm_omni.diffusion.models.qwen_image.qwen_image_transformer import (
)
from vllm_omni.diffusion.profiler.diffusion_pipeline_profiler import DiffusionPipelineProfilerMixin
from vllm_omni.diffusion.request import OmniDiffusionRequest
from vllm_omni.diffusion.utils.size_utils import (
normalize_min_aligned_size,
)
from vllm_omni.diffusion.utils.tf_utils import get_transformer_config_kwargs
from vllm_omni.inputs.data import OmniTextPrompt
from vllm_omni.model_executor.model_loader.weight_utils import (
@@ -99,9 +102,7 @@ def get_qwen_image_edit_plus_pre_process_func(
width = request.sampling_params.width or calculated_width
# Ensure dimensions are multiples of vae_scale_factor * 2
multiple_of = vae_scale_factor * 2
height = height // multiple_of * multiple_of
width = width // multiple_of * multiple_of
height, width = normalize_min_aligned_size(height, width, vae_scale_factor * 2)
# Store calculated dimensions in request
prompt["additional_information"]["calculated_height"] = calculated_height
@@ -604,9 +605,7 @@ class QwenImageEditPlusPipeline(
height = height or calculated_height
width = width or calculated_width
multiple_of = self.vae_scale_factor * 2
width = width // multiple_of * multiple_of
height = height // multiple_of * multiple_of
height, width = normalize_min_aligned_size(height, width, self.vae_scale_factor * 2)
condition_images = []
vae_images = []
@@ -36,6 +36,9 @@ from vllm_omni.diffusion.models.qwen_image.qwen_image_transformer import (
)
from vllm_omni.diffusion.profiler.diffusion_pipeline_profiler import DiffusionPipelineProfilerMixin
from vllm_omni.diffusion.request import OmniDiffusionRequest
from vllm_omni.diffusion.utils.size_utils import (
normalize_min_aligned_size,
)
from vllm_omni.diffusion.utils.tf_utils import get_transformer_config_kwargs
from vllm_omni.inputs.data import OmniTextPrompt
from vllm_omni.model_executor.model_loader.weight_utils import (
@@ -109,9 +112,7 @@ def get_qwen_image_layered_pre_process_func(
height = calculated_height
width = calculated_width
multiple_of = vae_scale_factor * 2
width = width // multiple_of * multiple_of
height = height // multiple_of * multiple_of
height, width = normalize_min_aligned_size(height, width, vae_scale_factor * 2)
# Store calculated dimensions in request
prompt["additional_information"]["calculated_height"] = calculated_height
@@ -665,9 +666,7 @@ the image\n<|vision_start|><|image_pad|><|vision_end|><|im_end|>\n<|im_start|>as
height = calculated_height
width = calculated_width
multiple_of = self.vae_scale_factor * 2
width = width // multiple_of * multiple_of
height = height // multiple_of * multiple_of
height, width = normalize_min_aligned_size(height, width, self.vae_scale_factor * 2)
if image is not None and not (isinstance(image, torch.Tensor) and image.size(1) == self.latent_channels):
image = self.image_processor.resize(image, calculated_height, calculated_width)
+20
View File
@@ -0,0 +1,20 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Shared size normalization helpers for diffusion pipelines."""
def normalize_min_aligned_size(height: int, width: int, alignment: int) -> tuple[int, int]:
"""Clamp dimensions to the minimum valid aligned size.
This preserves floor-to-alignment behavior for normal requests while
preventing very small dimensions from collapsing to zero after alignment.
"""
alignment = int(alignment)
if alignment <= 0:
raise ValueError(f"Expected positive alignment, got {alignment}")
normalized_height = max(alignment, (int(height) // alignment) * alignment)
normalized_width = max(alignment, (int(width) // alignment) * alignment)
return normalized_height, normalized_width