最近一直在尝试优化之前 Vibe 的播客翻译 CLI ,毕竟自用和分享为目的,开发方式还是尽可能做到 Human in Loop,主要一方面音频工具还是需要人参与评估效果,另一方面在踩坑同时积累点经验,不想欠太多认知债。
多渠道支持
TL;DR:主要还是给之前的播客翻译项目填坑,毕竟原来依赖阿里 DashScope 生态的话不太符合开源项目本地优先的原则,不关心的话可以跳过。
Google 翻译
去年可以白嫖的谷歌网页翻译的接口变更过一次,当时整了个脚本来白嫖新的接口,这次直接把脚本丢给 Codex,就很快在我的翻译接口中实现了谷歌渠道支持。简单测试了下速度快到飞起,并发也完全没问题。
vLLM-Omni
vLLM 最初设计用于支持基于文本的自回归生成任务的大语言模型。vLLM-Omni 是一个扩展了其对全模态模型推理与服务支持的框架:
- 全模态:支持文本、图像、视频和音频数据处理
- 非自回归架构:将 vLLM 的自回归支持扩展至扩散 Transformer(DiT)及其他并行生成模型
- 异构输出:从传统文本生成到多模态输出
简单来说就是 vLLM 的多模态版本。
快速开始失败
一开始参考的官方命令 uv pip install vllm --torch-backend=auto,由于使用的公司测试服务器,解决各种依赖问题后,还是卡在了低 glibc 版本的编译问题上。由于不想在环境上浪费太多时间,直接弃暗投明切换方案到 docker 上。
镜像构建
首先确认驱动版本:
1 | (root) [root@gpu01 ~]# nvidia-smi |
cuda 版本天花板卡在了 12.8,由于官方构建的镜像基于 12.9,所以得自己搓一个镜像:
1 | FROM nvidia/cuda:12.8.1-cudnn-devel-ubuntu22.04 |
保存退出后即可开始漫长构建:
1 | docker build -t vllm-omni-cu128 . |
Docker,启动
构建成功后就可以启动了,启动时注意把环境中的 HF_TOKEN 和 HF_ENDPOINT 带进容器。
1 | docker run --rm --gpus all -v ~/.cache/huggingface:/root/.cache/huggingface -e HF_TOKEN="$HF_TOKEN" -e HF_ENDPOINT="$HF_ENDPOINT" -p 8091:8091 --ipc=host vllm-omni-cu128 Qwen/Qwen3-TTS-12Hz-1.7B-Base --omni --port 8091 |
api 服务成功启动,但是调用时发现很慢,单次调用五分钟还没有结果返回(后续会快很多)。
vllm-onmi 的 qwen3_tts 官方文档中有特别说明后端服务的单线程与多线程的区别:
基础克隆任务在每次请求时都会进行参考音频编码,因此进程间通信开销占总成本的比例较大。
官方推荐 Base 规格的启动方式如下:
1 | vllm serve Qwen/Qwen3-TTS-12Hz-1.7B-Base \ |
vLLM-Omni 的 v0.18.0 版本默认 mp 模式且没有上述配置文件,试了下单独的配置参数没有太大效果,后续升级镜像版本应该会快些。
1 | (APIServer pid=1) INFO 04-27 03:18:35 [api_server.py:324] Starting vLLM API server 0 on http://0.0.0.0:8091 |
等待一会 API 服务启动成功,实际这个接口也可以并发调用,但是由于任务主要瓶颈还是在显卡侧,所以超时时间较短的话,实际测试和单线程跑效率差异不大,反而容易造成失败重试多次调用导致的资源浪费。
做完本地 Qwen 支持后发现 vLLM-Omni 有点鸡肋了。。
本地 Qwen TTS
vLLM-Omni 兼容性虽然强,部署起来还是有点麻烦,最好还是使用 qwen-tts 的官方依赖来简化使用,犹豫再三还是作为附加依赖放进了项目中,保证主依赖尽可能干净。
1 | [project.optional-dependencies] |
安装时只要附带 [qwen-local]就行:
1 | uv tool install --torch-backend auto "podtran[qwen-local] @ git+https://github.com/R0sin/podtran" |
接口方面让 AI 参考 Qwen 官方的 sdk 很快集成好。其实 0.6B 大小的语音生成效果已经很不错了,速度方面还是比较依赖配置,具体效果的话后面有说明。
VibeVoice
正好刷到 Simon Willson 发的一篇体验,看了下 VibeVoice 这个微软开源的音频推理框架,主打播客这种长音频场景,不过由于参数量不小配置要求也不低,并且最大支持一小时的特性不太适配我的切片处理,暂不考虑了。
Gemini 3.1 Flash TTS
接口格式看起来需要重新适配,不过胜在免费,后面有空再看看。
跨语种克隆优化
本地克隆的痛点
之前 AI 在实现 vllm-omni 和 qwen-local 渠道时已经帮我把 instructions 字段配置预留出来,试了下通过指令控制预置音色的语速慢、情感过于丰富等问题,但是 preset(预置音色)最大的问题在于工作流无法识别说话人的性别,需要人工介入设置或者引入额外的模型来解决。而默认的 clone 模式则会带来明显的跨语种口音问题。
测试 DashScope 的云服务虽然也有口音问题,但是比我本地 1.7B 的效果好不少,怀疑是阿里对跨语种音色克隆编排做了优化,或者藏了更大参数的模型。
尝试解决
又试了下这个参数在 vllm-omni 的音色克隆模式下虽然有传但实际没有效果,难怪在 Qwen 官方 sdk 封装的 generate_voice_clone() 没有 instruct 参数。
于是找到 vLLM-Omni 语音克隆(Qwen)接口的标准参数如下:
| 参数 | 类型 | 必填 | 描述 |
|---|---|---|---|
ref_audio |
string | 必填 | 参考音频(HTTP URL, base64 数据 URL 或带有 --allowed-local-media-path 的 file:// URI) |
ref_text |
string | 否 | 参考音频的转录文本(用于 ICL 模式) |
x_vector_only_mode |
bool | 否 | 仅使用说话人嵌入(无 ICL) |
搜索了下 x_vector_only_mode 这个参数的官方说明是用来控制音频参考文本(ref_text)的开关,默认关闭表示需要传参考文本用于 ICL(In-Context Learning)上下文学习。实际测试的话如果默认关闭,音色更偏向原声,但是会有上述歪果仁口音的问题。
x_vector_only_mode=false
如果开启的话,返回的就是字正腔圆的中文,语速也适中。
x_vector_only_mode=true
Yes, but
很快代价就暴露出来:
这段仅和上面隔了一段,但是音色已经发生了很大转变。
音色丢失的问题还好,毕竟在穿插模式下的输出音频也只需要补充翻译的功能职责。但是音色漂移在长播客的场景下听感太差很容易出戏。
灵感实践
既然开启 ICL 有更好的音色一致性和坏口音,而关闭 ICL 则会带来自然口音但音色漂移的问题,那么不难想到,如果尝试从工程上解决痛点的话,可以先开启 x_vector_only_mode,clone 一段中文发音标准,男女声等基本特征正确的参考音频作为标准。再关闭 x_vector_only_mode 重新跑,来保证所有段落的音色一致性。
有想法了就使唤 Codex 开工,正好 OpenAI 大善人今天重置额度,本来还以为得拖到明天的。
由于 vLLM-Omni 也是用的 Qwen,所以直接用 0.6B 的版本快速测试下。
附上测试的最终效果:
Huberman Lab 的采样由于介绍太长(恰饭推广太多),而默认最小说话人是 2,所以后面会多一个声音,问题不大。
现在的效果已经足够稳定。第一轮抽卡理论上应该可以调参或者多抽来优化效果,不过还是先暂不考虑过早优化了,后面有空再试试用 1.7B 首抽会不会更好。
本地推理速度优化
TL;DR:本地的话主要针对 Qwen-TTS 这个方便开箱即用的场景做测试,优化的方向主要还是显存/内存(Money)换时间。
简单记录
找手头几个环境测试了下,执行预览模式(5 分钟)的话:
- 笔记本(Intel U7 155H + 32G RAM):默认 ASR 配置(medium + int8)下大概需要 5 分钟,运行时大约 3G 内存;翻译用的谷歌时间基本可忽略;TTS 用的 0.6B 的本地 Qwen 需要 30 分钟,运行时大约 8G 内存。
- 服务器(3090):ASR 配置(distil-large-v3 + float16)2 分钟;TTS 也用 0.6B 的跑了 20 分钟,显存仅用 1/10。
这么看来的话只能预览听听,想用的话效率有点低。搜了下 qwen-tts 是支持 batch 推理的,随即在配置中加上参数支持开始继续给内存上强度——测试同音源 batch 改为 4 后虽然多吃了 3G 内存(毕竟还得从 Chrome 碗里抢),时间直接缩短到了 15 分钟。
虽然有点吃资源,但优化效果还是肉眼可见的。配合 resume 模式在中午等空闲时间断点续跑的话,一周跑一个长播客通勤听问题不大(中途不出问题的话)。
而在 GPU 环境效果会更好些——同 0.6B 参数量的模型,单卡 3090 之前跑 5 分钟预览需要 20 分钟,batch 加到 12 后只需要 3 分钟即可跑完。
What’s Next
之前调研了下直接发布到 Spotify 之类的平台会有版权风险,后续应该会考虑支持发布到 RSS,实现客户端自动订阅。订阅实现后再找个三方的音频源下载,整理成 skill 丢到虾啊马啊什么的上面跑的话应该会比较方便。
MLX 的推理适配应该需要单独做,不过手头没 mac 设备,还是先搁置吧。版本稳定之后可以再套个前端页面或者 GUI。
