返回列表

5th place solution: Self-Distillation is All You Need

654. BirdCLEF+ 2025 | birdclef-2025

开始: 2025-03-10 结束: 2025-06-05 环境监测 数据算法赛
第 5 名解决方案:自蒸馏就是一切

第 5 名解决方案:自蒸馏就是一切 (Self-Distillation is All You Need)

作者: MYSO

团队成员: Zuoli, youknow

发布时间: 2025-06-06

竞赛排名: 第 5 名

我们要感谢 Kaggle、组织者、我们的队友以及所有参与者。参加这次比赛是一次很棒的经历。以下是我们解决方案的简要概述。

数据

我们仅使用了 2025 年的数据集。
首先,我们使用 Silero VAD 从 train_audio 集中检测包含人声的音频文件。接着,使用 @zuoliao11 开发的 Streamlit 工具,我们手动聆听了这些文件并移除了包含人声的片段。
数据清理示意图

对于代表性不足的类别(n < ~30),我们手动选择了包含鸟鸣的片段。
对于清理后的文件,我们使用前 60 秒;对于其他文件,我们使用前 30 秒。为了平衡数据集,我们复制了样本少于 20 个的类别的文件。

模型

我们使用了一个 声音事件检测 (SED) 模型
骨干网络:
• 4x tf_efficientnetv2_s
• 3x tf_efficientnetv2_b3
• 4x tf_efficient_b3_ns
• 2x tf_efficient_b0_ns

训练

我们分三个阶段训练模型。
训练阶段示意图

输入特征:

随机 10 秒片段
Mel 频谱图:

  sample_rate: 32000 
  mel_bins: 192 
  fmin: 20 
  fmax: 15000 
  window_size: 2048 
  hop_size: 768

我们通过计算 log(melspec+1e-6) 将 Mel 频谱图转换为对数尺度。
数据增强:
重采样 (Resampling)
增益 (Gain)
FilterAugment
频率掩蔽,时间掩蔽 (FrequencyMasking, TimeMasking)
Mel 域上的 Mixup (Sumix on mel domain)

优化器: Adam + 带热身的余弦退火 (Cosine Annealing with warmup)
损失函数: FocalLoss (gamma=2)
训练轮数: 10
目标标签: 主要标签和次要标签

第一阶段:

我们仅使用 train_audio 训练了 5 折模型。

第二阶段 - 仅使用 train_audio 的自蒸馏:

如在数据部分所述,在聆听音频时,我们发现训练数据中存在许多鸟鸣,尽管它们未被标记。这是意料之中的,因为录音师主要关注目标物种,因此其他鸟鸣往往未被标注。
基于这一观察,我们认为比赛的核心挑战是准确分配次要标签。为了解决这个问题,我们使用自蒸馏来丰富 train_audio 中的次要标签。我们使用第一阶段训练的模型预测作为教师标签,并将其与原始标签混合。教师模型的预测可能包含了原始注释中缺失的真实次要标签。
我们重复自蒸馏 4-5 次。从第 2 轮开始,我们以迭代方式使用先前蒸馏的模型作为新教师。每次模型权重都会重新初始化。这种方法与这篇论文中提出的方法非常相似。

第三阶段 - 使用 train_audio + train_soundscapes 的自蒸馏:

我们将 train_soundscapes 的数据添加到训练集中,并继续进行两次自蒸馏。我们在每个批次中以 1:1 的比例混合 train_audio 和 train_soundscapes(不分折)。我们进一步使用不同的随机种子训练了几个模型。

LB 分数 (公共榜) 第 1 ~ 3 阶段(5 个模型集成)

模型 阶段 1 阶段 2 (蒸馏 x2) 蒸馏 x4 蒸馏 x5 阶段 3 (蒸馏 x1) 蒸馏 x2
tf_efficientnetv2_s 0.839 0.863 0.880 0.884 0.915 0.921
tf_efficientnetv2_b3 0.842 N/A 0.872 - N/A 0.918
tf_efficient_b3_ns N/A N/A N/A - N/A 0.921
tf_efficient_b0_ns 0.836 0.871 0.879 0.883 0.905 0.912

*N/A = 未提交到 LB

下图展示了不同模型的自蒸馏结果。
自蒸馏结果图

推理

我们将第 3 阶段的模型分为两组,并在可能的情况下为每组分配不同的随机种子。

模型组 A:

4x tf_efficientnetv2_s (seed= 0, 1, 2, 3)
3x tf_efficientnetv2_b3 (seed= 2, 3, 4)
4x tf_efficient_b3_ns (seed= 0, 1, 2, 3)
2x tf_efficient_b0_ns (seed= 0, 1)

模型组 B:

4x tf_efficientnetv2_s (seed= 1, 2, 3, 4)
3x tf_efficientnetv2_b3 (seed=0, 1, 2)
4x tf_efficient_b3_ns (seed= 0, 1, 2, 3) *失误了,我们最终使用了与组 A 相同的种子。
2x tf_efficient_b0_ns (seed= 2, 3)

后处理/TTA

推理采用 2.5 秒重叠。

分数进行加权组合(类似于去年的第 4 名解决方案)。
Alpha = 0.5
后处理示意图

平滑:

我们使用邻帧平滑,窗口为 [0.1, 0.8, 0.1]。

低排名类别的幂调整:

我们的公共笔记本中分享的后处理方法提高了 LB 分数,但由于过拟合风险,我们最终决定不使用它。

加速:

• OpenVINO
• Concurrent.futures.ThreadPoolExecutor

最终集成 LB 分数

设置 原始分数 (仅组 A) 2.5 秒重叠 平滑 + 重叠
公共榜 0.919 0.928 0.928
私有榜 0.917 0.924 0.924

无效的方法

基于 CNN 的模型。
1D 模型。
过多的数据增强。

同比赛其他方案