[Rebase] Rebase to vllm 0.27.0 (#5976)
Signed-off-by: tzhouam <tzhouam@connect.ust.hk> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
584d78c673
commit
2ce15ab7a0
55 files changed
+1335
-93
No files matched your search
@@ -285,7 +285,17 @@ def test_cached_apply_hf_processor_expands_pair_miss_for_audio_hit_video_miss():
|
||||
captured["mm_cache_keys"] = kwargs["mm_hashes"]
|
||||
return MagicMock(name="mm_kwargs"), {"video": [[]], "audio": [[]]}
|
||||
|
||||
fake_self = SimpleNamespace(cache=cache, info=SimpleNamespace(model_id="m"))
|
||||
fake_self = SimpleNamespace(
|
||||
cache=cache,
|
||||
info=SimpleNamespace(
|
||||
model_id="m",
|
||||
ctx=SimpleNamespace(
|
||||
get_mm_config=lambda: SimpleNamespace(
|
||||
mm_hasher_algorithm="sha256",
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
fake_self._get_hf_mm_data = MagicMock(return_value=({}, {}))
|
||||
# Bound methods called via self inside _cached_apply_hf_processor.
|
||||
fake_self._get_audio_in_video_pairs = lambda mm_data_items, hf_processor_mm_kwargs: (
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
"""Regression tests for the Qwen3-Omni thinker forward return contract.
|
||||
|
||||
Background
|
||||
----------
|
||||
Since omni architectures unconditionally override upstream's registry entries,
|
||||
``Qwen3OmniMoeForConditionalGeneration`` (and the standalone thinker) are also
|
||||
constructed by plain, non-staged vLLM runs — e.g. ``vllm serve
|
||||
Qwen/Qwen3-Omni-30B-A3B-Instruct`` in the nightly vLLM-text perf job. Stock
|
||||
vLLM's ``GPUModelRunner`` indexes the forward output directly
|
||||
(``hidden_states[logit_indices]``), so a thinker forward that always returns a
|
||||
``(hidden_states, captured_hidden_states)`` tuple kills the engine during
|
||||
``profile_run`` with ``TypeError: only integer tensors of a single element can
|
||||
be converted to an index`` (Buildkite build 2952).
|
||||
|
||||
Contract under test:
|
||||
|
||||
- No capture requested → the forward returns a **bare tensor** (stock-runner
|
||||
compatible).
|
||||
- Capture requested (``capture_layer_indices`` + ``return_hidden_states``,
|
||||
staged runs with a talker downstream) → the forward returns the
|
||||
``(hidden_states, captured_layer_dict)`` tuple omni's runner consumes via
|
||||
``make_omni_output``.
|
||||
- The combined model requests capture only in staged runs
|
||||
(``model_config.model_stage`` injected), never in plain vLLM runs.
|
||||
- ``make_omni_output`` tolerates both return shapes.
|
||||
|
||||
Pure shape/contract tests: CPU-only, no weights, no GPU.
|
||||
"""
|
||||
|
||||
from types import SimpleNamespace
|
||||
|
||||
import pytest
|
||||
import torch
|
||||
from torch import nn
|
||||
from vllm.sequence import IntermediateTensors
|
||||
|
||||
from vllm_omni.model_executor.models.output_templates import OmniOutput
|
||||
from vllm_omni.model_executor.models.qwen3_omni.qwen3_omni import (
|
||||
Qwen3OmniMoeForConditionalGeneration,
|
||||
)
|
||||
from vllm_omni.model_executor.models.qwen3_omni.qwen3_omni_moe_thinker import (
|
||||
Qwen3OmniMoeThinkerForConditionalGeneration,
|
||||
)
|
||||
|
||||
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
||||
|
||||
_HIDDEN = 8
|
||||
_TOKENS = 4
|
||||
|
||||
|
||||
def _hidden_states() -> torch.Tensor:
|
||||
return torch.zeros(_TOKENS, _HIDDEN)
|
||||
|
||||
|
||||
class _InnerModelStub:
|
||||
"""Stands in for ``Qwen3MoeLLMModel``: always returns the internal 2-tuple."""
|
||||
|
||||
def __init__(self, output=None):
|
||||
self.calls: list[dict] = []
|
||||
self._output = output
|
||||
|
||||
def __call__(self, input_ids, positions, intermediate_tensors, **kwargs):
|
||||
self.calls.append(kwargs)
|
||||
if self._output is not None:
|
||||
return self._output
|
||||
if kwargs.get("return_hidden_states"):
|
||||
return _hidden_states(), {"hidden_states": {"layers": {0: _hidden_states()}}}
|
||||
return _hidden_states(), None
|
||||
|
||||
|
||||
def _make_thinker(inner_output=None) -> tuple[Qwen3OmniMoeThinkerForConditionalGeneration, _InnerModelStub]:
|
||||
thinker = object.__new__(Qwen3OmniMoeThinkerForConditionalGeneration)
|
||||
nn.Module.__init__(thinker)
|
||||
inner = _InnerModelStub(output=inner_output)
|
||||
thinker.use_deepstack = False
|
||||
thinker.language_model = SimpleNamespace(model=inner)
|
||||
return thinker, inner
|
||||
|
||||
|
||||
def _forward_args():
|
||||
return {
|
||||
"input_ids": torch.zeros(_TOKENS, dtype=torch.long),
|
||||
"positions": torch.arange(_TOKENS),
|
||||
}
|
||||
|
||||
|
||||
def test_thinker_forward_returns_bare_tensor_without_capture():
|
||||
thinker, _ = _make_thinker()
|
||||
out = thinker.forward(**_forward_args())
|
||||
assert isinstance(out, torch.Tensor)
|
||||
assert out.shape == (_TOKENS, _HIDDEN)
|
||||
|
||||
|
||||
def test_thinker_forward_returns_tuple_when_capturing():
|
||||
thinker, _ = _make_thinker()
|
||||
out = thinker.forward(
|
||||
**_forward_args(),
|
||||
capture_layer_indices=[0, 2],
|
||||
return_hidden_states=True,
|
||||
)
|
||||
assert isinstance(out, tuple)
|
||||
hidden, captured = out
|
||||
assert isinstance(hidden, torch.Tensor)
|
||||
assert "hidden_states" in captured
|
||||
|
||||
|
||||
def test_thinker_forward_passes_through_intermediate_tensors():
|
||||
it = IntermediateTensors({"hidden_states": _hidden_states(), "residual": _hidden_states()})
|
||||
thinker, _ = _make_thinker(inner_output=it)
|
||||
out = thinker.forward(**_forward_args())
|
||||
assert out is it
|
||||
|
||||
|
||||
class _ThinkerStub(nn.Module):
|
||||
"""Records capture kwargs; mirrors the fixed thinker return contract."""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.received: dict = {}
|
||||
|
||||
def forward(self, **kwargs):
|
||||
self.received = kwargs
|
||||
if kwargs.get("return_hidden_states"):
|
||||
return _hidden_states(), {"hidden_states": {"layers": {}}}
|
||||
return _hidden_states()
|
||||
|
||||
|
||||
def _make_combined(*, is_staged_run: bool, accept_hidden_layer=6) -> Qwen3OmniMoeForConditionalGeneration:
|
||||
model = object.__new__(Qwen3OmniMoeForConditionalGeneration)
|
||||
nn.Module.__init__(model)
|
||||
model.model_stage = "thinker"
|
||||
model.is_staged_run = is_staged_run
|
||||
model.talker_config = SimpleNamespace(accept_hidden_layer=accept_hidden_layer)
|
||||
model.thinker = _ThinkerStub()
|
||||
return model
|
||||
|
||||
|
||||
def test_combined_forward_plain_run_skips_capture_and_returns_tensor():
|
||||
model = _make_combined(is_staged_run=False)
|
||||
out = model.forward(**_forward_args())
|
||||
assert "capture_layer_indices" not in model.thinker.received
|
||||
assert isinstance(out, torch.Tensor)
|
||||
|
||||
|
||||
def test_combined_forward_staged_run_captures_and_returns_tuple():
|
||||
model = _make_combined(is_staged_run=True)
|
||||
out = model.forward(**_forward_args())
|
||||
assert model.thinker.received["capture_layer_indices"] == [0, 6]
|
||||
assert model.thinker.received["return_hidden_states"] is True
|
||||
assert isinstance(out, tuple)
|
||||
|
||||
|
||||
def test_combined_forward_staged_run_without_accept_layer_returns_tensor():
|
||||
model = _make_combined(is_staged_run=True, accept_hidden_layer=None)
|
||||
out = model.forward(**_forward_args())
|
||||
assert "capture_layer_indices" not in model.thinker.received
|
||||
assert isinstance(out, torch.Tensor)
|
||||
|
||||
|
||||
def test_make_omni_output_accepts_bare_tensor():
|
||||
model = _make_combined(is_staged_run=False)
|
||||
out = model.make_omni_output(_hidden_states())
|
||||
assert isinstance(out, OmniOutput)
|
||||
assert out.text_hidden_states.shape == (_TOKENS, _HIDDEN)
|
||||
assert out.multimodal_outputs == {}
|
||||
|
||||
|
||||
def test_make_omni_output_accepts_capture_tuple():
|
||||
model = _make_combined(is_staged_run=True)
|
||||
captured = {"hidden_states": {"layers": {}}}
|
||||
out = model.make_omni_output((_hidden_states(), captured))
|
||||
assert isinstance(out, OmniOutput)
|
||||
assert out.multimodal_outputs == captured
|
||||
Reference in new issue
Block a user