返回列表

17th Place Solution - How to Learn and Practice as a Beginner

575. RSNA 2023 Abdominal Trauma Detection | rsna-2023-abdominal-trauma-detection

开始: 2023-07-26 结束: 2023-10-15 医学影像分析 数据算法赛
作者:m1dsolo(物理学转软件工程初学者)
排名:RSNA 2023腹部创伤检测竞赛第17名(银牌)
时间:2023年10月17日

感谢RSNA举办这场有趣的竞赛,也祝贺所有获奖者付出的努力。

我是一名仅仅转专业从物理学到软件工程一年的初学者,我喜欢通过实践来学习,因此选择了Kaggle竞赛平台,这里有许多优秀的学习资源。

我非常高兴能够从对3D图像处理一无所知,到击败基线并最终获得银牌。我希望我的竞赛经验能给你带来一些启发,特别是对于那些和我一样刚开始挣扎着击败基线的初学者。

方法

总结

出于学习目的,我计划在本竞赛中尝试2D分类、3D分类、2D分割、3D分割等多种方法。因此我的流程可能会稍微复杂一些。

阶段1:2D + 3D分割

  • 2D UNet 分割肝脏、脾脏、左肾、右肾和肠道
  • 3D UNet 进一步优化脾脏分割

阶段2:肝脏、脾脏、肾脏:3D分类

  • 从分割结果中裁剪器官并调整大小:肝脏(64, 312, 312)、脾脏(80, 224, 224)、左肾(40, 128, 128)、右肾(40, 128, 128)
  • 使用3D分类器 X3D_l 对肝脏、脾脏和肾脏进行分类(对于肾脏,仅反向传播概率更高的正样本)

阶段3:肠道:2.5D + 1D分类

  • 使用肠道掩码的边界框裁剪肠道(每个切片只选择掩码像素值大于1000的区域)
  • 从裁剪后的肠道中均匀采样64个切片,每个切片调整至(512, 512),每个切片有4个通道(z-1, z, z+1, mask)。因此输入形状为(B, N, 4, 512, 512),其中B是批次大小,N是切片数量
  • 使用 convnext_tiny 作为特征提取器。输入数据(B, N, 4, 512, 512)经过特征提取器后将转换为特征(B, N, 768)。如果 N < 64,将使用零特征进行填充,最终输出特征形状为(B, 64, 768)
  • 使用 lstm + attention pooling concat maxpooling 进行特征融合
  • 使用 nn.Linear 进行分类

阶段4:渗出物:2.5D + 1D分类

  • 均匀采样64个切片,对每个切片使用5crop(左上、右上、左下、右下、中心),然后调整每个裁剪区域至(512, 512),最后堆叠。因此输入形状为(B, N, 5, 3, 512, 512)
  • 使用 convnext_tiny 作为特征提取器。输入数据(B, N, 5, 3, 512, 512)将转换为特征(B, N, 5, 768)。如果 N < 64,将使用零特征进行填充,最终输出特征形状为(B, 64, 5, 768)
  • 使用 attention_pooling concat maxpooling 融合每个切片的5个特征,输出形状为(B, 64, 768)
  • 使用 lstm + attention pooling concat maxpooling 进行特征融合
  • 使用 nn.Linear 进行分类

一些有用的细节

  1. 当我开始处理渗出物分类时,看到了IAN PAN关于渗出物边界框的讨论(感谢!),我认为这对渗出物分类很有帮助。对于正样本,配合使用 albumentations.BBoxSafeRandomCropFixedSize(288, 288),这是一个围绕边界框随机裁剪图像的数据增强函数,能帮助 convnext_tiny 更关注小区域。对于负样本,使用 albumentations.RandomCrop(288, 288) 随机裁剪输入
  2. 我统计了所有正肠道切片,发现它们的 mask.sum() >= 1000(掩码由TotalSegmentator生成)。因此我认为 mask.sum() < 1000 的切片可以被忽略,从而使网络更专注于ROI区域
  3. NISCHAY DHANKHAR的第三名解决方案中学到,使用伪标签数据集进行初始训练(大学习率),最后使用精细标注数据集进行微调。因此训练2D UNet时,我使用TotalSegmentator的预测作为伪标签,然后用206个精细分割数据进行微调
  4. 由于约5%的TotalSegmentator零样本分割存在严重问题,我使用训练好的2D UNet分割结果与其计算Dice系数。如果小于0.75,则重新考虑
  5. 针对Notebook内存不足问题:
    • 根据Shai Ronen的讨论,加载2D DICOM后立即转换为uint8格式,并删除变量 + gc.collect() 有很大帮助
    • 减少 DataLoader.num_workers 可以节省内存,设置 DataLoader.pin_memory=False 可以节省GPU内存

