本文使用ECS50数据集对语音检测和分类模型PANNs进行自定义训练的完整流程进行了记录。
在PANNs音频分类模型预研信息总结一文中,详细介绍了在语音分类应用中非常流行的模型PANNs,该模型使用Google的AudioSet数据集上进行了充分的训练,从而在不同种类的语音检测、辨识和分类应用上取得了非常好的效果。本文基于该模型(CNN14结构)的预训练文件Cnn14_mAP=0.431.pth,使用ECS-50语音数据集对预训练模型进行微调,使之适应ECS-50数据集的检测和分类需求。
ESC-50数据集包含有2000个环境录音文件,该数据集适用于环境声音分类的基准方法。数据集中的每个音频文件由5秒长的记录组成,可分为50个语义类,每个类型有40个示例,松散地分为5个主要类别:

ECS-50数据集的下载地址:karolpiczak/ESC-50: ESC-50: Dataset for Environmental Sound Classification
需要注意的是,ESC-50 数据集中的音频文件原始采样率是 44.1kHz,而 PANNs Cnn14 的预训练权重是基于 32kHz 的。 因此在读取这些音频文件送入模型训练时,必须强制重采样,从44.1Khz转换为32KHz。
客观的讲,PANNs模型对于自定义数据集的训练支持并不是很友好,所以需要自行设计和处理整个训练过程(数据集准备,模型检测头修改,训练流程)的各个阶段的处理流程。
首先从以上ECS-50数据集的下载地址下载到这个数据集的压缩包,整个数据集有600多MB的样子。
然后基于Pytorch的Dataset类派生专门的ECS50数据集的Dataset类,在其中实现len和getitem接口。此处值得一提的是,因为PANNs模型是基于32KHz的音频文件进行训练的,所以此处在加载训练数据之前,需要把ECS50数据集的44.1KHz的音频文件转换为32KHz。
此外为了进一步规范化训练数据集中的音频数据长度,统一把训练数据集中的音频长度固定为5s,过长的音频文件直接截断,过短的因为文件则在后面补零。
class ESC50Dataset(Dataset):
def __init__(self, csv_file, audio_dir, sample_rate=32000):
self.df = pd.read_csv(csv_file)
self.audio_dir = audio_dir
self.sr = sample_rate
def __len__(self):
return len(self.df)
def __getitem__(self, idx):
path = f"{self.audio_dir}/{self.df.iloc[idx]['filename']}"
# 强制进行 32kHz 重采样以匹配 PANNs 预训练设置
audio, _ = librosa.load(path, sr=self.sr, mono=True)
# 音频长度固定为 5秒 (32000 * 5 = 160000 采样点)
if len(audio) < 160000:
audio = np.pad(audio, (0, 160000 - len(audio)), 'constant')
else:
audio = audio[:160000]
label = self.df.iloc[idx]['target'] # 从数据集的csv文件中读取label
return torch.tensor(audio), torch.tensor(label)
PANNs模型是在Google的AudioSet数据集的基础上进行设计和训练的,预训练文件Cnn14_mAP=0.431.pth对应的模型检测头支持527种音频分类。而ECS50数据集支持50种音频分类,因此要在训练之前对检测头部分进行修改,以适应ECS50数据集的要求。
整个过程分为以下步骤: