- 人工智能
- 语音
- 音频
【免费下载链接】PaddleSpeech
Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award.
本篇技术指南围绕 PaddleSpeech 仓库中paddleaudio.datasets.dataset模块展开,深入剖析音频分类任务中统一数据集基类AudioClassificationDataset的设计原理、特征提取机制与数据切分策略,并结合 ESC-50、GTZAN、TESS、UrbanSound8K、HeySnips、VoxCeleb 等真实数据集实现,说明如何基于该基类构建、使用和扩展音频分类数据集。读者读完后,将掌握 PaddleSpeech 中音频数据管线的完整调用链、feat_type五种特征模式的选型要点,以及训练集/开发集切分的底层逻辑。
一、模块定位:音频分类数据集的统一基类
1.1 文档入口与模块结构
docs/source/audio_api/paddleaudio.datasets.dataset.rst是 PaddleSpeech 文档系统中paddleaudio.datasets.dataset模块的 API 文档入口,通过 Sphinx 的automodule指令自动生成该模块的完整成员文档:
.. automodule:: paddleaudio.datasets.dataset :members: :undoc-members: :show-inheritance:该模块的实体代码位于 audio/paddleaudio/datasets/dataset.py,核心交付物是一个面向音频分类任务的通用数据集基类AudioClassificationDataset,它继承自 Paddle 框架的paddle.io.Dataset,为所有音频分类数据集子类提供了统一的"文件列表 + 标签列表 + 特征提取"骨架。
在 PaddleSpeech 中,该基类被两个位置复用:
- PaddleAudio 独立音频库:audio/paddleaudio/datasets/dataset.py;
- PaddleSpeech 主包:paddlespeech/audio/datasets/dataset.py。
两个位置的类定义保持同构,子类通过 audio/paddleaudio/datasets/init.py 统一导出,当前注册的数据集包括ESC50、GTZAN、HeySnips、OpenRIRNoise、TESS、UrbanSound8K、VoxCeleb。
1.2 继承体系与整体调用链
从源码结构看,AudioClassificationDataset的继承与调用链可以归纳为:
paddle.io.Dataset └── AudioClassificationDataset # 基类:files + labels + 特征提取 ├── ESC50 # 环境声音分类(50 类) ├── GTZAN # 音乐流派分类(10 类) ├── TESS # 情感语音识别(7 类) ├── UrbanSound8K # 城市声音分类(10 类) └── HeySnips # 唤醒词检测(kaldi_fbank 特征) paddle.io.Dataset └── OpenRIRNoise # 数据增强用 RIR/噪声(独立实现) └── VoxCeleb # 说话人验证(独立实现)其中HeySnips、OpenRIRNoise、VoxCeleb直接使用基类模块中定义的feat_funcs特征函数注册表,共享同一套特征提取能力。
二、基类核心实现:构造参数与数据获取
2.1 构造函数参数说明
AudioClassificationDataset.__init__接收四个核心参数(dataset.py):
| 参数 | 类型 | 默认值 | 含义 |
|---|---|---|---|
files | List[str] | 必填 | 音频文件的绝对路径列表 |
labels | List[int] | 必填 | 与files一一对应的类别标签 |
feat_type | str | 'raw' | 特征类型,决定对每段音频做何种特征提取 |
sample_rate | int | None | 采样率;为None时保持音频原始采样率,否则统一重采样 |
**kwargs | dict | {} | 额外的特征提取配置,透传给对应的特征函数 |
构造函数在实例化时会先校验feat_type是否在feat_funcs注册表中,若传入未知类型会抛出RuntimeError:
if feat_type not in feat_funcs.keys(): raise RuntimeError( f"Unknown feat_type: {feat_type}, it must be one in {list(feat_funcs.keys())}" )2.2 特征函数注册表 feat_funcs
基类模块顶部定义了五种特征模式的注册表,是整个数据管线的特征分发中枢(dataset.py):
feat_funcs = { 'raw': None, 'melspectrogram': melspectrogram, 'mfcc': mfcc, 'kaldi_fbank': kaldi_fbank, 'kaldi_mfcc': kaldi_mfcc, }各模式对应的实现与适用场景:
feat_type | 底层实现 | 输入形态 | 输出 | 典型场景 |
|---|---|---|---|---|
raw | None | numpy 波形 | 原始波形 | 端到端模型或下游自定义特征 |
melspectrogram | librosa 兼容实现 | numpy 波形 | (n_mels, num_frames) | 音频分类、环境声音识别 |
mfcc | librosa 兼容实现 | numpy 波形 | (n_mfcc, num_frames) | 音乐流派、情感识别 |
kaldi_fbank | Kaldi 对齐实现 | Paddle Tensor(C, T) | (num_frames, n_mels) | 唤醒词检测(HeySnips 默认) |
kaldi_mfcc | Kaldi 对齐实现 | Paddle Tensor(C, T) | (num_frames, n_mfcc) | ASR 前端特征 |
值得注意的是,两种 kaldi 系列特征输入的是paddle.Tensor((C, T)形状),输出帧优先的二维矩阵;而两种 librosa 系列特征与raw模式处理的是 numpy 波形。基类在_convert_to_record中对这一差异做了分支处理。
2.3 数据获取与记录转换流程
_convert_to_record完成"读音频 → 提特征 → 组装样本"的核心流程(dataset.py):
def _convert_to_record(self, idx): file, label = self.files[idx], self.labels[idx] if self.sample_rate is None: waveform, sample_rate = load_audio(file) else: waveform, sample_rate = load_audio(file, sr=self.sample_rate) feat_func = feat_funcs[self.feat_type] record = {} if self.feat_type in ['kaldi_fbank', 'kaldi_mfcc']: waveform = paddle.to_tensor(waveform).unsqueeze(0) # (C, T) record['feat'] = feat_func( waveform=waveform, sr=self.sample_rate, **self.feat_config) else: record['feat'] = feat_func( waveform, sample_rate, **self.feat_config) if feat_func else waveform record['label'] = label return record流程要点:
- 音频读取:通过
soundfile_load(audio/paddleaudio/backends/soundfile_backend.py)加载波形;该函数底层基于libsndfile,支持 WAV、FLAC、OGG/VORBIS、SPHERE 等格式,并内置单声道合并、线性/高斯归一化、kaiser 滤波重采样等处理; - 特征分发:依据
feat_type从注册表取出对应特征函数,把**kwargs中的feat_config作为特征参数透传; - kaldi 系列特殊处理:将波形转为
paddle.Tensor并增加通道维度到(C, T),与 Kaldi 特征函数fbank/mfcc的输入契约(waveform: Tensor,形状(C, T),C取值 0 或 1)对齐; - 标签组装:把标签写入
record['label'],供__getitem__返回。
__getitem__进一步区分返回格式(dataset.py):
- 对
kaldi_fbank/kaldi_mfcc,返回三元组(self.keys[idx], record['feat'], record['label']),其中keys由子类在_get_data中填充(如 HeySnips 的音频 id),供流式/对齐训练使用; - 其余特征类型返回
(np.array(feat).transpose(), np.array(label, dtype=np.int64)),即转置后的特征矩阵与 int64 标签。
__len__直接返回files列表长度,保证与数据总量一致。
三、音频后端与特征实现:底层原理纵深
3.1 音频读取后端 soundfile_load
基类默认使用 soundfile 后端读取音频(from ..backends.soundfile_backend import soundfile_load as load_audio)。soundfile_load的核心处理链为:soundfile_load_(libsndfile 底层读取)→to_mono(多声道合并,支持ch0/ch1/random/average四种策略)→resample(基于 resampy,支持kaiser_best与kaiser_fast)→normalize(linear线性归一化到[-1, 1]或gaussian零均值单位方差)→depth_convert(按目标 dtype 转换)。
设计上的一个细节:resample在kaiser_best模式下会输出性能告警,提示大规模训练建议使用kaiser_fast,这与 PaddleSpeech 大规模音频训练的实际诉求一致。
3.2 两类特征实现的对齐语义
Kaldi 对齐特征(kaldi_fbank / kaldi_mfcc):实现在 audio/paddleaudio/compliance/kaldi.py,目标是"输出与 Kaldi 完全一致"。以fbank为例(kaldi.py),完整复刻了 Kaldi 的参数体系:
- 窗函数参数:
frame_length=25.0(毫秒)、frame_shift=10.0、window_type="povey"、blackman_coeff=0.42; - 信号预处理:
preemphasis_coefficient=0.97、remove_dc_offset=True、dither=0.0、snip_edges=True; - Mel 滤波:
n_mels=23、low_freq=20.0、high_freq=0.0、use_power=True、use_log_fbank=True; - 输出修饰:
subtract_mean=False、use_energy=False、htk_compat=False、vtln_warp=1.0。
计算管线依次为:分帧加窗(_get_waveform_and_window_properties+_get_window)→paddle.fft.rfft计算幅度谱 → 可选平方转功率谱 → 与 Kaldi Mel 滤波器组(_get_mel_banks,含 VTLN 分段线性扭曲)做矩阵乘法 → 取对数 → 可选拼接能量维 → 可选减列均值。mfcc在 fbank 基础上叠加 DCT 变换矩阵(_get_dct_matrix)与倒谱提升(cepstral_lifter=22.0),输出n_mfcc=13维系数。
librosa 对齐特征(melspectrogram / mfcc):实现在 audio/paddleaudio/compliance/librosa.py,用于在无 librosa 依赖的环境下复现其计算语义。melspectrogram(librosa.py)的关键参数为:
- 帧参数:
window_size=512、hop_length=320、window='hann'、center=True、pad_mode='reflect'; - Mel 参数:
n_mels=64、fmin=50.0、fmax=None(None 时取sr//2)、power=2.0; - 刻度转换:
to_db=True、ref=1.0、amin=1e-10、top_db=None。
计算流程为 STFT(stft)→ 功率谱np.abs(s)**power→ 乘以 Mel 滤波器组矩阵compute_fbank_matrix→ 可选power_to_db转 dB 刻度。mfcc则在其上施加 scipy DCT(dct_type=2, norm='ortho')并支持倒谱提升lifter。
这种"双套特征实现"的设计使得同一份数据既能为 Kaldi 生态的 ASR/唤醒词模型提供严格对齐的帧级特征,也能为基于 librosa 语义的分类模型提供频谱类特征,是feat_type设计意图的直接体现。
四、经典数据集子类实现:从基类到真实数据
基类的_get_data以NotImplementedError占位,强制子类实现"文件-标签"对的生产逻辑。以下按子类逐一分析。
4.1 ESC50:环境声音分类(50 类)
audio/paddleaudio/datasets/esc50.py 实现 ESC-50 数据集:2000 段 5 秒环境录音,覆盖 50 个语义类别(每类 40 条),源自论文ESC: Dataset for Environmental Sound Classification。
- 归档与校验:
archives指向 PaddleAudio 镜像的ESC-50-master.zip,附带 md5 校验;首次使用时_get_data检测DATA_HOME下缺少音频目录或元数据文件meta/esc50.csv,自动调用download_and_decompress下载解压; - 元数据解析:
meta_info为 7 字段 namedtuple('filename', 'fold', 'target', 'category', 'esc10', 'src_file', 'take'),逐行读取 CSV 跳过表头; - 折切分:ESC-50 官方预定义 5 折(fold 1-5),
mode='train'时取fold != split的全部样本,mode != 'train'(即 dev)时取fold == split的样本,无需随机种子即可保证训练/开发集不相交。
4.2 GTZAN:音乐流派分类(10 类)
audio/paddleaudio/datasets/gtzan.py 实现 GTZAN 数据集:1000 段 30 秒音乐片段,10 种流派各 100 条,是音乐流派识别(MGR)领域使用最广的公开数据集。
- 构造参数在基类之上增加了
seed=0、n_folds=5、split=1,并断言split <= n_folds; - 与 ESC50 依赖官方 fold 不同,GTZAN 采用随机折切分:读取
genres/input.mf元数据后先random.seed(seed)再random.shuffle(meta_info),随后按n_samples_per_fold = len(meta_info) // n_folds均匀划分为 n 折,第split折作为 dev、其余作为 train——同样的 seed 可以复现出完全一致的切分; - 文件路径按
DATA_HOME/genres/{label}/{filename}组织,标签通过label_list.index(label)转为整数索引。
4.3 TESS:情感语音识别(7 类)
audio/paddleaudio/datasets/tess.py 实现 TESS(Toronto Emotional Speech Set):两位女演员(26 岁与 64 岁)在载句 "Say the word ____" 中朗读 200 个目标词,录制 7 种情感(angry、disgust、fear、happy、neutral、pleasant surprise、sad),共 2800 条刺激样本。
- 不依赖外部元数据文件,而是从文件名解析信息:
_get_meta_info取文件去掉扩展名的 basename 按_拆分出(speaker, word, emotion)三元组; - 情感标签通过
self.label_list.index(emotion)转换; - 同样采用
seed+n_folds+split的随机折切分策略,切分前先os.walk收集全部.wav文件。
4.4 UrbanSound8K:城市声音分类(10 类)
audio/paddleaudio/datasets/urban_sound.py 实现 UrbanSound8K:8732 段不超过 4 秒的城市声音片段,10 个类别(air_conditioner、car_horn、children_playing、dog_bark、drilling、engine_idling、gun_shot、jackhammer、siren、street_music)。
- 元数据文件为
metadata/UrbanSound8K.csv,namedtuple 含 8 字段('filename', 'fsid', 'start', 'end', 'salience', 'fold', 'class_id', 'label'); - 与 ESC50 一致采用官方预定义 fold 切分,音频按
audio/fold{fold}/目录组织; - 归档来自 Zenodo 官方发布,同样附带 md5 校验与自动下载。
4.5 HeySnips:唤醒词检测(kaldi_fbank)
audio/paddleaudio/datasets/hey_snips.py 实现 HeySnips 唤醒词数据集,是基类"非默认特征 + 定制返回格式"的典型:
- 构造函数要求显式传入
data_dir,feat_type默认为kaldi_fbank,sample_rate=16000; - 元数据来自
{mode}.json(JSON 逐条包含id、is_hotword、duration、audio_file_path),is_hotword == 1的样本标签为 0,其余为 -1(负样本); _get_data额外填充self.keys与self.durations,配合基类__getitem__中 kaldi 分支返回(key, feat, label)三元组,供流式唤醒词模型的帧级训练使用。
五、独立数据集实现:OpenRIRNoise 与 VoxCeleb
这两个数据集直接继承paddle.io.Dataset,但复用了基类导出的feat_funcs注册表,并在基类之上增加了**音频切块(chunking)**能力,服务数据增强与说话人验证场景。
5.1 OpenRIRNoise:RIR 与噪声数据增强
audio/paddleaudio/datasets/rirs_noises.py 提供 OpenSLR 28 号资源(rirs_noises.zip)的封装,subsets仅含['rir', 'noise'],默认subset='rir',统一sample_rate=16000。
关键设计与参数:
chunk_duration=3.0(秒):_get_audio_info中若音频时长超过该值,按_get_chunks切分为等长片段,并调用soundfile_save落盘为_chunk_XX.wav,同时记录每个切片的起止时间戳;random_chunk=True时随机选取片段;target_dir:可通过该参数重定向 CSV 生成目录,便于数据预处理到指定磁盘;prepare_data读取 RIR 与噪声的 list 文件生成rir.csv/noise.csv,generate_csv表头为["id", "duration", "wav"];_convert_to_record遍历 namedtuple 字段组装 record,并按feat_type经feat_funcs提取特征,__getitem__返回该 record。
该数据集典型的用途是数据增强:用rir子集做房间冲击响应卷积、用noise子集做加噪,从而提升模型在远场、嘈杂环境下的鲁棒性。
5.2 VoxCeleb:说话人验证
audio/paddleaudio/datasets/voxceleb.py 实现 VoxCeleb1 的完整数据管线,subsets为['train', 'dev', 'enroll', 'test'],默认subset='train'、sample_rate=16000、num_speakers=1211(代码注释说明:vox1 1211 人、vox2 5994 人、vox1+vox2 共 7205 人,测试集 41 人)。
- 多分卷下载与拼接:
archives_audio_dev包含vox1_dev_wav_partaa~partad四个分卷(各带 md5),下载后通过cat拼接为vox1_dev_wav.zip再解压;archives_audio_test直接下载vox1_test_wav.zip;archives_meta下载验证协议veri_test2.txt; - 数据准备:
prepare_data从veri_test2.txt提取 enroll/test 文件集合与对应说话人,将其从训练池中排除,再以split_ratio=0.9把剩余音频随机切分为 train/dev,分别生成train.csv/dev.csv,enroll/test 则不切块直接生成 CSV;说话人 id 经排序后写入spk_id2label.txt完成类别编码; - 特征与切块:
_convert_to_record中random_chunk=True时在每段音频内随机选取chunk_duration秒窗口,否则使用元数据记录的起止采样点;仅train/dev子集附带label; - 并行预处理:
generate_csv使用pathos.multiprocessing.Pool(cpu_count())并行计算各音频的信息与切块信息,适配大规模说话人数据。
六、环境变量与数据目录约定
所有数据集子类通过DATA_HOME定位本地数据,该约定定义在 audio/paddleaudio/utils/env.py:
PPAUDIO_HOME --> 根目录,默认 ~/.paddleaudio,可用环境变量 PPAUDIO_HOME 覆盖 ├── models --> MODEL_HOME,存放模型文件 └── datasets --> DATA_HOME,存放自动下载的数据集DATA_HOME为PPAUDIO_HOME/datasets,首次使用某数据集时若本地缺少对应音频目录与元数据,子类会通过download_and_decompress自动下载并解压(如 ESC50 的ESC-50-master.zip、GTZAN 的genres.tar.gz等,均带 md5 完整性校验)。这在实践上意味着:训练脚本首次运行会自动完成数据准备,无需手工搬运数据。
七、实践要点与选型建议
综合基类与各子类的源码实现,落地使用时建议关注以下几点:
- 特征选型与模型匹配:端到端模型选
raw(返回原始波形);频谱类分类模型选melspectrogram或mfcc;需要与 Kaldi 生态严格对齐(如流式唤醒词、ASR 前端)时选kaldi_fbank/kaldi_mfcc,此时__getitem__返回(key, feat, label)三元组,且输入须为(C, T)的 Paddle Tensor。 - 特征参数透传:通过
**kwargs可覆盖特征函数默认参数,例如AudioClassificationDataset(..., feat_type='melspectrogram', n_mels=80, fmin=0),但需注意参数名必须与对应特征函数签名一致,否则会抛类型错误。 - 切分复现:依赖官方 fold 的 ESC50 / UrbanSound8K 用
split参数即可精确复现;依赖随机折切分的 GTZAN / TESS,必须固定seed以保证训练/开发集一致,TESS/GTZAN 还要求split <= n_folds(构造函数内已断言)。 - 采样率统一:
sample_rate=None时保留原始采样率;传入目标值后统一走 resampy 重采样(默认kaiser_fast),多数据集混合训练时应显式统一采样率。 - 自定义数据集:继承
AudioClassificationDataset后只需实现_get_data(mode, ...) -> (files, labels),即可自动获得特征提取、__len__、__getitem__等能力;若需返回帧级key,在_get_data中填充self.keys并选用 kaldi 系特征即可。
八、结语
paddleaudio.datasets.dataset模块以AudioClassificationDataset基类 +feat_funcs特征注册表为核心,向下对接 soundfile 音频后端与两套(Kaldi/librosa)特征实现,向上支撑 ESC50、GTZAN、TESS、UrbanSound8K、HeySnips 等分类数据集,并与 OpenRIRNoise、VoxCeleb 共享特征提取与数据准备能力,构成了 PaddleSpeech 音频分类任务统一、可扩展的数据管线。理解这一模块的继承关系、特征分发机制与折切分逻辑,是高效使用 PaddleSpeech 音频分类与相关语音任务的第一步。
- 人工智能
- 语音
- 音频
【免费下载链接】PaddleSpeech
Easy-to-use Speech Toolkit including Self-Supervised Learning model, SOTA/Streaming ASR with punctuation, Streaming TTS with text frontend, Speaker Verification System, End-to-End Speech Translation and Keyword Spotting. Won NAACL2022 Best Demo Award.
相关推荐
PaddleSpeech 音频分类:TESS 情绪语音数据集加载、5 折划分与特征提取实战
PaddleSpeech 音频分类:TESS 情绪语音数据集加载、5 折划分与特征提取实战 导读 本文聚焦 PaddleSpeech 项目 PaddleAudi
人工智能语音音频NLP媒体生成PaddleSpeech PaddleAudio 数据集 API 全解:AudioClassificationDataset 基类与七大公开音频数据集
PaddleSpeech PaddleAudio 数据集 API 全解:AudioClassificationDataset 基类与七大公开音频数据集 padd
人工智能语音音频NLP媒体生成PaddleHub ESC50 数据集详解:环境声音分类数据加载与特征提取实践指南
PaddleHub ESC50 数据集详解:环境声音分类数据加载与特征提取实践指南 导读 :本文围绕 PaddleFormers 仓库中 docs/docs_e
人工智能大模型微调模型推理服务
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考