625. RSNA 2024 Lumbar Spine Degenerative Classification | rsna-2024-lumbar-spine-degenerative-classification
感谢组织者举办此次竞赛,感谢我的合作伙伴 Simon Veitner @simonveitner 提供的帮助!
我们的解决方案建立在两阶段流程之上:
代码可在 https://github.com/phalendj/rsna2024 获取。
浏览训练数据时,我们发现有不同的研究(studies),然后分为不同的序列(series),涵盖不同的图像类型:矢状面 T2/STIR、矢状面 T1 和轴位 T2。在某些研究中,单一图像类型有多个序列。在不同的图像类型中,有我称之为“堆栈(Stacks)”的内容,即形成规则体素网格的实例,因此都具有相同的方向和间距。
在单个堆栈内,我们可以通过仿射矩阵(Affine matrix)得出将体素位置映射到世界空间点的矩阵,该矩阵可由 DICOM 元数据中的图像方向和位置数据构建。然后,我们将使用此仿射矩阵将每个堆栈的点从一个像素空间转换到另一个像素空间。为了构建完整的仿射矩阵,我们参考了 nipy.org/nibabel/dicom/dicom_orientation.html。设 $$(Z_x \Delta k, Z_y \Delta k, Z_z \Delta k) = S_1 - S_0$$ 为两个实例的零体素点之差,则仿射矩阵定义为 $P = A n$:
从一个像素空间到另一个像素空间的转换是使用矩阵 $$ A^{\prime -1} A$$ 完成的。
我们发现许多椎骨标注错误,通常偏移了一个位置。我们经过了几次迭代,找出关键点模型与训练数据不匹配的地方,并修正了任何训练数据。
为此,我们专注于矢状面 T2/STIR 图像以寻找椎骨的位置。首先,我们在最大堆栈的所有矢状面 T2/STIR 实例上使用 TD-CNN 找到了投影实例编号:
然后我们输出每张图像是正确图像的概率。
使用相同的矢状面 T2/STIR 图像,我们使用了具有 15 通道输入的 2.5D CNN,并在 segmentation-models-pytorch 包中使用了 timm_efficientnet_b2。然后我们使用了 Angel Jacinto Sanchez Ruiz (@sacuscreed) 在 此 Notebook 中概述的热图损失(Heatmap loss)。
最后,在获取训练数据并将每个标签坐标转换到世界空间后,我们找到了椎间孔位置和关节突下位置的平均偏移量(单位 mm)。我们用它生成了文件 'test_label_coordinates.csv' 用于下一步。
鉴于我们要为诊断模型提取的区域大小,我们发现这足以进入下一级。
找到位置后,我们使用 224x224 图像作为输入进入 TDCNN,同上所述。我们会找到一个层面的中心位置,然后裁剪该位置周围 40-50mm 大小的图像并缩放至输入大小。我们发现不同的研究具有各种各样的像素间距,因此这提供了目标区域的标准大小。然后我们使用加权交叉熵损失(Weighted CrossEntropyLoss)进行训练。我们提交的模型是 densenet121。
对于脊柱(spinal),训练批次的大小为 (B, 5(层面), 11(图像), 224, 224);对于椎间孔狭窄(foraminal narrowing),大小为 (B, 5(层面), 2 (侧), 11(图像), 224, 224);对于关节突下狭窄(subarticular stenosis),大小为 (B, 5(层面), 7(图像), 224, 224)。对于关节突下狭窄,我们发现对右侧图像应用翻转可以得到更好的模型,因为所有内容都处于标准格式。
在所有训练之后,我们确实添加了一个主模型,它具有所有相同的输入,但将单个层面的所有输出连接到一个大型输入中以用于分类头。我们发现单个脊柱层面的不同诊断之间存在很多相关性,但在不同层面之间则没有那么多。