lycoris-lora 3.0.0.dev9__py3-none-any.whl
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.
- lycoris/__init__.py +26 -0
- lycoris/concept.py +254 -0
- lycoris/config.py +86 -0
- lycoris/dylora.py +175 -0
- lycoris/functional/__init__.py +13 -0
- lycoris/functional/general.py +79 -0
- lycoris/functional/locon.py +102 -0
- lycoris/functional/loha.py +187 -0
- lycoris/functional/lokr.py +259 -0
- lycoris/hcp/__init__.py +4 -0
- lycoris/hcp/base.py +153 -0
- lycoris/hcp/diag_oft.py +62 -0
- lycoris/hcp/loha.py +85 -0
- lycoris/hcp/lokr.py +131 -0
- lycoris/ia3.py +68 -0
- lycoris/kohya/__init__.py +866 -0
- lycoris/kohya/kohya_model_utils.py +1165 -0
- lycoris/kohya/kohya_utils.py +48 -0
- lycoris/kohya/model_utils.py +1633 -0
- lycoris/kohya/original_unet.py +1760 -0
- lycoris/kohya/sdxl_model_util.py +581 -0
- lycoris/kohya/sdxl_original_unet.py +1243 -0
- lycoris/kohya/test_hyperdream.py +527 -0
- lycoris/kohya/utils.py +48 -0
- lycoris/kohya.py +850 -0
- lycoris/kohya_model_utils.py +1165 -0
- lycoris/kohya_utils.py +48 -0
- lycoris/locon.py +86 -0
- lycoris/logging.py +36 -0
- lycoris/loha.py +199 -0
- lycoris/lokr.py +220 -0
- lycoris/modules/__init__.py +147 -0
- lycoris/modules/attention.py +259 -0
- lycoris/modules/base.py +278 -0
- lycoris/modules/boft.py +198 -0
- lycoris/modules/diag_oft.py +182 -0
- lycoris/modules/dylora.py +157 -0
- lycoris/modules/full.py +166 -0
- lycoris/modules/glokr.py +300 -0
- lycoris/modules/glora.py +204 -0
- lycoris/modules/hyperlycoris.py +3 -0
- lycoris/modules/hypernet/__init__.py +1 -0
- lycoris/modules/hypernet/generater.py +223 -0
- lycoris/modules/hypernet/text_encoder.py +266 -0
- lycoris/modules/ia3.py +130 -0
- lycoris/modules/locon.py +279 -0
- lycoris/modules/loha.py +268 -0
- lycoris/modules/lokr.py +469 -0
- lycoris/modules/norms.py +104 -0
- lycoris/utils/__init__.py +669 -0
- lycoris/utils/bnb.py +29 -0
- lycoris/utils/general.py +5 -0
- lycoris/utils/logger.py +35 -0
- lycoris/utils/preset.py +9 -0
- lycoris/utils/xformers_utils.py +13 -0
- lycoris/utils.py +504 -0
- lycoris/wrapper.py +537 -0
- lycoris_lora-3.0.0.dev9.dist-info/LICENSE.md +201 -0
- lycoris_lora-3.0.0.dev9.dist-info/METADATA +14 -0
- lycoris_lora-3.0.0.dev9.dist-info/RECORD +62 -0
- lycoris_lora-3.0.0.dev9.dist-info/WHEEL +5 -0
- lycoris_lora-3.0.0.dev9.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,102 @@
|
|
|
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
|
+
|
|
9
|
+
|
|
10
|
+
def lora_weight_gen(org_weight, rank, tucker=True):
|
|
11
|
+
"""### lora_weight_gen
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
org_weight (torch.Tensor): the weight tensor
|
|
15
|
+
rank (int): low rank
|
|
16
|
+
|
|
17
|
+
Returns:
|
|
18
|
+
torch.Tensor: down, up[, mid]
|
|
19
|
+
"""
|
|
20
|
+
out_dim, in_dim, *k = org_weight.shape
|
|
21
|
+
if k and tucker:
|
|
22
|
+
down = torch.empty(rank, in_dim, *(1 for _ in k))
|
|
23
|
+
up = torch.empty(out_dim, rank, *(1 for _ in k))
|
|
24
|
+
mid = torch.empty(rank, rank, *k)
|
|
25
|
+
nn.init.kaiming_uniform_(down, a=math.sqrt(5))
|
|
26
|
+
nn.init.constant_(up, 0)
|
|
27
|
+
nn.init.kaiming_uniform_(mid, a=math.sqrt(5))
|
|
28
|
+
return down, up, mid
|
|
29
|
+
else:
|
|
30
|
+
down = torch.empty(rank, in_dim)
|
|
31
|
+
up = torch.empty(out_dim, rank)
|
|
32
|
+
nn.init.kaiming_uniform_(down, a=math.sqrt(5))
|
|
33
|
+
nn.init.constant_(up, 0)
|
|
34
|
+
return down, up
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def lora_diff_weight(d, u, m=None, gamma=1.0):
|
|
38
|
+
"""### lora_diff_weight
|
|
39
|
+
|
|
40
|
+
Get ΔW = BA, where BA is low rank decomposition
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
d (torch.Tensor): weight of down proj linear/conv layer
|
|
44
|
+
u (torch.Tensor): weight of up proj linear/conv layer
|
|
45
|
+
m (torch.Tensor, optional): middle weight of tucker decomposition
|
|
46
|
+
gamma (float, optional): scale factor, normally alpha/rank here
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
torch.Tensor: ΔW
|
|
50
|
+
"""
|
|
51
|
+
R, I, *k = d.shape
|
|
52
|
+
O, R, *_ = u.shape
|
|
53
|
+
u = u * gamma
|
|
54
|
+
|
|
55
|
+
if m is None:
|
|
56
|
+
result = u.reshape(-1, u.size(1)) @ d.reshape(d.size(0), -1)
|
|
57
|
+
else:
|
|
58
|
+
R, R, *k = m.shape
|
|
59
|
+
u = u.reshape(u.size(0), -1).transpose(0, 1)
|
|
60
|
+
d = d.reshape(d.size(0), -1)
|
|
61
|
+
result = rebuild_tucker(m, u, d)
|
|
62
|
+
return result.reshape(O, I, *k)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def lora_bypass_forward_diff(x, d, u, m=None, gamma=1.0, extra_args={}):
|
|
66
|
+
"""### lora_bypass_forward_diff
|
|
67
|
+
|
|
68
|
+
Args:
|
|
69
|
+
x (torch.Tensor): input tensor
|
|
70
|
+
d (torch.Tensor): weight of down proj linear/conv layer
|
|
71
|
+
u (torch.Tensor): weight of up proj linear/conv layer
|
|
72
|
+
m (torch.Tensor, optional): middle weight of tucker decomposition
|
|
73
|
+
gamma (float, optional): scale factor, normally alpha/rank here
|
|
74
|
+
extra_args (dict, optional): extra args for forward func, \
|
|
75
|
+
e.g. padding, stride for Conv1/2/3d
|
|
76
|
+
|
|
77
|
+
Returns:
|
|
78
|
+
torch.Tensor: output tensor
|
|
79
|
+
"""
|
|
80
|
+
if m is not None:
|
|
81
|
+
down = FUNC_LIST[d.dim()](x, d)
|
|
82
|
+
mid = FUNC_LIST[d.dim()](down, m, **extra_args)
|
|
83
|
+
up = FUNC_LIST[d.dim()](mid, u)
|
|
84
|
+
else:
|
|
85
|
+
down = FUNC_LIST[d.dim()](x, d, **extra_args)
|
|
86
|
+
up = FUNC_LIST[d.dim()](down, u)
|
|
87
|
+
return up * gamma
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
if __name__ == "__main__":
|
|
91
|
+
w = torch.randn(32, 32, 3, 3, 3)
|
|
92
|
+
d, u, m = lora_weight_gen(w, 4)
|
|
93
|
+
u = u + 0.01
|
|
94
|
+
extra_args = {"padding": 1}
|
|
95
|
+
|
|
96
|
+
x = torch.randn(1, 32, 8, 8, 8)
|
|
97
|
+
y = FUNC_LIST[d.dim()](x, w, **extra_args)
|
|
98
|
+
diff_w = lora_diff_weight(d, u, m, 1)
|
|
99
|
+
diff_y = lora_bypass_forward_diff(x, d, u, m, 1, extra_args)
|
|
100
|
+
|
|
101
|
+
print(F.mse_loss(y, y + diff_y))
|
|
102
|
+
print(F.mse_loss(w, w + diff_w))
|
|
@@ -0,0 +1,187 @@
|
|
|
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 FUNC_LIST
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class HadaWeight(torch.autograd.Function):
|
|
11
|
+
@staticmethod
|
|
12
|
+
def forward(ctx, w1d, w1u, w2d, w2u, scale=torch.tensor(1)):
|
|
13
|
+
ctx.save_for_backward(w1d, w1u, w2d, w2u, scale)
|
|
14
|
+
diff_weight = ((w1u @ w1d) * (w2u @ w2d)) * scale
|
|
15
|
+
return diff_weight
|
|
16
|
+
|
|
17
|
+
@staticmethod
|
|
18
|
+
def backward(ctx, grad_out):
|
|
19
|
+
(w1d, w1u, w2d, w2u, scale) = ctx.saved_tensors
|
|
20
|
+
grad_out = grad_out * scale
|
|
21
|
+
temp = grad_out * (w2u @ w2d)
|
|
22
|
+
grad_w1u = temp @ w1d.T
|
|
23
|
+
grad_w1d = w1u.T @ temp
|
|
24
|
+
|
|
25
|
+
temp = grad_out * (w1u @ w1d)
|
|
26
|
+
grad_w2u = temp @ w2d.T
|
|
27
|
+
grad_w2d = w2u.T @ temp
|
|
28
|
+
|
|
29
|
+
del temp
|
|
30
|
+
return grad_w1d, grad_w1u, grad_w2d, grad_w2u, None
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class HadaWeightTucker(torch.autograd.Function):
|
|
34
|
+
@staticmethod
|
|
35
|
+
def forward(ctx, t1, w1d, w1u, t2, w2d, w2u, scale=torch.tensor(1)):
|
|
36
|
+
ctx.save_for_backward(t1, w1d, w1u, t2, w2d, w2u, scale)
|
|
37
|
+
|
|
38
|
+
rebuild1 = torch.einsum("i j ..., j r, i p -> p r ...", t1, w1d, w1u)
|
|
39
|
+
rebuild2 = torch.einsum("i j ..., j r, i p -> p r ...", t2, w2d, w2u)
|
|
40
|
+
|
|
41
|
+
return rebuild1 * rebuild2 * scale
|
|
42
|
+
|
|
43
|
+
@staticmethod
|
|
44
|
+
def backward(ctx, grad_out):
|
|
45
|
+
(t1, w1d, w1u, t2, w2d, w2u, scale) = ctx.saved_tensors
|
|
46
|
+
grad_out = grad_out * scale
|
|
47
|
+
|
|
48
|
+
temp = torch.einsum("i j ..., j r -> i r ...", t2, w2d)
|
|
49
|
+
rebuild = torch.einsum("i j ..., i r -> r j ...", temp, w2u)
|
|
50
|
+
|
|
51
|
+
grad_w = rebuild * grad_out
|
|
52
|
+
del rebuild
|
|
53
|
+
|
|
54
|
+
grad_w1u = torch.einsum("r j ..., i j ... -> r i", temp, grad_w)
|
|
55
|
+
grad_temp = torch.einsum("i j ..., i r -> r j ...", grad_w, w1u.T)
|
|
56
|
+
del grad_w, temp
|
|
57
|
+
|
|
58
|
+
grad_w1d = torch.einsum("i r ..., i j ... -> r j", t1, grad_temp)
|
|
59
|
+
grad_t1 = torch.einsum("i j ..., j r -> i r ...", grad_temp, w1d.T)
|
|
60
|
+
del grad_temp
|
|
61
|
+
|
|
62
|
+
temp = torch.einsum("i j ..., j r -> i r ...", t1, w1d)
|
|
63
|
+
rebuild = torch.einsum("i j ..., i r -> r j ...", temp, w1u)
|
|
64
|
+
|
|
65
|
+
grad_w = rebuild * grad_out
|
|
66
|
+
del rebuild
|
|
67
|
+
|
|
68
|
+
grad_w2u = torch.einsum("r j ..., i j ... -> r i", temp, grad_w)
|
|
69
|
+
grad_temp = torch.einsum("i j ..., i r -> r j ...", grad_w, w2u.T)
|
|
70
|
+
del grad_w, temp
|
|
71
|
+
|
|
72
|
+
grad_w2d = torch.einsum("i r ..., i j ... -> r j", t2, grad_temp)
|
|
73
|
+
grad_t2 = torch.einsum("i j ..., j r -> i r ...", grad_temp, w2d.T)
|
|
74
|
+
del grad_temp
|
|
75
|
+
return grad_t1, grad_w1d, grad_w1u, grad_t2, grad_w2d, grad_w2u, None
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def make_weight(w1d, w1u, w2d, w2u, scale):
|
|
79
|
+
return HadaWeight.apply(w1d, w1u, w2d, w2u, scale)
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def make_weight_tucker(t1, w1d, w1u, t2, w2d, w2u, scale):
|
|
83
|
+
return HadaWeightTucker.apply(t1, w1d, w1u, t2, w2d, w2u, scale)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def loha_weight_gen(org_weight, rank, tucker=True):
|
|
87
|
+
"""### loha_weight_gen
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
org_weight (torch.Tensor): the weight tensor
|
|
91
|
+
rank (int): low rank
|
|
92
|
+
|
|
93
|
+
Returns:
|
|
94
|
+
torch.Tensor: w1d, w2d, w1u, w2u[, t1, t2]
|
|
95
|
+
"""
|
|
96
|
+
out_dim, in_dim, *k = org_weight.shape
|
|
97
|
+
if k and tucker:
|
|
98
|
+
w1d = torch.empty(rank, in_dim)
|
|
99
|
+
w1u = torch.empty(rank, out_dim)
|
|
100
|
+
t1 = torch.empty(rank, rank, *k)
|
|
101
|
+
w2d = torch.empty(rank, in_dim)
|
|
102
|
+
w2u = torch.empty(rank, out_dim)
|
|
103
|
+
t2 = torch.empty(rank, rank, *k)
|
|
104
|
+
nn.init.normal_(w1d, std=1)
|
|
105
|
+
nn.init.constant_(w1u, 0)
|
|
106
|
+
nn.init.normal_(w2d, std=1)
|
|
107
|
+
nn.init.normal_(w2u, std=0.1)
|
|
108
|
+
nn.init.normal_(t1, std=0.1)
|
|
109
|
+
nn.init.normal_(t2, std=0.1)
|
|
110
|
+
return w1d, w2d, w1u, w2u, t1, t2
|
|
111
|
+
else:
|
|
112
|
+
w1d = torch.empty(rank, in_dim)
|
|
113
|
+
w1u = torch.empty(rank, out_dim)
|
|
114
|
+
w2d = torch.empty(rank, in_dim)
|
|
115
|
+
w2u = torch.empty(rank, out_dim)
|
|
116
|
+
nn.init.normal_(w1d, std=1)
|
|
117
|
+
nn.init.constant_(w1u, 0)
|
|
118
|
+
nn.init.normal_(w2d, std=1)
|
|
119
|
+
nn.init.normal_(w2u, std=0.1)
|
|
120
|
+
return w1d, w2d, w1u, w2u
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def loha_diff_weight(w1d, w1u, w2d, w2u, t1=None, t2=None, gamma=1.0):
|
|
124
|
+
"""### loha_diff_weight
|
|
125
|
+
|
|
126
|
+
Get ΔW = BA, where BA is low rank decomposition
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
w1d, w2d (torch.Tensor): weight of down proj linear/conv layer
|
|
130
|
+
w1u, w2u (torch.Tensor): weight of up proj linear/conv layer
|
|
131
|
+
t1, t2 (torch.Tensor, optional): middle weight of tucker decomposition
|
|
132
|
+
gamma (float, optional): scale factor, normally alpha/rank here
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
torch.Tensor: ΔW
|
|
136
|
+
"""
|
|
137
|
+
if t1 is not None and t2 is not None:
|
|
138
|
+
R, I = w1d.shape
|
|
139
|
+
R, O = w1u.shape
|
|
140
|
+
R, R, *k = t1.shape
|
|
141
|
+
result = make_weight_tucker(t1, w1d, w1u, t2, w2d, w2u, gamma)
|
|
142
|
+
else:
|
|
143
|
+
R, I, *k = w1d.shape
|
|
144
|
+
O, R, *_ = w1u.shape
|
|
145
|
+
w1d = w1d.reshape(w1d.size(0), -1)
|
|
146
|
+
w1u = w1u.reshape(-1, w1u.size(1))
|
|
147
|
+
w2d = w2d.reshape(w2d.size(0), -1)
|
|
148
|
+
w2u = w1u.reshape(-1, w2u.size(1))
|
|
149
|
+
result = make_weight(w1d, w1u, w2d, w2u, gamma)
|
|
150
|
+
|
|
151
|
+
result = result.reshape(O, I, *k)
|
|
152
|
+
return result
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def loha_bypass_forward_diff(
|
|
156
|
+
x, w1d, w1u, w2d, w2u, t1=None, t2=None, gamma=1.0, extra_args={}
|
|
157
|
+
):
|
|
158
|
+
"""### loha_bypass_forward_diff
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
x (torch.Tensor): input tensor
|
|
162
|
+
w1d, w2d (torch.Tensor): weight of up proj linear/conv layer
|
|
163
|
+
w1u, w2u (torch.Tensor): weight of down proj linear/conv layer
|
|
164
|
+
gamma (float, optional): scale factor, normally alpha/rank here
|
|
165
|
+
extra_args (dict, optional): extra args for forward func, \
|
|
166
|
+
e.g. padding, stride for Conv1/2/3d
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
torch.Tensor: output tensor
|
|
170
|
+
"""
|
|
171
|
+
diff_w = loha_diff_weight(w1d, w1u, w2d, w2u, t1, t2, gamma)
|
|
172
|
+
return FUNC_LIST[w1d.dim() if t1 is None else t1.dim()](x, diff_w, **extra_args)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
if __name__ == "__main__":
|
|
176
|
+
w = torch.randn(128, 128, 3, 3, 3)
|
|
177
|
+
w1d, w2d, w1u, w2u, t1, t2 = loha_weight_gen(w, 4, tucker=True)
|
|
178
|
+
w1u += 0.01
|
|
179
|
+
extra_args = {"padding": 1}
|
|
180
|
+
|
|
181
|
+
x = torch.randn(1, 128, 8, 8, 8)
|
|
182
|
+
y = FUNC_LIST[w.dim()](x, w, **extra_args)
|
|
183
|
+
diff_w = loha_diff_weight(w1d, w2d, w1u, w2u, t1, t2, 1)
|
|
184
|
+
diff_y = loha_bypass_forward_diff(x, w1d, w2d, w1u, w2u, t1, t2, 1, extra_args)
|
|
185
|
+
|
|
186
|
+
print(F.mse_loss(y, y + diff_y))
|
|
187
|
+
print(F.mse_loss(w, w + diff_w))
|
|
@@ -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))
|
lycoris/hcp/__init__.py
ADDED
lycoris/hcp/base.py
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
from typing import Tuple, Callable, Any, Optional
|
|
2
|
+
import torch
|
|
3
|
+
import torch.nn as nn
|
|
4
|
+
import torch.nn.functional as F
|
|
5
|
+
|
|
6
|
+
from diffusers.models.lora import LoRACompatibleLinear, LoRACompatibleConv
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
import hcpdiff
|
|
10
|
+
from hcpdiff.models.plugin import PatchPluginContainer, PatchPluginBlock
|
|
11
|
+
from hcpdiff.utils.utils import isinstance_list
|
|
12
|
+
except ImportError:
|
|
13
|
+
print(
|
|
14
|
+
"HCP-Diffusion is not installed, hcp feature will be disabled. "
|
|
15
|
+
"Use `pip install hcpdiff` to install hcpdiff."
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from ..utils.logger import logger
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class LycorisPluginContainer(PatchPluginContainer):
|
|
22
|
+
def __init__(self, host_name: str, host: nn.Module, parent_block: nn.Module):
|
|
23
|
+
super(LycorisPluginContainer, self).__init__(host_name, host, parent_block)
|
|
24
|
+
|
|
25
|
+
self.op = None
|
|
26
|
+
self.module_type = ""
|
|
27
|
+
self.extra_args = {}
|
|
28
|
+
if isinstance(host, nn.Conv2d):
|
|
29
|
+
self.op = F.conv2d
|
|
30
|
+
self.module_type = "conv"
|
|
31
|
+
self.extra_args = {
|
|
32
|
+
"stride": host.stride,
|
|
33
|
+
"padding": host.padding,
|
|
34
|
+
"dilation": host.dilation,
|
|
35
|
+
"groups": host.groups,
|
|
36
|
+
}
|
|
37
|
+
elif isinstance(host, nn.Linear):
|
|
38
|
+
self.op = F.linear
|
|
39
|
+
self.module_type = "linear"
|
|
40
|
+
self.extra_args = {}
|
|
41
|
+
elif isinstance(host, nn.LayerNorm):
|
|
42
|
+
self.op = F.layer_norm
|
|
43
|
+
self.module_type = "norm"
|
|
44
|
+
self.extra_args = {
|
|
45
|
+
"normalized_shape": host.normalized_shape,
|
|
46
|
+
"eps": host.eps,
|
|
47
|
+
}
|
|
48
|
+
elif isinstance(host, nn.GroupNorm):
|
|
49
|
+
self.op = F.group_norm
|
|
50
|
+
self.module_type = "norm"
|
|
51
|
+
self.extra_args = {"num_groups": host.num_groups, "eps": host.eps}
|
|
52
|
+
else:
|
|
53
|
+
logger.warning(
|
|
54
|
+
f"Unsupported host type: '{type(host)}' for LyCORIS plugin. "
|
|
55
|
+
"Will ignore this block."
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
def forward(self, *args, **kwargs):
|
|
59
|
+
if self.op is None:
|
|
60
|
+
return self._host(*args, **kwargs)
|
|
61
|
+
|
|
62
|
+
if (
|
|
63
|
+
isinstance(self._host, (LoRACompatibleLinear, LoRACompatibleConv))
|
|
64
|
+
and len(args) == 2
|
|
65
|
+
):
|
|
66
|
+
scale = args[1]
|
|
67
|
+
args = [args[0]]
|
|
68
|
+
else:
|
|
69
|
+
scale = 1
|
|
70
|
+
|
|
71
|
+
org_weight = self._host.weight
|
|
72
|
+
org_bias = getattr(self._host, "bias", None)
|
|
73
|
+
new_weight = org_weight
|
|
74
|
+
new_bias = org_bias
|
|
75
|
+
total_diff_output = 0
|
|
76
|
+
|
|
77
|
+
for name in self.plugin_names:
|
|
78
|
+
lyco_plugin_block = getattr(self, name)
|
|
79
|
+
(
|
|
80
|
+
diff_weight,
|
|
81
|
+
diff_bias,
|
|
82
|
+
diff_output,
|
|
83
|
+
update_weight,
|
|
84
|
+
update_bias,
|
|
85
|
+
) = lyco_plugin_block(
|
|
86
|
+
org_weight, org_bias, new_weight, new_bias, *args, **kwargs
|
|
87
|
+
)
|
|
88
|
+
# logger.debug(f'diff weight norm: {torch.norm(diff_weight).detach().cpu().item()}')
|
|
89
|
+
if diff_weight is not None:
|
|
90
|
+
if update_weight:
|
|
91
|
+
new_weight = new_weight + diff_weight * scale
|
|
92
|
+
else:
|
|
93
|
+
new_weight = diff_weight
|
|
94
|
+
if diff_bias is not None:
|
|
95
|
+
if update_bias:
|
|
96
|
+
new_bias = (
|
|
97
|
+
diff_bias * scale
|
|
98
|
+
if new_bias is None
|
|
99
|
+
else new_bias + diff_bias * scale
|
|
100
|
+
)
|
|
101
|
+
else:
|
|
102
|
+
new_bias = diff_bias
|
|
103
|
+
if diff_output is not None:
|
|
104
|
+
total_diff_output = total_diff_output + diff_output * scale
|
|
105
|
+
|
|
106
|
+
weight_dict = {
|
|
107
|
+
"weight": new_weight,
|
|
108
|
+
"bias": new_bias,
|
|
109
|
+
}
|
|
110
|
+
output = self.op(*args, **weight_dict, **self.extra_args)
|
|
111
|
+
return output + total_diff_output
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class LycorisPluginBlock(PatchPluginBlock):
|
|
115
|
+
container_cls = LycorisPluginContainer
|
|
116
|
+
|
|
117
|
+
def __init__(
|
|
118
|
+
self,
|
|
119
|
+
*args,
|
|
120
|
+
dim=4,
|
|
121
|
+
alpha=1.0,
|
|
122
|
+
dropout=0.0,
|
|
123
|
+
rank_dropout=0.0,
|
|
124
|
+
module_dropout=0.0,
|
|
125
|
+
use_tucker=False,
|
|
126
|
+
**kwargs,
|
|
127
|
+
):
|
|
128
|
+
super(LycorisPluginBlock, self).__init__(*args, **kwargs)
|
|
129
|
+
self.module_type = self.container().module_type
|
|
130
|
+
self.dim = dim
|
|
131
|
+
self.alpha = alpha
|
|
132
|
+
self.dropout = dropout
|
|
133
|
+
self.rank_dropout = rank_dropout
|
|
134
|
+
self.module_dropout = module_dropout
|
|
135
|
+
self.tucker = False
|
|
136
|
+
|
|
137
|
+
if self.module_type == "conv":
|
|
138
|
+
self.out_dim = self.host().out_channels
|
|
139
|
+
self.in_dim = self.host().in_channels
|
|
140
|
+
self.k_size = self.host().kernel_size
|
|
141
|
+
self.tucker = use_tucker
|
|
142
|
+
self.shape = [self.out_dim, self.in_dim, *self.k_size]
|
|
143
|
+
elif self.module_type == "linear":
|
|
144
|
+
self.out_dim = self.host().out_features
|
|
145
|
+
self.in_dim = self.host().in_features
|
|
146
|
+
self.shape = [self.out_dim, self.in_dim]
|
|
147
|
+
elif self.module_type == "norm":
|
|
148
|
+
self.dim = self.host().weight.shape[0]
|
|
149
|
+
else:
|
|
150
|
+
raise NotImplementedError
|
|
151
|
+
|
|
152
|
+
def forward(self, org_weight, org_bias, new_weight, new_bias, *args, **kwargs):
|
|
153
|
+
raise NotImplementedError
|