Kaggle 经典比赛 Global Wheat Detection 高分方案解析

75 阅读4分钟

本篇文章为比赛第一名方案解析,该比赛涉及到CV-目标检测-农业方向。

介绍:参赛者将从小麦植物的户外图像中检测小麦穗,包括来自全球各地的小麦数据集,利用世界范围内的数据,以估计小麦穗的数量和大小。

网址:www.kaggle.com/c/global-wh…

重点

  • Custom mosaic data augmentation
    自定义马赛克数据增强
  • MixUp  混合
  • Heavy augmentation  重度增强
  • Data cleaning  数据清洗
  • EfficientDet  高效检测
  • Faster RCNN FPN  更快的 RCNN FPN
  • Ensemble multi-scale model 集成多尺度模型
  • Test time augmentation(HorizontalFlip, VerticalFlip, Rotate90)
    测试时间增强(水平翻转,垂直翻转,旋转 90 度)
  • Pseudo labeling  伪标签

数据处理

  • 自定义马赛克增强

马赛克是一种数据增强方法,将 4 张训练图像合并成一张进行训练(而不是 CutMix 中的 2 张)。不是随机裁剪图像的一部分,我创建了以下自定义马赛克增强,以保留边界信息:

image.png

  • 混合操作

image.png

  •   重度增强:
    随机裁剪,水平翻转,垂直翻转,转为灰度,添加高斯噪声,高斯噪声,运动模糊,中值模糊,模糊,对比度受限自适应直方图均衡化,锐化,浮雕,随机亮度对比度,色调饱和度值

image.png

模型

  • 5 折,分层-k 折,按来源分割(usask_1,arvalis_1,arvalis_2…)
  • 优化器:EfficientDet 使用初始学习率 5e-4 的 Adam,Faster RCNN FPN 使用初始学习率 5e-3 的 SGD
  • LR 调度器:余弦退火
  • 混合精度训练与 nvidia-apex

性能
有效 AP/公共 LB AP

  • EfficientDet-d7 图像大小 768:Fold0 0.709/0.746,Fold1 0.716/0.750,Fold 2 0.707/0.749,Fold3 0.716/0.748,Fold4 0.713/0.740
  • EfficientDet-d7 图像尺寸 1024:Fold1,3
  • EfficientDet-d5 图像尺寸 512:Fold4
  • Faster RCNN FPN-resnet152 图像大小 1024: 第 1 折
  • 集成使用 wbf 的 9 个模型可以达到 0.7629 公共 LB/0.7096 私有 LB(旧测试集)

伪标签

  • 基础:EfficientDet-d6 图像尺寸 640 Fold1 0.716 有效 AP
  • 第一轮:使用 trainset + 隐藏测试集(集成输出)高效 Det-d6 训练 10 个 epoch,从基础检查点加载权重
    结果:[旧测试集] 0.7719 公共 LB/0.7175 私有 LB 和 [新测试集] 0.7633 公共 LB/0.6787 私有 LB
  • Round2: 继续使用 trainset + 隐藏测试集(伪标签轮次 1 的输出)训练 EfficientDet-d6 6 个 epoch,从伪标签轮次 1 的检查点加载权重
    结果:[旧测试集]0.7754 公共 LB/0.7205 私有 LB 和 [新测试集]0.7656 公共 LB/0.6897 私有 LB

源代码

github.com/321Leo123/g…

以上为方案思路,便于大家有一个整体的概念,现在我来讲讲源代码中一些比较重要的内容。

重点代码讲解

一、数据处理

该方案能拿到这么高的分数,其中最重要的原因之一就是在训练时对数据进行了非常细致的清洗,这也是这个方案的精妙之处。

1. ​过滤无效标注(isbox过滤)​
  • 验证集处理valid_df = valid_df.loc[valid_df['isbox']==True]
    这一操作过滤了验证集中 isbox 为 False 的样本,确保验证集仅包含有效标注的边界框数据。
valid_df = valid_df.loc[valid_df['isbox']==True].reset_index(drop=True)
warm_df = pd.concat([train_df, wheat2017_df, spike_df], ignore_index=True).sample(frac=1).reset_index(drop=True)
train_df = pd.concat([train_df, wheat2017_df], ignore_index=True).sample(frac=1).reset_index(drop=True)
2. ​数据合并与采样
  • 组合外部数据:将 wheat2017_df 和 spike_df 合并到训练数据中,例如:
warm_df = pd.concat([train_df, wheat2017_df, spike_df], ignore_index=True)
train_df = pd.concat([train_df, wheat2017_df], ignore_index=True)
  • 随机打乱:通过 sample(frac=1).reset_index(drop=True) 对合并后的数据进行随机打乱,避免顺序偏差。
3. ​潜在的隐含清洗
  • 数据集类(WheatDataset)​

    • 跳过无效图像路径或损坏的图像文件。
    • 过滤空标签(无边界框的样本),尤其是在训练模式(mode='train')下。

通过以上这些步骤可以增加数据集的可用性,去除大量的伪标签。

二、模型融合

这个方案是20年的,所使用的模型也比较老了。原方案所使用的模型是faster_rcnn融合后的模型,对于25年的读者来说,将方案多次融合的模型换成简单的viT就可以得到相近的效果。

三、提分思路

对于这么一个高分的方案,我们想要再进行提分肯定是不容易的。读者可以将模型加入近期大火的MOE模型。我简单的跑了一下代码,在不做过多调参的情况下可以达到接近原方案的分数,相信根据新模型调整后能得到更好的表现,读者根据此思路也可自行进行尝试。