[tts][bugfix] Fix CosyVoice3 sampling and stage handoff (#6424)
Signed-off-by: akshatvishu <akshatnayak197@gmail.com>
This commit is contained in:
1 parent
0db262de2a
commit
39c16d75a9
11 files changed
+221
-68
No files matched your search
@@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
"""Unit tests for CosyVoice3 components."""
|
||||
|
||||
from types import SimpleNamespace
|
||||
@@ -9,10 +9,41 @@ import torch
|
||||
import torch.nn as nn
|
||||
|
||||
from tests.helpers.mark import hardware_test
|
||||
from vllm_omni.model_executor.models.cosyvoice3.code2wav_core.hifigan import (
|
||||
CausalHiFTGenerator,
|
||||
)
|
||||
|
||||
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def causal_hift():
|
||||
return CausalHiFTGenerator(
|
||||
base_channels=32,
|
||||
upsample_rates=[2, 2],
|
||||
upsample_kernel_sizes=[4, 4],
|
||||
source_resblock_kernel_sizes=[3, 3],
|
||||
source_resblock_dilation_sizes=[[1, 3, 5], [1, 3, 5]],
|
||||
)
|
||||
|
||||
|
||||
def test_causal_hift_moves_stft_window_with_model(causal_hift):
|
||||
assert causal_hift.get_buffer("stft_window") is causal_hift.stft_window
|
||||
assert "stft_window" not in causal_hift.state_dict()
|
||||
causal_hift.to(dtype=torch.float64)
|
||||
assert causal_hift.stft_window.dtype == torch.float64
|
||||
|
||||
|
||||
def test_causal_hift_stft_moves_window_to_input_device(causal_hift):
|
||||
waveform = torch.empty((1, 64), device="meta")
|
||||
|
||||
real, imag = causal_hift._stft(waveform)
|
||||
|
||||
assert real.device == waveform.device
|
||||
assert imag.device == waveform.device
|
||||
assert causal_hift.stft_window.device == waveform.device
|
||||
|
||||
|
||||
class TestPreLookaheadLayer:
|
||||
"""Tests for PreLookaheadLayer."""
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
import pytest
|
||||
|
||||
from vllm_omni.config.model import OmniModelArchConfigConvertor
|
||||
from vllm_omni.transformers_utils.configs.cosyvoice3 import CosyVoice3Config
|
||||
|
||||
pytestmark = [pytest.mark.core_model, pytest.mark.cpu]
|
||||
|
||||
|
||||
def test_attention_geometry_matches_qwen_backbone() -> None:
|
||||
config = CosyVoice3Config()
|
||||
model_arch_config = OmniModelArchConfigConvertor(config, config.get_text_config()).convert()
|
||||
|
||||
assert model_arch_config.total_num_attention_heads == 14
|
||||
assert model_arch_config.total_num_kv_heads == 2
|
||||
assert model_arch_config.head_size == 64
|
||||
@@ -1,5 +1,5 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project
|
||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM-Omni project
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@@ -401,6 +401,52 @@ def test_sample_tolerates_padded_rows_without_history():
|
||||
assert out.sampled_token_ids.shape == (2, 1)
|
||||
|
||||
|
||||
def test_sample_excludes_non_finite_logits():
|
||||
model = _make_talker_model()
|
||||
metadata = _make_sampling_metadata(output_token_ids=[[]])
|
||||
metadata.temperature.fill_(0.5)
|
||||
logits = torch.tensor([[float("nan"), 1.0, float("inf"), float("-inf")]], dtype=torch.bfloat16)
|
||||
|
||||
out = model.sample(logits, metadata)
|
||||
|
||||
assert out is not None
|
||||
assert out.sampled_token_ids.tolist() == [[1]]
|
||||
|
||||
|
||||
def test_sample_preserves_allowed_token_mask_with_invalid_logits():
|
||||
model = _make_talker_model()
|
||||
metadata = _make_sampling_metadata(output_token_ids=[[]])
|
||||
metadata.allowed_token_ids_mask = torch.tensor([[True, False, True]])
|
||||
logits = torch.tensor([[float("nan"), 1.0, float("inf")]], dtype=torch.float32)
|
||||
|
||||
out = model.sample(logits, metadata)
|
||||
|
||||
assert out is not None
|
||||
assert out.sampled_token_ids.tolist() == [[1]]
|
||||
|
||||
|
||||
def test_sample_rejects_rows_without_finite_logits():
|
||||
model = _make_talker_model()
|
||||
metadata = _make_sampling_metadata(output_token_ids=[[]])
|
||||
metadata.allowed_token_ids_mask = torch.tensor([[True, False, True]])
|
||||
logits = torch.tensor([[0.0, float("nan"), 0.0]], dtype=torch.float32)
|
||||
|
||||
with pytest.raises(ValueError, match="no finite logits"):
|
||||
model.sample(logits, metadata)
|
||||
|
||||
|
||||
def test_sample_keeps_only_finite_token_after_ras_rejection():
|
||||
model = _make_talker_model()
|
||||
metadata = _make_sampling_metadata(output_token_ids=[[1] * 10])
|
||||
metadata.allowed_token_ids_mask = torch.tensor([[True, False, True]])
|
||||
logits = torch.tensor([[0.0, 1.0, 0.0]], dtype=torch.float32)
|
||||
|
||||
out = model.sample(logits, metadata)
|
||||
|
||||
assert out is not None
|
||||
assert out.sampled_token_ids.tolist() == [[1]]
|
||||
|
||||
|
||||
def test_gpu_ar_model_runner_prefers_model_sampler_when_opted_in():
|
||||
metadata = _make_sampling_metadata(output_token_ids=[[1, 2, 3]])
|
||||
expected = SamplerOutput(
|
||||
@@ -423,9 +469,14 @@ def test_gpu_ar_model_runner_prefers_model_sampler_when_opted_in():
|
||||
_, GPUARModelRunner = _cosyvoice3_model_and_runner()
|
||||
runner = object.__new__(GPUARModelRunner)
|
||||
runner.input_batch = _DummyInputBatch()
|
||||
|
||||
def model_sample(logits, sampling_metadata):
|
||||
calls.append(logits.clone())
|
||||
return expected
|
||||
|
||||
runner.model = SimpleNamespace(
|
||||
prefer_model_sampler=True,
|
||||
sample=lambda logits, sampling_metadata: calls.append(logits.clone()) or expected,
|
||||
sample=model_sample,
|
||||
)
|
||||
runner.sampler = lambda **_: (_ for _ in ()).throw(AssertionError("fallback sampler should not be used"))
|
||||
|
||||
@@ -459,12 +510,14 @@ def test_gpu_ar_model_runner_supplies_req_output_history_to_model_sampler():
|
||||
_, GPUARModelRunner = _cosyvoice3_model_and_runner()
|
||||
runner = object.__new__(GPUARModelRunner)
|
||||
runner.input_batch = _DummyInputBatch()
|
||||
|
||||
def model_sample(logits, sampling_metadata):
|
||||
seen_histories.append([list(x) for x in sampling_metadata.output_token_ids])
|
||||
return SamplerOutput(sampled_token_ids=torch.tensor([[7]], dtype=torch.int32), logprobs_tensors=None)
|
||||
|
||||
runner.model = SimpleNamespace(
|
||||
prefer_model_sampler=True,
|
||||
sample=lambda logits, sampling_metadata: (
|
||||
seen_histories.append([list(x) for x in sampling_metadata.output_token_ids])
|
||||
or SamplerOutput(sampled_token_ids=torch.tensor([[7]], dtype=torch.int32), logprobs_tensors=None)
|
||||
),
|
||||
sample=model_sample,
|
||||
)
|
||||
runner.sampler = lambda **_: (_ for _ in ()).throw(AssertionError("fallback sampler should not be used"))
|
||||
|
||||
@@ -504,12 +557,14 @@ def test_gpu_ar_model_runner_repairs_async_placeholders_for_model_sampler():
|
||||
_, GPUARModelRunner = _cosyvoice3_model_and_runner()
|
||||
runner = object.__new__(GPUARModelRunner)
|
||||
runner.input_batch = _DummyInputBatch()
|
||||
|
||||
def model_sample(logits, sampling_metadata):
|
||||
seen_histories.append([list(x) for x in sampling_metadata.output_token_ids])
|
||||
return SamplerOutput(sampled_token_ids=torch.tensor([[7]], dtype=torch.int32), logprobs_tensors=None)
|
||||
|
||||
runner.model = SimpleNamespace(
|
||||
prefer_model_sampler=True,
|
||||
sample=lambda logits, sampling_metadata: (
|
||||
seen_histories.append([list(x) for x in sampling_metadata.output_token_ids])
|
||||
or SamplerOutput(sampled_token_ids=torch.tensor([[7]], dtype=torch.int32), logprobs_tensors=None)
|
||||
),
|
||||
sample=model_sample,
|
||||
)
|
||||
runner.sampler = lambda **_: (_ for _ in ()).throw(AssertionError("fallback sampler should not be used"))
|
||||
|
||||
|
||||
Reference in new issue
Block a user