matlod commited on
Commit
ae0c487
·
verified ·
1 Parent(s): a871c04

Add nynxz Destripe and DeBand Strong to edit anatomy

Browse files
Files changed (1) hide show
  1. research/edit_anatomy_lora.py +59 -0
research/edit_anatomy_lora.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Add any MOSS-Image LoRA as an arm of output/moss/edit_anatomy.json (after edit_anatomy.py and edit_anatomy_c.py).
3
+
4
+ comfyui_venv/bin/python workflows/moss/edit_anatomy_lora.py <tag> <file in models/loras>
5
+ Reads lora_up/lora_down(/alpha) or .diff keys; split q/k/v LoRA keys are placed into the fused qkv rows (q, k, v blocks of
6
+ 3072 rows each), as ComfyUI does when it applies them. Per matrix the weight change at strength 1 gets w2 = |D|^2, dot = <D, Delta>,
7
+ and for layers 21-41 ef/eg (raw flat/gen Grams) and efc/egc (row-centred flatc/genc Grams); untouched matrices get no entry.
8
+ """
9
+ import json, os, sys
10
+ import torch
11
+ from safetensors import safe_open
12
+
13
+ ROOT = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "..")
14
+ PATH = os.path.join(ROOT, "output", "moss", "edit_anatomy.json")
15
+ tag, lora = sys.argv[1], sys.argv[2]
16
+ torch.set_num_threads(16)
17
+
18
+ h = safe_open(os.path.join(ROOT, "models", "loras", lora), "pt")
19
+ keys = set(h.keys())
20
+ sft = safe_open(os.path.join(ROOT, "models/diffusion_models/moss_image_sft_bf16.safetensors"), "pt")
21
+ base = safe_open(os.path.join(ROOT, "models/diffusion_models/moss_image_base_bf16.safetensors"), "pt")
22
+ grams = {n: safe_open(os.path.join(ROOT, "output/moss/grams", n + ".safetensors"), "pt") for n in ("flat", "gen", "flatc", "genc")}
23
+
24
+
25
+ def piece(name):
26
+ """Weight change of one LoRA target (e.g. layers.33.proj.k) at strength 1, or None."""
27
+ k = f"diffusion_model.{name}"
28
+ if k + ".diff" in keys:
29
+ return h.get_tensor(k + ".diff").float()
30
+ if k + ".lora_up.weight" not in keys:
31
+ return None
32
+ up, down = h.get_tensor(k + ".lora_up.weight").float(), h.get_tensor(k + ".lora_down.weight").float()
33
+ alpha = float(h.get_tensor(k + ".alpha")) if k + ".alpha" in keys else up.shape[1]
34
+ return (up @ down) * (alpha / up.shape[1])
35
+
36
+
37
+ rows = json.load(open(PATH))
38
+ n = 0
39
+ for row in rows:
40
+ k = f"layers.{row['layer']}.proj.{row['proj']}"
41
+ D = piece(k)
42
+ if row["proj"] == "qkv" and D is None:
43
+ parts = [piece(f"layers.{row['layer']}.proj.{p}") for p in ("q", "k", "v")]
44
+ if any(p is not None for p in parts):
45
+ D = torch.cat([p if p is not None else torch.zeros(3072, 3072) for p in parts])
46
+ if D is None:
47
+ row.pop(tag, None)
48
+ continue
49
+ delta = base.get_tensor(k + ".weight").float() - sft.get_tensor(k + ".weight").float()
50
+ e = {"w2": float(D.pow(2).sum()), "dot": float((D * delta).sum())}
51
+ if 21 <= row["layer"] <= 41:
52
+ DtD = D.T @ D
53
+ for g, key in (("flat", "ef"), ("gen", "eg"), ("flatc", "efc"), ("genc", "egc")):
54
+ e[key] = float((DtD * grams[g].get_tensor(k + ".G").float()).sum())
55
+ row[tag] = e
56
+ n += 1
57
+ print(k, {x: round(v, 4) for x, v in e.items()}, flush=True)
58
+ json.dump(rows, open(PATH, "w"))
59
+ print(f"{tag}: {n} matrices added to {PATH}")