可能有效的方法

  1. 对于只有小面积对比度的任务,maxpooling 可能比 avgpooling 更好
  2. 端到端训练 convnext_tiny + lstm + attention pooling concat maxpooling + nn.Linear(我看到本地CV提升很大,但比赛结束前没有足够时间提交)

可能无效的方法

  1. 使用 uniformer 替代 X3D
  2. 使用 efficientnetv2_s 替代 convnext_tiny

给像我一样的初学者

我知道当你第一次参加不熟悉的竞赛时会有点困难。我将列出一些个人经验,帮助初学者迈出第一步。

加入竞赛之前

加入竞赛前,你必须首先明确竞赛任务类型(3D CT多标签分类),并估算所需的计算资源、存储容量和硬盘空间。这用于判断你是否应该参加这个竞赛,因为当硬盘空间不足以存储处理后的数据时,你可能会感到沮丧。

编码之前

对于不熟悉的任务(3D CT分类),最好的入门方式是阅读已结束的类似竞赛解决方案。巧合的是,RSNA过去几年举办了许多类似的竞赛。我发现RSNA 2022颈椎骨折检测(去年)RSNA STR肺栓塞检测(三年前)与本次竞赛高度相关,它们的任务都是3D CT分类。你应该大量阅读优胜者的解决方案来决定自己的实验方法。我的发现是:2D骨干网络提取特征(或2.5D)+ 1D RNN融合的方式往往表现最佳。

关于编码

阅读顶级解决方案后,你有两条路线来开发自己的流程。第一是复制并修改公开代码,但你必须理解每一行代码。第二是参考公开代码,使用自己的编程习惯或代码段来开发流程。我使用第二种方法,因为它能极大提高我的编码能力。在我过去一年的深度学习学习过程中,我不断积累并编写了一个基于PyTorch的简单多折训练、验证、测试、预测框架。它既能锻炼我的编码技能,又能极大提高编码速度,拥有自己的代码感觉真的很棒。同时,这种代码积累对未来类似任务也很有益。

设计方法

大多数人的方法无法击败基线,可能是因为他们只是简单地将3D数据输入网络进行训练。我一开始也这样做,但结果很差。GUANSHUO XU的第一名解决方案告诉我,裁剪ROI非常重要。也许是因为在3D分类任务中,网络很难从几千个训练数据中就学会ROI。因此我认为分割每个器官是重要的第一步。

由于肠道和渗出物有2D分类标签,我决定对两者都使用2D分类方法,而对肝脏、脾脏和肾脏使用3D分类方法。

通过Selim的第四名解决方案(CSN)IAN PAN的第六名解决方案(X3D),似乎使用 transformer 作为骨干网络在小训练数据量上效果不佳。最终我选择 X3D_l 作为3D分类器。

接下来是为肠道和渗出物分类设计2D + 1D方法。根据QISHEN HA的第一名解决方案Đăng Nguyễn Hồng的第一名解决方案convnext 是2D特征提取器的好选择。根据Guanshuo Xu的第一名解决方案lstm + attention pooling concat maxpooling 模型被选作特征融合。

对于分割,由于我在上一次竞赛 hubmap-hacking-the-human-vasculature 中已经编写过2D分割代码,因此决定早期实验中直接训练2D UNet。后来我发现2D UNet分割脾脏效果不佳(可能是我训练技术不好),于是使用3D UNet,仅输入2D UNet粗分割的边界框裁剪数据来进一步优化脾脏分割(脾脏Dice:0.880 -> 0.943)。

进一步改进

在简要阅读其他获胜队伍的解决方案后,我列出了一些未来可能尝试的技巧。

  1. NISCHAY DHANKHAR的第一名解决方案:辅助分割损失、3D分割、通过器官可见性从序列级标签生成图像级标签
  2. THEO VIEL的第二名解决方案:推断每个切片中存在的器官、大量增强、3D resnet18 裁剪器官、使用 RNN 聚合前一个模型的信息并直接优化竞赛指标
  3. YUJIARIYASU的第三名解决方案:裁剪前放大掩码、将所有器官输入一个模型
  4. LLREDA的第七名解决方案Mask2Former 思想、使用图像级标签辅助特征学习、裁剪方法
  5. IAN PAN的第八名解决方案:使用平方根缩放概率
  6. KAPENON的第九名解决方案:后处理优化any_injury
  7. YU4U的第十名解决方案:堆叠模型优化any_injury、上采样正样本、训练 max(logits, gt) 而非 gt(因为图像级标签噪声)、region_crop() 移除外部黑色区域
同比赛其他方案