Qwen-Image-2.1 DiT โ NVFP4 (ComfyUI)
โ ๏ธ ComfyUI format only. These files use ComfyUI's native quantized-checkpoint layout (
comfy_quanttensors +_quantization_metadata). They will not load indiffusers, and they need a ComfyUI build withQwenImage21support (merged after 2026-09-14). If you want the model fordiffusers, use the official bf16 release.
Not affiliated with, or endorsed by, Alibaba / Qwen. Community derivative of
Qwen/Qwen-Image-2.1, redistributed under the Qwen Research License (copy included asLICENSE, per ยง3.a). Non-commercial use only (ยง1.i / ยง2.a); commercial use needs a separate licence from Qwen (model-business@notice.qwencloud.com, ยง2.b).
NVFP4 quantizations of the diffusion transformer. Comfy-Org ships bf16 and
int8_convrot; there is no official NVFP4 build, so these are new.
Showcase
Every image below was generated with these NVFP4 files (the default qwen_image_2.1_nvfp4.safetensors) driven by the PE-T2I rewriter โ each from a single short prompt plus a photographic style, through a small ComfyUI node: ComfyUI-QwenImage-PhotoStyles. Curious how it's put together? The node and its full recipe are in that repo.
![]() Black Fury |
![]() Geometry of Light |
![]() Warm Documentary |
![]() White Leap |
![]() Cold Power |
![]() Hyper Chic East |
![]() Private Diary |
![]() Color Behind Glass |
![]() Frozen Film Still |
![]() Fairytale Giants |
![]() Vivid Garden |
![]() Playful Film |
Pick a file
| File | Size | Start here ifโฆ |
|---|---|---|
qwen_image_2.1_nvfp4.safetensors |
3.91 GB | you just want the smallest thing that works โ this is the default |
qwen_image_2.1_nvfp4_T2.safetensors |
4.29 GB | you see artefacts on hard material and want a little more headroom |
qwen_image_2.1_nvfp4_T3.safetensors |
4.67 GB | you want the most conservative option in the set |
Source is 13.25 GB bf16, so these are 29.5 % / 32.4 % / 35.2 % of the original.
What actually differs between them
The model has 32 transformer blocks, each with 6 quantizable layers
(attn.to_q/k/v/out.0, img_mlp.gate_up, img_mlp.out) = 192 layers total.
The only axis that changes between tiers is how many blocks at the head and tail
are kept at 8-bit instead of 4-bit:
| 4-bit NVFP4 (group 16) | 8-bit MXFP8 (group 32) | bf16 | |
|---|---|---|---|
| T1 (3.91 GB) | all 192 layers | โ | 73 tensors |
| T2 (4.29 GB) | 168 layers | 24 layers โ blocks 0, 1, 30, 31 | 73 tensors |
| T3 (4.67 GB) | 144 layers | 48 layers โ blocks 0โ3, 28โ31 | 73 tensors |
The bf16 protection set is identical in all three โ the tiers differ only in that 4-bit โ 8-bit trade at the ends of the stack.
Does the extra size buy anything?
On a like-for-like test โ same seed, same prompt, same text encoder โ the three tiers produced near-identical images: mean per-pixel difference of 3โ4 out of 255. The extra 0.4โ0.8 GB did not show a visible benefit there.
That was one prompt and one seed, so treat it as a starting point rather than a verdict. Faces, small text and dense texture are the places where a difference would show up first, so if you work on those, T2/T3 are worth a try.
What is protected, and why
| Layers | Count | Precision |
|---|---|---|
attn.to_q/k/v/out, img_mlp.gate_up/out |
192 | NVFP4, or MXFP8 in T2/T3 |
img_in, txt_in.in_layer/out_layer |
3 | bf16 |
time_text_embed.timestep_embedder.linear_1/2 |
2 | bf16 |
modulation.1 |
1 | bf16 |
norm_out.linear, proj_out |
2 | bf16 |
| norms / biases (non-2-D) | 65 | bf16 |
98.1 % of parameters are quantized; the protected 1.9 % costs only ~240 MB.
Why the timestep path stays bf16. A DiT's time_text_embed and modulation decide
how far each denoising step moves. Measurements on a distilled model in this family
showed that when timestep conditioning is rewritten, the model stops working outside
the exact schedule it was trained for. Keeping that path in bf16 costs almost nothing
and removes a whole class of risk.
Every 2-D weight in this model has in_features divisible by 16, so no padding is
needed anywhere โ the quantization is clean.
Audit
| Check | Result |
|---|---|
| Metadata | format_version 1.0, 192 layers declared |
| Tensor bookkeeping | 0 missing, 0 extra; comfy_quant matches metadata for every layer |
| NVFP4 round-trip error | median 9.44 %, max 9.49 % (24-layer sample) |
| MXFP8 round-trip error | median 2.65 % โ 3.6ร tighter than NVFP4, as the bit budget predicts |
| Protected layers | 40/40 sampled are byte-identical to the bf16 source |
| Loads in ComfyUI | โ
all three, detected as QwenImage21 |
| End-to-end | โ 1024ร1024, 25 steps, ~20โ22 s on a GB10 |
The MXFP8 number matters: had the 8-bit path been written wrong, it would have landed at or above the 4-bit error. It didn't.
Usage
Place in ComfyUI/models/diffusion_models/, then use the official
Qwen-Image-2.1 text-to-image workflow:
UNETLoader โ (this file)
CLIPLoader โ qwen3vl_8b_*, type: qwen_image
TextEncodeQwenImage21
VAELoader โ qwen_image_2.1_vae_bf16.safetensors
KSampler โ 25 steps, cfg 1.0, euler, simple
Older ComfyUI builds report UNSUPPORTED DIFFUSION MODEL for Qwen-Image-2.1 in
general โ including the official bf16 files โ so if you see that, update ComfyUI
rather than suspecting these weights.
Getting legible text
Dense drink labels stay legible while the bottles keep their glass/liquid translucency โ the cfg-schedule handoff below.
The cfg 1.0 above is the fast default, but this DiT is the full model, not a
distilled few-step one โ so classifier-free guidance is a real lever, and text is
where it shows most:
- cfg 1.0 โ best photorealism and material feel (glass/liquid translucency, mood), but dense small text comes out as plausible-looking gibberish.
- cfg ~3.0 + a negative prompt โ text snaps to legible (brand names,
prices, whole menu rows), at the cost of flatter, more "plastic" materials and higher
saturation. Put
oversaturated, overexposedin the negative so it doesn't scorch. - cfg ~2.0 โ a reasonable single-pass middle ground.
Same bottle crop: cfg 1.0 keeps the glass/liquid translucency but the labels are gibberish; cfg 3.0 makes labels legible but the bottles go flat and plastic; the schedule handoff keeps most of the translucency while the labels turn readable.
No single cfg is best at both a great photo and great text, so the best result is a
schedule handoff: run the first ~2/3 of the steps at cfg 1.0 (structure and
materials lock in), then the last ~1/3 at cfg 3.0 (text sharpens without
re-plasticising the materials, which are already set). One denoising trajectory, one
seed โ two KSamplerAdvanced nodes:
KSamplerAdvanced #1 add_noise enable, cfg 1.0, start_at_step 0, end_at_step 17, return_with_leftover_noise enable
KSamplerAdvanced #2 add_noise disable, cfg 3.0, start_at_step 17, end_at_step 25, return_with_leftover_noise disable
Both take the same model / positive / negative; #2's latent_image is #1's output.
Move the split later for more material fidelity, earlier for sharper text.
Speed
cfg > 1 evaluates the negative branch too, so cfg-1 steps cost 1ร and cfg-3 steps 2ร.
The handoff only pays that on its final third. GB10, 1024ร1280, 25 steps, T3:
| Setting | Forward passes | Time |
|---|---|---|
| cfg 1.0 (all steps) | 25 | 27 s |
| handoff (2/3 cfg1 โ 1/3 cfg3) | 33 | 33 s |
| cfg 3.0 (all steps) | 50 | 48 s |
The handoff buys cfg-3 text quality for ~20 % over the cfg-1 baseline, and runs a third faster than cfg 3.0 the whole way.
Legible signage also needs the text spelled out. The model only renders text it is
given โ put exact strings in the prompt (a sign that reads "ๅฑ
้
ๅฑ"); it invents
gibberish for any sign you merely describe. The "rewriter" is a prompt-enhancement LLM โ Qwen's own PE-T2I (Prompt Enhancement for text-to-image), which expands a short request into a detailed prompt; a refusal-ablated build is โฆ-PE-T2I-Heretic. It runs before the text encoder, and is not the text encoder itself. A prompt-rewriter that lays signs out
spatially (distinct positions, generous size) lets it render many at once โ the
difference between readable and "pretty neon soup".
Five scenes, each row: left = a terse prompt straight to the model, right = the same request expanded by a prompt-rewriter. Same DiT, same seed. Without it you get atmospheric but garbled neon; with it, legible signage (ๆญ่ไผ็บ, FamilyMart 120็จฎ้ก, a full ramen menu, ่ชๅ่ฒฉๅฃฒๆฉ) and a composed frame. The rewriter does the interpretive heavy lifting.
Pitfall worth knowing (T2/T3)
TensorCoreMXFP8Layout.quantize() returns its scale as float8_e8m0, which
ComfyUI's safetensors loader cannot parse โ KeyError: 'F8_E8M0', and the file simply
refuses to load. The official checkpoints store that bit pattern as uint8 and
reinterpret it at load time; these files do the same.
The all-NVFP4 tier never touches that code path, so a bug in the MXFP8 route stays invisible until you test T2/T3 specifically โ verifying T1 and assuming the rest follow is exactly how it gets missed.
Text encoder
The other half of the pipeline, with refusal behaviour ablated (5/100 refusals @ KL 0.0220):
| Repo | Format | Runtime |
|---|---|---|
โฆ-Text-Encoder-Heretic |
bf16, 16.33 GB | transformers / any |
โฆ-Heretic-NVFP4 |
NVFP4, 5.87 GB | ComfyUI |
โฆ-Heretic-W4A8 |
W4A8 INT8, 5.88 GB | ComfyUI |
โฆ-Heretic-GGUF |
GGUF Q4_K_M + mmproj, 5.76 GB | llama.cpp / Mac |
This DiT + the NVFP4 text encoder is a complete ~9.8 GB pipeline.
Model tree for pottokao/Qwen-Image-2.1-DiT-NVFP4-ComfyUI
Base model
Qwen/Qwen-Image-2.1













