[Refactor] Migrate Step-Audio2 online test to deploy config (#5309)

Signed-off-by: zwhzzz0821 <2831474076@qq.com>
This commit is contained in:
Yukim1 authored and GitHub committed 2026-07-22 09:44:27 +00:00
1 parent 8fc9df4331
commit 633ebbd8a4
4 files changed
+74 -113

No files matched your search

@@ -1,81 +0,0 @@
# Stage config for Step-Audio2 CI tests
# Stage 0: Thinker (audio understanding → text + audio tokens)
# Stage 1: Token2Wav (audio tokens → waveform)
# The following config has been verified on 2x 24GB GPU (L4/RTX3090/RTX4090).
stage_args:
- stage_id: 0
runtime:
process: true
devices: "0"
max_batch_size: 1
engine_args:
model_stage: thinker
model_arch: StepAudio2ThinkerForConditionalGeneration
tensor_parallel_size: 1
hf_overrides:
architectures: ["StepAudio2ThinkerForConditionalGeneration"]
worker_cls: vllm_omni.worker.gpu_ar_worker.GPUARWorker
scheduler_cls: vllm_omni.core.sched.omni_ar_scheduler.OmniARScheduler
max_model_len: 1024
max_num_batched_tokens: 1024
max_num_seqs: 1
gpu_memory_utilization: 0.7
skip_mm_profiling: true
enforce_eager: true
trust_remote_code: true
enable_prefix_caching: false
engine_output_type: text # Output text + audio tokens
is_comprehension: true
final_output: true
final_output_type: text
default_sampling_params:
temperature: 0.7
top_p: 0.9
top_k: -1
max_tokens: 256
seed: 42
detokenize: true
repetition_penalty: 1.05
- stage_id: 1
runtime:
process: true
devices: "0"
max_batch_size: 1
engine_args:
model_stage: token2wav
model_arch: StepAudio2Token2WavModel
worker_cls: vllm_omni.worker.gpu_generation_worker.GPUGenerationWorker
scheduler_cls: vllm_omni.core.sched.omni_generation_scheduler.OmniGenerationScheduler
hf_overrides:
architectures: ["StepAudio2Token2WavModel"]
gpu_memory_utilization: 0.2
enforce_eager: true
trust_remote_code: true
enable_prefix_caching: false
max_num_batched_tokens: 1024
engine_output_type: audio # Output waveform
engine_input_source: [0]
custom_process_input_func: vllm_omni.model_executor.stage_input_processors.step_audio2.thinker2token2wav
final_output: true
final_output_type: audio
default_sampling_params:
temperature: 0.0
top_p: 1.0
top_k: -1
max_tokens: 1
seed: 42
detokenize: false
runtime:
enabled: true
defaults:
window_size: -1
max_inflight: 1
edges:
- from: 0
to: 1
window_size: -1
@@ -3,34 +3,32 @@
"""
E2E expansion tests for Step-Audio2 online serving (weekly CI).
Tests speech-to-speech translation via /v1/chat/completions.
Tests audio-to-text generation via /v1/chat/completions.
Request shape follows examples/online_serving/step_audio2/openai_chat_completion_client.py.
"""
import os
from pathlib import Path
import pytest
from tests.helpers.mark import hardware_test
from tests.helpers.media import generate_synthetic_audio
from tests.helpers.runtime import OmniServerParams
from tests.helpers.stage_config import get_deploy_config_path
os.environ.setdefault("VLLM_WORKER_MULTIPROC_METHOD", "spawn")
MODEL = "stepfun-ai/Step-Audio-2-mini"
STAGE_CONFIG = str(Path(__file__).parent / "stage_configs" / "step_audio2_ci.yaml")
DEPLOY_CONFIG = get_deploy_config_path("step_audio2_ci.yaml")
SAMPLE_RATE = 16000
SEED = 42
# pyttsx3 synthetic input phrase; Step-Audio2 text output includes codec tokens
# (<audio_NNNN>) so we validate audio only, not text↔audio similarity.
SYNTH_PHRASE = "how are you"
TEST_PARAMS = [
pytest.param(
OmniServerParams(
model=MODEL,
stage_config_path=STAGE_CONFIG,
server_args=["--deploy-config", DEPLOY_CONFIG, "--trust-remote-code"],
env_dict={"VLLM_IMAGE_FETCH_TIMEOUT": "60"},
),
id="step_audio2",
@@ -64,19 +62,11 @@ def _default_sampling_params_list() -> list[dict]:
"detokenize": True,
"repetition_penalty": 1.05,
},
{
"temperature": 0.0,
"top_p": 1.0,
"top_k": -1,
"max_tokens": 1,
"seed": SEED,
"detokenize": False,
},
]
def _build_s2st_request_config(omni_server, audio_base64: str) -> dict:
"""Build audio-to-audio (S2ST) chat completion request config."""
def _build_audio_to_text_request_config(omni_server, audio_base64: str) -> dict:
"""Build an audio-to-text chat completion request config."""
audio_url = f"data:audio/wav;base64,{audio_base64}"
return {
"model": omni_server.model,
@@ -86,7 +76,7 @@ def _build_s2st_request_config(omni_server, audio_base64: str) -> dict:
"content": [
{
"type": "text",
"text": "You are an audio processing assistant. Listen and repeat the audio content.",
"text": "You are a speech recognition assistant. Transcribe the audio accurately.",
}
],
},
@@ -94,26 +84,19 @@ def _build_s2st_request_config(omni_server, audio_base64: str) -> dict:
"role": "user",
"content": [
{"type": "audio_url", "audio_url": {"url": audio_url}},
{"type": "text", "text": "Please listen to this audio and repeat its content."},
{"type": "text", "text": "Please transcribe the audio content."},
],
},
{"role": "assistant", "content": "<tts_start>"},
],
# Thinker text includes undetokenized audio codec placeholders; assert audio only.
"modalities": ["audio"],
"audio_ref_text": SYNTH_PHRASE,
"modalities": ["text"],
"sampling_params_list": _default_sampling_params_list(),
"extra_body": {
"continue_final_message": True,
"add_generation_prompt": False,
},
}
@hardware_test(res={"cuda": "H100"}, num_cards=1)
def test_single_s2st_request(omni_server, openai_client) -> None:
"""Test single speech-to-speech request via chat completions API."""
request_config = _build_s2st_request_config(
def test_single_audio_to_text_request(omni_server, openai_client) -> None:
"""Test a single audio-to-text request via the chat completions API."""
request_config = _build_audio_to_text_request_config(
omni_server,
_synthetic_audio_base64(duration_sec=2),
)
@@ -122,9 +105,9 @@ def test_single_s2st_request(omni_server, openai_client) -> None:
@hardware_test(res={"cuda": "H100"}, num_cards=1)
@pytest.mark.parametrize("request_num", [2, 4])
def test_concurrent_s2st_requests(omni_server, openai_client, request_num: int) -> None:
"""Test concurrent speech-to-speech requests."""
request_config = _build_s2st_request_config(
def test_concurrent_audio_to_text_requests(omni_server, openai_client, request_num: int) -> None:
"""Test concurrent audio-to-text requests."""
request_config = _build_audio_to_text_request_config(
omni_server,
_synthetic_audio_base64(duration_sec=2),
)
+28
View File
@@ -1174,6 +1174,7 @@ stages:
("step_audio_2.yaml", "step_audio_2", 2, "audio", None),
("step_audio_2_asr.yaml", "step_audio_2_asr", 1, "text", "step_audio_2_asr"),
("step_audio_2_async_chunk.yaml", "step_audio_2", 2, "audio", None),
("step_audio2_ci.yaml", "step_audio_2_asr", 1, "text", "step_audio_2_asr"),
("hunyuan_video_15.yaml", "hunyuan_video_15", 1, "video", None),
("wan2_2_ti2v.yaml", "wan2_2_ti2v", 1, "video", None),
],
@@ -1241,6 +1242,33 @@ stages:
assert deploy.stages[0].tensor_parallel_size == 2
assert deploy.stages[1].devices == "1"
def test_step_audio2_online_ci_deploy_is_single_thinker(self):
deploy = load_deploy_config(Path(get_deploy_config_path("step_audio2_ci.yaml")))
assert deploy.pipeline == "step_audio_2_asr"
assert deploy.async_chunk is False
assert deploy.trust_remote_code is True
assert deploy.enable_prefix_caching is False
assert len(deploy.stages) == 1
stage = deploy.stages[0]
assert stage.devices == "0"
assert stage.tensor_parallel_size == 1
assert stage.max_model_len == 1024
assert stage.max_num_batched_tokens == 1024
assert stage.max_num_seqs == 1
assert stage.gpu_memory_utilization == 0.7
assert stage.skip_mm_profiling is True
assert stage.enforce_eager is True
assert stage.async_scheduling is False
assert stage.engine_extras["hf_overrides"]["architectures"] == ["StepAudio2ThinkerForConditionalGeneration"]
stages = merge_pipeline_deploy(OMNI_PIPELINES[deploy.pipeline], deploy)
assert len(stages) == 1
assert stages[0].final_output is True
assert stages[0].final_output_type == "text"
assert stages[0].yaml_engine_args["engine_output_type"] == "text"
def test_step_audio2_dispatches_sync_and_async_chunk_processors(self):
pipeline = resolve_pipeline_config("step_audio_2")
assert isinstance(pipeline, PipelineConfig)
+31
View File
@@ -0,0 +1,31 @@
# Step-Audio2 online CI deploy: thinker only (audio/text -> text).
#
# The two-stage topology can deadlock when an audio-to-text request skips the
# Token2Wav stage, so this config explicitly selects the ASR pipeline.
# Keeps the legacy 1x 24GB CI sizing; validated here on 1x H100-80GB.
pipeline: step_audio_2_asr
async_chunk: false
trust_remote_code: true
enable_prefix_caching: false
stages:
- stage_id: 0
devices: "0"
tensor_parallel_size: 1
max_model_len: 1024
max_num_batched_tokens: 1024
max_num_seqs: 1
gpu_memory_utilization: 0.7
skip_mm_profiling: true
enforce_eager: true
async_scheduling: false
hf_overrides:
architectures: ["StepAudio2ThinkerForConditionalGeneration"]
default_sampling_params:
temperature: 0.7
top_p: 0.9
top_k: -1
max_tokens: 256
seed: 42
detokenize: true
repetition_penalty: 1.05