lycoris-lora 3.0.0.dev8__tar.gz → 3.0.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 (39) hide show
  1. {lycoris_lora-3.0.0.dev8/lycoris_lora.egg-info → lycoris_lora-3.0.0.dev9}/PKG-INFO +1 -1
  2. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/README.md +8 -1
  3. lycoris_lora-3.0.0.dev9/lycoris/functional/lokr.py +259 -0
  4. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/modules/base.py +6 -1
  5. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/modules/boft.py +0 -44
  6. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/modules/diag_oft.py +0 -45
  7. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/modules/dylora.py +0 -44
  8. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/modules/full.py +7 -35
  9. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/modules/glora.py +0 -43
  10. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/modules/ia3.py +0 -43
  11. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/modules/locon.py +2 -45
  12. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/modules/loha.py +0 -44
  13. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/modules/lokr.py +96 -71
  14. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/utils/bnb.py +3 -0
  15. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9/lycoris_lora.egg-info}/PKG-INFO +1 -1
  16. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris_lora.egg-info/SOURCES.txt +1 -0
  17. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/setup.py +1 -1
  18. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/LICENSE.md +0 -0
  19. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/__init__.py +0 -0
  20. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/config.py +0 -0
  21. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/functional/__init__.py +0 -0
  22. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/functional/general.py +0 -0
  23. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/functional/locon.py +0 -0
  24. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/functional/loha.py +0 -0
  25. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/kohya.py +0 -0
  26. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/logging.py +0 -0
  27. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/modules/__init__.py +0 -0
  28. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/modules/norms.py +0 -0
  29. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/utils/__init__.py +0 -0
  30. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/utils/general.py +0 -0
  31. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/utils/logger.py +0 -0
  32. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/utils/preset.py +0 -0
  33. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/utils/xformers_utils.py +0 -0
  34. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris/wrapper.py +0 -0
  35. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris_lora.egg-info/dependency_links.txt +0 -0
  36. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris_lora.egg-info/not-zip-safe +0 -0
  37. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris_lora.egg-info/requires.txt +0 -0
  38. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/lycoris_lora.egg-info/top_level.txt +0 -0
  39. {lycoris_lora-3.0.0.dev8 → lycoris_lora-3.0.0.dev9}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lycoris_lora
3
- Version: 3.0.0.dev8
3
+ Version: 3.0.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
@@ -74,7 +74,7 @@ In any case, please install this package in the corresponding virtual environmen
74
74
  - through pip
75
75
 
76
76
  ```bash
77
- pip install lycoris_lora
77
+ pip install lycoris-lora
78
78
  ```
79
79
  - or from source
80
80
 
@@ -111,6 +111,8 @@ You can use this package's kohya module to run kohya's training script to train
111
111
 
112
112
  #### HCP-Diffusion
113
113
 
114
+ **The support for HCP-Diffusion has been dropped on LyCORIS3.0.0, we will wait until HCP side finish the implementation of new wrapper**
115
+
114
116
  You can use this package's hcp module to run HCP-Diffusion's training script to train lycoris module for SD models
115
117
 
116
118
  ```bash
@@ -156,6 +158,11 @@ forward_with_lyco = your_model(x)
156
158
 
157
159
  You can check my [HakuPhi](https://github.com/KohakuBlueleaf/HakuPhi) project to see how I utilize LyCORIS to finetune the Phi-1.5 models.
158
160
 
161
+ #### Other method
162
+ After LyCORIS3.0.0, Parametrize API and Functional API have been added, which provide more different ways on utilizing LyCORIS library.
163
+
164
+ Check [xxx] for more informations.
165
+
159
166
  #### Bitsandbytes support
160
167
 
161
168
  See [bnb_example.py](bnb_example.py) for example. Basically as same as standalone wrapper.
@@ -0,0 +1,259 @@
1
+ import math
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ import torch.nn.functional as F
6
+
7
+ from .general import rebuild_tucker, FUNC_LIST
8
+ from .general import factorization
9
+
10
+
11
+ def make_kron(w1, w2, scale):
12
+ for _ in range(w2.dim() - w1.dim()):
13
+ w1 = w1.unsqueeze(-1)
14
+ w2 = w2.contiguous()
15
+ rebuild = torch.kron(w1, w2)
16
+
17
+ return rebuild * scale
18
+
19
+
20
+ def weight_gen(
21
+ org_weight,
22
+ rank,
23
+ tucker=True,
24
+ factor=-1,
25
+ decompose_both=False,
26
+ full_matrix=False,
27
+ unbalanced_factorization=False,
28
+ ):
29
+ """### weight_gen
30
+
31
+ Args:
32
+ org_weight (torch.Tensor): the weight tensor
33
+ rank (int): low rank
34
+
35
+ Returns:
36
+ torch.Tensor | None: w1, w1a, w1b, w2, w2a, w2b, t2
37
+ """
38
+ out_dim, in_dim, *k = org_weight.shape
39
+ w1 = w1a = w1b = None
40
+ w2 = w2a = w2b = None
41
+ t2 = None
42
+ use_w1 = use_w2 = False
43
+
44
+ if k:
45
+ k_size = k
46
+ shape = (out_dim, in_dim, *k_size)
47
+
48
+ in_m, in_n = factorization(in_dim, factor)
49
+ out_l, out_k = factorization(out_dim, factor)
50
+ if unbalanced_factorization:
51
+ out_l, out_k = out_k, out_l
52
+ shape = ((out_l, out_k), (in_m, in_n), *k_size) # ((a, b), (c, d), *k_size)
53
+ tucker = tucker and any(i != 1 for i in k_size)
54
+ if (
55
+ decompose_both
56
+ and rank < max(shape[0][0], shape[1][0]) / 2
57
+ and not full_matrix
58
+ ):
59
+ w1a = torch.empty(shape[0][0], rank)
60
+ w1b = torch.empty(rank, shape[1][0])
61
+ else:
62
+ use_w1 = True
63
+ w1 = torch.empty(shape[0][0], shape[1][0]) # a*c, 1-mode
64
+
65
+ if rank >= max(shape[0][1], shape[1][1]) / 2 or full_matrix:
66
+ use_w2 = True
67
+ w2 = torch.empty(shape[0][1], shape[1][1], *k_size)
68
+ elif tucker:
69
+ t2 = torch.empty(rank, rank, *shape[2:])
70
+ w2a = torch.empty(rank, shape[0][1]) # b, 1-mode
71
+ w2b = torch.empty(rank, shape[1][1]) # d, 2-mode
72
+ else: # Conv2d not tucker
73
+ # bigger part. weight and LoRA. [b, dim] x [dim, d*k1*k2]
74
+ w2a = torch.empty(shape[0][1], rank)
75
+ w2b = torch.empty(rank, shape[1][1], *shape[2:])
76
+ # w1 ⊗ (w2a x w2b) = (a, b)⊗((c, dim)x(dim, d*k1*k2)) = (a, b)⊗(c, d*k1*k2) = (ac, bd*k1*k2)
77
+ else: # Linear
78
+ shape = (out_dim, in_dim)
79
+
80
+ in_m, in_n = factorization(in_dim, factor)
81
+ out_l, out_k = factorization(out_dim, factor)
82
+ if unbalanced_factorization:
83
+ out_l, out_k = out_k, out_l
84
+ shape = (
85
+ (out_l, out_k),
86
+ (in_m, in_n),
87
+ ) # ((a, b), (c, d)), out_dim = a*c, in_dim = b*d
88
+ # smaller part. weight scale
89
+ if decompose_both and rank < max(shape[0][0], shape[1][0]) / 2:
90
+ w1a = torch.empty(shape[0][0], rank)
91
+ w1b = torch.empty(rank, shape[1][0])
92
+ else:
93
+ use_w1 = True
94
+ w1 = torch.empty(shape[0][0], shape[1][0]) # a*c, 1-mode
95
+ if rank < max(shape[0][1], shape[1][1]) / 2:
96
+ # bigger part. weight and LoRA. [b, dim] x [dim, d]
97
+ w2a = torch.empty(shape[0][1], rank)
98
+ w2b = torch.empty(rank, shape[1][1])
99
+ # w1 ⊗ (w2a x w2b) = (a, b)⊗((c, dim)x(dim, d)) = (a, b)⊗(c, d) = (ac, bd)
100
+ else:
101
+ use_w2 = True
102
+ w2 = torch.empty(shape[0][1], shape[1][1])
103
+
104
+ if use_w2:
105
+ torch.nn.init.constant_(w2, 1)
106
+ else:
107
+ if tucker:
108
+ torch.nn.init.kaiming_uniform_(t2, a=math.sqrt(5))
109
+ torch.nn.init.kaiming_uniform_(w2a, a=math.sqrt(5))
110
+ torch.nn.init.constant_(w2b, 1)
111
+
112
+ if use_w1:
113
+ torch.nn.init.kaiming_uniform_(w1, a=math.sqrt(5))
114
+ else:
115
+ torch.nn.init.kaiming_uniform_(w1a, a=math.sqrt(5))
116
+ torch.nn.init.kaiming_uniform_(w1b, a=math.sqrt(5))
117
+
118
+ return w1, w1a, w1b, w2, w2a, w2b, t2
119
+
120
+
121
+ def lokr_diff_weight(w1, w1a, w1b, w2, w2a, w2b, t, gamma=1.0):
122
+ """### lokr_diff_weight
123
+
124
+ Args:
125
+ gamma (float, optional): scale factor, normally alpha/rank here
126
+
127
+ Returns:
128
+ torch.Tensor: ΔW
129
+ """
130
+ if w1a is not None:
131
+ rank = w1a.shape[1]
132
+ elif w2a is not None:
133
+ rank = w2a.shape[1]
134
+ else:
135
+ rank = gamma
136
+ scale = gamma / rank
137
+ if w1 is None:
138
+ w1 = w1a @ w1b
139
+ if w2 is None:
140
+ if t is None:
141
+ r, o, *k = w2b.shape
142
+ w2 = w2a @ w2b.view(r, -1)
143
+ w2 = w2.view(-1, o, *k)
144
+ else:
145
+ w2 = rebuild_tucker(t, w2a, w2b)
146
+ return make_kron(w1, w2, scale)
147
+
148
+
149
+ def lokr_bypass_forward_diff(
150
+ h, w1, w1a, w1b, w2, w2a, w2b, t, gamma=1.0, extra_args={}
151
+ ):
152
+ """### lokr_bypass_forward_diff
153
+
154
+ Args:
155
+ gamma (float, optional): scale factor, normally alpha/rank here
156
+ extra_args (dict, optional): extra args for forward func, \
157
+ e.g. padding, stride for Conv1/2/3d
158
+
159
+ Returns:
160
+ torch.Tensor: output tensor
161
+ """
162
+ use_w1 = w1 is not None
163
+ use_w2 = w2 is not None
164
+ tucker = t is not None
165
+ dim = t.dim() if tucker else w2.dim() if w2 is not None else w2b.dim()
166
+ print(dim)
167
+ rank = w1b.size(0) if not use_w1 else w2b.size(0) if not use_w2 else gamma
168
+ scale = gamma / rank
169
+ is_conv = dim > 2
170
+ op = FUNC_LIST[dim]
171
+
172
+ if is_conv:
173
+ kw_dict = extra_args
174
+ else:
175
+ kw_dict = {}
176
+
177
+ if use_w2:
178
+ ba = w2
179
+ else:
180
+ a = w2b
181
+ b = w2a
182
+
183
+ if t is not None:
184
+ a = a.view(*a.shape, *[1] * (dim - 2))
185
+ b = b.view(*b.shape, *[1] * (dim - 2))
186
+ elif is_conv:
187
+ b = b.view(*b.shape, *[1] * (dim - 2))
188
+
189
+ if use_w1:
190
+ c = w1
191
+ else:
192
+ c = w1a @ w1b
193
+ uq = c.size(1)
194
+
195
+ if is_conv:
196
+ # (b, uq), vq, ...
197
+ B, _, *rest = h.shape
198
+ h_in_group = h.reshape(B * uq, -1, *rest)
199
+ else:
200
+ # b, ..., uq, vq
201
+ h_in_group = h.reshape(*h.shape[:-1], uq, -1)
202
+
203
+ if use_w2:
204
+ hb = op(h_in_group, ba, **kw_dict)
205
+ else:
206
+ if is_conv:
207
+ if tucker:
208
+ ha = op(h_in_group, a)
209
+ ht = op(ha, t, **kw_dict)
210
+ hb = op(ht, b)
211
+ else:
212
+ ha = op(h_in_group, a, **kw_dict)
213
+ hb = op(ha, b)
214
+ else:
215
+ ha = op(h_in_group, a, **kw_dict)
216
+ hb = op(ha, b)
217
+
218
+ if is_conv:
219
+ # (b, uq), vp, ..., f
220
+ # -> b, uq, vp, ..., f
221
+ # -> b, f, vp, ..., uq
222
+ hb = hb.view(B, -1, *hb.shape[1:])
223
+ h_cross_group = hb.transpose(1, -1)
224
+ else:
225
+ # b, ..., uq, vq
226
+ # -> b, ..., vq, uq
227
+ h_cross_group = hb.transpose(-1, -2)
228
+
229
+ hc = F.linear(h_cross_group, c)
230
+ if is_conv:
231
+ # b, f, vp, ..., up
232
+ # -> b, up, vp, ... ,f
233
+ # -> b, c, ..., f
234
+ hc = hc.transpose(1, -1)
235
+ h = hc.reshape(B, -1, *hc.shape[3:])
236
+ else:
237
+ # b, ..., vp, up
238
+ # -> b, ..., up, vp
239
+ # -> b, ..., c
240
+ hc = hc.transpose(-1, -2)
241
+ h = hc.reshape(*hc.shape[:-2], -1)
242
+
243
+ return h * scale
244
+
245
+
246
+ if __name__ == "__main__":
247
+ w = torch.randn(32, 32, 3, 3, 3)
248
+ w1, w1a, w1b, w2, w2a, w2b, t = weight_gen(w, 2, tucker=False)
249
+ extra_args = {"padding": 1}
250
+
251
+ x = torch.randn(1, 32, 8, 8, 8)
252
+ y = FUNC_LIST[w.dim()](x, w, **extra_args)
253
+ diff_w = lokr_diff_weight(w1, w1a, w1b, w2, w2a, w2b, t, 1)
254
+ diff_y_w = FUNC_LIST[w.dim()](x, diff_w, **extra_args)
255
+ diff_y = lokr_bypass_forward_diff(x, w1, w1a, w1b, w2, w2a, w2b, t, 1, extra_args)
256
+
257
+ print(F.mse_loss(y, y + diff_y))
258
+ print(F.mse_loss(w, w + diff_w))
259
+ print(F.mse_loss(diff_y, diff_y_w))
@@ -184,6 +184,10 @@ class LycorisBaseModule(ModuleCustomSD):
184
184
 
185
185
  @classmethod
186
186
  def parametrize(cls, org_module, attr, *args, **kwargs):
187
+ from .full import FullModule
188
+
189
+ if cls is FullModule:
190
+ raise RuntimeError("FullModule cannot be used for parametrize.")
187
191
  target_param = getattr(org_module, attr)
188
192
  kwargs["bypass_mode"] = False
189
193
  if target_param.dim() == 2:
@@ -206,11 +210,12 @@ class LycorisBaseModule(ModuleCustomSD):
206
210
  target_param.shape[0],
207
211
  target_param.shape[1],
208
212
  *target_param.shape[2:],
213
+ bias=False,
209
214
  )
210
215
  proxy_module.weight = target_param
211
216
  module_obj = cls("", proxy_module, *args, **kwargs)
212
217
  module_obj.forward = module_obj.parametrize_forward
213
- module_obj.to(target_param.device)
218
+ module_obj.to(target_param)
214
219
  parametrize.register_parametrization(org_module, attr, module_obj)
215
220
  return module_obj
216
221
 
@@ -3,7 +3,6 @@ from math import log2
3
3
 
4
4
  import torch
5
5
  import torch.nn as nn
6
- import torch.nn.functional as F
7
6
 
8
7
  from einops import rearrange
9
8
 
@@ -197,46 +196,3 @@ class ButterflyOFTModule(LycorisBaseModule):
197
196
  w = self.make_weight(scale, x.device)
198
197
  kw_dict = self.kw_dict | {"weight": w, "bias": self.org_module[0].bias}
199
198
  return self.op(x, **kw_dict)
200
-
201
-
202
- if __name__ == "__main__":
203
- device = torch.device("cuda")
204
- module = ButterflyOFTModule
205
- with torch.autocast("cuda" if torch.cuda.is_available() else "cpu"):
206
- base = nn.Linear(128, 128).to(device).half()
207
- net = module("test", base, 1, 4, 1, weight_decompose=True).to(device)
208
- print(net)
209
- test_input = torch.randn(1, 128).to(device).half()
210
- test_output = net(test_input)
211
- torch.sum(test_output).backward()
212
- print(test_output.shape)
213
-
214
- base_4bit = LinearNF4(128, 128, device="cuda")
215
- base_4bit.load_state_dict(base.state_dict())
216
- base_4bit.to(device)
217
- qnet = module("test", base_4bit, 1, 4, 1, weight_decompose=False).to(device)
218
- print(qnet)
219
- test_input = torch.randn(1, 128).to(device).half()
220
- test_output = qnet(test_input)
221
- torch.sum(test_output).backward()
222
- print(test_output.shape)
223
-
224
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
225
- net = module("test", base, 1, 4, 1, weight_decompose=True, use_tucker=True).to(
226
- device
227
- )
228
- print(net)
229
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
230
- test_output = net(test_input)
231
- torch.sum(test_output).backward()
232
- print(test_output.shape)
233
-
234
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
235
- net = module.parametrize(
236
- base, "weight", 1, 4, 1, weight_decompose=True, use_tucker=True
237
- ).to(device)
238
- print(base)
239
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
240
- test_output = base(test_input)
241
- torch.sum(test_output).backward()
242
- print(test_output.shape)
@@ -4,8 +4,6 @@ import torch
4
4
  import torch.nn as nn
5
5
  import torch.nn.functional as F
6
6
 
7
- from einops import rearrange
8
-
9
7
  from .base import LycorisBaseModule
10
8
  from ..functional import factorization
11
9
  from ..logging import logger
@@ -182,46 +180,3 @@ class DiagOFTModule(LycorisBaseModule):
182
180
  w = self.make_weight(scale, x.device)
183
181
  kw_dict = self.kw_dict | {"weight": w, "bias": self.org_module[0].bias}
184
182
  return self.op(x, **kw_dict)
185
-
186
-
187
- if __name__ == "__main__":
188
- device = torch.device("cuda")
189
- module = DiagOFTModule
190
- with torch.autocast("cuda" if torch.cuda.is_available() else "cpu"):
191
- base = nn.Linear(128, 128).to(device).half()
192
- net = module("test", base, 1, 4, 1, weight_decompose=True).to(device)
193
- print(net)
194
- test_input = torch.randn(1, 128).to(device).half()
195
- test_output = net(test_input)
196
- torch.sum(test_output).backward()
197
- print(test_output.shape)
198
-
199
- base_4bit = LinearNF4(128, 128, device="cuda")
200
- base_4bit.load_state_dict(base.state_dict())
201
- base_4bit.to(device)
202
- qnet = module("test", base_4bit, 1, 4, 1, weight_decompose=False).to(device)
203
- print(qnet)
204
- test_input = torch.randn(1, 128).to(device).half()
205
- test_output = qnet(test_input)
206
- torch.sum(test_output).backward()
207
- print(test_output.shape)
208
-
209
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
210
- net = module("test", base, 1, 4, 1, weight_decompose=True, use_tucker=True).to(
211
- device
212
- )
213
- print(net)
214
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
215
- test_output = net(test_input)
216
- torch.sum(test_output).backward()
217
- print(test_output.shape)
218
-
219
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
220
- net = module.parametrize(
221
- base, "weight", 1, 4, 1, weight_decompose=True, use_tucker=True
222
- ).to(device)
223
- print(base)
224
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
225
- test_output = base(test_input)
226
- torch.sum(test_output).backward()
227
- print(test_output.shape)
@@ -3,7 +3,6 @@ import random
3
3
 
4
4
  import torch
5
5
  import torch.nn as nn
6
- import torch.nn.functional as F
7
6
 
8
7
  from .base import LycorisBaseModule
9
8
  from ..utils import product
@@ -156,46 +155,3 @@ class DyLoraModule(LycorisBaseModule):
156
155
  else self.org_module[0].bias.data
157
156
  )
158
157
  return self.op(x, weight, bias, **self.kw_dict)
159
-
160
-
161
- if __name__ == "__main__":
162
- device = torch.device("cuda")
163
- module = DyLoraModule
164
- with torch.autocast("cuda" if torch.cuda.is_available() else "cpu"):
165
- base = nn.Linear(128, 128).to(device).half()
166
- net = module("test", base, 1, 4, 1, weight_decompose=True).to(device)
167
- print(net)
168
- test_input = torch.randn(1, 128).to(device).half()
169
- test_output = net(test_input)
170
- torch.sum(test_output).backward()
171
- print(test_output.shape)
172
-
173
- base_4bit = LinearNF4(128, 128, device="cuda")
174
- base_4bit.load_state_dict(base.state_dict())
175
- base_4bit.to(device)
176
- qnet = module("test", base_4bit, 1, 4, 1, weight_decompose=False).to(device)
177
- print(qnet)
178
- test_input = torch.randn(1, 128).to(device).half()
179
- test_output = qnet(test_input)
180
- torch.sum(test_output).backward()
181
- print(test_output.shape)
182
-
183
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
184
- net = module("test", base, 1, 4, 1, weight_decompose=True, use_tucker=True).to(
185
- device
186
- )
187
- print(net)
188
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
189
- test_output = net(test_input)
190
- torch.sum(test_output).backward()
191
- print(test_output.shape)
192
-
193
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
194
- net = module.parametrize(
195
- base, "weight", 1, 4, 1, weight_decompose=True, use_tucker=True
196
- ).to(device)
197
- print(base)
198
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
199
- test_output = base(test_input)
200
- torch.sum(test_output).backward()
201
- print(test_output.shape)
@@ -1,4 +1,3 @@
1
- from typing import Mapping
2
1
  import torch
3
2
  import torch.nn as nn
4
3
 
@@ -77,6 +76,12 @@ class FullModule(LycorisBaseModule):
77
76
  else:
78
77
  self.org_bias = None
79
78
 
79
+ def restore(self):
80
+ self.org_module[0].forward = self.org_forward
81
+ self.org_module[0].weight = nn.Parameter(self._org_weight[0])
82
+ if self.org_bias is not None:
83
+ self.org_module[0].bias = nn.Parameter(self.org_bias[0])
84
+
80
85
  def load_state_dict(self, state_dict, strict: bool = True, assign: bool = False):
81
86
  return
82
87
 
@@ -141,7 +146,7 @@ class FullModule(LycorisBaseModule):
141
146
  if shape is not None:
142
147
  weight = weight.view(shape)
143
148
  if bias is not None:
144
- bias = bias.view(shape[0], 1)
149
+ bias = bias.view(shape[0])
145
150
  return weight, bias
146
151
 
147
152
  def forward(self, x: torch.Tensor, *args, **kwargs):
@@ -159,36 +164,3 @@ class FullModule(LycorisBaseModule):
159
164
  weight, bias = self.make_weight(scale, x.device)
160
165
  kw_dict = self.kw_dict | {"weight": weight, "bias": bias}
161
166
  return self.op(x, **kw_dict)
162
-
163
-
164
- if __name__ == "__main__":
165
- device = torch.device("cuda")
166
- module = FullModule
167
- with torch.autocast("cuda" if torch.cuda.is_available() else "cpu"):
168
- base = nn.Linear(128, 128).to(device).half()
169
- net = module("test", base, 1, 4, 1, weight_decompose=True).to(device)
170
- print(net)
171
- test_input = torch.randn(1, 128).to(device).half()
172
- test_output = net(test_input)
173
- torch.sum(test_output).backward()
174
- print(test_output.shape)
175
-
176
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
177
- net = module("test", base, 1, 4, 1, weight_decompose=True, use_tucker=True).to(
178
- device
179
- )
180
- print(net)
181
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
182
- test_output = net(test_input)
183
- torch.sum(test_output).backward()
184
- print(test_output.shape)
185
-
186
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
187
- net = module.parametrize(
188
- base, "weight", 1, 4, 1, weight_decompose=True, use_tucker=True
189
- ).to(device)
190
- print(base)
191
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
192
- test_output = base(test_input)
193
- torch.sum(test_output).backward()
194
- print(test_output.shape)
@@ -202,46 +202,3 @@ class GLoRAModule(LycorisBaseModule):
202
202
  else self.org_module[0].bias.data
203
203
  )
204
204
  return self.op(x, weight, bias, **self.kw_dict)
205
-
206
-
207
- if __name__ == "__main__":
208
- device = torch.device("cuda")
209
- module = GLoRAModule
210
- with torch.autocast("cuda" if torch.cuda.is_available() else "cpu"):
211
- base = nn.Linear(128, 128).to(device).half()
212
- net = module("test", base, 1, 4, 1, weight_decompose=True).to(device)
213
- print(net)
214
- test_input = torch.randn(1, 128).to(device).half()
215
- test_output = net(test_input)
216
- torch.sum(test_output).backward()
217
- print(test_output.shape)
218
-
219
- base_4bit = LinearNF4(128, 128, device="cuda")
220
- base_4bit.load_state_dict(base.state_dict())
221
- base_4bit.to(device)
222
- qnet = module("test", base_4bit, 1, 4, 1, weight_decompose=False).to(device)
223
- print(qnet)
224
- test_input = torch.randn(1, 128).to(device).half()
225
- test_output = qnet(test_input)
226
- torch.sum(test_output).backward()
227
- print(test_output.shape)
228
-
229
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
230
- net = module("test", base, 1, 4, 1, weight_decompose=True, use_tucker=True).to(
231
- device
232
- )
233
- print(net)
234
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
235
- test_output = net(test_input)
236
- torch.sum(test_output).backward()
237
- print(test_output.shape)
238
-
239
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
240
- net = module.parametrize(
241
- base, "weight", 1, 4, 1, weight_decompose=True, use_tucker=True
242
- ).to(device)
243
- print(base)
244
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
245
- test_output = base(test_input)
246
- torch.sum(test_output).backward()
247
- print(test_output.shape)
@@ -128,46 +128,3 @@ class IA3Module(LycorisBaseModule):
128
128
  else self.org_module[0].bias.data
129
129
  )
130
130
  return self.op(x, weight, bias, **self.kw_dict)
131
-
132
-
133
- if __name__ == "__main__":
134
- device = torch.device("cuda")
135
- module = IA3Module
136
- with torch.autocast("cuda" if torch.cuda.is_available() else "cpu"):
137
- base = nn.Linear(128, 128).to(device).half()
138
- net = module("test", base, 1, 4, 1, weight_decompose=True).to(device)
139
- print(net)
140
- test_input = torch.randn(1, 128).to(device).half()
141
- test_output = net(test_input)
142
- torch.sum(test_output).backward()
143
- print(test_output.shape)
144
-
145
- base_4bit = LinearNF4(128, 128, device="cuda")
146
- base_4bit.load_state_dict(base.state_dict())
147
- base_4bit.to(device)
148
- qnet = module("test", base_4bit, 1, 4, 1, weight_decompose=False).to(device)
149
- print(qnet)
150
- test_input = torch.randn(1, 128).to(device).half()
151
- test_output = qnet(test_input)
152
- torch.sum(test_output).backward()
153
- print(test_output.shape)
154
-
155
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
156
- net = module("test", base, 1, 4, 1, weight_decompose=True, use_tucker=True).to(
157
- device
158
- )
159
- print(net)
160
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
161
- test_output = net(test_input)
162
- torch.sum(test_output).backward()
163
- print(test_output.shape)
164
-
165
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
166
- net = module.parametrize(
167
- base, "weight", 1, 4, 1, weight_decompose=True, use_tucker=True
168
- ).to(device)
169
- print(base)
170
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
171
- test_output = base(test_input)
172
- torch.sum(test_output).backward()
173
- print(test_output.shape)
@@ -74,7 +74,7 @@ class LoConModule(LycorisBaseModule):
74
74
  self.down_op = self.op
75
75
  self.up_op = self.op
76
76
  if use_tucker and any(i != 1 for i in k_size):
77
- self.lora_down = self.module(in_dim, lora_dim, (1, 1), bias=False)
77
+ self.lora_down = self.module(in_dim, lora_dim, 1, bias=False)
78
78
  self.lora_mid = self.module(
79
79
  lora_dim, lora_dim, k_size, stride, padding, bias=False
80
80
  )
@@ -83,7 +83,7 @@ class LoConModule(LycorisBaseModule):
83
83
  self.lora_down = self.module(
84
84
  in_dim, lora_dim, k_size, stride, padding, bias=False
85
85
  )
86
- self.lora_up = self.module(lora_dim, out_dim, (1, 1), bias=False)
86
+ self.lora_up = self.module(lora_dim, out_dim, 1, bias=False)
87
87
  elif isinstance(org_module, nn.Linear):
88
88
  self.isconv = False
89
89
  self.down_op = F.linear
@@ -277,46 +277,3 @@ class LoConModule(LycorisBaseModule):
277
277
  return self.op(x, weight, bias, **self.kw_dict)
278
278
  else:
279
279
  return self.bypass_forward(x, scale=self.multiplier)
280
-
281
-
282
- if __name__ == "__main__":
283
- device = torch.device("cuda")
284
- module = LoConModule
285
- with torch.autocast("cuda" if torch.cuda.is_available() else "cpu"):
286
- base = nn.Linear(128, 128).to(device).half()
287
- net = module("test", base, 1, 4, 1, weight_decompose=True).to(device)
288
- print(net)
289
- test_input = torch.randn(1, 128).to(device).half()
290
- test_output = net(test_input)
291
- torch.sum(test_output).backward()
292
- print(test_output.shape)
293
-
294
- base_4bit = LinearNF4(128, 128, device="cuda")
295
- base_4bit.load_state_dict(base.state_dict())
296
- base_4bit.to(device)
297
- qnet = module("test", base_4bit, 1, 4, 1, weight_decompose=False).to(device)
298
- print(qnet)
299
- test_input = torch.randn(1, 128).to(device).half()
300
- test_output = qnet(test_input)
301
- torch.sum(test_output).backward()
302
- print(test_output.shape)
303
-
304
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
305
- net = module("test", base, 1, 4, 1, weight_decompose=True, use_tucker=True).to(
306
- device
307
- )
308
- print(net)
309
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
310
- test_output = net(test_input)
311
- torch.sum(test_output).backward()
312
- print(test_output.shape)
313
-
314
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
315
- net = module.parametrize(
316
- base, "weight", 1, 4, 1, weight_decompose=True, use_tucker=True
317
- )
318
- print(base)
319
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
320
- test_output = base(test_input)
321
- torch.sum(test_output).backward()
322
- print(test_output.shape)
@@ -2,7 +2,6 @@ import math
2
2
 
3
3
  import torch
4
4
  import torch.nn as nn
5
- import torch.nn.functional as F
6
5
 
7
6
  from .base import LycorisBaseModule
8
7
  from ..functional.loha import loha_diff_weight
@@ -267,46 +266,3 @@ class LohaModule(LycorisBaseModule):
267
266
  if self.wd:
268
267
  weight = self.apply_weight_decompose(weight)
269
268
  return self.op(x, weight, bias, **self.kw_dict)
270
-
271
-
272
- if __name__ == "__main__":
273
- device = torch.device("cuda")
274
- module = LohaModule
275
- with torch.autocast("cuda" if torch.cuda.is_available() else "cpu"):
276
- base = nn.Linear(128, 128).to(device).half()
277
- net = module("test", base, 1, 4, 1, weight_decompose=True).to(device)
278
- print(net)
279
- test_input = torch.randn(1, 128).to(device).half()
280
- test_output = net(test_input)
281
- torch.sum(test_output).backward()
282
- print(test_output.shape)
283
-
284
- base_4bit = LinearNF4(128, 128, device="cuda")
285
- base_4bit.load_state_dict(base.state_dict())
286
- base_4bit.to(device)
287
- qnet = module("test", base_4bit, 1, 4, 1, weight_decompose=False).to(device)
288
- print(qnet)
289
- test_input = torch.randn(1, 128).to(device).half()
290
- test_output = qnet(test_input)
291
- torch.sum(test_output).backward()
292
- print(test_output.shape)
293
-
294
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
295
- net = module("test", base, 1, 4, 1, weight_decompose=True, use_tucker=True).to(
296
- device
297
- )
298
- print(net)
299
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
300
- test_output = net(test_input)
301
- torch.sum(test_output).backward()
302
- print(test_output.shape)
303
-
304
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
305
- net = module.parametrize(
306
- base, "weight", 1, 4, 1, weight_decompose=True, use_tucker=True
307
- )
308
- print(base)
309
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
310
- test_output = base(test_input)
311
- torch.sum(test_output).backward()
312
- print(test_output.shape)
@@ -9,6 +9,7 @@ from einops import rearrange
9
9
 
10
10
  from .base import LycorisBaseModule
11
11
  from ..functional import factorization, rebuild_tucker
12
+ from ..functional.lokr import make_kron
12
13
  from ..logging import logger
13
14
  from ..utils.bnb import LinearNF4
14
15
 
@@ -22,15 +23,6 @@ def logging_force_full_matrix(lora_dim, dim, factor):
22
23
  )
23
24
 
24
25
 
25
- def make_kron(w1, w2, scale):
26
- if len(w2.shape) == 4:
27
- w1 = w1.unsqueeze(2).unsqueeze(2)
28
- w2 = w2.contiguous()
29
- rebuild = torch.kron(w1, w2)
30
-
31
- return rebuild * scale
32
-
33
-
34
26
  class LokrModule(LycorisBaseModule):
35
27
  support_module = {
36
28
  "linear",
@@ -115,9 +107,7 @@ class LokrModule(LycorisBaseModule):
115
107
  torch.empty(shape[0][1], shape[1][1], *k_size)
116
108
  )
117
109
  elif self.tucker:
118
- self.lokr_t2 = nn.Parameter(
119
- torch.empty(lora_dim, lora_dim, shape[2], shape[3])
120
- )
110
+ self.lokr_t2 = nn.Parameter(torch.empty(lora_dim, lora_dim, *shape[2:]))
121
111
  self.lokr_w2_a = nn.Parameter(
122
112
  torch.empty(lora_dim, shape[0][1])
123
113
  ) # b, 1-mode
@@ -339,40 +329,74 @@ class LokrModule(LycorisBaseModule):
339
329
  return scaled, orig_norm * ratio
340
330
 
341
331
  def bypass_forward_diff(self, h, scale=1):
342
- if len(self.shape) > 2 and self.shape[2] > 1:
343
- return (
344
- self.op(h, self.get_weight(self.shape), **self.kw_dict)
345
- * self.multiplier
346
- )
347
- if self.module_type.startswith("conv"):
348
- h = h.transpose(1, -1)
332
+ is_conv = self.module_type.startswith("conv")
349
333
  if self.use_w2:
350
334
  ba = self.lokr_w2
351
335
  else:
352
336
  a = self.lokr_w2_b
353
337
  b = self.lokr_w2_a
338
+
339
+ if self.tucker:
340
+ t = self.lokr_t2
341
+ a = a.view(*a.shape, *[1] * (len(t.shape) - 2))
342
+ b = b.view(*b.shape, *[1] * (len(t.shape) - 2))
343
+ elif is_conv:
344
+ a = a.view(*a.shape, *self.shape[2:])
345
+ b = b.view(*b.shape, *[1] * (len(self.shape) - 2))
346
+
354
347
  if self.use_w1:
355
348
  c = self.lokr_w1
356
349
  else:
357
350
  c = self.lokr_w1_a @ self.lokr_w1_b
358
351
  uq = c.size(1)
359
352
 
353
+ if is_conv:
354
+ # (b, uq), vq, ...
355
+ b, _, *rest = h.shape
356
+ h_in_group = h.reshape(b * uq, -1, *rest)
357
+ else:
358
+ # b, ..., uq, vq
359
+ h_in_group = h.reshape(*h.shape[:-1], uq, -1)
360
+
360
361
  if self.use_w2:
361
- vq = ba.size(1)
362
- h_in_group = rearrange(h, "b ... (uq vq) -> b ... uq vq", uq=uq, vq=vq)
363
- hb = F.linear(h_in_group, ba)
362
+ hb = self.op(h_in_group, ba, **self.kw_dict)
363
+ else:
364
+ if is_conv:
365
+ if self.tucker:
366
+ ha = self.op(h_in_group, a)
367
+ ht = self.op(ha, t, **self.kw_dict)
368
+ hb = self.op(ht, b)
369
+ else:
370
+ ha = self.op(h_in_group, a, **self.kw_dict)
371
+ hb = self.op(ha, b)
372
+ else:
373
+ ha = self.op(h_in_group, a, **self.kw_dict)
374
+ hb = self.op(ha, b)
375
+
376
+ if is_conv:
377
+ # (b, uq), vp, ..., f
378
+ # -> b, uq, vp, ..., f
379
+ # -> b, f, vp, ..., uq
380
+ hb = hb.view(b, -1, *hb.shape[1:])
381
+ h_cross_group = hb.transpose(1, -1)
364
382
  else:
365
- vq = a.size(1)
366
- h_in_group = rearrange(h, "b ... (uq vq) -> b ... uq vq", uq=uq, vq=vq)
367
- ha = F.linear(h_in_group, a)
368
- hb = F.linear(ha, b)
383
+ # b, ..., uq, vq
384
+ # -> b, ..., vq, uq
385
+ h_cross_group = hb.transpose(-1, -2)
369
386
 
370
- h_cross_group = hb.transpose(-1, -2)
371
387
  hc = F.linear(h_cross_group, c)
372
-
373
- h = rearrange(hc, "b ... vp up -> b ... (up vp)")
374
- if self.module_type.startswith("conv"):
375
- h = h.transpose(1, -1)
388
+ if is_conv:
389
+ # b, f, vp, ..., up
390
+ # -> b, up, vp, ... ,f
391
+ # -> b, c, ..., f
392
+ hc = hc.transpose(1, -1)
393
+ h = hc.reshape(b, -1, *hc.shape[3:])
394
+ else:
395
+ # b, ..., vp, up
396
+ # -> b, ..., up, vp
397
+ # -> b, ..., c
398
+ hc = hc.transpose(-1, -2)
399
+ h = hc.reshape(*hc.shape[:-2], -1)
376
400
 
377
401
  return self.drop(h * scale)
378
402
 
@@ -402,43 +426,44 @@ class LokrModule(LycorisBaseModule):
402
426
 
403
427
 
404
428
  if __name__ == "__main__":
405
- device = torch.device("cuda")
406
- module = LokrModule
407
- with torch.autocast("cuda" if torch.cuda.is_available() else "cpu"):
408
- base = nn.Linear(128, 128).to(device).half()
409
- net = module("test", base, 1, 4, 1, weight_decompose=True).to(device)
410
- print(net)
411
- test_input = torch.randn(1, 128).to(device).half()
412
- test_output = net(test_input)
413
- torch.sum(test_output).backward()
414
- print(test_output.shape)
415
-
416
- base_4bit = LinearNF4(128, 128, device="cuda")
417
- base_4bit.load_state_dict(base.state_dict())
418
- base_4bit.to(device)
419
- qnet = module("test", base_4bit, 1, 4, 1, weight_decompose=False).to(device)
420
- print(qnet)
421
- test_input = torch.randn(1, 128).to(device).half()
422
- test_output = qnet(test_input)
423
- torch.sum(test_output).backward()
424
- print(test_output.shape)
425
-
426
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
427
- net = module("test", base, 1, 4, 1, weight_decompose=True, use_tucker=True).to(
428
- device
429
- )
430
- print(net)
431
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
432
- test_output = net(test_input)
433
- torch.sum(test_output).backward()
434
- print(test_output.shape)
435
-
436
- base = nn.Conv2d(128, 128, 3, 1, 1).to(device).half()
437
- net = module.parametrize(
438
- base, "weight", 1, 4, 1, weight_decompose=True, use_tucker=True
439
- )
440
- print(base)
441
- test_input = torch.randn(1, 128, 16, 16).to(device).half()
442
- test_output = base(test_input)
443
- torch.sum(test_output).backward()
444
- print(test_output.shape)
429
+ base = nn.Conv2d(128, 128, 3, 1, 1)
430
+ net = LokrModule(
431
+ "",
432
+ base,
433
+ multiplier=1,
434
+ lora_dim=4,
435
+ alpha=1,
436
+ weight_decompose=False,
437
+ use_tucker=False,
438
+ use_scalar=False,
439
+ decompose_both=True,
440
+ )
441
+ net.apply_to()
442
+ sd = net.state_dict()
443
+ for key in sd:
444
+ if key != "alpha":
445
+ sd[key] = torch.randn_like(sd[key])
446
+ net.load_state_dict(sd)
447
+
448
+ test_input = torch.randn(1, 128, 16, 16)
449
+ test_output = net(test_input)
450
+ print(test_output.shape)
451
+
452
+ net2 = LokrModule(
453
+ "",
454
+ base,
455
+ multiplier=1,
456
+ lora_dim=4,
457
+ alpha=1,
458
+ weight_decompose=False,
459
+ use_tucker=False,
460
+ use_scalar=False,
461
+ bypass_mode=True,
462
+ decompose_both=True,
463
+ )
464
+ net2.apply_to()
465
+ net2.load_state_dict(sd)
466
+ print(net2)
467
+
468
+ test_output2 = net(test_input)
469
+ print(F.mse_loss(test_output, test_output2))
@@ -2,7 +2,10 @@ from functools import cache
2
2
 
3
3
  try:
4
4
  from bitsandbytes.nn import LinearNF4, Linear8bitLt, LinearFP4
5
+
6
+ SUPPORT_BNB = True
5
7
  except:
8
+ SUPPORT_BNB = False
6
9
  import torch.nn as nn
7
10
 
8
11
  class LinearNF4(nn.Linear):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: lycoris_lora
3
- Version: 3.0.0.dev8
3
+ Version: 3.0.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
@@ -10,6 +10,7 @@ lycoris/functional/__init__.py
10
10
  lycoris/functional/general.py
11
11
  lycoris/functional/locon.py
12
12
  lycoris/functional/loha.py
13
+ lycoris/functional/lokr.py
13
14
  lycoris/modules/__init__.py
14
15
  lycoris/modules/base.py
15
16
  lycoris/modules/boft.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="3.0.0.dev8",
7
+ version="3.0.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",