Repository navigation
feat: Support dynamic batching for heterogeneous diffusion requests - #4024
asukaqaq-s wants to merge 3 commits into
Conversation
|
Codex usage limits have been reached for code reviews. Please check with the admins of this repo to increase the limits by adding credits. |
|
This PR has only been tested on single GPU so far. Multi-GPU and CUDA Graph validation still need to be added. |
|
is this PR ready for review? |
It may take until next week to resolve the issue. |
|
Hi, I compared this PR to #3638 on an Ada 6000 Pro GPU for Qwen-image model, and here is the latency results:
Maybe you can evaluate #3638 to A100 as well, to see if the conclusion remains. |
Signed-off-by: asukaqaq-s <1311722138@qq.com>
Signed-off-by: asukaqaq-s <1311722138@qq.com>
Signed-off-by: asukaqaq-s <1311722138@qq.com>
d7ffa5d to
5f05f13
Compare
SummaryWe added packed varlen step batching to Qwen-Image in vLLM-Omni. Previously, step batching only supported requests with the same resolution; now each denoise step can pack requests with different resolutions into a single [total_image_tokens, C] forward, using joint text+image varlen attention and packed GEMMs. The batched output is bit-exact to the serial output, with max_abs = 0. Batching delivers around 1.1–1.8× speedup depending on the resolution mix and parallel mode, in both BF16 and INT8. Setup
What we measure
The threshold is AccuracyAcross all configurations:
The result is:
Batching introduces zero numerical drift. The batched result is identical to the serial result. PerformanceBF16 speedup
INT8 speedup
Representative absolute wall time:
Notes
|




What does this PR do?
related:
#874
#3846
plans:
This PR adds dynamic batching support for heterogeneous diffusion
execute_stepwiserequests.It allows diffusion requests with different image resolutions, image token lengths, text lengths, denoise progress, and request-local CFG scalar values to be batched in the same step, as long as they share the same execution mode.
Qwen-Image is used as the first supported model path to validate the metadata contract and execution flow.
Why is this needed?
diffusion batching is mostly limited by
SamplingParamsKey. Several request-local fields are treated as hard batching keys, even though they do not change the transformer execution path.For example, requests with different resolutions or different
true_cfg_scalevalues may still be able to share one packed attention forward. However, because these fields are included in the compatibility key, the scheduler splits them into separate batches. This reduces batching opportunities and lowers GPU utilization.This PR moves shape-related and CFG scalar fields out of the scheduler key and keeps them as request-local runner/model metadata.
Main changes
This PR:
Narrows the dynamic diffusion batching key to true execution barriers:
do_classifier_free_guidancelora_int_idlora_scaleKeeps resolution, text length, timestep, scheduler state, RoPE inputs, and CFG scalar values as request-local state.
Adds attention metadata for:
Adds a FlashAttention varlen path for packed
[total_tokens, num_heads, head_dim]Q/K/V tensors.Adds a Qwen-Image dynamic path that:
Keeps the existing dense homogeneous path unchanged.
Fails fast for unsupported profiles.
How batching works
Instead of padding every request to the largest shape, the runner packs only real tokens.
For each step batch:
img_shapes;The packed path only changes how tokens are laid out for FlashAttention. It does not change request-local RoPE, attention boundaries, or output restore semantics.
Correctness model
The dynamic path relies on three metadata layers.
1. Request-local state
Each request keeps its own shape, text length, timestep, scheduler state, CFG values, and RoPE inputs.
RoPE is rebuilt from this request-local state. The model does not infer positions from packed global offsets, so a request should get the same RoPE whether it runs alone or inside a mixed batch.
2. AttentionMetadata
AttentionMetadatadescribes the varlen execution contract consumed by the attention backend.It records packed request order,
q_cu_seqlens,kv_cu_seqlens, max lengths, padded token count, and position metadata.The FlashAttention varlen path consumes these boundaries directly, so tokens from one request cannot attend to tokens from another request even when they are concatenated into one flat tensor.
3. AttentionSegment
AttentionSegmentrecords semantic split/gather spans inside each request.It is used to identify text, image, and negative-text spans, and to scatter attention outputs back to the original request-local latent state.
AttentionSegmentis intentionally separate from cache layout, LoRA routing, and MoE routing.CFG behavior
CFG batching is split into two parts:
The scheduler only keeps one CFG execution key:
do_classifier_free_guidance.In the first validated Qwen-Image path, a request is treated as CFG-active when:
This prevents CFG-active and non-CFG requests from sharing an incompatible forward shape.
However, different CFG scalar values can still batch together. For example, requests with
true_cfg_scale=2.0andtrue_cfg_scale=7.0can share the same CFG batch because the scalar does not change the attention layout.At runner/model time:
true_cfg_scaleandcfg_normalizeremain per-request values;This ensures that different guidance scales can batch together without mixing request semantics.
Current guardrails
This PR keeps the first dynamic path conservative.
The dynamic path currently fails fast for:
These are intentionally disabled until their metadata and correctness requirements are handled explicitly.
Test plan
Focused scheduler and Qwen-Image dynamic batching tests:
Online serving e2e test:
Lint and format checks for changed Python files:
Test results
Focused scheduler and dynamic batching tests:
Online serving e2e test:
The current e2e coverage uses Qwen-Image and compares execute-model, dynamic single-request, and staggered dynamic multi-request paths for:
512x512 + 512x512512x512 + 1024x1024512x512 + 256x256It also covers batching requests with different
true_cfg_scalevalues and verifies that the dynamic multi-request path does not materially regress against the dynamic single-request path in the tested cases.CC List.
cc
@ZJY0516 @fake0fan @SamitHuang @hsliuustc0106 @fhfuih @wuhang2014 @Semmer2 @wtomin