[Model] Default MOSS Local 1.5 to adaptive CUDA MRV2 with MPS (#8438)

Signed-off-by: Sy03 <1370724210@qq.com>
This commit is contained in:
Sy03 authored and GitHub committed 2026-10-06 08:20:46 -07:00
1 parent ee9ab9ea88
commit 7be49aa0ce
30 files changed
+808 -152

No files matched your search

@@ -318,26 +318,45 @@ def test_failed_output_handoff_retains_decoded_samples(cuda):
fast.close()
@pytest.mark.cpu
@pytest.mark.parametrize("enabled,complete", [(False, False), (True, False), (True, True), (True, None)])
def test_gate_waits_only_for_enabled_inflight_decode(mocker, enabled, complete):
# A fixed GPU sleep cannot prove that an event is still pending when the
# host reaches gate(), particularly across CUDA and ROCm implementations.
fast = object.__new__(MossFirstChunkFastPath)
fast._device = torch.device("cuda")
fast._gate_main = enabled
event = None if complete is None else mocker.Mock()
if event is not None:
event.query.return_value = complete
fast._inflight = event
stream = mocker.Mock()
current_stream = mocker.patch("torch.cuda.current_stream", return_value=stream)
fast.gate()
if enabled and complete is False:
current_stream.assert_called_once_with(fast._device)
stream.wait_event.assert_called_once_with(event)
else:
current_stream.assert_not_called()
stream.wait_event.assert_not_called()
@pytest.mark.cuda
def test_gate_orders_main_stream_after_inflight_fast_decode(cuda):
def test_gate_hands_inflight_gpu_output_to_main_stream(cuda):
fast, _, _ = _fast(cuda)
side = torch.cuda.Stream()
output = torch.zeros(16, device=cuda)
side.wait_stream(torch.cuda.current_stream())
with torch.cuda.stream(side):
torch.cuda._sleep(200_000_000)
output.fill_(7)
pending = torch.cuda.Event()
pending.record(side)
fast._inflight = pending
fast.gate() # disabled: no wait
unordered = torch.cuda.Event()
unordered.record()
fast._gate_main = True
fast.gate()
ordered = torch.cuda.Event()
ordered.record()
unordered.synchronize()
assert not pending.query() and not ordered.query()
ordered.synchronize()
assert pending.query()
received = output.clone()
torch.testing.assert_close(received, torch.full_like(received, 7))
fast.close()
def _cpu_fast(monkeypatch, *, scheduler=None):
@@ -545,3 +564,41 @@ def test_platform_failure_wakes_pending_handoff(monkeypatch):
assert fast._closed
with pytest.raises(RuntimeError, match="decode failed"):
fast.order_after(0)
@pytest.mark.cpu
@pytest.mark.tts
@pytest.mark.parametrize("limit", [1, 2])
def test_congested_admission_preserves_routes_and_slots_then_recovers(monkeypatch, limit):
import sys
from functools import partial
helpers = sys.modules[__name__]
from vllm_omni.model_executor.models.moss_tts.first_chunk_fast_path import MossFirstChunkFastPath
monkeypatch.setattr(helpers, "MossFirstChunkFastPath", partial(MossFirstChunkFastPath, max_active_streams=limit))
fast, session, sink, _ = helpers._cpu_fast(monkeypatch)
calls = []
class Sink:
def prepare(self, ids):
calls.append(ids)
return sink.prepare(ids)
fast._sink = Sink()
thread = threading.Thread()
monkeypatch.setattr(thread, "is_alive", lambda: True)
fast._thread = thread
slots = {f"busy{i}": session.acquire() for i in range(limit)}
before_slots, before_free = slots.copy(), session.free.copy()
codes = torch.tensor([1, 2])
assert not fast.submit("r", "r", codes, slots)
assert slots == before_slots and session.free == before_free
assert not calls and not fast._decoded and not fast._handoffs and fast._jobs.empty()
released = slots.pop("busy0")
session.release(released)
assert fast.submit("r", "r", codes, slots)
codes.fill_(99)
job = fast._jobs.get_nowait()
assert job.slot == slots["r"] and calls == [["r"]]
assert job.codes.tolist() == [[1], [2]]
@@ -0,0 +1,48 @@
# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Deployment sampler settings override the legacy environment switch."""
import pytest
from transformers import GPT2Config
from vllm_omni.model_executor.models.moss_tts import modeling_moss_tts_local_depth as depth
pytestmark = [pytest.mark.core_model, pytest.mark.tts, pytest.mark.cpu]
@pytest.mark.parametrize(
"configured,env,expected", [(None, "0", False), (None, "1", True), (True, "0", True), (False, "1", False)]
)
def test_sampler_compile_setting_and_idempotent_setup(monkeypatch, configured, env, expected):
monkeypatch.setenv("VLLM_OMNI_MOSS_LOCAL_COMPILE_AUDIO_SAMPLER", env)
monkeypatch.setattr(depth.current_omni_platform, "supports_torch_inductor", lambda: True)
calls = []
def compile_fn(fn, **kwargs):
calls.append((fn, kwargs))
return fn
monkeypatch.setattr(depth.torch, "compile", compile_fn)
model = depth.MossTTSLocalDepthTransformer(
GPT2Config(n_embd=80, n_head=1, n_inner=160), compile_audio_sampler=configured
)
model.setup_compile()
model.setup_compile()
assert len(calls) == 1 + expected
assert (model._compiled_audio_sampler is depth._sample_token) is expected
sampler_calls = [kwargs for fn, kwargs in calls if fn is depth._sample_token]
assert len(sampler_calls) == int(expected)
if expected:
assert sampler_calls[0] == {"fullgraph": True, "dynamic": True, "options": {"fallback_random": True}}
def test_sampler_compile_setting_respects_platform_support(monkeypatch):
monkeypatch.setattr(depth.current_omni_platform, "supports_torch_inductor", lambda: False)
def forbidden(*args, **kwargs):
raise AssertionError("compile called on unsupported platform")
monkeypatch.setattr(depth.torch, "compile", forbidden)
model = depth.MossTTSLocalDepthTransformer(GPT2Config(n_embd=80, n_head=1, n_inner=160), compile_audio_sampler=True)
model.setup_compile()
assert model._compiled_audio_sampler is None
@@ -40,14 +40,18 @@ def _model(device):
model.audio_assistant_slot_token_id, model.im_end_token_id = 2, 3
model.talker_mtp_output_key = ("audio_codes", "current")
model.talker_mtp_graph_safe = False
model.talker_mtp_accepts_per_row_generators = True
model.gpu_resident_buffer_keys = {("hidden_states", "last"), ("audio_codes", "current")}
model.audio_lm_heads = model.audio_embeddings = model.local_text_lm_head = None
model._audio_embed = lambda codes: codes[:, :1].expand(-1, 4).to(dtype) / 8
model.force_stop = False
def frame(hidden, *_args, generator=None, temperature=None, top_k=None, top_p=None, **_kwargs):
def frame(hidden, *_args, generator=None, generators=None, temperature=None, top_k=None, top_p=None, **_kwargs):
assert (temperature, top_k, top_p) == (1.7, 25, 0.8)
noise = torch.randint(0, 8, (hidden.shape[0], 2), device=device, generator=generator)
if generators is not None:
noise = torch.cat([torch.randint(0, 8, (1, 2), device=device, generator=g) for g in generators])
else:
noise = torch.randint(0, 8, (hidden.shape[0], 2), device=device, generator=generator)
codes = (hidden[:, :2].mul(16).long() + noise) % 8
return torch.full((hidden.shape[0],), not model.force_stop, device=device), codes
@@ -85,11 +89,11 @@ def _admit(state, slot, name, seed):
state.intermediate_buffer.buffers[slot]["codes"] = {"ref": torch.tensor([[1, 2], [3, 4], [5, 6], [2, 3]])}
def _batch(device, slots, counts):
def _batch(device, slots, counts, index_dtype=torch.int32):
starts = np.array([0, *np.cumsum(counts)], dtype=np.int32)
return SimpleNamespace(
idx_mapping_np=np.array(slots),
idx_mapping=torch.tensor(slots, device=device),
idx_mapping=torch.tensor(slots, device=device, dtype=index_dtype),
num_reqs=len(slots),
num_tokens=int(starts[-1]),
num_scheduled_tokens=np.array(counts),
@@ -122,7 +126,8 @@ def _step(state, batch, req_states, dispatcher=None):
@pytest.mark.parametrize("seed", [None, 17])
@pytest.mark.parametrize("batch_prefill", [False, True])
def test_slot_matches_canonical_mixed_prefill_reorder_stop_and_reuse(device, seed, batch_prefill):
@pytest.mark.parametrize("index_dtype", [torch.int32, torch.int64])
def test_slot_matches_canonical_mixed_prefill_reorder_stop_and_reuse(device, seed, batch_prefill, index_dtype):
reference, candidate = (_state(cls, device) for cls in (OmniModelState, MossLocalModelState))
candidate._batch_prefill = batch_prefill
for state in (reference, candidate):
@@ -154,7 +159,7 @@ def test_slot_matches_canonical_mixed_prefill_reorder_stop_and_reuse(device, see
for state in (reference, candidate):
state.model.force_stop = index == 3
torch.manual_seed(91 + index)
outputs.append(_step(state, _batch(device, slots, counts), req_states))
outputs.append(_step(state, _batch(device, slots, counts, index_dtype), req_states))
a, b = outputs
torch.testing.assert_close(a[0], b[0], rtol=0, atol=0)
torch.testing.assert_close(a[2], b[2], rtol=0, atol=0)
@@ -190,6 +195,23 @@ def test_slot_honors_external_stopping_control(device):
assert output[1]["codes"]["audio"][0].tolist() == [[8, 8]]
@pytest.mark.cpu
@pytest.mark.parametrize("state_cls", [OmniModelState, MossLocalModelState])
def test_local_seeded_mtp_keeps_per_row_generators_in_one_batch(state_cls):
state = _state(state_cls, torch.device("cpu"))
generators = [torch.Generator().manual_seed(seed) for seed in (17, 29)]
inputs = [torch.zeros(2, dtype=torch.long), *[torch.ones(2, 4) for _ in range(3)]]
frame = MagicMock(wraps=state.model.local_transformer.generate_frame)
state.model.local_transformer.generate_frame = frame
state._call_mtp_with_sampling(*inputs, buffers=[{}, {}], req_ids=["first", "second"], generators=generators)
frame.assert_called_once()
assert frame.call_args.args[0].shape[0] == 2
assert frame.call_args.kwargs["generators"] == generators
assert frame.call_args.kwargs["generator"] is None
@pytest.mark.cuda
def test_slot_mtp_graph_padding_reorder_and_owned_output():
if not torch.cuda.is_available():
@@ -2,7 +2,7 @@
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
"""Reference batching preserves coordinates and asynchronous source ownership."""
from types import SimpleNamespace
from dataclasses import dataclass
import numpy as np
import pytest
@@ -15,6 +15,12 @@ from vllm_omni.model_executor.models.moss_tts.modeling_moss_tts_talker import Mo
pytestmark = pytest.mark.core_model
@dataclass
class _PrefillPositions:
prompt_len: np.ndarray
num_computed_tokens: np.ndarray
@pytest.mark.cpu
@pytest.mark.parametrize("flat", [False, True])
def test_prefill_reuses_text_embeddings_and_noncontiguous_reference_offsets(mocker, flat):
@@ -28,7 +34,8 @@ def test_prefill_reuses_text_embeddings_and_noncontiguous_reference_offsets(mock
"ref_offset": offset,
}
batch = _batch(torch.device("cpu"), [3, 0], [2, 1])
req = SimpleNamespace(prompt_len=np.full(5, 8), num_computed_tokens=np.zeros(5))
req = _PrefillPositions(prompt_len=np.full(5, 8), num_computed_tokens=np.zeros(5))
req.num_computed_tokens[[3, 0]] = [1, 2]
embeds = state._static_inputs_embeds[:3]
expected = state.model.embed_input_ids(batch.input_ids) + state.model._audio_embed(codes[[1, 2, 2]])
embed = mocker.spy(state.model.model.embed_tokens, "forward")
@@ -40,6 +47,65 @@ def test_prefill_reuses_text_embeddings_and_noncontiguous_reference_offsets(mock
assert state.intermediate_buffer.buffers[0]["ref_offset"] == 3
@pytest.mark.cpu
@pytest.mark.parametrize("batch_prefill", [False, True])
@pytest.mark.parametrize("cached,count", [(2, 1), (1, 2)])
def test_cached_prefix_prefill_uses_absolute_reference_position(batch_prefill, cached, count):
state = _state(MossLocalModelState, torch.device("cpu"))
state._batch_prefill = batch_prefill
codes = torch.tensor([[1, 2], [3, 4], [5, 6], [2, 3]])
state.intermediate_buffer.buffers[0] = {"req_id": "prefix-hit", "codes": {"ref": codes}}
batch = _batch(torch.device("cpu"), [0], [count])
req = _PrefillPositions(prompt_len=np.full(5, 4), num_computed_tokens=np.full(5, cached))
embeds = state._static_inputs_embeds[:count]
expected = state.model.embed_input_ids(batch.input_ids) + state.model._audio_embed(codes[cached : cached + count])
with torch.inference_mode():
state.run_preprocess(batch, {"input_ids": batch.input_ids, "inputs_embeds": embeds}, req)
torch.testing.assert_close(embeds, expected, rtol=0, atol=0)
assert state.intermediate_buffer.buffers[0]["ref_offset"] == cached + count
@pytest.mark.cpu
def test_scalar_prefill_uses_cached_prompt_position():
state = _state(MossLocalModelState, torch.device("cpu"))
codes = torch.tensor([[1, 2], [3, 4], [5, 6], [2, 3]])
ids = torch.tensor([2])
expected = state.model.embed_input_ids(ids) + state.model._audio_embed(codes[2:3])
with torch.inference_mode():
_, actual, updates = state.model.preprocess(
ids, None, codes={"ref": codes}, _omni_is_prefill=True, _omni_num_computed_tokens=2
)
torch.testing.assert_close(actual, expected, rtol=0, atol=0)
assert updates["ref_offset"] == 3
@pytest.mark.cpu
@pytest.mark.parametrize("batch_prefill", [False, True])
@pytest.mark.parametrize("omit_trailing_pad", [False, True])
def test_prefill_chunk_crosses_reference_end(batch_prefill, omit_trailing_pad):
state = _state(MossLocalModelState, torch.device("cpu"))
state._batch_prefill = batch_prefill
# codes.ref uses prompt coordinates, including PAD rows for text tokens.
codes = torch.tensor([[8, 8], [1, 2], [3, 4], [5, 6], [8, 8], [8, 8]])
if omit_trailing_pad:
codes = codes[:4]
state.model._audio_embed = lambda rows: rows[:, :1].masked_fill(rows[:, :1] == 8, 0).expand(-1, 4) / 8
state.intermediate_buffer.buffers[0] = {"req_id": "reference-boundary", "codes": {"ref": codes}}
req = _PrefillPositions(prompt_len=np.full(5, 6), num_computed_tokens=np.zeros(5))
outputs = []
with torch.inference_mode():
for start, count in [(0, 2), (2, 4)]:
req.num_computed_tokens[0] = start
batch = _batch(torch.device("cpu"), [0], [count])
embeds = state._static_inputs_embeds[:count]
state.run_preprocess(batch, {"input_ids": batch.input_ids, "inputs_embeds": embeds}, req)
outputs.append(embeds.clone())
expected = state.model.embed_input_ids(torch.full((6,), 2))
expected[1:4] += torch.tensor([1, 3, 5]).reshape(-1, 1) / 8
torch.testing.assert_close(torch.cat(outputs), expected, rtol=0, atol=0)
assert state.intermediate_buffer.buffers[0]["ref_offset"] == 6
@pytest.mark.cuda
def test_pending_reference_uploads_survive_staging_reuse_and_overflow():
if not torch.cuda.is_available():