返回列表

3rd Place Solution

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

开始: 2024-06-27 结束: 2024-09-06 医学影像分析 数据算法赛
第三名解决方案 - ISIC 2024
作者: KS (kyohei1)
发布日期: 2024-09-08
竞赛排名: 第 3 名

第三名解决方案

我很激动能在这次竞赛中获得第 3 名,我想感谢 Kaggle 和组织者让这次奇妙的经历成为可能。同时也祝贺所有其他获奖者!

特别感谢 @greysky@murashow@merfarukelik@richolson 在整个竞赛期间的工作和分享。

解决方案概述

我的解决方案与许多其他优秀的公开 Notebook 一致,将 GBDT 表格模型与图像模型的输出作为特征相结合。我的大部分工作集中在开发各种图像模型以提高 GBDT 的分数。正如许多 Kaggle 选手指出的那样,这次竞赛的关键因素是可信的交叉验证(Trust-CV),我专注于创建可靠的 CV 并最大化 CV 分数。(我的最终 CV 为 0.183099)

解决方案架构图

图像模型

我的最终解决方案使用了 4 个图像模型:

正样本:"target" = 1

  • convnextv2_nano.fcmae_ft_in22k_in1k (CV 0.1599389)
  • vit_tiny_patch16_224.augreg_in21k_ft_in1k (CV 0.1612504)

正样本:target=1 + iddx_1=Indeterminate + iddx_2!=nan

  • vit_tiny_patch16_224.augreg_in21k_ft_in1k (CV 0.1460650)
  • vit_small_patch16_224.augreg_in21k_ft_in1k (CV 0.1486832)

上述最后 2 个模型旨在提供保守的预测,以便 GBDT 模型拥有更多样化的特征。
总体而言,正如许多人提到的,较小的模型在我的案例中表现也更好。

训练技巧

  • 调度器 (scheduler): 带热身的余弦退火 (CosineAnnealing with warmup)
  • 批大小 (batch_size): 32
  • 学习率 (learning rate): 1e-4
  • 优化器 (optimizer): AdamW
  • 权重衰减 (weight decay): 权重参数为 0.001
  • 正样本:负样本 = 1:1
  • 分类头 (Classification head): fc(64 或 32) + relu + dropout
  • 每个 epoch 更改负样本
  • 数据增强基于上一届竞赛的第 1 名解决方案:SIIM-ISIC 黑色素瘤分类第 1 名解决方案
  • 确保每个批次中的正/负比例相同(示例代码如下)
class ISICDataset(Dataset):
    def __init__(self, hdf5_file, isic_ids, targets=None, transform=None, ratio_int=2):
        self.hdf5_file = hdf5_file
        self.isic_ids = isic_ids
        self.targets = targets
        self.transform = transform
        self.ratio_int = ratio_int  # 如果 ratio_int=2 则 正:负 = 1:2
        self.positive_list = [ii for ii, tt in zip(self.isic_ids, self.targets) if tt == 1]
        random.shuffle(self.positive_list)
        self.negative_list = [ii for ii, tt in zip(self.isic_ids, self.targets) if tt == 0]
        random.shuffle(self.negative_list)
        self.balanced_list = self.create_balanced_list()

    def create_balanced_list(self):
        balanced_list = []
        pos_count = 0
        neg_count = 0
        # 根据指定比例依次重复和排列正列表和负列表。
        while pos_count < len(self.positive_list) or neg_count < len(self.negative_list):
            if pos_count < len(self.positive_list):
                balanced_list.append(self.positive_list[pos_count])
                pos_count += 1

            for _ in range(self.ratio_int):
                if neg_count < len(self.negative_list):
                    balanced_list.append(self.negative_list[neg_count])
                    neg_count += 1
        return balanced_list

    def __getitem__(self, idx):
        isic_id = self.balanced_list[idx]

交叉验证策略

按 patient_id 进行 GroupStratified 5 折交叉验证,并检查患者数量和正标签在各折之间是否均匀分布。图像模型和表格模型使用相同的折数分割。

表格模型

我的表格模型几乎与以下优秀的 Notebook 相同。我的最终解决方案使用了 LGBM(无图像) + LGBM(有图像) + Catboost(有图像) + XGB(有图像)。

未生效的尝试

预测目标与 GBDT 预测之间差异的图像模型

在整个竞赛过程中,我一直在思考如何最好地将 GBDT 模型与图像模型结合起来,旨在通过覆盖对方挣扎的领域来互补彼此的弱点。我尝试训练图像模型,目标为 ("target" - "GBDT prediction"),但该模型对最终集成的 GBDT 模型没有贡献。

特征工程 - 合并左侧和右侧

在我看来,身体左侧和右侧发生恶性肿瘤的概率不同似乎不合逻辑。因此,我通过将“左臂 - 下部”和“右臂 - 下部”等类别合并为单个“臂 - 下部”特征来创建新特征,但这并没有导致分数提高。

其他

  • 分层学习率衰减 (Layerwise learning rate decay) 破坏了训练。
  • 像 Eva02、Swin 和 EfficientNet 这样的模型并没有显著更好。
  • GBDT 模型的堆叠 (Stacking)。
  • 更多的图像模型 (>4 个)。

最后,我的工作建立在许多 Kaggle 选手的贡献之上。再次我想向所有慷慨分享知识和技术的 Kaggle 选手表示感谢。这是一次很棒的学习经历,我很兴奋能在这个奇妙的社区中继续成长。

代码

我的代码可在 此处 获取。

同比赛其他方案