最开始做这个项目纯粹是为了好玩。
我有一天在网上听了很多 AI 翻唱,数量不少,但真正合我口味的歌不多。我又发现 Volibear 这个角色的翻唱基本没人做,就算偶尔能搜到,歌曲也很少。于是我开始想:能不能自己训练一个?
说干就干吧。
事实证明,这种“一下午随便玩玩”的突发奇想,最后通常都会稳定地吞掉后面一整周的时间。
为什么选 RVC
技术选型没什么复杂的。我随便搜索了一圈,最后锁定了 RVC。原因也很现实:它的资料多、现成工具多、训练和推理流程都比较成熟,而且单卡就能跑。对于我这种只是想尽快听到结果的人来说,它已经是当下最好的选择了。
我最后使用的是 RVC v2、48k 采样率、RMVPE F0 提取和 HuBERT v2 特征,训练设备是一张 RTX 4070 12GB。最初训练 200 个 epoch,后来发现通常 150 个就够了,再往后跑浪费时间也没有收益。
整个流程后来被我拿 AI 收拢成了一系列的脚本,方便我在聊天框里面指点江山:
1 | 收集语料 |
我懒得用 WebUI,所以直接把 RVC 项目拉到本地,让 AI Agent 写脚本接管整条训练流水线。这样反而能给每个版本的数据来源、参数和输出模型都能固定下来。我自己就是写前端的,我还能不懂 webui 么,他只会耽误我 all in agent 的步伐,哈哈。
我的语音来源
训练之前首先要解决的当然是语料。
我一开始就排除了国服语音。一方面是国服资源提取起来更麻烦;另一方面,今年正好有国内 CV 公开批评 AI 音色转换:大量游戏配音被做成语音包和二次内容,很多并没有取得授权。
虽然当时主要批评的是某些大公司借“用户上传”的名义规避责任的作风,但大公司有自己的法务和平台规则,真要出现争议,最先死的往往还是个人兴趣作者。我肯定不趟这个浑水,所以直接选了外服英语配音。
换成英语配音其实也没法解决版权和伦理问题,只是我不太想碰已经明确表达反对态度的国内 CV 音色,然后也不把这件事做成商业项目,就是玩玩。
确定方向以后,我先让 OpenCode 写爬虫,从 Wiki 下载 Volibear 的英语游戏语音,同时也下载了 Inkshadow 皮肤的语音。皮肤语音实际检查后发现不适合作为训练数据,我又补了《Legends of Runeterra》里的几十条相关台词。最后整理出 178 个可用文件,其中 132 个来自主体游戏语音,46 个来自 LOR。
总时长只有十几分钟,而且全是短促、表演感很强的游戏台词。这个数据规模拿来学音色勉强够,但拿来学唱歌就是先天不足了,这是后续一系列痛苦的根源。
AI Agent 在这个项目里到底帮了什么
训练过程里我得感谢 OpenCode 这个 AI Agent 产品。
虽然我写这篇 Blog 的时候,已经因为它的 Subagent 在各种边界条件下卡死的 Bug 触发得过于频繁,切到了更轻量、更稳定的 Oh My Pi,但 OpenCode 确实帮了我很多。
训练 AI 这类项目有个特点:真正需要灵感的工作不算多,大量时间都花在下载、重命名、筛选、转码、统计、批量运行和偶尔介入 Debug 上。这些工作单独看都不难,但数量非常多,而且任何一步出错都会污染后面的实验。AI Agent 很适合处理这种“简单,但是杂,而且必须反复做”的工程劳动。
我负责判断结果到底好不好、下一轮实验值不值得做;Agent 负责把数据管线、训练脚本、批量推理和分析工具搭起来。就算偶尔流口水也比我自己手动整理几百个音频文件快多了。
RVC 里一个让我哭笑不得的坑
RVC 当时还有一个很隐蔽的坑:我拿到的那版代码在提取 F0 特征时,把设备写死成了 CPU,然后又开多线程跑。
我看到 CPU 一直满载、GPU 却基本没动,就觉得不对,这里调用的库明明支持 GPU,RMVPE 本身也正适合用 CUDA。顺着调用链看下去,果然是写了个 device="cpu",估计是跑太慢又顺手加了个多线程。
也就是说,以前用这套 RVC WebUI 的人都在等 CPU 用多线程慢慢提取 F0。一想到这里我就想笑,如果不是我自己也会一点 PyTorch 也得踩坑。
给我看笑了,顺手改成 cuda 了。改完本来想提 PR,又想到还要做 self-review、兼容性和通用性检查,嫌麻烦就先放了一下,结果一放就放到现在,直到写这篇 Blog 才重新想起来。
我还想梳理一下这个多线程“优化”到底是怎么引入的,但本地仓库只是 depth=1 的浅克隆,没有历史。我再去 GitHub 查看时,发现 2026 年 7 月 21 日 RVC-Project/Retrieval-based-Voice-Conversion-WebUI 的仓库历史已经被一次强制覆盖式提交替换,旧的 Git 历史无法从当前仓库正常访问。新提交里倒是已经修复了设备判断,不再写死 CPU。
我只能说,这位作者多少有点把 Git 当 tar、把 GitHub 当网盘用了。换以前我可能会谴责这种做法不符合 Git 规范,是缺少工程责任的体现;不过现在我无所谓了,他愿意继续维护这个项目就不错了。
第一版模型:能说话,不代表能唱歌
第一版训练完成后,我立刻找了几首自己喜欢的歌去跑。第一首重点测试的是 Avicii 的《Without You》。
我一开始以为这就是一首普通流行歌,后来才知道这类现代电子乐一点也不简单,纯粹是给自己上难度:
- 原曲人声经过了大量制作和混音处理,本身就不是干净、自然、未经修饰的人声;
- 翻唱前需要先做人声与伴奏分轨,合成人声和复杂混音同样会挑战分轨算法,UVR5 之类的模型可能留下相位和频谱残留;
- RVC 底模学的是普通语音转换,不会自动理解商业电子音乐里的人声设计;
- Volibear 的训练数据全是说话,没有长音、滑音、颤音、换气和旋律短语;
- 角色声线很低,原始语料的音高范围也窄,高音数据几乎不存在;
- 游戏台词里还混有雷电、风暴和低频冲击音效,这些东西一旦被模型当成音色特征学进去,唱歌时就会一起冒出来。
最终效果显然是个灾难:文字含糊,高音失真,空档处出现怪叫;即使落在模型勉强能唱的频谱里,也会出现那种调音失败的 Vocaloid 一样的合成声,整体听起来非常撕裂。
后来我才意识到,现代电子乐的编曲、录音和混音都是高度专业化的技术工作。拿一个“脚本 + 音色转换模型”的流水线,根本碰瓷不了成熟商业作品的制作质量,尤其是《Without You》这种歌。
RVC 更适合人声处理相对少、人声与伴奏边界比较清楚的流行、民谣和部分摇滚。与此同时,选曲还得符合训练音色和音域:至少要“听起来像这个角色有可能唱出来”。超出角色音域太多、长时间高音、音色极亮或者原唱处理过重的歌,模型就是唱不出来。
所以,我们一开始幻想的那种“模型训练完,以后想听什么就让角色唱什么”的场景,其实不存在,工程难度太高了。
对于模型明确做不到的事情反而好办:认识到它做不了,直接开摆,不做了,就很简单。
真正可怕的是那些“理论上似乎还能优化”的东西。这才是后面烧掉我一周时间的罪魁祸首。
先把“听起来不好”变成可以比较的问题
发现质量不好以后,我就想着,坏了,得加大计量了。
首先得想办法比较不同模型。纯靠试听当然可以,但人耳很容易受到音量、歌曲、片段和预期影响,而且我很懒,也不能一直听。
我在 OpenCode 里面和 Deepseek 讨论了几轮,做了一套批量 Benchmark:准备多首相对干净、风格不同的人声歌曲,让所有模型转换同一批输入,再统计频谱指标,最后结合人工试听做判断。
真正有区分度的指标主要有这些:
- 频谱质心稳定性:观察音色亮度随时间的波动,数值越低,通常意味着颤抖和忽明忽暗的问题越少;
- 频谱质心:大致反映声音偏亮还是偏暗,不是越高越好,但能看出是否发闷;
- 0–500 Hz 能量占比:过高通常意味着低频膨胀,听起来糊、闷、像把嘴埋进被子里唱;
- 0.5–2 kHz 能量占比:这一段和人声清晰度关系更直接;
- 8 kHz 以上能量占比:用于观察高频毛刺和分轨、声码器带来的异常。
我也试过 HNR、频谱平坦度、过零率、jitter 和 shimmer。后来发现,UVR5 分离后的人声存在相位破坏,基于自相关的 HNR 几乎固定输出 -30 dB,根本不能用于比较;jitter 和 shimmer 也会被不稳定的 F0 提取污染。只能说音频处理 pipeline 这块对数据的破坏力度比我想的厉害多了,能废掉一堆评判自然人声的指标,听起来差不多的东西数据上差的比我预想的还要多。
所以最后的原则很简单:指标负责筛选和定位问题,耳朵负责决定成品。本来还想偷懒拿一个数字能替我判断“这首歌到底好不好听”的,这样就可以加大力度,睡前一个 /loop 下去让 ai 自己找办法优化,这样效果和账单起码有一个能让我第二天起来震惊瘫坐的。没办法,智能人力了
从 v1 到 v7.2:一轮轮试错到底改了什么
为了避免把几十轮实验写成流水账,我把真正影响结果的版本整理一下。
v1 / v2:先把流程跑通
最早的版本就是用收集到的游戏台词直接训练。v1 还包含一部分后来被剔除的数据;v2 清理到 178 个文件,并调整了高通滤波实现。
结果证明,filtfilt 换成 lfilter 这类静态滤波差异,对最终听感没有可检测的帮助。它们不完全没意义,但不是当时真正限制模型的东西。
v3:0.2 秒静音垫片,第一次明显提升
讨论了很多轮后,我突然意识到一个问题:游戏语音都很紧凑,文件往往从第一个音素开始,到最后一个音素立刻结束。模型从来没见过“声音自然开始”和“声音自然结束”是什么样子。
RVC 自己会对音频做内部切片,所以我在每个训练片段前后各加了 0.2 秒静音垫片,让模型能学到边界处的淡入、淡出和停顿。
这一版后来对应 volibear_original。改善非常明显,咬字和句尾稳定性提升了很多。这是第一次让我产生了“再找几个优化就能彻底解决”的错觉。
事实证明,这个错觉很贵。
v4:降噪没有带来第二次奇迹
有了静音垫片的成功经验,我又加了频谱降噪,训练出 volibear_denoised。
结果没有明显提升。继续加训练轮次、调整滤波、尝试各种预处理,也都没有复制静音垫片那种立竿见影的效果。我在这里卡了很久,因为每个方案听起来都“理论上有用”,但跑完以后就是没什么区别。
只能说,不是所有干净的数据处理都会让模型变好。而游戏音频本身已经比较干,降噪处理什么的作用已经很小了,还可能删掉音色细节。
v5:加入同一配音演员的数据
继续清洗十几分钟的 Volibear 台词已经挤不出多少收益,我开始想办法扩大数据集。
Volibear 英语配音演员是 David Sobolov。我翻了他参与的各种作品,最后在一个接近一小时的 YouTube 配音视频里找到了一段使用相近声线的 Washford 角色录音。提取人声后,我得到了大约 35.9 分钟的新数据。
v5 最终混合了 178 个 Volibear 文件和 778 个 Washford 片段,总计 956 个文件、2800 多个训练片段。新语料的数据量超过游戏台词后,原本混在游戏语音里的雷电和背景音不再占主导,模型的可用性又提升了一截。
这部分对应 volibear_sobolov,也是后面所有实验真正可靠的基底。
v5+:更长的片段更干净,但低频也更重
v5 的问题是切片脚本把音频切得太碎,平均片段只有 2.9 秒左右。短片段对音色还原有好处,但很难让模型看到完整的呼吸和连续表达。
于是我重新整理 Washford 数据,切成 151 个 5–15 秒的长片段,再和 178 个 Volibear 文件合并,训练出 volibear_sobolov_v2,也就是我内部叫的 v5+。
这一版的连续性和谐波干净程度更好,但也出现了新的代价:低频占比明显增加,声音更容易发闷。最后得到的结论不是“片段越长越好”,而是一个很现实的取舍:
- 短片段更贴近输入音色,重心稳定,但噪声和断裂感更明显;
- 长片段更容易学到连续表达,谐波更干净,但可能带来低频膨胀。
v6:Pitch Augmentation,彻底失败
因为原始语料的音域窄,我尝试对训练素材做 ±2、±4 半音的变调扩增,希望模型能见到更宽的 F0 范围。
结果非常直接:它不但没学会唱高音,连正常说话都开始不稳定。这个版本的稳定性和听感都明显退化,最后被我整个删掉。
这条路看起来合理,实际却忽略了一个问题:变调只是在数学上改变频率,不会凭空生成真实的发声方式、共鸣位置和唱歌技巧。它提供了“更高的音”,却没有提供“人是怎么唱出这个音的”。
所以 v6 给我的结论也很明确:Pitch Augmentation 对这个声音无效,以后不再碰。
v7:用模型自己制造“伪唱歌”数据
到这里项目再次进入瓶颈。David Sobolov 没有公开、可直接使用并且符合这个声线的唱歌素材,我能找到的基本都是说话。没有唱歌数据,模型就学不会长音、颤音、滑音和旋律短语。
最后我半摆烂地参考了 LLM 数据蒸馏和自训练的思路:既然没有真人唱歌语料,那就先让已有模型唱,再把相对好听的结果放回训练集。
严格来说,这和 LLM 蒸馏不是一回事,但思路很像:用现有模型生成带有目标结构的数据,让下一版模型学习这些结构。这里的伪唱歌数据不是用来重新定义“Volibear 的音色”,游戏台词和同 CV 数据已经负责这件事;它主要是让模型在特征空间里见到持续音、颤音、滑音和自然换气。
我最终选择 v5,而不是低频更重的 v5+,来转换干净的人声。v7 使用 John Legend 的《All of Me》和 Tracy Chapman 的《Fast Car》,各截取大约 150 秒,与 v5+ 基础语料一起训练。伪唱歌占总训练数据约 14%。
这一版把频谱质心稳定性做到了约 848 Hz,是所有版本里最稳的一版,证明伪唱歌方向是有效的。
但它也有一个明显问题:John Legend 和 Tracy Chapman 的选段整体偏暗,最后模型也学得偏暗。v7 的平均频谱质心约 827 Hz,0–500 Hz 低频占比约 57%,唱歌稳定了,却有点闷。
v7.1:过度过滤,把有用数据一起删了
我又尝试把伪唱歌切成句子,做陷波、质量门控和去重,希望只保留“最干净”的部分。
结果 286 个候选片段最后只剩下大约 3 分钟,伪唱歌比例降到约 12%。模型稳定性反而回退了约 119 Hz。
后续分析发现,同一个单人声模型生成的句子在频谱上天然非常相似,余弦相似度普遍超过 0.92。用频谱去重会把几乎所有句子都当成重复;用 F0 去重也没用,因为 Volibear 的主要音高范围只有大约 100–250 Hz,最后还是会收敛到同一小块空间。
最后总结出来是,过滤器不知道什么叫有用的唱歌模式,只会按照几个统计指标删东西。删到最后信息也一起没了,确实是个很“纯”的数据,可惜对训练没啥用。
v7.2:最终决定音色的,竟然是伪歌曲选曲
v7.2 没有继续堆复杂算法,而是回到最朴素的问题:既然 v7 太暗,那就换两首更亮的伪歌曲。
我选择了 Dido 的《Thank You》和 Birdy 的《Skinny Love》,仍然各取约 150 秒,伪唱歌比例保持在约 14%,其余训练设置基本不变。最终选择第 140 个 epoch 的 checkpoint。
结果如下:
| 模型 | 频谱质心 | 质心稳定性 | 0–500 Hz | 0.5–2 kHz | 听感 |
|---|---|---|---|---|---|
| v7 | 约 827 Hz | 约 848 Hz | 约 57.1% | 约 35.2% | 最稳,但偏暗、偏闷 |
| v7.2 | 约 933 Hz | 约 890 Hz | 约 50.2% | 约 41.5% | 更亮、更清楚,低频膨胀明显减少 |
v7.2 的稳定性比 v7 稍差一点,但清晰度和亮度的提升非常明显,综合听感更好,所以我最终把它定为正式版本。
这个结果也给了我整个项目里最有价值的结论:伪唱歌不是简单地“加一点唱歌数据”就结束了,选什么歌会直接控制模型最后的音色。
Dido 和 Birdy 的素材更亮,模型输出也更亮;John Legend 和 Tracy Chapman 的素材偏暗,模型就会往低频和暗色方向靠。
看来弄一堆自己也看不懂的脚本来筛东西还不如自己选两首歌,这数据处理的活还是太难干了。
还有一些看起来有用、实际没用的方案
这一周里我还试过不少东西,最后都被证明不值得继续:
- 对训练数据做 ±2 或 ±4 半音的 Pitch Augmentation:v6 已经证明无效;
- 对本来就比较干的游戏语音做 MDXNet 去混响:没有必要;
- 对输出做 8 kHz 低通:模型在 8 kHz 以上本来就没多少有效内容,只会进一步变闷;
- 调整 RVC 的
protect和filter_radius:频谱变化不到 1%,听感也没有意义; - 句子级频谱去重:单人声模型生成结果天然相似,最后会把数据删光;
- F0 去重:音域太窄,没有区分度;
- 把两个模型做 STFT 分频混合:交界处会破坏谐波结构;
- 做所谓的“去沙哑”谐波/噪声分解:对 UVR5 人声的破坏比修复更明显。
这些失败并不是完全浪费时间。至少它们帮我确认了什么不该再做,避免以后看到一个新参数就忍不住再训练一版。
最终模型也没有变成万能歌手
经过这么多尝试,我终于知道为什么网上没什么人做 Volibear 翻唱了:太难了啊。
花了这么多时间和算力,最后得到的也只是一个堪堪能用、仍然很难驯服的模型。v7.2 能唱的歌明显多了,咬字、清晰度和连续性也比第一版好很多,但它依然不能通用地“拿来就唱”。高音和极端音色区域还是可能出现怪叫,复杂电子人声仍然容易翻车,选曲依然比参数重要。
它就像一个音色很有特点、但是唱功不太稳定的人:得知道他的舒适区,给他选对歌,不然开始怪叫了。
不过我还是做了一些翻唱发到 Bilibili 了,应该能直接搜到。毕竟这个角色做的人确实很少,只要搜 Volibear 或者沃利贝尔 AI 翻唱,基本不会被淹没。
配图:跑了一千张之后,我选择了 Gemini
唱歌部分讲完了,接下来是配图和视频。
配图反而简单一点。我先试了 ComfyUI,又从 Civit AI 下载了 Volibear 的 LoRA,让 OpenCode 连接 ComfyUI API,把我的自然语言要求转换成 Prompt,然后自动批量生成。
最后跑了四五十个场景、接近一千张图,我决定改用 Google Gemini。
前面那一千张里,没有一张能稳定达到作品级海报的要求,各种构图、肢体、盔甲和风格都在发疯。这其实很正常,因为那个 LoRA 能拿到跑训练的图我基本都看过,我还不知道它能生成什么、擅长什么画面吗?反正不是我想要的音乐海报,哈哈。
严格来说 ComfyUI 其实是能做到的我的要求了,但是我太懒了,不想手动搞流程图,就想着让 OpenCode 驾驶 ComfyUI 抽卡自己看,那就很难了。
最后我发现这个许愿式的需求还得用现成的商业平台,Gemini 直接给了更接近正式封面的构图。最终视频使用一张带标题和作者信息的封面作为前几秒开场,之后切换到无文字主视觉,再叠加歌词。
视频:Kdenlive 崩了以后,我差点开始用 Blender 剪字幕
视频合成也有一段很荒唐的过程。
我的 Kdenlive 在 Debian + KDE + Wayland + NVIDIA 这套雷霆组合下面垮掉了。各种预览、编码和界面问题叠在一起,我没有办法,甚至一度开始用 Blender 剪视频字幕。
这很疯狂。Blender 当然能剪视频,但是我本来就懒,再让我拿着 Blender 剪视频我会疯掉的。
最后我还是回到了最简单的方案:
1 | 封面图 / 主视觉 |
开场十秒显示标题、作者和 AI Cover 信息,之后切换主视觉;字幕使用白字、黑色描边,固定在画面底部。这样没有复杂转场,也没有大量镜头,但至少稳定、可复现,而且修改歌词时间轴后可以直接重新生成。
折腾到最后,我已经懒得为它做什么宣传了。把视频丢到 Bilibili,再发给几个朋友,完事。
为什么我最后只写了 Blog,没有把整个项目传到 GitHub
做到这里可能会有人问:既然脚本、模型和流水线都已经有了,为什么不干脆整理一下传到 GitHub?
因为这是一个 90 多 GB 的实验现场。里面有 57 GB 训练日志、模型权重、Benchmark 输出、游戏语音、商业歌曲、分轨文件、生成图片,以及一个单独就有 206 MB 的 pack.zip。我还没有把 Github 当成网盘的习惯。
而且语音、歌曲和模型权重也没法一起公开,这可是实打实的侵权,小子,RVC 本身已经有上游仓库,我真正写的脚本里又混着本机路径、一次性实验和各种失败遗迹。原样上传, clone 下来大概率是参与技术考古。
真要发布,我需要整理一个干净的 code-only 仓库,只保留脚本、配置和说明,数据与模型全部排除——但是这样的成本太高了,而且我觉得短时间没有什么人会对这个角色的翻唱感兴趣,实在有兴趣的可以直接发一份邮件到我邮箱联系我,我肯定会倾力相助的。
所以现在先写 Blog。经验可以分享,实验现场就没必要打包上传了。除非我哪天清理硬盘遇到这个项目顺手清一下。
最后
这个项目最开始只是“让狗熊唱两首我喜欢的歌”,最后却变成了一整套数据收集、训练、评测、音频处理、图片生成和视频合成流水线。
我最后让 AI 帮我总结了一下学到的东西:
- 模型不会凭空学会训练数据里不存在的能力;
- 数据边界和片段组织,有时比增加训练轮次更重要;
- 同一配音演员的高质量语料,比大量相似但不匹配的数据更有价值;
- 伪唱歌可以补充唱歌模式,但比例和选曲会直接改变输出音色;
- 指标只能帮助定位问题,最终还是要靠统一输入下的人工试听;
- 失败实验最大的价值,是让我以后别再做一遍。
如果只看最终结果,这个模型仍然称不上成熟:它不会唱所有歌,也不能彻底避免怪叫。但从第一版那种高音全面撕裂、空档随机发疯的状态,到 v7.2 已经能稳定完成一批流行、民谣和摇滚歌曲,这个变化还是很明显的。
从“做一个通用 Volibear 歌手”的目标来看,这一个星期的工作还是比较失败的,因为这个目标根本没实现。
但从“我就是想听这个角色唱几首歌”的角度来看,也不算太失败。至少最后真的听到了,而且网上确实没多少人做。
那就够了,就这样了
评论