返回列表

27th place simple solution (0.932 public, 0.940 private) - dl_pipeline

419. Rainforest Connection Species Audio Detection | rfcx-species-audio-detection

开始: 2020-11-17 结束: 2021-02-17 环境监测 数据算法赛
第27名简单方案 (公开榜0.932, 私有榜0.940) - dl_pipeline

第27名简单方案 (公开榜0.932, 私有榜0.940) - dl_pipeline

作者: Miguel Pinto | 比赛排名: 第27名

总结:

  • 最佳单模型 (公开榜 0.925): densenet121 特征 + fastai 头部
  • 损失函数: 交叉熵
  • 采样: 围绕真实正样本裁剪 128x1024 的区域
  • 声谱图参数: n mels 128, hop length 640, sample rate 32000
  • 增强: 削波失真, 变调 和 mixup
  • 推理: 在较小宽度的裁剪图上进行预测 (例如 128x128,而不是训练时使用的 128x1024),并计算 24 个类别中每个类别的最大概率。

前言

首先,这是一场有趣的比赛,也是一次很好的学习机会,就像 Kaggle 上经常发生的那样!这场比赛的一个“问题”是,测试数据的标记方法不同,而且没有提供标记测试数据的样本。这使得很难感知验证分数,并增加了过拟合公开测试结果的风险。事实上,当我意识到这种情况时,我差点放弃了这场比赛。但最终我决定回到比赛中,致力于一个简单的解决方案和一个 python 库——dl_pipelinehttps://github.com/mnpinto/dl_pipeline)——我将其作为未来一般 Kaggle 比赛的通用框架。最初,dl_pipeline 的想法只是让我的代码更有条理、更可重用,但我发现分享它可能也有价值。

数据预处理

将所有波形文件以 32000 Hz 的采样率保存为 npy 文件,以节省时间。

def audio2npy(file, path_save:Path, sample_rate=32_000):
    path_save.mkdir(exist_ok=True, parents=True)
    wave, _ = librosa.load(file, sr=sample_rate)
    np.save(path_save/f'{file.stem}.npy', wave)

我没有立即将音频转换为声谱图,因为我仍然希望能够在波形上使用音频增强。

增强与声谱图

  • 首先,我在波形上创建包含真实正标签的裁剪区域,计算的样本数使得声谱图的宽度为 1024。

注意:在应用增强之前进行裁剪比反过来做要快得多。

  • 然后对于波形增强,我使用了 audiomentations 库。我最终只使用了以下增强,因为基于公开排行榜我没有发现其他增强有帮助,尽管这需要适当的验证才能得出结论。
def audio_augment(sample_rate, p=0.25):
    return Pipeline([
        ClippingDistortion(sample_rate, max_percentile_threshold=10, p=p),
        PitchShift(sample_rate, min_semitones=-8, max_semitones=8, p=p),
    ])

注意:有些增强要慢得多,例如变调和时间拉伸。当使用这些增强时,使用的概率对训练所需时间有很大影响。

  • 然后我寻找在 GPU 上将音频转换为声谱图的最快方法,最终使用了 nnAudiohttps://github.com/KinWaiCheuk/nnAudio)。同样,在波形裁剪后转换为声谱图在处理时间上是一个很好的收益。

模型

我尝试了几种模型,但在公开排行榜上给我更好结果的是 densenet121,第二好是 ResNeSt50。一个特点是我对所有模型都使用了带有强 dropout 的 fastai 头部。

fastai 头部 (使用 create_head(num_features*2, num_classes, ps=0.8))。

(1): Sequential(
      (0): AdaptiveConcatPool2d(
        (ap): AdaptiveAvgPool2d(output_size=1)
        (mp): AdaptiveMaxPool2d(output_size=1)
      )
      (1): Flatten(full=False)
      (2): BatchNorm1d(2048, eps=1e-05, momentum=0.1, affine