当前位置: 首页 > news >正文

Seed-VC 语音克隆指南

语音转换基本上就是将一个说话者的语音拿出来,使其听起来像另一个人——同时保持原始内容不变。它有广泛的应用场景,从AI配音和虚拟YouTuber到个性化语音生成。

但在实践中,事情并不总是那么完美。传统方法通常在处理未见过的说话者时会遇到困难,而且它们并不总是能很好地将说话者身份与实际内容分离——这可能导致不自然或混合的结果。

这就是为什么零样本语音转换是一个如此重要的想法。与其为每个说话者训练一个模型,零样本方法可以使用短参考音频适应新的声音。这使得整个系统在现实场景中更加灵活和实用。

在本文中,我将介绍Seed-VC,这是一种旨在解决这些挑战的现代方法。Seed-VC不是直接将一个声音映射到另一个声音,而是首先将语音分离为内容和说话者风格,然后重新组合它们来生成目标声音。

在此基础上,它利用基于扩散的生成过程,实现更自然、更逼真的语音合成。因此,Seed-VC即使在模型从未见过的说话者身上也能实现高质量的零样本语音转换。

通过本文,你将清楚地理解Seed-VC框架以及如何使用LibriTTS数据集在PyTorch中实现完整的语音转换管道——从语义特征提取到基于扩散的语音生成。

1、为什么零样本语音转换很难

语音转换已经走过了很长的路,近年来取得了许多令人印象深刻的成果。但当涉及到真正的零样本推理时,只有少数方法在实践中效果好。乍一看,这个想法听起来很简单:

将正在说的内容(内容)与说话者(音色)分离,然后重新组合。

但在实践中,这种分离远非完美。有三个基本问题使零样本语音转换特别具有挑战性。

1.1 音色泄漏

最大的问题是所谓的音色泄漏。大多数语音转换系统尝试使用wav2vec或HuBERT等模型提取与说话者无关的"内容"特征。理想情况下,这些特征应该只表示语言信息——正在说什么——而不携带任何关于说话者的信息。

但实际上,它们并非如此。这些表示仍然携带原始说话者声音的微妙痕迹。因此,当我们把这种"内容"与目标说话者的声音组合时,模型实际上是在混合两种身份。结果,声音听起来既不像源说话者也不像目标说话者——而是介于两者之间的某种东西。这不完全错误,但绝对不是我们想要的。

1.2 弱音色表示

即使我们能从内容中完美地去除说话者信息,还有另一个问题:

我们如何表示目标说话者?

大多数传统方法将一个人的声音压缩成一个嵌入向量。当模型在训练期间已经见过该说话者时,这种方法效果不错。但在零样本设置中,这成为一个严重的限制。

单个向量根本无法捕捉人类声音的全部丰富性——比如说话风格、节奏、语调和微妙变化等。结果,生成的语音通常听起来:平淡、过度平滑,或仅粗略地类似于目标说话者。

1.3 训练与推理的差距

Seed-VC强调的最后一个问题是训练和推理之间的差距。在训练期间,大多数模型学习从同一说话者重建语音:

content (A) + timbre (A) → speech (A)

但在推理期间,我们要求模型做完全不同的事情:

content (A) + timbre (B) → speech (B)

这种不匹配在模型训练要做的和我们期望它在实践中做的之间造成了根本差距。由于模型从未真正在这种跨说话者场景中进行过训练,它在零样本设置中的性能自然会下降。

2、Seed-VC如何解决这些问题

现在让我们看看Seed-VC如何解决这些问题~

Seed-VC架构(来源)### 2.1 音色转换器

为了解决音色泄漏问题,Seed-VC引入了一个简单但强大的想法。模型不是直接从原始语音中提取内容,而是首先使用音色转换器修改说话者的声音,然后才从修改后的版本中提取内容。

回顾原始音色泄漏问题:

原始语音(说话者A) ↓ 提取内容(仍然包含A的音色) ↓ + 说话者B的音色 ↓ 输出(混合身份)

此时,一个自然的问题出现了:

如果我们在应用音色转换器后提取内容,它不仍然会包含说话者信息——只是来自改变后的说话者?

答案是肯定的——而这正是关键所在。新的Seed-VC管道如下所示:

