From 76d76be4b753896adbebb28e6d86f7d66d48c1fe Mon Sep 17 00:00:00 2001 From: CalamitousFelicitousness Date: Sun, 26 Jul 2026 21:18:14 +0100 Subject: [PATCH] fix(lora): promote per-network multipliers after the removal pass Cached networks are shared objects, and network_load overwrote their multipliers before network_deactivate ran, so fuse-mode removal recomputed the subtraction delta with the new values: a strength edit froze at its first applied value and a later removal left residue in the model weights. network_load now stages the values on the net and network_activate promotes them, so the removal pass always subtracts the delta that was applied. Backup mode restores from stored tensors and was unaffected. --- modules/lora/lora_load.py | 8 +++++--- modules/lora/network.py | 1 + modules/lora/networks.py | 6 ++++++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/modules/lora/lora_load.py b/modules/lora/lora_load.py index b7c3c6aa0..c898131ca 100644 --- a/modules/lora/lora_load.py +++ b/modules/lora/lora_load.py @@ -305,9 +305,11 @@ def network_load(names, te_multipliers=None, unet_multipliers=None, dyn_dims=Non continue if hasattr(sd_model, 'embedding_db'): sd_model.embedding_db.load_diffusers_embedding(None, net.bundle_embeddings) - net.te_multiplier = te_multipliers[i] if te_multipliers else shared.opts.extra_networks_default_multiplier - net.unet_multiplier = unet_multipliers[i] if unet_multipliers else shared.opts.extra_networks_default_multiplier - net.dyn_dim = dyn_dims[i] if dyn_dims else None # a multiplier is not a rank; float dyn_dim crashes every consumer that slices with it + net.pending_config = { # staged, not assigned: cached nets are shared objects and network_deactivate must still see the multipliers that were applied + 'te': te_multipliers[i] if te_multipliers else shared.opts.extra_networks_default_multiplier, + 'unet': unet_multipliers[i] if unet_multipliers else shared.opts.extra_networks_default_multiplier, + 'dyn': dyn_dims[i] if dyn_dims else None, # a multiplier is not a rank; float dyn_dim crashes every consumer that slices with it + } l.loaded_networks.append(net) while len(lora_cache) > shared.opts.lora_in_memory_limit: diff --git a/modules/lora/network.py b/modules/lora/network.py index e05f6abe9..213f979a6 100644 --- a/modules/lora/network.py +++ b/modules/lora/network.py @@ -148,6 +148,7 @@ class Network: # LoraModule self.te_multiplier = 1.0 self.unet_multiplier = [1.0] * 3 self.dyn_dim = None + self.pending_config = None # staged multipliers; network_activate promotes them after the removal pass so fuse removal subtracts the delta that was applied self.modules = {} self.bundle_embeddings = {} self.mtime = None diff --git a/modules/lora/networks.py b/modules/lora/networks.py index 1ed5ca392..bc3a896ae 100644 --- a/modules/lora/networks.py +++ b/modules/lora/networks.py @@ -18,6 +18,12 @@ def network_activate(include=None, exclude=None): exclude = [] if include is None: include = [] + for net in l.loaded_networks: # promote staged multipliers only now: the deactivate pass ran against the previous values, which fuse-mode removal recomputes with + pending = getattr(net, 'pending_config', None) + if pending is not None: + net.te_multiplier = pending['te'] + net.unet_multiplier = pending['unet'] + net.dyn_dim = pending['dyn'] t0 = time.time() with limit_errors("network_activate") as elimit: sd_model = getattr(shared.sd_model, "pipe", shared.sd_model)