diffusion: Fix silent override of explicit guidance_scale=0 (#4999)

Signed-off-by: Harenome Ranaivoarivony-Razanajato <harenome.razanajato1@huawei.com>
This commit is contained in:
Harenome 安仁 Ranaivoarivony-Razanajato authored and GitHub committed 2026-08-01 03:19:21 +00:00
1 parent 0a03359224
commit 8cb79308c6
6 files changed
+48 -9

No files matched your search

+37
View File
@@ -72,3 +72,40 @@ def test_tp_seed_same_across_ranks_and_varies_across_requests():
# Seeds must vary across requests (non-determinism preserved).
assert len(set(seeds)) == n_requests, f"Expected {n_requests} unique seeds but got {len(set(seeds))}: {seeds}"
def _request_with_guidance(**sampling_kwargs) -> OmniDiffusionRequest:
return OmniDiffusionRequest(
prompt={"prompt": "a cup of coffee on a table"},
sampling_params=OmniDiffusionSamplingParams(num_inference_steps=1, **sampling_kwargs),
request_id="request-test",
)
def test_omitted_guidance_scale_is_unset_and_resolved_to_one():
# No guidance_scale passed: the caller did not set it, so it must NOT count as
# "provided" (each pipeline applies its own default), and __post_init__ resolves the
# None "unset" sentinel to a concrete float so no consumer ever observes None.
req = _request_with_guidance()
assert req.sampling_params.guidance_scale_provided is False
assert req.sampling_params.guidance_scale == 1.0
def test_explicit_zero_guidance_scale_is_honored():
# Regression (#4998): an explicit guidance_scale=0 (disable CFG) must be honored,
# not mistaken for "unset" and overridden by the pipeline's model default. This is
# the sentinel collision that the None default + ``is not None`` check fixes.
req = _request_with_guidance(guidance_scale=0.0)
assert req.sampling_params.guidance_scale_provided is True
assert req.sampling_params.guidance_scale == 0.0
@pytest.mark.parametrize("value", [0.999, 1.0, 5.0])
def test_explicit_nonzero_guidance_scale_is_honored(value):
# Any explicitly-set value (truthy or not) is honored as provided and preserved.
req = _request_with_guidance(guidance_scale=value)
assert req.sampling_params.guidance_scale_provided is True
assert req.sampling_params.guidance_scale == value
@@ -640,7 +640,9 @@ class FluxKontextPipeline(
width = req.sampling_params.width or width
num_inference_steps = req.sampling_params.num_inference_steps or num_inference_steps
sigmas = req.sampling_params.sigmas or sigmas
guidance_scale = req.sampling_params.guidance_scale or guidance_scale
guidance_scale = (
req.sampling_params.guidance_scale if req.sampling_params.guidance_scale_provided else guidance_scale
)
num_images_per_prompt = (
req.sampling_params.num_outputs_per_prompt
if req.sampling_params.num_outputs_per_prompt > 0
@@ -733,7 +733,7 @@ class GlmImagePipeline(nn.Module, DiffusionPipelineProfilerMixin, SupportsCompon
)
width = ar_width or req.sampling_params.width or img_width or self.default_sample_size * self.vae_scale_factor
num_inference_steps = req.sampling_params.num_inference_steps or 50
guidance_scale = req.sampling_params.guidance_scale or 1.5
guidance_scale = req.sampling_params.guidance_scale if req.sampling_params.guidance_scale_provided else 1.5
# Ensure dimensions are multiples of vae_scale_factor * patch_size
multiple_of = self.vae_scale_factor * self._patch_size
@@ -353,7 +353,7 @@ class FlowMatchingAudioPipeline(
sampling_params.extra_args = extra_args
num_inference_steps = sampling_params.num_inference_steps or 32
guidance_scale = sampling_params.guidance_scale or 3.0
guidance_scale = sampling_params.guidance_scale if sampling_params.guidance_scale_provided else 3.0
generator = self._resolve_diffusion_generator(sampling_params)
with self._stage_timer("consume_payload"):
+5 -5
View File
@@ -42,11 +42,11 @@ class OmniDiffusionRequest:
self.sampling_params.seed = random.randint(0, 2**31 - 1)
# 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:
# The unset sentinel is None (see OmniDiffusionSamplingParams); any value
# the caller set -- including an explicit 0.0 (disable CFG) -- must be
# honored. Resolve before auto-filling guidance_scale_2, else the sentinel
# leaks into guidance_scale_2.
if self.sampling_params.guidance_scale is not None:
self.sampling_params.guidance_scale_provided = True
else:
self.sampling_params.guidance_scale = 1.0
+1 -1
View File
@@ -263,7 +263,7 @@ class OmniDiffusionSamplingParams:
# 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: float | None = None
guidance_scale_provided: bool = False
guidance_scale_2: float | None = None
guidance_scale_2_provided: bool = False