Video-to-Video
Diffusers
English
Chinese
video-editing
streaming
quantization
int8
text-stream-stripping
Instructions to use kylinfires/Joy-face_change_optimized with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Diffusers
How to use kylinfires/Joy-face_change_optimized with Diffusers:
pip install -U diffusers transformers accelerate
import torch from diffusers import DiffusionPipeline # switch to "mps" for apple devices pipe = DiffusionPipeline.from_pretrained("kylinfires/Joy-face_change_optimized", dtype=torch.bfloat16, device_map="cuda") prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k" image = pipe(prompt).images[0] - Notebooks
- Google Colab
- Kaggle
Download tools/quantization/quantize_int4.py from kylinfires/Joy-face_change_optimized: direct link, hf CLI and curl.
- Browser
- Download file 5.15 kB
-
https://huggingface.co/kylinfires/Joy-face_change_optimized/resolve/main/tools/quantization/quantize_int4.py
- Command line
-
hf download hf://kylinfires/Joy-face_change_optimized/tools/quantization/quantize_int4.py
-
curl -L -o quantize_int4.py https://huggingface.co/kylinfires/Joy-face_change_optimized/resolve/main/tools/quantization/quantize_int4.py
5.15 kB
| #!/usr/bin/env python3 | |
| """Group-wise symmetric int4 quantization of the JoyAI-Video-Edit DiT. | |
| Reads the official diffusers shards, renames `double_blocks.N.attn.X` -> | |
| `double_blocks.N.X` (the runtime's layout), quantizes every large 2D Linear | |
| weight to int4 (group_size=64) and writes packed weights + bf16 group scales. | |
| out/int4-0000X-of-00002.safetensors : packed uint8 [out, in/2] + scales | |
| out/meta.json : group size, key list, dtype map | |
| """ | |
| from __future__ import annotations | |
| import json | |
| import os | |
| import time | |
| from pathlib import Path | |
| import torch | |
| from safetensors import safe_open | |
| from safetensors.torch import save_file | |
| SRC = Path("/home/ubuntu/jve-diff") | |
| OUT = SRC / "int4" | |
| OUT.mkdir(exist_ok=True) | |
| GROUP = 64 | |
| MIN_NUMEL = 8_000_000 # quantize the big Linears only | |
| def map_key(k: str) -> str: | |
| if k.startswith("double_blocks."): | |
| parts = k.split(".") | |
| if parts[2] == "attn": | |
| return ".".join(parts[:2] + parts[3:]) | |
| return k | |
| def quantize(w: torch.Tensor): | |
| """w: [out, in] -> (packed uint8 [out, in/2], scales bf16 [out, in/64])""" | |
| out_f, in_f = w.shape | |
| assert in_f % GROUP == 0 and in_f % 2 == 0, w.shape | |
| wr = w.float().reshape(out_f, in_f // GROUP, GROUP) | |
| scale = wr.abs().amax(dim=-1).clamp_min(1e-8) / 7.0 | |
| q = torch.round(wr / scale.unsqueeze(-1)).clamp_(-8, 7).to(torch.int8) | |
| q = q.reshape(out_f, in_f) + 8 # 0..15 | |
| q8 = q.to(torch.uint8) | |
| packed = (q8[:, 0::2] | (q8[:, 1::2] << 4)).contiguous() | |
| return packed, scale.to(torch.bfloat16).contiguous() | |
| def main() -> None: | |
| t0 = time.time() | |
| idx = json.load(open(SRC / "transformer_diffusion_pytorch_model.safetensors.index.json")) | |
| weight_map = idx["weight_map"] | |
| shards = sorted(set(weight_map.values())) | |
| print(f"{len(weight_map)} tensors in {len(shards)} shards", flush=True) | |
| # group keys by shard so we stream one shard at a time (RAM stays ~5 GB) | |
| per_shard: dict[str, list[str]] = {} | |
| for k, s in weight_map.items(): | |
| per_shard.setdefault(s, []).append(k) | |
| packed_t: dict[str, torch.Tensor] = {} | |
| meta: dict[str, dict] = {} | |
| stats = [] | |
| for si, shard in enumerate(shards, 1): | |
| path = SRC / "transformer" / shard | |
| with safe_open(str(path), framework="pt", device="cpu") as f: | |
| for k in per_shard[shard]: | |
| t = f.get_tensor(k).to(torch.bfloat16) | |
| nk = map_key(k) | |
| if t.dim() == 2 and t.numel() >= MIN_NUMEL: | |
| packed, scales = quantize(t) | |
| packed_t[nk + ".qweight"] = packed | |
| packed_t[nk + ".scales"] = scales | |
| # reconstruction error | |
| deq = (packed & 0x0F).to(torch.float32) - 8 | |
| deq2 = (packed >> 4).to(torch.float32) - 8 | |
| w_deq = torch.empty(t.shape, dtype=torch.float32) | |
| w_deq[:, 0::2] = deq | |
| w_deq[:, 1::2] = deq2 | |
| w_deq = (w_deq.reshape(t.shape[0], -1, GROUP) * | |
| scales.float().unsqueeze(-1)).reshape(t.shape) | |
| tf = t.float() | |
| mse = (tf - w_deq).pow(2).mean().item() | |
| var = tf.pow(2).mean().item() | |
| cos = torch.nn.functional.cosine_similarity( | |
| tf.flatten(), w_deq.flatten(), dim=0).item() | |
| stats.append((nk, mse / max(var, 1e-12), cos, t.numel())) | |
| meta[nk] = {"group": GROUP, "shape": list(t.shape), | |
| "dtype": "int4", "rel_mse": mse / max(var, 1e-12)} | |
| else: | |
| packed_t[nk] = t.contiguous() | |
| meta[nk] = {"dtype": "bf16", "shape": list(t.shape)} | |
| print(f" shard {si}/{len(shards)} done tensors={len(packed_t)} " | |
| f"{time.time() - t0:.0f}s", flush=True) | |
| # split the output into two files to keep each under ~5 GB | |
| keys = sorted(packed_t) | |
| half = len(keys) // 2 | |
| parts = [keys[:half], keys[half:]] | |
| for pi, ks in enumerate(parts, 1): | |
| save_file({k: packed_t[k] for k in ks}, | |
| str(OUT / f"int4-{pi:05d}-of-{len(parts):05d}.safetensors")) | |
| print(f"wrote part {pi} ({len(ks)} tensors)", flush=True) | |
| json.dump({"group_size": GROUP, "tensors": meta}, | |
| open(OUT / "meta.json", "w"), indent=1) | |
| n_q = len(stats) | |
| params_q = sum(s[3] for s in stats) | |
| rel = sorted(s[1] for s in stats) | |
| cosl = sorted(s[2] for s in stats) | |
| print(f"\nquantized {n_q} tensors, {params_q/1e9:.2f} B params") | |
| print(f"rel_mse mean={sum(rel)/len(rel):.5f} p50={rel[len(rel)//2]:.5f} max={rel[-1]:.5f}") | |
| print(f"cosine mean={sum(cosl)/len(cosl):.6f} min={cosl[0]:.6f}") | |
| worst = sorted(stats, key=lambda s: -s[1])[:3] | |
| for nk, m, c, n in worst: | |
| print(f" worst {nk:<48} rel_mse={m:.5f} cos={c:.5f}") | |
| tot = sum(p.numel() * p.element_size() for p in packed_t.values()) | |
| print(f"output size {tot/2**30:.2f} GiB") | |
| print(f"done in {time.time() - t0:.0f}s") | |
| if __name__ == "__main__": | |
| main() | |