sd: support changing preloaded LoRA multipliers (#2041)

* sd: remove C++ support for enforcing fixed LoRA multipliers

The logic at the Python level is enough.

* sd: support changing preloaded LoRA multipliers

We keep the same rules as before:
- Any LoRA with multiplier 0 can be changed
- If all LoRAs have multiplier != 0, they are fixed and optimized

but tweak the corner case of LoRAs specified more than once to
allow adjusting the multiplier if the same LoRA is also specified
with a zero multiplier, as if they were two different LoRAs.

So the following keeps working as before:
- --sdlora /loras/lcm.gguf --sdloramult 1 : fixed as 1
- --sdlora /loras/lcm.gguf --sdloramult 0 : dynamic, default 0
- --sdlora /loras/ : dynamic, default 0
- --sdlora /loras/lcm.gguf /loras/lcm.gguf --sdloramult 1 1 : fixed as 2

But now we have:
- --sdlora /loras/lcm.gguf /loras/lcm.gguf --sdloramult 1 0 : dynamic, default 1
- --sdlora /loras/lcm.gguf /loras/ --sdloramult 1 : dynamic, default 1
This commit is contained in:
Wagner Bruna
2026-03-16 23:09:55 -03:00
committed by GitHub
parent 0c66ed863d
commit 51187d5362
3 changed files with 35 additions and 41 deletions
+20 -15
View File
@@ -89,8 +89,8 @@ ttsmodelpath = "" #if empty, not initialized
embeddingsmodelpath = "" #if empty, not initialized
musicllmmodelpath = "" #if empty, not initialized
musicdiffusionmodelpath = "" #if empty, not initialized
imglora_preload = []
imglora_bypath = {}
imglora_preload = [] # all preloaded LoRAs
imglora_bypath = {} # len(imglora_bypath) == 0 <==> static loras
imglora_name2path = {}
imglora_cached = True
imglora_initial_fixed = True
@@ -2070,8 +2070,7 @@ def sd_load_model(model_filename,vae_filename,t5xxl_filename,clip1_filename,clip
if imglora_bypath:
lora_dynamic = 1 << 3 # accept changes at runtime
lora_cache = 1 << 4 if imglora_cached else 0 # cache the preloaded LoRAs
lora_fixed = 1 << 5 if imglora_initial_fixed else 0 # do not allow changes to the non-zero preloaded LoRAs
lora_apply_mode = lora_dynamic | lora_cache | lora_fixed
lora_apply_mode = lora_dynamic | lora_cache
inputs.lora_apply_mode = lora_apply_mode
inputs.img_hard_limit = args.sdclamped
@@ -2253,7 +2252,7 @@ def mk_sdapi_lora_list(imglora_bypath):
return [
{'name': info['name'], 'path': info['path']}
for info in imglora_bypath.values()
if info['multiplier'] == 0.0 # both preloaded and scanned
if not info.get('fixed')
]
def extract_loras_from_prompt(prompt):
@@ -8854,8 +8853,12 @@ def mk_lora_info(imgloras, multipliers, mock_filesystem=False):
if not mock_filesystem:
lora_fullpath = os.path.abspath(lora_fullpath)
# dedup paths (e.g. preloaded and on directory)
if lora_fullpath in lora_fullmap:
lora_fullmap[lora_fullpath]["multiplier"] += multiplier
info = lora_fullmap.get(lora_fullpath)
if info:
info["multiplier"] += multiplier
if multiplier == 0.0 and 'fixed' in info:
# allow changes if we see this lora again with weight 0
del info['fixed']
continue
lora_name, lora_ext = os.path.splitext(lora_file)
# ensure unique names
@@ -8867,23 +8870,25 @@ def mk_lora_info(imgloras, multipliers, mock_filesystem=False):
unique_lora_names.add(lora_uname)
lora_upath = lora_uname + lora_ext
lora_entry = {
'fullpath': lora_fullpath,
'name': lora_uname,
'path': lora_upath,
'multiplier': multiplier,
'preloaded': preloaded,
'fullpath': lora_fullpath, # where it is on disk
'name': lora_uname, # 'name' in api field and <lora:name:multiplier>
'path': lora_upath, # 'path' in api field (relative), + extension
'multiplier': multiplier, # preload multiplier
}
if preloaded:
lora_entry['preloaded'] = preloaded
if multiplier != 0.0 and imglora_initial_fixed:
lora_entry['fixed'] = True
lora_fullmap[lora_fullpath] = lora_entry
# build the runtime tables
preloaded_table = []
lora_path_map = {}
lora_name_map = {}
for lora_entry in lora_fullmap.values():
# only map LoRAs that can be changed
if not imglora_initial_fixed or lora_entry["multiplier"] == 0.0:
if not lora_entry.get("fixed"): # only map LoRAs that can be changed
lora_path_map[lora_entry["path"]] = lora_entry
lora_name_map[lora_entry["name"]] = lora_entry["path"]
if lora_entry["preloaded"]:
if lora_entry.get("preloaded"):
preloaded_table.append(lora_entry)
return preloaded_table, lora_path_map, lora_name_map