原始语音(A) ↓ 音色转换器 → (A → 随机说话者R) ↓ 提取内容(现在包含R的音色) ↓ + 目标音色(A或B) ↓ 输出

从新的管道中,我们可以看到每次使用来自说话者A的相同输入语音时,它都会被转换为不同的随机说话者。因此,提取的内容总是携带不一致且变化的说话者信息。

这在训练期间产生了重要效果。由于内容中的说话者信息不再稳定或可靠,模型不能依赖它来最小化损失。它唯一能做的就是学会忽略这些不稳定的说话者线索。

而这正是我们想要的。不是试图从内容中完美地去除说话者信息——这极其困难——Seed-VC使该信息变得不可靠,迫使模型只关注正在说的内容,而不是说话者是谁。

2.2 解决训练与推理差距

如前所述,Seed-VC首先使用音色转换器将原始语音转换为移位版本,然后训练模型从中恢复原始语音。

移位语音(A → 随机)+ 音色(A)→ 语音(A)

这完全改变了训练目标。模型不再学习同说话者重建,而是在训练期间始终处理不匹配的说话者条件。

因此,模型已经在与推理时间紧密匹配的设置下进行了训练。模型在训练期间看到的和我们在推理时期望它做的之间不再存在差距。

2.3 扩散Transformer

最后,Seed-VC采用扩散Transformer作为核心架构,将源语义转换为目标语音。使用基于注意力的模型的关键优势是它能够随时间动态关注输入的不同部分。这对于语音特别重要,因为时间结构和微妙变化起着关键作用。

更重要的是,Transformer允许模型联合推理语义特征和说话者信息,实现正在说的内容和应该如何听起来之间的更准确对齐。因此,生成的语音更加连贯、自然且与说话者一致。

3、训练与推理步骤

训练步骤 ------------------- 原始语音(A) ↓ (1) 说话者分支: 原始语音 → CAM++ → 说话者嵌入s (2) 内容分支: 原始语音 → 语义(A) ↓ 音色转换器 → 移位语音(A → 随机R) ↓ 语义(R) ↓ 组合(时间维度拼接): [ 语义(A)(前部分/作为参考保留)] [ 语义(R)(后部分/待重建)] + 说话者嵌入s + 时间步t + 掩码 ↓ U-DiT(扩散Transformer) ↓ 重建目标语音(A) (仅后部分被预测) ↓ 计算损失(仅掩码区域) 推理步骤 ------------------- 参考语音(目标B) ↓ (1) 说话者分支: 参考语音 → CAM++ → 说话者嵌入s (2) 内容分支: 源语音(A)→ 源语义 参考语音(B)→ 参考语义 ↓ 组合(时间维度拼接): [ 参考语义(前部分/提示)] [ 源语义(后部分/待转换)] + 说话者嵌入s + 时间步t + 掩码 ↓ U-DiT(扩散Transformer) ↓ ODE求解器(迭代去噪) ↓ 生成的频谱图 (仅源部分是新生成的;参考部分保留/忽略) ↓ 声码器 ↓ 转换后的语音(A → B)

3.1 LibriTTS数据预处理

为了训练我们的模型,我们使用LibriTTS数据集,这是一个从LibriSpeech构建的大型英语语音集合。在预处理期间,数据加载器加载每个音频文件,将其转换为mel频谱图,并在批次内填充所有内容使它们具有相同长度。

你可以在以下链接找到’mel_spectrogram’函数:链接

3.2 设置OpenVoice音色转换器

在Seed-VC中,OpenVoice的ToneColorConverter被用作音色转换器。它能够将输入说话者的声音转换为来自预训练说话者数据库的不同说话者音色。在训练期间,此组件用于随机将源说话者的音色转换为另一个说话者。

让我们首先从GitHub仓库安装模块~~

!git clone https://github.com/Alienpups/OpenVoice.git cd OpenVoice !pip install -r requirements.txt

注意,requirements中的某些版本已过时,可能与较新的PyTorch不兼容,因此我建议使用更新的版本

由于默认的OpenVoice音色转换器只接受音频文件路径作为输入,因此在训练中效率很低。为了使其适合我们的管道,我们修改它以直接接受波形输入。

