跳到正文
原文
Hugging Face:Blog(RSS)·· 2023-02-08精选AI 评分70

SpeechT5 语音模型登陆 Hugging Face Transformers,支持 TTS、ASR 与语音转换

Speech Synthesis, Recognition, and More With SpeechT5

AI 导读

微软亚洲研究院的 SpeechT5 现已加入 Hugging Face Transformers,官方 checkpoint 发布在 Hub 上,一个架构可完成语音转文本(ASR)、文本转语音(TTS)和语音转语音(如变声)三类任务。

推荐理由

SpeechT5 以一套架构同时支持 TTS、ASR 和语音转换,官方 checkpoint 已进入 Transformers,文中附完整可跑的代码示例。

正文 · AI 翻译

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

SpeechT5 最初在微软亚洲研究院的论文 SpeechT5: Unified-Modal Encoder-Decoder Pre-Training for Spoken Language Processing 中描述。论文作者发布的官方检查点可在 Hugging Face Hub 上获取。

如果你想直接上手,这里有一些 Spaces 上的演示:

简介

SpeechT5 不是一种,不是两种,而是三种语音模型集于一个架构之中。

它可以做到:

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

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

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

为了使同一个 Transformer 能够处理文本和语音数据,添加了所谓的前网络和后网络。前网络的工作是将输入文本或语音转换为 Transformer 使用的隐藏表示。后网络接收 Transformer 的输出,并将它们再次转换为文本或语音。

下图展示了 SpeechT5 的架构(取自原始论文)。

SpeechT5 architecture diagram

在预训练期间,所有前网络和后网络同时使用。预训练后,整个编码器-解码器主干在单个任务上进行微调。这样的微调模型仅使用特定于给定任务的前网络和后网络。例如,要使用 SpeechT5 进行文本到语音,你会将文本编码器前网络替换为文本输入,并将语音解码器前网络和后网络替换为语音输出。

注意:尽管微调模型最初使用来自共享预训练模型的相同权重集,但最终版本最终都相当不同。例如,你不能拿一个微调过的 ASR 模型并替换前网络和后网络来获得一个可用的 TTS 模型。SpeechT5 很灵活,但没有那么灵活。

文本到语音

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

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

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

  • 语音解码器 pre-net。它以 log mel 频谱图作为输入,并使用一系列线性层将频谱图压缩为隐藏表示。该设计取自 Tacotron 2 TTS 模型。

  • 语音解码器 post-net。它预测一个残差以添加到输出频谱图中,用于细化结果,同样来自 Tacotron 2。

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

SpeechT5 architecture for text-to-speech

以下是如何使用 SpeechT5 文本转语音模型合成语音的完整示例。你也可以在这个交互式 Colab notebook中跟着操作。

SpeechT5 尚未在最新版本的 Transformers 中提供,因此你需要从 GitHub 安装它。同时安装额外的依赖 sentencepiece,然后重启你的运行时。

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

首先,我们从 Hub 加载微调后的模型,以及用于分词和特征提取的 processor 对象。我们将使用的类是 SpeechT5ForTextToSpeech。

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 模型并不局限于为单个说话人创建语音。相反,它使用所谓的说话人嵌入来捕捉特定说话人的声音特征。我们将从 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 嵌入都应该可行。

现在我们可以告诉模型根据输入 token 和说话人嵌入来生成语音。

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

这会输出一个形状为 (140, 80) 的张量,其中包含 log mel 频谱图。第一个维度是序列长度,它可能在不同运行之间有所变化,因为语音解码器 pre-net 总是对输入序列应用 dropout。这会给生成的语音增加一点随机变化。

要将预测的 log mel 频谱图转换为实际的语音波形,我们需要一个声码器。理论上,你可以使用任何适用于 80-bin mel 频谱图的声码器,但为了方便,我们在 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 notebook,其中详细介绍了整个过程。

用于语音转换的语音到语音

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

SpeechT5 architecture for speech-to-speech

语音编码器 pre-net与 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 模型使用以下 pre-net 和 post-net:

  • 语音编码器 pre-net。这与语音到语音模型使用的 pre-net 相同,由 wav2vec 2.0 的 CNN 特征编码器层组成。

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

  • 文本解码器 post-net。这是其中最简单的,由一个线性层组成,将隐藏表示投影为词汇表上的概率。

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

SpeechT5 architecture for speech-to-text

如果你以前尝试过任何其他 🤗 Transformers 语音识别模型,你会发现 SpeechT5 同样易于使用。最快的方法是使用 pipeline。

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

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

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

现在我们可以让 pipeline 处理语音并生成文本转录。

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")

最后,让模型根据语音输入生成文本 token,然后使用处理器的解码函数将这些 token 转换为实际文本。

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

体验 语音转文本任务 的交互式演示。

结论

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

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

来源:Hugging Face:Blog(RSS) · huggingface.co