lycoris-lora 2.1.0.dev8__tar.gz → 2.1.0.dev9__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 (47) hide show
  1. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/PKG-INFO +1 -1
  2. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/__init__.py +2 -0
  3. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/kohya/__init__.py +39 -39
  4. lycoris_lora-2.1.0.dev9/lycoris/logging.py +36 -0
  5. lycoris_lora-2.1.0.dev9/lycoris/modules/boft.py +211 -0
  6. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/wrapper.py +17 -17
  7. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris_lora.egg-info/PKG-INFO +1 -1
  8. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris_lora.egg-info/SOURCES.txt +2 -0
  9. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/setup.py +1 -1
  10. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/LICENSE.md +0 -0
  11. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/README.md +0 -0
  12. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/config.py +0 -0
  13. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/hcp/__init__.py +0 -0
  14. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/hcp/base.py +0 -0
  15. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/hcp/diag_oft.py +0 -0
  16. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/hcp/loha.py +0 -0
  17. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/hcp/lokr.py +0 -0
  18. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/kohya/model_utils.py +0 -0
  19. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/kohya/original_unet.py +0 -0
  20. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/kohya/sdxl_model_util.py +0 -0
  21. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/kohya/sdxl_original_unet.py +0 -0
  22. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/kohya/utils.py +0 -0
  23. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/__init__.py +0 -0
  24. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/attention.py +0 -0
  25. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/base.py +0 -0
  26. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/diag_oft.py +0 -0
  27. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/dylora.py +0 -0
  28. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/full.py +0 -0
  29. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/glokr.py +0 -0
  30. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/glora.py +0 -0
  31. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/hypernet/__init__.py +0 -0
  32. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/hypernet/generater.py +0 -0
  33. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/hypernet/text_encoder.py +0 -0
  34. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/ia3.py +0 -0
  35. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/locon.py +0 -0
  36. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/loha.py +0 -0
  37. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/lokr.py +0 -0
  38. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/modules/norms.py +0 -0
  39. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/utils/__init__.py +0 -0
  40. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/utils/logger.py +0 -0
  41. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/utils/preset.py +0 -0
  42. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris/utils/xformers_utils.py +0 -0
  43. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris_lora.egg-info/dependency_links.txt +0 -0
  44. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris_lora.egg-info/not-zip-safe +0 -0
  45. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris_lora.egg-info/requires.txt +0 -0
  46. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/lycoris_lora.egg-info/top_level.txt +0 -0
  47. {lycoris_lora-2.1.0.dev8 → lycoris_lora-2.1.0.dev9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lycoris_lora
3
- Version: 2.1.0.dev8
3
+ Version: 2.1.0.dev9
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
@@ -19,3 +19,5 @@ from .wrapper import (
19
19
  create_lycoris,
20
20
  create_lycoris_from_weights,
21
21
  )
22
+
23
+ from .logging import logger
@@ -7,7 +7,6 @@
7
7
  import os
8
8
  import re
9
9
  import sys
10
- from warnings import warn
11
10
  from typing import List
12
11
 
13
12
  sys.setrecursionlimit(10000)
@@ -26,11 +25,13 @@ from ..modules.glora import GLoRAModule
26
25
  from ..modules.norms import NormModule
27
26
  from ..modules.full import FullModule
28
27
  from ..modules.diag_oft import DiagOFTModule
28
+ from ..modules.boft import ButterflyOFTModule
29
29
  from ..modules import make_module
30
30
 
31
31
  from ..config import PRESET
32
32
  from ..utils.preset import read_preset
33
33
  from ..utils import get_module, str_bool
34
+ from ..logging import logger
34
35
 
35
36
 
36
37
  network_module_dict = {
@@ -43,6 +44,7 @@ network_module_dict = {
43
44
  "glora": GLoRAModule,
44
45
  "full": FullModule,
45
46
  "diag-oft": DiagOFTModule,
47
+ "boft": ButterflyOFTModule,
46
48
  }
47
49
 
48
50
 
@@ -64,7 +66,7 @@ def create_network(
64
66
  or kwargs.get("use_tucker", False)
65
67
  )
66
68
  if "disable_conv_cp" in kwargs or "use_cp" in kwargs or "use_conv_cp" in kwargs:
67
- warn(
69
+ logger.warning(
68
70
  "disable_conv_cp and use_cp are deprecated. Please use use_tucker instead.",
69
71
  stacklevel=2,
70
72
  )
@@ -76,7 +78,7 @@ def create_network(
76
78
 
77
79
  if algo == "glora" and conv_dim > 0:
78
80
  conv_dim = 0
79
- print("Disable conv layer for GLoRA")
81
+ logger.info("Disable conv layer for GLoRA")
80
82
 
81
83
  preset = kwargs.get("preset", "full")
82
84
  if preset not in PRESET:
@@ -86,22 +88,20 @@ def create_network(
86
88
  assert preset is not None
87
89
  LycorisNetworkKohya.apply_preset(preset)
88
90
 
89
- print(f"Using rank adaptation algo: {algo}")
91
+ logger.info(f"Using rank adaptation algo: {algo}")
90
92
 
91
93
  if (
92
94
  (algo == "loha")
93
95
  and not kwargs.get("no_dim_warn", False)
94
96
  and (network_dim > 64 or conv_dim > 64)
95
97
  ):
96
- print("=" * 20 + "WARNING" + "=" * 20)
97
98
  warning_type = {"loha": "Hadamard Product representation"}
98
99
  warning_msg = f"""You are not supposed to use dim>64 (64*64 = 4096, it already has enough rank)\n
99
100
  in {warning_type[algo]}!\n
100
101
  Please consider use lower dim or disable this warning with --network_args no_dim_warn=True\n
101
102
  If you just want to use high dim {algo}, please consider use lower lr.
102
103
  """
103
- warn(warning_msg, stacklevel=2)
104
- print("=" * 20 + "WARNING" + "=" * 20)
104
+ logger.warning(warning_msg, stacklevel=2)
105
105
 
106
106
  if algo == "ia3":
107
107
  network = IA3Network(
@@ -241,7 +241,7 @@ def create_hypernetwork(
241
241
  or kwargs.get("use_tucker", False)
242
242
  )
243
243
  if "disable_conv_cp" in kwargs or "use_cp" in kwargs or "use_conv_cp" in kwargs:
244
- warn(
244
+ logger.warning(
245
245
  "disable_conv_cp and use_cp are deprecated. Please use use_tucker instead.",
246
246
  stacklevel=2,
247
247
  )
@@ -255,7 +255,7 @@ def create_hypernetwork(
255
255
  "locon": LoConModule,
256
256
  }[algo]
257
257
 
258
- print(f"Using rank adaptation algo: {algo}")
258
+ logger.info(f"Using rank adaptation algo: {algo}")
259
259
 
260
260
  return HyperDreamNetwork(
261
261
  text_encoder,
@@ -353,19 +353,19 @@ class LycorisNetworkKohya(LycorisNetwork):
353
353
 
354
354
  self.conv_lora_dim = int(conv_lora_dim)
355
355
  if self.conv_lora_dim and self.conv_lora_dim != self.lora_dim:
356
- print("Apply different lora dim for conv layer")
357
- print(f"Conv Dim: {conv_lora_dim}, Linear Dim: {lora_dim}")
356
+ logger.info("Apply different lora dim for conv layer")
357
+ logger.info(f"Conv Dim: {conv_lora_dim}, Linear Dim: {lora_dim}")
358
358
  elif self.conv_lora_dim == 0:
359
- print("Disable conv layer")
359
+ logger.info("Disable conv layer")
360
360
 
361
361
  self.alpha = alpha
362
362
  self.conv_alpha = float(conv_alpha)
363
363
  if self.conv_lora_dim and self.alpha != self.conv_alpha:
364
- print("Apply different alpha value for conv layer")
365
- print(f"Conv alpha: {conv_alpha}, Linear alpha: {alpha}")
364
+ logger.info("Apply different alpha value for conv layer")
365
+ logger.info(f"Conv alpha: {conv_alpha}, Linear alpha: {alpha}")
366
366
 
367
367
  if 1 >= dropout >= 0:
368
- print(f"Use Dropout value: {dropout}")
368
+ logger.info(f"Use Dropout value: {dropout}")
369
369
  self.dropout = dropout
370
370
  self.rank_dropout = rank_dropout
371
371
  self.module_dropout = module_dropout
@@ -466,7 +466,7 @@ class LycorisNetworkKohya(LycorisNetwork):
466
466
  target_replace_modules,
467
467
  target_replace_names=[],
468
468
  ) -> List:
469
- print("Create LyCORIS Module")
469
+ logger.info("Create LyCORIS Module")
470
470
  loras = []
471
471
  next_config = {}
472
472
  for name, module in root_module.named_modules():
@@ -503,7 +503,7 @@ class LycorisNetworkKohya(LycorisNetwork):
503
503
  return loras
504
504
 
505
505
  if network_module == GLoRAModule:
506
- print("GLoRA enabled, only train transformer")
506
+ logger.info("GLoRA enabled, only train transformer")
507
507
  # only train transformer (for GLoRA)
508
508
  LycorisNetworkKohya.UNET_TARGET_REPLACE_MODULE = [
509
509
  "Transformer2DModel",
@@ -529,7 +529,7 @@ class LycorisNetworkKohya(LycorisNetwork):
529
529
  LycorisNetworkKohya.TEXT_ENCODER_TARGET_REPLACE_NAME,
530
530
  )
531
531
  )
532
- print(
532
+ logger.info(
533
533
  f"create LyCORIS for Text Encoder: {len(self.text_encoder_loras)} modules."
534
534
  )
535
535
 
@@ -539,14 +539,14 @@ class LycorisNetworkKohya(LycorisNetwork):
539
539
  LycorisNetworkKohya.UNET_TARGET_REPLACE_MODULE,
540
540
  LycorisNetworkKohya.UNET_TARGET_REPLACE_NAME,
541
541
  )
542
- print(f"create LyCORIS for U-Net: {len(self.unet_loras)} modules.")
542
+ logger.info(f"create LyCORIS for U-Net: {len(self.unet_loras)} modules.")
543
543
 
544
544
  algo_table = {}
545
545
  for lora in self.text_encoder_loras + self.unet_loras:
546
546
  algo_table[lora.__class__.__name__] = (
547
547
  algo_table.get(lora.__class__.__name__, 0) + 1
548
548
  )
549
- print(f"module type table: {algo_table}")
549
+ logger.info(f"module type table: {algo_table}")
550
550
 
551
551
  self.weights_sd = None
552
552
 
@@ -580,12 +580,12 @@ class LycorisNetworkKohya(LycorisNetwork):
580
580
  ), f"internal error: flag not set"
581
581
 
582
582
  if apply_text_encoder:
583
- print("enable LyCORIS for text encoder")
583
+ logger.info("enable LyCORIS for text encoder")
584
584
  else:
585
585
  self.text_encoder_loras = []
586
586
 
587
587
  if apply_unet:
588
- print("enable LyCORIS for U-Net")
588
+ logger.info("enable LyCORIS for U-Net")
589
589
  else:
590
590
  self.unet_loras = []
591
591
 
@@ -598,7 +598,7 @@ class LycorisNetworkKohya(LycorisNetwork):
598
598
  if self.weights_sd:
599
599
  # if some weights are not in state dict, it is ok because initial LoRA does nothing (lora_up is initialized by zeros)
600
600
  info = self.load_state_dict(self.weights_sd, False)
601
- print(f"weights are loaded: {info}")
601
+ logger.info(f"weights are loaded: {info}")
602
602
 
603
603
  # TODO refactor to common function with apply_to
604
604
  def merge_to(self, text_encoder, unet, weights_sd, dtype, device):
@@ -610,12 +610,12 @@ class LycorisNetworkKohya(LycorisNetwork):
610
610
  apply_unet = True
611
611
 
612
612
  if apply_text_encoder:
613
- print("enable LoRA for text encoder")
613
+ logger.info("enable LoRA for text encoder")
614
614
  else:
615
615
  self.text_encoder_loras = []
616
616
 
617
617
  if apply_unet:
618
- print("enable LoRA for U-Net")
618
+ logger.info("enable LoRA for U-Net")
619
619
  else:
620
620
  self.unet_loras = []
621
621
 
@@ -717,12 +717,12 @@ class HyperDreamNetwork(torch.nn.Module):
717
717
  self.alpha = alpha
718
718
 
719
719
  if 1 >= dropout >= 0:
720
- print(f"Use Dropout value: {dropout}")
720
+ logger.info(f"Use Dropout value: {dropout}")
721
721
  if network_module != LoConModule:
722
- print("HyperDreamBooth only support LoRA at this time")
722
+ logger.info("HyperDreamBooth only support LoRA at this time")
723
723
  raise NotImplementedError
724
724
  if lora_dim * (down_dim + up_dim) > 4096:
725
- print(
725
+ logger.info(
726
726
  "weight elements > 4096 (dim * (down_dim + up_dim)) is not recommended!"
727
727
  )
728
728
 
@@ -737,7 +737,7 @@ class HyperDreamNetwork(torch.nn.Module):
737
737
  target_replace_modules,
738
738
  target_replace_names=[],
739
739
  ) -> List[network_module]:
740
- print("Create LyCORIS Module")
740
+ logger.info("Create LyCORIS Module")
741
741
  loras = []
742
742
  for name, module in root_module.named_modules():
743
743
  if module.__class__.__name__ in target_replace_modules:
@@ -832,7 +832,7 @@ class HyperDreamNetwork(torch.nn.Module):
832
832
  LycorisNetworkKohya.TEXT_ENCODER_TARGET_REPLACE_MODULE,
833
833
  )
834
834
  )
835
- print(
835
+ logger.info(
836
836
  f"create LyCORIS for Text Encoder: "
837
837
  f"{len(self.text_encoder_loras)} modules."
838
838
  )
@@ -842,7 +842,7 @@ class HyperDreamNetwork(torch.nn.Module):
842
842
  unet,
843
843
  LycorisNetworkKohya.UNET_TARGET_REPLACE_MODULE,
844
844
  )
845
- print(f"create LyCORIS for U-Net: {len(self.unet_loras)} modules.")
845
+ logger.info(f"create LyCORIS for U-Net: {len(self.unet_loras)} modules.")
846
846
 
847
847
  self.loras: list[LoConModule] = self.text_encoder_loras + self.unet_loras
848
848
  self.img_weight_generater = ImgWeightGenerator(
@@ -968,12 +968,12 @@ class HyperDreamNetwork(torch.nn.Module):
968
968
  ), f"internal error: flag not set"
969
969
 
970
970
  if apply_text_encoder:
971
- print("enable LyCORIS for text encoder")
971
+ logger.info("enable LyCORIS for text encoder")
972
972
  else:
973
973
  self.text_encoder_loras = []
974
974
 
975
975
  if apply_unet:
976
- print("enable LyCORIS for U-Net")
976
+ logger.info("enable LyCORIS for U-Net")
977
977
  else:
978
978
  self.unet_loras = []
979
979
 
@@ -1125,7 +1125,7 @@ class IA3Network(torch.nn.Module):
1125
1125
  target_replace_names=[],
1126
1126
  target_train_input=[],
1127
1127
  ) -> List[IA3Module]:
1128
- print("Create LyCORIS Module")
1128
+ logger.info("Create LyCORIS Module")
1129
1129
  loras = []
1130
1130
  for name, module in root_module.named_modules():
1131
1131
  if module.__class__.__name__ in target_replace_modules:
@@ -1174,7 +1174,7 @@ class IA3Network(torch.nn.Module):
1174
1174
  IA3Network.TRAIN_INPUT,
1175
1175
  )
1176
1176
  )