具体来说,用以下版本替换ToneColorConverter类中的extract_seconvert函数:

现在,我们可以将预训练权重加载到音色转换器中,你可以在以下链接找到这些模型权重的详情:链接1和链接2

3.3 CAM++说话者嵌入

要执行从说话者A到说话者B的语音转换,模型需要了解目标说话者的声音特征。这是使用CAM++模型完成的,它从参考音频中提取说话者嵌入。该嵌入主要设计用于捕捉说话者的声音特征,同时尽量减少语言内容的包含。

你也可以尝试其他说话者嵌入方法,如ECAPA-TDNN、d-vector或HuBERT,尽管它们的性能可能因任务而异。

注意:你可以从Seed-VC GitHub仓库获取此模块,将modules/campplus下的所有文件复制到你的工作目录。CAM++模型的详情可参考:链接

3.4 Wav2Vec2特征提取器

最后,我们将使用的最后一个预训练模型是Wav2Vec2模型。与CAM++提取说话者嵌入类似,Wav2Vec2用于从波形中提取内容表示。这些表示关注语言信息(即正在说什么),而不是说话者的身份。

3.5 准备DiT模型输入

现在,我们将所有内容整合在一起,并将其转换为扩散模型期望的格式。*get_model_input*函数输出训练期间使用的所有必要输入。

target: → 真实mel频谱图 → 模型尝试重建的目标 → 用于计算训练损失 → 形状:(B, 80, T) cond: → 混合语义条件(内容引导) → 第一部分 = 原始语音(A) → 剩余部分 = 转换后语音(R) → 强制模型学习独立于说话者的内容 → 形状:(B, T, 384) style: → 说话者嵌入(来自CAM++) → 表示"说话者是谁" → 注入以控制目标声音身份 → 形状:(B, 192) prompt_len: → 原始语义前缀的长度 → 控制揭示多少"真实内容" → 用于模拟基于提示的生成 → 形状:(B,) mel_lengths: → 每个样本的有效长度 → 用于掩码(在损失中忽略填充) → 形状:(B,)

需要注意的一点是,我们使用长度对齐模型将语义嵌入(S_ori, S_alt)的时间维度与mel频谱图对齐,因为Wav2Vec2通常会降低时间分辨率。

4、构建模型与训练步骤

Seed-VC中使用的模型是专为音频设计的扩散Transformer。其主干遵循具有跳跃连接的U形Transformer架构,使其能够捕获全局上下文和细粒度细节。它还结合了RoPE以更好地建模时间结构。

在训练期间,我们使用无分类器指导随机丢弃一些条件,这使模型在推理时更加稳健和灵活。

