ChatTTS

https://github.com/2noise/ChatTTS/blob/main/docs/cn/README.md
https://2noise.com/
https://github.com/libukai/Awesome-ChatTTS
  1. 对话式 TTS: ChatTTS 针对对话式任务进行了优化,能够实现自然且富有表现力的合成语音。它支持多个说话者,便于生成互动式对话。
  2. 精细的控制: 该模型可以预测和控制精细的韵律特征,包括笑声、停顿和插入语。
  3. 更好的韵律: ChatTTS 在韵律方面超越了大多数开源 TTS 模型。我们提供预训练模型以支持进一步的研究和开发。

数据集和模型

  • 主模型使用了 100,000+ 小时的中文和英文音频数据进行训练。
  • HuggingFace 上的开源版本是一个在 40,000 小时数据上进行无监督微调的预训练模型。
###################################
# Sample a speaker from Gaussian.

rand_spk = chat.sample_random_speaker()
print(rand_spk) # save it for later timbre recovery

params_infer_code = ChatTTS.Chat.InferCodeParams(
    spk_emb = rand_spk, # add sampled speaker 
    temperature = .3,   # using custom temperature
    top_P = 0.7,        # top P decode
    top_K = 20,         # top K decode
)

###################################
# For sentence level manual control.

# use oral_(0-9), laugh_(0-2), break_(0-7) 
# to generate special token in text to synthesize.
params_refine_text = ChatTTS.Chat.RefineTextParams(
    prompt='[oral_2][laugh_0][break_6]',
)

wavs = chat.infer(
    texts,
    params_refine_text=params_refine_text,
    params_infer_code=params_infer_code,
)

###################################
# For word level manual control.

text = 'What is [uv_break]your favorite english food?[laugh][lbreak]'
wavs = chat.infer(text, skip_refine_text=True, params_refine_text=params_refine_text,  params_infer_code=params_infer_code)
torchaudio.save("output2.wav", torch.from_numpy(wavs[0]), 24000)

模型组成:LlamaModel、DVAE(VQVAE)、VOCOS声码器

文本控制

  • 1. Input Text : 需要转换的文本,支持中文和英文混杂
  • 2. Refine text : 是否对文本进行口语化处理
  • 3. Text Seed : 配置文本种子值,不同种子对应不同口语化风格
  • 4. 🎲 : 随机产生文本种子值
  • 5. Output Text : 口语化处理后生成的文本

音色控制

  • 6. Timbre : 预设的音色种子值
  • 7. Audio Seed : 配置音色种子值,不同种子对应不同音色
  • 8. 🎲 : 随机产生音色种子值
  • 9. Speaker Embedding : 音色码,详见 音色控制

情感控制

  • 10. temperate : 控制音频情感波动性,范围为 0-1,数字越大,波动性越大
  • 11. top_P :控制音频的情感相关性,范围为 0.1-0.9,数字越大,相关性越高
  • 12. top_K :控制音频的情感相似性,范围为 1-20,数字越小,相似性越高

系数控制

  • 13. DVAE Coefficient : 模型系数码
  • 14. Reload : 重新加载模型系数

播放控制

  • 15. Auto Play : 是否在生成音频后自动播放
  • 16. Stream Mode : 是否启用流式输出
  • 17. Generate : 点击生成音频文件
  • 18. Output Audio : 音频生成结果
  • 19. ↓ : 点击下载音频文件
  • 20. ▶️ : 点击播放音频文件

示例控制

  • 21. Example : 点击切换示例配置

快速体验

网址类型
Original Web原版网页版体验
Forge WebForge 增强版体验
LinuxPython 安装包
Samples音色种子示例
Cloning音色克隆体验

热门分支

功能增强

项目Star亮点
jianchang512/ChatTTS-ui提供 API 接口,可在第三方应用中调用
6drf21e/ChatTTS_colab提供流式输出,支持长音频生成和分角色阅读
lenML/ChatTTS-Forge提供人声增强和背景降噪,可使用附加提示词
CCmahua/ChatTTS-Enhanced支持文件批量处理,以及导出 SRT 文件
HKoon/ChatTTS-OpenVoice配合 OpenVoice 进行声音克隆

功能扩展

项目Star亮点
6drf21e/ChatTTS_Speaker音色角色打标与稳定性评估
AIFSH/ComfyUI-ChatTTSComfyUi 版本,可作为工作流节点引入
MaterialShadow/ChatTTS-manager提供了音色管理系统和 WebUI 界面

FunAudioLLM:人类和LLMs之间自然交互的语音理解和生成基础模型

https://funaudiollm.github.io/  [阿里团队]
arxiv.org/abs/2407.04051

[Paper] [Code] [Modelscope:SenseVoiceCosyVoice] [HuggingFace: SenseVoice]

我们介绍FunAudioLLM,本报告介绍了FunAudioLLM,这是一个旨在增强人类与大型语言模型之间的自然语音交互的框架(LLMs)。其核心是两个创新模型:SenseVoice用于高精度多语言语音识别,情感识别和音频事件检测;CosyVoice用于多语言,音色和情感控制的自然语音生成。SenseVoice具有极低的延迟并支持50多种语言,而CosyVoice在多语言语音生成、零触发语音生成、跨语言语音克隆和指令遵循功能方面表现出色。与SenseVoice和CosyVoice相关的模型已经在Modelscope和Huggingface上开源,沿着相应的训练,推理和微调代码发布在GitHub上。 通过将这些模型与LLMs集成,FunAudioLLM可以实现语音翻译、情感语音聊天、交互式播客和富有表现力的有声读物叙述等应用,从而推动语音交互技术的发展。

SenseVoice支持多语言语音识别,其训练时间超过30万小时。具体来说,SenseVoice-Small在推理方面非常高效,其中识别延迟小于80 ms,分别比Whisper-Small和Whisper-large快5倍和15倍以上,SenseVoice-Large支持50多种语言的高精度ASR。此外,SenseVoice支持丰富的转录,包括最先进的情感识别、音频事件检测、反向文本标准化(Pusateri 等人,2017)和标点符号(Chen 等人,2020年)。

语音生成模型,CosyVoice,可以生成多语言的语音,这是超过17万小时和五种语言,包括中文(ZH),英语(EN),日语(JP),广东话(Yue)和韩语(KO)的训练。CosyVoice生成的样本可以实现低于2%的WER和超过75%的说话人相似度,达到人类平价的质量水平。CosyVoice支持零样本上下文学习,这使得语音克隆只需要3秒的提示语音。音色、情感、韵律和风格可以在语言内部或跨语言复制。我们还发布了一个指令模型,它可以控制说话者身份,说话风格(例如,情感)和其他具有自然纹理指令的细粒度语言特征。

Speech-to-Speech Translation:

通过集成SenseVoice、LLMs和CosyVoice,我们可以毫不费力地执行语音到语音翻译(S2ST)。

Emotional VoiceChat 情感语音聊天:

通过集成SenseVoice、LLMs和CosyVoice,我们可以开发一个情感语音聊天应用程序。

Interactive Podcast 互动播客:通过集成SenseVoice,一个基于LLM的多智能体系统,具有实时世界知识,以及CosyVoice,我们可以创建一个交互式播客。

有声书:通过LLMs的分析能力来构建和识别书籍中的情感,并将其与CosyVoice合成,我们实现了具有增强表现力的有声读物。

CosyVoice:

在推理阶段概述CosyVoice模型。概括地说,CosyVoice包括一个自回归Transformer,用于为输入文本生成相应的语音标记,一个基于ODE的扩散模型,流匹配,用于从生成的语音标记重建Mel频谱,以及一个基于HiFiGAN的声码器,用于合成波形。虚线模块在特定模型用途中是可选的,例如跨语言、SFT推理等。[论文]

图1:所提出的CosyVoice模型的概述。(a)演示了 𝒮3
标记器,其中虚线模块仅在训练阶段使用。(b)是CosyVoice的示意图,由文本到令牌LLM和令牌到语音流匹配模型组成。 S、E和T表示“start of sequence”、“end of sequence”和“turn of speech”标记。虚线表示推理阶段的自回归解码。(c)提供了我们的流匹配模型的放大视图,该模型以概率密度路径上的时间步长 t处的说话者嵌入 𝐯、语义标记 μ、掩蔽语音特征 X~和中间状态 Xt为条件。
图2:(a)零触发上下文学习和(B)跨语言语音克隆的序列构建。LID表示目标语言标识符。

CosyVoice由四个组件组成,即文本编码器、语音分词器[ speech tokenizer]、大语言模型和条件流匹配模型。具体地说,文本编码器用于对齐文本和语音token的语义空间,而  speech tokenizer 用于提取语义记号,如图1(a)所示。我们采用一个大的语言模型来学习整个文本编码和语音标记序列,将TTS重新表述为一个给定文本作为提示的自回归序列生成问题。然后,如图1(c)所示,利用条件流匹配模型,通过最佳路径上的去噪过程将语音令牌转换为Mel频谱图 。2020)用于以所生成的Mel频谱图作为输入来合成波形。

