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 <noreply@anthropic.com>
This commit is contained in:
26
nodes.py
26
nodes.py
@@ -90,15 +90,8 @@ class SMCCFGCtrl:
|
|||||||
# Smooth switching via tanh(s/phi) instead of hard sign(s).
|
# Smooth switching via tanh(s/phi) instead of hard sign(s).
|
||||||
# The paper uses sign(s) which works in DiffSynth but creates
|
# The paper uses sign(s) which works in DiffSynth but creates
|
||||||
# salt-and-pepper artifacts in ComfyUI's latent space. tanh
|
# salt-and-pepper artifacts in ComfyUI's latent space. tanh
|
||||||
# provides the same bounded correction with smooth spatial
|
# provides smooth spatial gradients: proportional near zero,
|
||||||
# gradients: proportional near zero, saturating at ±K for
|
# saturating at ±K for large |s|.
|
||||||
# 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.
|
|
||||||
phi = s.std().clamp(min=1e-6)
|
phi = s.std().clamp(min=1e-6)
|
||||||
u_sw = -K * torch.tanh(s / phi)
|
u_sw = -K * torch.tanh(s / phi)
|
||||||
|
|
||||||
@@ -107,14 +100,17 @@ class SMCCFGCtrl:
|
|||||||
if u_sw.ndim == 4:
|
if u_sw.ndim == 4:
|
||||||
u_sw = F.avg_pool2d(u_sw, kernel_size=5, stride=1, padding=2)
|
u_sw = F.avg_pool2d(u_sw, kernel_size=5, stride=1, padding=2)
|
||||||
|
|
||||||
# Corrected guidance error (in normalized noise space)
|
# Store RAW guidance (before correction) for the next step's
|
||||||
guidance_eps = guidance_eps + u_sw
|
# sliding surface. The paper stores corrected guidance, but in
|
||||||
|
# ComfyUI the corrections accumulate through the surface's
|
||||||
# Store corrected guidance for next step's sliding surface
|
# 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()
|
state["prev_eps"] = guidance_eps.detach().clone()
|
||||||
|
|
||||||
# Convert back to sigma-scaled space and apply CFG
|
# Apply correction and convert back to sigma-scaled space
|
||||||
return uncond + cond_scale * guidance_eps * sigma_val
|
return uncond + cond_scale * (guidance_eps + u_sw) * sigma_val
|
||||||
|
|
||||||
m = model.clone()
|
m = model.clone()
|
||||||
m.set_model_sampler_cfg_function(smc_cfg_function, disable_cfg1_optimization=True)
|
m.set_model_sampler_cfg_function(smc_cfg_function, disable_cfg1_optimization=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user