lycoris-lora 2.1.0.dev3__tar.gz → 2.1.0.dev5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/PKG-INFO +1 -1
  2. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/kohya/__init__.py +27 -46
  3. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/__init__.py +2 -1
  4. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/base.py +21 -0
  5. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/dylora.py +1 -3
  6. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/full.py +19 -2
  7. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/loha.py +4 -2
  8. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/utils/__init__.py +171 -271
  9. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/wrapper.py +6 -3
  10. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris_lora.egg-info/PKG-INFO +1 -1
  11. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/setup.py +1 -1
  12. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/LICENSE.md +0 -0
  13. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/README.md +0 -0
  14. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/__init__.py +0 -0
  15. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/config.py +0 -0
  16. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/hcp/__init__.py +0 -0
  17. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/hcp/base.py +0 -0
  18. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/hcp/diag_oft.py +0 -0
  19. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/hcp/loha.py +0 -0
  20. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/hcp/lokr.py +0 -0
  21. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/kohya/model_utils.py +0 -0
  22. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/kohya/original_unet.py +0 -0
  23. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/kohya/sdxl_model_util.py +0 -0
  24. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/kohya/sdxl_original_unet.py +0 -0
  25. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/kohya/utils.py +0 -0
  26. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/attention.py +0 -0
  27. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/diag_oft.py +0 -0
  28. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/glokr.py +0 -0
  29. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/glora.py +0 -0
  30. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/hypernet/__init__.py +0 -0
  31. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/hypernet/generater.py +0 -0
  32. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/hypernet/text_encoder.py +0 -0
  33. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/ia3.py +0 -0
  34. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/locon.py +0 -0
  35. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/lokr.py +0 -0
  36. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/modules/norms.py +0 -0
  37. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/utils/logger.py +0 -0
  38. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/utils/preset.py +0 -0
  39. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris/utils/xformers_utils.py +0 -0
  40. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris_lora.egg-info/SOURCES.txt +0 -0
  41. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris_lora.egg-info/dependency_links.txt +0 -0
  42. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris_lora.egg-info/not-zip-safe +0 -0
  43. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris_lora.egg-info/requires.txt +0 -0
  44. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/lycoris_lora.egg-info/top_level.txt +0 -0
  45. {lycoris_lora-2.1.0.dev3 → lycoris_lora-2.1.0.dev5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lycoris_lora
3
- Version: 2.1.0.dev3
3
+ Version: 2.1.0.dev5
4
4
  Summary: Lora beYond Conventional methods, Other Rank adaptation Implementations for Stable diffusion
5
5
  Home-page: https://github.com/KohakuBlueleaf/LyCORIS
6
6
  Author: Shih-Ying Yeh(KohakuBlueLeaf), Yu-Guan Hsieh, Zhidong Gao
@@ -15,6 +15,7 @@ import torch
15
15
  import torch.utils.checkpoint as checkpoint
16
16
 
17
17
  from .utils import *
18
+ from ..wrapper import LycorisNetwork
18
19
  from ..modules.locon import LoConModule
19
20
  from ..modules.loha import LohaModule
20
21
  from ..modules.ia3 import IA3Module
@@ -186,9 +187,7 @@ def create_network_from_weights(
186
187
  else:
187
188
  prefix = LycorisNetworkKohya.LORA_PREFIX_TEXT_ENCODER
188
189
  for name, modules in te.named_modules():
189
- lora_name = f"{prefix}_{name}".replace(
190
- ".", "_"
191
- )
190
+ lora_name = f"{prefix}_{name}".replace(".", "_")
192
191
  if lora_name in te_loras:
193
192
  te_loras[lora_name] = modules
194
193
 
@@ -279,7 +278,7 @@ def create_hypernetwork(
279
278
  )
280
279
 
281
280
 
282
- class LycorisNetworkKohya(torch.nn.Module):
281
+ class LycorisNetworkKohya(LycorisNetwork):
283
282
  """
284
283
  LoRA + LoCon
285
284
  """
@@ -343,7 +342,7 @@ class LycorisNetworkKohya(torch.nn.Module):
343
342
  train_norm=False,
344
343
  **kwargs,
345
344
  ) -> None:
346
- super().__init__()
345
+ torch.nn.Module.__init__(self)
347
346
  root_kwargs = kwargs
348
347
  self.multiplier = multiplier
349
348
  self.lora_dim = lora_dim
@@ -548,19 +547,15 @@ class LycorisNetworkKohya(torch.nn.Module):
548
547
 
549
548
  self.weights_sd = None
550
549
 
550
+ self.loras = self.text_encoder_loras + self.unet_loras
551
551
  # assertion
552
552
  names = set()
553
- for lora in self.text_encoder_loras + self.unet_loras:
553
+ for lora in self.loras:
554
554
  assert (
555
555
  lora.lora_name not in names
556
556
  ), f"duplicated lora name: {lora.lora_name}"
557
557
  names.add(lora.lora_name)
558
558
 
559
- def set_multiplier(self, multiplier):
560
- self.multiplier = multiplier
561
- for lora in self.text_encoder_loras + self.unet_loras:
562
- lora.multiplier = self.multiplier
563
-
564
559
  def load_weights(self, file):
565
560
  if os.path.splitext(file)[1] == ".safetensors":
566
561
  from safetensors.torch import load_file, safe_open
@@ -591,7 +586,9 @@ class LycorisNetworkKohya(torch.nn.Module):
591
586
  else:
592
587
  self.unet_loras = []
593
588
 
594
- for lora in self.text_encoder_loras + self.unet_loras:
589
+ self.loras = self.text_encoder_loras + self.unet_loras
590
+
591
+ for lora in self.loras:
595
592
  lora.apply_to()
596
593
  self.add_module(lora.lora_name, lora)
597
594
 
@@ -600,34 +597,27 @@ class LycorisNetworkKohya(torch.nn.Module):
600
597
  info = self.load_state_dict(self.weights_sd, False)
601
598
  print(f"weights are loaded: {info}")
602
599
 
603
- def apply_max_norm_regularization(self, max_norm_value, device):
604
- key_scaled = 0
605
- norms = []
606
- for model in self.unet_loras:
607
- if hasattr(model, "apply_max_norm"):
608
- scaled, norm = model.apply_max_norm(max_norm_value, device)
609
- norms.append(norm)
610
- key_scaled += scaled
611
-
612
- for model in self.text_encoder_loras:
613
- if hasattr(model, "apply_max_norm"):
614
- scaled, norm = model.apply_max_norm(max_norm_value, device)
615
- norms.append(norm)
616
- key_scaled += scaled
600
+ # TODO refactor to common function with apply_to
601
+ def merge_to(self, text_encoder, unet, weights_sd, dtype, device):
602
+ apply_text_encoder = apply_unet = False
603
+ for key in weights_sd.keys():
604
+ if key.startswith(LycorisNetworkKohya.LORA_PREFIX_TEXT_ENCODER):
605
+ apply_text_encoder = True
606
+ elif key.startswith(LycorisNetworkKohya.LORA_PREFIX_UNET):
607
+ apply_unet = True
617
608
 
618
- if key_scaled == 0:
619
- return key_scaled, 0, 0
620
-
621
- return key_scaled, sum(norms) / len(norms), max(norms)
609
+ if apply_text_encoder:
610
+ print("enable LoRA for text encoder")
611
+ else:
612
+ self.text_encoder_loras = []
622
613
 
623
- def enable_gradient_checkpointing(self):
624
- # not supported
625
- def make_ckpt(module):
626
- if isinstance(module, torch.nn.Module):
627
- module.grad_ckpt = True
614
+ if apply_unet:
615
+ print("enable LoRA for U-Net")
616
+ else:
617
+ self.unet_loras = []
628
618
 
629
- self.apply(make_ckpt)
630
- pass
619
+ self.loras = self.text_encoder_loras + self.unet_loras
620
+ super().merge_to(1)
631
621
 
632
622
  def prepare_optimizer_params(self, text_encoder_lr, unet_lr, learning_rate):
633
623
  def enumerate_params(loras):
@@ -653,15 +643,6 @@ class LycorisNetworkKohya(torch.nn.Module):
653
643
 
654
644
  return all_params
655
645
 
656
- def prepare_grad_etc(self, text_encoder, unet):
657
- self.requires_grad_(True)
658
-
659
- def on_epoch_start(self, text_encoder, unet):
660
- self.train()
661
-
662
- def get_trainable_params(self):
663
- return self.parameters()
664
-
665
646
  def save_weights(self, file, dtype, metadata):
666
647
  if metadata is not None and len(metadata) == 0:
667
648
  metadata = None
@@ -99,7 +99,8 @@ def make_module(lyco_type, params, lora_name, orig_module):
99
99
  1,
100
100
  )
