513. RSNA 2022 Cervical Spine Fracture Detection | rsna-2022-cervical-spine-fracture-detection
感谢 Kaggle 和 RSNA 举办了这样一场精彩的比赛,我们很高兴能获得第二名。在这个复杂的比赛中,我们试图找到最简洁高效的解决方案,并收获了很多知识。这也是我经历过的对硬盘读写要求最高的比赛之一,因为没有足够的空间保存高分辨率的伪标签体素数据,我们在加载数据上浪费了一些时间。
长话短说,我们的解决方案包含两个阶段,并使用了 2.5D CNN,这是我们在 UWM 比赛中向 @Awsaf 学习到的技巧 (UWMGI: 2.5D Train [PyTorch] | Kaggle)。
阶段 1:2.5D CNN + Unet 用于分割
阶段 2:CNN + BiGRU + Attention 用于分类
首先,我们使用了组织者提供的 87 个分割样本。我们按照以下方法重建了掩码标签:
0 ---> 背景
1 ---> C1
2 ---> C2
...
8 ---> T1 - T12
我们使用了更通用的 2.5D 方法,输入为 3 通道的图像数据,即原始图像 i 及其两侧的图像:i-1 和 i+1。

这里的数据增强部分如下,类似于 UWMGI: 2.5D [Train] [PyTorch] | Kaggle,没有太大的改动。
我们也尝试了更重的数据增强,但效果并没有更好。
Resize(CFG.img_size, CFG.img_size, interpolation=cv2.INTER_NEAREST),
HorizontalFlip(p=0.5),
ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.05, rotate_limit=10, p=0.5),
OneOf([
GridDistortion(num_steps=5, distort_limit=0.05, p=1.0),
ElasticTransform(alpha=1, sigma=50, alpha_affine=50, p=1.0)
], p=0.25),
对于分割模型,我们使用了 segmentation_models_pytorch 库,主干网络为 efficientnet-b0,解码器为 unet。
优化器 = "AdamW"
学习率调度器 = "CosineAnnealingLR" + "GradualWarmupSchedulerV3"
一旦我们训练好分割模型,就将其推广到所有的 2019 个样本。我们对输入数据进行了与之前相同的预处理,在模型预测出结果后,我们人工查看了几张预测图像,发现准确率相当不错。
我们分别裁剪了每个样本的所有 7 个颈椎。每个颈椎对应来自 train.csv 的一个骨折标签。根据我们的 EDA(探索性数据分析),大多数样本包含 200-300 张切片,因此每个椎骨的平均切片数约为 30 张。我们选择了 24 张切片,这能满足大多数椎骨的需求。对于超过 24 张切片的颈椎,我们使用了一个简单的 numpy 函数来均匀获取 24 张切片。
sample_index = np.linspace(0, len(one_study_cid)-1, sample_num, dtype=int)
我们面临的挑战之一是本次比赛的训练图像有 300GB,如果我们要在本地保存裁剪后的 3D 高分辨率训练图像,将会超过硬盘的容量。因此,我们被迫选择只记录裁剪的坐标范围 [x0:x1, y0:y1, z0:z