[Bugfix][Qwen3-Omni] Default the talker voice to Ethan (#8568)
Signed-off-by: Yueqian Lin <linyueqian@outlook.com>
This commit is contained in:
1 parent
1c71a2c03a
commit
6a70bda0f6
2 files changed
+58
-2
No files matched your search
@@ -0,0 +1,42 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
"""Regression tests for the Qwen3-Omni default talker voice.
|
||||
|
||||
The released checkpoint lists ``talker_config.speaker_id`` as
|
||||
``{"chelsie": 2301, "ethan": 2302, "aiden": 2303}``. The default voice used to
|
||||
be the first key, so a request that named no speaker was spoken by Chelsie,
|
||||
while the reference ``generate(speaker="Ethan")`` (and other servers) use Ethan.
|
||||
Benchmarks that omit ``speaker`` then compared two different voices.
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from vllm_omni.model_executor.models.qwen3_omni.qwen3_omni import (
|
||||
DEFAULT_SPEAKER,
|
||||
Qwen3OmniMoeForConditionalGeneration,
|
||||
resolve_default_speaker,
|
||||
)
|
||||
|
||||
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
||||
|
||||
# Order as shipped in Qwen/Qwen3-Omni-30B-A3B-Instruct config.json.
|
||||
CHECKPOINT_SPEAKER_IDS = {"chelsie": 2301, "ethan": 2302, "aiden": 2303}
|
||||
|
||||
|
||||
def test_default_speaker_is_ethan_even_when_listed_second() -> None:
|
||||
assert DEFAULT_SPEAKER == "ethan"
|
||||
assert resolve_default_speaker(CHECKPOINT_SPEAKER_IDS) == "ethan"
|
||||
|
||||
|
||||
def test_default_speaker_falls_back_to_first_key_without_ethan() -> None:
|
||||
assert resolve_default_speaker({"chelsie": 1, "aiden": 2}) == "chelsie"
|
||||
|
||||
|
||||
def test_unknown_or_missing_speaker_uses_ethan_token() -> None:
|
||||
model = object.__new__(Qwen3OmniMoeForConditionalGeneration)
|
||||
model.tts_text_spk_token_ids = dict(CHECKPOINT_SPEAKER_IDS)
|
||||
model.default_tts_text_spk_type = resolve_default_speaker(model.tts_text_spk_token_ids)
|
||||
|
||||
assert model._get_text_spk_token_id("not-a-speaker") == CHECKPOINT_SPEAKER_IDS["ethan"]
|
||||
assert model._get_text_spk_token_id(model.default_tts_text_spk_type) == CHECKPOINT_SPEAKER_IDS["ethan"]
|
||||
assert model._get_text_spk_token_id("chelsie") == CHECKPOINT_SPEAKER_IDS["chelsie"]
|
||||
@@ -67,6 +67,20 @@ from vllm_omni.model_executor.stage_input_processors.chunk_size_utils import par
|
||||
from vllm_omni.platforms import current_omni_platform
|
||||
from vllm_omni.utils.device_copy import to_device_nonblocking
|
||||
|
||||
# Voice used when a request names no speaker. Matches the reference
|
||||
# ``Qwen3OmniMoeForConditionalGeneration.generate(speaker="Ethan")``; the
|
||||
# checkpoint's ``talker_config.speaker_id`` lists "chelsie" first, so taking the
|
||||
# first key would silently switch the default to a different (female) voice.
|
||||
DEFAULT_SPEAKER = "ethan"
|
||||
|
||||
|
||||
def resolve_default_speaker(speaker_token_ids: dict[str, int]) -> str:
|
||||
"""Return the speaker key used for requests that do not name one."""
|
||||
if DEFAULT_SPEAKER in speaker_token_ids:
|
||||
return DEFAULT_SPEAKER
|
||||
return next(iter(speaker_token_ids))
|
||||
|
||||
|
||||
# Special token IDs for Qwen3 Omni MoE
|
||||
# Reference: https://huggingface.co/Qwen/Qwen3-Omni-30B-A3B-Instruct/blob/main/tokenizer_config.json
|
||||
|
||||
@@ -552,7 +566,7 @@ class Qwen3OmniMoeForConditionalGeneration(
|
||||
intermediate_tensors: IntermediateTensors | None = None,
|
||||
inputs_embeds: torch.Tensor | None = None,
|
||||
generate_audio: bool = True,
|
||||
voice_type: str = "ethan",
|
||||
voice_type: str = DEFAULT_SPEAKER,
|
||||
codec: torch.Tensor | None = None,
|
||||
sampling_metadata: SamplingMetadata | None = None,
|
||||
logits_index: int | None = None,
|
||||
@@ -963,7 +977,7 @@ class Qwen3OmniMoeForConditionalGeneration(
|
||||
"prefix_caching": talker_hf_config.audio_start_token_id,
|
||||
}
|
||||
|
||||
self.default_tts_text_spk_type = list(self.tts_text_spk_token_ids.keys())[0]
|
||||
self.default_tts_text_spk_type = resolve_default_speaker(self.tts_text_spk_token_ids)
|
||||
|
||||
return set(["thinker_embedding.weight", "talker_embedding.weight"])
|
||||
|
||||
|
||||
Reference in new issue
Block a user