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.
Files changed (62) hide show
  1. lycoris/__init__.py +26 -0
  2. lycoris/concept.py +254 -0
  3. lycoris/config.py +86 -0
  4. lycoris/dylora.py +175 -0
  5. lycoris/functional/__init__.py +13 -0
  6. lycoris/functional/general.py +79 -0
  7. lycoris/functional/locon.py +102 -0
  8. lycoris/functional/loha.py +187 -0
  9. lycoris/functional/lokr.py +259 -0
  10. lycoris/hcp/__init__.py +4 -0
  11. lycoris/hcp/base.py +153 -0
  12. lycoris/hcp/diag_oft.py +62 -0
  13. lycoris/hcp/loha.py +85 -0
  14. lycoris/hcp/lokr.py +131 -0
  15. lycoris/ia3.py +68 -0
  16. lycoris/kohya/__init__.py +866 -0
  17. lycoris/kohya/kohya_model_utils.py +1165 -0
  18. lycoris/kohya/kohya_utils.py +48 -0
  19. lycoris/kohya/model_utils.py +1633 -0
  20. lycoris/kohya/original_unet.py +1760 -0
  21. lycoris/kohya/sdxl_model_util.py +581 -0
  22. lycoris/kohya/sdxl_original_unet.py +1243 -0
  23. lycoris/kohya/test_hyperdream.py +527 -0
  24. lycoris/kohya/utils.py +48 -0
  25. lycoris/kohya.py +850 -0
  26. lycoris/kohya_model_utils.py +1165 -0
  27. lycoris/kohya_utils.py +48 -0
  28. lycoris/locon.py +86 -0
  29. lycoris/logging.py +36 -0
  30. lycoris/loha.py +199 -0
  31. lycoris/lokr.py +220 -0
  32. lycoris/modules/__init__.py +147 -0
  33. lycoris/modules/attention.py +259 -0
  34. lycoris/modules/base.py +278 -0
  35. lycoris/modules/boft.py +198 -0
  36. lycoris/modules/diag_oft.py +182 -0
  37. lycoris/modules/dylora.py +157 -0
  38. lycoris/modules/full.py +166 -0
  39. lycoris/modules/glokr.py +300 -0
  40. lycoris/modules/glora.py +204 -0
  41. lycoris/modules/hyperlycoris.py +3 -0
  42. lycoris/modules/hypernet/__init__.py +1 -0
  43. lycoris/modules/hypernet/generater.py +223 -0
  44. lycoris/modules/hypernet/text_encoder.py +266 -0
  45. lycoris/modules/ia3.py +130 -0
  46. lycoris/modules/locon.py +279 -0
  47. lycoris/modules/loha.py +268 -0
  48. lycoris/modules/lokr.py +469 -0
  49. lycoris/modules/norms.py +104 -0
  50. lycoris/utils/__init__.py +669 -0
  51. lycoris/utils/bnb.py +29 -0
  52. lycoris/utils/general.py +5 -0
  53. lycoris/utils/logger.py +35 -0
  54. lycoris/utils/preset.py +9 -0
  55. lycoris/utils/xformers_utils.py +13 -0
  56. lycoris/utils.py +504 -0
  57. lycoris/wrapper.py +537 -0
  58. lycoris_lora-3.0.0.dev9.dist-info/LICENSE.md +201 -0
  59. lycoris_lora-3.0.0.dev9.dist-info/METADATA +14 -0
  60. lycoris_lora-3.0.0.dev9.dist-info/RECORD +62 -0
  61. lycoris_lora-3.0.0.dev9.dist-info/WHEEL +5 -0
  62. 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))
@@ -0,0 +1,4 @@
1
+ from .base import LycorisPluginContainer, LycorisPluginBlock
2
+ from .loha import LohaBlock
3
+ from .lokr import LokrBlock
4
+ from .diag_oft import DiagOFTBlock
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