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:
1 parent
0a03359224
commit
8cb79308c6
6 files changed
+48
-9
No files matched your search
@@ -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"):
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in new issue
Block a user