1177
- print(
1177
+ logger.info(
1178
1178
  f"create LyCORIS for Text Encoder: {len(self.text_encoder_loras)} modules."
1179
1179
  )
1180
1180
 
@@ -1185,7 +1185,7 @@ class IA3Network(torch.nn.Module):
1185
1185
  IA3Network.UNET_TARGET_REPLACE_NAME,
1186
1186
  IA3Network.TRAIN_INPUT,
1187
1187
  )
1188
- print(f"create LyCORIS for U-Net: {len(self.unet_loras)} modules.")
1188
+ logger.info(f"create LyCORIS for U-Net: {len(self.unet_loras)} modules.")
1189
1189
 
1190
1190
  self.weights_sd = None
1191
1191
 
@@ -1238,12 +1238,12 @@ class IA3Network(torch.nn.Module):
1238
1238
  ), f"internal error: flag not set"
1239
1239
 
1240
1240
  if apply_text_encoder:
1241
- print("enable LyCORIS for text encoder")
1241
+ logger.info("enable LyCORIS for text encoder")
1242
1242
  else:
1243
1243
  self.text_encoder_loras = []
1244
1244
 
1245
1245
  if apply_unet:
1246
- print("enable LyCORIS for U-Net")
1246
+ logger.info("enable LyCORIS for U-Net")
1247
1247
  else:
