Instructions to use SumomoLee/MOSS-Image-Base-ConvRot-ComfyUI with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusion Single File
How to use SumomoLee/MOSS-Image-Base-ConvRot-ComfyUI with Diffusion Single File:
# No code snippets available yet for this library. # To use this model, check the repository files and the library's documentation. # Want to help? PRs adding snippets are welcome at: # https://github.com/huggingface/huggingface.js
- Notebooks
- Google Colab
- Kaggle
File size: 5,031 Bytes
be0f394 16364ff be0f394 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | """Quantize MOSS-Image components into ComfyUI-native ConvRot formats (comfy-kitchen layouts).
dit int4 : convrot_w4a4 (group 256, kernel group 64), header _quantization_metadata (= toxicdog/MOSS-Image-SFT-INT4-ConvRot-ComfyUI)
dit int8 : int8_tensorwise + convrot (per-row scale), per-layer .comfy_quant tensors (= Abiray/MOSS-Image-SFT-INT8-convrot)
te int8 : same as Abiray text encoder (embed_tokens + LM linears except in_proj_a/b + vision block linears)
"""
import argparse, json, os, re, sys, time
import torch
from safetensors import safe_open
from safetensors.torch import save_file
from comfy_kitchen.tensor import TensorWiseINT8Layout, TensorCoreConvRotW4A4Layout
DIT_RE = re.compile(r"^layers\.\d+\.proj\.(q|k|v|o|ffn_up_gate|ffn_down)\.weight$")
TE_RE = re.compile(r"^(language_model\.embed_tokens|language_model\.layers\.\d+\.(linear_attn\.(in_proj_qkv|in_proj_z|out_proj)|mlp\.(gate|up|down)_proj|self_attn\.(q|k|v|o)_proj)|visual\.blocks\.\d+\.(attn\.(qkv|proj)|mlp\.linear_fc[12]))\.weight$")
def te_group(k):
for g in (256, 64, 16, 4):
if k % g == 0:
return g
return None
def load_index(d, index):
m = json.load(open(os.path.join(d, index)))["weight_map"]
by = {}
for k, f in m.items():
by.setdefault(f, []).append(k)
return by
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--component", choices=["dit", "te"], required=True)
ap.add_argument("--mode", choices=["int8", "int4"], required=True)
ap.add_argument("--src", required=True, help="MOSS-Image pipeline dir")
ap.add_argument("--out", required=True)
ap.add_argument("--device", default="cpu")
ap.add_argument("--threads", type=int, default=32)
a = ap.parse_args()
torch.set_num_threads(a.threads)
if os.path.exists(a.out):
sys.exit(f"exists: {a.out}")
sub, index = ("transformer", "diffusion_pytorch_model.safetensors.index.json") if a.component == "dit" else ("text_encoder", "model.safetensors.index.json")
d = os.path.join(a.src, sub)
rx = DIT_RE if a.component == "dit" else TE_RE
out, layers, stats = {}, {}, []
t0 = time.time()
for fn, keys in sorted(load_index(d, index).items()):
with safe_open(os.path.join(d, fn), "pt") as f:
for k in sorted(keys):
w = f.get_tensor(k)
if not rx.match(k):
out[k] = w.contiguous()
continue
name = k[: -len(".weight")]
wf = w.to(a.device, torch.float32)
if a.mode == "int4":
q, p = TensorCoreConvRotW4A4Layout.quantize(wf, convrot_groupsize=256)
deq = TensorCoreConvRotW4A4Layout.dequantize(q, p)
out[name + ".weight"] = q.cpu().contiguous()
out[name + ".weight_scale"] = p.scale.float().reshape(-1).cpu().contiguous()
layers[name] = {"format": "convrot_w4a4", "convrot_groupsize": 256, "quant_group_size": 64}
else:
g = 256 if a.component == "dit" else te_group(wf.shape[1])
q, p = TensorWiseINT8Layout.quantize(wf, is_weight=True, per_channel=True, convrot=True, convrot_groupsize=g)
deq = TensorWiseINT8Layout.dequantize(q, p)
out[name + ".weight"] = q.cpu().contiguous()
out[name + ".weight_scale"] = p.scale.float().reshape(-1, 1).cpu().contiguous()
conf = {"format": "int8_tensorwise", "convrot": True, "convrot_groupsize": g}
out[name + ".comfy_quant"] = torch.frombuffer(bytearray(json.dumps(conf).encode()), dtype=torch.uint8).clone()
layers[name] = conf
deq = deq.float()
rel = ((deq - wf).norm() / wf.norm()).item()
cos = torch.nn.functional.cosine_similarity(deq.flatten(), wf.flatten(), dim=0).item()
stats.append((name, list(wf.shape), rel, cos))
print(f"{name} {list(wf.shape)} rel={rel:.5f} cos={cos:.6f}", flush=True)
if a.component == "te":
# HF / ComfyUI-core naming (model.language_model.*, model.visual.*); also accepted by the MOSS-Image plugin
out = {("model." + k if k.startswith(("language_model.", "visual.")) else k): v for k, v in out.items()}
meta = {"format": "pt", "model": "moss-image"}
if a.mode == "int4":
meta["_quantization_metadata"] = json.dumps({"format_version": "1.0", "layers": layers})
tmp = a.out + ".partial"
os.makedirs(os.path.dirname(os.path.abspath(a.out)), exist_ok=True)
save_file(out, tmp, metadata=meta)
os.rename(tmp, a.out)
json.dump(stats, open(a.out + ".stats.json", "w"))
rels = [s[2] for s in stats]
print(f"DONE {a.out} layers={len(stats)} tensors={len(out)} mean_rel={sum(rels)/len(rels):.5f} max_rel={max(rels):.5f} min_cos={min(s[3] for s in stats):.6f} size={os.path.getsize(a.out)} t={time.time()-t0:.0f}s")
if __name__ == "__main__":
main()
|