返回列表

10th Place Solution

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

开始: 2023-07-26 结束: 2023-10-15 医学影像分析 数据算法赛
第10名解决方案 - RSNA 2023腹部创伤检测

第10名解决方案

团队: yu4u + tattaka

排名: 第10名

比赛: RSNA 2023腹部创伤检测

概述

祝贺所有获奖者和奖牌得主!我很享受这场比赛,因为与去年的RSNA比赛一样,这个任务有多种多样的解决方案选择。我们分享团队的解决方案(yu4u + tattaka)。

我们的解决方案是先对器官进行分割,裁剪出每个器官区域,并为每个器官构建专用模型。对于需要探索大区域的肠道和渗出类别,我们不进行分割裁剪,而是执行简单的黑色区域移除,并将大区域输入模型。各个模型的结果通过堆叠模型进行优化,并作为最终结果提交。

解决方案架构图

分割模型

我们使用了MONAI提供的3D SwinUNETR模型。即使在少量训练数据下,它的表现也出乎意料地好。为了降低计算成本,在分割前将整个体素调整为128x128x128的大小。

器官模型

对于肝脏、脾脏、肾脏和肠道裁剪区域,使用了2.5D CNN + LSTM模型。

肝脏和脾脏模型

裁剪后的区域被调整为16x386x386的大小,并输入到专用模型中。

肾脏模型

左肾和右肾被独立裁剪、调整大小,并沿水平轴连接。这使得我们能够进行水平翻转增强和测试时增强(TTA)。连接后的区域变为16x224x448。

肠道模型

裁剪后的区域被调整为64x224x224的大小。在训练肠道模型时,同时使用了患者级别标签和图像级别标签。

堆叠模型

堆叠模型的目的是直接优化加权对数损失的平均值(这是本次比赛的评估指标),包括任何损伤(any_injury)的对数损失。每个模型针对每种损伤类型的加权对数损失进行优化,但不直接优化any_injury,因为它会自动从其他损伤的概率计算得出。对于any_injury,由于其权重相对较大,优化any_injury至关重要。作为堆叠模型,我们使用了简单的4层MLP,并以比赛指标作为损失函数进行训练。

下表显示了堆叠前后的交叉验证评估结果(由于我们在比赛延长前撰写此解决方案,以下数值已过时。最终提交的CV为0.3686)。

肠道 渗出 肾脏 肝脏 脾脏 任何损伤 总体
无堆叠 0.1186 0.4716 0.2948 0.4282 0.4301 0.5528 0.3827
有堆叠 0.1034 0.4885 0.2861 0.4409 0.4452 0.4777 0.3736

tattaka的部分

我负责肠道和渗出分类。我们的解决方案遵循了3年前RSNA比赛的2阶段方法。

图像级建模(第一阶段)

第一阶段的输入是一个包含相邻帧的3通道图像。在所有标注图像上进行了1个epoch的训练。

  • 骨干网络: resnetrs50
  • 头部: 按肠道和渗出分离头部
    nn.Sequential(
        nn.Conv2d(num_features[-1], 512, kernel_size=1),
        nn.AdaptiveAvgPool2d((1, 1)),
        Flatten(),
        nn.Dropout(0.5, inplace=False),
        nn.Linear(512, 1),
    )

在第一阶段,模型同时学习肠道和渗出分类。

序列级建模(第二阶段)

第二阶段的输入也遵循了之前的解决方案。使用第一阶段头部Flatten后的512维作为图像特征。图像特征以步长3创建而非使用所有图像,输入序列长度按照之前的解决方案设置为最多256。相邻特征之间的差异被组合,模型输入形式为(bs, 256, 1536)。

  • 模型: 将BiGRU输出的注意力池化和最大池化在一层中结合,创建序列级预测。BiGRU输出还应预测图像标签。

与第一阶段不同,肠道和渗出被分别优化。

成功训练的技巧

本次比赛中有几个成功训练的技巧:

  • 由于数据严重不平衡,正样本上采样10倍(高影响)
    • 此外,使用了focal loss
  • 在图像级训练第一阶段后,将logit和gt的最大值作为新图像级的标签再次训练(高影响)
    • 重复了两次
    • 可能图像标签有噪声
  • 在图像输入模型前,基于规则移除外围黑色区域
    • 由于使用更高分辨率时计算时间更长,移除外围区域后使用384x384的大小
def region_crop(img: np.ndarray) -> np.ndarray:
    image_1ch = (img.mean(2) * 255).astype(np.uint8)
    kernel = np.ones((3, 3), np.uint8)
    image_1ch = cv2.erode(image_1ch, kernel, iterations=2)
    mask = image_1ch > 50
    if mask.sum() == 0:
        return img
    rows = np.any(mask, axis=1)
    cols = np.any(mask, axis=0)
    y_min, y_max = np.where(rows)[0][[0, -1]]
    x_min, x_max = np.where(cols)[0][[0, -1]]
    if (y_max - y_min) > 5 and (x_max - x_min) > 5:
        img = img[y_min:y_max, x_min:x_max]
    return img

堆叠前的肠道和渗出分数:

肠道logloss 肠道auc 渗出logloss 渗出auc
阶段1 0.2719 0.9314 0.4602 0.8287
阶段2 0.1167 0.9167 0.4579 0.8264

未生效的方法

  • 标签平滑
  • resnet3dcsn
    • 还不错,但我没有时间调参
  • 缩放logit
  • GeM池化
  • 其他骨干网络
    • ConvNeXt略逊于resnetrs50
    • 我无法使transformer骨干网络正常工作
同比赛其他方案