load_arm_lora: handle mixed-rank LoRAs via zero padding
Browse files- training/v2/model.py +12 -6
training/v2/model.py
CHANGED
|
@@ -113,14 +113,19 @@ def load_arm_lora(model, path):
|
|
| 113 |
"""Load an ai-toolkit/kohya edit LoRA (e.g. armV5) into a frozen LoRA module on `model`.
|
| 114 |
Handles lora_down/lora_up and lora_A/lora_B keys; folds file alpha/rank into B."""
|
| 115 |
sd = load_file(path)
|
| 116 |
-
|
| 117 |
for k, v in sd.items():
|
| 118 |
if k.endswith(('.lora_down.weight', '.lora_A.weight')):
|
| 119 |
-
|
| 120 |
-
|
| 121 |
-
if rank is None:
|
| 122 |
raise ValueError('no LoRA tensors found')
|
|
|
|
|
|
|
|
|
|
| 123 |
lora = LoRA(model.dims, model.depth, rank, rank).requires_grad_(False)
|
|
|
|
|
|
|
|
|
|
| 124 |
for i in range(model.depth):
|
| 125 |
for name in PROJ:
|
| 126 |
p = f'diffusion_model.layers.{i}.proj.{name}'
|
|
@@ -130,8 +135,9 @@ def load_arm_lora(model, path):
|
|
| 130 |
down, up = sd[p + '.lora_A.weight'], sd[p + '.lora_B.weight']
|
| 131 |
alpha_t = sd.get(p + '.alpha')
|
| 132 |
alpha = float(alpha_t) if alpha_t is not None else float(down.shape[0])
|
| 133 |
-
|
| 134 |
-
lora.
|
|
|
|
| 135 |
return lora.to(next(model.tr.parameters()).device)
|
| 136 |
|
| 137 |
|
|
|
|
| 113 |
"""Load an ai-toolkit/kohya edit LoRA (e.g. armV5) into a frozen LoRA module on `model`.
|
| 114 |
Handles lora_down/lora_up and lora_A/lora_B keys; folds file alpha/rank into B."""
|
| 115 |
sd = load_file(path)
|
| 116 |
+
ranks = set()
|
| 117 |
for k, v in sd.items():
|
| 118 |
if k.endswith(('.lora_down.weight', '.lora_A.weight')):
|
| 119 |
+
ranks.add(v.shape[0])
|
| 120 |
+
if not ranks:
|
|
|
|
| 121 |
raise ValueError('no LoRA tensors found')
|
| 122 |
+
rank = max(ranks) # mixed-rank LoRAs: pad smaller deltas with zeros (exact)
|
| 123 |
+
if len(ranks) > 1:
|
| 124 |
+
print(f'load_arm_lora: mixed ranks {sorted(ranks)}, padding to {rank}', flush=True)
|
| 125 |
lora = LoRA(model.dims, model.depth, rank, rank).requires_grad_(False)
|
| 126 |
+
with torch.no_grad():
|
| 127 |
+
for p in lora.parameters():
|
| 128 |
+
p.zero_()
|
| 129 |
for i in range(model.depth):
|
| 130 |
for name in PROJ:
|
| 131 |
p = f'diffusion_model.layers.{i}.proj.{name}'
|
|
|
|
| 135 |
down, up = sd[p + '.lora_A.weight'], sd[p + '.lora_B.weight']
|
| 136 |
alpha_t = sd.get(p + '.alpha')
|
| 137 |
alpha = float(alpha_t) if alpha_t is not None else float(down.shape[0])
|
| 138 |
+
r = down.shape[0]
|
| 139 |
+
lora.A[name][i, :r].copy_(down.float())
|
| 140 |
+
lora.B[name][i, :, :r].copy_(up.float() * (alpha / r) / lora.scale)
|
| 141 |
return lora.to(next(model.tr.parameters()).device)
|
| 142 |
|
| 143 |
|