From 2c50da025d79894752608acc6aad35d7fed3b0a8 Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Wed, 4 Mar 2026 18:59:39 +0100 Subject: [PATCH] Fix correction accumulation: store raw guidance in prev_eps The paper stores corrected guidance, but in ComfyUI the corrections compound through the sliding surface's lambda * prev_eps term (amplified 4x per step at lambda=5). Over 20 steps this overwhelms the actual guidance signal, causing total corruption at full K. Storing raw (pre-correction) guidance keeps the surface tracking the model's actual guidance evolution while applying fresh corrections each step. This allows using full K=0.2 (matching the paper) without accumulation-driven instability. Co-Authored-By: Claude Opus 4.6 --- nodes.py | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/nodes.py b/nodes.py index 62a8b51..2abd2c6 100644 --- a/nodes.py +++ b/nodes.py @@ -90,15 +90,8 @@ class SMCCFGCtrl: # Smooth switching via tanh(s/phi) instead of hard sign(s). # The paper uses sign(s) which works in DiffSynth but creates # salt-and-pepper artifacts in ComfyUI's latent space. tanh - # provides the same bounded correction with smooth spatial - # gradients: proportional near zero, saturating at ±K for - # large |s|. phi normalizes s so the transition width matches - # the actual surface magnitude distribution. - # - # K is used at full strength (matching the paper) — the - # tanh smoothing + spatial blur handle artifact prevention. - # The paper's correction of cfg_scale * K per element in noise - # space is what provides the stabilization at high CFG. + # provides smooth spatial gradients: proportional near zero, + # saturating at ±K for large |s|. phi = s.std().clamp(min=1e-6) u_sw = -K * torch.tanh(s / phi) @@ -107,14 +100,17 @@ class SMCCFGCtrl: if u_sw.ndim == 4: u_sw = F.avg_pool2d(u_sw, kernel_size=5, stride=1, padding=2) - # Corrected guidance error (in normalized noise space) - guidance_eps = guidance_eps + u_sw - - # Store corrected guidance for next step's sliding surface + # Store RAW guidance (before correction) for the next step's + # sliding surface. The paper stores corrected guidance, but in + # ComfyUI the corrections accumulate through the surface's + # lambda * prev_eps term (amplified 4x per step at lambda=5), + # overwhelming the actual guidance signal after a few steps. + # Storing raw guidance keeps the surface tracking the model's + # actual guidance evolution while applying corrections fresh. state["prev_eps"] = guidance_eps.detach().clone() - # Convert back to sigma-scaled space and apply CFG - return uncond + cond_scale * guidance_eps * sigma_val + # Apply correction and convert back to sigma-scaled space + return uncond + cond_scale * (guidance_eps + u_sw) * sigma_val m = model.clone() m.set_model_sampler_cfg_function(smc_cfg_function, disable_cfg1_optimization=True)