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
Download quantize_moss.py from SumomoLee/MOSS-Image-Base-ConvRot-ComfyUI: direct link, hf CLI and curl.
- Browser
- Download file 5.03 kB
-
https://huggingface.co/SumomoLee/MOSS-Image-Base-ConvRot-ComfyUI/resolve/main/quantize_moss.py
- Command line
-
hf download hf://SumomoLee/MOSS-Image-Base-ConvRot-ComfyUI/quantize_moss.py
-
curl -L -o quantize_moss.py https://huggingface.co/SumomoLee/MOSS-Image-Base-ConvRot-ComfyUI/resolve/main/quantize_moss.py
5.03 kB
| """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() | |