vLLM-Omni 中 Ming-omni-tts 密集 0.5B 离线推理实战指南
【免费下载链接】vllm-omniA framework for efficient model inference with omni-modality models项目地址: https://gitcode.com/GitHub_Trending/vl/vllm-omni
本文以 vLLM-Omni 仓库内置的 Ming 密集 0.5B 离线推理示例为主线,系统讲解如何通过end2end.py驱动两阶段 TTS 流水线,覆盖 11 种内置用例(风格合成、零样本克隆、播客多说话人生成、BGM 音乐生成、文本转音频事件等)的完整配置与运行方式。读完本文,你将掌握 Ming-omni-tts 的提示词组装原理、ming_tts.yaml部署配置的每个字段含义、阻塞/异步流式两种执行路径的差异,以及如何产出 WAV 音频、统计日志与运行清单(manifest)。
示例概览:一条命令跑通端到端 Ming 语音合成
examples/offline_inference/text_to_speech/ming_tts/目录下的示例与仓库其余 TTS 示例(如 qwen3_tts、cosyvoice3)不同:它直接复用仓库内的 Ming prompt 组装辅助函数(build_ming_dense_prompt),而不是示例自带的简化封装,因此请求结构与真实集成路径完全一致。该目录共包含三个文件:
| 文件 | 用途 |
|---|---|
end2end.py | 驱动脚本:CLI 参数解析、用例加载、提示词构造、整体编排(约 150 行) |
cases.yaml | 全部 11 个内置用例定义(prompt、text、instruction、参考音频标志、流程控制项) |
runner.py | 引擎管理与音频输出(流式 + 阻塞两条路径) |
从入口脚本可以看到整体执行链路:解析参数 → 用AutoTokenizer.from_pretrained加载分词器 →_build_prompt_payload组装提示词 →build_sampling_params构造两阶段采样参数 →run_generation分发到阻塞或流式路径 → 写 WAV 文件 → 可选写出 manifest JSON。
模型与两阶段流水线架构
Ming dense 0.5B(默认模型为inclusionAI/Ming-omni-tts-0.5B)在本示例中被组织为两阶段离线流水线:
- Stage 0:基于 Qwen2 的自回归(AR)生成,带 Ming prompt 格式与内联流程控制
- Stage 1:音频 VAE 解码,输出单声道 44.1 kHz波形
config_ming_tts.py负责将检查点的 HuggingFace 配置字段(LLM、DiT、聚合器、AudioVAE、token id)适配为 vLLM-Omni 可用的扁平配置。从config_ming_tts.py 可以看到MingTTSConfig会读取llm_config、ditar_config、aggregator_config、audio_tokenizer_config四个子配置,并根据 Stage-0 LLM 骨干家族自动判定变体:dense(Qwen2)或 moe(bailing_moe);model_type="dense"的 HuggingFace 兼容性保留在MingDenseConfig中。
关键架构常量(来自 constants.py):
| 常量 | 值 | 含义 |
|---|---|---|
SAMPLE_RATE | 44100 | 输出采样率(Hz) |
AUDIO_FRAME_HOP | 882 | AudioVAE 编码帧 hop |
LATENT_DIM | 64 | 音频 latent 维度 |
PATCH_SIZE/VAE_PATCH_SIZE | 4 / 4 | AR patch 与 VAE patch 尺寸 |
HISTORY_PATCH_SIZE | 32 | 历史 patch 窗口 |
SPEAKER_EMBEDDING_DIM | 192 | CampPlus 说话人嵌入维度 |
LLM_HIDDEN_SIZE | 896 | Stage-0 LLM 隐藏层宽度 |
DEFAULT_CFG/DEFAULT_SIGMA/DEFAULT_TEMPERATURE | 2.0 / 0.25 / 0.0 | FlowLoss 采样默认值 |
部署配置vllm_omni/deploy/ming_tts.yaml
vllm_omni/deploy/ming_tts.yaml 是示例唯一的部署配置文件,它选择 vLLM-Omni 流水线与阶段运行时拓扑(连接器、异步分块、内存限制、采样默认值),同时支持两种执行模式:阻塞 eager(async_chunk: false语义下的阻塞路径)与异步分块 eager(默认async_chunk: true)。核心字段解读:
pipeline: ming_tts:HF config 报告model_type="dense"且无architectures,自动探测会失效,此键直接路由到正确的流水线注册项(见StageConfigFactory.create_from_model的 deploy-config 探测逻辑);async_chunk: true:默认开启异步分块流式传输;dtype: bfloat16:全流水线使用 bf16 精度;connectors.connector_of_shared_memory:SharedMemoryConnector,latent_chunk_size: 25、initial_latent_chunk_size: 4、latent_left_context: 0,负责 Stage 0 → Stage 1 的 latent 分块搬运;stages[0]:max_num_seqs: 1、gpu_memory_utilization: 0.45、max_model_len: 8192、devices: "0",默认采样temperature: 0.0 / top_p: 1.0 / top_k: -1 / max_tokens: 512 / detokenize: true;stages[1]:gpu_memory_utilization: 0.25、max_tokens: 1、detokenize: false(纯解码不反 tokenize)。
环境准备与依赖
按平台要求安装 vLLM-Omni:
uv pip install -e .Ming 离线示例不要求单独安装上游 Ming 包。参考音频用例复用仓库依赖完成音频加载、重采样与 CampPlus 说话人提取,在文档记录的 ROCm 环境中包括soundfile、torchaudio、onnxruntime-rocm。测试环境的完整摘要见仓库配方 recipes/inclusionAI/Ming-omni-tts.md(其中记录了 1×AMD MI300X / ROCm 7.2 与 1×H100 / CUDA 13.0 两种已验证环境的软件版本、Docker 镜像与启动命令)。
11 种内置用例详解
cases.yaml覆盖了上游 dense 0.5B cookbook 中可干净映射到当前示例的全部面,每个用例由prompt(系统提示前缀)、text(生成文本)、instruction(Ming 指令,可为字符串或结构化 dict)、max_decode_steps(最大解码步数)以及若干流程控制字段组成。以下按零说话人与参考音频两类展开:
| 用例 | 类型 | 说明 | 参考输入 |
|---|---|---|---|
style | 零说话人 | 风格化语音(ASMR 耳语等创意风格) | 无 |
ip | 零说话人 | IP 音色合成(如“灵小甄”) | 无 |
bgm | 零说话人 | 纯音乐生成(含 Genre/Mood/Instrument/Theme/Duration 描述) | 无 |
tta | 零说话人 | 文本转音频事件,带 FlowLoss 控制 | 无 |
emotion | 参考音频 | 语音 + 情感控制 | 1 个 |
basic | 参考音频 | 语速/基频/音量控制 | 1 个 |
dialect | 参考音频 | 方言控制(如“广粤话”) | 1 个 |
zero_shot | 参考音频 | 带显式转写的零样本克隆 | 1 个音频 + 1 段转写 |
podcast | 参考音频 | 多参考对话生成,自动提取说话人嵌入 | ≥2 个 |
speech_bgm | 参考音频 | 语音 + 背景音乐条件(BGM 含 Genre/Mood/Instrument/Theme/SNR) | 1 个 |
speech_sound | 参考音频 | 语音 + 环境音条件(BGM.ENV,如 "Birds chirping") | 1 个 |
从 cases.yaml 可以看到各用例的具体指令设计,例如style用自由文本指令描述 ASMR 耳语风格,basic用结构化指令{"语速":"快速","基频":"中","音量":"中"},podcast的prompt_text中通过speaker_1:/speaker_2:标签对齐多说话人转写。tta额外指定了cfg: 4.5、sigma: 0.3、temperature: 2.5三个 FlowLoss 采样控制项,会通过运行时控制字典透传。
指令组装与提示词构造原理
end2end.py中的_build_prompt_payload(见 end2end.py)会把用例字段、CLI 覆盖项、参考波形与说话人嵌入一起交给 prompt_assembly.py 的build_ming_dense_prompt处理:
- 指令序列化:
create_instruction将 dict 指令填充到BASE_CAPTION_TEMPLATE(含 序号/说话人/方言/风格/语速/基频/音量/情感/BGM/IP 等槽位)后序列化为 JSON; - 时长感知的解码步数:
resolve_effective_runtime_controls会从text中解析Duration: Ns(正则Duration:\s*([0-9]+(?:\.[0-9]+)?)\s*s),并按samples_per_decode_step = AUDIO_FRAME_HOP × PATCH_SIZE × VAE_PATCH_SIZE估算min/max_decode_steps窗口(目标步数 ±3); - prompt token 序列:
build_dense_prompt_token_ids组装system/user轮次、说话人占位(speaker_N:+<|vision_start|><|vision_pad|><|vision_end|>)、指令(末尾接<|endoftext|>)、参考转写 token、<audio>起始符与<audioPatch>占位 latent token; - 说话人嵌入:
coerce_speaker_embeddings统一处理单个/多个 192 维向量;use_zero_spk_emb: true时(style、ip)使用零嵌入走零说话人路径; - 运行时控制:
max_decode_steps/cfg/sigma/temperature等被打入additional_information张量,随请求一起传给 Stage-0。
快速开始:各用例运行命令
零说话人风格合成
python examples/offline_inference/text_to_speech/ming_tts/end2end.py \ --case style \ --deploy-config vllm_omni/deploy/ming_tts.yaml \ --enforce-eager带转写的零样本克隆
python examples/offline_inference/text_to_speech/ming_tts/end2end.py \ --case zero_shot \ --ref-audio /path/to/10002287-00000094.wav \ --ref-text "在此奉劝大家别乱打美白针。" \ --deploy-config vllm_omni/deploy/ming_tts.yaml \ --enforce-eager情感控制语音
python examples/offline_inference/text_to_speech/ming_tts/end2end.py \ --case emotion \ --ref-audio /path/to/emotion_prompt.wav \ --deploy-config vllm_omni/deploy/ming_tts.yaml \ --enforce-eager播客多说话人生成
python examples/offline_inference/text_to_speech/ming_tts/end2end.py \ --case podcast \ --ref-audio-paths /path/to/CTS-CN-F2F-2019-11-11-423-012-A.wav /path/to/CTS-CN-F2F-2019-11-11-423-012-B.wav \ --deploy-config vllm_omni/deploy/ming_tts.yaml \ --enforce-eager脚本会使用 Ming 模型的campplus.onnx自动为每段参考 WAV 提取一个 192 维说话人嵌入。若已有预计算的说话人嵌入,可用如下参数覆盖提取过程:
--speaker-embedding /path/to/podcast_speaker_embeddings.json其中 JSON 是一个说话人嵌入列表,每位说话人对应一个 192 维向量。底层实现在 end2end.py:SpeakerEmbeddingExtractor(args.model, allow_download=True).extract_many(paths)在引擎构建前完成提取(此时尚未预取campplus.onnx)。
文本转音频事件(TTA)
python examples/offline_inference/text_to_speech/ming_tts/end2end.py \ --case tta \ --deploy-config vllm_omni/deploy/ming_tts.yaml \ --enforce-eager异步分块流式输出
python examples/offline_inference/text_to_speech/ming_tts/end2end.py \ --case basic \ --ref-audio /path/to/10002287-00000095.wav \ --streaming \ --deploy-config vllm_omni/deploy/ming_tts.yaml \ --enforce-eager--streaming使用AsyncOmni与异步分块部署配置,通过async for stage_output in engine.generate(...)增量消费音频块(见 runner.py),并统计首包延迟(TTFP)与块间平均间隔。注意:流式模式当前仅支持单进程单 prompt;--num-prompts > 1时请使用阻塞模式。
收集运行时统计与运行清单
python examples/offline_inference/text_to_speech/ming_tts/end2end.py \ --case style \ --deploy-config vllm_omni/deploy/ming_tts.yaml \ --enforce-eager \ --enable-stats \ --stats-log-file output_audio/ming_style_pipeline.log \ --metadata-json output_audio/ming_style_manifest.json启用统计后,脚本可额外写出统计日志文件与 manifest JSON(含每个输出的元数据、阶段耗时、峰值内存;流式模式下还包含客户端延迟指标),manifest 的字段结构见 runner.py 的build_manifest。
参考音频素材(Reference Fixtures)
上游 Ming cookbook 使用inclusionAI/Ming-omni-tts/data/wavs中的公开音频素材,各用例对应关系如下:
| 素材 | 适用用例 |
|---|---|
10002287-00000094.wav | zero_shot |
10002287-00000095.wav | basic |
emotion_prompt.wav | emotion |
yue_prompt.wav | dialect |
00000309-00000300.wav | speech_bgm、speech_sound |
CTS-CN-F2F-2019-11-11-423-012-A.wav/...-B.wav | podcast |
验证矩阵与实测输出
仓库面向自身的示例旨在覆盖本地 Ming 验证脚本使用的同一套 dense TTS 工作流,各用例在两种执行模式下的覆盖情况如下:
| 用例 | 阻塞deploy/ming_tts.yaml | 异步分块deploy/ming_tts.yaml | 额外输入 |
|---|---|---|---|
style | 是 | 可选冒烟测试 | 无 |
ip | 是 | 可选冒烟测试 | 无 |
bgm | 是 | 可选冒烟测试 | 无 |
tta | 是 | 可选冒烟测试 | 无 |
emotion | 是 | 是 | --ref-audio emotion_prompt.wav |
basic | 是 | 是 | --ref-audio 10002287-00000095.wav |
dialect | 是 | 是 | --ref-audio yue_prompt.wav |
zero_shot | 是 | 是 | --ref-audio 10002287-00000094.wav --ref-text ... |
podcast | 是 | 是 | 两个--ref-audio-paths |
speech_bgm | 是 | 是 | --ref-audio 00000309-00000300.wav |
speech_sound | 是 | 是 | --ref-audio 00000309-00000300.wav |
以下测量值来自早期的L4 CUDA 验证(非 ROCm 基准结果)。默认async_chunk模式在每个用例上都与阻塞模式保持了完全一致的输出帧数与 Stage-1 patch 数:
| 用例 | 阻塞 frames / patches / sec | 异步分块 frames / patches / sec |
|---|---|---|
style | 409248 / 29 / 9.28 | 409248 / 29 / 9.28 |
ip | 183456 / 13 / 4.16 | 183456 / 13 / 4.16 |
bgm | 1326528 / 94 / 30.08 | 1326528 / 94 / 30.08 |
tta | 465696 / 33 / 10.56 | 465696 / 33 / 10.56 |
emotion | 324576 / 23 / 7.36 | 324576 / 23 / 7.36 |
basic | 211680 / 15 / 4.80 | 211680 / 15 / 4.80 |
dialect | 239904 / 17 / 5.44 | 239904 / 17 / 5.44 |
zero_shot | 409248 / 29 / 9.28 | 409248 / 29 / 9.28 |
podcast | 437472 / 31 / 9.92 | 437472 / 31 / 9.92 |
speech_bgm | 296352 / 21 / 6.72 | 296352 / 21 / 6.72 |
speech_sound | 352800 / 25 / 8.00 | 352800 / 25 / 8.00 |
这些数字仅作为两条执行路径输出一致性的验证记录,不代表特定硬件的性能基准。此外,配方文档中记录了一次 ROCm 7.2 / MI300X 的离线冒烟运行:basic用例产出 44.1 kHz 单声道 WAV、时长 4.80 秒、RMS 0.1449、峰值绝对振幅 0.8621,首请求耗时 20.406 秒(实时因子 4.25),两个阶段的权重加载分别占用 1.31 GiB 与 1.47 GiB,全设备单秒最大内存采样 91.05 GiB(含预留 KV cache),AR 阶段选择了TRITON_ATTN。
关键命令行参数
| 参数 | 说明 |
|---|---|
--model | HuggingFace 仓库名或本地 Ming 检查点路径(默认inclusionAI/Ming-omni-tts-0.5B) |
--deploy-config | 部署配置 YAML,使用vllm_omni/deploy/ming_tts.yaml |
--case | 内置演示用例(style为默认值) |
--ref-audio | 单个参考 wav 路径(克隆类用例) |
--ref-audio-paths | 多个参考 wav 路径(podcast使用) |
--ref-text | 参考转写,zero_shot必需 |
--instructions | 自由格式 Ming 指令字符串 |
--instruction-json | 结构化 Ming 指令 JSON(如'{"方言":"广粤话"}') |
--speaker-embedding | 包含 192 维说话人嵌入的 JSON 文件 |
--extract-speaker-embeddings | 强制从给定参考音频路径执行 CampPlus 说话人提取 |
--max-decode-steps | 覆盖ming_max_decode_steps |
--num-prompts | 同一用例重复 N 次;N>1 时输出文件带索引 |
--streaming | 使用AsyncOmni与 async_chunk 传输 |
--enforce-eager | 推荐用于 Ming dense;非 eager 超出支持范围 |
--enable-stats/--log-stats | 启用 vLLM-Omni 每请求统计日志 |
--stats-log-file | 统计日志可选路径 |
--metadata-json | 运行清单 JSON 可选路径 |
--stage-init-timeout | 每阶段初始化超时(秒,默认 300) |
--init-timeout | 总初始化超时(秒,默认 600) |
--batch-timeout | 批处理超时(秒,默认 5) |
--worker-backend | multi_process或ray |
--ray-address | 使用--worker-backend ray时的 Ray 集群地址 |
其余可用参数(来自 end2end.py 的解析器)还包括--text(覆盖用例文本)、--prompt(覆盖系统提示前缀)、--output-dir(默认output_audio)、--output-name(自定义输出文件名)、--trust-remote-code、--shm-threshold-bytes(默认 65536)等。
引擎侧参数语义
--stage-init-timeout/--init-timeout/--batch-timeout会经build_engine_kwargs(见 runner.py)传入Omni/AsyncOmni引擎构造;--log-stats开启时还会追加log_file。两阶段采样参数由build_sampling_params构造:Stage-0 为temperature=0.0、max_tokens=max_decode_steps+1、stop_token_ids=[TEXT_EOS_TOKEN_ID](即151669的<text_eos>),Stage-1 为temperature=0.0、max_tokens=1(对应 VAE 解码的单步输出)。注意end2end.py在main()中会设置VLLM_WORKER_MULTIPROC_METHOD=spawn。
输出产物约定
- 每次运行写一个单声道 44.1 kHz WAV文件;
- 默认输出目录:
output_audio/; - 默认文件名:
ming_<case>.wav; --num-prompts > 1时按ming_<case>_00000.wav、ming_<case>_00001.wav… 索引;- 音频写出时先 clamp 到 [-1, 1] 再量化到 16-bit PCM(见
write_wav,runner.py); - 启用统计时还可写出:统计日志文件(如
ming_style_pipeline.log)与 manifest JSON——后者包含每个输出的元数据(request_id、stage_id、stage 耗时、峰值内存、采样率/样本数/时长/最大振幅)、prompt 信息与说话人嵌入形状,以及流式模式下的客户端延迟指标。
使用注意事项
style与ip是零说话人路径,不需要参考片段;emotion、basic、dialect、speech_bgm、speech_sound各需一个参考片段;zero_shot需要同时提供--ref-audio与--ref-text;podcast至少需要两个参考片段(通过--ref-audio-paths),并自动为每个参考片段提取一个说话人嵌入;--speaker-embedding既可包含单个 192 维向量,也可包含多个 192 维向量的列表;- 已验证运行均使用
--enforce-eager; - 早期 L4 验证中 Ming 音频 VAE 使用 SDPA 而非 FlashAttention2——后者是可用时的首选默认后端;
- 流式模式(
--streaming)每次进程调用仅支持一个 prompt,多 prompt 请使用阻塞模式。
如需在线服务形态(OpenAI 兼容/v1/audio/speechAPI)与 16.8B MoE 变体部署,可进一步参考 recipes/inclusionAI/Ming-omni-tts.md 与仓库内同名在线示例;若需深入模型实现,可查看 vllm_omni/model_executor/models/ming_tts/ 下的ming_tts.py(模型组装)、ming_tts_llm.py(Stage-0 AR LLM)、ming_tts_audio_vae.py(Stage-1 VAE 解码)与speaker_extractor.py(CampPlus 说话人嵌入)等模块。
【免费下载链接】vllm-omniA framework for efficient model inference with omni-modality models项目地址: https://gitcode.com/GitHub_Trending/vl/vllm-omni
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考