返回列表

1st Place Solution: Multi-Iterative Noisy Student Is All You Need

654. BirdCLEF+ 2025 | birdclef-2025

开始: 2025-03-10 结束: 2025-06-05 环境监测 数据算法赛
1st Place Solution: Multi-Iterative Noisy Student Is All You Need
比赛: BirdCLEF 2025
作者: Nikita Babych (MASTER)
排名: 第 1 名
发布日期: 2025-06-07

第一名解决方案:多迭代噪声学生(Multi-Iterative Noisy Student)就是你所需要的

我知道 Kaggle 选手们都知道乌克兰正在发生的事情,你们来这里是为了查看我的解决方案,但让我分享一点比赛截止日期的缩影,这反映了我们当前的现实:我不得不在避难所里进行最后的提交,因为当时我们有稳定的连接,而乌克兰正遭受另一次毁灭性的袭击,造成许多平民伤亡,其中一些就来自我的社区。
我想感谢乌克兰武装部队、乌克兰安全局、乌克兰国防情报局和乌克兰国家紧急服务局,感谢他们提供安全和保障,使我能够参加这场伟大的比赛,完成这项工作,并帮助科学、技术和商业不停止而是向前发展。

TLDR (太长不看版)

  • SED 模型基于 20 秒的输入片段。
  • 使用多迭代噪声学生(Multi-Iterative Noisy Student)作为自训练方法,通过混合(MixUp)焦点训练数据和伪标签声景。
  • 对伪标签应用幂变换(Power transform)以减少噪声。
  • 伪标签采样器分配的权重等于每个声景中标签最大值的总和。
  • 使用来自 Xeno-Canto 的扩展物种数据,为 Amphibia(两栖纲)和 Insecta(昆虫纲)标签组训练单独的模型。
  • 最终集成来自不同训练迭代阶段的模型。
  • 推理通过平均相邻片段的重叠帧级预测来执行,随后进行平滑和 delta shift 推理。

解决方案概览

Solution Overview Diagram

数据

额外的 Xeno-Canto 数据

  • 目标物种
    • 样本数:5489
    • 每个物种组的样本数:Aves(鸟类)=5480, Amphibia=6, Mammalia=3
    • 每个物种的最大样本数:500
    • 备注:这通常会恶化结果,所以只有一个模型看到了这些数据。
  • 额外物种
    • 样本数:17197
    • 每个物种组的样本数:Insecta=16218 (544 个额外物种), Amphibia=979 (113 个额外物种)
    • 每个物种的最大样本数:200
    • 额外过滤器:持续时间小于 60 秒
    • 备注:这些数据用于训练一个专门的模型,针对 Insecta 和 Amphibia 组。

关于 Insecta 的有趣说明

Insecta 组包含家族级别的标签,如 Cicadidae, Gryllidae 和 Tettigoniidae,而其余的 Insecta 标签是来自 Tettigoniidae 家族的物种。但以下实验表明,家族级别的标签可能与特定物种或至少与栖息在中马格达莱纳河谷(Middle Magdalena Valley)的一窄组物种有关:

  • 将 Tettigoniidae 标签包含在 Tettigoniidae 家族物种的次要标签中会恶化结果。
  • 在针对目标物种的训练中包含 Gryllidae 和 Tettigoniidae 的额外 Xeno-Canto 数据(即家族级别标签)也会恶化结果。
  • 使用来自 Xeno-Canto 的额外 Gryllidae 和 Tettigoniidae 样本,根据每个样本的物种分配独特的新标签,而不是分配家族级别标签,并训练专用模型,结果有所改善。这意味着 Tettigoniidae 和 Gryllidae 目标标签与特定物种相关,这些物种可以与作为其他 Insecta 目标标签存在的这些家族内的其他物种或下载的这些家族的额外物种分开。

数据准备

  • 5 折交叉验证
  • 每折至少包含每个标签的 1 个样本
  • 20 秒音频片段通过 absmax 归一化
  • 所有次要标签 = 1

从一开始,我就想到 Amphibia 和 Insecta 组的存在会使模型倾向于更长的输入持续时间,而不是更短的持续时间,因为这些组的物种的叫声持续时间长且重复性是它们的显著特征。
为了找到最佳持续时间,我用不同的持续时间进行了多次实验,发现 20 秒的片段对我来说效果最好,任何更长的持续时间都没有提高结果,但需要更多的推理时间,所以我继续使用该片段持续时间。
以下是我在训练(仅使用训练数据进行监督)5 个 SED efficientnetb0 模型的集成并成比例调整频谱图跳长时,通过尝试不同持续时间获得的公共分数(关于模型和推理的更多详细信息将在下一节提供):

片段持续时间 公共 LB
5 秒 0.842
10 秒 0.864
15 秒 0.87
20 秒 0.872
30 秒 0.872

模型

架构

在不同的训练阶段,我使用了各种 CNN,并在每个阶段逐渐加入更复杂的模型。所有模型都包括 SED 头(改编自 2021 年第 4 名解决方案),与其他头变体相比,它始终提供显著提升。

  • SED
  • Gem 频率池化
  • 重复 3 个 Mel 频谱图作为输入
  • 1 阶段骨干网络:
    • tf_efficientnet_b0.ns_jft_in1k
    • regnety_008.pycls_in1k
  • 1 次伪标签迭代骨干网络:
    • tf_efficientnet_b0.ns_jft_in1k
    • regnety_008.pycls_in1k
    • tf_efficientnet_b3.ns_jft_in1k
    • regnety_016.tv2_in1k
  • 2-4 次伪标签迭代骨干网络:
    • tf_efficientnet_b3.ns_jft_in1k
    • tf_efficientnet_b4.ns_jft_in1k
    • regnety_016.tv2_in1k
    • eca_nfnet_l0.ra2_in1k
  • Amphibia/Insecta 模型骨干网络:
    • tf_efficientnet_b0.ns_jft_in1k

Mel 频谱图参数

  • 20 秒 -> 图像大小 = (3, 224, 512)
  • MelSpectrogram (sample_rate: 32000, mel_bins: 224, fmin: 0, fmax: 16000, n_fft: 4096, hop_size: 1252, top_db=80.0)
  • 0-1 归一化
关于 Mel 参数调整的想法
  • 因为使用了长输入片段,我必须设置较大的 hop length 值,否则推理时间会太长,我将没有能力准备一个好的集成模型。
  • 重要的是设置较多的 n_mels。我怀疑这是因为某些物种(尤其是来自 Amphibia 和 Insecta 组的物种)的叫声在狭窄的频率范围内,因此向模型展示更多的 mel 频带对于区分物种很重要。

验证

  • 我没有找到好的 CV/LB 相关性,所以考虑到主办方说公共/私有分布非常相似,以及去年解决方案的知识,我仅使用公共 LB 验证想法。
  • 单个模型的 LB 分数在不同种子下变化很大,所以我通常在不同的折上训练相同的设置(2-5 折,取决于剩余时间),并将它们集成起来以获得对 LB 更可靠的响应。

事实证明,主办方对我们绝对诚实(没有任何怀疑),大多数公共结果与私有 LB 相关性很好。

1 阶段 (监督学习)

训练细节

  • Epochs: 15
  • Loss: CrossEntropy
  • LR: 5e-4 - 1e-6 (所有模型相同)
  • Optimizer: AdamW with 1e-4 weight decay
  • Scheduler: CosineAnnealingWarmRestarts,每 5 个 epoch 后重启。应用热重启,我可以比单周期训练更长时间
  • BS: 64
  • 增强:
    • Mixup: p = 0.5, 在通过 absmax 归一化的原始音频上,每个物种的采样权重相等
  • 填充:为了保持不同长度的样本在 mixup 后重叠,左侧填充 0,因此右侧总是有重叠,确保训练样本实际上总是混合在一起
  • 模型:efficientnet0, regnety8。第一阶段的小模型集成与更深模型的集成结果几乎相同

Loss 选择

我注意到 Loss 的选择在讨论中受到了很多关注。所以我进行了一些实验,发现当学习率和 epoch 数量调整得很好时,CE 和 BCE/Focal losses 都能给我类似的结果。然而,CE 给了我稍好的结果,所以我选择了它。
我将更好的结果与 CE 联系起来(我可能是错的),基于以下相互关联的假设:

  • CE 对每个标签的更新幅度取决于正标签(概率 > 0)的分类效果。这意味着如果罕见的正标签 A 获得低概率,那么负过代表标签 B(比其他负标签具有更高概率)会被更强的更新推向零。
  • CE 更好地处理不平衡标签,并避免过拟合过代表类,因为当 Softmax 无法给 A 更高分时(因为过代表标签 B 已经由于之前 numerous 不平衡更新当标签 B 为正时获得了太高的 logits),它会惩罚它们。

此外,我没有将样本标签归一化为总和为 1,动机是更困难的样本(那些有更多正标签的样本)应该对 Loss 有更大的影响。

推理

Inference Flow

我首先展示我的推理流程,以便在进入下一节之前提供更多背景,我在下一节中解释如何使用通过该推理生成的伪标签。我希望我的图表看起来不会太 overloaded。

核心思想是通过平均相邻音频片段的重叠帧级预测,充分利用 SED 头产生的所有帧级预测,而不是仅从中心 5 秒取最大值并丢弃宝贵的预测。

  • 它可以看作是大图像 2D 滑动窗口分割的 1D 模拟,而不是将每个音频片段视为完全独立的样本。
  • 它可以看作是一种测试时增强(TTA),因为每个帧级预测都是在多个片段上平均的,这些片段向模型呈现相同的时间帧,但具有略微不同的周围上下文。
  • 一致地提高了我的 LB 分数(0.002-0.003)。
  • 有助于获得更泛化的预测。

其他推理/后处理技巧

  • 填充信号的左侧和右侧,以确保分割后第一个和最后一个 5 秒片段居中。然后移除与填充相关的帧级预测。
  • 平滑 [0.1, 0.2, 0.4, 0.2, 0.1]。
  • Delta shift TTA (来自 2023 年第 2 名解决方案)。

自训练

在监督学习方法达到瓶颈后,很明显进一步的改进将来自未标记声景的使用。
我使用来自第 1 阶段的最佳 LB 集成模型,通过上述推理流程对未标记数据进行伪标签,并开始尝试将伪标签数据纳入训练的方法。
最初尝试将伪标签数据单独连接到训练批次中并未成功。

MixUps (终于起作用了)

然后我尝试将伪标签原始数据与训练原始数据混合,遵循 2024 年第 2 名解决方案 的方法。起初它没有起作用,因为我将 Beta 分布的参数设置得太低(用于采样混合权重)。但在切换到 0.5 的恒定混合权重(Beta 参数 = inf)后,魔法开始发生,LB 分数开始上升。我怀疑这与混合权重远离 0.5 有时会抑制有意义的信号有关,特别是当混合相对清晰的训练数据与噪声大得多的训练声景时。

随机深度 (Stochastic Depth)

阅读关于 Noisy Student 方法的论文 [1] 时,我发现它与我正在使用的自训练方法有某些相似之处。
所以,我开始实验在提到的论文中对自训练显示积极影响的技术,发现添加随机深度 [3](即应用于整个残差块的 dropout)对我也有效。

  • 应用 drop_path_rate = 0.15(结果证明对我训练的所有模型都是最佳的),我一致地看到 LB 分数的提升,某些模型高达 0.005。
  • 在监督训练期间应用随机深度并没有导致任何改进,这支持了当前的自训练方法是 Noisy Student 自训练的一种形式的想法。

为什么是 Noisy Student?(我的理解)

阅读 [1] 后,我终于明白了为什么 mixup 有效而简单连接无效。由于它与我的方法非常匹配,我认为它是 Noisy Student 自训练的一种形式,并相应地命名了我的解决方案。
简单来说 - 向模型展示相同的输入并要求相同的输出并不会教给学生任何新东西,所以在最好的情况下它会收敛到相同的结果,在最坏的情况下它会累积误差并且 LB 分数下降(这是我经历过的)。但是当我们注入噪声(如 mixup, drop paths 等增强)并要求提供与干净输入相同的输出时,它开始学习更鲁棒的特征而不是累积误差。
我想象了以下场景:我们有一个伪标签样本,其中 A 是真实标签,B 是负标签。教师模型预测 A ≈ 1 且 B ≈ 0,但不完全是零。如果我们反复在这个相同的输入上训练,模型可能会开始学习与 B 相关的不相关特征,仅仅因为它的分数不完全是零。它也可能过拟合一些噪声,因为它认为这与 A 有关。同时,它没有提供教师模型已经看到和学到的任何新东西,所以它不会导致任何改进。
然而,如果我们增强该样本,学生模型必须更努力地理解为什么教师给 A 高分(教师的未增强输入)。结果,通过这种噪声学生训练,我们迫使模型专注于与 A 相关的最一致、最泛化的特征,而不是记忆与 A 和 B 相关的噪声。
此外,Noisy Student 方法涉及在训练中包含标记样本(正如我所做的那样),其信号有助于引导模型走向更好的最优解,特别是在早期 epoch。
与伪标签数据的 MixUps 作为标记样本的伟大增强,提供了具有可能物种软标签的目标域背景。

伪标签准备

  • 伪标签是使用前一阶段的最佳模型集成生成的。
  • 伪标签在自训练之前生成,并存储为 5 秒段的最大标签概率,或者帧级预测按原样存储而不 pooling(每 5 秒段 4 帧)。
  • 帧级预测提供了更多的声景分块(当每 5 秒保存时为 9 个 splits,当保存帧级预测时为 45 个 splits),但更多的 splits 通常不会提供更好的结果

伪标签数据采样

  • 最大标签概率总和较高的声景通常伪标签更准确。这是因为大多数声景 overloaded 各种物种叫声,低总和通常表明模型难以识别和区分这些物种。
  • 使用 WeightedRandomSampler,权重等于每个声景内最大标签概率的总和。这确保了具有更准确伪标签的样本被更频繁地采样。我在论文 [2] 中找到了使用采样器进行伪标签的想法。
    • 从由 WeightedRandomSampler 采样的训练声景中选择一个随机的 20 秒间隔。
    • 对于该间隔,取 4 个段(或 16 帧)中每个标签的最大概率,然后在自训练中使用该软标签。
    • WeightedRandomSampler 稳定了训练并提高了 LB 分数。
    • 这种方法在我减少标签噪声(在多迭代伪标签部分描述)后尤其相关,最终导致许多样本具有低标签总和(求和 206 个标签小于 0.5),这与使用未标记数据相同,因此对这种“几乎”未标记的样本在采样中给予较低权重是有益的。

训练细节:

  • 更多 epochs = 25-35.
  • Drop path rate = 0.15.
  • 随机填充。短于 20 秒的样本随机放置在 20 秒内。
  • 其他训练参数与监督学习相同。

伪标签 mixups 的比例

  • 我在每个批次 (bs=64) 中与伪标签片段混合的标记训练样本的比例非常重要,并显著影响 LB 分数。
  • 为了找到最佳比例,我通过 0.25 逐渐增加它,使用上述自训练设置重新训练 5 个 SED efficientnetb0 折的集成,并检查 LB 以找到最佳比例。
混合样本比例 公共 LB
0 (仅标记训练数据) 0.872
0.25 0.883
0.5 0.887
0.75 0.89
1.0 0.898
  • 结果证明,将每个训练样本与随机伪标签样本混合显示了最佳分数。

多迭代伪标签

2024 年第 2 名解决方案 和关于自训练的论文 [1, 2] 的启发,我尝试再次对未标记声景进行伪标签,使用已经在上一迭代的伪标签上训练过的模型。然而,这种方法并没有立即起作用,我花了一些时间调查原因,直到我找到了正确的伪标签预处理方法,使我能够继续在下一个伪标签迭代上训练模型。

多迭代标签预处理

模型在后续迭代中无法收敛的原因是伪标签变得太嘈杂,掩盖了任何有意义的信号。
这是对我最有效并允许我继续前进的方法:

  • 技巧是对概率应用大于 1 的幂(类似于温度缩放,但应用于概率而不是 logits)。这有效是因为对 logits 应用温度会增加高于 0.5 的概率,这会恶化结果。
  • 通过对概率应用幂,我能够保留重要信号,同时防止放大自信的噪声。

在下图中,您可以看到幂变换是对抗标签噪声的真正力量。变换后,标签变得干净得多,只有最初自信的标签幸存下来,仍然具有明显的值来训练模型。

Power Transform Effect

知道如何训练多迭代噪声学生后,我运行了 4 次迭代,在每个阶段通过验证 LB 上的结果调整伪标签幂,并一致地获得 LB 提升。
这种自训练魔法在第 5 次伪标签迭代时停止工作。我无法实现任何进一步的改进,所以我停止了尝试使新迭代工作的尝试。

迭代 幂值 公共 LB
1 1 0.909
2 1 / 0.65 0.918
3 1 / 0.55 0.927
4 1 / 0.6 0.93

训练细节

  • 除了用 eca_nfnet_l0, efficientnet4 扩展训练集成以及对标签应用幂之外,所有训练细节自第 1 次迭代以来保持不变。

Amphibia 和 Insecta 的单独模型

知道像 Amphibia 和 Insecta 这样的物种组非常代表性不足,并且 Xeno-Canto 为训练中没有出现的这些组的多个物种提供数据,我决定尝试训练一个单独的模型,该模型仅查看来自这些组的样本,具有更高的物种多样性。动机是该模型将学习与这些组相关的更多代表性特征,这将是对仅在训练数据中受限制的样本/物种上训练的模型的巨大补充。

数据细节

  • 物种组:amphibia, insecta
  • 物种总数:700
  • 样本总数:17844
  • 数据来源:train, xeno-canto 样本短于 1 分钟
  • 每个物种的最小样本数:1 (将该值提高到 5 会大幅下降分数)

训练细节

  • Epochs: 40
  • BS: 128 (较低值分数下降)
  • 模型:efficient net 0 ns (更深的模型和集成效果不佳)
  • 其他参数与我解决方案中的其他模型相同

推理细节

  • 对所有物种运行推理
  • 将目标物种的预测插入零矩阵,只有它们的列是非零的,用于与其他模型集成

在找到最佳工作参数后,我实现了 0.002–0.003 的 LB 提升。

最终集成

我发现集成来自不同训练阶段的模型不仅有利于略微提高 LB 分数,而且让我有点信心,我的解决方案不会因为做越来越多的自训练迭代而过拟合。

最终集成由以下 7 个模型 组成,这些模型在特定数据和不同的自训练迭代上训练:

  • 1 个 efficientnetb4 来自第 3 次自训练迭代
  • 1 个 efficientnetb3 来自第 3 次自训练迭代
  • 2 个 regnety016 来自第 4 次自训练迭代
  • 1 个 ecanfnetl0 来自第 3 次自训练迭代 (带有额外的 Xeno-Canto 目标物种数据)
  • 1 个 regnety008 来自第 1 阶段 (监督训练)
  • 1 个 efficientnetb0 (在扩展的 Amphibia/Insecta 物种上进行监督训练)

在我最好的解决方案中,我稍微调整了集成权重,给 efficientnetb3 和 ecanfnetl0 稍高的权重,因为它们作为单个模型表现更好。然而,最佳私有提交,分数为 0.935,是在我给所有模型分配相等权重时实现的。

我相信多阶段模型的集成、多样化的骨干架构以及针对某些物种组的专用模型是我解决方案 withstand shake-up 的关键部分。
结果,我最好的公共 LB 分数在私有 LB 上仅略有下降 从 0.933 到 0.930

推理优化

  • OpenVINO 推理引擎,无量化
  • 测试声景的多进程加载
  • 频谱图生成一次,然后在所有模型中重用

结束语

我道歉我的写出来有点长。我不想跳过任何重要的东西。
我在比赛期间积累的 Google Sheet 超过 320+ 行待检查的想法(其中 95% 最终被标记为红色)。所以我决定不包含 What did not work 块,否则它将显著增加已经很长的写出来的长度。
请随时在评论中问我关于我的解决方案的任何问题。我会尽力回答。

我也想感谢以前 BirdCLEF 迭代的所有参与者,他们分享了他们的想法。
没有你们 brilliant 的想法,我将无法取得那个结果。

特别感谢组织者、hosts 和参与举办 BirdCLEF 的每个人。非常感激你们每年为举办 BirdCLEF 付出如此多的努力,你们始终保持联系,并使每次新的迭代变得特别(这反映在今年的参与者数量上)。

同比赛其他方案