音频课程文档

语音到语音翻译

Hugging Face's logo
加入 Hugging Face 社区

并获得增强的文档体验

开始使用

语音到语音翻译

语音到语音翻译(STST 或 S2ST)是一项相对较新的口语处理任务。它涉及将一种语言的语音翻译成**不同**语言的语音。

Diagram of speech to speech translation

STST 可以被视为传统机器翻译(MT)任务的扩展:我们不是将一种语言的**文本**翻译成另一种语言,而是将一种语言的**语音**翻译成另一种语言。STST 在多语言交流领域具有应用前景,它能使不同语言的说话者通过语音媒介相互交流。

假设您想与跨越语言障碍的另一个人交流。您无需先写下您想要表达的信息,然后再将其翻译成目标语言的文本,而是可以直接说出来,让 STST 系统将您的口语转换为目标语言。接收者可以通过对 STST 系统讲话来回应,然后您可以听他们的回应。与基于文本的机器翻译相比,这是一种更自然的交流方式。

在本章中,我们将探讨一种**级联**的 STST 方法,将您在课程单元 5 和 6 中学到的知识整合起来。我们将使用**语音翻译(ST)**系统将源语音转录成目标语言的文本,然后使用**文本到语音(TTS)**将翻译后的文本生成目标语言的语音。

Diagram of cascaded speech to speech translation

我们也可以使用三阶段方法,即首先使用自动语音识别(ASR)系统将源语音转录成相同语言的文本,然后使用机器翻译将转录后的文本翻译成目标语言,最后使用文本到语音系统生成目标语言的语音。然而,向管道中添加更多组件会导致**错误传播**,即在一个系统中引入的错误在流经其余系统时会累积,同时也会增加延迟,因为需要对更多模型进行推理。

尽管这种级联的 STST 方法非常简单,但它能产生非常有效的 STST 系统。ASR + MT + TTS 的三阶段级联系统曾被用于为许多商业 STST 产品提供支持,包括 Google 翻译。它也是一种开发 STST 系统的非常数据和计算效率高的方式,因为现有的语音识别和文本到语音系统可以耦合在一起,无需额外训练即可产生新的 STST 模型。

在本单元的其余部分,我们将重点关注创建一个将任何语言 X 的语音翻译成英语语音的 STST 系统。所涵盖的方法可以扩展到将任何语言 X 翻译成任何语言 Y 的 STST 系统,但我们将其留作读者的扩展,并在适用时提供提示。我们进一步将 STST 任务分为其两个组成部分:ST 和 TTS。最后,我们将它们组合在一起,构建一个 Gradio 演示来展示我们的系统。

语音翻译

我们将使用 Whisper 模型作为我们的语音翻译系统,因为它能够将超过 96 种语言翻译成英语。具体来说,我们将加载 Whisper Base 检查点,它有 74M 参数。它绝不是性能最好的 Whisper 模型,最大的 Whisper 检查点 比它大 20 倍以上,但由于我们将两个自回归系统(ST + TTS)连接在一起,我们希望确保每个模型都能相对快速地生成,以便获得合理的推理速度。

import torch
from transformers import pipeline

device = "cuda:0" if torch.cuda.is_available() else "cpu"
pipe = pipeline(
    "automatic-speech-recognition", model="openai/whisper-base", device=device
)

太棒了!为了测试我们的 STST 系统,我们将加载一个非英语的音频样本。让我们加载 VoxPopuli 数据集的意大利语(it)拆分中的第一个示例。

from datasets import load_dataset

dataset = load_dataset("facebook/voxpopuli", "it", split="validation", streaming=True)
sample = next(iter(dataset))

要收听此样本,我们可以在 Hub 上使用数据集查看器播放:facebook/voxpopuli/viewer

或使用 ipynb 音频功能回放

from IPython.display import Audio

Audio(sample["audio"]["array"], rate=sample["audio"]["sampling_rate"])

现在,让我们定义一个函数,该函数接受此音频输入并返回翻译后的文本。您会记得,我们必须传递用于“task”的生成关键字参数,将其设置为“translate”以确保 Whisper 执行语音翻译而不是语音识别。

def translate(audio):
    outputs = pipe(audio, max_new_tokens=256, generate_kwargs={"task": "translate"})
    return outputs["text"]

Whisper 也可以“被骗”将任何语言 X 的语音翻译成任何语言 Y。只需将任务设置为 `“transcribe”`,并将 `“language”` 设置为生成关键字参数中的目标语言,例如对于西班牙语,可以设置

generate_kwargs={"task": "transcribe", "language": "es"}

太好了!让我们快速检查一下模型是否给出了合理的结果

translate(sample["audio"].copy())
' psychological and social. I think that it is a very important step in the construction of a juridical space of freedom, circulation and protection of rights.'

好的!如果我们将其与原文进行比较

sample["raw_text"]
'Penso che questo sia un passo in avanti importante nella costruzione di uno spazio giuridico di libertà di circolazione e di protezione dei diritti per le persone in Europa.'

我们看到翻译大致吻合(您可以使用 Google 翻译进行双重检查),除了转录开头多出了几个词,那是说话者正在结束前一句。

至此,我们已经完成了级联 STST 管道的前半部分,将我们在单元 5 学习如何使用 Whisper 模型进行语音识别和翻译时获得的技能付诸实践。如果您想复习我们涵盖的任何步骤,请阅读单元 5 中关于用于 ASR 的预训练模型的部分。

文本转语音

我们级联 STST 系统的第二部分涉及将英文文本映射到英文语音。为此,我们将使用预训练的 SpeechT5 TTS 模型进行英文 TTS。🤗 Transformers 目前没有 TTS `pipeline`,所以我们必须自己直接使用模型。这没什么大不了的,在单元 6 之后,你们都是使用模型进行推理的专家了!

首先,我们从预训练检查点加载 SpeechT5 处理器、模型和声码器。

from transformers import SpeechT5Processor, SpeechT5ForTextToSpeech, SpeechT5HifiGan

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

model = SpeechT5ForTextToSpeech.from_pretrained("microsoft/speecht5_tts")
vocoder = SpeechT5HifiGan.from_pretrained("microsoft/speecht5_hifigan")
这里我们使用的是专门针对英语 TTS 训练的 SpeechT5 检查点。如果您希望翻译成非英语语言,请将检查点替换为针对您选择的语言进行微调的 SpeechT5 TTS 模型,或使用在目标语言中预训练的 MMS TTS 检查点。

与 Whisper 模型一样,如果存在 GPU 加速设备,我们也将 SpeechT5 模型和声码器放置在上面。

model.to(device)
vocoder.to(device)

太好了!让我们加载说话人嵌入。

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

我们现在可以编写一个函数,它接受文本提示作为输入,并生成相应的语音。我们首先使用 SpeechT5 处理器预处理文本输入,对文本进行标记以获取我们的输入 ID。然后我们将输入 ID 和说话人嵌入传递给 SpeechT5 模型,如果可用,则将它们放置在加速设备上。最后,我们将返回生成的语音,将其带回 CPU,以便我们可以在 ipynb 笔记本中播放它。

def synthesise(text):
    inputs = processor(text=text, return_tensors="pt")
    speech = model.generate_speech(
        inputs["input_ids"].to(device), speaker_embeddings.to(device), vocoder=vocoder
    )
    return speech.cpu()

让我们用一个虚拟文本输入检查它是否有效

speech = synthesise("Hey there! This is a test!")

Audio(speech, rate=16000)

听起来不错!现在是激动人心的部分——将它们整合在一起。

创建 STST 演示

在我们创建 Gradio 演示来展示我们的 STST 系统之前,我们先快速进行一次健全性检查,以确保我们可以连接这两个模型,即输入一个音频样本并输出一个音频样本。我们将通过连接前面两个小节中定义的两个函数来实现这一点,这样我们就可以输入源音频并检索翻译后的文本,然后将翻译后的文本合成以获得翻译后的语音。最后,我们将合成的语音转换为 `int16` 数组,这是 Gradio 所需的输出音频文件格式。为此,我们首先必须通过目标 dtype (`int16`) 的动态范围对音频数组进行归一化,然后从默认的 NumPy dtype (`float64`) 转换为目标 dtype (`int16`)

import numpy as np

target_dtype = np.int16
max_range = np.iinfo(target_dtype).max


def speech_to_speech_translation(audio):
    translated_text = translate(audio)
    synthesised_speech = synthesise(translated_text)
    synthesised_speech = (synthesised_speech.numpy() * max_range).astype(np.int16)
    return 16000, synthesised_speech

让我们检查一下这个级联函数是否给出预期结果

sampling_rate, synthesised_speech = speech_to_speech_translation(sample["audio"])

Audio(synthesised_speech, rate=sampling_rate)

完美!现在我们将其封装到一个漂亮的 Gradio 演示中,以便我们可以使用麦克风输入或文件输入录制我们的源语音,并播放系统的预测。

import gradio as gr

demo = gr.Blocks()

mic_translate = gr.Interface(
    fn=speech_to_speech_translation,
    inputs=gr.Audio(source="microphone", type="filepath"),
    outputs=gr.Audio(label="Generated Speech", type="numpy"),
)

file_translate = gr.Interface(
    fn=speech_to_speech_translation,
    inputs=gr.Audio(source="upload", type="filepath"),
    outputs=gr.Audio(label="Generated Speech", type="numpy"),
)

with demo:
    gr.TabbedInterface([mic_translate, file_translate], ["Microphone", "Audio File"])

demo.launch(debug=True)

这将启动一个 Gradio 演示,类似于 Hugging Face Space 上运行的那个。

您可以复制这个演示并对其进行修改,以使用不同的 Whisper 检查点、不同的 TTS 检查点,或者放宽输出英语语音的限制,并按照提供的提示翻译成您选择的语言!

展望未来

虽然级联系统是一种计算和数据高效的 STST 系统构建方式,但它存在上述错误传播和累加延迟问题。最近的研究探索了一种**直接**的 STST 方法,这种方法不预测中间文本输出,而是直接从源语音映射到目标语音。这些系统还能够保留源说话者在目标语音中的说话特征(如韵律、音高和语调)。如果您有兴趣了解更多关于这些系统的信息,请查看补充阅读部分列出的资源。

< > 在 GitHub 上更新