语音的受监督语义令牌 [ speech tokenizer] :

采用有监督的自动语音识别(ASR)模型来导出用于语音的有监督的语义语音( 𝒮3 )分词器。该模型是我们专有的SenseVoice ASR模型的微调版本。它接受了多语言音频数据的训练,并具有丰富的音频内容理解能力。 与原始ASR模型不同,我们将编码器分为两部分,并在它们之间插入矢量量化层。给定Mel频谱图 X 作为输入,其经历位置编码和 Encoder1 以获得上下文感知表示 H :

然后,一个矢量量化器(VQ)参与获得离散令牌。 对于帧 l 处的隐藏表示 𝐡l ,码本 C 中的最近嵌入的索引被视为该时间步处的语音令牌 μl :

语音令牌的对应码本嵌入被用作量化的隐藏表示 H¯={𝐜μ1,𝐜μ2,…,𝐜μL} ,并通过剩余的编码器层 Encoder2 :

 在 Encoder2 之后,接下来是基于transformer的ASR解码器,预测文本标签的后验概率:

TTS的大型语言模型:

我们将TTS任务表述为具有大型语言模型的自回归语音令牌生成问题(LLM)。对于LLM,序列构建是最重要的事项,其构建如下:

S and E denote the start and end of sequence, respectively.T is “turn of speech” tokens. 𝐯 is a speaker embedding vector extracted from the speech X with a pre-trained voice-print model2. The text encodings Y¯={𝐲¯u}u⁣∈⁣[1:U] is obtained by passing the text through a Byte Pair Encoded (BPE) tokenizer and text encoder:

由于文本和语音标记位于不同的语义层,因此文本编码器用于对齐它们的语义空间并有利于LLM建模。 在文本编码和语音标记 {μl}l⁣∈⁣[1:L] 之间插入开始标识符T报告问题,语音标记 {μl}l⁣∈⁣[1:L] 是用2.1中描述的监督语义标记器提取的。在训练阶段,我们采用教师强迫方案,其中左移序列作为模式输入,原始序列作为期望输出。 注意,在训练期间仅考虑语音标记的交叉熵损失和:

Optimal-transport Conditional Flow Matching:

在CosyVoice中,采用最优传输条件流匹配模型(OT-CFM)来学习Mel谱图的分布,并以生成的语音令牌为条件从其生成样本。 与扩散概率模型(DPM)相比,OT-CFM可以实现更好的性能,具有更简单的梯度,更容易的训练和更快的生成.

  在连续时间归一化流(CNF)中,从先验分布 p0⁢(X) 到Mel谱图 q⁢(X) 的数据分布构造概率密度路径。 概率密度路径由依赖于时间的矢量场 νt⁢(X):[0,1]×ℝL∗D→ℝL∗D 定义,其通过以下常微分方程(ODE)生成流 ϕt :

流匹配模型(The flow matching model)用于估计条件概率 P(S|X, v, Sref)。其中,X 和 v 分别表示语音片段和说话人嵌入,S 和 Sref 分别表示目标和参考语音的梅尔频谱。该模型使用卷积 Transformer U-Net 来确定最优传输 ODE 中先验分布与目标分布之间的矢量场。在推理阶段,只需五到十次迭代即可生成令人满意的梅尔频谱图。此外,还采用无分类器指导技术,通过屏蔽 70% 到 100% 的前置特征条件来增强上下文学习能力。

在从预测的梅尔频谱图合成波形时,我们使用改进的 HiFTNet 声码器,以支持流式生成。

关于最优传输条件流匹配模型的补充:

最优传输条件流匹配(Optimal Transport Conditional Flow Matching,OT-CFM)是一种用于生成模型的流匹配方法,它旨在学习将输入分布和目标分布之间的条件映射。与传统扩散模型(DPM)不同,OT-CFM的优化目标是基于最优传输理论(Optimal Transport,OT)进行的。通过构建和学习流场,OT-CFM能够高效地生成目标数据。

问题背景:给定输入分布 X0​ 和目标分布 X1,最优传输的目标是找到一个时间相关的流动函数 ϕt 【t介于0-1之间】​ 使得它能够逐渐将输入分布 X0​ 演变为目标分布 X1​。这个流动由常微分方程(ODE)定义:

其中 vt是一个时间相关的速度场(或流场)。ϕt(X)表示输入数据 X 在时间 t 的状态。

优化目标:OT-CFM 的核心是通过学习流场 vt​ 使得生成过程遵循最优传输路径。为此,定义最优传输条件流匹配的目标函数:

最优传输路径下的流场与中间状态:

流场的估计与学习:为了学习最优传输的流场 vt​,引入一个神经网络 vtθ​ 对 vt​ 进行参数化。具体步骤如下:

时间调度策略:为了使生成过程更稳定,文章引入了一个时间调度 t 的变换函数:

这个变换函数可以更均匀地分配时间步,提高生成效果。

可以实现的任务:

(a)零触发上下文学习和(B)跨语言语音克隆的序列构建。LID表示语言标识符。

Multi-lingual Voice Generation 【多语言的语音合成】

Zero-shot In-context Generation 零样本上下文生成

CosyVoice模型具有零触发的上下文学习能力,允许仅用简短的参考语音样本复制任意语音。这个过程需要仔细构造令牌语言模型(LM)的输入序列,如图2所示。 对于同一语言的提示语音和输入文本,我们将它们合并成一个统一的输入,将提示语音标记视为预生成的。利用该输入序列,自回归LM迭代地预测后续令牌,直到其遇到针对前一元素的“序列结束”令牌E。 然而,当提示语音和输入文本在语言上不同时,我们省略与提示相关联的文本和标记,以防止原始语言的韵律特征影响目标语言。 重要的是要注意,提示文本(对应于提示语音的内容)可以通过人工注释或ASR模型(如SenseVoice)转录。与提示文本类似,提示令牌是使用 𝒮3 tokenizer从提示语音中提取的。在生成语音标记之后,它们被附加在提示标记之后,形成流匹配模型的复合条件。此外,说话人嵌入和梅尔声谱图的提示语音,以进一步提高音色和环境的一致性。

Instructed Voice Generation指令语音生成:

Speaker Identity Control、细粒度控制、Style Control、情感丰富的声音生成、Speaker Fine-tune、Speaker Interpolation

为了进一步实现对CosyVoice的可控性,我们尝试集成额外的指令微调(Ji 等人,2023年)。CosyVoice-instruct扩展了CosyVoice-base,具有增强的后续功能。具体地说,它支持对诸如说话人身份(即,说话者的特征)、说话风格(包括情感、性别、语速和音调)以及细粒度的副语言特征。这些功能包括插入笑声、呼吸、边笑边说以及强调某些单词的能力。

SenseVoice:

SenseVoice 是具有音频理解能力的音频基础模型,包括语音识别(ASR)、语种识别(LID)、语音情感识别(SER)和声学事件分类(AEC)或声学事件检测(AED)。提出了具有不同大小和架构的两个模型以适应不同的要求:SenseVoice-Small,用于快速语音理解的仅编码器语音基础模型,以及SenseVoice-Large,编码器-解码器(Vaswani 等人,2017)语音基础模型,用于更准确的语音理解,支持更多语言。

SenseVoice模型概述。SenseVoice是一个语音基础模型,具有多种语音理解功能,包括ASR、LID、SER和AED。SenseVoice-Small是一种用于快速语音理解的仅编码器语音基础模型,SenseVoice-Large是一种编码器-解码器语音基础模型,用于更准确的语音理解,支持更多语言。

𝐞LID 、 𝐞SER 、 𝐞AEC 、 𝐞ITN/NoITN 是四个特殊标记的嵌入:

⟨LID⟩ 表示LID任务。如果 ⟨LID⟩ 被放置 ,则模型被训练以预测输出的对应位置处的语言标记。 在训练阶段,我们根据概率0.8用真实语言标记随机替换 ⟨LID⟩ ,以便模型可以预测语言标记,或者在推理阶段配置指定的语言标记。

⟨SER⟩ 表示SER任务。如果 ⟨SER⟩ 被放置,则训练模型以预测输出的对应位置处的语音情感标签。

⟨AEC⟩ 表示AEC任务。如果 ⟨AEC⟩ 被放置 ,则模型被训练以预测输出的对应位置处的音频事件标签。

⟨ITN⟩ 或 ⟨NoITN⟩ 指定转录样式。如果提供了 ⟨ITN⟩ ,则模型被训练为使用反向文本规范化(ITN)和标点符号进行转录。如果提供了 ⟨NoITN⟩ ,则模型被训练为在没有ITN和标点符号的情况下转录。

在训练阶段,利用交叉熵损失对LID、SER和AEC任务进行优化。ASR任务使用CTC损失来优化。

SenseVoice-Large是一个自回归编码器-解码器模型,用于多语言ASR和多语音理解任务。与Whisper类似(拉德福 等人,2023),SenseVoice-Large通过解码器的输入令牌序列来指定任务。具体来说,我们通过分别包括 ⟨LID⟩ 、 ⟨SER⟩ 、 ⟨AED⟩ 令牌来指定是否预测具有时间戳的语言、语音情感和音频事件。与SenseVoice-Small相比,SenseVoice-Large的优势在于转录准确性和支持大量语言(50+)。

SenseVoice 专注于高精度多语言语音识别、情感辨识和音频事件检测

  • 多语言识别: 采用超过 40 万小时数据训练,支持超过 50 种语言,识别效果上优于 Whisper 模型。
  • 富文本识别:
    • 具备优秀的情感识别,能够在测试数据上达到和超过目前最佳情感识别模型的效果。
    • 支持声音事件检测能力,支持音乐、掌声、笑声、哭声、咳嗽、喷嚏等多种常见人机交互事件进行检测。
  • 高效推理: SenseVoice-Small 模型采用非自回归端到端框架,推理延迟极低,10s 音频推理仅耗时 70ms,15 倍优于 Whisper-Large。
  • 微调定制: 具备便捷的微调脚本与策略,方便用户根据业务场景修复长尾样本问题。
  • 服务部署: 具有完整的服务部署链路,支持多并发请求,支持客户端语言有,python、c++、html、java 与 c# 等。

推理效率:

表1. 比较了SenseVoice、Paraformer和Whisper的模型结构、参数规模、支持的语言和推理效率。SenseVoice-small采用非自回归架构,与Whisper相比,它在推理效率方面具有显着优势。

性能评测:

我们在开源基准数据集(包括AISHELL-1、AISHELL-2、Wenetspeech、Librisepeech和Common Voice)上比较了SenseVoice和Whisper的多语言识别性能和推理效率。使用A800机器进行推理效率评估。SenseVoice-small采用非自回归端到端架构,推理延迟极低-与Whisper-small相比快7倍,与Whisper-large相比快17倍。

1、文本识别:[在开源基准数据集(包括 AISHELL-1、AISHELL-2、Wenetspeech、Librispeech 和 Common Voice)上比较了 SenseVoice 与 Whisper 的多语言语音识别性能和推理效率。在中文和粤语识别效果上,SenseVoice-Small 模型具有明显的效果优势。]

2、情感识别

SenseVoice也可以用于离散情感识别。支持快乐、悲伤、愤怒和中立。我们在7个流行的情感识别数据集上对其进行了评估。SenseVoice-Large可以在大多数数据集上接近或超过SOTA结果,即使没有目标语料库微调。

由于目前缺乏被广泛使用的情感识别测试指标和方法,我们在多个测试集的多种指标进行测试,并与近年来 Benchmark 上的多个结果进行了全面的对比。所选取的测试集同时包含中文 / 英文两种语言以及表演、影视剧、自然对话等多种风格的数据,在不进行目标数据微调的前提下,SenseVoice 能够在测试数据上达到和超过目前最佳情感识别模型的效果。

我们还在测试集上对多个开源情感识别模型进行对比,结果表明,SenseVoice-Large 模型可以在几乎所有数据上都达到了最佳效果,而 SenseVoice-Small 模型同样可以在多数数据集上取得超越其他开源模型的效果。

3、事件检测

SenseVoice-Small和SenseVoice-Large模型都可以检测到语音中的音频事件,包括音乐、掌声、笑声。SenseVoice-Large可以预测音频事件的开始和结束位置,而SenseVoice Small只能预测音频中发生了什么(只有一个事件),但是,它可以检测更多的事件,例如在人机交互过程中可能发生的咳嗽,打喷嚏,呼吸和哭泣。

尽管 SenseVoice 只在语音数据上进行训练,它仍然可以作为事件检测模型进行单独使用。我们在环境音分类 ESC-50 数据集上与目前业内广泛使用的 BEATS 与 PANN 模型的效果进行了对比。SenseVoice 模型能够在这些任务上取得较好的效果,但受限于训练数据与训练方式,其事件分类效果专业的事件检测模型相比仍然有一定的差距。

训练数据:

SenseVoice的训练集

下图展示了用于训练 SenseVoice 模型的数据集概览。

SenseVoice-Small 模型在一个包含约 30 万小时音频数据的庞大语料库上进行了训练,覆盖了包括中文、粤语、英语、日语和韩语在内的 5 种语言。为了进一步增强 SenseVoice-Large 的多语言能力,训练语料库中额外加入了 10 万小时多语言数据。为了从语音数据中获取丰富的转录标签,我们利用了开源的音频事件检测(AED)模型和语音情感识别(SER)模型,生成伪标签,从而构建了一个内容丰富的大规模转录数据集。具体而言,AED 数据集包含了 1.5 亿条音频,而 SER 数据集则包含了 3000 万条音频。

【 SER 模型 :https://modelscope.cn/models/iic/emotion2vec_plus_large

【 AED模型 :https://github.com/qiuqiangkong/audioset_tagging_cnn/tree/master

CosyVoice 的训练集

为了训练 CosyVoice 模型,我们积累了一个包含多种语言的大量数据集。在整个收集过程中,我们利用专门的内部工具进行语音检测、信噪比 (SNR) 估计、说话人分类和分离。随后,使用 SenseVoice-Large 和 Paraformer 生成伪文本标签。这些标签在力对齐 (FA) 模型的帮助下经过优化过程,这有助于消除低质量的数据并提高标点符号的准确性。表 4 列出了各种语言的训练数据持续时间的全面细分。

对于 CosyVoice-instruct 模型,我们使用指令训练数据对 CosyVoice-base 进行了微调,而无需在自回归语言模型中加入说话人嵌入。表 5 显示了不同类型指令的训练数据的持续时间。

限制:

1、SenseVoice有一些需要解决的局限性。首先,对于资源不足的语言,ASR性能通常要低得多。其次,SenseVoice不是为流式转录而设计的。因此,未来的工作可能会集中在开发基于SenseVoice的流式语音理解模型。

2、CosyVoice也有一些限制。首先,它支持的语言数量有限。虽然它可以根据明确的指令表达情感和说话风格,但它不能根据文本的语义内容推断出适当的情感或风格。此外,CosyVoice在唱歌时表现不佳。在保持声音原有音色的同时,实现富有表现力的情感变化仍有改进的空间。

3、另一个限制是FunAudioLLM中的两个创新模型没有使用LLMs进行端到端的训练。这种流水线方法可能会引入错误传播,这可能会影响整体性能。

sensevoice 推理代码:

    def inference(
        self,
        data_in,
        data_lengths=None,
        key: list = ["wav_file_tmp_name"],
        tokenizer=None,
        frontend=None,
        **kwargs,
    ):


        meta_data = {}
        if (
            isinstance(data_in, torch.Tensor) and kwargs.get("data_type", "sound") == "fbank"
        ):  # fbank
            speech, speech_lengths = data_in, data_lengths
            if len(speech.shape) < 3:
                speech = speech[None, :, :]
            if speech_lengths is None:
                speech_lengths = speech.shape[1]
        else:
            # extract fbank feats
            time1 = time.perf_counter()
            audio_sample_list = load_audio_text_image_video(
                data_in,
                fs=frontend.fs,
                audio_fs=kwargs.get("fs", 16000),
                data_type=kwargs.get("data_type", "sound"),
                tokenizer=tokenizer,
            )
            # print(audio_sample_list)
            time2 = time.perf_counter()
            meta_data["load_data"] = f"{time2 - time1:0.3f}"
            speech, speech_lengths = extract_fbank(
                audio_sample_list, data_type=kwargs.get("data_type", "sound"), frontend=frontend
            )
            time3 = time.perf_counter()
            meta_data["extract_feat"] = f"{time3 - time2:0.3f}"
            meta_data["batch_data_time"] = (
                speech_lengths.sum().item() * frontend.frame_shift * frontend.lfr_n / 1000
            )

        speech = speech.to(device=kwargs["device"])
        speech_lengths = speech_lengths.to(device=kwargs["device"])
        print("speech", speech.shape, speech_lengths)
        language = kwargs.get("language", "auto")
        language_query = self.embed(
            torch.LongTensor(
                [[self.lid_dict[language] if language in self.lid_dict else 0]]
            ).to(speech.device)
        ).repeat(speech.size(0), 1, 1)
        print("language_query", language_query.shape)
        use_itn = kwargs.get("use_itn", False)
        textnorm = kwargs.get("text_norm", None)
        if textnorm is None:
            textnorm = "withitn" if use_itn else "woitn"
        textnorm_query = self.embed(
            torch.LongTensor([[self.textnorm_dict[textnorm]]]).to(speech.device)
        ).repeat(speech.size(0), 1, 1)
        print("textnorm_query", textnorm_query.shape)
        speech = torch.cat((textnorm_query, speech), dim=1)
        speech_lengths += 1
        print("speech_add_textnorm", speech.shape, speech_lengths)
        event_emo_query = self.embed(torch.LongTensor([[1, 2]]).to(speech.device)).repeat(
            speech.size(0), 1, 1
        )
        print("event_emo_query", event_emo_query.shape)
        input_query = torch.cat((language_query, event_emo_query), dim=1)
        print("input_query", input_query.shape)
        speech = torch.cat((input_query, speech), dim=1)
        speech_lengths += 3
        print("speech_final", speech.shape, speech_lengths)

        # Encoder
        encoder_out, encoder_out_lens = self.encoder(speech, speech_lengths)
        print("encoder_out", encoder_out.shape, encoder_out_lens)
        if isinstance(encoder_out, tuple):
            encoder_out = encoder_out[0]

        # c. Passed the encoder result and the beam search

        # 束搜索和CTC解码
        ctc_logits = self.ctc.log_softmax(encoder_out)

        results = []
        b, n, d = encoder_out.size()
        if isinstance(key[0], (list, tuple)):
            key = key[0]
        if len(key) < b:
            key = key * b
        for i in range(b):

