349. Understanding Clouds from Satellite Images | understanding_cloud_organization
更新:代码现已发布在 这里。
感谢马克斯·普朗克气象研究所和 Kaggle 主办了如此有趣的比赛。祝贺所有的获奖者。
我解决方案的关键在于训练了两个分割模型:seg1 使用 BCE loss 在所有数据上训练,seg2 仅在非空图像上使用 soft DICE loss 训练。我认为这之所以有效,是因为本次比赛基本上包含两个任务:1) 检测空图像;2) 为非空图像预测准确的掩码。这两个分割模型分别解决了这两个任务。
我以使用 BCE loss 的 resnet34-FPN 开始了这场比赛 (seg1)。该模型在 LB 上达到了约 0.608,主要贡献来自于捕捉空掩码:它捕捉了约 80% 的空掩码。我尝试了很多方法来改进非空部分,比如使用 BCE 和 DICE 的组合 loss,但同时提高 neg-dice(空掩码的 dice 分数)和 pos-dice(非空掩码的 dice 分数)很难。
为了准确预测非空掩码,我决定为非空图像训练 4 个独立的分割模型,然后将它们集成在一起。由于所有训练图像都是非空的,我们可以直接使用 soft DICE loss,模型将专注于预测准确的掩码。我使用了完全相同的网络结构 resnet34-FPN (seg2)。然后我简单地用 'seg2' 的预测替换了 seg1 模型的所有非空预测。仅 1 折的这个 2 阶段分割流程,没有 TTA,没有最小尺寸移除器,没有分类器,没有阈值调整(均为 0.5)就可以达到 LB 0.652。在加入 resnet34 分类器(0.5 阈值)后,我得到了 LB 0.655。
后来,我通过实现 pos-only soft DICE loss,成功在一个模型中训练了所有 4 个类别。代码如下:
def dice_only_pos(logits, labels, labels_fc):
# logits -> 像素级预测
# labels -> 像素级标签
# labels_fc -> 图像/通道级标签
pos_idx = (labels_fc > 0.5)
neg_idx = (labels_fc < 0.5)
loss = SoftDiceLoss()(logits[pos_idx], labels[pos_idx])
return loss
这个 loss 只计算非空通道,忽略所有空通道。
总之,流程如下:
最终提交通过以下步骤实现:
像素级(分割)和图像级(分类器)阈值均为 0.5。
模型摘要:
结果:
TTA1 表示仅原图;TTA3 表示原图 + H/V 翻转。
我剩下的工作只是尝试不同的 backbone 以找到最好的一个。我的最终模型是: