Kaggle竞赛「找盐」冠军:价值5万美元的第一名方案出炉

机器之心报道,机器之心编辑部。

地球上一些储藏了大量石油和天然气的区域,其地表下还有大量的沉积盐。但要准确找出哪些地方有大量沉积盐并非易事。专业的地震成像仍然需要对盐矿体进行专业的人工判断。这导致了非常主观、高度可变的渲染过程。此外,这对石油和天然气开采也造成了潜在的隐患。为了创建最准确的地震成像(seismic image)和 3D 渲染,TGS(世界领先的地理数据公司)希望 Kaggle 的机器学习社区能构建一种可以自动、准确识别一块次表层是不是盐体的算法。这正是我们今天要介绍的 Kaggle 竞赛:TGS 盐体识别挑战赛,挑战者需要开发出能准确分割地表以下沉积盐分布的算法。简言之,这就是一个图像语义分割任务。本文介绍了获得该竞赛第一名的方案。

本项竞赛奖金丰厚,前四名总共可获得 10 万美元的奖励,而第一名将获得 5 万美元。

目前该竞赛的提交日期已经截止,该赛事共有 3291 个队伍参赛。以下是前十名的成绩排行:

Kaggle竞赛「找盐」冠军:价值5万美元的第一名方案出炉

赛题背景

地震数据是通过地震反射(reflection seismology)收集的,这种方法要求能量的受控震源(如压缩气体或地震振动器),以及记录来自地下岩石界面反射的传感器。之后处理记录的数据,创建地球内部的 3D 视图。地震反射类似于 X 光、声波定位仪和回波定位。

地震成像是通过将来自岩石边界的反射成像来生成的。地震成像展示了不同岩石类型之间的边界。理论上,反射的力量与岩石界面两侧的物理特性的差别成正比。地震成像展示了岩石边界,但它们并不能显示岩石的属性,一些岩石容易辨认,一些则很难。

世界上一些地区地下存在大量的盐。地震成像的一大挑战就是识别哪些地表下面有盐。盐很容易识别,也很难识别。盐的密度通常是 2.14 g/cc,比周围的岩石密度低。盐的地震波速是 4.5 km/sec,通常比周围的岩石速度快。这种区别就使得在盐岩-沉积层界面处反射的变化比较大。通常盐是非晶质岩石,没有太多内部结构。这意味着盐内部通常不会有太多反射,除非其中有沉积物。这种情况下盐的地震波速较高,使得地震成像出现问题。

数据

使用的数据是在次表层底部多个地点选取的一系列图片。图像的分辨率为 101 x 101,每个像素被分类为盐或沉积物。除了地震成像之外,还为每个图像提供成像位置的深度。比赛的目标是分割含盐区域。

Kaggle竞赛「找盐」冠军:价值5万美元的第一名方案出炉

训练数据集示例

评估

比赛根据 IoU 阈值上不同交叉点的平均精度来计算比分。提交的目标像素预测值和真实目标像素之间的 IoU 分数计算方式如下:

Kaggle竞赛「找盐」冠军:价值5万美元的第一名方案出炉

将一系列 IoU 阈值代入该公式,在每个点计算一个平均精度值。阈值的范围在 0.5 到 0.95 之间,步长为 0.05:(0.5, 0.55, 0.6, 0.65, 0.7, 0.75, 0.8, 0.85, 0.9, 0.95)。换句话说,在阈值为 0.5 时,如果预测目标与真实目标的交集大于 0.5,则该预测对象被视为「命中」。

在每个阈值 t 处,基于预测目标与所有真实目标对比所产生的真正类(TP)、假负类(FN)和假正类(FP)的数量来计算精度值:

Kaggle竞赛「找盐」冠军:价值5万美元的第一名方案出炉

当单个预测目标与真实目标匹配并且 IoU 高于阈值时,记为真正类。假正类表示预测目标没有与之关联的真实对象,假负类表示真实目标没有与之关联的预测目标。然后,将上述每个 IoU 阈值上精度值的平均值作为单个图像的平均精度值:

Kaggle竞赛「找盐」冠军:价值5万美元的第一名方案出炉

最后,竞赛的评估度量返回的分数是测试数据集中每个图像平均精度的平均值。

第一名方案

首先,我要祝贺并感谢我的队友 phalanx,他为此付出了很大的努力!这是我在图像分割领域处理的第一个问题,三个月前我对分割还一无所知。所以,这项第一是对我们所获知识和经验的巨大奖励。我想,这对新手来说也是一个很好的示例:只要你肯努力,即使没什么背景知识也能获得不错的成绩。