#对每个 batch 样本提取 CTC logits 输出的前 encoder_out_lens[i] 帧。
#使用 argmax 找到每个时间步概率最大的类别 ID (yseq)。
#使用 torch.unique_consecutive 去除连续的重复类别 ID(CTC 解码中的常见步骤,用于去除重复的符号)。
            x = ctc_logits[i, : encoder_out_lens[i].item(), :]
            yseq = x.argmax(dim=-1)
            yseq = torch.unique_consecutive(yseq, dim=-1) # 使用 torch.unique_consecutive 去除连续的重复类别 ID(CTC 解码中的常见步骤,用于去除重复的符号)

            ibest_writer = None
            if kwargs.get("output_dir") is not None:
                if not hasattr(self, "writer"):
                    self.writer = DatadirWriter(kwargs.get("output_dir"))
                ibest_writer = self.writer[f"1best_recog"]

#使用 mask 去掉 CTC 解码中的 blank ID。
#将整数 ID 列表转化为对应的字符或单词(通过 tokenizer.decode)。
            mask = yseq != self.blank_id
            token_int = yseq[mask].tolist()

            # Change integer-ids to tokens
            text = tokenizer.decode(token_int)

            result_i = {"key": key[i], "text": text}
            results.append(result_i)

            if ibest_writer is not None:
                ibest_writer["text"][key[i]] = text

        return results, meta_data

CTC使用blank id来对齐不同长度的输入和输出:

  • 在语音识别等任务中,输入的语音帧数往往远多于输出的字符数。CTC 通过引入 blank ID 来解决这个问题,使模型能够生成对齐(alignment),从而允许输入长度大于输出长度。
  • blank 用来表示在某个时间步模型没有输出任何字符,或者保持上一个字符的状态不变。

去除重复和冗余:

  • 语音帧与字符之间的对齐并不是一一对应的,CTC 会允许模型在多个时间步中输出相同的字符,同时在其他时间步输出 blank
  • 解码过程中,当遇到连续的相同字符时,只保留第一个字符,忽略重复出现的字符和 blank,这帮助去除冗余。
  • 例如,模型输出可能是 [a, blank, blank, a, a, blank, t, blank, blank],最终解码结果会变为 "a, t"

GPT-4o背后的语音技术

5月14日凌晨,OpenAI推出了最新的生成模型GPT-4o,带来了一系列震撼的功能,用技术彻底颠覆了产品形态。产品最大的亮点在于:以近乎完美的交互方式,为每位用户带来GPT-4级别的智能体验。在语音方面,GPT-4o做到了实时低延迟,平均响应时间与人类反应速度相当,输出的语音能够理解极度贴合对话上下文,能够理解人类的情感情绪,听觉质量上佳,与真人无异。

OpenAI的博客:https://openai.com/index/hello-gpt-4o/

GPT-4o是一个any2any的多模态模型,能够接受文本、音频、图像、视频等多模态输入,也能够生成包含文本、语音、图像和视频等混合内容的多模态输出。限于篇幅,本文主要谈谈语音多模态的实现,并分享一些对于语音研究未来发展的看法。

当我们主要关注文本和语音模态时,GPT-4o其实就是一个语音语言模型(speech language model, SLM)。该SLM同时具备语音理解能力和语音合成能力,输入端和输出端均支持文本和语音的混合多模态。那么,这一SLM应该如何实现呢?在大语言模型(large language model, LLM)滥觞的今日,不难想到这样一种方法:将连续的语音数据离散化成如同单词(或者称token,词元)一样的表示,并入到LLM的词表中,再走一遍训练LLM的老路。

基于上述思想来构建SLM,需要解决以下几个问题:

  1. 语音如何离散化?
  2. 如何让LLM理解语音的token?加入语音token之后,LLM在语音数据的理解上是否具有涌现性?
  3. LLM如何合成/解码语音?

接下来,我们按图索骥,分别看看上述三个问题应该如何解决。看完现有的方案之后,也会谈谈一些关于工程实现的思考以及新兴语音技术对于游戏业务的影响。最后,我会给出一个完整的roadmap来收束全文。

语音的离散化:向LLM看齐!

在谈及语音离散化之前,我们先来看看语音和文本作为两种不同的模态,有什么区别,有什么联系。这直接关系到后文建模方法的选择以及离散化特征的关注点。

语音和文本的差别主要体现在:文本离散、序列短、信息密度高(几乎每个词都包含语义);语音则连续、序列长、信息密度低。语音序列长、信息密度低的特点,意味着语音数据有很大的压缩空间,这一点和图像非常类似。因此,一些用于图像的离散化压缩方法也可以用在语音上。

除了差异,语音和文本也有一定的联系:语音是文本的超集,既包含文本内容(说话人说了什么,也就是语义信息),也包含语音特有的音色、韵律、语速等声学信息(也叫做副语言)。既然语音包含文本,那么在NLP中预训练语言模型也可以用来建模语音中的上下文依赖关系,从而得到语音的离散化token。基于这些方法得到的token主要包含语音的语义信息。

花开两朵,各表一枝。我们先来看看语音的语义token如何获取。

语义token:  用MLM建模语音的上下文依赖

语音的语义建模方法,最常用到的就是BERT的MLM方法,比较经典的工作有三个:wav2vec 2.0[1]、HuBERT[2]和w2v-BERT[3]。

类似于BERT,wav2vec 2.0[1]在隐空间(latent space)随机mask了一定比例的语音输入,然后用基于对比学习的训练目标学习帧的表征。值得注意的一点是,对比学习中目标帧的离散化处理是一个非常巧妙的操作,它将无限的连续特征空间坍缩为有限的离散空间,让帧特征的鲁棒性更强了。这在语音领域上非常有用的trick,允许模型接受带有噪声的语音作为输入。

图1:wav2vec 2.0的模型架构

wav2vec 2.0只是借用了BERT中mask的操作,训练目标大体上是基于对比学习的范式。那么,能直接用BERT的MLM建模目标来得到高质量的语音表征吗?其后的HuBERT[2]做的就是这个事情。HuBERT[2]的核心点在于使用简单的KMeans聚类方法为语音数据抽取离散化的分类标签,也就是文中所说的hidden unit/acoustic unit。有了分类标签,然后就是用BERT的MLM loss来学习语音数据中内在的上下文依赖关系。对于KMeans聚类对初始值和K值高灵敏的特点,作者设计了ensemble和iterative refinement方法予以解决。前者就是多个聚类模型ensemble,后者就是先在基于MFCC的聚类标签上进行学习,学习到一定程度时,在模型学习到的表征重新聚类,再做一次BERT的学习。

图2:HuBERT的模型架构

既然对比学习可以学习语音的语义表征,BERT的MLM也可以,那将二者结合起来,会不会有互补的效果呢?w2v-BERT[3]做的就是这个事情。注意到:HuBERT中语音的离散token不是端到端获得的,需要用KMeans算法对特征进行离线聚类,而wav2vec 2.0又正好提供了音频帧的量化离散表征,HuBERT和wav2vec 2.0很容易就能缝合在一起。缝合的方法也是显然的:前面若干层做类似wav2vec 2.0的对比学习,学习出HuBERT要用的离散表征,然后在后面若干层做类似HuBERT的MLM训练。

图3:w2v-BERT的模型架构

声学token:压缩+离散

上一部分介绍的预训练模型做的是上下文关系的预训练,学习到的表征主要包含与上下文相关的语义信息。要想将语音的token还原成为真正具有真人表现力的信号,还需要有包含音色、韵律、语速等副语言信息的声学特征。声学特征的学习在很大程度上参考了图像领域的工作,用到的主要是类似于VQVAE[4]、VQGAN等的离散化压缩方法,并针对语音数据的特性做了优化。这一部分比较经典的工作就是SoundStream[5]和Encodec[6],二者的工作高度类似,我们放在一起来看。

说到压缩,最先想到的模型当然就是AutoEncoder(自编码器)。为提升压缩效率,有利于数字传输和存储,以及离散化建模的要求,压缩模型中还需要包含量化(quantization),将连续的音频信号转换为离散的数值。基于上述考虑,模型大体上应该是VQVAE[4]的结构。为了平衡VQ(Vector Quantization,向量量化)与音频实时高保真传输的矛盾,通常采用多个残差连接的codebook来进行量化,这个就是所谓的RVQ(具体分析过程可以参见知乎文章)。采用RVQ的好处主要有两个:其一,区分不同quantization block的分工,第一个block包含最重要的语义信息,后续的block包含还原语音的副语言信息;第二,模型训练时可随机采样前面若干个block来训练,保持一定精度,实现对比特率的动态适应。

总而言之,SoundStream[5]/Encodec[6]其实就是一个RVQ-VAE,它们所建模的语音离散化token包含了层次化的语义信息和声学信息。

图4:Encodec的模型架构

语音的统一表征?

不难发现,虽然说SoundStream[5]和Encodec[6]这样的基于RVQ-VAE的压缩建模方法包含了语音的声学特征,但其中也不可避免地带入了语义特征。二者提取的实际上更像是一种语义特征和声学特征的混合体。基于此,SpeechTokenizer[7]在二者的基础上,引入了语义引导信息来解耦语义特征和声学特征。语义特征和声学特征的解耦对于最终的语音合成有着相当的重要性。SpeechTokenizer的具体做法是:使用HuBERT[2]的特征对RVQ1的特征做语义蒸馏,其余部分保留声学信息。

图5:SpeechTokenizer的模型架构


语音的其他表征:MEL依旧有用!

上述的语音离散表征,不管是基于HuBERT[2]的语义token,还是基于Encodec[6]的声学token,它们都是直接基于原始的音频波形抽取的。除此之外,也可以基于语音的中间表征来抽取。最典型的语音中间表征就是梅尔谱(MEL spectrogram,下文简称MEL)。梅尔谱本身就对语音进行了压缩,将梅尔谱类比于图像,使用单码本的VQ也可以达到与SoundStream和Encodec那样类似的压缩程度。这种MEL+VQ的做法在各种语音合成模型中也相当常见。我们在语音合成部分会详细介绍。

让LLM理解语音token!

有了上面所说的语义token和声学token之后,其实就可以利用它们来构建语音层面的语言模型了。比较经典的工作有:谷歌的AudioLM[8]和AudioPaLM[9]、字节的SALMONN[10]、复旦的SpeechGPT[11]/SpeechGPT-Gen[12]/SpeechAlign[13]、阿里的LauraGPT[14]和新加坡国立大学的NextGPT[15]。它们的做法其实都大差不差,我们看几个就知道是怎么回事了。

AudioLM:最初的SLM

见名知义,AudioLM[8]构建的是语音层面的语言模型——给定一段语音,模型预测后续的语音。输入侧和输出侧都只有语音模态。这个任务形式和GPT-4o非常类似,不会经历ASR->LM->TTS的过程,而是直接从语音上下文中推理语义信息,再结合声学信息合成贴合上下文的高表现力语音。而上文所述的语义token和声学token正好就能满足这个任务的要求。

AudioLM的具体做法是:用SoundStream[5]提取声学token,用w2v-BERT[3]提取语义token,模型主体就是一个常规的GPT,词表包含所有的声学token和语义token。它的建模过程也相当有意思,有很大的参考意义:先做最重要的语义建模,然后先预测SoundStream的前若干层特征,建模粗糙的声学特征,在预测SoundStream的剩余层特征,建模声音的细节信息,最后基于所有的声学token还原为语音。这种层次化的建模在诸如VALL-E[16]这样的语音合成模型中也非常常见。

图6:AudioLM的tokenizer

图7:AudioLM的建模流程

当然,AudioLM[8]仅仅关注语音模态,LM也很常规,不具备如同GPT-4o一样强悍的指令遵循能力和对话能力,语音对话的连贯性和表现力都相当弱。但这一工作仍然具有相当的启发性和开拓性,证明了:即使是常规的LM,照样也能理解语音token。

AudioPaLM[9]:整合LLM

这个就是AudioLM的后续了,谷歌将常规的LM替换成已经训练好的、具有强大文本理解能力和生成能力的大语言模型——PaLM-2[17],既继承了AudioLM保留副语言的能力,又融合了PaLM-2强大的语义理解能力和推理能力。而且,该模型的词表同时包含大语言模型的token和语音token,可以同时做语音理解任务和合成生成任务,第一将这些任务整合在一个模型中进行解决。

不过,需要指出地是,文中的语音token embedding是直接输入到Transformer中的,并没有使用音频编码器做一次转换。而且,AudioPaLM的训练更加接近文本多任务的T5,并未用到复杂的、丰富多样的指令来表达任务的意图,还不能算是真正严格的instruction fine-tuning。

图8:AudioPaLM的模型架构

SALMONN[10]:让LLM理解语音

这是字节跳动和清华大学电子系(也是我们实验室)的合作成果。虽然这个工作的目的是让LLM能够理解语音,还不能生成语音,但它的训练方法和LLM比较接近,而且在诸多语音相关的任务上都显示出了涌现性,可以用作universal的特征提取器,这对于构建高质量的、包含语音-文本多模态的指令微调数据集具有相当大的意义。

图9:SALMONN的模型架构

SpeechGPT/SpeechGPT-Gen/SpeechAlign:向LLM的训练方法看齐

这算是复旦大学邱锡鹏组在这个领域一个成系列的工作,我们一个一个来看。

SpeechGPT[11]做的也是兼具语音理解能力和语音生成能力的多模态模型。在模型的训练上,SpeechGPT大幅度向LLM看齐,使用了三段式的训练方法:第一阶段先做模态适应的预训练,其实就是拿ASR的语音数据来做预训练;第二阶段和第三阶段都是指令微调,不过根据指令模态的不同,细分为了跨模态的指令微调和模态链指令微调。指令微调的数据集都是来自ASR数据集。描述任务需求的指令由GPT-4生成。

在我看来,这个工作还是相当偏学术化的作品,文中有不少点都有值得商榷的地方:第一,语音的离散化仅仅用了HuBERT[2],模型只能看到语音的语义特征,这对模型合成语音的音质和表现力有非常大的影响,demo的语音也验证了我的判断;第二,指令微调数据集的构造上有问题。他们用的是ASR数据集,其实更好的选择应该是TTS数据集,可惜高质量的TTS数据集实在是太少了。ASR数据集中的文本和语音可能并不是严格对齐的,GPT-4产生的meta-prompt和语音本身的特征也有可能是对不上的,比如prompt要求大声朗读,但语音本身可能是特定低沉的。meta-prompt本身就无法做到足够复杂丰富,不能描述到语音的一些细粒度信息。

这一部分,最好要有像诸如SALMONN[10]这样的多模态语音理解模型的介入,像DALLE3一样丰富指令的多样性。至于语音方面,可以考虑引入zero-shot的语音合成模型或者变声模型来做合成数据。第三,文中的训练方法也没有与人类偏好做对齐。

图10:SpeechGPT的模型架构

对于上面的第一个问题,作者在其后的SpeechGPT-Gen[12]中做了解决。解决思路的核心点就是:让模型不仅看到语音的语义token,也要看到语音的声学token。具体做法是:SpeechGPT的HuBERT特征替换成了SpeechTokenizer[7]中的语义特征,用SpeechGPT这一LLM来自回归地建模语义特征,有了语义特征之后,再使用Flow-Matching这样的扩散模型来建模声学特征。这里选用Flow-Matching扩散模型,可能是受了SD3和Voicebox/Audiobox的影响。为了增强两阶段建模的依赖关系,作者将语义特征的先验信息注入到第二阶段扩散模型的先验分布中。可以看到,这里语音的解码其实也是一种层次化渐进式解码。

图11:SpeechGPT-Gen的模型架构

SpeechAlign[13]做的则是SLM与人类偏好的对齐,彻底地向LLM的训练方法看齐。该工作构建了对比gold token和合成token的encodec数据集,然后进行偏好优化来进行改进。使用的偏好优化方法包括RLHF和Chain of Hindsight。

图12:SpeechAlign的流程图

