2026-09-26 · 31 min · image-generation · diffusion · flow-matching · distillation · lora · qwen · open-weights · inference-optimization · benchmarks · explainer
Qwen-Image-2.1 samples an image in 40 denoising steps. The piece on the release covers the architecture, a 7B single-stream DiT with an exact prefix KV cache, and I will not repeat it here. This one is about what arrived in the week after: two few-step students.
- Viggle published
Viggle/Qwen-Image-2.1-viggle-turboon 22 September and was at v0.2.1 two days later. AK's post on v0.2: "Text-to-image and image editing in 6 steps", "about 5× faster than the 40-step Qwen-Image-2.1". - Pruna published
PrunaAI/Pruna-Qwen-Image-2.1on 23 September: "a set of a few-step LoRA adapters that make Qwen-Image-2.1 … up to 6.3× faster". Its two short links resolve to the Hub repo and to a dashboard login; there is no blog post.
The tidy framing is two routes: a full distilled checkpoint against LoRA adapters. That was
true for about a day. I read the repositories: safetensors headers over HTTP range requests,
scheduler configs, both cards, and the cases.json behind Viggle's comparison Space, which holds 32
pairs of end-to-end timings. Measured means I computed it from a file.
Reported means it is the publisher's number and I could not re-run it. Reasoned is my
arithmetic on the other two. The first version of this piece ran no weights. The section on
four CPU cores, added the same day, runs Pruna's adapters and
generates images, and its timings are labelled by how busy the box was.
- task
- text-to-image
- library
- diffusers
- license
- other
- safetensors
- 9 shards
- largest file
- 14.23 GB
- files
- 24
- downloads
- 101.5K
- likes
- 282
Measured from the headers: v0.2.1 is a rank-256 LoRA of 679,542,784 parameters, 9.55% of the denoiser. The 7.1B the Hub reports is the superseded v0.1 full fine-tune. The 5.02x sums 32 end-to-end pairs on one B200. Qwen Research License, non-commercial.
repo last modified 2026-09-25
- task
- text-to-image
- library
- diffusers
- license
- other
- safetensors
- 2 shards
- largest file
- 335.6 MB
- files
- 13
- downloads
- 5.1K
- likes
- 99
Measured from the headers: two rank-64, alpha-128 LoRAs of 167,772,160 parameters, 2.36% of the denoiser, on attention and image MLP only. The 6.3x is the 5-step adapter at 2048²; the recommended 8-step one at 1024² is 3.8x. No quality metric. Qwen Research License, non-commercial.
repo last modified 2026-09-24
Why the base model takes 40 steps
Qwen-Image-2.1 is a flow-matching model. Training mixes an image with Gaussian noise
as and teaches the denoiser to
predict the velocity . Sampling runs it backwards: start at , pure
noise, and take Euler steps down a list of noise levels to . That is what
FlowMatchEulerDiscreteScheduler.step does:
Each step is one forward pass of the 7B denoiser, and the step count is set by how curved the path is. The ideal velocity at any point is an average, . At pure noise every image the prompt allows is still possible, so the velocity points at their average, and one Euler step from there lands on the average image: a blur. As falls the posterior narrows, the direction swings toward one image, and the path bends. Euler holds the direction fixed across a step, so it overshoots every bend by an amount that grows with the step. Forty small steps keep that error small. Six large ones do not, unless the network is retrained to take them.
Qwen-Image-2.1's pipeline default: true_cfg_scale = 1.0, one pass per step. The only thing a student can remove from this baseline is steps.
The toy's velocity field is exact, so its error is the sampler's alone. At N = 1 the teacher lands on the average of the three clusters. From 4 to 8 steps it heads for the right cluster and misses the 400-step endpoint; at 40 it is close. A few-step student is trained to close that gap.
The second cost, which this base does not pay
Classifier-free guidance runs the denoiser twice per step, with and without the prompt, and
extrapolates between the two. It doubles the passes. Qwen-Image 1.0 and Qwen-Image-2512 both call
their pipelines with a negative prompt, num_inference_steps=50 and true_cfg_scale=4.0: 100
forward passes an image. Qwen-Image-2.1's card calls its pipeline with 40 steps and no guidance
argument. The diffusers pipeline defaults to true_cfg_scale=1.0, and switches guidance on only
when the scale exceeds 1 and a negative prompt is passed. The denoiser has no guidance embedder
either: its only conditioning on the step is time_text_embed.timestep_embedder (measured, from
the tensor names). So the 40-step baseline is 40 passes, not 80.
This shapes every speed claim below. Distillation usually removes two costs at once, because the student is trained to reproduce the teacher's guided output in one pass per step. Here the guidance half was already gone before either student arrived, and the budget is the step ratio alone: 40/6 = 6.67x for Viggle's default, 40/8 = 5x and 40/5 = 8x for Pruna's adapters. Those are ceilings, before the text encoder and the VAE, which no step count touches.
The distillation families, and where these two sit
Every few-step method trains a student to do in N big steps what the teacher does in many small ones. They differ in what "the same" means.
| Family | The student is trained to | Examples | Used here |
|---|---|---|---|
| Consistency | map any point on the teacher's trajectory to that trajectory's endpoint | CM, LCM, LCM-LoRA | no |
| Continuous-time consistency | the same in the limit of tiny steps, through a Jacobian-vector-product loss | sCM; rCM adds score distillation as a regulariser | no |
| Rectified-flow reflow | regenerate noise-image pairs with the teacher and retrain on straight lines between them | Rectified flow, InstaFlow | no |
| Adversarial | fool a discriminator on its samples | ADD (DINOv2 features), LADD (the teacher's latent features; SD3-Turbo in four unguided steps) | not stated |
| Distribution matching | produce samples the teacher's score cannot tell from its own | DMD, DMD2, SenseFlow | both |
| Guidance distillation | reproduce the two-pass guided output in one pass, with the scale as an input | Meng et al. | moot: no CFG to remove |
The first three are trajectory methods. They care which image a given noise becomes, which is the dashed straight path in the toy. Distribution matching does not. DMD keeps two score estimates: the teacher's, and a "fake" one trained online on the student's own outputs. It re-noises a student sample, asks both where it should go, and pushes the student along the difference, which is the gradient of the reverse KL divergence . DMD2 dropped the first paper's regression loss on teacher-generated pairs, added a two-time-scale update for the critic and a GAN term on real images, and made the student multi-step by simulating its own inference during training. The failure this family invites is mode collapse, because reverse KL is mode-seeking; the rCM paper reports matching DMD2's quality "while mitigating mode collapse".
Viggle says what it did (reported): "DMD2 (Yin et al., 2024) / SenseFlow-style distribution
matching", plus SenseFlow's intra-segment guidance, in which "the student's velocity over each of
its segments is regressed on the teacher's", with teacher targets made from rewritten prompts. The
weights are the step-700 EMA student of a run named v6_isg, trained on a 4-step schedule. Whether
a GAN term survived, the card does not say.
It also measured the collapse. Its "sample diversity" is the mean DINOv2 patch distance between 8 seeds of one prompt, over 32 prompts, as a ratio to the base model. The v0.1 students scored 0.75 (LoRA) and 0.72 (full fine-tune): seeds landing on near-identical layouts. v0.2.1 scores 0.98. These are Viggle's numbers on its own prompts, and the most useful on either card: they test for the failure the method is known for.
Pruna says one sentence: "Training is based on DMD." No loss terms, no teacher settings, no code. The sentence after it, "Improved using Qwen", reads like a method and is a licence obligation: clause 4(b) of the Qwen Research License says anyone who uses the model or its outputs to train or improve a model they distribute "shall prominently display 'Built with Qwen' or 'Improved using Qwen'". Viggle's card uses the other phrase.
What is actually in each repository
Measured from the safetensors headers:
| File | Rank | Alpha | Tensors | Parameters | Share of denoiser | Targets | Size |
|---|---|---|---|---|---|---|---|
| Viggle v0.2.1, 6-step | 256 | 256 | 454 | 679,542,784 | 9.55% | q, k, v, out, 3 MLP, shared modulation, timestep embedder | 1.36 GB |
| Viggle v0.2.1, rank cut | 128 | 128 | 454 | 339,771,392 | 4.78% | same | 0.68 GB |
| Viggle v0.1 LoRA, 4-step | 64 | 64 | 454 | 169,885,696 | 2.39% | same | 0.34 GB |
Viggle v0.1 transformer/ | full | n/a | 297 | 7,115,124,736 | 100% | every weight | 14.23 GB |
| Pruna v0.1, 8-step and 5-step | 64 | 128 | 448 | 167,772,160 | 2.36% | q, k, v, out, 3 MLP | 0.34 GB each |
There is no full-checkpoint route any more. Viggle shipped one as v0.1 on 22 September, a fine-tune of all 7,115,124,736 weights beside a rank-64 LoRA, moved to a rank-256 LoRA a day later, and now says of the old files "there is no reason to prefer them". I compared the first 64 KB of seven of the full fine-tune's tensors with the base's, and every one had changed. The share of bf16 values that differ is 31% in block 0's query projection, 56% in block 31's MLP output, 75% in the shared modulation and 84% in the timestep embedder (measured). The step-conditioning path moved most. That is the part a sampler that only ever sees four noise levels has most reason to relearn (reasoned).
The two adapters sit on the same 32 blocks and differ in two ways.
- Scope. Viggle's also reaches the shared
modulation.1projection, 4,096 to 16,384, which every block slices its scales and gates from, and both timestep-embedder layers. Pruna's touches only the attention and image-MLP projections inside the blocks, so it can change what the blocks do with the noise level but not how the model reads it. - Rank. Viggle's is four times Pruna's. Its card also ships a rank-128 cut made by per-layer SVD, keeping 83–100% of each update's energy. On the v0.2 pair, the card reports, images from the cut differ from the rank-256 adapter's by LPIPS 0.0244, against 0.0239 for re-factoring the rank-256 adapter at full rank, which changes nothing but round-off.
Pruna's alpha is twice its rank, so "keep the LoRA strength at 1.0" applies the update at scale 2.
Why not merge the update into the weights and pay nothing per step? Viggle measured that too: round-to-nearest into bf16 keeps about 70% of its update on average, and about 40% in some early MLP layers, because the update is small against a bf16 weight's rounding step (reported). Both cards therefore run the adapter unmerged, as a side branch on every call. That is exact, and it is not free; the speed section finds the bill.
Both students run the same clock
The schedules are where the two releases turn out closest. Viggle passes raw nodes
[1.0, 0.9375, 0.875, 0.75, 0.5, 0.25] through the pipeline's own resolution-dependent shift.
Pruna switches the shift off and passes nodes already shifted, on evenly spaced : a
fixed shift of 2. At 1024 x 1024 the pipeline's own shift is , so the two land
on one grid.
At 1024px the pipeline's own shift is 2.0008, within 0.001 of Pruna's hard-coded 2. 7 of Viggle's 8 dense-text nodes, counting the start at 1, sit on Pruna's 8-step nodes; the dashed guides are the three that every student schedule here shares: 6/7, 2/3 and 2/5.
Three things follow, reasoned from the configs.
- Both spend extra steps at the high-noise end. Viggle trained on
linspace(1, 1/4, 4)and samples with its first segment cut into three. Pruna's 5-step schedule is the 4-step shift-2 grid plus one node at 0.94. Viggle's card says why: "The composition is decided between raw sigma 1 and 0.875", and one big Euler step there "ghosts and drifts the layout". Its 5-step launch schedule changed the layout on 4% of 96 held-out requests; 6 steps changed none (reported). A raw 0.875 becomes 0.933 after the shift, so the decisive span is the first 6.7% of the noise range by the pipeline's formula; the card says "roughly the first 5%". - Both switch off
shift_terminal. The base config stretches its schedule so the last non-zero node is 0.02. Applied to a student whose last node is 0.4, the stretch would move every node, and Viggle's card says it "would wreck the last step". - At 2048 they part. Viggle's nodes follow the pipeline's shift to 3.72 and spend more of the budget at high noise, as the base does. Pruna's stay at shift 2, the schedule it trained at 1K. Its card calls 2K outside the training coverage and says the 2K timings "show inference speed, not a guarantee of quality".
Checking the speed claims
Both claims are end-to-end, and they are not on the same GPU.
- Viggle (reported): 32 of the 37 examples in Qwen's own demo Space, rendered once by the base at 40 steps and once by v0.2.1 at 6, same prompt, inputs and seed 42, on one NVIDIA B200, timing "text encoding, denoising and VAE decoding" after warm-up. Text-to-image outputs are about 4 MP, edits 1536² in area.
- Pruna (reported): the card's own prompt, BF16, batch 1, on one H100 80GB, median of 3 after a warm-up, at 1024² and 2048². Base at 40 steps with the KV cache on; adapters with it off, unmerged, no compilation.
- text-to-image, 1024 · 8 steps6.10 s → 1.61 s = 3.79x of 5.00x (76%)
- text-to-image, 1024 · 5 steps6.10 s → 1.06 s = 5.75x of 8.00x (72%)
- text-to-image, 2048 · 8 steps31.44 s → 7.60 s = 4.14x of 5.00x (83%)
- text-to-image, 2048 · 5 steps31.44 s → 4.98 s = 6.31x of 8.00x (79%)
- edit, 1024 · 8 steps7.05 s → 2.01 s = 3.51x of 5.00x (70%)
- edit, 1024 · 5 steps7.05 s → 1.43 s = 4.93x of 8.00x (62%)
- edit, 2048 · 8 steps34.40 s → 8.54 s = 4.03x of 5.00x (81%)
- edit, 2048 · 5 steps34.40 s → 5.73 s = 6.00x of 8.00x (75%)


Viggle's "about 5x" holds. Summing all 32 pairs gives 633.7 s against 126.3 s, 5.02x
(measured, from cases.json). By task it is 5.55x for text-to-image (median 26.1 s against 4.7 s),
83% of the 6.67x ceiling, and 4.7x for single-reference edits (median 14.2 s against 3.0 s).
Pruna's "up to 6.3x" is one cell of eight. It is the 5-step adapter at 2048², 31.44 s against 4.98 s: the adapter its card calls "visibly worse", at a resolution its card says it did not train at. The recommended default, the 8-step adapter at 1K, is 3.8x for text-to-image and 3.5x for editing (reported). Every ratio on the four charts reproduces from its bar labels, with one rounding slip: 6.10/1.06 is 5.75, charted as 5.7x.
The adapters' steps cost more than the base's. Pruna's 5- and 8-step runs share their fixed work, so their difference is three steps. That gives the adapter's per-step cost, the fixed encode-and-decode cost, and from those the base's per-step cost (reasoned; tick "per-step fit" above). At 1K an adapter step is 0.183 s against the base's 0.149 s, 23% dearer; at 2K, 0.873 s against 0.771 s, 13%. The arms differ in the unmerged side branch and the KV cache. The branch adds only 2.4% to the multiply-accumulates of the seven projections it wraps, and in text-to-image the cached prefix is just the prompt, so most of the gap is not FLOPs. My guess is the fourteen small matmuls per block, each rereading its input; nothing published separates the causes. At the base's per-step cost, the 5-step run at 1K would take about 0.89 s: 6.9x rather than 5.75x.
Editing gains less, and the KV cache is why. The base caches the keys and values of the prompt and reference images after its first step (the mechanism, and how it measured). Its first step is a full pass over references and target; the other 39 run the target only. A 6-step student gets five cheap steps, so the full step and the reference encoding are a far larger share of its time. Viggle's worst case shows it: an edit with ten references, about 41,000 condition tokens against 9,216 target tokens, is 36.6 s against 9.9 s, 3.7x. Solving those two timings for a fixed cost and a per-step cost puts 5 to 6 s of the student's 9.9 s outside the loop (reasoned; the range is whether a student step costs the same as a base step or 15% more).
Pruna's edit rows hold a small puzzle. The fitted edit step at 1K is only 5.5% dearer than the text-to-image step, yet an uncached edit with a megapixel reference would process twice the tokens. Either those runs had the cache on, as the card's examples do, or the reference was small. The card does not say (reasoned).
What the quality claims measure
Viggle's card says the student is "very competitive with it in quality: on the official Qwen examples the two are hard to tell apart on most prompts". The evidence is of two kinds. The first is the comparison set: 32 pairs, one sample each, no seed picking. I looked at two of the five dense-text examples, where the card says the student is weakest.



Both failures are the ones Viggle's own notes in the Space describe, to its credit: at 6 steps "small Latin text can print twice, like a double exposure (decided in the 0.75 → 0.5 step), and small Chinese strokes can get colour blotches (the last 0.25 → 0 step)". Its OCR check puts numbers on them. Word recall on the infographic's caption rises from 0.71 at 6 steps to 0.83 at 8 over 16 seeds, and on the board's Chinese labels from 0.76 to 0.90 over 4 seeds, against 0.95 for the base on both (reported).
The second kind is the metrics table: sample diversity, centroid drift and the share of prompts whose layout differs from the base's, over 96 held-out user requests and 32 prompts, plus Laplacian sharpness (0.0199 for v0.2.1, 0.0187 for v0.2). Every one measures distance from the teacher. None measures whether the picture does what the prompt asked. The card is plain about it: "no standard benchmark is claimed", and "2K output is compared with the base model only by eye". Its numbers were also taken with Qwen's prompt rewriters on, which the piece on the pocket rewriter found made rendered images less faithful to the request, not more.
Pruna publishes no quality number at all. Its card says v0.1 "does not yet match the visual quality of the base model", that the 5-step adapter's images are "visibly worse", and that short prompts do worse. The pictures it ships have no base-model counterpart and no stated settings.

The rest of the checklist. Both edit: Viggle trained with 1 to 3 references and says 5, 6 and 10
references, RGBA output and mask-guided edits "work … but are not measured"; Pruna trained single-
and multi-image editing at 1K with up to three. Both run at true_cfg_scale=1.0 with no negative
prompt, and Viggle's card adds that CFG does not help. Both LICENSE files are byte-identical to
Qwen's (measured): the Qwen Research License, non-commercial, "for research or evaluation purposes
only".
Pruna's adapter on four CPU cores
Every timing above is someone else's, on a B200 or an H100. The release piece ran the base model on the four-core Xeon that builds this site, with no GPU at all: a 512² image at the vendor's 40 steps took about an hour. A few-step adapter is the obvious thing to try there. I ran Pruna's, because its pair gives a 5-step and an 8-step point on one base; at 90 seconds a step, every image here is ten minutes or more of the box.
The setup is the release piece's: stable-diffusion.cpp at commit 2bb7294, leejet's Q4_K GGUF of
the denoiser, Qwen's Q4_K_M encoder, 512 x 512, Euler, guidance off, seed 42, four threads. The
sigmas are Pruna's own lists, passed verbatim with no shift on top:
1.0, 0.9333333, 0.8571429, 0.7692308, 0.6666667, 0.5454545, 0.4, 0.2222222, 0 for 8 steps and
1.0, 0.94, 0.8571429, 0.6666667, 0.4, 0 for 5. LoRA strength 1.0, as the card says.
The adapter does not load as shipped
Loaded as published, sd.cpp applied 320 of the file's 448 tensors, and logged as much. Two things do not line up.
- The MLP names. leejet's GGUF fuses the image MLP's two input projections,
img_mlp.gate_layerandimg_mlp.proj, into oneimg_mlp.gate_upmatrix, gate rows first. The adapter's 128 tensors for those layers, 32 blocks times two layers times A and B, name weights the file does not have. - The scale. PEFT scales an update by alpha over rank, 128/64 = 2, and keeps alpha in the
file's metadata. sd.cpp reads a scale only from an
.alphatensor and otherwise uses 1, so even the matched layers would get half the update.
The fix is a rewrite of the file. Multiply every B by 2, a power of two and so exact in bf16. For
each block, stack the gate and up A matrices into one rank-128 A, and put the two Bs on the diagonal
of one B, so the product is the gate update over the up update. The rewritten adapter has 384
tensors, sd.cpp applies all 384, and the largest difference between its updates and PEFT's, over
all 32 blocks, is 0.0 (measured). It is 436 MB against 0.34 GB, because the block-diagonal B stores
its zeros. Half of this is already fixed upstream: a stable-diffusion.cpp change merged on 25
September, #2057, maps the two MLP
names onto the fused weight. The scale is still read only from an .alpha or .scale tensor, so a
PEFT file still needs its B matrices doubled by hand (the stable-diffusion.cpp piece
has the code path).
What it costs
| Run | Box | Per step | Sampling | VAE decode | Total | Peak RSS |
|---|---|---|---|---|---|---|
| Base, 40 steps (release piece) | shared | 87.09 s median | 46.06 s | 3,863 s | ||
| Pruna, 8 steps | quiet | 89.89–91.64 s | 725.60 s | 39.56 s | 771.68 s | 11.59 GiB |
| Pruna, 5 steps | shared | 98.42–124.30 s | 532.66 s | 76.11 s | 615.85 s | 10.23 GiB |
| Base, 8 steps on Pruna's sigmas | shared | 90.39–127.90 s | 829.02 s | 66.00 s | 900.86 s | 10.36 GiB |
"Quiet" means the load average stayed near the job's own four threads; "shared" means other work, mostly other agents building this site, was on the box. The quiet run is the one to read.
- The 8-step adapter is 4.6x faster than the base at its own settings. 771.68 s against the release piece's arithmetic figure of 3,535 s for 40 clean steps, or 5.0x against its 3,863 s wall-clock. Steps alone allow 5x; the 46.08 s outside the loop, mostly the VAE decode, is the difference (measured, and reasoned from the release piece's medians).
- An adapter step costs what a base step costs. The quantised weights mean sd.cpp cannot merge
the update, so its
automode applies it at runtime, as the unmerged side branch the cards describe. The quiet run's eight steps took 89.89 to 91.64 s; the base's first two steps in the control, before the box filled up, took 90.39 and 90.50 s, and the release piece's median base step was 87.09 s. The branch adds 2.4% to the multiply-accumulates of the projections it wraps, which is inside this box's run-to-run spread. On the H100, Pruna's own numbers put an adapter step 23% above a base step. On a CPU that does the arithmetic and little else, the premium disappears, which fits the reading that the GPU's gap is not FLOPs (reasoned). - The 5-step run only looks slow. It ran on a shared box, and its steps were 8 to 37% slower than the quiet run's. At the quiet run's 90.70 s a step and 46.08 s outside the loop, 5 steps is about 500 s, 7.1x the 40-step base (reasoned).
What it draws




All four get every word and the comma. The chalkboard is easy enough that the base at 8 steps on Pruna's schedule gets it too, so on this prompt the adapter does not buy legibility. The release piece's 8-step runs were unreadable, but those were at Q2_K on the vendor's schedule; two things changed at once, so the pair says nothing about which one mattered.
What the adapter buys is finish. On the grey-level images, its 8-step picture has the 40-step base's contrast, a standard deviation of 60.6 against 60.7, and nearly its sharpness, a Laplacian variance of 512 against 524. The base at 8 steps is flatter and softer, at 56.6 and 467 (measured). That is one prompt, one seed and two crude statistics: evidence that the distillation did its job here, and not a quality benchmark.


The poster repeats the pattern. Both spell everything, the date included. The adapter sets it larger and heavier, and its grey-level standard deviation is 40.8 against 28.6. Both leave the middle empty, which is what "minimalist" asked for. Their wall-clocks are twice the quiet run's because the box was running other jobs; they measure the box, not the model.
At the adapter's own resolution
512² is a quarter of the pixels Pruna trained at, so the last four images are at 1024 x 1024 with
the same rewritten 8-step adapter, guidance off, seed 42, and --vae-tiling, which decodes the
latent in tiles instead of all at once. The prompts are longer on purpose: a scene with signage,
a dense illustration with a line of text, a labelled diagram, and a photograph with fine texture.
Only the hummingbird had the box nearly to itself, so it is the one to time. Its eight steps took 370.47 to 377.67 s, 4.1 times a 512² step for 4 times the pixels, and the whole image 3,303.93 s, 55 minutes, with a peak RSS of 11.88 GiB. The other three shared the box and took 4,551.41 to 8,581.52 s; those times measure the neighbours as much as the model. At the same step cost, 40 base steps at 1024² would take about 15,240 s, over four hours, so the adapter's 4.6x holds at this size too (reasoned: the base was not run at 1024² here).




Across the four, text holds up at 8 steps: the two strings on the sign, the poster's title and four labels, and all but one letter of the chalkboard. What slips is composition. A prompt with more parts than the picture makes room for loses some of them: the poster's four stages collapse into one finished painting, the café's reading nook moves to the roof, and the hummingbird gets one flower instead of a cluster. One seed each, so this is a look at the adapter, not a measurement of it.
The take
The step count is the whole story here. Qwen-Image-2.1 had already dropped classifier-free guidance by default, so there was no second factor for distillation to remove. A 6-step student can be at most 6.67x faster, and an unmerged adapter gives some of that back on every step. Viggle's 5.02x on a B200 is three quarters of that ceiling, measured on Qwen's own examples, and its card names the price: small text, complicated edits and seed diversity, the last of which DMD is known to spend.
Pruna's release is a v0.1 and says so; the headline does not. "Up to 6.3x" is the adapter the card calls visibly worse, at a resolution it did not train at, and the recommended configuration is 3.8x. The card is precise about its timing method, down to which arm had the KV cache on, and publishes nothing about image quality.
The finding I would carry away is the schedule. Two teams, distilling the same model separately, put their students on the same shift-2 grid and spent their extra steps at the high-noise end, where the composition gets decided. A few-step release for this model that lands its nodes elsewhere will be worth reading closely.
What would change my mind
4 claims above, and what would falsify each
The 40-step Qwen-Image-2.1 baseline runs one forward pass per step, so a few-step student's speedup is bounded by 40 / N.
Rests on the pipeline default
true_cfg_scale=1.0, the card's examples and the tensor names. A Qwen-recommended setting with guidance on, or either baseline timed with CFG, would double the baseline and change every ratio here.Both releases are distribution-matching (DMD-family) LoRAs, not full checkpoints.
Rests on both cards and every adapter header. A new recommended full-weight file, or training code whose main loss is a consistency or adversarial objective, would change it.
Unmerged adapter steps cost 13-23% more than base steps in Pruna's runs, mostly not because of the adapter's FLOPs.
A two-point fit on medians of three, assuming both arms share one fixed cost. A merged or cached 5-step timing at 1024² near 6.9x would confirm it; one still near 5.75x would put the overhead somewhere else.
Viggle's quality metrics measure distance from the teacher, not prompt adherence.
The card's own words and metric definitions. A GenEval, DPG or Qwen-Image-Bench run on either student against the 40-step base would replace this with an actual number.
Sources, read directly: Viggle/Qwen-Image-2.1-viggle-turbo
(card, NOTICE, LICENSE, scheduler and adapter configs, comfyui/viggle_turbo.py, and all nine
safetensors headers by range request) and its
demo Space (compare.py,
compare/cases.json, the renders); PrunaAI/Pruna-Qwen-Image-2.1
(card, LICENSE, both adapter headers, the latency charts);
Qwen/Qwen-Image-2.1 (card, LICENSE, configs, shard
headers); the diffusers QwenImage21Pipeline at the commit Viggle pins; and the Qwen-Image and
Qwen-Image-2512 cards. Figures 3 to 5 are Pruna's and 1, 2 and 6 Viggle's, served locally; the
crops and layouts of 1, 2 and 6 are mine.