用于语音合成的预训练模型
与 ASR(自动语音识别)和音频分类任务相比,可用的预训练模型检查点要少得多。在 🤗 Hub 上,您会找到近 300 个合适的检查点。在这些预训练模型中,我们将重点关注 🤗 Transformers 库中 readily available 的两种架构 - SpeechT5 和 Massive Multilingual Speech (MMS)。在本节中,我们将探讨如何在 Transformers 库中将这些预训练模型用于 TTS。
SpeechT5
SpeechT5 是微软 Junyi Ao 等人发表的一个模型,它能够处理一系列语音任务。虽然在本单元中,我们专注于文本到语音方面,但此模型可以调整为语音到文本任务(自动语音识别或说话人识别),以及语音到语音(例如语音增强或在不同语音之间转换)。这是由于模型的设计和预训练方式。
SpeechT5 的核心是一个普通的 Transformer 编码器-解码器模型。就像任何其他 Transformer 一样,编码器-解码器网络使用隐藏表示对序列到序列的转换进行建模。这种 Transformer 主干对于 SpeechT5 支持的所有任务都是相同的。
此 Transformer 辅以六个特定于模态(语音/文本)的预网络和后网络。输入语音或文本(取决于任务)通过相应的预网络进行预处理,以获得 Transformer 可以使用的隐藏表示。然后将 Transformer 的输出传递到一个后网络,该网络将使用它来生成目标模态中的输出。
这是架构的外观(来自原始论文的图像)
SpeechT5 首先使用大规模的未标记语音和文本数据进行预训练,以获取不同模态的统一表示。在预训练阶段,所有预网络和后网络同时使用。
预训练后,整个编码器-解码器主干针对每个单独的任务进行微调。在此步骤中,仅使用与特定任务相关的预网络和后网络。例如,要将 SpeechT5 用于文本到语音,您需要文本编码器预网络用于文本输入,以及语音解码器预网络和后网络用于语音输出。
这种方法允许获得多个针对不同语音任务微调的模型,所有这些模型都受益于在未标记数据上的初始预训练。
即使微调模型最初使用来自共享预训练模型的相同权重集,但最终版本最终都大不相同。例如,您不能使用微调的 ASR 模型并交换预网络和后网络来获得可用的 TTS 模型。SpeechT5 很灵活,但没有那么灵活;)
让我们看看 SpeechT5 专门用于 TTS 任务的预网络和后网络是什么
- 文本编码器预网络:一个文本嵌入层,将文本标记映射到编码器期望的隐藏表示。这类似于 BERT 等 NLP 模型中发生的情况。
- 语音解码器预网络:这将对数梅尔谱图作为输入,并使用一系列线性层将谱图压缩成隐藏表示。
- 语音解码器后网络:这预测一个残差以添加到输出谱图中,并用于细化结果。
结合起来,这就是 SpeechT5 用于文本到语音的架构
如您所见,输出是对数梅尔谱图,而不是最终的波形。如果您还记得,我们在单元 3中简要介绍了此主题。生成音频的模型通常会生成对数梅尔谱图,需要使用称为声码器的另一个神经网络将其转换为波形。
让我们看看如何做到这一点。
首先,让我们从 🤗 Hub 加载微调的 TTS SpeechT5 模型,以及用于标记化和特征提取的处理器对象
from transformers import SpeechT5Processor, SpeechT5ForTextToSpeech
processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_tts")
model = SpeechT5ForTextToSpeech.from_pretrained("microsoft/speecht5_tts")
接下来,对输入文本进行标记化。
inputs = processor(text="Don't count the days, make the days count.", return_tensors="pt")
SpeechT5 TTS 模型不仅限于为单个说话人生成语音。相反,它使用所谓的说话人嵌入来捕捉特定说话人的声音特征。
说话人嵌入是一种以紧凑的方式表示说话人身份的方法,作为固定大小的向量,而不管话语的长度如何。这些嵌入捕获了说话人声音、口音、语调和其他区分一个说话人与另一个说话人的独特特征的基本信息。此类嵌入可用于说话人验证、说话人分段、说话人识别等。生成说话人嵌入的最常见技术包括
- I-向量(身份向量):I-向量基于高斯混合模型 (GMM)。它们以从说话人特定 GMM 的统计数据派生的低维固定长度向量表示说话人,并以无监督的方式获得。
- X-向量:X-向量是使用深度神经网络 (DNN) 派生的,通过结合时间上下文捕获帧级说话人信息。
X-向量 是一种最先进的方法,与 I-向量相比,在评估数据集上表现出优越的性能。深度神经网络用于获得 X-向量:它训练以区分说话人,并将可变长度的话语映射到固定维度的嵌入。您还可以加载预先计算的 X-向量说话人嵌入,它将封装特定说话人的说话特征。
让我们从 Hub 上的数据集中加载这样的说话人嵌入。这些嵌入是使用CMU ARCTIC 数据集和此脚本获得的,但任何 X-向量嵌入都应该可以工作。
from datasets import load_dataset
embeddings_dataset = load_dataset("Matthijs/cmu-arctic-xvectors", split="validation")
import torch
speaker_embeddings = torch.tensor(embeddings_dataset[7306]["xvector"]).unsqueeze(0)
说话人嵌入是一个形状为 (1, 512) 的张量。此特定说话人嵌入描述了女性的声音。
此时我们已经拥有足够的输入来生成对数梅尔谱图作为输出,您可以像这样执行操作
spectrogram = model.generate_speech(inputs["input_ids"], speaker_embeddings)
这输出一个形状为 (140, 80) 的张量,其中包含对数梅尔谱图。第一个维度是序列长度,它可能在不同的运行之间有所不同,因为语音解码器预网络始终将 dropout 应用于输入序列。这会为生成的语音添加一些随机变化。
但是,如果我们希望生成语音波形,我们需要指定一个声码器来用于谱图到波形的转换。理论上,您可以使用任何适用于 80 bin 梅尔谱图的声码器。方便的是,🤗 Transformers 提供了一个基于 HiFi-GAN 的声码器。其权重由 SpeechT5 的原始作者提供。
HiFi-GAN 是一种最先进的生成对抗网络 (GAN),专为高保真语音合成而设计。它能够从谱图输入生成高质量和逼真的音频波形。
在高级别上,HiFi-GAN 由一个生成器和两个鉴别器组成。生成器是一个全卷积神经网络,它以梅尔谱图作为输入,并学习生成原始音频波形。鉴别器的作用是区分真实音频和生成音频。这两个鉴别器侧重于音频的不同方面。
HiFi-GAN是在一个大型的高质量音频录制数据集上训练的。它使用了所谓的对抗训练,其中生成器和判别器网络相互竞争。最初,生成器会产生低质量的音频,判别器可以很容易地将其与真实音频区分开来。随着训练的进行,生成器会改进其输出,旨在欺骗判别器。而判别器则变得更加准确地识别真实和生成的音频。这种对抗性反馈循环有助于两个网络随着时间的推移而改进。最终,HiFi-GAN学会生成高保真音频,使其非常接近训练数据的特征。
加载声码器就像加载任何其他 🤗 Transformers 模型一样简单。
from transformers import SpeechT5HifiGan
vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")
现在您需要做的就是在生成语音时将其作为参数传递,输出将自动转换为语音波形。
speech = model.generate_speech(inputs["input_ids"], speaker_embeddings, vocoder=vocoder)
让我们听听结果。SpeechT5 使用的采样率始终为 16 kHz。
from IPython.display import Audio
Audio(speech, rate=16000)
不错!
请随意使用 SpeechT5 文本转语音演示,探索其他声音,尝试不同的输入。请注意,此预训练检查点仅支持英语。
Bark
Bark是由Suno AI在suno-ai/bark中提出的一个基于Transformer的文本转语音模型。
与SpeechT5不同,Bark直接生成原始语音波形,消除了推理过程中对单独声码器的需求——它已经集成在内。这种效率是通过利用Encodec
实现的,它既充当编解码器,也充当压缩工具。
使用Encodec
,您可以将音频压缩成轻量级格式以减少内存使用,然后将其解压缩以恢复原始音频。此压缩过程由8个码本促进,每个码本都包含整数向量。将这些码本视为音频的整数形式表示或嵌入。需要注意的是,每个后续码本都会提高从先前码本重建音频的质量。由于码本是整数向量,因此Transformer模型可以学习它们,而Transformer模型在此任务中非常有效。这就是Bark专门训练的目标。
更具体地说,Bark由4个主要模型组成。
BarkSemanticModel
(也称为“文本”模型):一个因果自回归Transformer模型,它以标记化的文本作为输入,并预测捕获文本含义的语义文本标记。BarkCoarseModel
(也称为“粗略声学”模型):一个因果自回归Transformer,它以BarkSemanticModel
模型的结果作为输入。它的目标是预测EnCodec所需的最初两个音频码本。BarkFineModel
(“精细声学”模型),这一次是一个非因果自编码器Transformer,它基于先前码本嵌入的总和迭代地预测最后的码本。- 在预测了
EncodecModel
中的所有码本通道后,Bark使用它来解码输出音频数组。
需要注意的是,前三个模块中的每一个都可以支持条件说话者嵌入,以根据特定预定义的声音来调节输出声音。
Bark是一个高度可控的文本转语音模型,这意味着您可以使用各种设置,正如我们即将看到的。
在开始之前,请加载模型及其处理器。
此处的处理器作用是双方面的。
- 它用于标记化输入文本,即将其分割成模型可以理解的小片段。
- 它存储说话者嵌入,即可以调节生成的语音预设。
from transformers import BarkModel, BarkProcessor
model = BarkModel.from_pretrained("suno/bark-small")
processor = BarkProcessor.from_pretrained("suno/bark-small")
Bark非常通用,可以根据说话者嵌入库生成有条件的音频,该库可以通过处理器加载。
# add a speaker embedding
inputs = processor("This is a test!", voice_preset="v2/en_speaker_3")
speech_output = model.generate(**inputs).cpu().numpy()
它还可以生成现成的多语言语音,例如法语和中文。您可以在此处找到支持语言的列表。与下面讨论的MMS不同,无需指定使用的语言,只需将输入文本调整为相应的语言即可。
# try it in French, let's also add a French speaker embedding
inputs = processor("C'est un test!", voice_preset="v2/fr_speaker_1")
speech_output = model.generate(**inputs).cpu().numpy()
该模型还可以生成非语言交流,例如笑声、叹息和哭泣。您只需使用相应的提示(例如[清了清嗓子]
、[笑声]
或...
)修改输入文本即可。
inputs = processor(
"[clears throat] This is a test ... and I just took a long pause.",
voice_preset="v2/fr_speaker_1",
)
speech_output = model.generate(**inputs).cpu().numpy()
Bark甚至可以生成音乐。您可以通过在单词周围添加♪ 音符 ♪ 来帮助实现。
inputs = processor(
"♪ In the mighty jungle, I'm trying to generate barks.",
)
speech_output = model.generate(**inputs).cpu().numpy()
除了所有这些功能外,Bark还支持批处理,这意味着您可以同时处理多个文本条目,但代价是计算量更大。在某些硬件(如GPU)上,批处理可以实现更快的整体生成,这意味着一次生成所有样本可能比逐个生成它们更快。
让我们尝试生成一些示例。
input_list = [
"[clears throat] Hello uh ..., my dog is cute [laughter]",
"Let's try generating speech, with Bark, a text-to-speech model",
"♪ In the jungle, the mighty jungle, the lion barks tonight ♪",
]
# also add a speaker embedding
inputs = processor(input_list, voice_preset="v2/en_speaker_3")
speech_output = model.generate(**inputs).cpu().numpy()
让我们逐一收听输出。
第一个。
from IPython.display import Audio
sampling_rate = model.generation_config.sample_rate
Audio(speech_output[0], rate=sampling_rate)
第二个。
Audio(speech_output[1], rate=sampling_rate)
第三个。
Audio(speech_output[2], rate=sampling_rate)
Bark与其他 🤗 Transformers 模型一样,只需几行代码即可在速度和内存影响方面进行优化。要了解如何操作,请点击此Colab演示笔记本。
大规模多语言语音 (MMS)
如果您正在寻找其他语言的预训练模型怎么办?大规模多语言语音 (MMS) 是另一个涵盖一系列语音任务的模型,但它支持大量语言。例如,它可以合成超过 1100 种语言的语音。
用于文本转语音的 MMS 基于Kim 等人,2021 年的 VITS,这是最先进的 TTS 方法之一。
VITS是一个将文本转换为原始语音波形的语音生成网络。它像一个条件变分自动编码器一样工作,根据输入文本估算音频特征。首先,生成以频谱图表示的声学特征。然后使用从 HiFi-GAN 适应而来的转置卷积层解码波形。在推理过程中,文本编码被上采样并使用流模块和 HiFi-GAN 解码器转换为波形。与 Bark 一样,无需声码器,因为波形是直接生成的。
pip install git+https://github.com/huggingface/transformers.git
让我们试用一下 MMS,看看我们如何合成其他语言(例如德语)的语音。首先,我们将加载模型检查点和正确语言的标记器。
from transformers import VitsModel, VitsTokenizer
model = VitsModel.from_pretrained("facebook/mms-tts-deu")
tokenizer = VitsTokenizer.from_pretrained("facebook/mms-tts-deu")
您可能会注意到,要加载 MMS 模型,您需要使用VitsModel
和VitsTokenizer
。这是因为用于文本转语音的 MMS 基于前面提到的 VITS 模型。
让我们选择一段德语示例文本,例如儿童歌曲的前两行。
text_example = (
"Ich bin Schnappi das kleine Krokodil, komm aus Ägypten das liegt direkt am Nil."
)
要生成波形输出,请使用标记器预处理文本,并将其传递给模型。
import torch
inputs = tokenizer(text_example, return_tensors="pt")
input_ids = inputs["input_ids"]
with torch.no_grad():
outputs = model(input_ids)
speech = outputs["waveform"]
让我们听一听。
from IPython.display import Audio
Audio(speech, rate=16000)
太棒了!如果您想尝试使用其他语言的 MMS,请在🤗 Hub 上查找其他合适的vits
检查点。
现在让我们看看如何自己微调 TTS 模型!