返回列表

9th Place Solution

623. ISIC 2024 - Skin Cancer Detection with 3D-TBP | isic-2024-challenge

开始: 2024-06-27 结束: 2024-09-06 医学影像分析 数据算法赛
第九名解决方案 - ISIC 2024

第九名解决方案

作者: Sinan Calisir (Grandmaster)

发布时间: 2024-09-07

竞赛: ISIC 2024 Challenge

大家好,

我甚至无法解释我现在的心情!?在经历了将近 3.5 年的 Kaggle 竞赛历程后,我终于第一次进入了金牌区,并且是作为个人参赛者做到的。我很高兴我的解决方案在私有榜单(Private LB)上也表现得很稳健。

我要感谢 Kaggle 和组织者创建了这个有趣的挑战,它将有益于世并改善世界各地许多人的生活。也要大声感谢组织者,他们在比赛期间响应非常迅速,这一点非常值得赞赏!

简要总结 (TLDR)

我构建了 2 个(+1 个来自公开)不同的表格数据 pipeline,结合了各种特征、数据和模型组合,并配以来自各种图像模型骨干网络的预测。然后我融合了这些 pipeline 的结果并做出了最终预测。不同 pipeline 的权重通过爬山算法找到。

对于以下每个实验,我都使用了 5 折 StratifiedGroupKfold。对于我添加的每个特征,我首先尝试了 5 种不同的种子组合。如果它们提高了分数,我就提交到榜单。如果在那里也提高了分数,我就保留该特征。

表格数据 Pipelines

我在这里使用术语"pipeline",是因为这三个 pipeline 中的每一个都使用不同的表格模型,如 LGBM、Catboost 或 XGBoost。除了基础特征外,我还使用了来自我的基线 notebook 的以下特征。

  1. Pipeline 1
    这是我的原始脚本,我试图从患者数据中提取尽可能多的上下文特征。我提取了 Z 分数、特征范围、偏度、峰度,以及 feature / max(feature)。我以 0.02 的比例对负样本进行了欠采样。我还添加了 efficient net 预测的平均值作为图像特征(如下所述)。这里我有一个 LGBM 和一个 Catboost。
    这个 pipeline 单独在公开榜单上得到了 18.3,CV 为 17.7。

  2. Pipeline 2
    使用我自己的代码,我在榜单上的排名在 10 到 20 名之间波动,直到 @greysky 的 notebook 发布。很幸运,我们使用相同的 CV 设置。我想试试融合效果如何,所以我在那个 notebook 中添加了一些我的特征,例如:

            .with_columns(
                n_images_per_location = pl.col("isic_id").count().over(["patient_id", "tbp_lv_location_simple"])
            )

    以及我的 swin-transformer 模型的预测作为图像特征。单独来看,这个 pipeline 给出了 17.5 的 CV 和 18.3 的 LB。与 pipeline 1 融合后,我的分数首次显著提升到了 18.6。

  3. Pipeline 3
    为了添加第三个图像模型并使集成更加多样化,我创建了另一个具有不同特征设置的 pipeline。我在之前的特征之上创建了排名和不同的 groupby 特征,并使用了不同的数据子集(0.05 负采样比例)。这个 pipeline 单独给出了 17.5 的 CV 和 18.0 的 LB。

图像模型

我的主要重点是多样性,因此对于每个 pipeline,我选择了不同的骨干网络。

  1. 两个 efficientnet_b0,图像大小 256。LB: 15.5 和 15.8,使用 TTA 后为 16.1
  2. swinv2_tiny_window8_256,图像大小 256。LB: 15.9
  3. convnextv2_tiny.fcmae_ft_in22k_in1k,图像大小 224。LB: 15.8

我用不同的数据、骨干网络和优化器设置做了很多实验。以下设置给我的 CV 和 LB 带来了一致的结果。

我只使用了 5% 的负图像,并将正样本过采样 10 倍。我只训练了 3 个 epoch,因为更多的 epoch 会使结果变差。对于 efficient-net 和 swin transformer 模型,我使用了 constant lr:1e-4,对于 convnext 模型使用了以下调度器。对于优化器,我只使用了 Adam。对于损失函数,我使用了 BCE。

scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=1, gamma=0.1)

对于数据增强,我使用了以下设置,类似于之前比赛的获胜者:

train_transforms = A.Compose([
    A.VerticalFlip(p=0.5),
    A.HorizontalFlip(p=0.5),
    A.RandomBrightnessContrast(brightness_limit=0.2,contrast_limit=0.2, p=0.75),
    A.OneOf([
        A.MotionBlur(blur_limit=5),
        A.MedianBlur(blur_limit=5),
        A.GaussianBlur(blur_limit=5),
        A.GaussNoise(var_limit=(5.0, 30.0)),
    ], p=0.7),
    A.OneOf([
        A.OpticalDistortion(distort_limit=1.0),
        A.GridDistortion(num_steps=5, distort_limit=1.),
        A.ElasticTransform(alpha=3),
    ], p=0.7),
    A.CLAHE(clip_limit=4.0, p=0.7),
    A.HueSaturationValue(hue_shift_limit=10, sat_shift_limit=20, val_shift_limit=10, p=0.5),
    A.ShiftScaleRotate(shift_limit=0.1, scale_limit=0.1, rotate_limit=15, border_mode=0, p=0.85),
    A.CoarseDropout(p=0.7),
    A.Resize(CFG.img_size, CFG.img_size),
    A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
    ToTensorV2()
])
valid_transforms = A.Compose([
    A.Resize(CFG.img_size, CFG.img_size),
    A.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
    ToTensorV2()
])

这里有个有趣的地方,至少对于有视觉背景的人来说,我的图像结果一度卡在 14.8,无论我尝试什么都没用。在检查代码并寻找改进方案时,我意识到 A.Resize 调用位于列表的开头。在着手解决图像部分时,我一开始并没有使用任何增强,只是随着实验append 新的增强。将其移动到归一化之前的末尾,将我的分数提高到了 15.4-15.5 的范围。

最终融合

为了找到最终模型的权重,我使用了爬山算法。感谢 @cdeotte 在此处的实现 链接

模型 权重
pipe3_pred_lgb0.407660
pipe3_pred_xgb0.272537
pipe1_pred_lgb0.152162
pipe1_pred_cat0.142441
pipe_2_pred0.124199
pipe3_pred_cat-0.099000

这个设置的 CV 是 18.2,LB 是 18.7,这是我同时获得的最好 CV 和 LB。

未生效的方法

  • 我想和我们大多数人一样,尝试了很多很多特征
  • 对于图像模型,我尝试使用模型误差最高的困难负样本(hard negatives),但没有成功
  • Focal loss 的表现总是比 BCE 差。很可能是由于我的设置
  • Mixup 是一个不错的多样性补充,但添加到集成中时通常表现不佳
  • 在我的解决方案之上堆叠额外的 ExtraTreeClassifier/LogisticRegression 模型
  • 使用 ** 0.5 或 rank ensemble 缩放预测
  • 修复 tbv_lv_y。数据集中有 5 名患者,他们都来自同一家医院,tbv_lv_y 值为负。我添加了每患者的最小值来修复它。CV 稍好,但 LB 没有改善
  • 用于去毛的 Dullrazor 算法
  • 毛发增强
  • 基于 lesion id 的样本权重
  • 使用数据集 mean&std 而不是 imagenet 初始化从头训练图像模型

这是我的总结。我会尝试在接下来的几天里添加更多内容。

同比赛其他方案