mobile wallpaper 1mobile wallpaper 2mobile wallpaper 3
532 字
1 分钟
Audio Course - 预处理数据集

为了让我们的数据集可以用于训练和推理模型,我们需要预处理数据,通常包含

  • 重采样音频
  • 过滤数据集
  • 将音频数据转换为模型所需的输入

重采样音频数据#

Hugging face datasets库中有非常简易的重采样方法

from datasets import load_dataset
from datasets import Audio
minds = load_dataset("audiofolder", data_dir="J:\Temporary\my_dataset", split="train")
minds = minds.cast_column("audio", Audio(sampling_rate=16000))
#这个函数可以对音频进行重采样,传入如上所述的两个参数,只需修改sampling_rate的值就可以改变目标的采样率
#这个函数也不会对原来的数据集产生影响,因此我们要把返回的新数据集赋回给minds
print(minds.features["audio"].sampling_rate)
#可以打印一下看看修改的效果

重采样的背景知识:如果一个音频信号以 8 kHz 采样,即每秒有 8000 个采样读数,我们知道该音频不包含任何超过 4 kHz 的频率,这由奈奎斯特采样定理保证。因此,我们可以确定在采样点之间,原始连续信号始终会形成一条平滑曲线。升采样到更高的采样率,就是通过近似这条曲线来计算现有采样点之间的额外采样值。然而,降采样要求我们首先滤除任何高于新奈奎斯特极限的频率,然后才能估算新的采样点。换句话说,你不能仅仅通过丢弃每隔一个样本来以 2 倍的因子进行降采样——这会在信号中产生称为混叠的失真

我们也可以使用PyTorch中的方法来对音频重采样,实际上,在 加载数据集 中我们使用过这种方法,只需先定义torchaudio中的Resample实例,再向其传入音频序列即可得到我们想要的返回值

import torch
import torchaudio
import os
data_dir = "J:\\Temporary\\my_dataset\\train\\aris"
audio_path = os.path.join(data_dir, os.listdir(data_dir)[0])
waveform, sampling_rate  = torchaudio.load(audio_path)
target_sr = 16000
resampler = torchaudio.transforms.Resample(sampling_rate, target_sr)
#第一个参数是原采样率,第二个则是目标采样率
waveform = resampler(waveform)

过滤数据集#

我们已有的数据集可能是有一些我们不想要的数据的,例如,我们常常需要过滤掉时长过长的音频,因为音频过长容易导致爆显存

datasets库中提供了一个filter()方法来完成这个工作

from datasets import load_dataset
from datasets import Audio
MAX_LENGTH = 10.0 #秒
TARGET_SR = 16000
def is_wanted_audio(input_length):
#我们需要一个会返回True和False的函数,以便filter()来调用
    return input_length < MAX_LENGTH
split = "train"
data_dir = "J:\\Temporary\\my_dataset"
minds = load_dataset("audiofolder", data_dir=data_dir, split=split)
minds = minds.cast_column("audio", Audio(sampling_rate=TARGET_SR))
#重采样音频,这对于计算秒数来说不是必要的,不过对于处理数据集来说是必要的,所以我还是加上来了
print(minds)
#这里print一下方便我们观察数据集的变化
new_column = [data["audio"].get_all_samples().duration_seconds for data in minds]
#由于datasets.filter()方法的特性(特性在后两行说),我们需要给我们的datasets对象加一列特性
minds = minds.add_column("duration", new_column)
#像这样,我们加入了名为"duration"的一个特性,其数值由第二个参数的列表决定
#显然,进行这个操作是需要加入的列表中的元素数与数据数一致的
minds = minds.filter(is_wanted_audio, input_columns="duration")
#filter()方法会对input_columns中的每一组数据调用前一个参数所指向的函数,然后根据函数在这次调用中的返回值来决定是否要过滤掉这个数据
#注意第一个参数我们要传入的是函数对象而非返回值,所以我们不加括号
#input_columns还可以是多个feature字符串组成的列表,这时候它调用函数的行为也会变化
#譬如我们有函数fun(x, y, z),那么datasets.filter(fun, input_columns=["f1","f2","f3"])的行为会变为,对于第i个数据的"f1", "f2", "f3"特征i1, i2, i3,调用fun(i1, i2, i3)
minds = minds.remove_columns(["duration"])
#filter完之后,如果时长信息不再有作用了,我们就可以去掉它
print(minds)
#再print一下我们就可以看到数据集的变化了

一个示例运行结果如下:

Dataset({
features: ['audio'],
num_rows: 11
})
Filter: 100%|███████████████████████████| 11/11 [00:00<00:00, 611.16 examples/s]
features: ['audio'],
num_rows: 8
})

在不使用huggingface datasets时,也可以使用librosa.get_duration()来得到音频的秒数

import librosa
import torch
from torch.utils.data import DataLoader, Dataset
def is_wanted_audio(file_path:str):
    return librosa.get_duration(path=file_path) < MAX_LENGTH
class AudioDataset(Dataset):
    def __init__(self, data_dir:str, target_sample_rate=16000):
        supported_files = (".ogg", ".wav", ".mp3", ".flac")
        self.files = []
        files_in_dir = os.listdir(data_dir)
        for file in files_in_dir:
            file_path = os.path.join(data_dir, file)
            if file.endswith(supported_files) and is_valid(file_path):
            #只需在这里多加一个判断即可
                self.files.append(file_path)
        self.target_sr = target_sample_rate

提取特征#

我们可以使用WhisperFeatureExtractor来得到对数梅尔频谱图来作为输入特征

import datasets
from datasets import Audio
from transformers import WhisperFeatureExtractor as wfe
feature_extractor = wfe.from_pretrained("openai/whisper-small")
minds = datasets.load_dataset("audiofolder", data_dir="J:\Temporary\my_dataset", split="train")
minds = minds.cast_column("audio", Audio(sampling_rate=16000))
#WhisperFeatureExtractor要求输入音频的频率与whisper模型所用音频频率一致,也就是16000Hz,所以我们在这里重采样
def prepare_dataset(example):
    audio = example["audio"]
    features = feature_extractor(audio["array"], sampling_rate=audio["sampling_rate"], padding=True)
    #通过这样的调用,我们可以得到单个音频的梅尔频谱图
    return features
minds = minds.map(prepare_dataset)
#datasets.map()方法可以对每条数据都进行操作,并且向数据集中加入"input_features"列,新加入的列中的数据就是我们刚刚得到的梅尔频谱图
print(minds)
#不妨打印一下看看数据集发生了什么变化

示例输出如下

Map: 100%|██████████████████████████| 11/11 [00:17<00:00, 1.62s/ examples]
Dataset({
features: ['audio', 'input_features'],
num_rows: 11
})
分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Audio Course - 预处理数据集
https://hatoya-doublepigeonblog.pages.dev/posts/audiocourse3/
作者
两只鸽子
发布于
2026-02-18
许可协议
CC BY-NC-SA 4.0

部分信息可能已经过时