[Bugfix][Frontend] Honor output_compression on the image generations route (#7447)

Signed-off-by: hsliu_ustc <hsliu_ustc@noreply.gitcode.com>
Signed-off-by: amy-why-3459 <wuhaiyan17@huawei.com>
Co-authored-by: amy-why-3459 <wuhaiyan17@huawei.com>
This commit is contained in:
Hongsheng Liuandamy-why-3459 authored and GitHub committed 2026-09-13 10:05:56 +08:00
1 parent f7d9deb45a
commit 01a2f93256
4 files changed
+101 -1

No files matched your search

+33
View File
@@ -452,6 +452,39 @@ curl -s http://localhost:8091/v1/chat/completions \
- **Known limitations:** the same single-GPU limitations as Base and Edit apply;
CPU offload, Cache-DiT, and multi-GPU parallelism are not yet validated.
## Output format and compression
Image requests accept `output_format` (`png`, `jpeg`, or `webp`) and
`output_compression` (0-100). The default is `png` with the fastest,
least-compressed PNG encode, which is lossless but produces multi-megabyte
payloads. For latency-sensitive clients, `output_format: "jpeg"` removes
almost the entire response-encoding overhead: on a 1024x1024 Turbo request
the client-observed e2e latency drops from ~900 ms to ~766 ms and the
payload shrinks from ~3.1 MB to ~0.8 MB. Use `output_compression` to trade
encode time against payload size when PNG must stay lossless: lower values
(e.g. 1) compress harder and produce smaller payloads at proportionally
longer encode times.
## Attention backend
The diffusion attention backend defaults to `FLASH_ATTN` (FlashAttention-2).
On Hopper-class GPUs (SM90) pass `--diffusion-attention-backend CUDNN_ATTN`
for a measured ~12% engine-time reduction on Boogu-Image workloads:
```bash
vllm serve Boogu/Boogu-Image-0.1-Turbo \
--omni \
--diffusion-attention-backend CUDNN_ATTN \
--port 8091
```
Measured on a 143 GB SM90 card (1024x1024, 4 steps, 5-run mean): stage time
673 ms with `CUDNN_ATTN` vs 763 ms with the default. Outputs are numerically
different from FLASH_ATTN (different attention kernel) but visually
equivalent, deterministic per seed, and decode identically. On datacenter
Blackwell (SM100 / SM103) use `--diffusion-attention-backend TRTLLM_ATTN`
instead; it is rejected on SM90.
## Performance validation
The checked-in single-device A40 measurements remain the current Boogu
@@ -0,0 +1,54 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""L1 tests for the image response encoder's compression contract."""
import base64
import io
import pytest
from PIL import Image
from vllm_omni.entrypoints.openai.image_api_utils import (
encode_image_base64_with_compression,
)
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
@pytest.fixture(scope="module")
def image():
# Photographic-content proxy: noise-plus-gradient content compresses very
# differently across PNG compress levels, which is what the mapping under
# test controls.
import numpy as np
rng = np.random.default_rng(0)
grad = np.linspace(0, 255, 256, dtype=np.float32)
arr = np.clip(grad[None, :, None] + rng.integers(-24, 25, (256, 256, 3)), 0, 255).astype(np.uint8)
return Image.fromarray(arr, mode="RGB")
def test_png_output_compression_maps_to_compress_level(image):
"""output_compression 100 -> compress_level 0, 1 -> compress_level 9."""
def encode(compression):
buffer = io.BytesIO()
image.save(buffer, format="PNG", compress_level=max(0, min(9, 9 - compression // 11)))
return len(base64.b64encode(buffer.getvalue()))
fast = encode_image_base64_with_compression(image, format="png", output_compression=100)
small = encode_image_base64_with_compression(image, format="png", output_compression=1)
# Level-0 PNG barely compresses; the mapped level-9 encode is smaller.
assert len(small) < len(fast)
# The mapping must produce the same sizes as the equivalent compress_level.
assert len(fast) == encode(100)
assert len(small) == encode(1)
def test_jpeg_output_compression_maps_to_quality(image):
high = base64.b64decode(encode_image_base64_with_compression(image, format="jpeg", output_compression=100))
low = base64.b64decode(encode_image_base64_with_compression(image, format="jpeg", output_compression=10))
assert len(high) > len(low)
+3 -1
View File
@@ -1605,7 +1605,9 @@ def _build_image_generation_response(
output_format = _choose_output_format(request.output_format or "png", None)
image_data = [
ImageData(
b64_json=encode_image_base64_with_compression(image, format=output_format),
b64_json=encode_image_base64_with_compression(
image, format=output_format, output_compression=request.output_compression
),
revised_prompt=None,
)
for image in images
@@ -175,6 +175,17 @@ class ImageGenerationRequest(BaseModel):
default=None,
description="Output image format: 'png', 'jpeg', or 'webp'. Defaults to 'png'.",
)
output_compression: int = Field(
default=100,
ge=0,
le=100,
description=(
"Compression level 0-100. For 'jpeg'/'webp' this is the encoder "
"quality. For 'png' 100 keeps the fastest, least-compressed "
"encode and lower values trade encode time for smaller payloads "
"(100 -> compress_level 0, 1 -> compress_level 9)."
),
)
return_stage_metrics: bool | None = Field(
default=None,
description="Return stage metrics for benchmark clients.",