rebase: align vllm-omni with vLLM ac9126e58aa7

Signed-off-by: tzhouam <tzhouam@connect.ust.hk>
This commit is contained in:
tzhouam committed 2026-10-02 10:37:50 +08:00
1 parent 383cc5ef1d
commit 2721f16ca8
93 files changed
+1908 -547

No files matched your search

@@ -42,10 +42,26 @@ def _make_processor(monkeypatch: pytest.MonkeyPatch) -> OmniVoiceMultiModalProce
return processor
class _FakeProcessorItem:
def __init__(self, processor_data: dict[str, object]) -> None:
self._processor_data = processor_data
def get_processor_data(self) -> dict[str, object]:
return dict(self._processor_data)
def get_passthrough_data(self) -> dict[str, object]:
return {}
def _items(counts: dict[str, int], mm_data: dict[str, object]) -> SimpleNamespace:
class _Selected:
@staticmethod
def values():
return [_FakeProcessorItem(mm_data)] if mm_data else []
return SimpleNamespace(
get_all_counts=lambda: counts,
select=lambda _keys: mm_data,
select=lambda _keys: _Selected(),
)
@@ -75,9 +91,8 @@ def test_apply_tokenizes_the_prompt_once(monkeypatch: pytest.MonkeyPatch) -> Non
def test_media_path_encodes_audio_without_retokenizing(monkeypatch: pytest.MonkeyPatch) -> None:
processor = _make_processor(monkeypatch)
audio = np.zeros(2400, dtype=np.float32)
monkeypatch.setattr(processor, "_get_hf_mm_data", lambda _items: ({"audios": [audio]}, {}))
out = processor._apply_hf_processor_main(_items({"audio": 1}, {}), {"ref_text": "reference"})
out = processor._apply_hf_processor_main(_items({"audio": 1}, {"audios": [audio]}), {"ref_text": "reference"})
assert tuple(out["ref_audio_tokens"].shape) == (8, 4)
assert list(out["ref_audio_len"]) == [4]
@@ -89,7 +104,6 @@ def test_media_path_encodes_audio_without_retokenizing(monkeypatch: pytest.Monke
def test_media_path_with_no_audio_touches_no_tokenizer(monkeypatch: pytest.MonkeyPatch) -> None:
"""Text-only requests and fully cached audio both reach this path with empty items."""
processor = _make_processor(monkeypatch)
monkeypatch.setattr(processor, "_get_hf_mm_data", lambda _items: ({}, {}))
out = processor._apply_hf_processor_main(_items({}, {}), {"ref_text": "reference"})
@@ -99,4 +113,6 @@ def test_media_path_with_no_audio_touches_no_tokenizer(monkeypatch: pytest.Monke
def test_legacy_call_hf_processor_is_gone() -> None:
assert not hasattr(OmniVoiceMultiModalProcessor, "_call_hf_processor")
# Upstream reintroduced a 2-arg `_call_hf_processor` on the base class; the
# omni-specific 4-arg hook must not be defined on the omni class itself.
assert "_call_hf_processor" not in OmniVoiceMultiModalProcessor.__dict__
@@ -262,6 +262,7 @@ def test_cached_apply_hf_processor_expands_pair_miss_for_audio_hit_video_miss():
"audio": 1,
}[modality]
mm_data_items.__getitem__ = MagicMock(side_effect=lambda modality: [f"{modality}-0"])
mm_data_items.values = MagicMock(return_value=[])
inputs = MagicMock()
inputs.mm_data_items = mm_data_items
@@ -275,6 +276,7 @@ def test_cached_apply_hf_processor_expands_pair_miss_for_audio_hit_video_miss():
cache = MagicMock()
# Video miss, audio hit under pair-aware keys — expansion must force audio.
cache.is_cached.side_effect = lambda keys: [False] if keys[0].startswith("v") else [True]
inputs.cache = cache
captured = {}
@@ -309,6 +311,8 @@ def test_cached_apply_hf_processor_expands_pair_miss_for_audio_hit_video_miss():
fake_self._get_mm_fields_config = MagicMock(return_value={})
fake_self._get_mm_prompt_updates = MagicMock(return_value={"video": [[object()]], "audio": [[object()]]})
fake_self._merge_mm_kwargs = capture_merge
fake_self._postprocess_prompt = lambda prompt: prompt
inputs.prompt = [0, 1, 2]
with patch(
"vllm_omni.model_executor.models.qwen2_5_omni.qwen2_5_omni_thinker.MultiModalKwargsItems.from_hf_inputs",
@@ -549,24 +553,6 @@ def test_qwen2_5_prompt_updates_validate_mask_against_request_video_count():
)
def test_qwen2_5_mm_only_dummy_counts_subtract_only_videos_using_audio():
captured_counts = {}
fake_self = SimpleNamespace(
dummy_inputs=SimpleNamespace(get_dummy_text=lambda counts: captured_counts.update(counts) or "dummy"),
_apply_hf_processor_text_mm=lambda **_kwargs: ([], {}, False),
)
mm_items = SimpleNamespace(get_all_counts=lambda: {"video": 2, "audio": 1})
Qwen2_5OmniThinkerMultiModalProcessor._apply_hf_processor_mm_only(
fake_self,
mm_items,
{"use_audio_in_video": [True, False]},
{},
)
assert captured_counts == {"video": 2, "audio": 0}
def test_get_video_use_audio_in_video_falls_back_to_prompt_updates_for_cache_hits():
fake_self = _fake_processor()
update_with_audio = SimpleNamespace(content=SimpleNamespace(full=[VIDEO_TOKEN_ID, AUDIO_TOKEN_ID]))
@@ -661,7 +647,12 @@ def test_qwen3_processor_inherits_vllm_omni_per_video_helpers():
Qwen3OmniMoeThinkerMultiModalProcessor,
Qwen2_5OmniThinkerMultiModalProcessor,
)
assert Qwen3OmniMoeThinkerMultiModalProcessor._get_hf_mm_data is UpstreamQwen3Processor._get_hf_mm_data
# Keep Qwen3's native HF preprocessing while inheriting Omni pair handling.
assert Qwen3OmniMoeThinkerMultiModalProcessor._get_hf_mm_inputs is UpstreamQwen3Processor._get_hf_mm_inputs
assert (
Qwen3OmniMoeThinkerMultiModalProcessor._get_audio_in_video_pairs
is Qwen2_5OmniThinkerMultiModalProcessor._get_audio_in_video_pairs
)
mro = Qwen3OmniMoeThinkerMultiModalProcessor.__mro__
assert mro.index(Qwen2_5OmniThinkerMultiModalProcessor) < mro.index(UpstreamQwen3Processor)
@@ -79,31 +79,16 @@ def get_text_token_prompts(
"""Return ``(text_prompt, token_prompt)`` for the given multimodal data."""
dummy_inputs = processor.dummy_inputs
tokenizer: TokenizerLike = processor.info.get_tokenizer()
model_config = processor.info.ctx.model_config
parsed_data = processor.info.parse_mm_data(mm_data)
mm_counts = {k: len(vs) for k, vs in parsed_data.items()}
inputs = dummy_inputs.get_dummy_processor_inputs(
model_config.max_model_len,
mm_counts,
mm_options={},
text_prompt = dummy_inputs.get_dummy_text(mm_counts)
token_prompt = tokenizer.encode(
text_prompt,
**processor.info.get_default_tok_params().get_encode_kwargs(),
)
text_prompt: str | None
token_prompt: list[int]
if isinstance(inputs.prompt, list):
text_prompt = None
token_prompt = inputs.prompt
elif isinstance(inputs.prompt, str):
text_prompt = inputs.prompt
token_prompt = tokenizer.encode(
text_prompt,
**processor.info.get_default_tok_params().get_encode_kwargs(),
)
else:
raise TypeError(type(inputs.prompt))
return text_prompt, token_prompt
@@ -199,8 +184,8 @@ def _test_processing_correctness(
modality: _to_dummy_options(modality, count) for modality, count in limit_mm_per_prompt_ints.items()
}
baseline_processor = factories.build_processor(ctx, cache=None)
cached_processor = factories.build_processor(ctx, cache=cache)
baseline_processor = factories.build_processor(ctx)
cached_processor = factories.build_processor(ctx)
rng = np.random.RandomState(0)
@@ -238,6 +223,7 @@ def _test_processing_correctness(
baseline_processor,
cached_processor,
batch_idx,
cache,
)
@@ -247,6 +233,7 @@ def _test_processing_correctness_one(
baseline_processor: BaseMultiModalProcessor,
cached_processor: BaseMultiModalProcessor,
batch_idx: int,
cache: MultiModalProcessorOnlyCache,
):
model_type = model_config.hf_config.model_type
@@ -258,12 +245,14 @@ def _test_processing_correctness_one(
token_prompt,
mm_items=mm_items,
hf_processor_mm_kwargs={},
cache=None,
)
cached_tokenized_result = cached_processor(
token_prompt,
mm_items=mm_items,
hf_processor_mm_kwargs={},
cache=cache,
)
_assert_inputs_equal(
@@ -278,11 +267,13 @@ def _test_processing_correctness_one(
text_prompt,
mm_items=mm_items,
hf_processor_mm_kwargs={},
cache=None,
)
cached_text_result = cached_processor(
text_prompt,
mm_items=mm_items,
hf_processor_mm_kwargs={},
cache=cache,
)
_assert_inputs_equal(