返回列表

7th place solution w/ code [Catalyst, Albumentations]

338. APTOS 2019 Blindness Detection | aptos2019-blindness-detection

开始: 2019-06-28 结束: 2019-09-07 医学影像分析 数据算法赛
第7名解决方案及代码 [Catalyst, Albumentations]

第7名解决方案及代码 [Catalyst, Albumentations]

作者: Eugene Khvedchenya
原文发布时间: 2019-09-08

我参加这次比赛的目的是为了确保获得一枚单人金牌,这是获得 Grand Master 徽章所必需的。独自解决 Kaggle 挑战很难,我感谢所有撰写赛后解决方案的人。了解其他人的方法并意识到我们都得出了或多或少相似的解决方案,这很酷。这是我对这次比赛的5点贡献:

代码可在此处获取:https://github.com/BloodAxe/Kaggle-2019-Blindness-Detection

太长不看版 (TLDR)

  1. 模型:SeResNext50, SeResNext101, InceptionV4
  2. 在2015年的数据上预训练模型,在本次比赛的数据和 Idrid(测试集)上进行验证
  3. 在本次比赛的数据、Idrid(训练集)和 Messidor 上进行训练
  4. 对测试数据集、Messidor 2、之前的比赛数据进行伪标记
  5. 微调模型
  6. 使用水平翻转 TTA 进行预测

预处理

我尝试了不同的预处理方法,包括 Ben 的方法以及一些基于 Clahe、丢弃红色通道和球形图像去变形的内部方法。所有这些方法都无法胜过直接使用原始图像。我对此的解释是,我们在这里使用的模型(在参数数量上)要复杂得多,并且具有更大的容量和泛化能力,因此预处理的影响微乎其微。

因此,我的预处理流程非常简单:

  • 裁剪图像以去除眼睛边界外的黑色区域
  • 如果需要,将图像填充为正方形尺寸
  • 调整为 512x512 像素(所有模型都在此分辨率下训练)

模型

我有一种印象,即简单的平均池化不足以检测像“所有4个象限都有出血”这样的疾病案例。所以我尝试了更高级的头部设计:

  • 全局加权平均池化
  • 平均池化和最大池化的连接
  • Coord-Conv + FPN 以及来自每个 FPN 层的最大池化
  • Coord-Conv + LSTM 池化

大多数头部的表现等同于或差于全局平均池化(GAP),因此我在最终的模型集成中使用了 GAP。

任务构想

开始时作为分类问题,然后切换到经典的回归问题,最后以类似有序回归的问题结束。与一些作者建议使用编码目标向量不同,我的方法有点不同——我的最终线性层预测了一个包含4个元素的张量,经过 sigmoid 激活后进行求和。通过这样构想问题,我能够使用 MSE 损失,并且仍然将预测限制在 [0;4] 范围内。对我来说,这种问题构想效果最好。

损失函数

  • 对于分类,我尝试了 soft-CE(标签平滑)(比普通 CE 更好),focal + kappa(比 soft-CE 更好)。
  • 对于回归,我从 MSE 开始,然后切换到 WingLoss。
  • 对于有序回归,我使用了 Huber 损失(又名平滑 L1 损失),但最后使用了 Cauchy 损失。

训练

为了增加批量大小,我使用 Apex 和 3x1080Ti 进行了 fp16 的混合精度训练。

为了防止模型过拟合,我的增强管道相当繁重。感谢 Albumentations 包,在我的训练循环中组合和使用它们变得非常容易:

    return A.Compose([
        A.OneOf([
            A.ShiftScaleRotate(shift_limit=0.05, scale_limit=0.1,
                               rotate_limit=15,
                               border_mode=cv2.BORDER_CONSTANT, value=0),
            A.OpticalDistortion(distort_limit=0.11, shift_limit=0.15,
                                border_mode=cv2.BORDER_CONSTANT,
                                value=0),
            A.NoOp()
        ]),
        ZeroTopAndBottom(p=0.3),
        A.RandomSizedCrop(min_max_height=(int(image_size[0] * 0.75), image_size[0]),
                          height=image_size[0],
                          width=image_size[1], p=0.3),
        A.OneOf([
            A.RandomBrightnessContrast