From 0a15c250080d7762b939aafa1250d82dcda2ee83 Mon Sep 17 00:00:00 2001 From: Faraway-So Date: Sun, 15 Nov 2026 09:55:05 +0800 Subject: [PATCH 1/2] fix: keep at least one trimmed sigma in the hires refine schedule make_hires_sigma_schedule() derived the second-pass schedule length with a truncating division, so for hires_steps = n every denoising_strength in (n / (n + 1), 1) collapsed back to n scheduler steps. The trim offset scheduler_steps - effective_steps was then 0, no sigma was dropped, and the second pass restarted from sigma_max. For flow-matching denoisers the initial latent is latent * (1 - sigma) + noise * sigma, so sigma = 1.0 gives the upscaled latent exactly zero weight. With --hires-steps 2 and the default --hires-denoising-strength 0.7 a learned upscaler and Latent (bicubic) produced bit-identical output: the upscale step had no effect at all. Bump the schedule length only when the truncation would trim nothing and denoising_strength is below 1. denoising_strength = 1 is the intentional full-denoise case and keeps starting at sigma_max, and every configuration that already trims at least one sigma keeps a bit-identical scheduler_steps. See #2360. --- src/pipeline/request.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/pipeline/request.cpp b/src/pipeline/request.cpp index 739b8e43a..53f0c3bf0 100644 --- a/src/pipeline/request.cpp +++ b/src/pipeline/request.cpp @@ -511,6 +511,12 @@ namespace sd::pipeline { // unlike img2img which trims from a fixed step count. int scheduler_steps = static_cast(effective_steps / hires.denoising_strength); scheduler_steps = std::max(1, scheduler_steps); + // Truncation maps every denoising_strength in (n / (n + 1), 1) back to n scheduler steps, so the trim below drops + // no sigma at all and the second pass restarts from sigma_max, discarding the upscaled latent. Keep at least one + // trimmed sigma; denoising_strength = 1 is the intentional full-denoise case and must keep starting at sigma_max. + if (scheduler_steps <= effective_steps && hires.denoising_strength < 1.0f) { + scheduler_steps = effective_steps + 1; + } scheduler_t scheduler = resolve_scheduler(sd, sample_params.scheduler, From 5649fbab268e22b55e5766ac15385c8a41068138 Mon Sep 17 00:00:00 2001 From: Faraway-So Date: Sun, 15 Nov 2026 12:21:26 +0800 Subject: [PATCH 2/2] fix: warn when the hires refine schedule starts below the requested strength The trim in make_hires_sigma_schedule() always keeps a suffix, so the starting sigma of the refine pass is a function of the effective step count alone and cannot be raised by picking a different scheduler_steps. With --hires-steps 1 it is the last sigma before the terminal zero: 0.0119 for MiniMax-H3 and 0 for Ming, i.e. the pass either barely moves the upscaled latent or does not run at all. Bumping the schedule length fixes the reported sigma_max restart for n >= 2 but cannot help n == 1, so report the under-refinement instead of returning a schedule that looks like a normal refine. Warn only when the trimmed start sigma is below the requested denoising strength, which leaves 2/0.7, 2/0.5, 4/0.4 and 8/0.7 quiet. See #2360. --- src/pipeline/request.cpp | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/pipeline/request.cpp b/src/pipeline/request.cpp index 53f0c3bf0..90b4b2505 100644 --- a/src/pipeline/request.cpp +++ b/src/pipeline/request.cpp @@ -529,8 +529,19 @@ namespace sd::pipeline { if (scheduler_steps_out != nullptr) { *scheduler_steps_out = scheduler_steps; } - return std::vector(sigmas.begin() + std::max(0, scheduler_steps - effective_steps), - sigmas.end()); + std::vector refine_sigmas(sigmas.begin() + std::max(0, scheduler_steps - effective_steps), + sigmas.end()); + // The trim always keeps a suffix, so the starting sigma depends on effective_steps alone. With effective_steps = 1 + // it is the last sigma before the terminal zero, which no scheduler_steps can raise. Report the under-refinement + // instead of silently returning a schedule that barely changes the upscaled latent. + if (refine_sigmas.size() > 1 && refine_sigmas.front() < hires.denoising_strength) { + LOG_WARN("hires refine starts at sigma %.4f over %d step(s), less than the requested denoising strength " + "%.2f; the upscaled latent will barely be refined (increase --hires-steps)", + refine_sigmas.front(), + effective_steps, + hires.denoising_strength); + } + return refine_sigmas; } } // namespace sd::pipeline