Press "Enter" to skip to content

语音合成、识别与更多功能的 SpeechT5

我们很高兴地宣布,SpeechT5现在已经在🤗 Transformers中可用,这是一个开源库,提供了易于使用的最先进的机器学习模型的实现。

SpeechT5最初在《SpeechT5: Unified-Modal Encoder-Decoder Pre-Training for Spoken Language Processing》一文中进行了描述,该论文是由微软亚洲研究院的研究人员撰写的。该论文作者发布的官方检查点可在Hugging Face Hub上找到。

如果您想立即开始,这里有一些Spaces上的演示:

  • 语音合成(TTS)
  • 语音转换
  • 自动语音识别

介绍

SpeechT5不是一个,也不是两个,而是三种语音模型在一个架构中。

它可以进行:

  • 语音转文本,用于自动语音识别或说话人识别,
  • 文本转语音,用于合成音频,以及
  • 语音转语音,用于在不同的声音之间进行转换或执行语音增强。

SpeechT5背后的主要思想是在文本转语音、语音转文本、文本转文本和语音转语音数据的混合中预训练单个模型。这样,模型可以同时从文本和语音中学习。这种预训练方法的结果是一个拥有文本和语音共享的统一的隐藏表示空间的模型。

SpeechT5的核心是一个常规的Transformer编码器-解码器模型。就像任何其他Transformer一样,编码器-解码器网络使用隐藏表示来建模序列到序列的转换。这个Transformer骨干网络对于所有SpeechT5任务都是相同的。

为了使同一个Transformer能够处理文本和语音数据,添加了所谓的预网络后网络。预网络的任务是将输入文本或语音转换为Transformer使用的隐藏表示。后网络将来自Transformer的输出转换为文本或语音。

下面的图示显示了SpeechT5的架构(摘自原论文)。

在预训练期间,所有的预网络和后网络都同时使用。预训练之后,整个编码器-解码器骨干网络在单个任务上进行微调。这样微调后的模型只使用与给定任务相关的预网络和后网络。例如,要将SpeechT5用于文本到语音的转换,您需要为文本输入切换到文本编码器预网络,并为语音输出切换到语音解码器预网络和后网络。

注意:尽管微调后的模型一开始使用了来自共享预训练模型的相同权重集合,但最终的版本在最后都是完全不同的。例如,您不能使用经过微调的ASR模型并更换预网络和后网络来获得一个可用的TTS模型。SpeechT5是灵活的,但并非如此灵活。

文本转语音

SpeechT5是我们在🤗 Transformers中添加的第一个文本到语音模型,我们计划在不久的将来添加更多的TTS模型。

对于TTS任务,该模型使用以下预网络和后网络:

  • 文本编码器预网络。一个文本嵌入层,将文本标记映射到编码器所期望的隐藏表示。类似于在NLP模型(如BERT)中发生的情况。

  • 语音解码器预网络。它以对数梅尔频谱图为输入,并使用一系列线性层将频谱图压缩为隐藏表示。这个设计来自Tacotron 2 TTS模型。

  • 语音解码器后网络。它预测一个添加到输出频谱图上的残差,并用于优化结果,同样来自Tacotron 2。

微调模型的架构如下所示。

以下是如何使用SpeechT5文本到语音模型合成语音的完整示例。您也可以在这个交互式的Colab笔记本中跟着进行。

SpeechT5在最新版本的Transformers中尚不可用,所以您需要从GitHub上安装它。还要安装附加的依赖项sentencepiece,然后重新启动运行时。

pip install git+https://github.com/huggingface/transformers.git
pip install sentencepiece

首先,我们从Hub加载经过微调的模型,以及用于标记化和特征提取的处理对象。我们将使用的类是SpeechT5ForTextToSpeech

from transformers import SpeechT5Processor, SpeechT5ForTextToSpeech

processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_tts")
model = SpeechT5ForTextToSpeech.from_pretrained("microsoft/speecht5_tts")

接下来,标记化输入文本。

