John2386 commited on
Commit
3a87e83
·
verified ·
1 Parent(s): 038f813

tools: merge script for rebuilding transformer from fullgreed_bf16

Browse files
Files changed (1) hide show
  1. tools/fullgreed_edit_merge_bf16.py +122 -0
tools/fullgreed_edit_merge_bf16.py ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Rebuild Fullgreed-Edit from fullgreed_bf16 (uploaded 2026-07-10).
2
+
3
+ merged = Z-Image-Edit (Anjoe/z-image-edit, fp32) + (fullgreed_bf16 - Z-Image base bf16)
4
+
5
+ Key mapping comfy(453) -> diffusers-edit(521): unfuse attention.qkv -> to_q/to_k/to_v
6
+ (order q,k,v), out -> to_out.0, q_norm/k_norm -> norm_q/norm_k,
7
+ final_layer.* -> all_final_layer.2-1.*, x_embedder -> all_x_embedder.2-1 with the
8
+ delta applied to cols 0-63 only (cols 64-127 = ref-latent branch, kept from Edit).
9
+ Output bf16, streamed to disk so peak RAM stays ~1 GB. Verifies 5 random tensors
10
+ by recompute, then uploads to John2386/fullgreed-edit/transformer/.
11
+
12
+ Run on a Colab CPU runtime. Needs HF_TOKEN in the environment (from Colab Secrets).
13
+ """
14
+ import hashlib, json, os, random, struct
15
+ import torch
16
+ from huggingface_hub import hf_hub_download, HfApi
17
+ from safetensors import safe_open
18
+
19
+ DIM = 3840
20
+ OUT = "/content/diffusion_pytorch_model.safetensors"
21
+ REPO_OUT = "John2386/fullgreed-edit"
22
+ PATH_IN_REPO = "transformer/diffusion_pytorch_model.safetensors"
23
+ TOKEN = os.environ["HF_TOKEN"] # fail fast if missing
24
+
25
+
26
+ def edit_to_comfy(k):
27
+ if k == "all_x_embedder.2-1.weight":
28
+ return "x_embedder.weight", ("padcols", 128)
29
+ if k == "all_x_embedder.2-1.bias":
30
+ return "x_embedder.bias", None
31
+ if k.startswith("all_final_layer.2-1."):
32
+ return "final_layer." + k[len("all_final_layer.2-1."):], None
33
+ if ".attention.norm_q." in k:
34
+ return k.replace(".attention.norm_q.", ".attention.q_norm."), None
35
+ if ".attention.norm_k." in k:
36
+ return k.replace(".attention.norm_k.", ".attention.k_norm."), None
37
+ if ".attention.to_out.0." in k:
38
+ return k.replace(".attention.to_out.0.", ".attention.out."), None
39
+ for i, proj in enumerate(("to_q", "to_k", "to_v")):
40
+ tag = f".attention.{proj}.weight"
41
+ if k.endswith(tag):
42
+ return k[: -len(tag)] + ".attention.qkv.weight", ("rows", i * DIM, (i + 1) * DIM)
43
+ return k, None
44
+
45
+
46
+ def delta_for(fg, fb, key):
47
+ ck, spec = edit_to_comfy(key)
48
+ d = fg.get_tensor(ck).to(torch.float32) - fb.get_tensor(ck).to(torch.float32)
49
+ if spec is None:
50
+ return d
51
+ if spec[0] == "rows":
52
+ return d[spec[1]:spec[2]]
53
+ if spec[0] == "padcols":
54
+ return torch.nn.functional.pad(d, (0, spec[1] - d.shape[1]))
55
+ raise ValueError(spec)
56
+
57
+
58
+ def merged_tensor(fe, fg, fb, key):
59
+ return (fe.get_tensor(key).to(torch.float32) + delta_for(fg, fb, key)).to(torch.bfloat16)
60
+
61
+
62
+ print("downloading inputs...", flush=True)
63
+ EDIT = hf_hub_download("Anjoe/z-image-edit", "transformer/diffusion_pytorch_model.safetensors")
64
+ BASE = hf_hub_download("Comfy-Org/z_image", "split_files/diffusion_models/z_image_bf16.safetensors")
65
+ GREED = hf_hub_download("John2386/fullgreed", "fullgreed_bf16.safetensors")
66
+
67
+ fe = safe_open(EDIT, framework="pt")
68
+ fb = safe_open(BASE, framework="pt")
69
+ fg = safe_open(GREED, framework="pt")
70
+ keys = sorted(fe.keys())
71
+ assert len(keys) == 521, len(keys)
72
+
73
+ shapes = {k: list(fe.get_slice(k).get_shape()) for k in keys}
74
+ header, off = {"__metadata__": {"format": "pt",
75
+ "merge": "Anjoe/z-image-edit + (John2386/fullgreed fullgreed_bf16 - Comfy-Org/z_image bf16)",
76
+ "merge_scale": "1.0", "built": "2026-07-11"}}, 0
77
+ for k in keys:
78
+ n = 2 # bf16 bytes
79
+ for s in shapes[k]:
80
+ n *= s
81
+ header[k] = {"dtype": "BF16", "shape": shapes[k], "data_offsets": [off, off + n]}
82
+ off += n
83
+ hb = json.dumps(header, separators=(",", ":")).encode()
84
+
85
+ print(f"writing {off/1e9:.2f} GB to {OUT}", flush=True)
86
+ with open(OUT, "wb") as f:
87
+ f.write(struct.pack("<Q", len(hb)))
88
+ f.write(hb)
89
+ for i, k in enumerate(keys):
90
+ t = merged_tensor(fe, fg, fb, k)
91
+ assert list(t.shape) == shapes[k], k
92
+ f.write(t.contiguous().view(torch.uint8).numpy().tobytes())
93
+ if i % 50 == 0:
94
+ print(f" {i}/521 {k}", flush=True)
95
+
96
+ print("verifying...", flush=True)
97
+ fo = safe_open(OUT, framework="pt")
98
+ okeys = list(fo.keys())
99
+ assert len(okeys) == 521, len(okeys)
100
+ random.seed(0)
101
+ for k in random.sample(okeys, 5) + ["all_x_embedder.2-1.weight"]:
102
+ want = merged_tensor(fe, fg, fb, k)
103
+ got = fo.get_tensor(k)
104
+ assert torch.equal(want, got), k
105
+ print(f" ok {k} {list(got.shape)}", flush=True)
106
+ # ref-latent columns must be pure Edit weights (delta zero there)
107
+ xe = fo.get_tensor("all_x_embedder.2-1.weight")
108
+ assert torch.equal(xe[:, 64:], fe.get_tensor("all_x_embedder.2-1.weight").to(torch.bfloat16)[:, 64:])
109
+ print(" ok ref-latent cols untouched", flush=True)
110
+
111
+ sha = hashlib.sha256()
112
+ with open(OUT, "rb") as f:
113
+ for chunk in iter(lambda: f.read(1 << 24), b""):
114
+ sha.update(chunk)
115
+ print("sha256:", sha.hexdigest())
116
+ print("size:", os.path.getsize(OUT))
117
+
118
+ print("uploading...", flush=True)
119
+ api = HfApi(token=TOKEN)
120
+ api.upload_file(path_or_fileobj=OUT, path_in_repo=PATH_IN_REPO, repo_id=REPO_OUT,
121
+ commit_message="transformer: rebuild edit merge from fullgreed_bf16 (2026-07-10 weights)")
122
+ print("DONE — uploaded to", REPO_OUT + "/" + PATH_IN_REPO)