简单总结一下上面这些工作中值得关注的点:

  1. 要想让LLM输出上下文连贯的高表现力语音,必须要让LLM看到语义token和声学token,只有语义token,那语音就会显得呆板机械,只有声学token,那语音就不知所云;
  2. LLM的指令微调同样可以迁移到语音-文本多模态领域中,LLM的指令微调同样可以带来如同NLP一样的涌现性;
  3. 高质量指令微调数据集的构建应该是最大的瓶颈!一下子让LLM同时做语音理解和语音生成,难度非常大。不如分步进行。
  4. 如果要分步进行的话,要先实现一个类似于SALMONN[10]那样的多模态理解模型和一个强大的Zero-shot TTS模型。前者用于给语音数据打上丰富的标签,可以是情感情绪、韵律、音高、语速,也可以是口音、意图和说话环境;后者则用于生成高质量的语音数据。毕竟,高质量的、文本和语音严格对齐的TTS数据实在是太少了,尤其是中文领域。有了这两个模型的加持,我们其实就能够构造出高质量的指令微调数据集。我不知道OpenAI是否有SALMONN这样的模型,但OpenAI的OpenVoice模型应该足够为其提供高质量的语音数据了。

既然我们在上面的篇幅中论述了语音理解多模态模型的构建,那我们在下一部分就重点关注zero-shot TTS模型,它对高质量指令微调数据集的构建同样至关重要。同时,LLM解码语音的方法也能从zero-shot TTS方案中得到不少的启发。

LLM如何合成语音:Zero-shot TTS

前面说到,SLM词表中包含了语音的语义token和声学token。语义token保证生成语音与对话上下文的连贯性,声学token保证了合成语音的质量和表现力。要想做到合成上下文连贯的高自然度语音,有两个问题必须要解决:

  1. 语音既有语义token,又有声学token,应该要如何解码成语音?
  2. SLM在合成语音的过程中是否能够遵循多轮对话中的文本指令和语音指令?这个很重要!这允许模型根据用户的即时要求来生成语音回复。比如说,OpenAI演示视频中出现的:“将语速提高两倍”、“采用更加机械化的语气”这样的要求。

对于第一个问题,以VALL-E[16]为代表的诸多zero-shot TTS模型给出了不同的解决方案,这些方案虽有不同,但也有不可忽视的共同点;对于第二个问题,以VoiceLDM[18]和ParlerTTS[19]为代表的text/prompt-guided zero-shot TTS工作给出了肯定的答案。简单解释一下text/prompt-guided zero-shot TTS是怎么回事,通常的语音合成就是将文本(transcription)转换成声音,该任务在transcription之外,又增加了description的输入,来描述合成语音的情感情绪、口音、语气、语速、音高、说话环境、氛围等等信息。我们逐个来看这些工作。

Zero-shot TTS

2023年以来,学术界和工业界出了不少具备in-context learning(zero-shot/few-shot)能力的TTS模型。这些TTS模型通常会将低信息密度、长序列的连续语音数据压缩为高信息密度的tokens或者latents(其实就是码本中具体的token embedding)。这些模型本质上做的事情就是:如何高效实现语音tokens/latents到音频波形的映射。

这些模型给出的解决方案基本上都遵循一个准则:语义token和声学token层次化解码,先语义后声学,或者先解码成MEL再后接声码器,并且非必要不做自回归(毕竟自回归上线虽高,但太吃数据了)!我们一个个来看。

基于声学token或语义token的工作

先是微软的VALL-E[16]。这是zero-shot TTS的开山之作,首次在TTS任务上采用了上万小时的数据。它采用Encodec将语音转换为离散的token,然后用GPT在token上做语言模型的任务。但是,语音毕竟不是文本,如果直接在语音的所有特征上都做自回归的话,那训练的成本会相当高。考虑到Encodec RVQ特征的层次性,低层特征表示语义内容这样的重要特征,高层特征则表征声学细节。前者具有比较强的上下文依赖关系,适合用自回归来建模,后者诸如音色这样的特征,具有全局性,用非自回归特征也可以搞定,所以就有了VALLE中自回归+非自回归的层次建模方式。

图13:VALL-E的模型架构

尽管VALL-E[16]在用GPT建模token的上下文关系的时候,基于token的层次化特性做了分治处理,可能是限于当前语音数据集的规模(几万小时可能不够),这种GPT自回归的难度还是相当大的,解码过程存在常见的错误传播现象,鲁棒性非常差,极其不稳定。根据Ilya Sutskever此前对于自回归的论述,GPT自回归相比于BERT这种双向结构是非常data-hungry的,万小时的数据可能不够。根据本人以及一些同行的经验,VALL-E模型这一类的自回归模型,也包括tortoise-tts[20]和xtts v2,要想显出威力,至少要有十几万小时的数据才行。

既然GPT自回归的难度这么大,就有不少人想方设法地来降低GPT学习的难度了。他们的解决方案也非常类似:给GPT提供额外的条件信息不就行了。比较典型的工作就是微软的RALL-E[21]和吉利的HAM-TTS[22]。RALL-E先生成了时长信息和音高信息,作为GPT自回归的先验,之所以会补充时长和音高,这大概是受到FastSpeech2[23]这样的非自回归模型的启发,这两个指标的引入,有助于提升合成的鲁棒性;HAM-TTS则是补充了基于HuBERT的语义信息。值得注意地是,HAM-TTS将模型的训练数据扩充到了65万小时,其中有50万小时的数据是合成数据。合成数据也能大幅度提升合成语音的音质。

图14:RALL-E的模型架构,框出来的就是辅助信息

图15:HAM-TTS的模型架构

说到VALL-E的后续改进,VoiceCraft不得不提。我愿意称之为“优雅的VALL-E”。它的优雅主要体现在两个方面:casual masking和delayed stacking。所谓的causal masking,是为了用自回归GPT架构来做语音编辑任务,就是把被mask的部分移动到序列末尾去预测,一套架构同时做合成和编辑任务;所谓的delay stacking,是为了适配自回归和RVQ,通过delay错位让当前码本的token预测正好可以利用前面那些token的预测结果,比起VALL-E那样自回归和非自回归缝合在一起的结构要优雅不少。

图16:VoiceCraft的建模流程

基于声学/语义latents的工作

我们通常所说的语音token是离散的。如果使用对应码本中的embedding来表示语音的话,它也可以是连续的低维度的latent变量。既然是低维度的连续latent变量,那图像合成领域中大火的LDM(latent diffusion model,其实就是stable diffsion 1&2采用的模型)模型[]自然也可以用到语音的合成上。这方面的经典工作有很多,比如说:NaturalSpeech 2&3[25, 26]、AudioLDM 2[27]、VoiceLDM[18]。但这里面只有NaturalSpeech2用到了语音离散化部分提及的声学/语义token,NaturalSpeech3的属性分解形式的VQ更像是另一种形式的RVQ。我们先来看NaturalSpeech 2&3,其他的工作后面再来看。

首先是NaturalSpeech 2[26],它基本上就是VALL-E的连续版本。它用的latent也是来自Encodec,对其中不同层次的latent做了求和,然后将其作为扩散模型的训练目标。值得注意地是,扩散模型和FastSpeech2一样也用了时长和音高作为合成的先验条件。这一点也被后来的RALL-E采用。该工作中的扩散模型采用WaveNet实现,同时预测不加噪的latent和后验均值,和图像合成领域的扩散模型在实现方式上还是有所不同的。

图17:NaturalSpeech2的模型架构

然后是NaturalSpeech 3[26],还是非自回归的,而且非自回归的正统性味道更加浓厚,借用了不少FastSpeech2和megatts1&2(后面会讲)[27, 28]的设计思想。像megatts 1&2一样,同样采用(自)监督信号对语音token编码的内容做了限制,而不再像是VALL-E/NaturalSpeech2那样一把抓。相应地,语音token化的方法也用VQ就行。具体而言,文章将语音信号分解为时长、内容、韵律和细节四个部分,然后每个部分用离散化的扩散模型来建模。不过,原文使用GRL来促进语音属性的分解,这一点的靠谱程度存疑。我也尝试过文章的FACodec,但效果很差。三级扩散模型级联的结构,预测起来似乎也非常麻烦。

图18:NaturalSpeech3的模型架构

基于MEL谱+VQ的TOKEN的工作

当然,也有不少工作用了MEL谱作为中间特征,然后在梅尔谱的基础上,或是用VQ提供离散token,或是用CNN来提取连续latent。对于MEL+VQ的工作,有tortoise-tts[20]、xtts 1&2、megatts1&2[28, 29]、base TTS[30]。对于MEL+latents的工作,有:AudioLDM 1&2[27]、StyleTTS 1&2[31, 32]。我们来简单看看是它们是怎么做的。

Tortoise-tts[20]。该工作是著名的开源英文TTS模型。其作者目前在OpenAI就职,同时也是GPT-4o的重要Contributor(他自个儿在博客中说的)。Tortoise-tts使用MEL+VQVAE的方法得到语音的MEL token,然后对MEL token以及text token做GPT自回归建模。对于语音的解码,自然也是分为两步:先是用扩散模型将MEL token转换为MEL谱,这一步和文生图很像,用扩散模型是很自然的选择;然后用声码器将MEL谱转换为音频波形。tortoise-tts和VALL-E的主体都是自回归建模,二者的不同主要在于token的不同。

图19:tortoise-tts的模型架构

MegaTTS 1&2[28, 29]。字节跳动的MegaTTS系列对语音token编码信息做了显式的信息压缩处理,让语音token仅编码上下文依赖强的韵律信息,然后用GPT自回归来建模语音的韵律。对于其他方面的信息,模型的处理显得较为常规:音色一般具有全局性,使用单一的音色编码器从参考音频中提取就性;对于文本语义内容的处理,模型在很大程度上参考了非自回归的FastSpeech 2。

对于语音的解码,也是分为两步:先通过MEL decoder还原为MEL谱,然后通过声码器解码为音频波形。MegaTTS 2和1总体上类似,在音色编码(音素级编码、多条参考音频)、语音提示长度(扩展同speaker语音上下文长度硬train,音频prompt长度更长)和时长建模(也用GPT自回归)上做了改进,同时堆了更大规模的数据。剪映的后端TTS模型用的就是megatts2。该工作在各论文的评测中表现也都不错。

图20:megatts1的模型架构

基于MEL谱+VAE的latents的工作

AudioLDM 1&2[27]。AudioLDM 1&2使用的语音latents是一致的,均通过MEL+VAE获得。既然是连续的latents,使用扩散模型来建模也合情合理。解码过程也相当简单:VAE decoder获得梅尔谱,然后用声码器转换为音频波形。该系列工作的核心创新点是利用多模态模型统一了扩散模型条件输入侧的信息:AudioLDM 1用CLAP统一了文本模态和音频模态,用单模态的音频数据就能完成模型的训练;AudioLDM 2则包含了图像、文本、转录文本等更多模态,模型泛用性也更强,既能做语音合成,也能做音乐生成、音频事件生成。

图21:AudioLDM 1的模型架构

图22:AudioLDM2的模型架构

StyleTTS 1&2[31, 32]。StyleTTS系列的模型一众zero-shot TTS模型显得比较老派,整体结构基本上沿袭了非自回归的FastSpeech 2,不同之处在于增加了基于参考音频抽取的风格信息。说是风格,其实跟megatts的音色很像。StyleTTS 2的工作则将风格进一步拆分成声学风格和韵律风格。训练时的风格信息由音频提供,推断时的风格信息则由扩散模型提供。StyleTTS 2通过一个扩散模型桥接了文本韵律和语音风格之间的联系,摆脱推断时对参考音频的依赖。不用参考音频其实对产品的意义还挺大的,要都用现实世界中真人尤其是名人的声音作为参考音频,那这势必会引起版权纠纷。这种纠纷在国内国外都有相关的事件。最近寡姐投诉OpenAI的事件就是一例。

图23:StyleTTS 1的模型架构

图24:StyleTTS 2的模型架构

TTS对指令的遵循

SLM不仅要合成合乎上下文语义的高表现力语音,合成的语音还要符合用户的即时要求。一些text-guided zero-shot TTS的工作值得参考。这些工作一般都是在已有的zero-shot TTS模型或者text-to-audio模型上改造而来,同时吸收transcription和description两路条件。其中的重点还是在于数据集的构建。这方面的工作有:PromptTTS[33]、InstructTTS[34]、ParlerTTS[19]、VoiceLDM[18]和Audiobox[35]。我们主要谈谈ParlerTTS和VoiceLDM。

ParlerTTS[19]。VALL-E/VoiceCraft的增强版,通过T5编码器和cross-attention旁路引入了描述性文本的信息。该工作的目的是想使用自然语言prompt来指定说话风格和环境信息,摆脱对参考音频的依赖。描述性标签文本的收集过程也显得相当朴素:通过定制化的监督式模型获取语音数据的口音特征、录音质量特征、音高语速特征。然后用LLM将这些特征转换为自然语言的描述。在我看来,这个工作有这么几点局限性吧:其一,缺乏情绪标签;其二,语音描述性标签的收集并不具备通用性,较为繁琐,远不如一个强大的多模态语音理解模型来得实在。文章demo虽然达到了预期的效果,但场景似乎局限在朗读的情景中。

图25:ParlerTTS的模型架构

VoiceLDM[18]。在VoiceLDM1的基础上增加了转录文本的输入。这个工作和AudioLDM 1很像,同样使用CLAP注入语音的描述性信息。不同地是,为了做TTS任务,该工作通过cross-attention旁路增加了transcription的信息。

图26:VoiceLDM的模型架构

TTS总结

林林总总说了这么多zero-shot的TTS方法,我想说明的结论有这么几点:

  1. 在LLM大行其道、scaling law大显神威的时代,TTS模型的训练数据规模已经突破了万小时,甚至达到了数十万小时的级别。在大数据的加持下,TTS任务上也涌现出了in-context learning能力。
  2. 语音信息的解码通常都要层次化或者多步进行,不能一步到位。自回归、扩散模型和流匹配都能在TTS中发挥作用;
  3. 借鉴NLP instruction fine-tuning和文生图的经验,TTS模型同样可以遵循文本指令或者语音指令,合成符合用户即时要求的语音,摆脱对参考音频的依赖,这或许也能规避一些知识产权的困扰(比如最近有名的寡姐投诉OpenAI事件)。同时,用户也能在对话过程中随时切换语音回复的风格,这一点在OpenAI的demo中有很明确的体现。另外,不知道大家有没有注意,GPT-4o合成的语音是可以是放映所处的声学环境的:有一段语音背后似乎是有钢琴声的。
  4. text-guided zero-shot TTS在模型架构上和zero-shot TTS有非常大的相似性。但训练数据可能较为缺乏。先开发zero-shot TTS,再用类似SALMONN那样的多模态理解模型来打标签(类似DALLE3的做法),这样数据集构造方式,可能会是更好的选择。

另外,对于语音的解码方案,我倾向于是这样的:

  1. 如果要做流式推理,外接类似HIFIGAN这样的声码器的方式可能不是好的选择。HIFIGAN并不天然支持流式解码。相反地,诸如SoundStream和Encodec这样的方法,同时有流式变体和非流式变体;
  2. 先做语义token的解码,这个解码大概率是自回归解码。语义token毕竟是建模上下文依赖关系,自回归方法已经在NLP上证明了这一点;
  3. 然后做声学token的解码,扩散或者flow-matching可能是更好的选择。扩散模型或者流匹配可以很好地修补语音的细节;

当然,除了上面讲到的,zero-shot TTS还有很多值得研究的方法。限于篇幅,仅列举于此,不再详述:HierSpeech++[36]、base TTS[30]、Voicebox/Audiobox[35]、UniAudio[37]、Make-a-Voice[38]等等。

其他问题

对于GPT-4o模型,如果仅仅聚焦于语音多模态,还有下面的问题值得关注:

  1. 语音交互如何做到低延迟?大概率要求流式切片处理,主要工作在于工程优化,用C++重写算子。推理框架的话,用tensorrt、mnn这些都行。上下文所述的音频离散化方法,诸如SoundStream和Encodec,其实也支持流式处理。
  2. 语音对话中的打断如何实现?个人认为有两种可能的方案:turn-based和流式处理。所谓的turn-based方案,是比较工程化的,简答概括一下就是:检测是否有停顿,如果一段时间内没有声音,模型就开始返回语音回复。另一种流式方案,则是:模型一直在接受用户的流式语音输入,判断是否应该输出语音回复,一个充分训练的模型应该是能够准确预测出语音词表中的[START]和[END]的。

对游戏配音业务的思考

text/prompt-guided zero-shot TTS方法对游戏的AI配音意义重大。主要体现在:

  1. 用自然语言提示去合成音色稳定的语音,摆脱对参考音频的依赖,在业务中能够更加灵活,至少比克隆已有人物/角色的语音的方式更加方便,更不容易出戏。举个例子,在开放世界剧情类游戏的研发阶段,我们会设定一些profile赋予NPC,让玩家跟NPC聊天。我们曾经用克隆《原神》、《崩坏:星穹铁道》已有角色的方式赋予这些NPC角色语音,但放在那些欧美背景的NPC中,就是很有违和感,没有现实世界中的accent,不够decent。
  2. 剧情任务中的配音会更加真人化、更有沉浸感。过年期间过《崩坏:星穹铁道》花火和黑天鹅的同行任务的时候,部分NPC角色会有六公主的翻译腔,这是花火行于欢愉命途的恶趣味,空气中顿时充满了快活的味道。如果走bv2、gsv的语音克隆方案,应该是很难有这种效果的。而且,玩家在剧情任务中势必会经过不同的地势地貌,至少室内、室外的声音听起来是有不同的。室内的声音至少会有回响、混响的吧。这种感觉语音克隆方案也是无法做到的。

全文总结

总结一下本文说谈的内容,我认为GPT-4o语音多模态的实现可能是走了以下的技术路线:

  1. audio & text tokenizer的实现应该是语音离散化部分所用的技术,例如SoundStream、Encodec、SpeechTokenizer,或者是MEL+VQ最后配合声码器来解码;参考zero-shot TTS、AudioLM/AudioPaLM、SpeechGPT-Gen等工作的结果,LLM中语音token的解码应该是要走层次化或者多步的方法,先解码语义特征,再解码声学特征,或者是先解码MEL,再加一个HIFIGAN这样的声码器。另外,如果做audio/speech/music这样的通用声合成的话,可能也能通过prompt来控制。AudioLDM2虽然做了这方面的工作,但audio/music和speech的参数其实是不一样的,说到底还不是同一个模型。
  2. 对于指令微调,数据集的构造非常重要,大概率要用到合成数据。其一,网络上高质量语音数据的量级远远不及文本,直接拿ASR数据来做肯定会影响模型合成语音的音质;其二,大语言模型合成的instruction往往触及不到语音的细粒度特征,这样的instruction其实无法准确详尽地描述text和speech之间的关系。因而,需要引入强大的zero-shot TTS模型合成高质量语音,然后用多模态语音理解模型来为合成语音打标签,当然也可以评分做筛选什么的。
  3. 最后是要让大模型的输出对齐人类的偏好。这方面的方法有很多,有DPO、PPO什么的,都可以用。

图27:全文总结,可能的roadmap

参考文献

[1] Baevski A, Zhou Y, Mohamed A, et al. wav2vec 2.0: A framework for self-supervised learning of speech representations[J]. Advances in neural information processing systems, 2020, 33: 12449-12460.

[2] Hsu W N, Bolte B, Tsai Y H H, et al. Hubert: Self-supervised speech representation learning by masked prediction of hidden units[J]. IEEE/ACM Transactions on Audio, Speech, and Language Processing, 2021, 29: 3451-3460.

[3] Chung Y A, Zhang Y, Han W, et al. W2v-bert: Combining contrastive learning and masked language modeling for self-supervised speech pre-training[C]//2021 IEEE Automatic Speech Recognition and Understanding Workshop (ASRU). IEEE, 2021: 244-250.

[4] Van Den Oord A, Vinyals O. Neural discrete representation learning[J]. Advances in neural information processing systems, 2017, 30.

[5] Zeghidour N, Luebs A, Omran A, et al. Soundstream: An end-to-end neural audio codec[J]. IEEE/ACM Transactions on Audio, Speech, and Language Processing, 2021, 30: 495-507.

[6] Défossez A, Copet J, Synnaeve G, et al. High fidelity neural audio compression[J]. arXiv preprint arXiv:2210.13438, 2022.

[7] Zhang X, Zhang D, Li S, et al. Speechtokenizer: Unified speech tokenizer for speech large language models[J]. arXiv preprint arXiv:2308.16692, 2023.

[8] Borsos Z, Marinier R, Vincent D, et al. Audiolm: a language modeling approach to audio generation[J]. IEEE/ACM Transactions on Audio, Speech, and Language Processing, 2023.

[9] Rubenstein P K, Asawaroengchai C, Nguyen D D, et al. Audiopalm: A large language model that can speak and listen[J]. arXiv preprint arXiv:2306.12925, 2023.

[10] Changli Tang, Wenyi Yu, Guangzhi Sun, Xianzhao Chen, Tian Tan, Wei Li, Lu Lu, Zejun Ma, Chao Zhang. SALMONN: Towards Generic Hearing Abilities for Large Language Models

[11] Zhang D, Li S, Zhang X, et al. Speechgpt: Empowering large language models with intrinsic cross-modal conversational abilities[J]. arXiv preprint arXiv:2305.11000, 2023.

[12] Zhang D, Zhang X, Zhan J, et al. SpeechGPT-Gen: Scaling Chain-of-Information Speech Generation[J]. arXiv preprint arXiv:2401.13527, 2024.

[13] Zhang D, Li Z, Li S, et al. SpeechAlign: Aligning Speech Generation to Human Preferences[J]. arXiv preprint arXiv:2404.05600, 2024.

[14] Chen Q, Chu Y, Gao Z, et al. Lauragpt: Listen, attend, understand, and regenerate audio with gpt[J]. arXiv preprint arXiv:2310.04673, 2023.

[15] Wu S, Fei H, Qu L, et al. Next-gpt: Any-to-any multimodal llm[J]. arXiv preprint arXiv:2309.05519, 2023.

[16] Wang C, Chen S, Wu Y, et al. Neural codec language models are zero-shot text to speech synthesizers[J]. arXiv preprint arXiv:2301.02111, 2023.

[17] Anil R, Dai A M, Firat O, et al. Palm 2 technical report[J]. arXiv preprint arXiv:2305.10403, 2023.

[18] Lee Y, Yeon I, Nam J, et al. VoiceLDM: Text-to-Speech with Environmental Context[C]//ICASSP 2024-2024 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP). IEEE, 2024: 12566-12571.

[19] Lyth D, King S. Natural language guidance of high-fidelity text-to-speech with synthetic annotations[J]. arXiv preprint arXiv:2402.01912, 2024.

[20] Betker J. Better speech synthesis through scaling[J]. arXiv preprint arXiv:2305.07243, 2023.

[21] Xin D, Tan X, Shen K, et al. RALL-E: Robust Codec Language Modeling with Chain-of-Thought Prompting for Text-to-Speech Synthesis[J]. arXiv preprint arXiv:2404.03204, 2024.

[22] Wang C, Zeng C, Zhang B, et al. HAM-TTS: Hierarchical Acoustic Modeling for Token-Based Zero-Shot Text-to-Speech with Model and Data Scaling[J]. arXiv preprint arXiv:2403.05989, 2024.

[23] Ren Y, Hu C, Tan X, et al. Fastspeech 2: Fast and high-quality end-to-end text to speech[J]. arXiv preprint arXiv:2006.04558, 2020.

[24] Rombach R, Blattmann A, Lorenz D, et al. High-resolution image synthesis with latent diffusion models[C]//Proceedings of the IEEE/CVF conference on computer vision and pattern recognition. 2022: 10684-10695.

[25] Shen K, Ju Z, Tan X, et al. Naturalspeech 2: Latent diffusion models are natural and zero-shot speech and singing synthesizers[J]. arXiv preprint arXiv:2304.09116, 2023.

[26] Ju Z, Wang Y, Shen K, et al. NaturalSpeech 3: Zero-shot speech synthesis with factorized codec and diffusion models[J]. arXiv preprint arXiv:2403.03100, 2024.

[27] Liu H, Tian Q, Yuan Y, et al. AudioLDM 2: Learning holistic audio generation with self-supervised pretraining[J]. arXiv preprint arXiv:2308.05734, 2023.

[28] Jiang Z, Ren Y, Ye Z, et al. Mega-tts: Zero-shot text-to-speech at scale with intrinsic inductive bias[J]. arXiv preprint arXiv:2306.03509, 2023.

[29] Jiang Z, Liu J, Ren Y, et al. Mega-tts 2: Zero-shot text-to-speech with arbitrary length speech prompts[J]. arXiv preprint arXiv:2307.07218, 2023.

[30] Łajszczak M, Cámbara G, Li Y, et al. BASE TTS: Lessons from building a billion-parameter text-to-speech model on 100K hours of data[J]. arXiv preprint arXiv:2402.08093, 2024.

[31] Li Y A, Han C, Mesgarani N. Styletts: A style-based generative model for natural and diverse text-to-speech synthesis[J]. arXiv preprint arXiv:2205.15439, 2022.

[32] Li Y A, Han C, Raghavan V, et al. Styletts 2: Towards human-level text-to-speech through style diffusion and adversarial training with large speech language models[J]. Advances in Neural Information Processing Systems, 2024, 36.

[33] Guo Z, Leng Y, Wu Y, et al. Prompttts: Controllable text-to-speech with text descriptions[C]//ICASSP 2023-2023 IEEE International Conference on Acoustics, Speech and Signal Processing (ICASSP). IEEE, 2023: 1-5.

[34] Yang D, Liu S, Huang R, et al. Instructtts: Modelling expressive TTS in discrete latent space with natural language style prompt[J]. arXiv preprint arXiv:2301.13662, 2023.

[35] Vyas A, Shi B, Le M, et al. Audiobox: Unified audio generation with natural language prompts[J]. arXiv preprint arXiv:2312.15821, 2023.

[36] Lee S H, Choi H Y, Kim S B, et al. HierSpeech++: Bridging the Gap between Semantic and Acoustic Representation of Speech by Hierarchical Variational Inference for Zero-shot Speech Synthesis[J]. arXiv preprint arXiv:2311.12454, 2023.

[37] Yang D, Tian J, Tan X, et al. Uniaudio: An audio foundation model toward universal audio generation[J]. arXiv preprint arXiv:2310.00704, 2023.

[38] Huang R, Zhang C, Wang Y, et al. Make-a-voice: Unified voice synthesis with discrete representation[J]. arXiv preprint arXiv:2305.19269, 2023.