DiT模型的输入数据(来源)```
y (Mel + Mask):
→ 噪声mel频谱图(在噪声z和干净x之间插值)
→ DiT模型的实际输入
→ 形状:(B, 80, T)

prompt (Mask + Mel):
→ 部分真实mel(前缀区域)
→ 提供给模型的可见区域(不加噪)
→ 用于上下文/基于提示的生成
→ 形状:(B, 80, T)

cond (原始语义 + 改变后的语义):
→ 混合语义条件(内容引导)
→ 第一部分 = 原始语音(A)
→ 剩余部分 = 音色移位后的语音(R)
→ 防止音色泄漏并强制内容一致性
→ 形状:(B, T, 384)

style (s):
→ 说话者嵌入(来自CAM++)
→ 表示目标说话者身份
→ 作为全局条件token注入
→ 形状:(B, 192)

t:
→ 连续扩散时间步
→ 控制噪声水平/去噪阶段
→ 形状:(B,)

以上是DiT模型的输入。它将'*y*'、'*prompt*'和'*cond*'拼接作为主输入,而'*style*'和时间步'*t*'作为条件信号注入到每一层。 ### 4.1 流匹配 Seed-VC中使用的训练策略基于流匹配。核心思想是通过训练模型预测转换(或"流")来学习从噪声到干净数据的映射,而不是直接重建目标。 例如,给定一个干净的mel频谱图'*x*'和随机噪声'*z*',我们首先使用时间步'*t*'在它们之间插值以获得噪声输入'*y*'。模型不是直接预测'*x*',而是训练预测一个速度项: ![None](https://i-blog.csdnimg.cn/img_convert/24f7d82d5da75e16e459090e16b79400.webp?x-oss-process=image/format,png) 它表示从噪声指向干净数据的方向。模型将'*y*'作为输入并输出预测速度,训练损失通过将此预测与真实值'*u*'比较来计算。 ![None](https://i-blog.csdnimg.cn/img_convert/693239434913426ec094229677ade699.webp?x-oss-process=image/format,png) 在推理期间,生成过程被视为求解ODE。从纯噪声开始,模型在每个时间步预测一个速度场,样本通过随时间积分该场来更新。结果,噪声逐渐被转换为逼真的mel频谱图。 ### 4.2 训练循环 最后,训练循环如下所示。这是一个简单的示例,用于说明整体流程。在实践中,你可以通过添加EMA(指数移动平均)或学习率调度器等技术进一步提高性能。(*注意:通常20-30个epoch的训练可以获得一些合理的转换结果。*) ### 4.3 模型推理 我们在推理期间使用ODE采样器来生成最终音频。你可以将其想象为从随机噪声开始,在模型预测的速度引导下,逐渐将其推向目标分布。 Seed-VC中使用的声码器基于HiFi-GAN。你可以尝试其他声码器将mel频谱图转换回波形,但要确保mel配置与数据加载器中使用的匹配。 --- 原文链接:[Seed-VC 语音克隆指南 - 汇智网](https://www.hubwiz.com/blog/seed-vc-voice-cloning-guide/)
http://www.jsqmd.com/news/742690/

相关文章:

  • PeerTube 部署指南:自建视频托管平台
  • Helm GCS插件:在Google云存储上构建私有Chart仓库的完整指南
  • AI应用开发实战指南:从API调用到智能体工程化
  • 【仅限前200名工控开发者】:获取完整C语言PLCopen Level B兼容套件(含SFC状态机C代码生成器+CANopen PDO映射表自动推导模块)
  • 普通车床数控化改造 毕业设计 及全套CAD图
  • OpenClaw离线安装包:零配置部署AI代理的Windows解决方案
  • ROS Kinetic-信号与系统-趣味案例
  • Zwift离线版终极指南:如何在无网络环境下构建专属虚拟骑行训练室
  • 纹理映射不止于游戏:用Three.js和WebGL打造高清数据可视化的完整流程
  • 保姆级教程:在1Panel面板上,用Docker一键部署MaxKB知识库并连接本地Ollama(Llama3模型)
  • 基于Node.js与微信API的Markdown自动化排版发布工具实践
  • Mem Reduct中文界面设置终极指南:3分钟让你的内存清理工具说中文
  • FastAPI API版本控制新思路:基于cadwyn的声明式版本管理实践
  • Ubuntu 18.04 经典 / 有趣 / 实用 APT 软件清单
  • 终极AI小说推文自动化方案:6小时完成从文字到视频的全流程创作
  • 硬件、环境与软件:那些让你怀疑人生的“玄学”Bug排查实录
  • 旋转机械系统形性一体数字孪生模型构建状态监测【附代码】
  • HPH构造大揭秘,新国标下家电更智能
  • Python项目启动报RequestsDependencyWarning?手把手教你锁定urllib3和chardet的兼容版本
  • 别再乱配了!SAP MRP批量大小(EX/FX/WB)实战避坑指南,附MD04结果对比
  • 构建本地化A股智能分析平台:OpenAshare架构解析与实战
  • 外包协作自动化工具套件:ClawSuite的设计原理与实战应用
  • KLineCharts配置避坑指南:在Vue3中自定义十字光标和指标样式的正确姿势
  • Mamba与Transformer融合架构:高效语言模型新突破
  • ARM GICv3中断控制器架构与调试实践
  • EldenRingSaveCopier:基于二进制逆向工程的游戏存档迁移架构解析
  • 新手零基础入门:在快马平台边学边练掌握vmware workstation核心操作
  • Orange Pi RV开发板:30美元起的RISC-V单板计算机解析
  • 从老式收音机到蓝牙音箱:聊聊功放电路简史与DIY一个TDA2030小功放的实战
  • Flowable外置表单实战:SpringBoot集成JSON表单与HTML表单的完整配置与避坑指南