[工具] 给 GPT-SoVITS 加了一套批量推理工作流
最近在鼓捣《魔法少女的魔女审判》的 mod,除了写剧本和 mod 化以外,主要的工作就是配音。配音主要是用 GPT-SoVITS 基于原版语音训练之后做推理,但 GPT-SoVITS 自带的 WebUI 只能一句一句推理,仓库里自带的批量推理脚本也是个半成品。我一开始随手写了个脚本跑 for-loop,结果发现批量推理真正的难点根本不在循环——而在怎么给每句话选参考音频,否则配出来的效果实在太抽象了。
于是我 fork 了一份上游 GPT-SoVITS,加了一整套批量推理 + 自动初筛 + 人工复核的工作流。最初的第一版我用的是”按文本情感初筛”的思路,后来发现这其实优化错了目标——下面第一节就讲这个。因此在第二个版本中,我改成了”按演绎方式匹配”的版本。
首先,参考音频到底在参考什么
GPT-SoVITS 推理时要给每句话一条参考音频。在第一个版本中,我想到的方式非常直接:开心的台词配开心的参考、难过的配难过的就行,于是拿情感分类模型给参考库和台词都打个”情感标签”,再按相似度初筛。在很多情况下是可以用的,但是效果总差点意思
后来劳烦 Claude 研究了一个问题参考音频到底在参考什么?发现 GPT-SoVITS 真正从参考音频里”抄”走的,是它的演绎方式——语调、节奏、轻重、停顿、情绪能量,甚至录音环境——这些是 AR 模型把参考音频的语义 token 当成前缀”续写”出来的(类似 VALL-E 的 in-context learning)。
也就是说,“情感标签”和”实际怎么念的”根本不是一回事。同一句「私、大丈夫です」,可以是冷冷的、哭着的、强颜欢笑的,文本情感模型完全分不出来,但这恰恰是输出里最关键的东西。
新思路:按”演绎”匹配
整个匹配现在分成两侧:
- 参考库:对每条参考音频做声学分析——用一个维度情感模型(SER)给出 valence / arousal / dominance,再用 librosa 提取一组韵律特征(基频走向、能量、语速、停顿数),变成 7 个维度温暖度、激动度、强势度、语速、音量、音高起伏、停顿,范围大概 −3…+3,而 0 是这个角色的正常状态。这些维度分数在每个角色自己的参考库内做归一化(所以”快、响、夸张”都是相对这个角色平常的嗓音而言的)。和第一个版本一样,我们自然要缓存结果——这是在是太消耗时间了。
- 台词:对每一句,让一个 LLM 读它的上下文对白(以及可选的”演绎备注”),输出 7 个维度的数值,描述这句”该怎么念”。
然后在同一套维度上算加权距离,挑选最接近的。权重直接用数值本身的绝对值——某个维度给得越极端,它在匹配里就越重要;给 0 就表示”这维度无所谓”,不参与挑选。
准备工作
要跑起来你需要两样东西:一份角色配置,一份剧本。
角色配置 inputs/speaker_config.yaml 告诉工具你有哪些角色、每个角色的 GPT/SoVITS 权重在哪、参考音频库(一个标准的 .list,直接用训练集就行)在哪:1
2
3
4
5
6
7
8
9
10
11speakers:
ema:
gpt_path: GPT_weights_v2ProPlus/ema-e15.ckpt
sovits_path: SoVITS_weights_v2ProPlus/ema_e8_s2232.pth
ref_list: inputs/ema.list
ref_audio_dir: inputs/
meruru:
gpt_path: GPT_weights_v2ProPlus/meruru-e15.ckpt
sovits_path: SoVITS_weights_v2ProPlus/meruru_e8_s480.pth
ref_list: inputs/meruru.list
ref_audio_dir: inputs/
剧本 inputs/scenes/*.scene 是新的输入格式,用来更好的组织多样化的输入。纯文本,一行一句,文件名就是场景名(也是输出子文件夹):1
2
3
4
5
6
7
8
9
10# scene01 (场景名 + 输出子文件夹)
lang: ja (场景默认语言)
ema: 心配要らないよ。今回はボクも一緒だから。
note: 表面は優しく安心させる口調、でも奥に冷たい支配感
meruru: 私も大好きですよ、エマさん。
note: 素直で温かい、信頼しきった声
narrator: ふたりは指を絡め合った。 (旁白,不在配置里 → 只当上下文,不配音)
角色名: 台词,其中角色名要对得上 yaml 里的 key 才会被配音。- 缩进的
note:用来给”演绎指示”(中日英都行,LLM 看得懂),ref:可以固定某条参考音频,行内lang:可以覆盖场景语言。 - 不在配置里的说话人(比如
narrator:)只会被当作上下文喂给 LLM,不会被配音——旁白、不需要配的杂鱼角色都丢这里就行,它们能帮 LLM 了解场景,从而辅助打分。
打开 WebUI
双击仓库根目录的 go-batch-webui.bat,或者手动运行:1
runtime\python.exe -I webui_batch_inference.py zh_CN
浏览器会自动开 http://localhost:9870。UI 还是三个 Tab——配置、审阅与调整、帮助,对应”分析 → 复核 → 生成”两大步。
第一步:分析并挑选参考
在 配置 标签页填几个框:Scene files to read(剧本的路径,旁边能预览匹配到哪些文件)、Speaker config(自动扫描 inputs/*.yaml)、Output folder、每句保留几个候选,以及一个 AI delivery analysis 折叠栏——里面选用哪个 LLM(anthropic / openai / 本地的 openai_compatible / 或者 none 完全不用 AI)、上下文行数、还有个”多样性(temperature)”。
填完点击 Step 1 · Analyze & pick references。这一步不合成音频,而是:
- 把各角色参考库都进行一遍声学分析;
- 让 LLM 逐句读上下文和写的 note 算出 7 维演绎数值;
- 在每个角色自己的库里按加权距离挑出 Top-K 候选;
- 把这些结果连同候选写进每个场景旁边的
<scene>.profiles.json。
日志会实时输出到 Live log 框里。
第二步:审阅与调整
切到 Review & adjust,选一个刚分析过的场景。每页 3 句,每句都展示:
- 台词;
- 你给的 演绎备注;
- 7 个滑块(温暖度/激动度/强势度/语速/音量/音高起伏/停顿,0 = 无所谓);
- 几个内嵌音频播放器(就是挑出来的候选),外加一个单选让你决定用哪条。
- 也有一个选项锁定对这一条的修改。
改完点 Save changes 写回去。如果你改了 note 想让 AI 重新打分,点 Re-analyze this scene就可以。这一步最花时间,但也是质量的关键——绝大多数情况下候选里会有一条能用,实在没有,那多半是参考库里压根没有。
第三步:生成音频
复核完点 Generate audio for this scene。正式生成时会优先用你选定的那条参考。然后就可以把电脑丢给显卡过夜,第二天早上就可以看输出目录里的配音文件了。
关于 LLM 和那句 note
“分析”这步要调 LLM,在仓库根目录放个 .env 填上 key 就行:1
2OPENAI_API_KEY=sk-... (AI service 选 openai)
ANTHROPIC_API_KEY=sk-... (选 anthropic,默认)
也可以把 Server URL 指到本地的 Ollama / LM Studio / vLLM,或者干脆选 none 完全不用 AI、纯手动拉滑块。
note 是可选的,但很有用:没写 note 的句子,AI 就纯靠上下文判断;写了 note,note 说了算,这就像你是配音导演一样。
最后,仓库地址:https://github.com/AsaChiri/GPT-SoVITS,欢迎试用反馈,有问题直接来 Github 提 issue。