diff --git a/benchmarks/qwen3-tts/README.md b/benchmarks/qwen3-tts/README.md index 73bc420f9..9c01f29aa 100644 --- a/benchmarks/qwen3-tts/README.md +++ b/benchmarks/qwen3-tts/README.md @@ -32,6 +32,9 @@ bash run_benchmark.sh --hf-only # Use a different model (e.g. 1.7B) MODEL=Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice bash run_benchmark.sh --async-only +# Use a Voice Clone model +MODEL=Qwen/Qwen3-TTS-12Hz-1.7B-Base TASK_TYPE=Base bash run_benchmark.sh --async-only + # Use bs16 config for higher throughput STAGE_CONFIG=vllm_omni/configs/qwen3_tts_bs16.yaml bash run_benchmark.sh --async-only diff --git a/benchmarks/qwen3-tts/run_benchmark.sh b/benchmarks/qwen3-tts/run_benchmark.sh index ef85d64d6..283b6b844 100755 --- a/benchmarks/qwen3-tts/run_benchmark.sh +++ b/benchmarks/qwen3-tts/run_benchmark.sh @@ -23,6 +23,9 @@ # # Use 1.7B model: # MODEL=Qwen/Qwen3-TTS-12Hz-1.7B-CustomVoice bash run_benchmark.sh --async-only # +# # Use Voice Clone model +# MODEL=Qwen/Qwen3-TTS-12Hz-1.7B-Base TASK_TYPE=Base bash run_benchmark.sh --async-only +# # # Use batch_size=4 config: # STAGE_CONFIG=vllm_omni/configs/qwen3_tts_bs4.yaml bash run_benchmark.sh --async-only # @@ -35,6 +38,7 @@ # GPU_MEM_TALKER - gpu_memory_utilization for talker stage (default: 0.3) # GPU_MEM_CODE2WAV - gpu_memory_utilization for code2wav stage (default: 0.2) # STAGE_CONFIG - Path to stage config YAML (default: configs/qwen3_tts_bs1.yaml) +# TASK_TYPE - Task type: CustomVoice, VoiceDesign, Base (default: CustomVoice) set -euo pipefail @@ -53,6 +57,7 @@ NUM_WARMUPS="${NUM_WARMUPS:-3}" STAGE_CONFIG="${STAGE_CONFIG:-vllm_omni/configs/qwen3_tts_bs1.yaml}" RESULT_DIR="${SCRIPT_DIR}/results" TIMESTAMP="$(date +%Y%m%d_%H%M%S)" +TASK_TYPE="${TASK_TYPE:-CustomVoice}" # Parse args RUN_ASYNC=true @@ -77,6 +82,7 @@ echo " Concurrency: ${CONCURRENCY}" echo " Port: ${PORT}" echo " Stage config: ${STAGE_CONFIG}" echo " Results: ${RESULT_DIR}" +echo " Task type: ${TASK_TYPE}" echo "============================================================" # Prepare stage config with correct GPU device and memory settings @@ -195,7 +201,8 @@ run_bench() { --max-concurrency ${conc_args} \ --num-warmups "${NUM_WARMUPS}" \ --config-name "${config_name}" \ - --result-dir "${RESULT_DIR}" + --result-dir "${RESULT_DIR}" \ + --task-type "${TASK_TYPE}" stop_server @@ -222,7 +229,8 @@ if [ "${RUN_HF}" = true ]; then --num-warmups "${NUM_WARMUPS}" \ --gpu-device "${GPU_DEVICE}" \ --config-name "hf_transformers" \ - --result-dir "${RESULT_DIR}" + --result-dir "${RESULT_DIR}" \ + --task-type "${TASK_TYPE}" # Allow GPU memory to settle sleep 5 diff --git a/benchmarks/qwen3-tts/transformers/bench_tts_hf.py b/benchmarks/qwen3-tts/transformers/bench_tts_hf.py index 0e0ef8e9e..ed04ee264 100644 --- a/benchmarks/qwen3-tts/transformers/bench_tts_hf.py +++ b/benchmarks/qwen3-tts/transformers/bench_tts_hf.py @@ -38,6 +38,10 @@ PROMPTS = [ "It was a dark and stormy night when the old lighthouse keeper heard a knock at the door.", ] +REF_AUDIO = "https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen3-TTS-Repo/clone_2.wav" +REF_TEXT = "Okay. Yeah. I resent you. I love you. I respect you. But you know what? You blew it! And thanks to you." +INSTRUCT = "Speak in an incredulous tone, but with a hint of panic beginning to creep into your voice." + @dataclass class BenchmarkResult: @@ -75,6 +79,29 @@ class BenchmarkResult: per_request: list = field(default_factory=list) +def generate_audio(model, prompt: str, args): + if args.task_type == "Base": + return model.generate_voice_clone( + text=prompt, + language=args.language, + ref_audio=REF_AUDIO, + ref_text=REF_TEXT, + ) + + if args.task_type == "VoiceDesign": + return model.generate_voice_design( + text=prompt, + language=args.language, + instruct=INSTRUCT, + ) + + return model.generate_custom_voice( + text=prompt, + language=args.language, + speaker=args.voice, + ) + + def run_benchmark(args): from qwen_tts import Qwen3TTSModel @@ -95,11 +122,7 @@ def run_benchmark(args): print(f"Warming up with {args.num_warmups} requests...") for i in range(args.num_warmups): p = PROMPTS[i % len(PROMPTS)] - wavs, sr = model.generate_custom_voice( - text=p, - language=args.language, - speaker=args.voice, - ) + wavs, sr = generate_audio(model, p, args) # Sync GPU torch.cuda.synchronize(device) print("Warmup done.") @@ -124,11 +147,7 @@ def run_benchmark(args): torch.cuda.synchronize(device) st = time.perf_counter() - wavs, sr = model.generate_custom_voice( - text=prompt, - language=args.language, - speaker=args.voice, - ) + wavs, sr = generate_audio(model, prompt, args) torch.cuda.synchronize(device) elapsed = time.perf_counter() - st @@ -268,6 +287,7 @@ def parse_args(): parser.add_argument("--gpu-device", type=int, default=0) parser.add_argument("--voice", type=str, default="Vivian") parser.add_argument("--language", type=str, default="English") + parser.add_argument("--task-type", type=str, default="CustomVoice", choices=["CustomVoice", "VoiceDesign", "Base"]) parser.add_argument( "--config-name", type=str, default="hf_transformers", help="Label for this config (used in filenames)" ) diff --git a/benchmarks/qwen3-tts/vllm_omni/bench_tts_serve.py b/benchmarks/qwen3-tts/vllm_omni/bench_tts_serve.py index 91e4ecbbb..96b904b01 100644 --- a/benchmarks/qwen3-tts/vllm_omni/bench_tts_serve.py +++ b/benchmarks/qwen3-tts/vllm_omni/bench_tts_serve.py @@ -37,6 +37,9 @@ PROMPTS = [ "Could you please turn down the music a little bit, I'm trying to concentrate on my work.", "It was a dark and stormy night when the old lighthouse keeper heard a knock at the door.", ] +REF_AUDIO = "https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen3-TTS-Repo/clone_2.wav" +REF_TEXT = "Okay. Yeah. I resent you. I love you. I respect you. But you know what? You blew it! And thanks to you." +INSTRUCT = "Speak in an incredulous tone, but with a hint of panic beginning to creep into your voice." @dataclass @@ -93,22 +96,39 @@ def pcm_bytes_to_duration(num_bytes: int, sample_rate: int = 24000, sample_width return num_samples / sample_rate +def create_payload( + prompt: str, task_type: str = "CustomVoice", voice: str = "vivian", language: str = "English" +) -> dict: + payload = { + "input": prompt, + "language": language, + "stream": True, + "response_format": "pcm", + "task_type": task_type, + } + + if task_type == "Base": + payload["ref_audio"] = REF_AUDIO + payload["ref_text"] = REF_TEXT + elif task_type == "CustomVoice": + payload["voice"] = voice + elif task_type == "VoiceDesign": + payload["instructions"] = INSTRUCT + + return payload + + async def send_tts_request( session: aiohttp.ClientSession, api_url: str, prompt: str, + task_type: str = "CustomVoice", voice: str = "vivian", language: str = "English", pbar: tqdm | None = None, ) -> RequestResult: """Send a streaming TTS request and measure latency metrics.""" - payload = { - "input": prompt, - "voice": voice, - "language": language, - "stream": True, - "response_format": "pcm", - } + payload = create_payload(prompt, task_type, voice, language) result = RequestResult(prompt=prompt) st = time.perf_counter() @@ -153,6 +173,7 @@ async def run_benchmark( num_prompts: int, max_concurrency: int, num_warmups: int = 3, + task_type: str = "CustomVoice", voice: str = "vivian", language: str = "English", ) -> BenchmarkResult: @@ -175,7 +196,7 @@ async def run_benchmark( warmup_tasks = [] for i in range(num_warmups): prompt = PROMPTS[i % len(PROMPTS)] - warmup_tasks.append(send_tts_request(session, api_url, prompt, voice, language)) + warmup_tasks.append(send_tts_request(session, api_url, prompt, task_type, voice, language)) await asyncio.gather(*warmup_tasks) print(" Warmup done.") @@ -189,7 +210,7 @@ async def run_benchmark( async def limited_request(prompt): async with semaphore: - return await send_tts_request(session, api_url, prompt, voice, language, pbar) + return await send_tts_request(session, api_url, prompt, task_type, voice, language, pbar) start_time = time.perf_counter() tasks = [asyncio.create_task(limited_request(p)) for p in request_prompts] @@ -306,6 +327,7 @@ async def main(args): num_prompts=args.num_prompts, max_concurrency=concurrency, num_warmups=args.num_warmups, + task_type=args.task_type, voice=args.voice, language=args.language, ) @@ -334,6 +356,7 @@ def parse_args(): "--max-concurrency", type=int, nargs="+", default=[1, 4, 10], help="Concurrency levels to test" ) parser.add_argument("--num-warmups", type=int, default=3) + parser.add_argument("--task-type", type=str, default="CustomVoice", choices=["CustomVoice", "VoiceDesign", "Base"]) parser.add_argument("--voice", type=str, default="vivian") parser.add_argument("--language", type=str, default="English") parser.add_argument(