338. APTOS 2019 Blindness Detection | aptos2019-blindness-detection
我参加这次比赛的目的是为了确保获得一枚单人金牌,这是获得 Grand Master 徽章所必需的。独自解决 Kaggle 挑战很难,我感谢所有撰写赛后解决方案的人。了解其他人的方法并意识到我们都得出了或多或少相似的解决方案,这很酷。这是我对这次比赛的5点贡献:
代码可在此处获取:https://github.com/BloodAxe/Kaggle-2019-Blindness-Detection
太长不看版 (TLDR)
我尝试了不同的预处理方法,包括 Ben 的方法以及一些基于 Clahe、丢弃红色通道和球形图像去变形的内部方法。所有这些方法都无法胜过直接使用原始图像。我对此的解释是,我们在这里使用的模型(在参数数量上)要复杂得多,并且具有更大的容量和泛化能力,因此预处理的影响微乎其微。
因此,我的预处理流程非常简单:
我有一种印象,即简单的平均池化不足以检测像“所有4个象限都有出血”这样的疾病案例。所以我尝试了更高级的头部设计:
大多数头部的表现等同于或差于全局平均池化(GAP),因此我在最终的模型集成中使用了 GAP。
开始时作为分类问题,然后切换到经典的回归问题,最后以类似有序回归的问题结束。与一些作者建议使用编码目标向量不同,我的方法有点不同——我的最终线性层预测了一个包含4个元素的张量,经过 sigmoid 激活后进行求和。通过这样构想问题,我能够使用 MSE 损失,并且仍然将预测限制在 [0;4] 范围内。对我来说,这种问题构想效果最好。
为了增加批量大小,我使用 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