返回列表

8th place Solution

535. RSNA Screening Mammography Breast Cancer Detection | rsna-breast-cancer-detection

开始: 2022-11-28 结束: 2023-02-27 医学影像分析 数据算法赛
第8名解决方案

第8名解决方案

作者: BladeRunner (队友: zephyruszx, calvchen)
比赛排名: 第8名

在一切开始之前,我想感谢 Kaggle 和竞赛组织者创建了这样一个令人钦佩的比赛。

我衷心感谢我的队友 @zephyruszx@calvchen 在整个比赛过程中给予的难以置信的支持。

数据集

我们选择了 Nvidia Dali,它可以使用 GPU 解码 dicom 图像文件,并生成了 uint16 位的 png 文件。我们没有使用更复杂的裁剪算法,而是使用了 cv2.connectedComponentsWithStats,它效果很好且速度快。

图像尺寸:1536*896

交叉验证策略:StratifiedGroupKFold 5折交叉验证

负样本策略:下采样 35%~50% 的负样本

具有 LIGHT 和 HEAVY 不同级别的数据增强策略:

def mixup_augmentation(x:torch.Tensor, yc:torch.Tensor, alpha:float = 1.0):
    """
    执行 Mixup 增强的函数
    """
    assert alpha > 0, "Alpha 必须大于 0"
    assert x.shape[0] > 1, "需要超过 1 个样本才能应用 mixup"

    lam = np.random.beta(alpha, alpha)
    rand_idx = torch.randperm(x.shape[0])
    
    mixed_x = lam * x + (1 - lam) * x[rand_idx, :]
    yc_j, yc_k = yc, yc[rand_idx]

    return mixed_x, yc_j, yc_k, lam

def get_transforms_16bit(data, img_size, normalize_mean, normalize_std):
    if data == 'train':
        return Compose([
            ToFloat(max_value=65535.0),
            RandomResizedCrop(img_size[0], img_size[1], scale=(0.8, 1), ratio=(0.45, 0.55), p=1), 
            HorizontalFlip(p=0.5),
            VerticalFlip(p=0.5),
            ShiftScaleRotate(rotate_limit=(-5, 5), p=0.3),
            RandomBrightnessContrast(brightness_limit=(-0.1,0.1), contrast_limit=(-0.1, 0.1), p=0.5),
            JpegCompression(quality_lower=80, quality_upper=100, p=0.3),
            Affine(p=0.3),
            ToTensorV2(),
            ])
        
    elif data == 'valid':
        return Compose([
            ToFloat(max_value=65535.0),
            Resize(img_size[0], img_size[1]),
            ToTensorV2(),
        ])

伪标签:我们简单地将 Vindr 数据用作外部数据集,并使用了几乎相同的数据处理方法。

模型

由于训练时间的限制,我们选择了主要模型的最小版本进行尝试,最终使用了三个模型的集成。这些模型的参数数量在 15M 到 21M 之间,模型训练参数大致相似,并对参数进行了一些调整。根据我们的实验,这些参数对学习率有巨大且敏感的影响。

  • tf_efficientnetv2_s,学习率: 1e-4
  • convnext_nano, 学习率: 7e-6
  • eca_nfnet_l0,学习率: 3e-5

在 Backbone 之后,我们选择了 GeM Pooling,设置 p_trainable=True,并在 fc 层添加了 dropout

训练

  • 3 阶段训练
    • 1. 使用比赛数据进行训练
    • 2. 使用伪数据进行训练
    • 3. 使用比赛数据进行微调
  • 参数:
    • 优化器:AdamW,weight_decay = 0.01
    • 损失函数:BCEWithLogitsLoss
    • 调度器:OneCycleLR

推理

  • 水平翻转 TTA
  • 二值化后处理

无效或未尝试的方法

  1. 使用 RCNN/Yolo 进行裁剪
  2. 更大的尺寸,例如 2048
  3. Focal Loss
  4. 更多外部数据