音频课程文档
用于自动语音识别的预训练模型
并获得增强的文档体验
开始使用
用于自动语音识别的预训练模型
在本节中,我们将介绍如何使用 pipeline()
利用预训练模型进行语音识别。在第二单元中,我们介绍了 pipeline()
是一种运行语音识别任务的简单方法,它在内部处理所有预处理和后处理,并具有快速尝试 Hugging Face Hub 上任何预训练检查点的灵活性。在本单元中,我们将深入探讨语音识别模型的不同属性,以及如何使用它们来处理一系列不同的任务。
如第三单元所述,语音识别模型大致分为两类:
- 连接时序分类 (CTC):仅编码器模型,顶部带有线性分类 (CTC) 头
- 序列到序列 (Seq2Seq):编码器-解码器模型,编码器和解码器之间具有交叉注意力机制
2022 年之前,CTC 是这两种架构中更受欢迎的一种,Wav2Vec2、HuBERT 和 XLSR 等仅编码器模型在语音的预训练/微调范式中取得了突破。Meta 和 Microsoft 等大型公司在大量未标记的音频数据上预训练编码器多天或数周。然后,用户可以获取一个预训练检查点,并使用 CTC 头在最少 10 分钟的标记语音数据上对其进行微调,以在下游语音识别任务中获得强大的性能。
然而,CTC 模型有其缺点。将一个简单的线性层附加到编码器会产生一个小型、快速的整体模型,但容易出现语音拼写错误。我们将在下面为 Wav2Vec2 模型演示这一点。
探测 CTC 模型
让我们加载 LibriSpeech ASR 数据集的一小部分,以演示 Wav2Vec2 的语音转录能力。
from datasets import load_dataset
dataset = load_dataset(
"hf-internal-testing/librispeech_asr_dummy", "clean", split="validation"
)
dataset
输出
Dataset({
features: ['file', 'audio', 'text', 'speaker_id', 'chapter_id', 'id'],
num_rows: 73
})
我们可以选择 73 个音频样本之一,并检查音频样本和转录。
from IPython.display import Audio
sample = dataset[2]
print(sample["text"])
Audio(sample["audio"]["array"], rate=sample["audio"]["sampling_rate"])
输出
HE TELLS US THAT AT THIS FESTIVE SEASON OF THE YEAR WITH CHRISTMAS AND ROAST BEEF LOOMING BEFORE US SIMILES DRAWN FROM EATING AND ITS RESULTS OCCUR MOST READILY TO THE MIND
好的!圣诞节和烤牛肉,听起来很棒!🎄 选择了一个数据样本后,我们现在将一个微调检查点加载到 pipeline()
中。为此,我们将使用在 100 小时 LibriSpeech 数据上微调的官方 Wav2Vec2 base 检查点。
from transformers import pipeline
pipe = pipeline("automatic-speech-recognition", model="facebook/wav2vec2-base-100h")
接下来,我们将从数据集中取一个示例,并将其原始数据传递给管道。由于 pipeline
会消耗我们传递给它的任何字典(这意味着它不能被重复使用),我们将传递数据的一个副本。这样,我们就可以在以下示例中安全地重复使用相同的音频样本。
pipe(sample["audio"].copy())
输出
{"text": "HE TELLS US THAT AT THIS FESTIVE SEASON OF THE YEAR WITH CHRISTMAUS AND ROSE BEEF LOOMING BEFORE US SIMALYIS DRAWN FROM EATING AND ITS RESULTS OCCUR MOST READILY TO THE MIND"}
我们可以看到 Wav2Vec2 模型在转录这个样本方面做得相当好——乍一看,它总体上是正确的。让我们将目标和预测并排放置,并突出显示差异。
Target: HE TELLS US THAT AT THIS FESTIVE SEASON OF THE YEAR WITH CHRISTMAS AND ROAST BEEF LOOMING BEFORE US SIMILES DRAWN FROM EATING AND ITS RESULTS OCCUR MOST READILY TO THE MIND
Prediction: HE TELLS US THAT AT THIS FESTIVE SEASON OF THE YEAR WITH **CHRISTMAUS** AND **ROSE** BEEF LOOMING BEFORE US **SIMALYIS** DRAWN FROM EATING AND ITS RESULTS OCCUR MOST READILY TO THE MIND
将目标文本与预测转录进行比较,我们可以看到所有单词听起来都正确,但有些拼写不准确。例如
- CHRISTMAUS 对比 CHRISTMAS
- ROSE 对比 ROAST
- SIMALYIS 对比 SIMILES
这凸显了 CTC 模型的缺点。CTC 模型本质上是一个“仅声学”模型:它由一个编码器组成,该编码器从音频输入中形成隐藏状态表示,以及一个将隐藏状态映射到字符的线性层。
这意味着系统几乎完全基于给定的声学输入(音频的语音)进行预测,因此倾向于以语音方式转录音频(例如,CHRISTMAUS)。它较少重视前后字母的语言建模上下文,因此容易出现语音拼写错误。更智能的模型会识别出 CHRISTMAUS 在英语词汇中不是有效词,并在预测时将其更正为 CHRISTMAS。我们的预测还缺少两个重要特征——大小写和标点符号——这限制了模型转录对实际应用的有用性。
向 Seq2Seq 进阶
欢迎 Seq2Seq 模型!正如第三单元中概述的那样,Seq2Seq 模型由一个编码器和一个通过交叉注意力机制连接的解码器组成。编码器扮演与之前相同的角色,计算音频输入的隐藏状态表示,而解码器扮演语言模型的角色。解码器处理来自编码器的隐藏状态表示的整个序列,并生成相应的文本转录。通过对音频输入的全局上下文,解码器能够在进行预测时使用语言建模上下文,实时纠正拼写错误,从而避免语音预测问题。
Seq2Seq 模型有两个缺点
- 它们的解码速度天生较慢,因为解码过程是分步进行的,而不是一次性完成
- 它们对数据需求更大,需要更多的训练数据才能达到收敛
特别是,对大量训练数据的需求一直是 Seq2Seq 语音架构发展中的一个瓶颈。带标签的语音数据很难获得,当时最大的带注释数据集只有 10,000 小时。这一切在 2022 年 Whisper 发布后发生了改变。Whisper 是 OpenAI 的 Alec Radford 等作者于 2022 年 9 月发布的用于语音识别的预训练模型。与完全在未标记音频数据上预训练的 CTC 前身不同,Whisper 在大量标记的音频转录数据上进行了预训练,精确地说,有 680,000 小时。
这比用于训练 Wav2Vec 2.0 的未标记音频数据(60,000 小时)多一个数量级。更重要的是,这 680,000 小时预训练数据中有 117,000 小时是多语言(或“非英语”)数据。这导致了可以应用于 96 种以上语言的检查点,其中许多被认为是低资源语言,这意味着该语言缺乏适合训练的大量语料库。
当扩展到 680,000 小时标记预训练数据时,Whisper 模型表现出对许多数据集和领域的强大泛化能力。预训练检查点取得了与最先进的管道系统相媲美的结果,在 LibriSpeech 管道的 test-clean 子集上达到了近 3% 的词错误率 (WER),并在 TED-LIUM 上创造了 4.7% WER 的新 SOTA(参见 Whisper 论文表 8)。
特别重要的是 Whisper 处理长音频样本的能力、对输入噪声的鲁棒性以及预测带大小写和标点符号转录的能力。这使其成为真实世界语音识别系统的可行候选者。
本节的其余部分将向您展示如何使用 🤗 Transformers 将预训练的 Whisper 模型用于语音识别。在许多情况下,预训练的 Whisper 检查点性能极佳并能给出很好的结果,因此我们鼓励您首先尝试使用预训练检查点来解决任何语音识别问题。通过微调,预训练检查点可以针对特定数据集和语言进行调整,以进一步改进这些结果。我们将在即将到来的微调小节中演示如何做到这一点。
Whisper 检查点有五种不同模型大小的配置。最小的四种仅在英语或多语言数据上进行训练。最大的检查点仅支持多语言。所有九个预训练检查点都可以在 Hugging Face Hub 上找到。下表总结了这些检查点,并提供了 Hub 上模型的链接。“VRAM”表示以最小批处理大小 1 运行模型所需的 GPU 内存。“相对速度”是检查点与最大模型相比的相对速度。根据这些信息,您可以选择最适合您硬件的检查点。
大小 | 参数量 | 显存 / GB | 相对速度 | 仅限英语 | 多语言 |
---|---|---|---|---|---|
微型 | 39 M | 1.4 | 32 | ✓ | ✓ |
基础 | 74 M | 1.5 | 16 | ✓ | ✓ |
小型 | 244 M | 2.3 | 6 | ✓ | ✓ |
中型 | 769 M | 4.2 | 2 | ✓ | ✓ |
大型 | 1550 M | 7.5 | 1 | X | ✓ |
让我们加载 Whisper Base 检查点,它的大小与我们之前使用的 Wav2Vec2 检查点相当。为了预见我们将转向多语言语音识别,我们将加载基础检查点的多语言变体。如果可用,我们还将把模型加载到 GPU 上,否则加载到 CPU 上。pipeline()
随后将负责根据需要将所有输入/输出从 CPU 移动到 GPU。
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
)
太好了!现在像以前一样转录音频。我们所做的唯一更改是传递一个额外的参数 max_new_tokens
,它告诉模型在进行预测时要生成的最大 token 数量。
pipe(sample["audio"], max_new_tokens=256)
输出
{'text': ' He tells us that at this festive season of the year, with Christmas and roast beef looming before us, similarly is drawn from eating and its results occur most readily to the mind.'}
够简单吧!你会注意到的第一件事是大小写和标点符号的存在。这使得转录比 Wav2Vec2 的无大小写和无标点符号的转录更容易阅读。让我们将转录与目标并排放置。
Target: HE TELLS US THAT AT THIS FESTIVE SEASON OF THE YEAR WITH CHRISTMAS AND ROAST BEEF LOOMING BEFORE US SIMILES DRAWN FROM EATING AND ITS RESULTS OCCUR MOST READILY TO THE MIND
Prediction: He tells us that at this festive season of the year, with **Christmas** and **roast** beef looming before us, **similarly** is drawn from eating and its results occur most readily to the mind.
Whisper 在纠正我们从 Wav2Vec2 看到的发音错误方面做得非常出色——Christmas 和 roast 都拼写正确。我们看到模型仍然在 SIMILES 上挣扎,被错误地转录为 similarly,但这次预测是英语词汇中的有效词。使用更大的 Whisper 检查点可以进一步减少转录错误,代价是需要更多的计算和更长的转录时间。
我们已经承诺了一个能够处理 96 种语言的模型,所以现在让我们暂时离开英语语音识别,走向全球🌎!多语言 LibriSpeech (MLS) 数据集是 LibriSpeech 数据集的相应多语言版本,包含六种语言的带标签音频数据。我们将从 MLS 数据集的西班牙语部分加载一个样本,使用流式模式,这样我们就无需下载整个数据集。
dataset = load_dataset(
"facebook/multilingual_librispeech", "spanish", split="validation", streaming=True
)
sample = next(iter(dataset))
再次,我们将检查文本转录并听取音频片段。
print(sample["text"])
Audio(sample["audio"]["array"], rate=sample["audio"]["sampling_rate"])
输出
entonces te delelitarás en jehová y yo te haré subir sobre las alturas de la tierra y te daré á comer la heredad de jacob tu padre porque la boca de jehová lo ha hablado
这就是我们希望通过 Whisper 转录实现的目标文本。尽管我们现在知道我们可能会做得更好,因为我们的模型还将预测标点符号和大小写,而这些在参考中都不存在。让我们将音频样本转发给管道以获取我们的文本预测。需要注意的一点是,管道会消耗我们输入的音频输入字典,这意味着该字典无法重复使用。为了避免这种情况,我们将传递音频样本的副本,这样我们就可以在后续的代码示例中重复使用相同的音频样本。
pipe(sample["audio"].copy(), max_new_tokens=256, generate_kwargs={"task": "transcribe"})
输出
{'text': ' Entonces te deleitarás en Jehová y yo te haré subir sobre las alturas de la tierra y te daré a comer la heredad de Jacob tu padre porque la boca de Jehová lo ha hablado.'}
太棒了——这看起来与我们的参考文本非常相似(可以说更好,因为它有标点符号和大小写!)。你会注意到我们将 "task"
作为生成关键字参数 (generate kwarg) 转发。将 "task"
设置为 "transcribe"
会强制 Whisper 执行语音识别任务,其中音频会以语音所用的相同语言进行转录。Whisper 也能够执行密切相关的语音翻译任务,其中西班牙语音频可以翻译成英语文本。为了实现这一点,我们将 "task"
设置为 "translate"
。
pipe(sample["audio"], max_new_tokens=256, generate_kwargs={"task": "translate"})
输出
{'text': ' So you will choose in Jehovah and I will raise you on the heights of the earth and I will give you the honor of Jacob to your father because the voice of Jehovah has spoken to you.'}
既然我们知道可以在语音识别和语音翻译之间切换,我们就可以根据自己的需求选择任务。我们可以将语言 X 中的音频识别为相同语言 X 的文本(例如,西班牙语音频到西班牙语文本),或者将任何语言 X 的音频翻译为英语文本(例如,西班牙语音频到英语文本)。
要了解有关如何使用 "task"
参数控制生成文本属性的更多信息,请参阅 Whisper 基础模型的模型卡。
长篇转录和时间戳
到目前为止,我们一直专注于转录少于 30 秒的短音频样本。我们提到 Whisper 的一个吸引力在于其处理长音频样本的能力。我们将在本节中处理此任务!
让我们通过连接 MLS 数据集中的顺序样本来创建一个长音频文件。由于 MLS 数据集是通过将长有声读物录音分成较短的片段来整理的,因此连接样本是重建较长有声读物片段的一种方法。因此,生成的音频在整个样本中应该是一致的。
我们将目标音频长度设置为 5 分钟,并在达到此值后停止连接样本。
import numpy as np
target_length_in_m = 5
# convert from minutes to seconds (* 60) to num samples (* sampling rate)
sampling_rate = pipe.feature_extractor.sampling_rate
target_length_in_samples = target_length_in_m * 60 * sampling_rate
# iterate over our streaming dataset, concatenating samples until we hit our target
long_audio = []
for sample in dataset:
long_audio.extend(sample["audio"]["array"])
if len(long_audio) > target_length_in_samples:
break
long_audio = np.asarray(long_audio)
# how did we do?
seconds = len(long_audio) / 16000
minutes, seconds = divmod(seconds, 60)
print(f"Length of audio sample is {minutes} minutes {seconds:.2f} seconds")
输出
Length of audio sample is 5.0 minutes 17.22 seconds
好的!5 分 17 秒的音频需要转录。将这个长音频样本直接转发给模型存在两个问题:
- Whisper 本身就是为处理 30 秒的样本而设计的:任何短于 30 秒的都会用静音填充到 30 秒,任何长于 30 秒的都会通过截断多余的音频来截断到 30 秒,所以如果我们将音频直接传入,我们将只得到前 30 秒的转录。
- Transformer 网络中的内存随序列长度的平方而缩放:输入长度加倍,内存需求就翻两番,因此传入超长音频文件必然会导致内存不足 (OOM) 错误。
🤗 Transformers 中长篇转录的工作方式是分块将输入音频分割成更小、更易于管理的片段。每个片段与前一个片段有少量重叠。这使得我们能够准确地在边界处将片段重新拼接在一起,因为我们可以找到片段之间的重叠并相应地合并转录。

分块样本的优点是我们不需要块的结果来转录后续块。拼接是在我们转录完所有块的块边界处完成的,所以我们以何种顺序转录块并不重要。算法完全是无状态的,所以我们甚至可以同时进行块和块!这使我们能够批量处理这些块,并并行地将它们通过模型,与顺序转录相比,大大提高了计算速度。要了解有关 🤗 Transformers 中分块的更多信息,您可以参考这篇博客文章。
要激活长篇转录,我们在调用管道时必须添加一个额外的参数。这个参数 chunk_length_s
控制分块片段的长度(秒)。对于 Whisper,30 秒的块是最佳的,因为这与 Whisper 预期的输入长度相匹配。
要激活批处理,我们需要向管道传递参数 batch_size
。综合起来,我们可以使用分块和批处理来转录长音频样本,如下所示:
pipe(
long_audio,
max_new_tokens=256,
generate_kwargs={"task": "transcribe"},
chunk_length_s=30,
batch_size=8,
)
输出
{'text': ' Entonces te deleitarás en Jehová, y yo te haré subir sobre las alturas de la tierra, y te daré a comer la
heredad de Jacob tu padre, porque la boca de Jehová lo ha hablado. nosotros curados. Todos nosotros nos descarriamos
como bejas, cada cual se apartó por su camino, mas Jehová cargó en él el pecado de todos nosotros...
我们不会在这里打印整个输出,因为它太长了(总共 312 个单词)!在 16GB V100 GPU 上,您可以预期上述代码行大约需要 3.45 秒才能运行,对于 317 秒的音频样本来说,这已经相当不错了。在 CPU 上,预计接近 30 秒。
Whisper 也能够预测音频数据的分段时间戳。这些时间戳指示一小段音频的开始和结束时间,对于将转录与输入音频对齐特别有用。假设我们要为视频提供字幕——我们需要这些时间戳来知道转录的哪一部分对应视频的特定片段,以便在该时间显示正确的转录。
激活时间戳预测很简单,我们只需要将参数 return_timestamps=True
设置为 true。时间戳与我们之前使用的分块和批处理方法都兼容,因此我们可以简单地将时间戳参数附加到我们之前的调用中。
pipe(
long_audio,
max_new_tokens=256,
generate_kwargs={"task": "transcribe"},
chunk_length_s=30,
batch_size=8,
return_timestamps=True,
)["chunks"]
输出
[{'timestamp': (0.0, 26.4),
'text': ' Entonces te deleitarás en Jehová, y yo te haré subir sobre las alturas de la tierra, y te daré a comer la heredad de Jacob tu padre, porque la boca de Jehová lo ha hablado. nosotros curados. Todos nosotros nos descarriamos como bejas, cada cual se apartó por su camino,'},
{'timestamp': (26.4, 32.48),
'text': ' mas Jehová cargó en él el pecado de todos nosotros. No es que partas tu pan con el'},
{'timestamp': (32.48, 38.4),
'text': ' hambriento y a los hombres herrantes metas en casa, que cuando vieres al desnudo lo cubras y no'},
...
瞧!我们得到了预测的文本以及相应的时间戳。
总结
Whisper 是一款强大的预训练语音识别和翻译模型。与 Wav2Vec2 相比,它具有更高的转录准确性,输出包含标点符号和大小写。它可用于转录英语以及其他 96 种语言的语音,无论是短音频片段还是通过分块处理的长音频片段。这些特性使其成为许多语音识别和翻译任务的可行模型,无需进行微调。pipeline()
方法提供了一种简单的方式,通过一行 API 调用进行推理,并可控制生成的预测。
尽管 Whisper 模型在许多高资源语言上表现出色,但它在低资源语言(即那些训练数据较少可用的语言)上的转录和翻译准确性较低。在某些语言的不同口音和方言之间也存在不同的性能,包括对不同性别、种族、年龄或其他人口统计学标准的说话者的准确性较低(参见 Whisper 论文)。
为了提升在低资源语言、口音或方言上的性能,我们可以使用预训练的 Whisper 模型,并在一个小规模的、适当选择的数据集上对其进行训练,这个过程称为微调。我们将展示,仅用少至十小时的额外数据,我们就可以将 Whisper 模型在低资源语言上的性能提高 100% 以上。在下一节中,我们将介绍选择用于微调的数据集的过程。
< > 在 GitHub 上更新