音频课程文档

音频数据集预处理

Hugging Face's logo
加入 Hugging Face 社区

并获得增强文档体验的访问权限

开始使用

音频数据集预处理

使用 🤗 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,
}

你可能会注意到数组值现在也发生了变化。这是因为我们现在每个以前的值都有两倍的振幅值。

💡 关于重采样的背景信息:如果一个音频信号以 8 kHz 采样,因此每秒有 8000 个样本读数,我们知道该音频不包含超过 4 kHz 的任何频率。这是奈奎斯特采样定理保证的。因此,我们可以确定在采样点之间,原始连续信号始终形成平滑曲线。然后,向上采样到更高的采样率只是通过逼近此曲线来计算现有样本之间的其他样本值的问题。然而,向下采样需要我们首先过滤掉任何高于新奈奎斯特极限的频率,然后才能估计新的采样点。换句话说,你不能简单地丢弃每个第二个样本来将采样率降低 2 倍——这会在信号中产生称为混叠的失真。正确执行重采样很棘手,最好留给经过良好测试的库,例如 librosa 或 🤗 Datasets。

过滤数据集

你可能需要根据某些条件过滤数据。常见的情况之一是将音频示例限制在某个持续时间内。例如,我们可能希望过滤掉任何超过 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()
Log mel spectrogram plot

现在您可以看到音频数据在预处理后输入 Whisper 模型时的样子。

模型的特征提取器类负责将原始音频数据转换为模型期望的格式。但是,许多涉及音频的任务是多模态的,例如语音识别。在这种情况下,🤗 Transformers 还提供特定于模型的标记器来处理文本输入。有关标记器的深入了解,请参阅我们的 NLP 课程

您可以分别加载 Whisper 和其他多模态模型的特征提取器和标记器,或者您可以通过所谓的处理器加载两者。为了使事情更简单,请使用 AutoProcessor 从检查点加载模型的特征提取器和处理器,如下所示

from transformers import AutoProcessor

processor = AutoProcessor.from_pretrained("openai/whisper-small")

在这里,我们说明了基本的数据准备步骤。当然,自定义数据可能需要更复杂的预处理。在这种情况下,您可以扩展函数 prepare_dataset 以执行任何类型的自定义数据转换。使用 🤗 Datasets,如果您可以用 Python 函数编写它,您就可以 将其应用 于您的数据集!