返回列表

10th Place Solution

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

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

第 10 名解决方案

作者: tomo20180402 (Grandmaster)
发布时间: 2024-09-09
竞赛排名: 10

感谢组织本次竞赛的人们!
代码:https://github.com/tomo20180402/isic2024_skin-cancer-detection-with-3d-tbp_10th-place-solution

概述

Solution Overview Diagram
  • CV=0.183, Public LB=0.181, Private LB=0.171
  • 两阶段模型
    • 第一阶段:CNN (EfficientNet-B0),仅使用图像作为输入
    • 第二阶段:GBDT (LightGBM, XGBoost, CatBoost),使用第一阶段的预测值和表格数据作为输入
  • 解决方案的核心是提高模型泛化能力的策略。

提高模型泛化能力的策略

基本上,相信交叉验证(CV)。
即使 CV 略微变差,如果我认为该技术能提高泛化性能,我也会应用它。

  1. 重复欠采样 (Repeat undersampling)
    • 将负样本划分为多个数据集进行训练
      • 在第一阶段,划分为 20 个数据集,每个 epoch 切换 (n_epoch=20)
      • 在第二阶段,划分为 10 个数据集,为每个数据集构建模型
    • 使用多个验证集
      • StratifiedGroupKFold (group=patient, k=5) × 5 个分割种子 (split seeds)
  2. 避免早停 (Avoid early stopping)
    • 使用多个验证集调查超参数(如 epoch 数量)并将其固定
    • 防止在特定折叠上偶然获得好的 CV(防止对 CV 过拟合)
  3. 处理未知类别 (Deal with unknown categories)
    • 在第二阶段,将缺少属性 (missing attributions) 的数据添加到训练数据中
    • 在推理期间将未知类别视为缺失
  4. 增加模型多样性 (Add diversity to models)
    • 在第一阶段使用 2 种不同的增强模式
    • 在第二阶段使用 3 种类型的 GBDT (LightGBM, XGBoost, CatBoost)
    • 关注的特征因模型而异
  5. 简单平均集成 (Simple average ensemble)
    • 平均而不加权特定模型
  6. 防止拟合病例多的患者 (Prevent fitting to patients with many cases)
    • 每位患者最多训练 50 个负样本
    • 将此 50% 包含在集成中作为第二次提交,但除了 Public LB 外其他指标都变差了
      • cv=0.182, public LB=0.182, private LB=0.170

第一阶段

  • 模型
    • EfficientNet-B0
  • 数据增强 (Augmentation)
  • 模型总数
    • 2 种增强 × 5 个分割种子 × 5 折 = 50
# 模式 1
train_transform = A.Compose([
    A.Transpose(p=0.5),
    A.VerticalFlip(p=0.5),
    A.HorizontalFlip(p=0.5),
    A.RandomBrightness(limit=0.2, p=0.75),
    A.RandomContrast(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.Resize(128, 128),
    A.Cutout(max_h_size=int(128 * 0.375), max_w_size=int(128 * 0.375), num_holes=1, p=0.7),    
    A.Normalize()
])
valid_transform = A.Compose([
    A.Resize(128, 128),
    A.Normalize()
])

# 模式 2
train_transform = transforms.Compose([
    transforms.Resize((144, 144)),
    transforms.RandomResizedCrop(128, scale=(0.8, 1.2), ratio=(0.75, 1.3333)),
    transforms.RandomHorizontalFlip(p=0.5),
    transforms.RandomVerticalFlip(p=0.5),
    RandomApply(transforms.RandomRotation(45), p=0.5),
    RandomApply(transforms.ColorJitter(brightness=0.5, contrast=0.5, saturation=0, hue=0), p=0.5),
    RandomApply(transforms.GaussianBlur(kernel_size=3), p=0.3),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])
valid_transform = transforms.Compose([
    transforms.Resize((128, 128)),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])

第二阶段

  • 模型
    • LightGBM, XGBoost, CatBoost
  • 特征 (Feature)
    • 模式 1
      • 第一阶段预测值
        • 在实际推理期间,取每个模式的第一阶段预测值的平均值作为第二阶段的输入
      • 来自公开 Notebook 的特征:ISIC 2024 | Only Tabular Data
      • 患者 × 其他类别的标准化和基于计数的特征
        • 其他类别:['tbp_tile_type', 'tbp_lv_location', 'tbp_lv_location_simple', 'attribution']
      • 移除:['tbp_lv_norm_color', 'tbp_lv_symm_2axis', 'tbp_lv_symm_2axis_angle', 'tbp_lv_nevi_confidence', 'sex', 'anatom_site_general']
      • 一些其他特征,详见下文
    • 模式 2
      • 与模式 1 相同,除了以下内容:
        • 移除:['tbp_lv_norm_color_per_long_diam', 'norm_A', 'norm_B', 'norm_L', 'clin_size_long_diam_mm_per_age', 'area_ratio', 'weighted_area_ratio']
  • 模型总数
    • 2 种特征 × 3 种 GBDT × 5 个分割种子 × 5 折 × 10 个集合 = 1500
...
# 一些其他特征
).with_columns(
    area_age_ratio = pl.col('tbp_lv_areaMM2') / pl.col('age_approx'),
    symmetry_eccentricity_interaction = pl.col('tbp_lv_symm_2axis') * pl.col('tbp_lv_eccentricity'),
    border_complexity_normalized = pl.col('tbp_lv_norm_border') / (pl.col('tbp_lv_areaMM2').sqrt() + err),
    color_variation_index = pl.col('tbp_lv_color_std_mean') * pl.col('tbp_lv_radial_color_std_max'),
    lesion_flatness = (pl.col('tbp_lv_x')**2 + pl.col('tbp_lv_y')**2).sqrt() / (pl.col('tbp_lv_z')+ err),
    relative_hue_difference = (pl.col('tbp_lv_H') - pl.col('tbp_lv_Hext')).abs() / (pl.col('tbp_lv_H') + pl.col('tbp_lv_Hext') + err),
    area_diameter_ratio = pl.col('tbp_lv_areaMM2') / (pl.col('clin_size_long_diam_mm')**2 + err),
    color_geometric_mean = (pl.col('tbp_lv_L') * pl.col('tbp_lv_A') * pl.col('tbp_lv_B')) ** (1/3),
    tbp_lv_norm_color_per_long_diam = pl.col('tbp_lv_norm_color') / pl.col('clin_size_long_diam_mm').log1p(),
    norm_L = (pl.col('tbp_lv_stdL') + pl.col('tbp_lv_color_std_mean')) / pl.col('tbp_lv_L'),
    norm_A = (pl.col('tbp_lv_stdL') + pl.col('tbp_lv_color_std_mean')) / abs((pl.col('tbp_lv_A')) + err),
    norm_B = (pl.col('tbp_lv_stdL') + pl.col('tbp_lv_color_std_mean')) / abs((pl.col('tbp_lv_B')) + err),
    clin_size_long_diam_mm_per_age = pl.col('clin_size_long_diam_mm') / pl.col('age_approx'),
    area_ratio = (np.pi * (pl.col('clin_size_long_diam_mm')/2)**2) / pl.col('tbp_lv_areaMM2'),
).with_columns(
    weighted_area_ratio = (pl.col('area_ratio') * (pl.col('tbp_lv_areaMM2'))).log1p(),
)
...
同比赛其他方案