From 5687475cc03be1f6f71720e115ccd20564afabb5 Mon Sep 17 00:00:00 2001 From: Ricardo-M-L Date: Tue, 21 Apr 2026 10:44:41 +0800 Subject: [PATCH] Fix RecursionError in CosineDPMSolver Brownian tree noise sampler MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `CosineDPMSolverMultistepScheduler.step` constructs `BrownianTreeNoiseSampler` with `sigma_min=self.config.sigma_min` / `sigma_max=self.config.sigma_max` and then queries it with `(self.sigmas[i], self.sigmas[i+1])`. Two drifts leave those queries outside the Brownian tree's valid interval: * The Karras reconstruction of `sigma_max` in fp32 can land a few ULPs above the config value (e.g. 500 -> 500.00006103515625), so the first query violates `tb <= t1`. * With the default `final_sigmas_type="zero"` the last query is `sigma_next == 0`, which is strictly below `config.sigma_min`, so it violates `ta >= t0`. torchsde responds to both by recursively splitting the backing interval until Python's recursion limit blows up, which surfaces as the `RecursionError: maximum recursion depth exceeded` reported by stable-audio users in #13274. Use the actual extrema of `self.sigmas` — the same pattern already used by `scheduling_dpmsolver_sde.py:690` — so the Brownian bounds always enclose every query issued during sampling. Fixes #13274 --- .../schedulers/scheduling_cosine_dpmsolver_multistep.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/diffusers/schedulers/scheduling_cosine_dpmsolver_multistep.py b/src/diffusers/schedulers/scheduling_cosine_dpmsolver_multistep.py index 2ba5c377744a..0d5c28a39783 100644 --- a/src/diffusers/schedulers/scheduling_cosine_dpmsolver_multistep.py +++ b/src/diffusers/schedulers/scheduling_cosine_dpmsolver_multistep.py @@ -659,10 +659,15 @@ def step( seed = ( [g.initial_seed() for g in generator] if isinstance(generator, list) else generator.initial_seed() ) + # Use the actual sigma extrema rather than the config values: the Karras + # reconstruction of `sigma_max` in fp32 can drift a few ULPs above the + # config value, and `sigma_next == 0` (final_sigmas_type="zero") is + # strictly below `config.sigma_min`. Both out-of-range queries drive + # torchsde into unbounded interval splitting (#13274). self.noise_sampler = BrownianTreeNoiseSampler( model_output, - sigma_min=self.config.sigma_min, - sigma_max=self.config.sigma_max, + sigma_min=self.sigmas.min().item(), + sigma_max=self.sigmas.max().item(), seed=seed, ) noise = self.noise_sampler(self.sigmas[self.step_index], self.sigmas[self.step_index + 1]).to(