From fa21c01afce4f2b152f40342f274d9e125da9f70 Mon Sep 17 00:00:00 2001 From: Ethanfel Date: Wed, 4 Mar 2026 18:27:02 +0100 Subject: [PATCH] Fix: compensate cfg amplification + smooth tanh switching MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two remaining noise sources fixed: 1. CFG amplification: the return value is uncond + cond_scale * u_sw * sigma, so the noise-space correction is cond_scale * K per element. At cfg=12 with K=0.2, that's 2.4 — far too large. Fix: K_eff = K / cond_scale, making the effective correction just K regardless of cfg scale. 2. Hard switching: even clamp(s/phi) creates sharp transitions at the boundary. Replace with tanh(s/phi) for a fully smooth correction. phi = std(s) normalizes the sliding surface to its natural scale. Net effect: the noise-space correction is now bounded by K=0.2 per element regardless of cfg scale, and varies smoothly across spatial positions. Co-Authored-By: Claude Opus 4.6 --- nodes.py | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/nodes.py b/nodes.py index f6cb69e..4cfd450 100644 --- a/nodes.py +++ b/nodes.py @@ -86,14 +86,20 @@ class SMCCFGCtrl: # Sliding surface: s_t = (e_t - e_{t-1}) + lambda * e_{t-1} s = (guidance_eps - prev_eps) + lam * prev_eps - # Boundary layer SMC: replaces hard sign(s) with sat(s/phi). - # Hard sign() creates random ±1 in regions where |s| is near zero, - # which cond_scale amplifies into visible noise. The boundary layer - # uses a linear transition near zero (standard chattering prevention - # in practical SMC). phi adapts to the guidance magnitude so K stays - # meaningful across models with different guidance scales. - phi = guidance_eps.std().clamp(min=1e-6) - u_sw = -K * (s / phi).clamp(-1.0, 1.0) + # Compensate for CFG amplification: the return value multiplies + # u_sw by cond_scale, so the effective noise-space correction is + # cond_scale * K_eff. We want this to equal K (independent of cfg), + # so K_eff = K / cond_scale. Without this, cfg=12 with K=0.2 gives + # a correction of 2.4 per element — far too large. + K_eff = K / max(cond_scale, 1.0) + + # Smooth switching via tanh(s/phi) instead of hard sign(s). + # sign() quantizes every element to ±1, creating a salt-and-pepper + # pattern that's visible as high-frequency noise. tanh provides + # a smooth transition: proportional near zero, saturating at ±1. + # phi normalizes s so the transition happens at the right scale. + phi = s.std().clamp(min=1e-6) + u_sw = -K_eff * torch.tanh(s / phi) # Corrected guidance error (in normalized noise space) guidance_eps = guidance_eps + u_sw