101
101
  module.w_norm.copy_(w_norm)
102
- module.b_norm.copy_(b_norm)
102
+ if b_norm is not None:
103
+ module.b_norm.copy_(b_norm)
103
104
  elif lyco_type == "full":
104
105
  diff, diff_b = params
105
106
  module = FullModule(
@@ -1,10 +1,31 @@
1
1
  from collections import OrderedDict
2
+ from typing import Any, Mapping
2
3
  import torch
3
4
  import torch.nn as nn
4
5
  import torch.nn.functional as F
5
6
 
6
7
 
7
8
  class ModuleCustomSD(nn.Module):
9
+ def __init__(self):
10
+ super().__init__()
11
+ self._register_load_state_dict_pre_hook(self.load_weight_prehook)
12
+ self.register_load_state_dict_post_hook(self.load_weight_hook)
13
+
14
+ def load_weight_prehook(
15
+ self,
16
+ state_dict,
17
+ prefix,
18
+ local_metadata,
19
+ strict,
20
+ missing_keys,
21
+ unexpected_keys,
22
+ error_msgs,
23
+ ):
24
+ pass
25
+
26
+ def load_weight_hook(self, module, incompatible_keys):
27
+ pass
28
+
8
29
  def custom_state_dict(self):
9
30
  return None
10
31
 
@@ -103,9 +103,7 @@ class DyLoraModule(ModuleCustomSD):
103
103
  self.org_module[0].forward = self.org_forward
104
104
 
105
105
  def merge_to(self, multiplier=1.0):
106
- up = torch.concat(
107
- list(self.up_list), dim=1
108
- )
106
+ up = torch.concat(list(self.up_list), dim=1)
109
107
  down = torch.concat(list(self.down_list))
110
108
  diff_weight = up @ down * self.scale * multiplier / up.size(1)
111
109
  self.org_module[0].weight.data.add_(diff_weight)
@@ -1,6 +1,7 @@
1
1
  import torch
2
2
  import torch.nn as nn
3
3
  import torch.nn.functional as F
4
+ from torch.nn.modules import Module
4
5
 
5
6
  from .base import ModuleCustomSD
6
7
 
@@ -54,11 +55,11 @@ class FullModule(ModuleCustomSD):
54
55
  def apply_to(self, **kwargs):
55
56
  self.org_forward = self.org_module[0].forward
56
57
  self.org_module[0].forward = self.forward
57
- self.weight.data.copy_(self.org_module[0].weight.data)
58
+ self.weight.data.add_(self.org_module[0].weight.data)
58
59
  self.org_weight = [self.org_module[0].weight.data.cpu().clone()]
59
60
  delattr(self.org_module[0], "weight")
60
61
  if self.org_module[0].bias is not None:
61
- self.bias.data.copy_(self.org_module[0].bias.data)
62
+ self.bias.data.add_(self.org_module[0].bias.data)
62
63
  self.org_bias = [self.org_module[0].bias.data.cpu().clone()]
63
64
  delattr(self.org_module[0], "bias")
64
65
  else:
@@ -76,6 +77,22 @@ class FullModule(ModuleCustomSD):
76
77
  sd["diff_b"] = self.bias.data.cpu() - self.org_bias[0]
77
78
  return sd
78
79
 
80
+ def load_weight_prehook(
81
+ self,
82
+ state_dict,
83
+ prefix,
84
+ local_metadata,
85
+ strict,
86
+ missing_keys,
87
+ unexpected_keys,
88
+ error_msgs,
89
+ ):
90
+ diff_weight = state_dict["diff"]
91
+ self.weight.data.add_(diff_weight)
92
+ if "diff_b" in state_dict:
93
+ diff_bias = state_dict["diff_b"]
94
+ self.bias.data.add_(diff_bias)
95
+
79
96
  def make_weight(self, scale=1, device=None, original=False):
80
97
  if original:
81
98
  weight = self.org_weight[0].to(device, dtype=self.weight.dtype)
@@ -191,9 +191,11 @@ class LohaModule(ModuleCustomSD):
191
191
  self.org_module = [org_module] # remove in applying
192
192
  self.org_forward = self.org_module[0].forward
193
193
  self.grad_ckpt = False
194
- self.register_load_state_dict_post_hook(self.load_weight_hook)
195
194
 
196
- def load_weight_hook(self, *args, **kwargs):
195
+ def load_weight_hook(self, module: nn.Module, incompatible_keys):
196
+ unexpected_keys = incompatible_keys.unexpected_keys
197
+ if "scalar" in unexpected_keys:
198
+ del unexpected_keys[unexpected_keys.index("scalar")]
197
199
  self.scalar = nn.Parameter(torch.ones_like(self.scalar))
198
200
 
199
201
  def apply_to(self):
@@ -67,7 +67,7 @@ def extract_conv(
67
67
 
68
68
  U = U[:, :lora_rank]
69
69
  S = S[:lora_rank]
70
- U = U @ torch.diag(S)
70
+ U = U @ torch.diag(S).to(device)
71
71
  Vh = Vh[:lora_rank, :]
72
72
 
73
73
  diff = (weight - (U @ Vh).reshape(out_ch, in_ch, kernel_size, kernel_size)).detach()
@@ -115,7 +115,7 @@ def extract_linear(
115
115
 
116
116
  U = U[:, :lora_rank]
117
117
  S = S[:lora_rank]
118
- U = U @ torch.diag(S)
118
+ U = U @ torch.diag(S).to(device)
119
119
  Vh = Vh[:lora_rank, :]
120
120
 
121
121
  diff = (weight - U @ Vh).detach()
@@ -125,6 +125,7 @@ def extract_linear(
125
125
  return (extract_weight_A, extract_weight_B, diff), "low rank"
126
126
 
127
127
 
128
+ @torch.no_grad()
128
129
  def extract_diff(
129
130
  base_tes,
130
131
  db_tes,
@@ -139,19 +140,20 @@ def extract_diff(
139
140
  small_conv=True,
140
141
  ):
141
142
  UNET_TARGET_REPLACE_MODULE = [
142
- "Transformer2DModel",
143
- "Attention",
144
- "ResnetBlock2D",
145
- "Downsample2D",
146
- "Upsample2D",
143
+ "Linear",
144
+ "Conv2d",
145
+ "LayerNorm",
146
+ "GroupNorm",
147
+ "GroupNorm32",
147
148
  ]
148
- UNET_TARGET_REPLACE_NAME = [
149
- "conv_in",
150
- "conv_out",
151
- "time_embedding.linear_1",
152
- "time_embedding.linear_2",
149
+ TEXT_ENCODER_TARGET_REPLACE_MODULE = [
150
+ "Embedding",
151
+ "Linear",
152
+ "Conv2d",
153
+ "LayerNorm",
154
+ "GroupNorm",
155
+ "GroupNorm32",
153
156
  ]
154
- TEXT_ENCODER_TARGET_REPLACE_MODULE = ["CLIPAttention", "CLIPMLP"]
155
157
  LORA_PREFIX_UNET = "lora_unet"
156
158
  LORA_PREFIX_TEXT_ENCODER = "lora_te"
157
159
 
@@ -160,236 +162,162 @@ def extract_diff(
160
162
  root_module: torch.nn.Module,
161
163
  target_module: torch.nn.Module,
162
164
  target_replace_modules,
163
- target_replace_names=[],
164
165
  ):
165
166
  loras = {}
166
167
  temp = {}
167
- temp_name = {}
168
168
 
169
169
  for name, module in root_module.named_modules():
170
170
  if module.__class__.__name__ in target_replace_modules:
171
- temp[name] = {}
172
- for child_name, child_module in module.named_modules():
173
- if child_module.__class__.__name__ not in {"Linear", "Conv2d"}:
174
- continue
175
- temp[name][child_name] = child_module
176
- elif name in target_replace_names:
177
- temp_name[name] = module
178
-
179
- for name, module in tqdm(list(target_module.named_modules())):
180
- if name in temp:
181
- weights = temp[name]
182
- for child_name, child_module in module.named_modules():
183
- lora_name = prefix + "." + name + "." + child_name
184
- lora_name = lora_name.replace(".", "_")
185
- layer = child_module.__class__.__name__
186
- if layer in {"Linear", "Conv2d"}:
187
- root_weight = child_module.weight
188
- if torch.allclose(root_weight, weights[child_name].weight):
189
- continue
190
-
191
- if layer == "Linear":
192
- weight, decompose_mode = extract_linear(
193
- (child_module.weight - weights[child_name].weight),
194
- mode,
195
- linear_mode_param,
196
- device=extract_device,
197
- )
198
- if decompose_mode == "low rank":
199
- extract_a, extract_b, diff = weight
200
- elif layer == "Conv2d":
201
- is_linear = (
202
- child_module.weight.shape[2] == 1
203
- and child_module.weight.shape[3] == 1
204
- )
205
- weight, decompose_mode = extract_conv(
206
- (child_module.weight - weights[child_name].weight),
207
- mode,
208
- linear_mode_param if is_linear else conv_mode_param,
209
- device=extract_device,
210
- )
211
- if decompose_mode == "low rank":
212
- extract_a, extract_b, diff = weight
213
- if (
214
- small_conv
215
- and not is_linear
216
- and decompose_mode == "low rank"
217
- ):
218
- dim = extract_a.size(0)
219
- (extract_c, extract_a, _), _ = extract_conv(
220
- extract_a.transpose(0, 1),
221
- "fixed",
222
- dim,
223
- extract_device,
224
- True,
225
- )
226
- extract_a = extract_a.transpose(0, 1)
227
- extract_c = extract_c.transpose(0, 1)
228
- loras[f"{lora_name}.lora_mid.weight"] = (
229
- extract_c.detach().cpu().contiguous().half()
230
- )
231
- diff = (
232
- child_module.weight
233
- - torch.einsum(
234
- "i j k l, j r, p i -> p r k l",
235
- extract_c,
236
- extract_a.flatten(1, -1),
237
- extract_b.flatten(1, -1),
238
- )
239
- .detach()
240
- .cpu()
241
- .contiguous()
242
- )
243
- del extract_c
244
- else:
245
- continue
246
- if decompose_mode == "low rank":
247
- loras[f"{lora_name}.lora_down.weight"] = (
248
- extract_a.detach().cpu().contiguous().half()
249
- )
250
- loras[f"{lora_name}.lora_up.weight"] = (
251
- extract_b.detach().cpu().contiguous().half()
252
- )
253
- loras[f"{lora_name}.alpha"] = torch.Tensor(
254
- [extract_a.shape[0]]
255
- ).half()
256
- if use_bias:
257
- diff = diff.detach().cpu().reshape(extract_b.size(0), -1)
258
- sparse_diff = (
259
- make_sparse(diff, sparsity).to_sparse().coalesce()
260
- )
261
-
262
- indices = sparse_diff.indices().to(torch.int16)
263
- values = sparse_diff.values().half()
264
- loras[f"{lora_name}.bias_indices"] = indices
265
- loras[f"{lora_name}.bias_values"] = values
266
- loras[f"{lora_name}.bias_size"] = torch.tensor(
267
- diff.shape
268
- ).to(torch.int16)
269
- del extract_a, extract_b, diff
270
- elif decompose_mode == "full":
271
- loras[f"{lora_name}.diff"] = (
272
- weight.detach().cpu().contiguous().half()
273
- )
274
- if weights[child_name].bias is not None:
275
- bias_diff = child_module.bias - weights[child_name].bias
276
- loras[f"{lora_name}.diff_b"] = (
277
- bias_diff.detach().cpu().contiguous().half()
278
- )
279
- else:
280
- raise NotImplementedError
281
- elif name in temp_name:
282
- weights = temp_name[name]
283
- lora_name = prefix + "." + name
284
- lora_name = lora_name.replace(".", "_")
285
- layer = module.__class__.__name__
286
-
287
- if layer in {"Linear", "Conv2d"}:
288
- root_weight = module.weight
289
- if torch.allclose(root_weight, weights.weight):
290
- continue
291
-
292
- if layer == "Linear":
293
- weight, decompose_mode = extract_linear(
294
- (root_weight - weights.weight),
295
- mode,
296
- linear_mode_param,
297
- device=extract_device,
298
- )
299
- if decompose_mode == "low rank":
300
- extract_a, extract_b, diff = weight
301
- elif layer == "Conv2d":
302
- is_linear = root_weight.shape[2] == 1 and root_weight.shape[3] == 1
303
- weight, decompose_mode = extract_conv(
304
- (root_weight - weights.weight),
305
- mode,
306
- linear_mode_param if is_linear else conv_mode_param,
307
- device=extract_device,
308
- )
309
- if decompose_mode == "low rank":
310
- extract_a, extract_b, diff = weight
311
- if small_conv and not is_linear and decompose_mode == "low rank":
312
- dim = extract_a.size(0)
313
- (extract_c, extract_a, _), _ = extract_conv(
314
- extract_a.transpose(0, 1),
315
- "fixed",
316
- dim,
317
- extract_device,
318
- True,
319
- )
320
- extract_a = extract_a.transpose(0, 1)
321
- extract_c = extract_c.transpose(0, 1)
322
- loras[f"{lora_name}.lora_mid.weight"] = (
323
- extract_c.detach().cpu().contiguous().half()
324
- )
325
- diff = (
326
- root_weight
327
- - torch.einsum(
328
- "i j k l, j r, p i -> p r k l",
329
- extract_c,
330
- extract_a.flatten(1, -1),
331
- extract_b.flatten(1, -1),
332
- )
333
- .detach()
334
- .cpu()
335
- .contiguous()
336
- )
337
- del extract_c
338
- else:
171
+ temp[name] = module
172
+
173
+ for name, module in tqdm(
174
+ list((n, m) for n, m in target_module.named_modules() if n in temp)
175
+ ):
176
+ weights = temp[name]
177
+ lora_name = prefix + "." + name
178
+ lora_name = lora_name.replace(".", "_")
179
+ layer = module.__class__.__name__
180
+
181
+ if layer in {
182
+ "Linear",
183
+ "Conv2d",
184
+ "LayerNorm",
185
+ "GroupNorm",
186
+ "GroupNorm32",
187
+ }:
188
+ root_weight = module.weight
189
+ if torch.allclose(root_weight, weights.weight):
339
190
  continue
191
+ else:
192
+ continue
193
+ module = module.to(extract_device)
194
+ weights = weights.to(extract_device)
195
+
196
+ if mode == "full":
197
+ decompose_mode = "full"
198
+ elif layer == "Linear":
199
+ weight, decompose_mode = extract_linear(
200
+ (root_weight - weights.weight),
201
+ mode,
202
+ linear_mode_param,
203
+ device=extract_device,
204
+ )
340
205
  if decompose_mode == "low rank":
341
- loras[f"{lora_name}.lora_down.weight"] = (
342
- extract_a.detach().cpu().contiguous().half()
206
+ extract_a, extract_b, diff = weight
207
+ elif layer == "Conv2d":
208
+ is_linear = root_weight.shape[2] == 1 and root_weight.shape[3] == 1
209
+ weight, decompose_mode = extract_conv(
210
+ (root_weight - weights.weight),
211
+ mode,
212
+ linear_mode_param if is_linear else conv_mode_param,
213
+ device=extract_device,
214
+ )
215
+ if decompose_mode == "low rank":
216
+ extract_a, extract_b, diff = weight
217
+ if small_conv and not is_linear and decompose_mode == "low rank":
218
+ dim = extract_a.size(0)
219
+ (extract_c, extract_a, _), _ = extract_conv(
220
+ extract_a.transpose(0, 1),
221
+ "fixed",
222
+ dim,
223
+ extract_device,
224
+ True,
343
225
  )
344
- loras[f"{lora_name}.lora_up.weight"] = (
345
- extract_b.detach().cpu().contiguous().half()
226
+ extract_a = extract_a.transpose(0, 1)
227
+ extract_c = extract_c.transpose(0, 1)
228
+ loras[f"{lora_name}.lora_mid.weight"] = (
229
+ extract_c.detach().cpu().contiguous().half()
346
230
  )
347
- loras[f"{lora_name}.alpha"] = torch.Tensor(
348
- [extract_a.shape[0]]
349
- ).half()
350
- if use_bias:
351
- diff = diff.detach().cpu().reshape(extract_b.size(0), -1)
352
- sparse_diff = make_sparse(diff, sparsity).to_sparse().coalesce()
353
-
354
- indices = sparse_diff.indices().to(torch.int16)
355
- values = sparse_diff.values().half()
356
- loras[f"{lora_name}.bias_indices"] = indices
357
- loras[f"{lora_name}.bias_values"] = values
358
- loras[f"{lora_name}.bias_size"] = torch.tensor(diff.shape).to(
359
- torch.int16
231
+ diff = (
232
+ root_weight
233
+ - torch.einsum(
234
+ "i j k l, j r, p i -> p r k l",
235
+ extract_c,
236
+ extract_a.flatten(1, -1),
237
+ extract_b.flatten(1, -1),
360
238
  )
361
- del extract_a, extract_b, diff
362
- elif decompose_mode == "full":
363
- loras[f"{lora_name}.diff"] = (
364
- weight.detach().cpu().contiguous().half()
239
+ .detach()
240
+ .cpu()
241
+ .contiguous()
365
242
  )
366
- if weights.bias is not None:
367
- bias_diff = module.bias - weights.bias
368
- loras[f"{lora_name}.diff_b"] = (
369
- bias_diff.detach().cpu().contiguous().half()
370
- )
243
+ del extract_c
244
+ else:
245
+ module = module.to("cpu")
246
+ weights = weights.to("cpu")
247
+ continue
248
+
249
+ if decompose_mode == "low rank":
250
+ loras[f"{lora_name}.lora_down.weight"] = (
251
+ extract_a.detach().cpu().contiguous().half()
252
+ )
253
+ loras[f"{lora_name}.lora_up.weight"] = (
254
+ extract_b.detach().cpu().contiguous().half()
255
+ )
256
+ loras[f"{lora_name}.alpha"] = torch.Tensor([extract_a.shape[0]]).half()
257
+ if use_bias:
258
+ diff = diff.detach().cpu().reshape(extract_b.size(0), -1)
259
+ sparse_diff = make_sparse(diff, sparsity).to_sparse().coalesce()
260
+
261
+ indices = sparse_diff.indices().to(torch.int16)
262
+ values = sparse_diff.values().half()
263
+ loras[f"{lora_name}.bias_indices"] = indices
264
+ loras[f"{lora_name}.bias_values"] = values
265
+ loras[f"{lora_name}.bias_size"] = torch.tensor(diff.shape).to(
266
+ torch.int16
267
+ )
268
+ del extract_a, extract_b, diff
269
+ elif decompose_mode == "full":
270
+ if "Norm" in layer:
271
+ w_key = "w_norm"
272
+ b_key = "b_norm"
371
273
  else:
372
- raise NotImplementedError
274
+ w_key = "diff"
275
+ b_key = "diff_b"
276
+ weight_diff = module.weight - weights.weight
277
+ loras[f"{lora_name}.{w_key}"] = (
278
+ weight_diff.detach().cpu().contiguous().half()
279
+ )
280
+ if weights.bias is not None:
281
+ bias_diff = module.bias - weights.bias
282
+ loras[f"{lora_name}.{b_key}"] = (
283
+ bias_diff.detach().cpu().contiguous().half()
284
+ )
285
+ else:
286
+ raise NotImplementedError
287
+ module = module.to("cpu")
288
+ weights = weights.to("cpu")
373
289
  return loras
374
290
 
375
291
  all_loras = {}
292
+
293
+ all_loras |= make_state_dict(
294
+ LORA_PREFIX_UNET,
295
+ base_unet,
296
+ db_unet,
297
+ UNET_TARGET_REPLACE_MODULE,
298
+ )
299
+ del base_unet, db_unet
300
+ if torch.cuda.is_available():
301
+ torch.cuda.empty_cache()
302
+
376
303
  for idx, (te1, te2) in enumerate(zip(base_tes, db_tes)):
377
304
  if len(base_tes) > 1:
378
305
  prefix = f"{LORA_PREFIX_TEXT_ENCODER}{idx+1}"
379
306
  else:
380
307
  prefix = LORA_PREFIX_TEXT_ENCODER
381
308
  all_loras |= make_state_dict(
382
- prefix, te1, te2, TEXT_ENCODER_TARGET_REPLACE_MODULE
309
+ prefix,
310
+ te1,
311
+ te2,
312
+ TEXT_ENCODER_TARGET_REPLACE_MODULE,
383
313
  )
314
+ del te1, te2
384
315
 
385
- all_loras |= make_state_dict(
386
- LORA_PREFIX_UNET,
387
- base_unet,
388
- db_unet,
389
- UNET_TARGET_REPLACE_MODULE,
390
- UNET_TARGET_REPLACE_NAME,
391
- )
392
- print(len(all_loras))
316
+ all_lora_name = set()
317
+ for k in all_loras:
318
+ lora_name, weight = k.rsplit(".", 1)
319
+ all_lora_name.add(lora_name)
320
+ print(len(all_lora_name))
393
321
  return all_loras
394
322
 
395
323
 
@@ -497,7 +425,7 @@ def get_module(lyco_state_dict: Dict, lora_name):
497
425
  return "full", (diff, diff_b)
498
426
  elif f"{lora_name}.w_norm" in lyco_state_dict:
499
427
  w_norm = lyco_state_dict[f"{lora_name}.w_norm"]
500
- b_norm = lyco_state_dict.get(f"{lora_name}.b_norm")
428
+ b_norm = lyco_state_dict.get(f"{lora_name}.b_norm", None)
501
429
  return "norm", (w_norm, b_norm)
502
430
  else:
503
431
  return "None", ()
@@ -594,19 +522,20 @@ def rebuild_weight(module_type, params, orig_weight, orig_bias, scale=1):
594
522
  @torch.no_grad()
595
523
  def merge(tes, unet, lyco_state_dict, scale: float = 1.0, device="cpu"):
596
524
  UNET_TARGET_REPLACE_MODULE = [
597
- "Transformer2DModel",
598
- "Attention",
599
- "ResnetBlock2D",
600
- "Downsample2D",
601
- "Upsample2D",
525
+ "Linear",
526
+ "Conv2d",
527
+ "LayerNorm",
528
+ "GroupNorm",
529
+ "GroupNorm32",
602
530
  ]
603
- UNET_TARGET_REPLACE_NAME = [
604
- "conv_in",
605
- "conv_out",
606
- "time_embedding.linear_1",
607
- "time_embedding.linear_2",
531
+ TEXT_ENCODER_TARGET_REPLACE_MODULE = [
532
+ "Embedding",
533
+ "Linear",
534
+ "Conv2d",
535
+ "LayerNorm",
536
+ "GroupNorm",
537
+ "GroupNorm32",
608
538
  ]
609
- TEXT_ENCODER_TARGET_REPLACE_MODULE = ["CLIPAttention", "CLIPMLP"]
610
539
  LORA_PREFIX_UNET = "lora_unet"
611
540
  LORA_PREFIX_TEXT_ENCODER = "lora_te"
612
541
  merged = 0
@@ -616,55 +545,28 @@ def merge(tes, unet, lyco_state_dict, scale: float = 1.0, device="cpu"):
616
545
  root_module: torch.nn.Module,
617
546
  lyco_state_dict: Dict[str, torch.Tensor],
618
547
  target_replace_modules,
619
- target_replace_names=[],
620
548
  ):
621
549
  nonlocal merged
622
- for name, module in tqdm(
550
+ for child_name, child_module in tqdm(
623
551
  list(root_module.named_modules()), desc=f"Merging {prefix}"
624
552
  ):
625
- if module.__class__.__name__ in target_replace_modules:
626
- for child_name, child_module in module.named_modules():
627
- if child_module.__class__.__name__ not in {
628
- "Linear",
629
- "Conv2d",
630
- "GroupNorm",
631
- "GroupNorm32",
632
- "LayerNorm",
633
- }:
634
- continue
635
- lora_name = prefix + "." + name + "." + child_name
636
- lora_name = lora_name.replace(".", "_")
637
-
638
- result, result_b = rebuild_weight(
639
- *get_module(lyco_state_dict, lora_name),
640
- getattr(child_module, "weight"),
641
- getattr(child_module, "bias", None),
642
- scale,
643
- )
644
- if result is not None:
645
- key_dict.pop(lora_name)
646
- merged += 1
647
- child_module.requires_grad_(False)
648
- child_module.weight.copy_(result)
649
- if result_b is not None:
650
- child_module.bias.copy_(result_b)
651
- elif name in target_replace_names:
652
- lora_name = prefix + "." + name
553
+ if child_module.__class__.__name__ in target_replace_modules:
554
+ lora_name = prefix + "." + child_name
653
555
  lora_name = lora_name.replace(".", "_")
654
556
 
655
557
  result, result_b = rebuild_weight(
656
558
  *get_module(lyco_state_dict, lora_name),
657
- getattr(module, "weight"),
658
- getattr(module, "bias", None),
559
+ getattr(child_module, "weight"),
560
+ getattr(child_module, "bias", None),
659
561
  scale,
660
562
  )
661
563
  if result is not None:
662
564
  key_dict.pop(lora_name)
663
565
  merged += 1
664
- module.requires_grad_(False)
665
- module.weight.copy_(result)
566
+ child_module.requires_grad_(False)
567
+ child_module.weight.copy_(result)
666
568
  if result_b is not None:
667
- module.bias.copy_(result_b)
569
+ child_module.bias.copy_(result_b)
668
570
 
669
571
  key_dict = {}
670
572
  for k, v in tqdm(list(lyco_state_dict.items()), desc="Converting Dtype and Device"):
@@ -673,10 +575,10 @@ def merge(tes, unet, lyco_state_dict, scale: float = 1.0, device="cpu"):
673
575
  if convert_key != module and len(tes) > 1:
674
576
  # kohya's format for sdxl is as same as SGM, not diffusers
675
577
  del lyco_state_dict[k]
676
- key_dict[convert_key] = k
578
+ key_dict[convert_key] = key_dict.get(convert_key, []) + [k]
677
579
  k = f"{convert_key}.{weight_key}"
678
580
  else:
679
- key_dict[module] = k
581
+ key_dict[module] = key_dict.get(module, []) + [k]
680
582
  if device == "cpu":
681
583
  lyco_state_dict[k] = v.float().cpu()
682
584
  else:
@@ -685,7 +587,7 @@ def merge(tes, unet, lyco_state_dict, scale: float = 1.0, device="cpu"):
685
587
  )
686
588
 
687
589
  for idx, te in enumerate(tes):
688
- if len(tes)>1:
590
+ if len(tes) > 1:
689
591
  prefix = LORA_PREFIX_TEXT_ENCODER + str(idx + 1)
690
592
  else:
691
593
  prefix = LORA_PREFIX_TEXT_ENCODER
@@ -694,14 +596,12 @@ def merge(tes, unet, lyco_state_dict, scale: float = 1.0, device="cpu"):
694
596
  te.to(device),
695
597
  lyco_state_dict,
696
598
  TEXT_ENCODER_TARGET_REPLACE_MODULE,
697
- UNET_TARGET_REPLACE_NAME,
698
599
  )
699
600
  merge_state_dict(
700
601
  LORA_PREFIX_UNET,
701
602
  unet.to(device),
702
603
  lyco_state_dict,
703
604
  UNET_TARGET_REPLACE_MODULE,
704
- UNET_TARGET_REPLACE_NAME,
705
605
  )
706
606
  print(f"Unused state dict key: {key_dict}")
707
607
  print(f"{merged} Modules been merged")
@@ -432,6 +432,9 @@ class LycorisNetwork(torch.nn.Module):
432
432
  info = self.load_state_dict(self.weights_sd, False)
433
433
  print(f"weights are loaded: {info}")
434
434
 
435
+ def is_mergeable(self):
436
+ return True
437
+
435
438
  def restore(self):
436
439
  for lora in self.loras:
437
440
  lora.restore()
@@ -479,13 +482,13 @@ class LycorisNetwork(torch.nn.Module):
479
482
  all_params.append(param_data)
480
483
  return all_params
481
484
 
482
- def prepare_grad_etc(self):
485
+ def prepare_grad_etc(self, *args):
483
486
  self.requires_grad_(True)
484
487
 
485
- def on_epoch_start(self):
488
+ def on_epoch_start(self, *args):
486
489
  self.train()
487
490
 
488
- def get_trainable_params(self):
491
+ def get_trainable_params(self, *args):
489
492
  return self.parameters()
490
493
 
491
494
  def save_weights(self, file, dtype, metadata):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lycoris-lora
3
- Version: 2.1.0.dev3
3
+ Version: 2.1.0.dev5
4
4
  Summary: Lora beYond Conventional methods, Other Rank adaptation Implementations for Stable diffusion
5
5
  Home-page: https://github.com/KohakuBlueleaf/LyCORIS
6
6
  Author: Shih-Ying Yeh(KohakuBlueLeaf), Yu-Guan Hsieh, Zhidong Gao
@@ -4,7 +4,7 @@ from setuptools import setup, find_packages
4
4
  setup(
5
5
  name="lycoris_lora",
6
6
  packages=find_packages(),
7
- version="2.1.0.dev3",
7
+ version="2.1.0.dev5",
8
8
  url="https://github.com/KohakuBlueleaf/LyCORIS",
9
9
  description="Lora beYond Conventional methods, Other Rank adaptation Implementations for Stable diffusion",
10
10
  author="Shih-Ying Yeh(KohakuBlueLeaf), Yu-Guan Hsieh, Zhidong Gao",