fix(multimodal): handle tensor images in exact-token preprocessing (#30368)

Signed-off-by: Zhuangcheng(Jesse) Gu <zcgu@connect.hku.hk>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: Mick <mickjagger19@icloud.com>
This commit is contained in:
Zhuangcheng(Jesse) Gu
2026-09-17 09:20:21 -07:00
committed by GitHub
co-authored by gemini-code-assist[bot] Mick
parent e4cbb28ea1
commit 25c9f724d4
2 changed files with 13 additions and 3 deletions
@@ -1732,7 +1732,14 @@ class BaseMultimodalProcessor(ABC):
""" """
assert images is not None assert images is not None
image_sizes = [(image.height, image.width) for image in images] image_sizes = [
(
tuple(image.shape[-2:])
if isinstance(image, torch.Tensor)
else (image.height, image.width)
)
for image in images
]
num_image_tokens = self._processor._get_num_multimodal_tokens( num_image_tokens = self._processor._get_num_multimodal_tokens(
image_sizes=image_sizes image_sizes=image_sizes
).num_image_tokens ).num_image_tokens
@@ -9,6 +9,9 @@ With SGLANG_MM_AVOID_RETOKENIZE ON (default), the server keeps the user's
original tokens verbatim and only expands the image placeholder, so prompt_tokens original tokens verbatim and only expands the image placeholder, so prompt_tokens
stays faithful to what the client sent. stays faithful to what the client sent.
The test uses JPEG so CUDA decoding returns a CHW tensor, covering the same
exact-token path as PIL-backed images.
For each model we launch a real server twice with the same predefined, For each model we launch a real server twice with the same predefined,
non-canonical prompt ("Describe" split into "D"+"escribe") plus one image: non-canonical prompt ("Describe" split into "D"+"escribe") plus one image:
@@ -42,8 +45,8 @@ register_cpu_ci(est_time=123, suite="stage-b-test-cpu-intel")
def _data_uri(): def _data_uri():
img = Image.new("RGB", (64, 64), (128, 128, 128)) img = Image.new("RGB", (64, 64), (128, 128, 128))
buf = io.BytesIO() buf = io.BytesIO()
img.save(buf, format="PNG") img.save(buf, format="JPEG")
return "data:image/png;base64," + base64.b64encode(buf.getvalue()).decode() return "data:image/jpeg;base64," + base64.b64encode(buf.getvalue()).decode()
def _build_drift_prompt(model, image_token): def _build_drift_prompt(model, image_token):