inputs = processor(text="不要计算天数,而是让每一天都有所作为。", return_tensors="pt")

SpeechT5 TTS模型不仅限于为单个说话者创建语音。相反,它使用所谓的说话者嵌入来捕捉特定说话者的声音特征。我们将从Hub上的数据集中加载这样一个说话者嵌入。

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)的张量。这个特定的说话者嵌入描述的是一个女性的声音。这些嵌入是使用CMU ARCTIC数据集和这个脚本获得的,但任何X-Vector嵌入都可以使用。

现在,我们可以告诉模型根据输入标记和说话者嵌入生成语音。

spectrogram = model.generate_speech(inputs["input_ids"], speaker_embeddings)

这将输出一个形状为(140, 80)的张量,其中包含一个对数梅尔频谱图。第一个维度是序列长度,它可能在运行时变化,因为语音解码器预网络总是对输入序列应用丢弃。这给生成的语音添加了一些随机变化。

要将预测的对数梅尔频谱图转换为实际的语音波形,我们需要一个声码器。理论上,您可以使用任何适用于80个频谱图的声码器,但为了方便起见,我们在Transformers中提供了一个基于HiFi-GAN的声码器。这个声码器的权重,以及经过微调的TTS模型的权重,是SpeechT5的原始作者们慷慨提供的。

加载声码器就像加载任何其他🤗 Transformers模型一样简单。

from transformers import SpeechT5HifiGan
vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")

要根据频谱图生成音频,请执行以下操作:

with torch.no_grad():
    speech = vocoder(spectrogram)

我们还提供了一个快捷方式,这样您就不需要制作频谱图的中间步骤。当您将声码器对象传递给generate_speech时,它直接输出语音波形。

speech = model.generate_speech(inputs["input_ids"], speaker_embeddings, vocoder=vocoder)

最后,将语音波形保存到文件中。SpeechT5使用的采样率始终为16 kHz。

import soundfile as sf
sf.write("tts_example.wav", speech.numpy(), samplerate=16000)

输出的声音如下所示(下载音频):

您的浏览器不支持音频元素。

这就是TTS模型的全部内容!使其听起来好的关键是使用正确的说话者嵌入。

您可以在Spaces上体验交互式演示。

💡 想要了解如何在自己的数据集或语言上对SpeechT5 TTS进行微调吗?请查看这个Colab笔记本,其中详细介绍了该过程。

声音转换的语音到语音

从概念上讲,使用SpeechT5进行声音转换的语音到语音建模与文本到语音相同。只需将文本编码器预网络替换为语音编码器预网络即可。模型的其余部分保持不变。

语音编码器预网络与wav2vec 2.0的特征编码模块相同。它由卷积层组成,将输入波形下采样为一系列音频帧表示。

作为一个语音到语音任务的示例,SpeechT5的作者提供了一个用于语音转换的微调模型。要使用此模型,首先从Hub加载模型。注意,模型类现在是SpeechT5ForSpeechToSpeech

from transformers import SpeechT5Processor, SpeechT5ForSpeechToSpeech

processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_vc")
model = SpeechT5ForSpeechToSpeech.from_pretrained("microsoft/speecht5_vc")

我们需要一些语音音频作为输入。为了这个示例,我们将从Hub上加载一个小的语音数据集的音频。你也可以加载自己的语音波形,只要它们是单声道的并且采样率为16 kHz。我们在这里使用的数据集样本已经符合这个格式。

from datasets import load_dataset
dataset = load_dataset("hf-internal-testing/librispeech_asr_demo", "clean", split="validation")
dataset = dataset.sort("id")
example = dataset[40]

接下来,对音频进行预处理,以符合模型的输入格式。

sampling_rate = dataset.features["audio"].sampling_rate
inputs = processor(audio=example["audio"]["array"], sampling_rate=sampling_rate, return_tensors="pt")

与TTS模型一样,我们需要说话者嵌入。这些描述了目标声音的特征。

import torch
embeddings_dataset = load_dataset("Matthijs/cmu-arctic-xvectors", split="validation")
speaker_embeddings = torch.tensor(embeddings_dataset[7306]["xvector"]).unsqueeze(0)

