Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 14 additions & 12 deletions src/diffusers/schedulers/scheduling_deis_multistep.py
Original file line number Diff line number Diff line change
Expand Up @@ -752,10 +752,11 @@ def multistep_deis_second_order_update(

m0, m1 = model_output_list[-1], model_output_list[-2]

# Convert to float64 scalars to avoid catastrophic cancellation in polynomial coefficients (#15090)
rho_t, rho_s0, rho_s1 = (
sigma_t / alpha_t,
sigma_s0 / alpha_s0,
sigma_s1 / alpha_s1,
float(sigma_t / alpha_t),
float(sigma_s0 / alpha_s0),
float(sigma_s1 / alpha_s1),
)

if self.config.algorithm_type == "deis":
Expand All @@ -764,8 +765,8 @@ def ind_fn(t, b, c):
# Integrate[(log(t) - log(c)) / (log(b) - log(c)), {t}]
return t * (-np.log(c) + np.log(t) - 1) / (np.log(b) - np.log(c))

coef1 = ind_fn(rho_t, rho_s0, rho_s1) - ind_fn(rho_s0, rho_s0, rho_s1)
coef2 = ind_fn(rho_t, rho_s1, rho_s0) - ind_fn(rho_s0, rho_s1, rho_s0)
coef1 = float(ind_fn(rho_t, rho_s0, rho_s1) - ind_fn(rho_s0, rho_s0, rho_s1))
coef2 = float(ind_fn(rho_t, rho_s1, rho_s0) - ind_fn(rho_s0, rho_s1, rho_s0))

x_t = alpha_t * (sample / alpha_s0 + coef1 * m0 + coef2 * m1)
return x_t
Expand Down Expand Up @@ -828,11 +829,12 @@ def multistep_deis_third_order_update(

m0, m1, m2 = model_output_list[-1], model_output_list[-2], model_output_list[-3]

# Convert to float64 scalars to avoid catastrophic cancellation in polynomial coefficients (#15090)
rho_t, rho_s0, rho_s1, rho_s2 = (
sigma_t / alpha_t,
sigma_s0 / alpha_s0,
sigma_s1 / alpha_s1,
sigma_s2 / alpha_s2,
float(sigma_t / alpha_t),
float(sigma_s0 / alpha_s0),
float(sigma_s1 / alpha_s1),
float(sigma_s2 / alpha_s2),
)

if self.config.algorithm_type == "deis":
Expand All @@ -850,9 +852,9 @@ def ind_fn(t, b, c, d):
denominator = (np.log(b) - np.log(c)) * (np.log(b) - np.log(d))
return numerator / denominator

coef1 = ind_fn(rho_t, rho_s0, rho_s1, rho_s2) - ind_fn(rho_s0, rho_s0, rho_s1, rho_s2)
coef2 = ind_fn(rho_t, rho_s1, rho_s2, rho_s0) - ind_fn(rho_s0, rho_s1, rho_s2, rho_s0)
coef3 = ind_fn(rho_t, rho_s2, rho_s0, rho_s1) - ind_fn(rho_s0, rho_s2, rho_s0, rho_s1)
coef1 = float(ind_fn(rho_t, rho_s0, rho_s1, rho_s2) - ind_fn(rho_s0, rho_s0, rho_s1, rho_s2))
coef2 = float(ind_fn(rho_t, rho_s1, rho_s2, rho_s0) - ind_fn(rho_s0, rho_s1, rho_s2, rho_s0))
coef3 = float(ind_fn(rho_t, rho_s2, rho_s0, rho_s1) - ind_fn(rho_s0, rho_s2, rho_s0, rho_s1))

x_t = alpha_t * (sample / alpha_s0 + coef1 * m0 + coef2 * m1 + coef3 * m2)

Expand Down
18 changes: 18 additions & 0 deletions tests/schedulers/test_scheduler_deis.py
Original file line number Diff line number Diff line change
Expand Up @@ -271,3 +271,21 @@ def test_beta_sigmas(self):

def test_exponential_sigmas(self):
self.check_over_configs(use_exponential_sigmas=True)

def test_high_step_coefficient_precision(self):
# Regression test for #15090: DEIS coefficient precision causes increasing error as inference steps increase
for solver_order in [2, 3]:
scheduler = DEISMultistepScheduler(solver_order=solver_order)
for steps in [50, 100]:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could the regression include the reported 500-step case with a time-varying model output? Constant epsilon combines the multistep coefficients, allowing individual coefficient errors to cancel, so it is a weak check of the polynomial cancellation being fixed.

scheduler.set_timesteps(steps)
rho0 = float(scheduler.sigmas[0])
sample = torch.full((1, 1), rho0 / (1 + rho0**2) ** 0.5, dtype=torch.float64)
constant = sample.item() * (1 + rho0**2) ** 0.5 - rho0
epsilon = torch.ones_like(sample)
for t in scheduler.timesteps:
sample = scheduler.step(epsilon, t, sample).prev_sample

rho = float(scheduler.sigmas[-1])
expected = (constant + rho) / (1 + rho**2) ** 0.5
assert sample.dtype == torch.float64
assert abs(sample.item() - expected) < 1e-4
Loading