Krea 2 Eric Insert: combined LoRA, license, notice, attribution
Browse files- .gitattributes +3 -0
- LICENSE.pdf +3 -0
- NOTICE +7 -0
- README.md +21 -0
- images/diagram-paper.png +3 -0
- images/porch.jpg +3 -0
- krea2-eric-insert.safetensors +3 -0
- merge_checkpoint.py +48 -0
- merge_loras.py +34 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
LICENSE.pdf filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
images/diagram-paper.png filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
images/porch.jpg filter=lfs diff=lfs merge=lfs -text
|
LICENSE.pdf
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b82a2805162bde714a4eb27b9063c4fc3345d08a30be055134a6160e5430ba74
|
| 3 |
+
size 137711
|
NOTICE
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Krea 2 is licensed under the Krea 2 Community License Agreement. For more information, visit https://krea.ai/krea-2-licensing.
|
| 2 |
+
|
| 3 |
+
This model is a modified version of the Krea Model (Krea 2 Turbo). It combines two LoRAs into one file:
|
| 4 |
+
- Krea 2 Identity Edit v1.2 by conradlocke (https://huggingface.co/conradlocke/krea2-identity-edit), distributed under the Krea 2 Community License Agreement.
|
| 5 |
+
- er1cshen v2 (step 2000), a character LoRA of Eric Shen trained with ai-toolkit (https://github.com/ostris/ai-toolkit).
|
| 6 |
+
|
| 7 |
+
This model is not an official Krea product and is not endorsed by Krea.
|
README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
license: other
|
| 3 |
+
license_name: krea-2-community-license
|
| 4 |
+
license_link: https://huggingface.co/yuncuns/krea2-eric-insert/blob/main/LICENSE.pdf
|
| 5 |
+
base_model: krea/Krea-2-Turbo
|
| 6 |
+
tags:
|
| 7 |
+
- lora
|
| 8 |
+
- krea2
|
| 9 |
+
---
|
| 10 |
+
|
| 11 |
+
# Krea 2 Eric Insert
|
| 12 |
+
|
| 13 |
+

|
| 14 |
+
|
| 15 |
+
<!-- description: written by Eric -->
|
| 16 |
+
|
| 17 |
+
## Attribution
|
| 18 |
+
|
| 19 |
+
- **Base model:** [Krea 2 Turbo](https://huggingface.co/krea/Krea-2-Turbo) by Krea. Krea 2 is licensed under the Krea 2 Community License Agreement. For more information, visit https://krea.ai/krea-2-licensing. This is a modified version of the Krea Model and is not an official Krea product or endorsed by Krea.
|
| 20 |
+
- **Krea 2 Identity Edit v1.2** by [conradlocke](https://huggingface.co/conradlocke/krea2-identity-edit), merged in unchanged. Requires the [ComfyUI-Krea2Edit](https://github.com/lbouaraba/comfyui-krea2edit) node pack.
|
| 21 |
+
- **er1cshen** character LoRA by Eric Shen, trained with [ai-toolkit](https://github.com/ostris/ai-toolkit).
|
images/diagram-paper.png
ADDED
|
Git LFS Details
|
images/porch.jpg
ADDED
|
Git LFS Details
|
krea2-eric-insert.safetensors
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:5f1eb227fb730f78313721e774443737301580bf75a5260adcca104a42d021b9
|
| 3 |
+
size 2056781272
|
merge_checkpoint.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Bake a LoRA into the base model: W_new = W + B @ A, for every layer the LoRA touches.
|
| 2 |
+
|
| 3 |
+
Streams one tensor at a time, so it never holds the whole 26 GB model in memory.
|
| 4 |
+
Tensor names, shapes and dtypes are unchanged, so the output header equals the input header.
|
| 5 |
+
"""
|
| 6 |
+
import json, struct, sys
|
| 7 |
+
import numpy as np
|
| 8 |
+
import torch
|
| 9 |
+
from safetensors import safe_open
|
| 10 |
+
|
| 11 |
+
base_path, lora_path, out_path = sys.argv[1:4]
|
| 12 |
+
|
| 13 |
+
with open(base_path, "rb") as f:
|
| 14 |
+
n = struct.unpack("<Q", f.read(8))[0]
|
| 15 |
+
header_bytes = f.read(n)
|
| 16 |
+
header = json.loads(header_bytes)
|
| 17 |
+
meta = header.pop("__metadata__", {})
|
| 18 |
+
data_start = 8 + n
|
| 19 |
+
|
| 20 |
+
lora = safe_open(lora_path, "pt")
|
| 21 |
+
lora_keys = set(lora.keys())
|
| 22 |
+
|
| 23 |
+
meta = dict(meta, merged_lora="krea2-eric-insert (Krea 2 Identity Edit v1.2 + er1cshen v2_2000)", merge="W + B@A at strength 1.0")
|
| 24 |
+
header["__metadata__"] = meta
|
| 25 |
+
new_header = json.dumps(header, separators=(",", ":")).encode()
|
| 26 |
+
new_header += b" " * ((8 - len(new_header) % 8) % 8)
|
| 27 |
+
|
| 28 |
+
order = sorted((k for k in header if k != "__metadata__"), key=lambda k: header[k]["data_offsets"][0])
|
| 29 |
+
patched = 0
|
| 30 |
+
with open(base_path, "rb") as src, open(out_path, "wb") as out:
|
| 31 |
+
out.write(struct.pack("<Q", len(new_header)))
|
| 32 |
+
out.write(new_header)
|
| 33 |
+
for k in order:
|
| 34 |
+
info = header[k]
|
| 35 |
+
s, e = info["data_offsets"]
|
| 36 |
+
src.seek(data_start + s)
|
| 37 |
+
raw = src.read(e - s)
|
| 38 |
+
stem = "diffusion_model." + k[: -len(".weight")] if k.endswith(".weight") else None
|
| 39 |
+
if stem and stem + ".lora_A.weight" in lora_keys:
|
| 40 |
+
assert info["dtype"] == "BF16"
|
| 41 |
+
w = torch.frombuffer(bytearray(raw), dtype=torch.bfloat16).reshape(info["shape"]).float()
|
| 42 |
+
A = lora.get_tensor(stem + ".lora_A.weight").float()
|
| 43 |
+
B = lora.get_tensor(stem + ".lora_B.weight").float()
|
| 44 |
+
w += B @ A
|
| 45 |
+
raw = w.to(torch.bfloat16).contiguous().view(torch.uint8).numpy().tobytes()
|
| 46 |
+
patched += 1
|
| 47 |
+
out.write(raw)
|
| 48 |
+
print(f"patched {patched} weights -> {out_path}")
|
merge_loras.py
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Combine two LoRAs that patch the same layers into ONE LoRA, exactly.
|
| 2 |
+
|
| 3 |
+
A LoRA stores a weight change as two thin matrices: delta_W = B @ A.
|
| 4 |
+
Loading two LoRAs adds their changes: W + B1@A1 + B2@A2.
|
| 5 |
+
Stacking the thin matrices side by side gives the same sum in one pair:
|
| 6 |
+
[B1 | B2] @ [A1 ; A2] = B1@A1 + B2@A2
|
| 7 |
+
So the combined file behaves identically to loading both at strength 1.0.
|
| 8 |
+
Rank is additive: 256 (Identity Edit) + 32 (er1cshen) = 288.
|
| 9 |
+
"""
|
| 10 |
+
import sys
|
| 11 |
+
import torch
|
| 12 |
+
from safetensors.torch import load_file, save_file
|
| 13 |
+
|
| 14 |
+
edit_path, char_path, out_path = sys.argv[1:4]
|
| 15 |
+
a, b = load_file(edit_path), load_file(char_path)
|
| 16 |
+
assert a.keys() == b.keys(), "the two LoRAs must patch the same layers"
|
| 17 |
+
|
| 18 |
+
out = {}
|
| 19 |
+
for k in a:
|
| 20 |
+
x, y = a[k].to(torch.bfloat16), b[k].to(torch.bfloat16)
|
| 21 |
+
if k.endswith("lora_A.weight"): # [rank, in] -> stack rows
|
| 22 |
+
out[k] = torch.cat([x, y], dim=0)
|
| 23 |
+
elif k.endswith("lora_B.weight"): # [out, rank] -> stack columns
|
| 24 |
+
out[k] = torch.cat([x, y], dim=1)
|
| 25 |
+
else:
|
| 26 |
+
raise ValueError(f"unexpected key {k}")
|
| 27 |
+
|
| 28 |
+
save_file(out, out_path, metadata={
|
| 29 |
+
"name": "Krea 2 Eric Insert",
|
| 30 |
+
"ss_base_model_version": "krea2",
|
| 31 |
+
"merged_from": "krea2_identity_edit_v1_2 (conradlocke) + krea2_er1cshen_v2_2000",
|
| 32 |
+
"method": "exact rank concatenation, rank 256 + 32 = 288, strength 1.0 each",
|
| 33 |
+
})
|
| 34 |
+
print(f"wrote {out_path}: {len(out)} tensors")
|