局部验证

我们创建了 5 个按深度分层的常见 fold。局部验证的分数与 LB 有很强的相关性。

第一阶段训练

我们每个人都基于训练数据开发了一个模型:

我的模型

  • 输入:101→resize to 192→pad to 224
  • 编码器:在 ImageNet 上预训练的 ResNeXt50
  • 解码器:conv3x3+BN,上采样,scSE

训练概览:

优化器:RMSprop,批大小:24

  1. 损失:BCE+Dice。从 0.0001 开始降低高原上的 LR
  2. 损失:Lovasz。从 0.0005 开始降低高原上的 LR
  3. 损失:Lovasz。4 个带有余弦退火 LR 的 snapshot,每个 snapshot 需要 80 个 epoch,LR 从 0.0001 开始

phalanx 的模型

编码器为 ResNet34(架构与下面描述的 resnet_34_pad_128 相似)

输入:101→ resize to 202→pad to 256

  • 5-fold ResNeXt50 有 0.864Public LB(0.878 Private LB)
  • 5-fold ResNet34 有 0.863Public LB(0.880 Private)
  • 它们的整合分数为 0.867Public LB(0.885 Private)

第二阶段训练

基于第一阶段得到的整合分数,我们创造了一套置信假标签。置信度为置信像素预测的百分比(probability < 0.2 or probability> 0.8)

我们有两个模型:

  1. 我的 ResNeXt50 在置信假标签上进行预训练;在它们上面训练了 5folds。0.871(0.890 Private)
  2. phalanx 在每个 fold 中添加了 1580 个假标签,并从头开始训练模型。0.861(0.883 Private)
  3. 它们的整合得分为 0.870(0.891 Private)

第三阶段训练

从第二阶段得到所有的假标签,phalanx 训练了 2 个模型:

resnet_34_pad_128

  • 输入:101 -> pad to 128
  • 编码器:ResNet34 + scSE (conv7x7 -> conv3x3,移除第一个最大池化)
  • 中心模块:特征金字塔注意力模块 (移除 7x7)
  • 解码器: conv3x3,转置卷积,scSE + hyper columns
  • 损失:Lovasz

resnet_34_resize_128

  • 输入: 101 -> resize to 128
  • 编码器:ResNet34 + scSE(移除第一个最大池化)
  • 中心模块:conv3x3, 全局卷积网络
  • 解码器:全局注意力上采样(实施 like senet -> like scSE, conv3x3 -> GCN) + 深度监督
  • 损失: 用于分类的 BCE 以及用于分割的 Lovasz

训练概览

优化器:SGD,批大小:32

  1. 在假标签上进行预训练。3 个带有余弦退火 LR 的 snapshot,每个 snapshot 有 50 个 epoch,LR 0.01 → 0.001
  2. 在训练数据上进行微调。5 folds、4 个带有余弦退火 LR 的 snapshot,每个 snapshot 有 50 个 epoch,LR 0.01 → 0.001
  • resnet_34_pad_128 had 0.874 (0.895 Private)
  • resnet_34_resize_128 had 0.872 (0.892 Private)

最终模型

最终模型是 ResNeXt50(来自第二阶段)和 resnet_34_pad_128(来自第三阶段)与水平翻转 TTA: 0.876Public LB(0.896 Private LB)的混合。

数据增强

我们用了非常相似的数据增强列表。我的数据增强基于强大的 albumentations 库:

  • 水平翻转(p=0.5)
  • 随机亮度(p=0.2,limit=0.2)
  • 随机对比(p=0.1,limit=0.2)
  • 平移 缩放 旋转(shift_limit=0.1625, scale_limit=0.6, rotate_limit=0, p=0.7)

后处理

我们开发了基于拼图镶嵌的后处理。理念如下:

  1. 在训练数据中找到所有的垂直或半垂直(图像的下半部分是垂直的)图像;
  2. 镶嵌中上述图像下方的所有测试图像都得到相同的掩码;
  3. 它们上方只有一个测试图像获得相同的掩码,并且只有当其镶嵌深度> = 3 时。

GPU 资源

  • 我只有一个 1080 的 GPU。
  • phalanx 有一个 1080Ti,在上周的比赛中又拿到一个。

框架

  • 我用的是 Keras。非常感谢 qubvel 在 Keras 中关于分割 zoo 的绝佳 repo。
  • phalanx 用的是 PyTorch。

相关推荐