lycoris-lora 1.8.0.dev6__tar.gz → 1.8.0.dev8__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.
- lycoris_lora-1.8.0.dev8/.gitignore +128 -0
- lycoris_lora-1.8.0.dev8/Algo.md +134 -0
- lycoris_lora-1.8.0.dev8/Change.md +25 -0
- lycoris_lora-1.8.0.dev8/Demo.md +53 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/PKG-INFO +1 -1
- lycoris_lora-1.8.0.dev8/experiments/better_conv.py +105 -0
- lycoris_lora-1.8.0.dev8/experiments/better_conv_extract.py +67 -0
- lycoris_lora-1.8.0.dev8/experiments/concept_neuron.py +239 -0
- lycoris_lora-1.8.0.dev8/experiments/locon_extract_test.py +34 -0
- lycoris_lora-1.8.0.dev8/experiments/locon_merge_test.py +29 -0
- lycoris_lora-1.8.0.dev8/experiments/singular_value_test.py +97 -0
- lycoris_lora-1.8.0.dev8/experiments/sparse_bias_test.py +71 -0
- lycoris_lora-1.8.0.dev8/experiments/time_test.py +88 -0
- lycoris_lora-1.8.0.dev8/experiments/weakre_speed.py +14 -0
- lycoris_lora-1.8.0.dev6/lycoris/modules/lokr.py → lycoris_lora-1.8.0.dev8/lycoris/modules/glokr.py +1 -4
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris/modules/locon.py +32 -8
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris/modules/loha.py +3 -3
- lycoris_lora-1.8.0.dev8/lycoris/modules/lokr.py +266 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris_lora.egg-info/PKG-INFO +1 -1
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris_lora.egg-info/SOURCES.txt +18 -1
- lycoris_lora-1.8.0.dev8/requirements.txt +4 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/setup.py +1 -1
- lycoris_lora-1.8.0.dev8/tools/extract_locon.py +129 -0
- lycoris_lora-1.8.0.dev8/tools/merge.py +85 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/LICENSE.md +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/README.md +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris/__init__.py +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris/kohya/__init__.py +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris/kohya/kohya_model_utils.py +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris/kohya/kohya_utils.py +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris/modules/__init__.py +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris/modules/dylora.py +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris/modules/glora.py +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris/modules/ia3.py +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris/utils.py +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris_lora.egg-info/dependency_links.txt +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris_lora.egg-info/not-zip-safe +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris_lora.egg-info/requires.txt +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/lycoris_lora.egg-info/top_level.txt +0 -0
- {lycoris_lora-1.8.0.dev6 → lycoris_lora-1.8.0.dev8}/setup.cfg +0 -0
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# test
|
|
2
|
+
test_model/
|
|
3
|
+
|
|
4
|
+
# Editors
|
|
5
|
+
.vscode/
|
|
6
|
+
.idea/
|
|
7
|
+
|
|
8
|
+
# Vagrant
|
|
9
|
+
.vagrant/
|
|
10
|
+
|
|
11
|
+
# Mac/OSX
|
|
12
|
+
.DS_Store
|
|
13
|
+
|
|
14
|
+
# Windows
|
|
15
|
+
Thumbs.db
|
|
16
|
+
|
|
17
|
+
# Source for the following rules: https://raw.githubusercontent.com/github/gitignore/master/Python.gitignore
|
|
18
|
+
# Byte-compiled / optimized / DLL files
|
|
19
|
+
__pycache__/
|
|
20
|
+
*.py[cod]
|
|
21
|
+
*$py.class
|
|
22
|
+
|
|
23
|
+
# C extensions
|
|
24
|
+
*.so
|
|
25
|
+
|
|
26
|
+
# Distribution / packaging
|
|
27
|
+
.Python
|
|
28
|
+
build/
|
|
29
|
+
develop-eggs/
|
|
30
|
+
dist/
|
|
31
|
+
downloads/
|
|
32
|
+
eggs/
|
|
33
|
+
.eggs/
|
|
34
|
+
lib/
|
|
35
|
+
lib64/
|
|
36
|
+
parts/
|
|
37
|
+
sdist/
|
|
38
|
+
var/
|
|
39
|
+
wheels/
|
|
40
|
+
*.egg-info/
|
|
41
|
+
.installed.cfg
|
|
42
|
+
*.egg
|
|
43
|
+
MANIFEST
|
|
44
|
+
|
|
45
|
+
# PyInstaller
|
|
46
|
+
# Usually these files are written by a python script from a template
|
|
47
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
48
|
+
*.manifest
|
|
49
|
+
*.spec
|
|
50
|
+
|
|
51
|
+
# Installer logs
|
|
52
|
+
pip-log.txt
|
|
53
|
+
pip-delete-this-directory.txt
|
|
54
|
+
|
|
55
|
+
# Unit test / coverage reports
|
|
56
|
+
htmlcov/
|
|
57
|
+
.tox/
|
|
58
|
+
.nox/
|
|
59
|
+
.coverage
|
|
60
|
+
.coverage.*
|
|
61
|
+
.cache
|
|
62
|
+
nosetests.xml
|
|
63
|
+
coverage.xml
|
|
64
|
+
*.cover
|
|
65
|
+
.hypothesis/
|
|
66
|
+
.pytest_cache/
|
|
67
|
+
|
|
68
|
+
# Translations
|
|
69
|
+
*.mo
|
|
70
|
+
*.pot
|
|
71
|
+
|
|
72
|
+
# Django stuff:
|
|
73
|
+
*.log
|
|
74
|
+
local_settings.py
|
|
75
|
+
db.sqlite3
|
|
76
|
+
|
|
77
|
+
# Flask stuff:
|
|
78
|
+
instance/
|
|
79
|
+
.webassets-cache
|
|
80
|
+
|
|
81
|
+
# Scrapy stuff:
|
|
82
|
+
.scrapy
|
|
83
|
+
|
|
84
|
+
# Sphinx documentation
|
|
85
|
+
docs/_build/
|
|
86
|
+
|
|
87
|
+
# PyBuilder
|
|
88
|
+
target/
|
|
89
|
+
|
|
90
|
+
# Jupyter Notebook
|
|
91
|
+
.ipynb_checkpoints
|
|
92
|
+
|
|
93
|
+
# IPython
|
|
94
|
+
profile_default/
|
|
95
|
+
ipython_config.py
|
|
96
|
+
|
|
97
|
+
# pyenv
|
|
98
|
+
.python-version
|
|
99
|
+
|
|
100
|
+
# celery beat schedule file
|
|
101
|
+
celerybeat-schedule
|
|
102
|
+
|
|
103
|
+
# SageMath parsed files
|
|
104
|
+
*.sage.py
|
|
105
|
+
|
|
106
|
+
# Environments
|
|
107
|
+
.env
|
|
108
|
+
.venv
|
|
109
|
+
env/
|
|
110
|
+
venv/
|
|
111
|
+
ENV/
|
|
112
|
+
env.bak/
|
|
113
|
+
venv.bak/
|
|
114
|
+
|
|
115
|
+
# Spyder project settings
|
|
116
|
+
.spyderproject
|
|
117
|
+
.spyproject
|
|
118
|
+
|
|
119
|
+
# Rope project settings
|
|
120
|
+
.ropeproject
|
|
121
|
+
|
|
122
|
+
# mkdocs documentation
|
|
123
|
+
/site
|
|
124
|
+
|
|
125
|
+
# mypy
|
|
126
|
+
.mypy_cache/
|
|
127
|
+
.dmypy.json
|
|
128
|
+
dmypy.json
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# Algorithm explanation
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## Basic Idea
|
|
5
|
+
Linear Layer:
|
|
6
|
+
|
|
7
|
+
$Y = W \cdot X$
|
|
8
|
+
|
|
9
|
+
finetuning is to get the $W'$
|
|
10
|
+
|
|
11
|
+
$Y = W \cdot X + W' \cdot X$
|
|
12
|
+
|
|
13
|
+
and normally $shape(W') = shape(W)$
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Conventional Methods
|
|
18
|
+
[Ref](https://arxiv.org/abs/2106.09685)
|
|
19
|
+
|
|
20
|
+
Linear:
|
|
21
|
+
|
|
22
|
+
$Y_{out \times batch} = W_{out \times in} \cdot X_{in \times batch}$
|
|
23
|
+
|
|
24
|
+
$\xrightarrow{} Y_{out \times batch} = W_{out \times in} \cdot X_{in \times batch} + Wa_{out \times dim} \cdot Wb_{dim \times in} \cdot X_{in \times batch}$
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
LoRA for Convolution:
|
|
28
|
+
Consider im2col of matmul first:
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+

|
|
32
|
+
$X:[channel, width, height]$
|
|
33
|
+
|
|
34
|
+
$\xrightarrow{reorder}[c \times kw \times kh, outw \times outh]$
|
|
35
|
+
|
|
36
|
+
$Kernels: [out, c, kw, kh] \xrightarrow{reshape} [out, c \times kw \times kh]$
|
|
37
|
+
|
|
38
|
+
$Conv(X, Kernels) = Kernels \times X \xrightarrow{reshape} [out, outw, outh]$
|
|
39
|
+
|
|
40
|
+
and then write down this conventional LoRA for conv layer
|
|
41
|
+
$Conv(in, out, ksize, padding, stride)$
|
|
42
|
+
|
|
43
|
+
$\xrightarrow{}Conv(dim, out, 1)\circ Conv(in, dim, ksize, padding, stride)$
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
In this method, we can get that
|
|
47
|
+
$W' = Wa \cdot Wb$ with $rank(W') \le dim$
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## Hadamard Product
|
|
52
|
+
[Ref](https://arxiv.org/abs/2108.06098)
|
|
53
|
+

|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
consider $W' = Wa \odot Wb$, we can get $rank(W') \le rank(Wa) \times rank(Wb)$.
|
|
57
|
+
And then we use conventional method on $Wa$ and $Wb$. Which means it can use 2x dim to get square rank.
|
|
58
|
+
|
|
59
|
+
**Rank != Information capacity, but they are relative**
|
|
60
|
+
|
|
61
|
+
based on the experiment result from the paper, it seems like although the rank(Wa) * rank(Wb) is just upper bound, but almost everytime it will produce W' with rank = rank(Wa)*rank(Wb).
|
|
62
|
+
|
|
63
|
+
### Why custom backward
|
|
64
|
+
with $W' = (Wa_1 \cdot Wa_2) \odot (Wb_1 \cdot Wb_2)$, when you need to calc the backpropogation, you will need $\Delta{W'}$ and $Wa$ to calc $\Delta{Wb}$, also $Wb$ for $\Delta{Wa}$.
|
|
65
|
+
|
|
66
|
+
With pytorch's autograd, this kind of operation will cache the $Wa$ and $Wb$ for calc the backward, which means it will cache 2x size of weight for backward.
|
|
67
|
+
|
|
68
|
+
To avoid this terrible situation, I impl a custom backward which will reconstruct $Wa$ and $Wb$ when actually needed, this method saved tons of memory.
|
|
69
|
+
|
|
70
|
+
### CP-Decomposition
|
|
71
|
+
[Ref](https://arxiv.org/abs/1412.6553)
|
|
72
|
+
|
|
73
|
+
As mentioned before, the weight shape for convolution layer is $[out, in, kw, kh]$. And we just unfold it to $[out, in \times kw \times kh]$ for decomposition.
|
|
74
|
+
|
|
75
|
+
But actually there is a method to decomposition any shape ot tensor called cp decomposition.
|
|
76
|
+
|
|
77
|
+
Using cp-decomposition in Covolution will be something like:
|
|
78
|
+
|
|
79
|
+
$\tau: [dim, dim, kw, kh]$ <br>
|
|
80
|
+
$x_1: [dim, out]$<br>
|
|
81
|
+
$x_2: [dim, in]$<br>
|
|
82
|
+
$W' = \tau \times_1 x_1 \times_2 x_2$<br>
|
|
83
|
+
$W': [out, in, kw, kh]$
|
|
84
|
+
|
|
85
|
+
Or write this thing as multiple conv layer:
|
|
86
|
+
|
|
87
|
+
Conv(in, dim, (1, 1))<br>
|
|
88
|
+
↓<br>
|
|
89
|
+
Conv(dim, dim, (kw, kh), stride, padding)<br>
|
|
90
|
+
↓<br>
|
|
91
|
+
conv(dim, out, (1, 1))<br>
|
|
92
|
+
|
|
93
|
+
For hadamard product implementation, just use 2 different $W'$ and multiply them together.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Kronercker Product
|
|
98
|
+
|
|
99
|
+
### Definition
|
|
100
|
+
|
|
101
|
+
If $W_1$ is an a x b matrix and $W_2$ is a c x d matrix, then the Kronecker Product of two matrices is
|
|
102
|
+
|
|
103
|
+
$W' = W_1 \otimes W_2$ and an ac x bd matrix.
|
|
104
|
+
|
|
105
|
+
In meaning of matrix, $W_2$ becomes weight and $W_1$ becomes weight scale of $W_2$
|
|
106
|
+
|
|
107
|
+
### About rank
|
|
108
|
+
|
|
109
|
+
And we can decompose $W_2$ using LoRA with rank, r.
|
|
110
|
+
|
|
111
|
+
$W_2 = Wa_2 \cdot Wb_2$ then $W' = W_1 \otimes (Wa_2 \cdot Wb_2)$
|
|
112
|
+
|
|
113
|
+
we can get $rank(W') \le rank(W_1) \times rank(Wa_2 \cdot Wb_2)$ and $rank(W_1) \le min(a, b), rank(Wa_2 \cdot Wb_2) \le r$
|
|
114
|
+
|
|
115
|
+
=> $rank(W') \le min(a, b) \times r$
|
|
116
|
+
|
|
117
|
+
Remember that $min(a, b) \times r$ is upper bound. $rank(W') = min(a, b) \times r$ does not guarantee. Experiment needs.
|
|
118
|
+
|
|
119
|
+
### Number of parameters
|
|
120
|
+
|
|
121
|
+
We decompose matrix, $W' = W_1 \otimes (Wa_2 \cdot Wb_2)$.
|
|
122
|
+
|
|
123
|
+
(# of parameters) = $(a \times b) + (c \times r + r \times d) = a \times b + r \times (c + d)$, m = ac, n = bd.
|
|
124
|
+
|
|
125
|
+
and suppose best case $a=c= \sqrt{m}, b=d= \sqrt{n}$
|
|
126
|
+
|
|
127
|
+
then, (# of parameters) = $\sqrt{mn} + r \times (\sqrt{m} + \sqrt{n})$
|
|
128
|
+
|
|
129
|
+
We can reduce the number of parameters to order of square root maximally.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Sparse Bias
|
|
134
|
+
Todo...
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
## 2023/06/28 update to 1.7.1
|
|
4
|
+
* **rearrange the version format, previous 0.1.7 should be 1.7.0**
|
|
5
|
+
* fix the bug in scale weight norm
|
|
6
|
+
|
|
7
|
+
## 2023/06/26 Update to 0.1.7
|
|
8
|
+
* Add support for rank_dropout and module_dropout on LoCon/LoHa/LoKr
|
|
9
|
+
* Add support for scale_weight_norms on LoCon/LoHa/LoKr
|
|
10
|
+
* Will support SDXL on 0.1.8 (you can follow the dev branch)
|
|
11
|
+
|
|
12
|
+
## 2023/06/04 update to 0.1.6
|
|
13
|
+
* add dylora and IA^3 algorithm
|
|
14
|
+
|
|
15
|
+
## 2023/03/29 Update to 0.1.4
|
|
16
|
+
* cp decomposition is default to disable now
|
|
17
|
+
* add 4 more layer to train (conv_in/out, time_embedding)
|
|
18
|
+
|
|
19
|
+
## 2023/03/12 Update to 0.1.0
|
|
20
|
+
* Add cp-decomposition implementation for convolution layer
|
|
21
|
+
* Both LoRA(LoCon) and LoHa can use this more parameter-efficient decomposition
|
|
22
|
+
* Add sparse bias for extracted LoRA
|
|
23
|
+
* Will add to training in the future (Maybe)
|
|
24
|
+
* Change weight initialization method in LoHa
|
|
25
|
+
* Use lower std to avoid loss to go high or NaN when using normal lr (like 0.5 in Dadap)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Demo, Example, Comparing
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
## expand LoRA to Convolution Layer
|
|
5
|
+
lora for transformer only
|
|
6
|
+
vs
|
|
7
|
+
lora for whole model
|
|
8
|
+
|
|
9
|
+
Yog-Sothoth LoRA/LoCon:
|
|
10
|
+
https://civitai.com/models/14878/loconlora-yog-sothoth-depersonalization
|
|
11
|
+
|
|
12
|
+
LoRA rank=1:
|
|
13
|
+

|
|
14
|
+
LoCon rank=1
|
|
15
|
+

|
|
16
|
+
|
|
17
|
+
xy grid:
|
|
18
|
+

|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
With some experiments from community, finetuning whole model can learn "More". But in some case this means it will overfit heavily.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Hadamard product vs Conventional
|
|
26
|
+
We introduced LoRA finetuning with Hadamard Product representation from FedPara.
|
|
27
|
+
And based on this [experiments](https://civitai.com/models/17336/roukin8-character-lohaloconfullckpt-8), LoHa with same size (and dim>2, or rank>4) can get better result in some situation.
|
|
28
|
+
|
|
29
|
+

|
|
30
|
+
|
|
31
|
+
This is some comments from the experiments:
|
|
32
|
+
```
|
|
33
|
+
Why LoHa?
|
|
34
|
+
|
|
35
|
+
The following comparison should be quite convincing.
|
|
36
|
+
|
|
37
|
+
(Left 4 LoHa with different number of training steps; Right 4 same thing but for LoCon; same seed same training parameters for the two training)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
In addition to the five characters I also train a bunch of style into the model (what I have always been doing actually).
|
|
41
|
+
|
|
42
|
+
However, LoRa and LoCon do not combine styles with characters that well (characters are only trained with anime images) and this capacity gets largely improved in LoHa.
|
|
43
|
+
|
|
44
|
+
Note that the two files have almost the same size (around 30mb). For this I set (linear_dim, conv_dim) to (16,8) for LoCon and (8,4) for LoHa. However with Hadamard product the resulting matrix could now be of rank 8x8=64 for linear layers and 4x4=16 for convolutional layers.
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
And there is more example about LoHA vs LoCon in same file size. (diff < 200KB)
|
|
48
|
+

|
|
49
|
+

|
|
50
|
+
|
|
51
|
+

|
|
52
|
+

|
|
53
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: lycoris_lora
|
|
3
|
-
Version: 1.8.0.
|
|
3
|
+
Version: 1.8.0.dev8
|
|
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
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
import torch.nn as nn
|
|
3
|
+
import torch.nn.functional as F
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class HadaWeightCP(torch.autograd.Function):
|
|
7
|
+
@staticmethod
|
|
8
|
+
def forward(ctx, orig_weight, t1, w1a, w1b, t2, w2a, w2b, scale=torch.tensor(1)):
|
|
9
|
+
ctx.save_for_backward(t1, w1a, w1b, t2, w2a, w2b, scale)
|
|
10
|
+
|
|
11
|
+
temp = torch.einsum('i j k l, j r -> i r k l', t1, w1b)
|
|
12
|
+
rebuild1 = torch.einsum('i j k l, i r -> r j k l', temp, w1a)
|
|
13
|
+
|
|
14
|
+
temp = torch.einsum('i j k l, j r -> i r k l', t2, w2b)
|
|
15
|
+
rebuild2 = torch.einsum('i j k l, i r -> r j k l', temp, w2a)
|
|
16
|
+
|
|
17
|
+
return orig_weight + rebuild1*rebuild2*scale
|
|
18
|
+
|
|
19
|
+
@staticmethod
|
|
20
|
+
def backward(ctx, grad_out):
|
|
21
|
+
(t1, w1a, w1b, t2, w2a, w2b, scale) = ctx.saved_tensors
|
|
22
|
+
|
|
23
|
+
grad_out = grad_out*scale
|
|
24
|
+
|
|
25
|
+
temp = torch.einsum('i j k l, j r -> i r k l', t2, w2b)
|
|
26
|
+
rebuild = torch.einsum('i j k l, i r -> r j k l', temp, w2a)
|
|
27
|
+
|
|
28
|
+
grad_w = rebuild*grad_out
|
|
29
|
+
del rebuild
|
|
30
|
+
|
|
31
|
+
grad_w1a = torch.einsum('r j k l, i j k l -> r i', temp, grad_w)
|
|
32
|
+
grad_temp = torch.einsum('i j k l, i r -> r j k l', grad_w, w1a.T)
|
|
33
|
+
del grad_w, temp
|
|
34
|
+
|
|
35
|
+
grad_w1b = torch.einsum('i r k l, i j k l -> r j', t1, grad_temp)
|
|
36
|
+
grad_t1 = torch.einsum('i j k l, j r -> i r k l', grad_temp, w1b.T)
|
|
37
|
+
del grad_temp
|
|
38
|
+
|
|
39
|
+
temp = torch.einsum('i j k l, j r -> i r k l', t1, w1b)
|
|
40
|
+
rebuild = torch.einsum('i j k l, i r -> r j k l', temp, w1a)
|
|
41
|
+
|
|
42
|
+
grad_w = rebuild*grad_out
|
|
43
|
+
del rebuild
|
|
44
|
+
|
|
45
|
+
grad_w2a = torch.einsum('r j k l, i j k l -> r i', temp, grad_w)
|
|
46
|
+
grad_temp = torch.einsum('i j k l, i r -> r j k l', grad_w, w2a.T)
|
|
47
|
+
del grad_w, temp
|
|
48
|
+
|
|
49
|
+
grad_w2b = torch.einsum('i r k l, i j k l -> r j', t2, grad_temp)
|
|
50
|
+
grad_t2 = torch.einsum('i j k l, j r -> i r k l', grad_temp, w2b.T)
|
|
51
|
+
del grad_temp
|
|
52
|
+
return grad_out, grad_t1, grad_w1a, grad_w1b, grad_t2, grad_w2a, grad_w2b, None
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def make_weight_cp(orig_weight, t1, w1a, w1b, t2, w2a, w2b, scale=torch.tensor(0.25)):
|
|
56
|
+
return HadaWeightCP.apply(orig_weight, t1, w1a, w1b, t2, w2a, w2b, scale)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def make_cp(orig_weight, t1, w1a, w1b, t2, w2a, w2b, scale=torch.tensor(0.25)):
|
|
60
|
+
temp = torch.einsum('i j k l, j r -> i r k l', t1, w1b)
|
|
61
|
+
rebuild1 = torch.einsum('i j k l, i r -> r j k l', temp, w1a)
|
|
62
|
+
|
|
63
|
+
temp = torch.einsum('i j k l, j r -> i r k l', t2, w2b)
|
|
64
|
+
rebuild2 = torch.einsum('i j k l, i r -> r j k l', temp, w2a)
|
|
65
|
+
|
|
66
|
+
return orig_weight + rebuild1*rebuild2 * scale
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
KERNEL_SIZE = 3
|
|
70
|
+
STRIDE = 1
|
|
71
|
+
PADDING = 1
|
|
72
|
+
IN_CH = 1280
|
|
73
|
+
OUT_CH = 1208
|
|
74
|
+
LORA_RANK = 4
|
|
75
|
+
SIZE = 32
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
t1 = nn.Parameter(torch.randn(LORA_RANK, LORA_RANK, 3, 3))
|
|
79
|
+
w1a = nn.Parameter(torch.randn(LORA_RANK, OUT_CH))
|
|
80
|
+
w1b = nn.Parameter(torch.randn(LORA_RANK, IN_CH))
|
|
81
|
+
|
|
82
|
+
t2 = nn.Parameter(torch.randn(LORA_RANK, LORA_RANK, 3, 3))
|
|
83
|
+
w2a = nn.Parameter(torch.randn(LORA_RANK, OUT_CH))
|
|
84
|
+
w2b = nn.Parameter(torch.randn(LORA_RANK, IN_CH))
|
|
85
|
+
|
|
86
|
+
orig = nn.Parameter(torch.randn(OUT_CH, IN_CH, 3, 3))
|
|
87
|
+
|
|
88
|
+
test_x = torch.randn(1, 4, 64, 64)
|
|
89
|
+
test_t = torch.randn(1, 4, 64, 64)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
w1 = make_cp(orig, t1, w1a, w1b, t2, w2a, w2b)
|
|
93
|
+
w2 = make_weight_cp(orig, t1, w1a, w1b, t2, w2a, w2b)
|
|
94
|
+
|
|
95
|
+
torch.mean(w1).backward()
|
|
96
|
+
grad1 = t1.grad.clone()
|
|
97
|
+
t1.grad = None
|
|
98
|
+
|
|
99
|
+
torch.mean(w2).backward()
|
|
100
|
+
grad2 = t1.grad.clone()
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
print('MSE Loss: ', F.mse_loss(grad1, grad2))
|
|
104
|
+
print('L1 Loss : ', F.l1_loss(grad1, grad2))
|
|
105
|
+
print('Distance: ', torch.dist(grad1, grad2))
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import os, sys
|
|
2
|
+
sys.path.insert(0, os.getcwd())
|
|
3
|
+
import torch
|
|
4
|
+
import torch.nn as nn
|
|
5
|
+
import torch.nn.functional as F
|
|
6
|
+
|
|
7
|
+
from lycoris.utils import extract_conv
|
|
8
|
+
from pytorch_lightning import seed_everything
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def make_sparse(t, sparsity=0.95):
|
|
12
|
+
sparse_t = t.masked_fill(
|
|
13
|
+
torch.abs(t) < torch.quantile(torch.abs(t), sparsity),
|
|
14
|
+
0
|
|
15
|
+
)
|
|
16
|
+
return sparse_t
|
|
17
|
+
|
|
18
|
+
def make_cp(t, x1, x2):
|
|
19
|
+
x1 = x1.reshape(x1.size(0), -1)
|
|
20
|
+
x2 = x2.reshape(x2.size(0), -1)
|
|
21
|
+
|
|
22
|
+
# [rank, rank, k, k] * [rank, out]
|
|
23
|
+
temp = torch.einsum('n m k l, i n -> i m k l', t, x2)
|
|
24
|
+
|
|
25
|
+
# [out, rank, k, k] * [rank, in]
|
|
26
|
+
result = torch.einsum('i m k l, m j -> i j k l', temp, x1)
|
|
27
|
+
print(result.shape)
|
|
28
|
+
return result
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
seed_everything(0)
|
|
32
|
+
|
|
33
|
+
KERNEL_SIZE = 3
|
|
34
|
+
STRIDE = 1
|
|
35
|
+
PADDING = 1
|
|
36
|
+
IN_CH = 1280
|
|
37
|
+
OUT_CH = 640
|
|
38
|
+
LORA_RANK = 32
|
|
39
|
+
SIZE = 32
|
|
40
|
+
|
|
41
|
+
conv_orig = nn.Conv2d(IN_CH, OUT_CH, 3, 1, 1, bias=False).cuda()
|
|
42
|
+
conv_orig.weight = nn.Parameter(
|
|
43
|
+
(torch.randn(OUT_CH, LORA_RANK)
|
|
44
|
+
@ torch.randn(LORA_RANK, IN_CH*9)
|
|
45
|
+
* 0.05
|
|
46
|
+
).reshape(conv_orig.weight.shape).cuda()
|
|
47
|
+
)
|
|
48
|
+
conv_rebd = nn.Conv2d(IN_CH, OUT_CH, 3, 1, 1, bias=False).cuda()
|
|
49
|
+
|
|
50
|
+
extract_a, extract_b, diff = extract_conv(conv_orig.weight, 'fixed', LORA_RANK, 'cuda')
|
|
51
|
+
out_weight = extract_b.reshape(OUT_CH, -1) @ extract_a.reshape(LORA_RANK, -1)
|
|
52
|
+
out_weight = out_weight.reshape(conv_orig.weight.shape)
|
|
53
|
+
|
|
54
|
+
extract_a, extract_c, diff = extract_conv(extract_a.transpose(0, 1), 'fixed', LORA_RANK, 'cuda')
|
|
55
|
+
extract_a = extract_a.transpose(0, 1)
|
|
56
|
+
extract_c = extract_c.transpose(0, 1)
|
|
57
|
+
print(extract_a.shape, extract_b.shape, extract_c.shape)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
conv_rebd.weight = nn.Parameter(make_cp(
|
|
61
|
+
extract_a, extract_c, extract_b
|
|
62
|
+
))
|
|
63
|
+
print()
|
|
64
|
+
print('without sparse bias')
|
|
65
|
+
print('MSE Loss: ', F.mse_loss(conv_orig.weight, conv_rebd.weight))
|
|
66
|
+
print('L1 Loss : ', F.l1_loss(conv_orig.weight, conv_rebd.weight))
|
|
67
|
+
print('Distance: ', torch.dist(conv_orig.weight, conv_rebd.weight))
|