WaveCut/Image21-Turbo-OrbitQuant-W4A4
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
Install and run
pip install -r https://huggingface.co/WaveCut/Image21-Turbo-OrbitQuant-W4A4/resolve/main/runtime-requirements.txt
orbitquant kernels-installimport 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.
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.outof 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):
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.
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
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 fromWaveCut/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.
