ãKaggleãISIC2024 237äœð¥ æ¯ãè¿ã
ä»åã¯ãKaggleã®ISIC2024ã³ã³ãã«åå ãã237äœã§é ã¡ãã«ãååŸããããšãã§ããã®ã§ã解æ³ã®æ¯ãè¿ããæžããŠããããšæããŸãã
ã»Solution
ã»ã³ãŒã
0. ã³ã³ãæŠèŠ
ä»åã®ã³ã³ãã¯ãæäŸãããç®èã®ç»åããŒã¿ããç®èããã®æ£è ã§ãã確çãäºæž¬ããååž°åé¡ã®ã¿ã¹ã¯ã§ããã
ã»æäŸããŒã¿
ç»å: ç®èã®ç»åãæ£è
ãã¹ããã§æ®åœ±ããåçããå€å¥ã§ããããã«ããããã«ãäœè§£å床ã§ãã
ããŒãã«: ç
å€ãšæãããéšäœã®è²ãçŽåŸãªã©ã®çŽ°ããæ
å ±ãåã³æ£è
ã®å¹Žéœ¢ãªã©ã®å人ããŒã¿(testæã«ãæäŸããã)
ã»æåºãã¡ã€ã«ã®ãã©ãŒããã
// targetåãç®èããã§ãã確ç
patient_id, target
ISIC_0015657, 0.3
ISIC_0015729, 0.3
ISIC_0015740, 0.3
ã»è©äŸ¡ææš
è©äŸ¡ææšã¯partial area under the ROC curve (pAUC)ã§ãTure positive rate ã80%以äžã§ããAUCã®é¢ç©ã®æ倧åãç®çã«ãªããŸãã(æ倧å€2.0)
Kaggle ISIC 2024 - Skin Cancer Detection with 3D-TBP
ã»ã³ã³ãã®æµã
åãã¯ç»åã¢ãã«ãäžå¿ã§ããããç»åã®è§£å床ã®äœããšãæäŸãããç
å€ããŒã¿ã®å€ãã®åœ±é¿ã§ãäžç€ã«ã¯LGBMãªã©ã®ããŒãã«ã¢ãã«ãPublic Notebookã§äžäœã§ããã
ãããŠã³ã³ãã®åŸåã§ã¯ãç»åã¢ãã«ãåºåããå€ãããŒãã«ã¢ãã«ã®å
¥åç¹åŸŽéãšããŠäœ¿çšãããããããã¹ã¿ããã³ã°ã®ææ³ãéåžžã«é«ãã¹ã³ã¢ãåºããŠããŸããã
1. 解æ³ã®æŠèŠ
æŠèŠ
ã»ããŒãã«ã¢ãã«ãšç»åã¢ãã«ã®ã¢ã³ãµã³ãã«(1:1ã®å²å)
ã»ããŒãã«ã¢ãã«ã¯ãããªãã¯ã®ããŒãããã¯ã䜿çš: ISIC 2024 | Skin Cancer Prediction
ã»ç»åã¢ãã«ã¯timmã®VITã䜿çš
ã»æ£äŸã®ããŒã¿ãéåžžã«å°ãªãã£ã(0.098%)ãããéåŠç¿ãæããããšãæè
ã€ã¡ãŒãž:
df_subm['target'] = ((df_table['target'].to_numpy() * 0.5) + \
(df_vit_sub["target"].to_numpy() * 0.5))
2. ç»åã¢ãã«
ããããã¯ãç»åã¢ãã«ã«ã€ããŠè©±ããŠãããŸãã
2.1 èšå®
model: "maxvit_rmlp_pico_rw_256.sw_in1k"
batch_size: 128
max_epoch: 9
n_folds: 5
optimizer: optim.AdamW
scheduler: OneCycleLR
lr: 1.0e-04
weight_decay: 1.0e-02
img_size: 256
interpolation: cv2.INTER_LINEAR
CV: StratifiedGroupKFold with "patient_id"
ããªããŒã·ã§ã³ã«ã¯æ£è ã®idãèæ ®ããŠfoldãåå²ã§ããããã«StratifiedGroupKFoldã䜿çšããŸããã
2.2 ã¢ãã«
ã¢ãã«ã¯timmã®äºååŠç¿æžã¿ã¢ãã«ã䜿çšããŸããã
éåŠç¿é²æ¢ã®ãããDropoutãå€ãã«å
¥ããŠããŸãã
self.model = timm.create_model(
model_name=model_name,
pretrained=pretrained,
in_chans=in_channels,
num_classes=num_classes,
global_pool=''
)
dim = CFG.output_dim_models[CFG.model_name]
self.dropout = nn.ModuleList([
nn.Dropout(0.5) for i in range(5)
])
self.target=DynamicLinear(out_size=1)
2.3 äžæãè¡ã£ãããš
2.3.1 2-stage learning
2-stage learning(転移åŠç¿)ãå©çšããŸããã
æ£äŸãå°ãªãåé¡ã«å¯ŸåŠããããã2段éã®åŠç¿ãè¡ããŸããã
- timmã®äºååŠç¿ã¢ãã«ãããã¯ããŒã³ãšããŠISICå ¬åŒãµã€ãã§éå»ã«èç©ãããå šãŠã®ããŒã¿ãå©çšããŠåŠç¿
- 1ã®ã¢ãã«ãäºååŠç¿ã¢ãã«ãšããŠã2024幎床ã®ããŒã¿ã®ã¿ã§åŠç¿
ããã«ãã£ãŠå¹
åºãç»åã«å¯ŸããŠç¹åŸŽãæœåºããæ©èœãä¿ã¡ãªãããä»åã®ããŒã¿ã«éäžããäºæž¬ãè¡ãããšãåºæ¥ãŸãã
ã»timmã®äºååŠç¿ã¢ãã«: äžè¬çãªç»åã®ç¹åŸŽæœåºèœåãæäŸ
ã»1st stage ã¢ãã«: æ§ã
ãªç®èç»åã®ç¹åŸŽæœåºèœåãæäŸ
ã»2nd stage ã¢ãã«: ä»åã®ã³ã³ãã®ããŒã¿ã«éäžããç¹åŸŽæœåºãäºæž¬èœåãæäŸ
ãã®ææ³ãæãCVã®åäžã«è²¢ç®ããŸããã
2.3.2 Augmentations
2020幎ã®ã³ã³ã解æ³ãšãèªåã®å®éšã®çµæããå¹æããããããªããŒã¿æ¡åŒµãéžæããŠããŸããã
éåŠç¿ãé²ãããã«ããŒã¿æ¡åŒµã¯éèŠã§ãããšæã£ãŠããã®ã§ãå€ãã®ãã¿ãŒã³ã§æ€èšŒãè¡ããŸããã
augmentations_train = A.Compose([
A.Transpose(p=0.5),
A.VerticalFlip(p=0.5),
A.HorizontalFlip(p=0.5),
A.ColorJitter(brightness=0.2, contrast=0.2, p=0.3),
A.OneOf([
A.MotionBlur(blur_limit=5, p=0.5),
A.MedianBlur(blur_limit=5, p=0.5),
A.GaussianBlur(blur_limit=5, p=0.5),
], p=0.2),
A.GaussNoise(var_limit=(5.0, 30.0), p=0.1),
A.ShiftScaleRotate(shift_limit=0.1, scale_limit=0.1, rotate_limit=15, border_mode=0, p=0.3),
A.CoarseDropout(max_holes=20, min_holes=10, p=0.3),
A.Resize(CFG.img_size, CFG.img_size),
ToTensorV2(p=1)
])
2.3.3 æšæºå
A.Normalizeã«ããæ£èŠåã®ä»£ããã«ãæšæºåãè¡ããŸããã
çç±ã¯å
¥åç»åã®ç¹æ§ãšããŠã
- ç»è³ªãèãããŸãè¡£é¡ãªã©é¢ä¿ã®ãªãç©ãåã蟌ãã§ããããšããã£ãããå€ãå€ãå€ã
- ç»åã®æããã®åœ±é¿ã§ãåãçç¶ã§ãããŒã¿ã®ååžããºã¬ãŠããå¯èœæ§ãé«ã
ããšããã£ããããå€ãå€ãååžã®ãºã¬ã«åŒ·ãæšæºåãå©çšããŸããã
ããã¯CVã¹ã³ã¢ã倧ããåäžãããŠãããŸããã
ã»æ£èŠåãšæšæºåã®éã
ãData MethodãNormalization VS Standardization
# A.Normalize(
# mean=[0.485, 0.456, 0.406],
# std=[0.229, 0.224, 0.225],
# max_pixel_value=255.0,
# p=1.0
# ),
x, t = batch
if CFG.standardization:
x = (x - x.min()) / (x.max() - x.min() +1e-6) * 255
2.3.4 HSVå ¥å
RGBã«å ããŠHSVã®6次å
ã®å
¥åãå©çšããŸããã
RGBã®è²ã®ã¿ã«äŸåãããããã圩床ãæ床ãªã©ãèæ
®ã§ããæ¹ããéåŠç¿ããŠããŸãå¯èœæ§ãäœããšèããŠå©çšããŸããã
def F_rgb2hsv(rgb: torch.Tensor) -> torch.Tensor:
cmax, cmax_idx = torch.max(rgb, dim=1, keepdim=True)
cmin = torch.min(rgb, dim=1, keepdim=True)[0]
delta = cmax - cmin
hsv_h = torch.empty_like(rgb[:, 0:1, :, :])
cmax_idx[delta == 0] = 3
hsv_h[cmax_idx == 0] = (((rgb[:, 1:2] - rgb[:, 2:3]) / delta) % 6)[cmax_idx == 0]
hsv_h[cmax_idx == 1] = (((rgb[:, 2:3] - rgb[:, 0:1]) / delta) + 2)[cmax_idx == 1]
hsv_h[cmax_idx == 2] = (((rgb[:, 0:1] - rgb[:, 1:2]) / delta) + 4)[cmax_idx == 2]
hsv_h[cmax_idx == 3] = 0.
hsv_h /= 6.
hsv_s = torch.where(cmax == 0, torch.tensor(0.).type_as(rgb), delta / cmax)
hsv_v = cmax
return torch.cat([hsv_h, hsv_s, hsv_v], dim=1)
2.3.5 åŠç¿éäžã§ã®ããŒã¿ã»ããã®å€æŽ
åŠç¿ã®epochã60%ãè¶
ãããšããã§ãããŒã¿æ¡åŒµã®ãªãããŒã¿ã§èšç·Žããããã«ããŠããŸããã
éäžã§ããŒã¿ã»ãããé«ç²ŸåºŠãªãã®ã«å€ããã®ã¯ããã现ãã2-stage learningã®ããã«æ©èœãããšèããŠããŸããããããŒã¿æ¡åŒµããªããšã¢ãã«ã®äžè¬æ§ãäœäžããå¯èœæ§ããããããããã¯äœ¿çšããªããŠãããã£ããããããŸããã
if CFG.change_dataset & epoch >= ((CFG.max_epoch+1) * 0.6):
train_loader = train_loader_noaugment
2.3.6 TTA(test time augmentation)
TTAã¯æšè«æã®å
¥åã«ããŒã¿æ¡åŒµãé©çšããæ¹æ³ã§ãæšè«ã®ç²ŸåºŠãé«ããããã®ææ³ã§ãã
ç§ã¯ããŒã¿æ¡åŒµãªãã§æšè«ããåºåãšãããŒã¿æ¡åŒµããã§æšè«ããåºåã7:3ã®å²åã§çµ±åããã·ã³ãã«ãªææ³ãå©çšããŸããã
CVãLBã«å€§ããªå€åã¯ãããŸããã§ããããPBã§ã¯äžæãæ©èœããŠããããã§ããã
TTA_rate = {'None':0.7, 'with_train_aug':0.3}
# get_dataloader
val_transform_TTA, val_transform = get_transforms()
val_dataset = ISICDataset(df=train_meta[train_meta["fold"] == fold_id], fp_hdf=CFG.TRAIN_HDF5_COMBINED, transform=val_transform)
val_loader = torch.utils.data.DataLoader(val_dataset, batch_size=CFG.batch_size, num_workers=4, shuffle=False, drop_last=False)
if CFG.TTA:
val_dataset_TTA = ISICDataset(df=train_meta[train_meta["fold"] == fold_id], fp_hdf=CFG.TRAIN_HDF5_COMBINED, transform=val_transform_TTA)
val_loader_TTA = torch.utils.data.DataLoader(val_dataset_TTA, batch_size=CFG.batch_size, num_workers=4, shuffle=False, drop_last=False)
# prediction
oof_pred_arr_merged = (oof_pred_arr * CFG.TTA_rate['None']) + (oof_pred_arr_TTA * CFG.TTA_rate['with_train_aug'])
2.3.7 ç°åžžããŒã¿ã®åé€
ãã®discussionã§ææãããŠãããåžå°ã®ããŒã¿ãªã©ãæããã«é¢ä¿ã®ãªãããŒã¿ãåé€ããŸããã
ids_to_drop = ['ISIC_0573025', 'ISIC_1443812', 'ISIC_5374420', 'ISIC_2611119', 'ISIC_2691718', 'ISIC_9689783', 'ISIC_9520696', 'ISIC_8651165', 'ISIC_9385142', 'ISIC_9680590', 'ISIC_2346081']
以äžãäž»ã«è¡ã£ãææ³ã«ãªããŸãã
3. äœãæ©èœããªãã£ãã
ã»ãªãŒããŒãµã³ããªã³ã°
positiveããŒã¿ã1epochäžã«è€æ°ååŠç¿ã«å©çšããæ¹æ³ãpositive rateã0.098%ãã0.3~1%çšåºŠãŸã§åŒãäžããŸãããæ§èœã¯åäžããŸããã§ããã
ã»è£å©ãã¹
ç»å以å€ã®æ£è
ã®ããŒã¿ãäºæž¬ããããããè¿œå ããæ£è§£ãšã®èª€å·®ãLOSSã«è¿œå ããææ³ã
ã»adaptive2dPoolã®ä»£ããã«gemPoolãå©çšãã
gemPool: å¹³åpoolingãšmaxpoolingã®äžéçææ³ã§ãã©ã¡ãã匷ããããã«ã€ããŠãåŠç¿å¯èœãªãã©ã¡ãŒã¿ã§æ±ºå®ããã
ã»ãã倧ããªãã©ã¡ãŒã¿æ°ã®vitã¢ãã«
maxvit_nano
ãmaxvit_pico
ãªã©ãè©ŠããŸããããCVã¹ã³ã¢ã¯éã«å°ãæªåããŸãããç»åã®è§£å床ãäœããããéåŠç¿ããå¯èœæ§ããããŸãã
4. ç°å¢
4.1 GPU
ã³ã³ãå
šäœãéããŠãããŒã«ã«ã®RTX4070 ti superãå©çšããŠããŸãããäž»ã«ããŒãpcããèªå®
ã®PCãžsshã§äœ¿çšãã圢ããšã£ãŠããŸãã
ã³ã³ãçµç€ã§ã¯ãRunpod.ioãVast.aiãšãã£ãã¯ã©ãŠãGPUã®ãµãŒãã¹ãå©çšããŠããŸããã
ããŸãæ
£ããŠãããç°å¢æ§ç¯ã«æéåããŸããããã©ã¡ãã䜿ãããããµãŒãã¹ã§ããã
ç¹åŸŽãšããŠã¯ãvast.aiã®æ¹ãäŸ¡æ Œãå®ãã§ãããrunpodã®æ¹ãã¹ã±ãŒã«ãããããUIãªã©ã芪åã§å©çšããããã£ãã§ãã
ã¯ã©ãŠãGPUã®ç°å¢æ§ç¯ã®æ¹æ³ã«ã€ããŠæ°ã«ãªãæ¹ã¯ä»¥äžã確èªããŠã¿ãŠäžããã
ã»ãCloud GPUãHow to use RunPod.io
ã»ãCloud GPUãHow to use the Vast.ai
4.2 Wandb(å®éšç®¡ç)
ã³ã³ãäžç€ããWandb(Weights and Biases)ãå©çšããŠå®éšç®¡çãè¡ã£ãŠããŸããã
å®éšã®èšå®ãç¹åŸŽéãåŠç¿æéãªã©ããŸãšããŠç®¡çãããã«åŠç¿éçšãGPUã®ç¶æ
ã®å¯èŠåãè¡ãããšãã§ããŠéåžžã«äŸ¿å©ã§ããã
LEAPã³ã³ãã§ã¯ãåŠç¿LOSSã®å¯èŠåã«ãã£ãŠ1epoch以å
ã§æ¢ã«éåŠç¿ããŠããŸã£ãŠããããšã«æ°ã¥ãã人ãããããããã¢ãã«æ§ç¯ã®å©ãã«ãªãããŒã«ã ãšæããŸãã
Wandb解説
ã»ãFor BegginerãHow to use wandb (Minimum Required)
ã»åŠç¿éçšãªã©
ã»GPUã®ç¶æ
ã»å®éšèšå®
5. ãŸãšã
æ¬è§£æ³ã§ã¯ããŒãã«ã¢ãã«ãšVITã«ããç»åã¢ãã«ã®ã¢ã³ãµã³ãã«ã䜿çšããŸããã
ã³ã³ããéããŠãã¢ãã«ãéåŠç¿ããªãããã«æ°ãã€ããŠããŸããã
æ¯ãè¿ãã¯ãããŸã§ã«ãªããŸããèªãã§ããã ãããããšãããããŸããïŒ
åè
[1] ISIC 2024 - Skin Cancer Detection with 3D-TBP, Kaggle
Discussion