我们还需要加载声码器,将生成的频谱图转换为音频波形。让我们使用与TTS模型相同的声码器。

from transformers import SpeechT5HifiGan
vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")

现在,我们可以通过调用模型的generate_speech方法来进行语音转换。

speech = model.generate_speech(inputs["input_values"], speaker_embeddings, vocoder=vocoder)

import soundfile as sf
sf.write("speech_converted.wav", speech.numpy(), samplerate=16000)

更换不同的声音就像加载一个新的说话者嵌入一样简单。你甚至可以从你自己的声音创建一个嵌入!

原始输入(下载):

您的浏览器不支持音频元素。

转换后的声音(下载):

您的浏览器不支持音频元素。

请注意,此示例中的转换音频在句子结束之前截断。这可能是由于两个句子之间的暂停导致SpeechT5(错误地)预测到达了序列的结尾。尝试使用另一个示例,您会发现转换通常是正确的,但有时会提前停止。

您可以在此处尝试交互式演示。

自动语音识别的语音到文本

ASR模型使用以下预网络和后网络:

  • 语音编码器预网络。这是与语音到语音模型相同的预网络,由wav2vec 2.0的CNN特征编码器层组成。

  • 文本解码器预网络。类似于TTS模型中使用的编码器预网络,它使用嵌入层将文本标记映射到隐藏表示。(在预训练期间,这些嵌入层在文本编码器和解码器预网络之间共享。)

  • 文本解码器后网络。这是最简单的网络,由一个线性层组成,将隐藏表示投影到词汇表上的概率。

微调模型的架构如下所示。

如果您以前尝试过任何其他🤗 Transformers语音识别模型,您会发现SpeechT5的使用方式一样简单。最快的入门方法是使用pipeline。

from transformers import pipeline
generator = pipeline(task="automatic-speech-recognition", model="microsoft/speecht5_asr")

作为语音音频,我们将使用与前一节相同的输入,但任何音频文件都可以使用,因为流水线会自动将音频转换为正确的格式。

from datasets import load_dataset
dataset = load_dataset("hf-internal-testing/librispeech_asr_demo", "clean", split="validation")
dataset = dataset.sort("id")
example = dataset[40]

现在我们可以要求流水线处理语音并生成文本转录。

transcription = generator(example["audio"]["array"])

打印转录结果如下:

a man said to the universe sir i exist

听起来完全正确!SpeechT5使用的分词器非常基础,以字符级别工作。因此,ASR模型不会输出任何标点符号或大写字母。

当然,也可以直接使用模型类。首先,加载微调后的模型和处理器对象。类现在是 SpeechT5ForSpeechToText

from transformers import SpeechT5Processor, SpeechT5ForSpeechToText

processor = SpeechT5Processor.from_pretrained("microsoft/speecht5_asr")
model = SpeechT5ForSpeechToText.from_pretrained("microsoft/speecht5_asr")

预处理语音输入:

sampling_rate = dataset.features["audio"].sampling_rate
inputs = processor(audio=example["audio"]["array"], sampling_rate=sampling_rate, return_tensors="pt")

最后,告诉模型从语音输入生成文本标记,然后使用处理器的解码函数将这些标记转换为实际文本。

predicted_ids = model.generate(**inputs, max_length=100)
transcription = processor.batch_decode(predicted_ids, skip_special_tokens=True)

使用交互式演示来体验语音到文本任务。

结论

SpeechT5是一个有趣的模型,因为与大多数其他模型不同,它允许您使用相同的架构执行多个任务。只有预网络和后网络会有所改变。通过在这些组合任务上进行预训练,模型在微调时对每个单独的任务变得更有能力。

我们只包含了语音识别(ASR)、语音合成(TTS)和语音转换任务的检查点,但论文还提到该模型成功用于语音翻译、语音增强和说话人识别。它非常多功能!

Leave a Reply

Your email address will not be published. Required fields are marked *