音频数据集预处理
使用 🤗 Datasets 加载数据集只是乐趣的一半。如果你计划将其用于训练模型或运行推理,则需要首先预处理数据。通常,这将涉及以下步骤
- 对音频数据进行重采样
- 过滤数据集
- 将音频数据转换为模型期望的输入
音频数据重采样
load_dataset
函数以其发布的采样率下载音频示例。这并不总是你计划训练或用于推理的模型期望的采样率。如果采样率之间存在差异,你可以将音频重采样到模型期望的采样率。
大多数可用的预训练模型都已在采样率为 16 kHz 的音频数据集上进行了预训练。当我们探索 MINDS-14 数据集时,你可能已经注意到它以 8 kHz 采样,这意味着我们可能需要对其进行上采样。
为此,请使用 🤗 Datasets 的 cast_column
方法。此操作不会就地更改音频,而是向数据集发出信号,以便在加载音频示例时动态对其进行重采样。以下代码将采样率设置为 16kHz
from datasets import Audio
minds = minds.cast_column("audio", Audio(sampling_rate=16_000))
重新加载 MINDS-14 数据集中第一个音频示例,并检查它是否已重采样到所需的 采样率
minds[0]
输出
{
"path": "/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-AU~PAY_BILL/response_4.wav",
"audio": {
"path": "/root/.cache/huggingface/datasets/downloads/extracted/f14948e0e84be638dd7943ac36518a4cf3324e8b7aa331c5ab11541518e9368c/en-AU~PAY_BILL/response_4.wav",
"array": array(
[
2.0634243e-05,
1.9437837e-04,
2.2419340e-04,
...,
9.3852862e-04,
1.1302452e-03,
7.1531429e-04,
],
dtype=float32,
),
"sampling_rate": 16000,
},
"transcription": "I would like to pay my electricity bill using my card can you please assist",
"intent_class": 13,
}
你可能会注意到数组值现在也发生了变化。这是因为我们现在每个以前的值都有两倍的振幅值。
过滤数据集
你可能需要根据某些条件过滤数据。常见的情况之一是将音频示例限制在某个持续时间内。例如,我们可能希望过滤掉任何超过 20 秒的示例,以防止在训练模型时出现内存不足错误。
我们可以通过使用 🤗 Datasets 的 filter
方法并将具有过滤逻辑的函数传递给它来做到这一点。让我们首先编写一个函数来指示要保留哪些示例以及要丢弃哪些示例。此函数 is_audio_length_in_range
在样本短于 20 秒时返回 True
,在样本长于 20 秒时返回 False
。
MAX_DURATION_IN_SECONDS = 20.0
def is_audio_length_in_range(input_length):
return input_length < MAX_DURATION_IN_SECONDS
过滤函数可以应用于数据集的列,但此数据集中没有包含音频轨道持续时间的列。但是,我们可以创建一个,根据该列中的值进行过滤,然后将其删除。
# use librosa to get example's duration from the audio file
new_column = [librosa.get_duration(path=x) for x in minds["path"]]
minds = minds.add_column("duration", new_column)
# use 🤗 Datasets' `filter` method to apply the filtering function
minds = minds.filter(is_audio_length_in_range, input_columns=["duration"])
# remove the temporary helper column
minds = minds.remove_columns(["duration"])
minds
输出
Dataset({features: ["path", "audio", "transcription", "intent_class"], num_rows: 624})
我们可以验证数据集已从 654 个示例缩减到 624 个。
音频数据预处理
使用音频数据集最具挑战性的方面之一是以正确的格式准备数据以进行模型训练。如你所见,原始音频数据以样本值的数组形式出现。但是,预训练模型(无论你将其用于推理还是希望对其进行微调以用于你的任务)都希望将原始数据转换为输入特征。输入特征的要求可能因模型而异——它们取决于模型的架构以及其预训练数据。好消息是,对于每个受支持的音频模型, 🤗 Transformers 都提供了一个特征提取器类,该类可以将原始音频数据转换为模型期望的输入特征。
那么特征提取器对原始音频数据做了什么?让我们看看 Whisper 的特征提取器以了解一些常见的特征提取转换。Whisper 是一个用于自动语音识别 (ASR) 的预训练模型,于 2022 年 9 月由来自 OpenAI 的 Alec Radford 等人发布。
首先,Whisper 特征提取器对一批音频示例进行填充/截断,以便所有示例都具有 30 秒的输入长度。短于此的示例通过在序列末尾追加零来填充到 30 秒(音频信号中的零对应于无信号或静音)。长于 30 秒的示例将被截断到 30 秒。由于批次中的所有元素都在输入空间中填充/截断到最大长度,因此不需要注意力掩码。Whisper 在这方面是独一无二的,大多数其他音频模型都需要一个注意力掩码来详细说明序列在何处被填充,以及在自注意力机制中应忽略何处。Whisper 经过训练可以在没有注意力掩码的情况下运行,并直接从语音信号中推断出忽略输入的位置。
Whisper 特征提取器执行的第二个操作是将填充后的音频数组转换为对数梅尔谱图。如你所知,这些谱图描述了信号的频率如何随时间变化,以梅尔尺度表示并在分贝(对数部分)中测量,以使频率和幅度更能代表人类的听觉。
所有这些转换都可以使用几行代码应用于你的原始音频数据。让我们继续从预训练的 Whisper 检查点加载特征提取器,以便为我们的音频数据做好准备
from transformers import WhisperFeatureExtractor
feature_extractor = WhisperFeatureExtractor.from_pretrained("openai/whisper-small")
接下来,你可以编写一个函数,通过将单个音频示例传递给 feature_extractor
来预处理它。
def prepare_dataset(example):
audio = example["audio"]
features = feature_extractor(
audio["array"], sampling_rate=audio["sampling_rate"], padding=True
)
return features
我们可以使用 🤗 Datasets 的 map 方法将数据准备函数应用于所有训练示例。
minds = minds.map(prepare_dataset)
minds
输出
Dataset(
{
features: ["path", "audio", "transcription", "intent_class", "input_features"],
num_rows: 624,
}
)
就这么简单,现在我们在数据集中拥有了作为 input_features
的对数梅尔声谱图。
让我们可视化 minds
数据集中其中一个示例。
import numpy as np
example = minds[0]
input_features = example["input_features"]
plt.figure().set_figwidth(12)
librosa.display.specshow(
np.asarray(input_features[0]),
x_axis="time",
y_axis="mel",
sr=feature_extractor.sampling_rate,
hop_length=feature_extractor.hop_length,
)
plt.colorbar()
现在您可以看到音频数据在预处理后输入 Whisper 模型时的样子。
模型的特征提取器类负责将原始音频数据转换为模型期望的格式。但是,许多涉及音频的任务是多模态的,例如语音识别。在这种情况下,🤗 Transformers 还提供特定于模型的标记器来处理文本输入。有关标记器的深入了解,请参阅我们的 NLP 课程。
您可以分别加载 Whisper 和其他多模态模型的特征提取器和标记器,或者您可以通过所谓的处理器加载两者。为了使事情更简单,请使用 AutoProcessor
从检查点加载模型的特征提取器和处理器,如下所示
from transformers import AutoProcessor
processor = AutoProcessor.from_pretrained("openai/whisper-small")
在这里,我们说明了基本的数据准备步骤。当然,自定义数据可能需要更复杂的预处理。在这种情况下,您可以扩展函数 prepare_dataset
以执行任何类型的自定义数据转换。使用 🤗 Datasets,如果您可以用 Python 函数编写它,您就可以 将其应用 于您的数据集!