Repository navigation
[Diffusion][Performance] Optimize MiniMax-H3 video output transfer - #6824
Conversation
Signed-off-by: lishunyang12 <lishunyang12@163.com>
|
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 appears to be related to model: MinimaxH3. Model owners: @david6666666 @lishunyang12, please review your own changes and leave a short self-review comment describing what you checked. PRs without author self-review may not be assigned a reviewer. Please take a look when you have a chance. If you would like an automated review, mention @vllm-omni-review-bot in a comment. |
|
Reviewer A/B test for PR #6824 Environment
Workload
Both measured MP4 outputs were byte-identical: Both outputs decoded successfully as 124-frame H.264 video with stereo 32-kHz AAC audio. One caveat: baseline used the Affected tests: |
|
Follow-up on the interaction with PR #6776: this PR’s contiguous BTHWC output is interleaved, so the existing non-streaming encoder falls back unless the strided-plane routing from #6776 is also present. Our 4-GPU MiniMax-H3 A/B (4 steps, 1344×768, 124 frames, seed 42) showed the net E2E gain, 9.738 s → 8.878 s (−8.84%), with byte-identical MP4s and unchanged peak memory. However, baseline used |
## Purpose **Problem:** with model-level CPU offload, vllm-project#6072 evicts the DiT before VAE decode, but the decoded output stays on the device until the request returns. For `num_outputs_per_prompt > 1` the appended output of seed N is still resident when seed N+1 reloads the DiT, so the peak the eviction removed comes back; with a large output even the first request can OOM in decode. **Fix:** on the executor reply rank, move each decoded output to the host inside the same seed iteration while active model-level offload is installed; non-reply ranks keep a metadata placeholder. Video is released after `_prepare_minimax_h3_video_output` quantizes to `uint8`, so vllm-project#6824's transfer optimisation is kept. Other offload modes and the no-offload path are unchanged; the design doc records the exception. ## Test Plan **Reproduce:** 8 XPU cards, TP4xSP2, ref2va at 1344x768 / 124 frames / 50 steps, Cache-DiT and model-level CPU offload for encoders and VAE. The first request finishes denoising (49/49) and then fails in `klvae.py:621 write_part -> torch.empty` with `XPU out of memory. Tried to allocate 1.43 GiB ... 1.42 GiB is free`, HTTP 500. ```bash pytest -q tests/diffusion/models/minimax_h3/test_minimax_h3_offload.py ``` **vLLM Version:** as pinned by `requirements/`. **vLLM-Omni Commit:** rebased onto current `main`. ## Test Result CPU tests pass (release only under active model-level offload; reply rank gets a host tensor, non-reply ranks a placeholder; video copied after quantization; no-offload path unchanged). On the 8-card run with this change: 0 OOM, 3/3 requests HTTP 200, 24 `Evicted 1 DiT module(s) (15.43 GiB)` lines. The device run used one output per prompt; the multi-seed overlap is covered by the CPU tests. Signed-off-by: heyuanliu-intel <heyuan.liu@intel.com>
## Purpose **Problem:** with model-level CPU offload, vllm-project#6072 evicts the DiT before VAE decode, but the decoded output stays on the device until the request returns. For `num_outputs_per_prompt > 1` the appended output of seed N is still resident when seed N+1 reloads the DiT, so the peak the eviction removed comes back; with a large output even the first request can OOM in decode. **Fix:** on the executor reply rank, move each decoded output to the host inside the same seed iteration while active model-level offload is installed; non-reply ranks keep a metadata placeholder. Video is released after `_prepare_minimax_h3_video_output` quantizes to `uint8`, so vllm-project#6824's transfer optimisation is kept. Other offload modes and the no-offload path are unchanged; the design doc records the exception. ## Test Plan **Reproduce:** 8 XPU cards, TP4xSP2, ref2va at 1344x768 / 124 frames / 50 steps, Cache-DiT and model-level CPU offload for encoders and VAE. The first request finishes denoising (49/49) and then fails in `klvae.py:621 write_part -> torch.empty` with `XPU out of memory. Tried to allocate 1.43 GiB ... 1.42 GiB is free`, HTTP 500. ```bash pytest -q tests/diffusion/models/minimax_h3/test_minimax_h3_offload.py ``` **vLLM Version:** as pinned by `requirements/`. **vLLM-Omni Commit:** rebased onto current `main`. ## Test Result CPU tests pass (release only under active model-level offload; reply rank gets a host tensor, non-reply ranks a placeholder; video copied after quantization; no-offload path unchanged). On the 8-card run with this change: 0 OOM, 3/3 requests HTTP 200, 24 `Evicted 1 DiT module(s) (15.43 GiB)` lines. The device run used one output per prompt; the multi-seed overlap is covered by the CPU tests. Signed-off-by: heyuanliu-intel <heyuan.liu@intel.com>
…llm-project#6824) Signed-off-by: lishunyang12 <lishunyang12@163.com>
## Purpose **Problem:** with model-level CPU offload, vllm-project#6072 evicts the DiT before VAE decode, but the decoded output stays on the device until the request returns. For `num_outputs_per_prompt > 1` the appended output of seed N is still resident when seed N+1 reloads the DiT, so the peak the eviction removed comes back; with a large output even the first request can OOM in decode. **Fix:** on the executor reply rank, move each decoded output to the host inside the same seed iteration while active model-level offload is installed; non-reply ranks keep a metadata placeholder. Video is released after `_prepare_minimax_h3_video_output` quantizes to `uint8`, so vllm-project#6824's transfer optimisation is kept. Other offload modes and the no-offload path are unchanged; the design doc records the exception. ## Test Plan **Reproduce:** 8 XPU cards, TP4xSP2, ref2va at 1344x768 / 124 frames / 50 steps, Cache-DiT and model-level CPU offload for encoders and VAE. The first request finishes denoising (49/49) and then fails in `klvae.py:621 write_part -> torch.empty` with `XPU out of memory. Tried to allocate 1.43 GiB ... 1.42 GiB is free`, HTTP 500. ```bash pytest -q tests/diffusion/models/minimax_h3/test_minimax_h3_offload.py ``` **vLLM Version:** as pinned by `requirements/`. **vLLM-Omni Commit:** rebased onto current `main`. ## Test Result CPU tests pass (release only under active model-level offload; reply rank gets a host tensor, non-reply ranks a placeholder; video copied after quantization; no-offload path unchanged). On the 8-card run with this change: 0 OOM, 3/3 requests HTTP 200, 24 `Evicted 1 DiT module(s) (15.43 GiB)` lines. The device run used one output per prompt; the multi-seed overlap is covered by the CPU tests. Signed-off-by: heyuanliu-intel <heyuan.liu@intel.com> (cherry picked from commit ba947d4)
…llm-project#6824) Signed-off-by: lishunyang12 <lishunyang12@163.com>
Purpose
MiniMax-H3 decoded video was returned from the diffusion worker as FP32 BCTHW. A 5-second 1344x768 output therefore moved 1,535,901,696 bytes through the worker-to-engine path before the parent process performed layout conversion and quantization for video encoding.
The worker-to-engine path already provides asynchronous pinned D2H transfer. This PR makes that path substantially cheaper by:
torch.catallocation for the common single-output case; andThere are no new Python or CLI options. The HTTP video response and encoded MP4 are unchanged. The raw MiniMax-H3 offline frame representation changes from float32
[0, 1]to contiguous uint8[0, 255]; callers that consumeOmniRequestOutput.images[0]directly should branch on dtype, as the generic offline video examples already do.Test Plan
The before/after runs and SGLang reference used the same MiniMax-H3 FL2VA BF16 checkpoint, prompt, seed, workload, and top-level parallel degree on 8x NVIDIA B300 SXM6 AC:
encoder_parallel=foldand its native SP8 decoder pathvLLM Version: 0.28.0 (Python 3.12.3, torch 2.13.0+cu130)
vLLM-Omni Commit: baseline
f7f48929db8dcd60c8ce538f4057bec5a789057c; candidatebdfd4847325ed70c88c7046c82acbbf7e7cf9459SGLang Commit:
fe694986a296787cb0ada3b8cd7b6dccd21de72aTest Result
Measured generations were
22.586 / 22.656 / 22.492 sbefore and21.703 / 21.676 / 21.669 safter. Both runs produced a 2,503,544-byte MP4 with the same SHA256:9904a1ae9f0fb86d38cfc43d4398bdacd07c6ca4d289a37eaa87a9965378e6aaThe matching SGLang no-offload/SP8 steady inference times were
18.816 / 18.844 s; its corresponding wall times including MP4 materialization were19.370 / 19.463 s(mean19.417 s). The table compares vLLM-Omnivalid_wave_swith SGLang schedulertotal_duration_ms; both exclude engine shutdown and MP4 materialization. This PR closes 23.9% of the original vLLM-Omni-to-SGLang steady-inference gap, while the remaining vLLM-Omni latency is 2.853 s (15.15%) above SGLang.Validation:
python -m pytest -q tests/diffusion/models/minimax_h3/test_minimax_h3_contract.py tests/entrypoints/openai_api/test_video_api_utils.py— 182 passedupstream/main