From f8576fde9e433a8eb9f39962882cb3657fb830f0 Mon Sep 17 00:00:00 2001 From: Mayuri Date: Fri, 7 Aug 2026 13:58:19 +0530 Subject: [PATCH] Fix division-by-zero NaN in shift_terminal with a single denoising step stretch_shift_to_terminal() rescales sigmas so the schedule ends at config.shift_terminal, using scale_factor = one_minus_z[-1] / (1 - shift_terminal). With num_inference_steps=1 the only sigma is always 1.0, so one_minus_z[-1] is 0, scale_factor is 0, and the division produces NaN. That NaN sigma then breaks index_for_timestep() with an IndexError during scheduler.step(). There is nothing to stretch with a single step, so skip the call when len(sigmas) <= 1. Applied the same guard to the three schedulers that support shift_terminal: FlowMatchEulerDiscreteScheduler, FlowMatchLCMScheduler, and UniPCMultistepScheduler (flow-sigmas path). Fixes #14411 Co-Authored-By: Claude Sonnet 5 --- .../schedulers/scheduling_flow_match_euler_discrete.py | 6 ++++-- src/diffusers/schedulers/scheduling_flow_match_lcm.py | 6 ++++-- src/diffusers/schedulers/scheduling_unipc_multistep.py | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/diffusers/schedulers/scheduling_flow_match_euler_discrete.py b/src/diffusers/schedulers/scheduling_flow_match_euler_discrete.py index 0e4f5c6a1f97..b034d7d2ecb6 100644 --- a/src/diffusers/schedulers/scheduling_flow_match_euler_discrete.py +++ b/src/diffusers/schedulers/scheduling_flow_match_euler_discrete.py @@ -350,8 +350,10 @@ def set_timesteps( else: sigmas = self.shift * sigmas / (1 + (self.shift - 1) * sigmas) - # 3. If required, stretch the sigmas schedule to terminate at the configured `shift_terminal` value - if self.config.shift_terminal: + # 3. If required, stretch the sigmas schedule to terminate at the configured `shift_terminal` value. This is + # skipped when there is only a single step, since there is nothing to stretch and the terminal rescaling + # otherwise divides by zero (the single sigma is always 1.0, i.e. `one_minus_z[-1]` is always 0). + if self.config.shift_terminal and len(sigmas) > 1: sigmas = self.stretch_shift_to_terminal(sigmas) # 4. If required, convert sigmas to one of karras, exponential, or beta sigma schedules diff --git a/src/diffusers/schedulers/scheduling_flow_match_lcm.py b/src/diffusers/schedulers/scheduling_flow_match_lcm.py index 97d4ebbc8e42..9b9a53efc7ac 100644 --- a/src/diffusers/schedulers/scheduling_flow_match_lcm.py +++ b/src/diffusers/schedulers/scheduling_flow_match_lcm.py @@ -359,8 +359,10 @@ def set_timesteps( else: sigmas = self.shift * sigmas / (1 + (self.shift - 1) * sigmas) # type: ignore - # 3. If required, stretch the sigmas schedule to terminate at the configured `shift_terminal` value - if self.config.shift_terminal: + # 3. If required, stretch the sigmas schedule to terminate at the configured `shift_terminal` value. This is + # skipped when there is only a single step, since there is nothing to stretch and the terminal rescaling + # otherwise divides by zero (the single sigma is always 1.0, i.e. `one_minus_z[-1]` is always 0). + if self.config.shift_terminal and len(sigmas) > 1: sigmas = self.stretch_shift_to_terminal(sigmas) # type: ignore # 4. If required, convert sigmas to one of karras, exponential, or beta sigma schedules diff --git a/src/diffusers/schedulers/scheduling_unipc_multistep.py b/src/diffusers/schedulers/scheduling_unipc_multistep.py index 5c2cbcc13ff1..74b4147a4375 100644 --- a/src/diffusers/schedulers/scheduling_unipc_multistep.py +++ b/src/diffusers/schedulers/scheduling_unipc_multistep.py @@ -432,7 +432,7 @@ def set_timesteps( sigmas = self.time_shift(mu, 1.0, sigmas) else: sigmas = self.config.flow_shift * sigmas / (1 + (self.config.flow_shift - 1) * sigmas) - if self.config.shift_terminal: + if self.config.shift_terminal and len(sigmas) > 1: sigmas = self.stretch_shift_to_terminal(sigmas) eps = 1e-6 if np.fabs(sigmas[0] - 1) < eps: