本文使用ECS50数据集对语音检测和分类模型PANNs进行自定义训练的完整流程进行了记录。

ECS50数据集简介

在PANNs音频分类模型预研信息总结一文中,详细介绍了在语音分类应用中非常流行的模型PANNs,该模型使用Google的AudioSet数据集上进行了充分的训练,从而在不同种类的语音检测、辨识和分类应用上取得了非常好的效果。本文基于该模型(CNN14结构)的预训练文件Cnn14_mAP=0.431.pth,使用ECS-50语音数据集对预训练模型进行微调,使之适应ECS-50数据集的检测和分类需求。

ESC-50数据集包含有2000个环境录音文件,该数据集适用于环境声音分类的基准方法。数据集中的每个音频文件由5秒长的记录组成,可分为50个语义类,每个类型有40个示例,松散地分为5个主要类别:

image.png

ECS-50数据集的下载地址:karolpiczak/ESC-50: ESC-50: Dataset for Environmental Sound Classification

需要注意的是,ESC-50 数据集中的音频文件原始采样率是 44.1kHz,而 PANNs Cnn14 的预训练权重是基于 32kHz 的。 因此在读取这些音频文件送入模型训练时,必须强制重采样,从44.1Khz转换为32KHz。

ECS-50数据集的训练流程记录

客观的讲,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)

CNN14检测头的修改

PANNs模型是在Google的AudioSet数据集的基础上进行设计和训练的,预训练文件Cnn14_mAP=0.431.pth对应的模型检测头支持527种音频分类。而ECS50数据集支持50种音频分类,因此要在训练之前对检测头部分进行修改,以适应ECS50数据集的要求。

整个过程分为以下步骤: