jennyxue commited on
Commit
c3a76ee
·
verified ·
1 Parent(s): a943bb5

Model card and the original license

Browse files
Files changed (1) hide show
  1. README.md +109 -0
README.md ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ base_model: hustvl/Moebius
3
+ base_model_relation: quantized
4
+ license: mit
5
+ pipeline_tag: image-to-image
6
+ library_name: onnx
7
+ tags:
8
+ - onnx
9
+ - moonbox
10
+ - moebius
11
+ - inpainting
12
+ - object-removal
13
+ - image-to-image
14
+ - diffusion
15
+ ---
16
+
17
+ # Moebius ONNX
18
+
19
+ ONNX builds of [Moebius](https://huggingface.co/hustvl/Moebius), made by Moonbox for on-device use with ONNX Runtime (CUDA, DirectML, CPU).
20
+ Each precision is a folder with one graph per part of the pipeline; large weights sit next to each graph as ONNX
21
+ external data (`*.onnx.data`), so keep a folder's files together.
22
+
23
+ ## Files
24
+
25
+ The last column is how far each graph's output is from the original PyTorch model run in fp32 on the same inputs
26
+ (relative RMS error). fp32 is the yardstick because the original's own bf16 run is not exact either. Image-quality
27
+ scores are added as each precision passes the image eval.
28
+
29
+ | Precision | File | Size | sha256 | Checked against fp32 |
30
+ |---|---|---|---|---|
31
+ | fp16 | [`fp16/unet/model.onnx`](https://huggingface.co/moonbox-dev/Moebius-ONNX/blob/main/fp16/unet/model.onnx) | 0.91 GB | `3ab9796281da` | fp32 graph (fp16 compute: 10 % off) |
32
+ | fp16 | [`fp16/vae_decoder/model.onnx`](https://huggingface.co/moonbox-dev/Moebius-ONNX/blob/main/fp16/vae_decoder/model.onnx) | 0.10 GB | `2818a7cbd433` | 1.9e-04 |
33
+ | fp16 | [`fp16/vae_encoder/model.onnx`](https://huggingface.co/moonbox-dev/Moebius-ONNX/blob/main/fp16/vae_encoder/model.onnx) | 0.07 GB | `8e37212ea885` | 6.3e-05 |
34
+
35
+ ## How to run
36
+
37
+ Moebius (0.22 B) is an image-inpainting / object-removal model: give it a picture and a mask (white = remove /
38
+ repaint) and it fills the masked region from the surroundings. No text prompt. These folders hold its three graphs
39
+ at 512 px (the short side the original pipeline uses): `vae_encoder`, `unet` (with classifier-free guidance and the
40
+ learned prompt embeddings inside) and `vae_decoder`. The VAE is PixelHacker's (the SDXL VAE, scaling 0.13025); it
41
+ stays fp32 where fp16 overflows (see the table).
42
+
43
+ **Run it** (ONNX Runtime + diffusers' DDIM scheduler; the original's defaults: 20 steps at strength 0.99, CFG 2.5,
44
+ noise offset 0.0357, result pasted back under a blurred mask):
45
+
46
+ ```python
47
+ import numpy as np, onnxruntime as ort, torch
48
+ from diffusers import DDIMScheduler
49
+ from PIL import Image, ImageFilter
50
+
51
+ d, prov = "int8", ["CUDAExecutionProvider", "CPUExecutionProvider"]
52
+ enc, unet, dec = (ort.InferenceSession(f"{d}/{p}/model.onnx", providers=prov) for p in ("vae_encoder", "unet", "vae_decoder"))
53
+ img = Image.open("photo.jpg").convert("RGB").resize((512, 512), Image.LANCZOS) # graphs are 512 x 512
54
+ mask = Image.open("mask.png").convert("L").resize((512, 512), Image.NEAREST)
55
+ x = np.asarray(img, np.float32).transpose(2, 0, 1)[None] / 127.5 - 1
56
+ m = (np.asarray(mask, np.float32)[None, None] / 255 >= 0.5).astype(np.float32)
57
+ lat, mlat = enc.run(None, {"image": x})[0], enc.run(None, {"image": x * (1 - m)})[0]
58
+ m64 = m[:, :, ::8, ::8].copy()
59
+ s = DDIMScheduler(beta_start=0.00085, beta_end=0.012, beta_schedule="scaled_linear", clip_sample=False)
60
+ s.set_timesteps(20); ts = s.timesteps[1:] # strength 0.99: 19 steps
61
+ g = torch.Generator().manual_seed(0)
62
+ noise = torch.randn(lat.shape, generator=g) + 0.0357 * torch.randn((1, 4, 1, 1), generator=g)
63
+ z = s.add_noise(torch.from_numpy(lat), noise, ts[:1])
64
+ for t in ts:
65
+ eps = unet.run(None, {"latent": z.numpy(), "mask": m64, "masked_latent": mlat,
66
+ "timestep": np.array([float(t)], np.float32), "guidance": np.array([2.5], np.float32)})[0]
67
+ z = s.step(torch.from_numpy(eps), t, z).prev_sample
68
+ y = dec.run(None, {"latent": (z.numpy() / 0.13025).astype(np.float32)})[0][0]
69
+ out = Image.fromarray((np.clip((y.transpose(1, 2, 0) + 1) / 2, 0, 1) * 255).astype(np.uint8))
70
+ blur = np.asarray(mask.convert("RGB").filter(ImageFilter.GaussianBlur(3)), np.float32) / 255
71
+ Image.fromarray((np.asarray(out) * blur + np.asarray(img) * (1 - blur)).astype(np.uint8)).save("filled.png")
72
+ ```
73
+
74
+ **Precisions.** fp16: every graph in fp16 where it stays within 5 % of fp32 on a test input, otherwise fp32 (the
75
+ table says which). int8: the UNet's weights int8 per output channel (weight-only), VAE graphs as in fp16. int4: the
76
+ UNet's MatMul weights 4-bit (MatMulNBits, block 32) and its other weights int8, VAE graphs as in fp16. No bf16 (no
77
+ bf16 convolution in ONNX Runtime's CUDA provider).
78
+
79
+ **Benchmark.** BSD100's 100 photos with seeded free-form masks (10-26 % of the picture), the pipeline above on an RTX
80
+ 3080 Laptop GPU with ONNX Runtime 1.30: PSNR / SSIM / LPIPS against the original photo and PSNR against the fp32
81
+ pipeline's result (same seed). Inpainting has no single right answer, so the ground-truth numbers are for comparing
82
+ precisions, not a quality score.
83
+
84
+ | Pipeline | Size | vs fp32 (PSNR, same seed) | PSNR / SSIM / LPIPS vs original | Time / picture | Peak VRAM |
85
+ |---|---|---|---|---|---|
86
+ | fp32 (reference, not published) | 1.24 GB | - | 26.35 / 0.906 / 0.067 | 3.8 s | 7.8 GB |
87
+ | fp16 (UNet fp32) | 1.07 GB | 46.5 dB (worst 35.6) | 26.35 / 0.906 / 0.067 | 3.6 s | 5.9 GB |
88
+ | int8 | 0.44 GB | 40.3 dB (worst 32.5) | 26.38 / 0.906 / 0.066 | 3.9 s | 5.9 GB |
89
+
90
+ ## How these were made
91
+
92
+ From [Moebius](https://huggingface.co/hustvl/Moebius) at revision `cd01f47fb6`: each part exported with `torch.onnx`, then converted or quantized
93
+ with ONNX Runtime's tools (fp16 / bf16 casts, int8 and int4 weight quantization). Every graph was checked against
94
+ the original before upload; the `sha256` column above is what the files must hash to.
95
+
96
+ ## License
97
+
98
+ MIT (weights; the GitHub code is Apache-2.0). These files are a derivative of the original model and carry its license: it is copied in this
99
+ repository, and it governs your use of these files. The original model card follows unchanged.
100
+
101
+ ---
102
+
103
+ # Original model card
104
+
105
+ 《Moebius: 0.2B Lightweight Image Inpainting Framework with 10B-Level Performance》
106
+ Project Page: https://hustvl.github.io/Moebius
107
+ Paper: https://arxiv.org/abs/2606.19195
108
+ Code: https://github.com/hustvl/Moebius
109
+ weight: https://huggingface.co/hustvl/Moebius/tree/main