[Bugfix] Fix MiniCPM-o 4.5 audio placeholder pool step (#5116)

Signed-off-by: a-kaa <siruhe666@gmail.com>
Co-authored-by: amy-why-3459 <wuhaiyan17@huawei.com>
This commit is contained in:
Hongshaorouandamy-why-3459 authored and GitHub committed 2026-07-21 15:44:05 +08:00
1 parent 5d44868e91
commit 0576264dd1
2 files changed
+76 -2

No files matched your search

@@ -0,0 +1,71 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
"""Regression tests for MiniCPM-o 4.5 audio placeholder pooling."""
from __future__ import annotations
import math
from types import SimpleNamespace
import pytest
from vllm_omni.model_executor.models.minicpmo_4_5.minicpmo_4_5_omni_llm import (
MiniCPMO45OmniLLMProcessingInfo,
MiniCPMOConfig,
)
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
class _FakeProcessor:
"""Minimal processor surface used by ``get_audio_placeholder``."""
def __init__(self) -> None:
# Reproduce the cached vLLM processor's legacy initial state.
self.pool_step = 2
self.audio_processor = SimpleNamespace(hop_length=160)
self.image_processor = SimpleNamespace(mean=[0.0], std=[1.0])
def get_audio_placeholder(
self,
audio_lens: int,
chunk_input: bool = True,
chunk_length: int = 1,
) -> str:
del chunk_input, chunk_length
feature_lens = math.ceil(audio_lens / self.audio_processor.hop_length)
cnn_feature_lens = (feature_lens - 1) // 2 + 1
output_lens = (cnn_feature_lens - self.pool_step) // self.pool_step + 1
return "<unk>" * output_lens
def _processing_info(pool_step: int, processor: _FakeProcessor) -> MiniCPMO45OmniLLMProcessingInfo:
info = object.__new__(MiniCPMO45OmniLLMProcessingInfo)
info.ctx = SimpleNamespace(
tokenizer=object(),
get_hf_config=lambda: SimpleNamespace(audio_pool_step=pool_step),
get_hf_processor=lambda **kwargs: processor,
)
return info
@pytest.mark.parametrize(
("configured_pool_step", "expected_placeholders"),
[(5, 50), (2, 125)],
)
def test_audio_placeholders_follow_checkpoint_pool_step(
configured_pool_step: int,
expected_placeholders: int,
) -> None:
"""The prompt path must use the same pool step as the audio encoder."""
processor = _FakeProcessor()
info = _processing_info(configured_pool_step, processor)
placeholder = info.get_audio_placeholder(5 * 16_000)
assert processor.pool_step == configured_pool_step
assert placeholder.count("<unk>") == expected_placeholders
def test_minicpmo_4_5_pool_step_defaults_to_checkpoint_value() -> None:
assert MiniCPMOConfig().audio_pool_step == 5
@@ -328,7 +328,7 @@ class MiniCPMOConfig(Qwen2Config):
tts_config=None,
use_image_id=True,
vision_batch_size=16,
audio_pool_step=2,
audio_pool_step=5,
audio_chunk_length=1.0,
stream_input=False,
init_vision=True,
@@ -2839,6 +2839,9 @@ class MiniCPMO45OmniLLMProcessingInfo(BaseProcessingInfo):
) -> str:
hf_processor = self.get_hf_processor()
# Keep prompt placeholders aligned with the encoder's checkpoint config.
hf_processor.pool_step = self.get_default_audio_pool_step()
return hf_processor.get_audio_placeholder(
audio_lens,
chunk_input=chunk_input,
@@ -2846,7 +2849,7 @@ class MiniCPMO45OmniLLMProcessingInfo(BaseProcessingInfo):
)
def get_default_audio_pool_step(self) -> int:
return getattr(self.get_hf_config(), "audio_pool_step", 2)
return getattr(self.get_hf_config(), "audio_pool_step", 5)
def get_default_audio_sampling_rate(self) -> int:
return 16000