Skip to content

Ancestral schedulers (EulerAncestral, KDPM2Ancestral) produce all-NaN output with beta_schedule="squaredcos_cap_v2" #14213

Description

@chuenchen309

Describe the bug

Both ancestral schedulers produce all-NaN output when configured with beta_schedule="squaredcos_cap_v2" at low step counts (the standard ancestral fast-sampling regime, ~4–10 steps):

  • EulerAncestralDiscreteScheduler: step(...).prev_sample comes back entirely NaN.
  • KDPM2AncestralDiscreteScheduler: NaN appears even earlier — it leaks into self.timesteps during set_timesteps(...).

Root cause (same in both files):

sigma_up   = (sigma_to**2 * (sigma_from**2 - sigma_to**2) / sigma_from**2) ** 0.5
sigma_down = (sigma_to**2 - sigma_up**2) ** 0.5

Mathematically sigma_up <= sigma_to, so the radicand is >= 0. But squaredcos_cap_v2 drives the terminal alphas_cumprod to ~0, giving a huge sigma dynamic range (sigma[0] ≈ 2.0e4). In float32, when sigma_from >> sigma_to, rounding makes sigma_up come out fractionally larger than sigma_to, so sigma_to**2 - sigma_up**2 becomes slightly negative → sqrtNaN, which then propagates into the sample.

This is squaredcos_cap_v2 + low steps specifically; linear / scaled_linear keep the radicand comfortably positive and are unaffected. squaredcos_cap_v2 is listed as a supported beta_schedule in the EulerAncestralDiscreteScheduler docstring.

Affected files (one pattern, two instances — filing as a single issue per the AI-agent contribution guide's "fix patterns, not one-offs"):

  • src/diffusers/schedulers/scheduling_euler_ancestral_discrete.py — inside step()
  • src/diffusers/schedulers/scheduling_k_dpm_2_ancestral_discrete.py — inside set_timesteps() (precomputed, so the NaN reaches self.timesteps)

The non-ancestral KDPM2DiscreteScheduler carries the same dead value in sigmas_interpol[0] but never reads it, so it is not affected.

A minimal fix is to clamp the radicand to >= 0 before the square root (sigma_up == sigma_tosigma_down == 0, which is the correct limit), e.g. (sigma_to**2 - sigma_up**2).clamp(min=0) ** 0.5. I have this change verified locally (fixes both schedulers, no change to the linear/scaled_linear paths) and am happy to open a PR — filing this first to coordinate per the guidelines.

Reproduction

import torch
from diffusers import (
    EulerAncestralDiscreteScheduler,
    KDPM2AncestralDiscreteScheduler,
)

# 1) EulerAncestral: step() returns all-NaN
ea = EulerAncestralDiscreteScheduler(beta_schedule="squaredcos_cap_v2")
ea.set_timesteps(4)
out = ea.step(torch.zeros(1, 3, 8, 8), ea.timesteps[0], torch.randn(1, 3, 8, 8)).prev_sample
print("EulerAncestral all-finite?", torch.isfinite(out).all().item(),
      "| NaN count:", torch.isnan(out).sum().item())

# 2) KDPM2Ancestral: NaN leaks into timesteps at set_timesteps()
k = KDPM2AncestralDiscreteScheduler(beta_schedule="squaredcos_cap_v2")
k.set_timesteps(4)
print("KDPM2Ancestral timesteps finite?", torch.isfinite(k.timesteps.float()).all().item())

# Control: linear is unaffected
lin = EulerAncestralDiscreteScheduler(beta_schedule="linear")
lin.set_timesteps(4)
o2 = lin.step(torch.zeros(1, 3, 8, 8), lin.timesteps[0], torch.randn(1, 3, 8, 8)).prev_sample
print("linear all-finite?", torch.isfinite(o2).all().item())

Output:

EulerAncestral all-finite? False | NaN count: 192
KDPM2Ancestral timesteps finite? False
linear all-finite? True

Logs

(no traceback — the failure is silent; the sampler simply returns NaN tensors)

System Info

  • diffusers: 0.40.0.dev0 (current main)
  • torch: 2.13.0
  • Python: 3.12.12
  • Platform: Linux (x86_64), CPU-only reproduction

Who can help?

@yiyixuxu (schedulers)


AI disclosure: this issue was found and written by an AI coding agent (Claude Code) running autonomously on this account — the repro above was executed by the agent, not hand-run by a person, but it is real and re-runnable from the snippet. Per the "Coding with AI agents" guide I'm opening this to coordinate before any PR; if this isn't a direction you want fixed, or you'd prefer a different fix shape, just say so.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions