Add Qwen-Image-2.1 recipe by xianbaoqian · Pull Request #996 · vllm-project/recipes · GitHub
Skip to content

Add Qwen-Image-2.1 recipe - #996

Merged
xianbaoqian merged 1 commit into
vllm-project:mainfrom
xianbaoqian:add-qwen-image-2-1
Sep 20, 2026
Merged

xianbaoqian merged 1 commit into
vllm-project:mainfrom
xianbaoqian:add-qwen-image-2-1

Conversation

@xianbaoqian

@xianbaoqian xianbaoqian commented Sep 20, 2026 •

Copy link
Copy Markdown
Collaborator

Adds models/Qwen/Qwen-Image-2.1.yaml.

Qwen-Image-2.1 serves text-to-image and image-conditioned generation through one
pipeline class, QwenImage21Pipeline: a 7.1B single-stream DiT with block-causal
attention and an exact cross-step prefix KV cache, a Qwen3-VL-8B text encoder, and
a 16x RGBA autoencoder.

Draft — two upstream blockers

Both resolve on their own; this is staged so it is ready when they do.

Verified on one NVIDIA GB300

Built from PR #7759. All at 1024x1024, 40 steps, CFG off, fixed seed,
--vae-use-tiling. Output was checked by decoding the response and asserting PNG
magic bytes, byte length and IHDR dimensions — not by accepting HTTP 200.

serves, valid PNG 4.5 s per image, 34.0 GB peak (BF16)
DiT FP8, img_mlp in BF16 32.0–32.7 GB, slightly slower
text-encoder FP8 27.5–28.1 GB — ~3x the DiT-only saving
prefix KV cache repeat prompt at 0.31x; changed tail returns to 2432 ms
prefix_kv_cache_dtype=fp8_v serves; 0.50x instead of 0.31x
Ulysses SP, 2 GPUs 3851 ms / 33.1 GB vs 4492 ms / 34.0 GB on one
step execution 4 concurrent in 4019 ms vs ~5870 ms serial
dimension handling floored to /32 (1000→992, 1328→1312), never rejected
seed determinism byte-identical
RGBA survives the round trip (PNG colour-type 6)
reference images 1, 2 and 4 accepted; a 5th refused by the server

Two bugs found by running it

Neither is visible from reading the source, and both are reportable upstream:

  1. --revision is silently ignored. omni_base.py:110 calls
    download_weights_from_hf_specific() with no revision=, so the engine always
    resolves main. A cache staged by commit sha has no refs/main and fails
    offline with LocalEntryNotFoundError with every shard present.
  2. The PR #7759 images carry no vllm serve entrypoint. They set
    WORKDIR /opt/vllm-omni, so a runner passing <model> --flags execs the model
    id as a binary and exits 127.

Corrections that source-reading alone got wrong

  • /v1/images/edits works — it takes multipart/form-data. A JSON body resets
    the connection, which reads as a broken endpoint. A data: URL in the url form
    field is additionally capped at 1024 KB per part, which a 512x512 PNG exceeds.
  • true_cfg_scale defaults to 4.0 but is inert without a negative_prompt, so a
    plain request behaves as if 1.0 had been sent. Measured: 853 ms without a negative
    prompt against a 1104 ms baseline, and 1800 ms with one.
  • The first-request cost is not graph capture — it persists at 1.26x under
    --enforce-eager with no graphs at all.
  • Per-component FP8 is serve-reachable via --diffusion-quantization-config;
    --ignored-layers exists only in text_to_image.py, not in vllm serve.
  • A plain clone lands on main, which does not contain this model.
  • Without model.docker_image the builder substitutes vllm/vllm-openai:latest.

Not measured, and not claimed

No throughput figure: vllm bench serve drives only /v1/completions and
/v1/chat/completions, so nothing in the harness can drive image generation. The
t2i task carries a benchmark override saying so, to stop a text benchmark being
added later and labelled this model's throughput. Pipeline parallelism is untested.
The GB200 FP8 figures stay attributed to the vLLM-Omni contributors and separate
from the GB300 numbers above.

meta.hardware records gb300: verified with default_hardware: gb300, so the page
opens on the hardware the numbers came from. vram_minimum_gb: 40 from the repo
formula ceil(33.1 GB × 1.2), which the measured 34.0 GB sits under. No hardware:
entry for any GPU that was not run.

Validated with node scripts/build-recipes-api.mjs: 191 → 192 models, no warnings
naming this file.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Sep 20, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
vllm-recipes Ready Ready Preview Sep 20, 2026 12:00pm UTC

Request Review

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new model recipe for Qwen-Image-2.1, including its metadata, dependencies, variants, and a comprehensive guide for offline inference, online serving, quantization, and limitations. Feedback on the changes suggests setting pip: false to avoid displaying a non-executable string in the UI, fixing a typo in the docker note, and explicitly pinning vllm==0.29.0 in the dependencies installation command to ensure consistency with the guide.

Comment thread models/Qwen/Qwen-Image-2.1.yaml Outdated
Comment on lines +28 to +31
note: "The PR is stil under review - use docker until the PR is merged."
pip:
command: "The PR is stil under review - use docker until the PR is merged."
note: "Base environment only; vLLM-Omni itself has to come from source."

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The pip.command is currently set to a text description rather than a valid shell command, which will cause the UI to display a non-executable string in the pip installation tab. Since the model is not yet in a tagged release and must be installed from source (as documented in the dependencies block), it is cleaner to set pip: false to hide the pip tab entirely. Additionally, this fixes a typo ('stil' -> 'still') in the docker note.

      note: "The PR is still under review - use docker until the PR is merged."
    pip: false

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To ensure compatibility and match the installation instructions in the guide, explicitly pin vllm==0.29.0 in the dependencies installation command, similar to how it is done in other recipes (e.g., Qwen-Image.yaml).

    command: "git clone https://github.com/vllm-project/vllm-omni.git && cd vllm-omni && git fetch origin pull/7759/head:qwen-image-2.1 && git checkout qwen-image-2.1 && uv pip install -e . vllm==0.29.0"

Unified text-to-image and image-conditioned generation through one pipeline
class: a 7.1B single-stream DiT with block-causal attention and an exact
cross-step prefix KV cache, a Qwen3-VL-8B text encoder, and a 16x RGBA
autoencoder.

Verified end to end on one NVIDIA GB300 built from PR #7759. The guide carries
the facts an operator acts on; the evidence for each is below.

What was measured (1024x1024, 40 steps, CFG off, seed fixed, --vae-use-tiling):

- serves and returns a valid PNG, checked by decoding it and asserting magic
  bytes, byte length and IHDR dimensions rather than accepting HTTP 200
- 4.5 s per image, 34.0 GB peak in BF16
- DiT FP8 (img_mlp kept BF16): 32.0-32.7 GB, slightly slower
- text-encoder FP8: 27.5-28.1 GB -- about three times the DiT-only saving
- prefix KV cache: a repeated prompt costs 0.31x the first submission; changing
  only the prompt tail returns it to 2432 ms, which rules out warm-up
- prefix_kv_cache_dtype=fp8_v serves, and returns 0.50x instead of 0.31x
- Ulysses SP across 2 GPUs: 3851 ms at 33.1 GB, against 4492 ms and 34.0 GB on 1
- step execution: 4 concurrent requests in 4019 ms against ~5870 ms serial
- dimensions floored to a multiple of 32 (1000 -> 992, 1328 -> 1312), never
  rejected; 1024x1536 and n=2 both fine
- seed determinism: byte-identical output
- RGBA survives the round trip -- PNG colour-type 6
- up to 4 reference images; a 5th is refused by the server

Bugs found by running it, neither visible from reading the source:

- --revision is not honoured. omni_base.py:110 calls
  download_weights_from_hf_specific() with no revision=, so the engine resolves
  "main"; a cache staged by commit sha has no refs/main and fails offline with
  LocalEntryNotFoundError despite every shard being present.
- The PR #7759 images set WORKDIR /opt/vllm-omni and do not inherit
  vllm/vllm-openai's `vllm serve` entrypoint, so passing only `<model> --flags`
  execs the model id as a binary and exits 127.

Corrections to claims that source-reading alone got wrong:

- /v1/images/edits works, but takes multipart/form-data. A JSON body resets the
  connection, which reads as a broken endpoint. A data: URL in the `url` form
  field is additionally capped at 1024 KB per part, which a 512x512 PNG exceeds.
- true_cfg_scale defaults to 4.0 when omitted but only applies alongside a
  negative_prompt, so a plain request behaves as if 1.0 had been sent.
- The first-request cost is not CUDA-graph capture: it persists at 1.26x with
  --enforce-eager and no graphs at all.
- Per-component FP8 is serve-reachable via --diffusion-quantization-config;
  --ignored-layers exists only in text_to_image.py, not in `vllm serve`.
- A plain clone lands on main, which does not contain this model.
- Without model.docker_image the builder falls back to vllm/vllm-openai:latest.

Not measured, and not claimed: throughput (vllm bench serve drives only
/v1/completions and /v1/chat/completions, so the t2i task carries a benchmark
override saying so), pipeline parallelism, and the GB200 FP8 figures, which stay
attributed to the vLLM-Omni contributors.

meta.hardware records gb300 as verified and default_hardware points there, so
the page opens on the hardware the numbers came from. vram_minimum_gb is 40 from
the repo formula ceil(33.1 GB x 1.2), which the measured 34.0 GB sits under. No
hardware: entry for any GPU that was not run.

Validated with `node scripts/build-recipes-api.mjs`: 191 -> 192 models, no
warnings naming this file.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Tiezhen WANG <tiezhen@inferact.ai>
@xianbaoqian
xianbaoqian marked this pull request as ready for review September 20, 2026 13:06
@xianbaoqian
xianbaoqian merged commit 7918dcd into vllm-project:main Sep 20, 2026
4 checks passed

This branch was successfully deployed

1 active deployment
Preview — bbcea939 Deployed Sep 20, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant