596. SenNet + HOA - Hacking the Human Vasculature in 3D | blood-vessel-segmentation
首先,我要向组织者和官方Kaggle团队为策划这场出色的比赛表示感谢。我在比赛后期才加入。尽管有一些分割比赛的经验,但我必须感谢@hengck23、@yoyobar和@junkoda(指标实现),以及其他社区参与者,感谢他们的开源贡献和讨论,这让我能快速跟上比赛的节奏。
我的方法非常简单,完全依赖2D模型,在整个训练和推理流程中仅使用了smp(segmentation models pytorch)和timm(pytorch image models)。
由于一半的训练集具有密集标签(kidney 1,kidney 3 dense),另一半是稀疏的,利用密集标签来优化稀疏标签是关键步骤。整体流程如下:
注:由于组织者公开了kidney 3和kidney 2中注释的比例,我在选择伪标签的阈值时,尽量基于像素数量选择与官方比例尽可能接近的阈值。
我决定参加这场比赛的一个关键原因是主办方公开了训练集和测试集的放大倍数。训练集的放大倍数是50um/voxel,公开测试集同样是50um/voxel,而私有测试集是63um/voxel。更大的放大倍数意味着更低的分辨率。例如,一个600um的对象在训练集和公开测试集中会占据12个像素,但在验证集中只有10个像素。因此,在训练过程中,我将缩放中心设为0.8,而不是1,缩放范围设为0.55到1.05,以模拟私有测试集。
A.ShiftScaleRotate(shift_limit=0.3,
scale_limit=(-0.45, 0.05),
rotate_limit=45,
# value=0,
border_mode=4,
p=0.95),
在这场比赛中,分别沿x轴、y轴和z轴进行训练和推理是一个非常关键的trick。然而,这带来了显著的风险。整个测试集包含1500个切片,其中公开测试集占67%,私有测试集占33%。这意味着私有测试集仅包含约500个切片。沿z轴使用更高分辨率(例如1024)进行推理是可行的。但如果沿y轴或x轴推理,则意味着其中一条边只有500像素长。此时,如果模型和代码配置为更大的分辨率(比如1024),将存在巨大的分数下降风险。
我的模型主要运行在512的分辨率下,其中一个模型在切片具有适当分辨率时,会切换到大分辨率切片的更高分辨率权重。
| 模型 | 骨干网络 | 分辨率 | Public | Private |
|---|---|---|---|---|
| UNet | MaxViT-Large 512 | 512 | 0.846 | 0.727(提交1) |
| UNet | SeResNext | 512 | 0.819 | 0.753 |
| UNet | Efficiennet_v2_s | 448, 832 | 0.799 | 0.703 |
| UNet++ | Efficiennet_v2_l | 512 | 0.817 | 0.692 |
| ensemble | - | - | 0.846 | 0.727(提交2) |
在比赛初期,无论是在kidney 2还是kidney 3上进行验证,我观察到如果训练20个epoch,在最初的几个epoch之后,验证集上的dice系数(非surface dice)变化非常小,其中MaxVit512 large模型的波动最小。考虑到我们只有三个肾脏,鉴于收敛的稳定性,我在完成伪标签过程后,决定直接在所有肾脏上训练。
我感谢@junkoda提供的指标计算方法。我最稳定的单模型能够在0.2的阈值范围内保持surface dice分数的极小波动(小于1)。在模型融合后,稳定的阈值范围可能在0.3~0.4之间。在分割比赛中,稳定的阈值极其关键。在这场比赛中,由于我的最终模型没有验证集,我不得不使用早期包含验证集的训练模型搜索到的阈值,并将其应用于最终版本。幸运的是,在完整数据集上训练的模型似乎拥有与早期在k1+k2(sparse)上训练、在k3上验证的模型非常接近的阈值。同时,阈值在kidney 3 dense、公开测试集和私有测试集之间的波动非常小。
正如@hengck23提到的,不同肾脏在强度上存在很大差异。因此我使用了大量的强度增强。
A.RandomBrightnessContrast(p=1.0),
A.RandomGamma(p=0.8),
| 模型 | 骨干网络 | 使用的关键点 | Public | Private |
|---|---|---|---|---|
| UNet | MaxViT-Large 512 | 3, 5, 6 | 0.818 | 0.586 |
| UNet | MaxViT-Large 512 | 3, 4, 5, 6 | 0.857 | 0.633 |
| UNet | MaxViT-Large 512 | 2, 3, 4, 5, 6 | 0.849 | 0.652 |
| UNet | MaxViT-Large 512 | 1, 2, 3, 4, 5, 6 | 0.846 | 0.727 |
我的最终提交是一个MaxViT单模型和一个包含四个模型的集成。令人惊讶的是,两个提交在私有排行榜上的得分都是0.727。我没有使用任何形式的加权,MaxViT只占集成提交的四分之一,但它们在私有排行榜上的得分完全相同。更令人惊讶的是,SeResNext在私有排行榜上的单模型得分反而是最高的。它的交叉验证表现并不出色,收敛性也不如MaxViT稳定,公开排行榜得分也不高,所以我没有理由选择它。
最后,我要再次向组织者、Kaggle以及所有参与者表示感谢!