Initial release
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
-- smc_cfg.lua: SMC-CFG — Sliding Mode Control Guidance
|
||||
-- Paper: "CFG-Ctrl: Control-Based Classifier-Free Diffusion Guidance"
|
||||
-- Han et al., 2025 (arXiv:2603.03281)
|
||||
--
|
||||
-- Reinterprets CFG as a feedback control system and applies Sliding Mode
|
||||
-- Control (SMC) to stabilise guidance, especially at high scales.
|
||||
--
|
||||
-- Key idea: define a sliding surface s(t) = ė(t) + λ·e(t) over the
|
||||
-- semantic error e = v_cond - v_uncond, then apply a switching control
|
||||
-- term Δe = -k·sign(s) that enforces convergence to a stable manifold.
|
||||
--
|
||||
-- Implementation: routes through native APG for stability (momentum,
|
||||
-- projection, norm thresholding), then applies the SMC correction as
|
||||
-- a delta on top: result = APG(cond, uncond, w) + w · Δe
|
||||
--
|
||||
-- Stateful: stores previous error vector across steps.
|
||||
|
||||
guidance = {
|
||||
name = "smc_cfg",
|
||||
display = "SMC-CFG",
|
||||
description = "Sliding mode control guidance (Han et al. 2025)",
|
||||
params = {
|
||||
{ key = "lambda", type = "slider", label = "λ (Surface Slope)",
|
||||
default = 0.5, min = 0.01, max = 2.0, step = 0.01,
|
||||
hint = "Controls the sliding surface shape. Higher = faster convergence" },
|
||||
{ key = "k", type = "slider", label = "k (Switching Gain)",
|
||||
default = 0.1, min = 0.01, max = 1.0, step = 0.01,
|
||||
hint = "Force toward the sliding surface. Too high = vibrations" },
|
||||
},
|
||||
}
|
||||
|
||||
-- Stateful: previous error buffer
|
||||
local prev_error = nil
|
||||
local prev_n = 0
|
||||
|
||||
local function sign(x)
|
||||
if x > 0 then return 1.0
|
||||
elseif x < 0 then return -1.0
|
||||
else return 0.0
|
||||
end
|
||||
end
|
||||
|
||||
function guide(pred_cond, pred_uncond, guidance_scale, result, Oc, T, norm_threshold)
|
||||
local n = Oc * T
|
||||
local lam = (params and params.lambda) or 0.5
|
||||
local k = (params and params.k) or 0.1
|
||||
|
||||
-- Reset state on first step of a new generation
|
||||
if (step_idx or 0) == 0 then prev_error = nil; prev_n = 0 end
|
||||
|
||||
-- Base guidance through APG (handles momentum, projection, norm thresholding)
|
||||
apg(pred_cond, pred_uncond, guidance_scale, result, Oc, T, norm_threshold)
|
||||
|
||||
-- Compute semantic error e(t) = cond - uncond
|
||||
local error_now = {}
|
||||
for i = 0, n - 1 do
|
||||
error_now[i] = pred_cond[i] - pred_uncond[i]
|
||||
end
|
||||
|
||||
-- First step or size change: no previous error, just use APG as-is
|
||||
if prev_error == nil or prev_n ~= n then
|
||||
prev_error = error_now
|
||||
prev_n = n
|
||||
return
|
||||
end
|
||||
|
||||
-- Compute ė ≈ (e_now - e_prev) / dt
|
||||
local dt_abs = math.abs(dt or 1.0)
|
||||
if dt_abs < 1e-8 then dt_abs = 1e-8 end
|
||||
local inv_dt = 1.0 / dt_abs
|
||||
|
||||
-- Apply SMC correction: Δe = -k · sign(ė + λ·e)
|
||||
-- Add w · Δe as delta on top of APG result
|
||||
for i = 0, n - 1 do
|
||||
local e_dot = (error_now[i] - prev_error[i]) * inv_dt
|
||||
local s = e_dot + lam * error_now[i]
|
||||
local delta_e = -k * sign(s)
|
||||
result[i] = result[i] + guidance_scale * delta_e
|
||||
end
|
||||
|
||||
-- Store for next step
|
||||
prev_error = error_now
|
||||
prev_n = n
|
||||
end
|
||||
Reference in New Issue
Block a user