[CI] Replace rigid beam search assertions with semantic term matching

Signed-off-by: Andreas Karatzas <akaratza@amd.com>
This commit is contained in:
Andreas Karatzas 2025-12-24 22:45:29 +00:00
parent bc5ef333e0
commit 0867becc6e
No known key found for this signature in database
GPG Key ID: 74A33CBB22F03519

View File

@ -2,6 +2,7 @@
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
import json import json
import warnings
import openai import openai
import pytest import pytest
@ -25,45 +26,33 @@ TEST_IMAGE_ASSETS = [
"RGBA_comp.png", # "https://vllm-public-assets.s3.us-west-2.amazonaws.com/vision_model_images/RGBA_comp.png", "RGBA_comp.png", # "https://vllm-public-assets.s3.us-west-2.amazonaws.com/vision_model_images/RGBA_comp.png",
] ]
EXPECTED_MM_BEAM_SEARCH_RES = [ # Required terms for beam search validation
[ # Each entry is a list of term groups - ALL groups must match
"The image shows a wooden boardwalk leading through a", # Each group is a list of alternatives - at least ONE term in the group must appear
"The image shows a wooden boardwalk extending into a", # This provides semantic validation while allowing wording variation
], REQUIRED_BEAM_SEARCH_TERMS = [
[ # Boardwalk image: must have "boardwalk" AND ("wooden" or "wood")
"The image shows two parrots perched on", [["boardwalk"], ["wooden", "wood"]],
"The image shows two birds perched on a cur", # Parrots image: must have ("parrot" or "bird") AND "two"
], [["parrot", "bird"], ["two"]],
[ # Venn diagram: must have "venn" AND "diagram"
"The image shows a Venn diagram with three over", [["venn"], ["diagram"]],
"The image displays a Venn diagram with three over", # Gradient image: must have "gradient" AND ("color" or "spectrum")
], [["gradient"], ["color", "spectrum"]],
[
"This image displays a gradient of colors ranging from",
"This image displays a gradient of colors forming a spectrum",
],
] ]
EXPECTED_MM_BEAM_SEARCH_RES_ROCM = [
# MultiHeadAttention attn_backend: FLASH_ATTN def check_output_matches_terms(content: str, term_groups: list[list[str]]) -> bool:
# with Triton Attention backend """
[ Check if content matches all required term groups.
"The image shows a wooden boardwalk leading through a", Each term group requires at least one of its terms to be present.
"The image shows a wooden boardwalk extending into a", All term groups must be satisfied.
], """
[ content_lower = content.lower()
"The image shows two parrots perched on", for group in term_groups:
"The image shows two birds perched on a cur", if not any(term.lower() in content_lower for term in group):
], return False
[ return True
"The image shows a Venn diagram with three over",
"The image contains a Venn diagram with three over",
],
[
"This image displays a gradient of colors ranging from",
"This image displays a gradient of colors transitioning from",
],
]
@pytest.fixture(scope="module") @pytest.fixture(scope="module")
@ -319,16 +308,9 @@ async def test_single_chat_session_image_base64encoded_beamsearch(
image_idx: int, image_idx: int,
url_encoded_image: dict[str, str], url_encoded_image: dict[str, str],
): ):
# ROCm: Switch expected results based on platform # NOTE: This test validates that we pass MM data through beam search
from vllm.platforms import current_platform
# NOTE: This test also validates that we pass MM data through beam search
raw_image_url = TEST_IMAGE_ASSETS[image_idx] raw_image_url = TEST_IMAGE_ASSETS[image_idx]
required_terms = REQUIRED_BEAM_SEARCH_TERMS[image_idx]
if current_platform.is_rocm():
expected_res = EXPECTED_MM_BEAM_SEARCH_RES_ROCM[image_idx]
else:
expected_res = EXPECTED_MM_BEAM_SEARCH_RES[image_idx]
messages = dummy_messages_from_image_url(url_encoded_image[raw_image_url]) messages = dummy_messages_from_image_url(url_encoded_image[raw_image_url])
@ -341,8 +323,31 @@ async def test_single_chat_session_image_base64encoded_beamsearch(
extra_body=dict(use_beam_search=True), extra_body=dict(use_beam_search=True),
) )
assert len(chat_completion.choices) == 2 assert len(chat_completion.choices) == 2
for actual, expected_str in zip(chat_completion.choices, expected_res):
assert actual.message.content == expected_str # Verify beam search produces two different non-empty outputs
content_0 = chat_completion.choices[0].message.content
content_1 = chat_completion.choices[1].message.content
# Emit warning with beam search outputs for debugging
warnings.warn(
f"Beam search outputs for image {image_idx} ({raw_image_url}): "
f"Output 0: {content_0!r}, Output 1: {content_1!r}",
UserWarning,
stacklevel=1,
)
assert content_0, "First beam search output should not be empty"
assert content_1, "Second beam search output should not be empty"
assert content_0 != content_1, "Beam search should produce different outputs"
# Verify each output contains the required terms for this image
for i, content in enumerate([content_0, content_1]):
if not check_output_matches_terms(content, required_terms):
pytest.fail(
f"Output {i} '{content}' doesn't contain required terms. "
f"Expected all of these term groups (at least one from each): "
f"{required_terms}"
)
@pytest.mark.asyncio @pytest.mark.asyncio