xocialize's picture
Moebius Places2 fp16 (UNet + SDXL KL-f8 VAE) β€” MLX conversion, layout-preserving; fp16 chosen by measured parity
8cef318 verified
|
Raw
History Blame Contribute Delete
3.6 kB
---
library_name: mlx
license: mit
pipeline_tag: image-to-image
base_model: hustvl/Moebius
tags:
- mlx
- inpainting
- image-inpainting
- object-removal
- diffusion
---
# mlx-community/Moebius-Places2-fp16
MLX conversion of [hustvl/Moebius](https://huggingface.co/hustvl/Moebius) (the **Places2**
fine-tune) β€” a 0.22B-parameter latent-diffusion **image inpainting / object removal** model
(["Moebius: 0.2B Lightweight Image Inpainting Framework with 10B-Level Performance"](https://arxiv.org/abs/2606.19195)),
distilled from PixelHacker. Reference code: [hustvl/Moebius](https://github.com/hustvl/Moebius)
(Apache-2.0).
The repo is consolidated: `unet.safetensors` (the LambdaNetworks-based denoiser, fp16, 453 MB)
plus `vae.safetensors` (the SDXL-family KL-f8 `AutoencoderKL` from
[hustvl/PixelHacker](https://huggingface.co/hustvl/PixelHacker), `scaling_factor 0.13025`, fp16,
167 MB). The VAE conversion is **lossless** β€” upstream ships it fp16 (round-trip worst |Ξ”| = 0).
## Conversion notes
- Tensors are stored in **PyTorch's own layouts** (OIHW conv weights, original key names, no
remapping); consumers perform their own layout transposes at load.
- The 124 `num_batches_tracked` BatchNorm counters are dropped (int64, never read at inference).
- BatchNorm `running_mean` / `running_var` stay **fp32** inside the fp16 file β€” a small variance
that rounds toward zero at fp16 would make `rsqrt` explode.
- **fp16 was chosen by measurement, not default**: per-forward error vs the fp32 reference is
rel 9.3e-04 (at the GPU fp32 noise floor), end-to-end trajectory cosine 0.99994, output visually
identical. **bf16 was rejected** (~9Γ— worse per forward β€” the 8-bit mantissa punishes these
well-scaled conv weights).
## Usage notes (things that will silently produce wrong output)
- **512Γ—512 only.** `rel_pos_emb` is spatially baked at construction (64Γ—64 latent) and the
attention wrapper assumes a square grid β€” other resolutions are structurally invalid, not merely
off-distribution. Resize in, paste the fill back at the original resolution through a blurred
mask.
- **Mask convention: white = remove** (luma β‰₯ 0.5), binarized.
- Denoiser input is **9 channels: noisy(4) + mask(1) + masked-image(4)** β€” the mask is the
*middle* channel group.
- Conditioning is a learned 20Γ—3072 category table (no text encoder): rows 0–9 = conditional,
rows 10–19 = unconditional, CFG batch-doubled `[uncond, cond]` through one forward
(reference CFG scale 2.5).
- Sampler: **DDIM**, `beta_start 0.00085 / beta_end 0.012 / scaled_linear / 1000` train steps,
`clip_sample false`, `eta 0`. Reference runs `num_steps 20` at `strength 0.99` β‡’ **19 real
steps starting at t=900**, initialized from the *clean* image latents noised at `timesteps[0]`
(not pure noise), with `noise_offset 0.0357` per-channel offset noise.
## Swift / MLX runtime
This checkpoint is consumed by [`xocialize/mlx-moebius-swift`](https://github.com/xocialize/mlx-moebius-swift)
(MLX-Swift port, parity-locked component-by-component against the PyTorch reference: full-UNet
forward rel 1.1e-06 fp32 CPU vs oracle; full 19-step pipeline matches the reference's decoded
image at the VAE's measured fp32 floor; ~4 s per 512Β² inpaint on an M-series GPU in release).
## Licenses
- Weights: **MIT** (per the upstream [hustvl/Moebius](https://huggingface.co/hustvl/Moebius) model
card). VAE: MIT (hustvl/PixelHacker repo; SDXL KL-f8 family).
- Reference code: Apache-2.0 (github.com/hustvl/Moebius).
- Fine-tune training data is Places2; see upstream for dataset terms.