音频课程文档

预处理音频数据集

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 是由 OpenAI 的 Alec Radford 等人于 2022 年 9 月发布的用于自动语音识别 (ASR) 的预训练模型。

首先,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 函数,就可以 将其应用于 你的数据集!

< > 在 GitHub 上更新