1248
1248
  self.unet_loras = []
1249
1249
 
@@ -1254,7 +1254,7 @@ class IA3Network(torch.nn.Module):
1254
1254
  if self.weights_sd:
1255
1255
  # if some weights are not in state dict, it is ok because initial LoRA does nothing (lora_up is initialized by zeros)
1256
1256
  info = self.load_state_dict(self.weights_sd, False)
1257
- print(f"weights are loaded: {info}")
1257
+ logger.info(f"weights are loaded: {info}")
1258
1258
 
1259
1259
  def enable_gradient_checkpointing(self):
1260
1260
  # not supported
@@ -0,0 +1,36 @@
1
+ import sys
2
+ import copy
3
+ import logging
4
+
5
+
6
+ class ColoredFormatter(logging.Formatter):
7
+ COLORS = {
8
+ "DEBUG": "\033[0;36m", # CYAN
9
+ "INFO": "\033[0;32m", # GREEN
10
+ "WARNING": "\033[0;33m", # YELLOW
11
+ "ERROR": "\033[0;31m", # RED
12
+ "CRITICAL": "\033[0;37;41m", # WHITE ON RED
13
+ "RESET": "\033[0m", # RESET COLOR
14
+ }
15
+
16
+ def format(self, record):
17
+ colored_record = copy.copy(record)
18
+ levelname = colored_record.levelname
19
+ seq = self.COLORS.get(levelname, self.COLORS["RESET"])
20
+ colored_record.levelname = f"{seq}{levelname}{self.COLORS['RESET']}"
21
+ return super().format(colored_record)
22
+
23
+
24
+ logger = logging.getLogger("LyCORIS")
25
+ logger.propagate = False
26
+ logger.setLevel(logging.INFO)
27
+
28
+
29
+ if not logger.handlers:
30
+ handler = logging.StreamHandler(sys.stdout)
31
+ handler.setFormatter(
32
+ ColoredFormatter(
33
+ "%(asctime)s|[%(name)s]-%(levelname)s: %(message)s", "%Y-%m-%d %H:%M:%S"
34
+ )
35
+ )
36
+ logger.addHandler(handler)
@@ -0,0 +1,211 @@
1
+ from functools import cache
2
+ from math import log2, ceil
3
+
4
+ import torch
5
+ import torch.nn as nn
6
+ import torch.nn.functional as F
7
+
8
+ from einops import rearrange
9
+
10
+ from .base import ModuleCustomSD
11
+ from lycoris.logging import logger
12
+
13
+
14
+ @cache
15
+ def log_butterfly_factorize(dim, factor, result):
16
+ logger.info(
17
+ f"Use BOFT({int(log2(result[1]))}, {result[0]//2})"
18
+ f" (equivalent to factor={result[0]}) "
19
+ f"for {dim=} and {factor=}"
20
+ )
21
+
22
+
23
+ def butterfly_factor(dimension: int, factor: int = -1) -> tuple[int, int]:
24
+ """
25
+ m = 2k
26
+ n = 2**p
27
+ m*n = dim
28
+ """
29
+
30
+ # Find the first solution and check if it is even doable
31
+ m = n = 0
32
+ while m <= factor:
33
+ m += 2
34
+ while dimension % m != 0 and m < dimension:
35
+ m += 2
36
+ if m > factor:
37
+ break
38
+ if sum(int(i) for i in f"{dimension//m:b}") == 1:
39
+ n = dimension // m
40
+
41
+ if n == 0:
42
+ raise ValueError(
43
+ f"It is impossible to decompose {dimension} with factor {factor} under BOFT constrains."
44
+ )
45
+
46
+ log_butterfly_factorize(dimension, factor, (dimension // n, n))
47
+ return dimension // n, n
48
+
49
+
50
+ class ButterflyOFTModule(ModuleCustomSD):
51
+ """
52
+ modifed from kohya-ss/sd-scripts/networks/lora:LoRAModule
53
+ """
54
+
55
+ def __init__(
56
+ self,
57
+ lora_name,
58
+ org_module: nn.Module,
59
+ multiplier=1.0,
60
+ lora_dim=4,
61
+ alpha=1,
62
+ dropout=0.0,
63
+ rank_dropout=0.0,
64
+ module_dropout=0.0,
65
+ use_tucker=False,
66
+ use_scalar=False,
67
+ rank_dropout_scale=False,
68
+ constrain=0,
69
+ rescaled=False,
70
+ **kwargs,
71
+ ):
72
+ """if alpha == 0 or None, alpha is rank (no scaling)."""
73
+ super().__init__()
74
+ self.lora_name = lora_name
75
+
76
+ if isinstance(org_module, nn.Linear):
77
+ self.op = F.linear
78
+ self.dim = org_module.out_features
79
+ self.kw_dict = {}
80
+ elif isinstance(org_module, nn.Conv2d):
81
+ self.op = F.conv2d
82
+ self.dim = org_module.out_channels
83
+ self.kw_dict = {
84
+ "stride": org_module.stride,
85
+ "padding": org_module.padding,
86
+ "dilation": org_module.dilation,
87
+ "groups": org_module.groups,
88
+ }
89
+ else:
90
+ raise NotImplementedError
91
+
92
+ out_dim = org_module.weight.shape[0]
93
+ b, m_exp = butterfly_factor(out_dim, lora_dim)
94
+ self.block_size = b
95
+ self.block_num = m_exp
96
+ #BOFT(m, b)
97
+ self.boft_b = b
98
+ self.boft_m = sum(int(i) for i in f"{m_exp-1:b}") + 1
99
+ # block_num > block_size
100
+ self.rescaled = rescaled
101
+ self.constrain = constrain * out_dim
102
+ self.oft_blocks = nn.Parameter(
103
+ torch.zeros(self.boft_m, self.block_num, self.block_size, self.block_size)
104
+ )
105
+ if rescaled:
106
+ self.rescale = nn.Parameter(torch.ones(self.block_num, self.block_size, 1))
107
+
108
+ self.rank_dropout = rank_dropout
109
+ self.rank_dropout_scale = rank_dropout_scale
110
+ self.module_dropout = module_dropout
111
+
112
+ self.multiplier = multiplier
113
+ self.org_module = [org_module]
114
+ self.org_forward = self.org_module[0].forward
115
+
116
+ @property
117
+ def I(self):
118
+ return torch.eye(self.block_size, device=next(self.parameters()).device)
119
+
120
+ def apply_to(self, **kwargs):
121
+ self.org_forward = self.org_module[0].forward
122
+ self.org_module[0].forward = self.forward
123
+
124
+ def restore(self):
125
+ self.org_module[0].forward = self.org_forward
126
+
127
+ def merge_to(self, multiplier=1.0):
128
+ weight = self.make_weight(scale=multiplier)
129
+ self.org_module[0].weight.data.copy_(weight)
130
+
131
+ def custom_state_dict(self):
132
+ return {"oft_diag": self.get_r()}
133
+
134
+ def get_r(self):
135
+ I = self.I
136
+ # for Q = -Q^T
137
+ q = self.oft_blocks - self.oft_blocks.transpose(-1, -2)
138
+ normed_q = q
139
+ # Diag OFT style constrain
140
+ if self.constrain > 0:
141
+ q_norm = torch.norm(q) + 1e-8
142
+ if q_norm > self.constrain:
143
+ normed_q = q * self.constrain / q_norm
144
+ # use float() to prevent unsupported type
145
+ r = (I + normed_q) @ (I - normed_q).float().inverse()
146
+ return r
147
+
148
+ def make_weight(self, scale=1, device=None):
149
+ if self.rank_dropout and self.training:
150
+ drop = torch.rand(self.dim, device=device) < self.rank_dropout
151
+ drop = drop.to(self.oft_blocks.dtype)
152
+ if self.rank_dropout_scale:
153
+ drop /= drop.mean()
154
+ else:
155
+ drop = 1
156
+
157
+ m = self.boft_m
158
+ b = self.boft_b
159
+ r_b = b // 2
160
+ r = self.get_r()
161
+ inp = self.org_module[0].weight.to(device, dtype=r.dtype)
162
+
163
+ for i in range(m):
164
+ bi = r[i] # b_num, b_size, b_size
165
+ if i == 0:
166
+ # Apply multiplier/scale and rescale into first weight
167
+ bi = bi * scale + (1 - scale) * self.I
168
+ if self.rescaled:
169
+ bi = bi * self.rescale
170
+ inp = rearrange(inp, "(c g k) ... -> (c k g) ...", g=2, k=2**i * r_b)
171
+ inp = rearrange(inp, "(d b) ... -> d b ...", b=b)
172
+ inp = torch.einsum("b i j, b j ... -> b i ...", bi, inp)
173
+ inp = rearrange(inp, "d b ... -> (d b) ...")
174
+ inp = rearrange(inp, "(c k g) ... -> (c g k) ...", g=2, k=2**i * r_b)
175
+
176
+ weight = inp
177
+ return weight*drop
178
+
179
+ @torch.no_grad()
180
+ def apply_max_norm(self, max_norm, device=None):
181
+ orig_norm = self.oft_blocks.to(device).norm()
182
+ norm = torch.clamp(orig_norm, max_norm / 2)
183
+ desired = torch.clamp(norm, max=max_norm)
184
+ ratio = desired / norm
185
+
186
+ scaled = ratio.item() != 1.0
187
+ if scaled:
188
+ self.oft_blocks *= ratio
189
+
190
+ return scaled, orig_norm * ratio
191
+
192
+ def forward(self, x):
193
+ if self.module_dropout and self.training:
194
+ if torch.rand(1) < self.module_dropout:
195
+ return self.org_forward(x)
196
+ scale = self.multiplier
197
+
198
+ w = self.make_weight(scale, x.device)
199
+ kw_dict = self.kw_dict | {"weight": w, "bias": self.org_module[0].bias}
200
+ return self.op(x, **kw_dict)
201
+
202
+
203
+ if __name__ == '__main__':
204
+ dim = 320
205
+ test_layer = nn.Linear(dim, dim)
206
+ test_layer.weight = nn.Parameter(torch.eye(dim))
207
+ test_boft = ButterflyOFTModule('test', test_layer, lora_dim=16)
208
+ test_boft.oft_blocks = nn.Parameter(torch.randn_like(test_boft.oft_blocks))
209
+
210
+ print(test_boft.make_weight(1, 'cpu').shape)
211
+ print(torch.count_nonzero(test_boft.make_weight(1, 'cpu')), dim*dim)
@@ -7,7 +7,6 @@ import sys
7
7
 
8
8
  sys.setrecursionlimit(10000)
9
9
  from typing import List
10
- from warnings import warn
11
10
 
12
11
  import torch
13
12
 
@@ -20,11 +19,13 @@ from .modules.glora import GLoRAModule
20
19
  from .modules.norms import NormModule
21
20
  from .modules.full import FullModule
22
21
  from .modules.diag_oft import DiagOFTModule
22
+ from .modules.boft import ButterflyOFTModule
23
23
  from .modules import make_module
24
24
 
25
25
  from .config import PRESET
26
26
  from .utils.preset import read_preset
27
27
  from .utils import get_module, str_bool
28
+ from .logging import logger
28
29
 
29
30
 
30
31
  network_module_dict = {
@@ -36,6 +37,7 @@ network_module_dict = {
36
37
  "glora": GLoRAModule,
37
38
  "full": FullModule,
38
39
  "diag-oft": DiagOFTModule,
40
+ "boft": ButterflyOFTModule,
39
41
  }
40
42
 
41
43
 
@@ -55,7 +57,7 @@ def create_lycoris(module, multiplier, linear_dim, linear_alpha, **kwargs):
55
57
  or kwargs.get("use_tucker", False)
56
58
  )
57
59
  if "disable_conv_cp" in kwargs or "use_cp" in kwargs or "use_conv_cp" in kwargs:
58
- warn(
60
+ logger.warning(
59
61
  "disable_conv_cp and use_cp are deprecated. Please use use_tucker instead.",
60
62
  stacklevel=2,
61
63
  )
@@ -67,7 +69,7 @@ def create_lycoris(module, multiplier, linear_dim, linear_alpha, **kwargs):
67
69
 
68
70
  if algo == "glora" and conv_dim > 0:
69
71
  conv_dim = 0
70
- print("Disable conv layer for GLoRA")
72
+ logger.info("Disable conv layer for GLoRA")
71
73
 
72
74
  preset = kwargs.get("preset", "full")
73
75
  if preset not in PRESET:
@@ -77,14 +79,13 @@ def create_lycoris(module, multiplier, linear_dim, linear_alpha, **kwargs):
77
79
  assert preset is not None
78
80
  LycorisNetwork.apply_preset(preset)
79
81
 
80
- print(f"Using rank adaptation algo: {algo}")
82
+ logger.info(f"Using rank adaptation algo: {algo}")
81
83
 
82
84
  if (
83
85
  (algo == "loha")
84
86
  and not kwargs.get("no_dim_warn", False)
85
87
  and (linear_dim > 64 or conv_dim > 64)
86
88
  ):
87
- print("=" * 20 + "WARNING" + "=" * 20)
88
89
  warning_type = {"loha": "Hadamard Product representation"}
89
90
  warning_msg = (
90
91
  "You are not supposed to use dim>64 (64*64 = 4096, it already has enough rank)\n"
@@ -92,8 +93,7 @@ def create_lycoris(module, multiplier, linear_dim, linear_alpha, **kwargs):
92
93
  "Please consider use lower dim or disable this warning with --network_args no_dim_warn=True\n"
93
94
  f"If you just want to use high dim {algo}, please consider use lower lr."
94
95
  )
95
- warn(warning_msg, stacklevel=2)
96
- print("=" * 20 + "WARNING" + "=" * 20)
96
+ logger.warning(warning_msg, stacklevel=2)
97
97
 
98
98
  network = LycorisNetwork(
99
99
  module,
@@ -230,19 +230,19 @@ class LycorisNetwork(torch.nn.Module):
230
230
 
231
231
  self.conv_lora_dim = int(conv_lora_dim)
232
232
  if self.conv_lora_dim and self.conv_lora_dim != self.lora_dim:
233
- print("Apply different lora dim for conv layer")
234
- print(f"Conv Dim: {conv_lora_dim}, Linear Dim: {lora_dim}")
233
+ logger.info("Apply different lora dim for conv layer")
234
+ logger.info(f"Conv Dim: {conv_lora_dim}, Linear Dim: {lora_dim}")
235
235
  elif self.conv_lora_dim == 0:
236
- print("Disable conv layer")
236
+ logger.info("Disable conv layer")
237
237
 
238
238
  self.alpha = alpha
239
239
  self.conv_alpha = float(conv_alpha)
240
240
  if self.conv_lora_dim and self.alpha != self.conv_alpha:
241
- print("Apply different alpha value for conv layer")
242
- print(f"Conv alpha: {conv_alpha}, Linear alpha: {alpha}")
241
+ logger.info("Apply different alpha value for conv layer")
242
+ logger.info(f"Conv alpha: {conv_alpha}, Linear alpha: {alpha}")
243
243
 
244
244
  if 1 >= dropout >= 0:
245
- print(f"Use Dropout value: {dropout}")
245
+ logger.info(f"Use Dropout value: {dropout}")
246
246
  self.dropout = dropout
247
247
  self.rank_dropout = rank_dropout
248
248
  self.module_dropout = module_dropout
@@ -341,7 +341,7 @@ class LycorisNetwork(torch.nn.Module):
341
341
  target_replace_modules,
342
342
  target_replace_names=[],
343
343
  ) -> List:
344
- print("Create LyCORIS Module")
344
+ logger.info("Create LyCORIS Module")
345
345
  loras = []
346
346
  next_config = {}
347
347
  for name, module in root_module.named_modules():
@@ -383,14 +383,14 @@ class LycorisNetwork(torch.nn.Module):
383
383
  LycorisNetwork.TARGET_REPLACE_MODULE,
384
384
  LycorisNetwork.TARGET_REPLACE_NAME,
385
385
  )
386
- print(f"create LyCORIS: {len(self.loras)} modules.")
386
+ logger.info(f"create LyCORIS: {len(self.loras)} modules.")
387
387
 
388
388
  algo_table = {}
389
389
  for lora in self.loras:
390
390
  algo_table[lora.__class__.__name__] = (
391
391
  algo_table.get(lora.__class__.__name__, 0) + 1
392
392
  )
393
- print(f"module type table: {algo_table}")
393
+ logger.info(f"module type table: {algo_table}")
394
394
 
395
395
  self.weights_sd = None
396
396
 
@@ -430,7 +430,7 @@ class LycorisNetwork(torch.nn.Module):
430
430
  if self.weights_sd:
431
431
  # if some weights are not in state dict, it is ok because initial LoRA does nothing (lora_up is initialized by zeros)
432
432
  info = self.load_state_dict(self.weights_sd, False)
433
- print(f"weights are loaded: {info}")
433
+ logger.info(f"weights are loaded: {info}")
434
434
 
435
435
  def is_mergeable(self):
436
436
  return True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lycoris-lora
3
- Version: 2.1.0.dev8
3
+ Version: 2.1.0.dev9
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
@@ -3,6 +3,7 @@ README.md
3
3
  setup.py
4
4
  lycoris/__init__.py
5
5
  lycoris/config.py
6
+ lycoris/logging.py
6
7
  lycoris/wrapper.py
7
8
  lycoris/hcp/__init__.py
8
9
  lycoris/hcp/base.py
@@ -18,6 +19,7 @@ lycoris/kohya/utils.py
18
19
  lycoris/modules/__init__.py
19
20
  lycoris/modules/attention.py
20
21
  lycoris/modules/base.py
22
+ lycoris/modules/boft.py
21
23
  lycoris/modules/diag_oft.py
22
24
  lycoris/modules/dylora.py
23
25
  lycoris/modules/full.py
@@ -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.dev8",
7
+ version="2.1.0.dev9",
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",