feat(lora): per-layer select stack modes klora and estlora

Two-network subject+style sets select a winner per layer instead of
summing: scores are top-K magnitude sums (klora) or Frobenius energies
(estlora), and a timestep ramp shifts layers from the subject network
toward the style network across sampling, reduced to at most one
precomputed flip per layer per pass. On sub-8-bit SDNQ the pair rides
the side-channel as separate segments flipped in place; other layers
recompute the winner from the pristine backup, so select modes force
backup mode. Selection resets per pass from the callback setup and is
gated off under model compile. estlora's measured style-discrepancy
term is exposed as an option. Adds XYZ axes for the stack settings.
This commit is contained in:
CalamitousFelicitousness
2026-07-18 02:58:11 +01:00
parent 2396185393
commit 259e15fafe
9 changed files with 426 additions and 19 deletions
+6
View File
@@ -17,6 +17,8 @@ def set_callbacks_p(processing):
global p, warned # pylint: disable=global-statement
p = processing
warned = False
from modules.lora import lora_stack
lora_stack.reset(int(getattr(processing, 'steps', 0) or 0)) # per-pass: restore initial selections and reschedule flips before any step runs
def prompt_callback(step, kwargs):
@@ -37,6 +39,8 @@ def prompt_callback(step, kwargs):
def diffusers_callback_legacy(step: int, timestep: int, latents: torch.FloatTensor | np.ndarray):
if p is None:
return
from modules.lora import lora_stack
lora_stack.on_step(step)
if isinstance(latents, np.ndarray): # latents from Onnx pipelines is ndarray.
latents = torch.from_numpy(latents)
shared.state.sampling_step = step
@@ -56,6 +60,8 @@ def diffusers_callback(pipe, step: int = 0, timestep: int = 0, kwargs: dict | No
if kwargs is None:
kwargs = {}
t0 = time.time()
from modules.lora import lora_stack
lora_stack.on_step(step)
if shared.opts.torch_sync:
if devices.backend == "ipex":