返回列表

10th Solution

654. BirdCLEF+ 2025 | birdclef-2025

开始: 2025-03-10 结束: 2025-06-05 环境监测 数据算法赛
10th Solution - BirdCLEF 2025

第十名解决方案

作者: lhwcv (Grandmaster)

比赛: BirdCLEF 2025

发布时间: 2025-06-06

排名: 第 10 名

感谢组织者举办这次比赛,同时也感谢往年许多 Kaggle 参赛者,他们的解决方案给了我很大的启发。
BirdCLEF 是一项具有挑战性的比赛,虽然数据集分布偏移(dataset shift)不是特别大,但缺乏来自相同分布的验证集使得训练和评估相当困难。
我在比赛期间采用了以下方法:

1. 建立基线模型性能

我使用了整个 train_audio 数据集,并直接在排行榜上进行验证。我发现以下模型架构表现最好:

(SED + CE loss) > (SED + FocalBCE) > (CNN + FocalBCE) > (CNN + CE)

这只是一个初步实验,因此可能受到其他因素的影响,并不具有普遍适用性。但由于在线提交机会有限,我在其余实验中坚持使用了 SED + CE 损失。
在此阶段训练的模型被称为 stage1 模型。

2. 域适应与伪标签数据

正如在以前的比赛中所见,利用未标记数据 (train_soundscapes) 可以带来显著的增益。
我使用了以下方法:

  1. 使用 stage1 模型在 train_soundscapes 上进行预测,生成软标签 (soft labels)
  2. 应用高低阈值 (thresh_low, thresh_high) 提取置信度高的负样本和正样本
  3. 将这些样本(假设相对干净)添加到 train_audio 中训练新模型 —— 即 stage2_models。介于两者之间的模糊样本被排除
  4. 再次使用 stage2_models 在 train_soundscapes 上进行预测以获得更新的软标签
    通过这个迭代过程,我们获得了相对干净的伪标签数据,称为 pp_data_clean。

3. 数据处理

遵循社区讨论,我移除了包含明显人声的样本 —— 这个清洗后的数据集称为 train_audio_clean。
为了进一步提高多样性并使数据更干净,我使用训练好的模型移除了显然不包含目标物种的片段,以 5 秒为间隔采样,形成一个新的数据集:train_audio_clean_v2。
这两个数据集都用于训练。

4. 梅尔频谱图参数

我使用了具有以下分辨率的梅尔频谱图:

  • 384x160
  • 384x256
  • 320x192
  • 320x160

fmin = 0, fmax = 16000, n_fft=1536/2048

5. 损失函数

我采用了一种修改后的混合损失函数与 CE (交叉熵)。
虽然公共 Notebook 显示 ConvNeXt 表现良好,但使用标准 CE 损失会导致很多噪声预测(许多假阳性/误报)。
因此,我逐渐 incorporated 了以下损失以更好地稳定训练:

threshold = -5
neg_mask = (y == 0.0)
negative_logits = logits[neg_mask]
penalty = F.relu(negative_logits - threshold)
sorted_penalty, _ = torch.sort(penalty)
cutoff_index = int(len(sorted_penalty) * 0.95)
selected_penalty = sorted_penalty[:cutoff_index]
mean_penalty = selected_penalty.mean()
loss = ce_loss + 0.1 * mean_penalty

在某些模型中,我还对置信度过低的正样本进行了惩罚。

6. 后处理

  • 使用核平滑:[0.02, 0.08, 0.8, 0.08, 0.02]
  • 以及平均:
def get_mean_scales(ref_freq):
    alpha_max = 0.3
    alpha_min = 0.1
    # 稀有类别更多召回
    alpha = alpha_min + ref_freq * (alpha_max - alpha_min)
    return alpha
...
   for c in len(n_classes):
     a = alpha[c]
     pred_prob[:, c] = pred_prob[:, c] * (1-a) + pred_prob[:, c].mean(keepdims=True) * a

7. 部分模型结果

  • ConvNeXt Tiny (320x192): 公共榜:0.901 私有榜:0.914
  • 3x ConvNeXt Tiny 集成:公共榜:0.908 私有榜:0.921
  • EfficientNetV2-S (384x160) 公共榜:0.904 私有榜:0.906
  • EfficientNetV2-S (384x256) 公共榜:0.896 私有榜:0.914

多样性通过改变所使用的数据集以及混合进的 pp_clean_data 的比例和质量来控制。
我最终总共集成了 10 个模型,公共榜:0.915 私有榜:0.921。
然而,由于排行榜 (LB) 的不稳定性,我未能选择最佳的模型组合。

8. 其他细节

  • 训练使用 10s/15s,推理使用 5s
  • AdamW + CosineAnnealingLR,学习率 (LR):2/3*e-4, 权重衰减 (WD): 1e-3/1e-4
  • Mixup 包含 additive, frequency, 和 time masking
  • 使用和不使用噪声增强
  • 许多其他常见技术,如标签平滑 (label smoothing)、翻转 (flip) 等。
同比赛其他方案