[Bugfix] Fix config misalignment between offline and online diffusion inference (Wan2.2, Qwen-Image series) (#1979)
Signed-off-by: samithuang <285365963@qq.com> Signed-off-by: Samit <285365963@qq.com> Co-authored-by: Hongsheng Liu <liuhongsheng4@huawei.com>
This commit is contained in:
1 parent
81793f1918
commit
5699fe7a96
6 files changed
+40
-22
No files matched your search
@@ -95,6 +95,9 @@ def get_qwen_image_layered_pre_process_func(
|
||||
else:
|
||||
image = cast(PIL.Image.Image | torch.Tensor | np.ndarray, raw_image)
|
||||
|
||||
if isinstance(image, PIL.Image.Image) and image.mode != "RGBA":
|
||||
image = image.convert("RGBA")
|
||||
|
||||
# 1. calculate dimensions
|
||||
image_size = image.size
|
||||
assert request.sampling_params.resolution in [640, 1024], (
|
||||
@@ -652,6 +655,8 @@ the image\n<|vision_start|><|image_pad|><|vision_end|><|im_end|>\n<|im_start|>as
|
||||
width = req.sampling_params.width
|
||||
else:
|
||||
# fallback to run pre-processing in pipeline (debug only)
|
||||
if isinstance(image, PIL.Image.Image) and image.mode != "RGBA":
|
||||
image = image.convert("RGBA")
|
||||
image_size = image[0].size if isinstance(image, list) else image.size
|
||||
assert resolution in [640, 1024], f"resolution must be either 640 or 1024, but got {resolution}"
|
||||
calculated_width, calculated_height = calculate_dimensions(
|
||||
|
||||
@@ -28,17 +28,23 @@ class OmniDiffusionRequest:
|
||||
|
||||
def __post_init__(self):
|
||||
"""Initialize dependent fields after dataclass initialization."""
|
||||
# Detect whether user explicitly provided guidance_scale.
|
||||
# The sentinel default is 0.0 (false-like); any truthy value means
|
||||
# the caller set it intentionally. We must resolve this BEFORE
|
||||
# auto-filling guidance_scale_2, otherwise the sentinel leaks into
|
||||
# guidance_scale_2.
|
||||
if self.sampling_params.guidance_scale:
|
||||
self.sampling_params.guidance_scale_provided = True
|
||||
else:
|
||||
self.sampling_params.guidance_scale = 1.0
|
||||
|
||||
# Set do_classifier_free_guidance based on guidance scale and negative prompt
|
||||
if self.sampling_params.guidance_scale > 1.0 and any(
|
||||
(not isinstance(p, str) and p.get("negative_prompt")) for p in self.prompts
|
||||
):
|
||||
self.sampling_params.do_classifier_free_guidance = True
|
||||
|
||||
# Auto-fill guidance_scale_2 from the (now-resolved) guidance_scale
|
||||
# so downstream code always has a valid value.
|
||||
if self.sampling_params.guidance_scale_2 is None:
|
||||
self.sampling_params.guidance_scale_2 = self.sampling_params.guidance_scale
|
||||
|
||||
# The dataclass default value is 0 (false-like), used to detect whether user explicitly provides this value
|
||||
# After this check is done, reset this value to old default 1
|
||||
if self.sampling_params.guidance_scale:
|
||||
self.sampling_params.guidance_scale_provided = True
|
||||
else:
|
||||
self.sampling_params.guidance_scale = 1.0
|
||||
@@ -221,6 +221,7 @@ class DiffusionModelRunner:
|
||||
not getattr(req, "skip_cache_refresh", False)
|
||||
and self.cache_backend is not None
|
||||
and self.cache_backend.is_enabled()
|
||||
and req.sampling_params.num_inference_steps is not None
|
||||
):
|
||||
self.cache_backend.refresh(self.pipeline, req.sampling_params.num_inference_steps)
|
||||
|
||||
|
||||
@@ -172,9 +172,6 @@ class AsyncOmniDiffusion:
|
||||
if request_id is None:
|
||||
request_id = f"diff-{uuid.uuid4().hex[:16]}"
|
||||
|
||||
if sampling_params.guidance_scale:
|
||||
sampling_params.guidance_scale_provided = True
|
||||
|
||||
if lora_request is not None:
|
||||
sampling_params.lora_request = lora_request
|
||||
|
||||
|
||||
@@ -2050,20 +2050,26 @@ class OmniOpenAIServingChat(OpenAIServingChat, AudioMixin):
|
||||
except ValueError:
|
||||
logger.warning("Invalid size format: %s", extra_body.get("size"))
|
||||
|
||||
# Get request parameters from extra_body
|
||||
# Text-to-image parameters (ref: text_to_image.py)
|
||||
num_inference_steps = extra_body.get("num_inference_steps", 50)
|
||||
# Get request parameters from extra_body.
|
||||
# Avoid hardcoded defaults here — let each pipeline's forward()
|
||||
# method apply its own model-specific default when the user does
|
||||
# not provide a value.
|
||||
num_inference_steps = extra_body.get("num_inference_steps")
|
||||
guidance_scale = extra_body.get("guidance_scale")
|
||||
true_cfg_scale = extra_body.get("true_cfg_scale") # Qwen-Image specific
|
||||
true_cfg_scale = extra_body.get("true_cfg_scale") or extra_body.get("cfg_scale")
|
||||
seed = extra_body.get("seed")
|
||||
negative_prompt = extra_body.get("negative_prompt")
|
||||
num_outputs_per_prompt = extra_body.get("num_outputs_per_prompt", 1)
|
||||
|
||||
# Text-to-video parameters (ref: text_to_video.py)
|
||||
num_frames = extra_body.get("num_frames")
|
||||
guidance_scale_2 = extra_body.get("guidance_scale_2") # For video high-noise CFG
|
||||
guidance_scale_2 = extra_body.get("guidance_scale_2")
|
||||
lora_body = extra_body.get("lora")
|
||||
|
||||
# Qwen-Image-Layered parameters
|
||||
layers = extra_body.get("layers")
|
||||
resolution = extra_body.get("resolution")
|
||||
|
||||
logger.info(
|
||||
"Diffusion chat request %s: prompt=%r, ref_images=%d, params=%s",
|
||||
request_id,
|
||||
@@ -2087,25 +2093,27 @@ class OmniOpenAIServingChat(OpenAIServingChat, AudioMixin):
|
||||
"negative_prompt": negative_prompt,
|
||||
}
|
||||
gen_params = OmniDiffusionSamplingParams(
|
||||
num_inference_steps=num_inference_steps,
|
||||
height=height,
|
||||
width=width,
|
||||
num_outputs_per_prompt=num_outputs_per_prompt,
|
||||
seed=seed,
|
||||
)
|
||||
|
||||
# Only override defaults when the user explicitly provides values
|
||||
if num_inference_steps is not None:
|
||||
gen_params.num_inference_steps = num_inference_steps
|
||||
if guidance_scale is not None:
|
||||
gen_params.guidance_scale = guidance_scale
|
||||
|
||||
# Add Qwen-Image specific parameter
|
||||
if true_cfg_scale is not None:
|
||||
gen_params.true_cfg_scale = true_cfg_scale
|
||||
|
||||
# Add video generation parameters if set
|
||||
if num_frames is not None:
|
||||
gen_params.num_frames = num_frames
|
||||
if guidance_scale_2 is not None:
|
||||
gen_params.guidance_scale_2 = guidance_scale_2
|
||||
if layers is not None:
|
||||
gen_params.layers = layers
|
||||
if resolution is not None:
|
||||
gen_params.resolution = resolution
|
||||
|
||||
# Parse per-request LoRA (works for both AsyncOmniDiffusion and AsyncOmni).
|
||||
if lora_body and isinstance(lora_body, dict):
|
||||
|
||||
@@ -234,8 +234,9 @@ class OmniDiffusionSamplingParams:
|
||||
step_index: int | None = None
|
||||
boundary_ratio: float | None = None
|
||||
|
||||
# Scheduler parameters
|
||||
num_inference_steps: int = 50
|
||||
# Scheduler parameters – ``None`` means "not explicitly set by the caller";
|
||||
# each pipeline's ``forward()`` decides its own model-specific default.
|
||||
num_inference_steps: int | None = None
|
||||
guidance_scale: float = 0.0
|
||||
guidance_scale_provided: bool = False
|
||||
guidance_scale_2: float | None = None
|
||||
|
||||
Reference in new issue
Block a user