返回列表

32nd place solution - what worked for me

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

开始: 2020-11-17 结束: 2021-02-17 环境监测 数据算法赛
第32名方案 - 对我有效的策略

第32名方案 - 对我有效的策略

作者:YoonSoo
比赛排名:第32名

祝贺获得顶尖名次的选手们!

这是我第一次参加音频比赛,所以我尝试了很多可能不太靠谱的想法,但也学到了很多。特别是康奈尔鸟叫声识别和 Freesound 音频标记 2019 比赛的解决方案对我帮助很大。

我的最终成绩并不算突出,但我想分享一些我认为(因为我的分数不够高,所以不能完全确定)对我有效(提高了 CV 或 Public 分数)的方法,并希望听听其他 Kaggle 选手的经验。

  • 频率裁剪

    • 对于一个音频片段,根据每个物种的 fmin 和 fmax 裁剪出 24 个不同的片段。
    • 我相信这与 @cpmpml@hengck23 的做法类似(无需重复卷积计算)。
  • LSoft 标签平滑

    • 我只使用 TP(真正例)和 FP(假正例)的裁剪作为标签。例如,对于 TP 或 FP 中的每一行,24 个标签中只有 1 个是存在的。
    • 基于 BCELoss,我对未知标签使用了 'lsoft'。LSoft 由 @romul0212 友情介绍,代码见 GitHub
    • 这是我使用 LSoft 的损失计算代码。mask 指示标签已知的位置。未知标签的 true 值初始化为 0。
    tmp_true = (1 - lsoft) * true + lsoft * torch.sigmoid(pred)
    true = torch.where(masks == 0, tmp_true, true)
    loss = nn.BCEWithLogitsLoss()(pred, true)
  • 迭代伪标签训练

    • 由于训练集的标注非常稀疏,我认为用模型重新标记然后重新训练会有所帮助,事实证明确实如此。我进行了 3 个阶段的伪标签训练。
    • 在进行伪标签训练时,我没有使用 LSoft,而是使用了普通的 BCE。
  • LSEPLoss

    • 我们的评估指标是 LWLRAP,因此关注每一行标签之间的排名很重要。我使用了符合这一目的的 LSepLoss,该损失由 @ddanevskyi 友情介绍,详情见 讨论区
    • 在第 3 阶段的 BCE 伪标签训练之后,我又使用 LSEPLoss 进行了额外的 2 个阶段伪标签训练。
    • 我稍微修改了原始代码以支持软标签。
    def lsep_loss(input, target):
        input_differences = input.unsqueeze(1) - input.unsqueeze(2)
        target_differences = target.unsqueeze(2) - target.unsqueeze(1)
        target_differences = torch.maximum(torch.tensor(0).to(input.device), target_differences)
        exps = input_differences.exp() * target_differences
        lsep = torch.log(1 + exps.sum(2).sum(1))
        return lsep.mean()
  • 仅在正值上进行全局平均池化

    • 我们需要知道物种是否存在。我们不在乎它出现得是否频繁。我认为对 CNN 最后一层特征图进行全局平均池化会使得一个片段中频繁出现的鸟叫声概率较高,而不频繁出现的概率较低,这与我们的目标不符。因此,我只取了 CNN 最后一层特征图中正值部分的平均值。
    • 以下代码附加在 CNN 提取特征图的末尾:
    mask = (x > 0).float()
    features = (x*mask).sum(dim=(2, 3))/(torch.maximum(mask.sum(dim=(2, 3)), torch.tensor(1e-8).to(mask.device)))