CoolFace
Modelpublic

WaveCut/Image21-Turbo-OrbitQuant-W4A4

sourceHugging Faceotherupdated 2h agoView on Hugging Face
0likes
Model Card

Image21 Turbo OrbitQuant W4A4

OrbitQuant build of WaveCut/Image21-Turbo: Qwen-Image-2.1 with the Viggle turbo v0.2.1 LoRA merged and the Texture-Fix VAE. The diffusion transformer is W4A4, the Qwen3-VL-8B text encoder is W6A6; the few projections that create or cancel massive activations stay in fp16 in both. Text-to-image and editing in 6 steps without guidance, with every component resident in 13.6 GB. Built with Qwen.

<a href="https://huggingface.co/WaveCut/Image21-Turbo-OrbitQuant-W4A4/resolve/main/assets/originalvsorbitquantw4a4.webp"><img src="https://huggingface.co/WaveCut/Image21-Turbo-OrbitQuant-W4A4/resolve/main/assets/originalvsorbitquantw4a4_preview.webp" alt="Image21 Turbo fp16 versus OrbitQuant on twelve paired prompts" width="100%"></a>

The preview links to the lossless 4096×6576 matrix: twelve pairs at the native 1024×1024, same prompt, seed and settings in each pair, tiles concatenated without resizing. The 24 PNGs are in `artifacts/generations/`.

At a glance

ItemValue
SourceWaveCut/Image21-Turbo (Qwen-Image-2.1 790c9263 + Viggle turbo v0.2.1 + Texture-Fix VAE)
Transformer214 linears OrbitQuant W4A4; fp16: img_in, txt_in, modulation.1, img_mlp.out of blocks 0, 4–11, 13, timestep embedder, norm_out, proj_out
Text encoder341 linears OrbitQuant W6A6 (language model, vision tower, lm_head); fp16: decoder layers 6, 16, 34, 35
QuantizationRP-BH rotation, Lloyd-Max codebooks, no calibration data, OrbitQuant 0.9.8
Sampling6 steps on the turbo sigmas, no CFG
Storagetransformer 4.52 GB (fp16 14.23 GB), text encoder 8.33 GB (bf16 17.5 GB), VAE 1.35 GB
BenchmarkRTX 5090 32 GB, torch 2.8.0+cu128, diffusers 0.41.0.dev0 80c7ed26, transformers 5.17.0

Install and run

bash
pip install -r https://huggingface.co/WaveCut/Image21-Turbo-OrbitQuant-W4A4/resolve/main/runtime-requirements.txt
orbitquant kernels-install
python
import torch
import orbitquant
from diffusers import QwenImage21Pipeline

pipe = QwenImage21Pipeline.from_pretrained("WaveCut/Image21-Turbo-OrbitQuant-W4A4", dtype=torch.float16).to("cuda")

SIGMAS = [1.0, 0.9375, 0.875, 0.75, 0.5, 0.25]
image = pipe(
    prompt="A rain-soaked Warsaw street seen through a tram window",
    width=1024, height=1024,
    num_inference_steps=6, sigmas=SIGMAS,
    generator=torch.Generator("cuda").manual_seed(0),
).images[0]

edited = pipe(
    prompt="Turn <image1> into a snowy winter night; keep the composition unchanged.",
    image=[image], output_resolution=1024,
    num_inference_steps=6, sigmas=SIGMAS,
    generator=torch.Generator("cuda").manual_seed(0),
).images[0]

import orbitquant registers the loaders; kernels-install fetches the native kernel wheel for the running torch/CUDA ABI (--build compiles it when no prebuilt variant matches). Keep the VAE untiled in fp16: tiled fp16 decoding produces non-finite pixels; for 2048² text-to-image use pipe.vae.to(torch.bfloat16); pipe.vae.enable_tiling(). `scripts/run_inference.py` wraps the same calls with the turbo schedules.

Latency and VRAM

RTX 5090, fp16 compute, 6 steps, 10 prompts, median of two hot sweeps after a cold one. The fp16 source does not fit 32 GB with all components resident, so both builds are also measured staged: text encoder on the GPU for encoding, then transformer and VAE.

MetricImage21 Turbo fp16OrbitQuantChange
1024², staged, hot end-to-end2.685 s2.122 s−21 %
1024², transformer 6 steps2.426 s1.816 s−25 %
1024², prompt encode0.035 s0.077 s+0.04 s
1024², VAE decode0.224 s0.229 s
1024², all resident, hot end-to-enddoes not fit2.248 s
2048², hot end-to-end (tiled VAE)17.88 s staged13.95 s resident−22 %
Peak VRAM, encode stage17.53 GB8.96 GB−49 %
Peak VRAM, transformer + VAE stage, 1024²22.45 GB13.40 GB−40 %
Peak VRAM, all resident, 1024² / 2048²—21.15 / 16.44 GB
Load from page cache to GPU8.4 s3.3 s−61 %
Learned-weight storage33.1 GB14.2 GB−57 %

VRAM is nvidia-smi (NVML) and includes the CUDA context. Raw records are in `benchmark/`.

What 4-bit breaks here and what stays in fp16

Both Qwen stacks carry massive activations — single channels of a few special tokens that grow to thousands. A module that writes or cancels such a value turns a routine 2–5 % quantization error into an error of the same order as the signal that survives:

  • —Text encoder. Layer 16's MLP writes ≈9000 into channel 2276 of the user-turn <|im_start|> token, layers 34–35 cancel it to a few hundred, and the pipeline reads exactly that pre-norm last hidden state. Layer 6 writes ≈13000 into the same channel of the system-turn <|im_start|> token. With W4A4 everywhere the embeddings drop to cosine 0.86 (token 0: 0.36) and the images change composition.
  • —Transformer. Text tokens carry values up to ≈9000 written by img_mlp.out of blocks 0, 4–11 and 13; the text stream feeds every image token through attention and the prefix KV cache.

The fix keeps those projections in fp16 and runs the rest of the text encoder at W6A6. Isolation on seven prompts (PSNR / SSIM against the fp16 pipeline; the fp16 pipeline with a bf16 text encoder scores 30.8 / 0.968):

Text encoderTransformerPSNRSSIMEncoder + transformer
W4A4W4A414.49 dB0.61010.0 GB
fp16W4A417.31 dB0.707
fp16W4A4 + fp16 massive-activation writers19.11 dB0.763
W4A4fp1615.27 dB0.640
W6A6 + fp16 layers 6, 16, 34, 35fp1624.42 dB0.909
W6A6 + fp16 layers 6, 16, 34, 35W4A4 + fp16 massive-activation writers18.66 dB0.75712.85 GB

Every transformer row keeps img_in, txt_in and modulation.1 in fp16.

Keeping all 32 img_mlp.out projections in fp16 instead of the ten writers costs 1.7 GB more and scores lower (18.84 dB). Across the twelve pairs of the matrix the final build scores 19.73 dB PSNR / 0.777 SSIM.

Sampling recipes

Measured on the fp16 Image21 Turbo pipeline, which this build follows step for step.

RecipeSettingsResult
Default6 steps, sigmas=[1, 0.9375, 0.875, 0.75, 0.5, 0.25], shipped scheduler, no CFGSharpest detail; Latin and Cyrillic text mostly right
Text, posters, natural skinsame sigmas, pipe.scheduler = FlowMatchEulerDiscreteScheduler.from_config(pipe.scheduler.config, use_dynamic_shifting=False, shift=3.0)Cleanest lettering, smoother skin, same speed
Dense text8 steps, sigmas=[1, 0.9375, 0.875, 0.75, 0.625, 0.5, 0.25, 0.125]Same composition, small print slightly cleaner, +30 % time
Guidance6 steps, true_cfg_scale=2 with a negative promptMore contrast and saturation, 2× time
Avoid4 steps [1, 0.75, 0.5, 0.25]; static shift 5Ghosted double contours; soft, smeared detail

Editing: reference images are <image1>, <image2>, … in the prompt, in the order passed; references are encoded at output_resolution² area and the canvas follows the last reference unless width/height are given.

Comparison protocol

#PromptStress categorySeed
01studio-productproduct detail61000
02human-portraitportrait61001
03mucha-posterpublic-domain artist style61002
04hokusai-wavepublic-domain artist style61003
05bauhaus-risographpopular image style61004
06technical-cutawaytechnical diagram61005
07long-latin-textlong Latin text61006
08long-cyrillic-textlong Cyrillic text61007
09mixed-diagrammixed Latin/Cyrillic diagram61008
10wide-city-scenedense scene composition61009
11edit-backgroundedit of pair 02's fp16 output61010
12edit-winteredit of pair 10's fp16 output61011

1024×1024, 6 steps, turbo sigmas, no CFG. Both columns of an edit pair start from the same fp16 input. Prompts are in `benchmark/prompts.json`. It is a deployment check, not an FID, CLIP or preference benchmark.

Repository contents

  • —transformer/, text_encoder/ — OrbitQuant components; processor/, vae/, scheduler/, model_index.json — the rest of the diffusers pipeline.
  • —assets/ — lossless comparison matrix, preview and its manifest with SHA-256 of every tile.
  • —artifacts/generations/ — 12 fp16 and 12 OrbitQuant PNGs.
  • —benchmark/ — timings, memory, prompts, environment, pairwise PSNR/SSIM.
  • —scripts/run_inference.py — command-line runner; scripts/quantize.py — rebuilds both components from WaveCut/Image21-Turbo.
  • —quantization_manifest.json — every quantized and fp16 module with parameter counts.
  • —LICENSE, NOTICE — license, modified files, upstream notices.

Limitations

  • —W4A4 moves the 6-step trajectory: object placement, faces and small print can differ from the fp16 build at the same seed; long Cyrillic text and dense mixed-script diagrams degrade more than Latin text.
  • —The first call compiles Triton kernels for new shapes; measure hot latency after a warm-up.
  • —Numbers are for one RTX 5090; other GPUs, drivers and torch builds differ.
  • —Non-commercial: the Qwen RESEARCH LICENSE AGREEMENT applies to all weights.

License

Derivative of Qwen-Image-2.1 under the Qwen RESEARCH LICENSE AGREEMENT (LICENSE), research and evaluation only. NOTICE lists the modified files and the Viggle and madebyollin notices.

Qwen is licensed under the Qwen RESEARCH LICENSE AGREEMENT, Copyright (c) 2026 Hangzhou Tongyi Laboratory Technology Co., Ltd. All Rights Reserved.