一、概述
基于图像的算法,以识别来自三维全身照片(TBP)的单一病变裁剪图像中经组织学确认的皮肤癌病例。图像质量类似于用于远程医疗的近距离智能手机照片。采取二分类算法可以在没有专门护理设施的环境中使用,从而改善早期皮肤癌检测的分诊工作。
**描述**
- 皮肤癌如果未能早期发现可能是致命的,但许多地区缺乏专门的皮肤科护理。在过去几年中,基于皮肤镜的人工智能算法已被证明能帮助临床医生诊断黑色素瘤、基底细胞癌和鳞状细胞癌。然而,确定哪些人应该首先去看医生具有重大影响。分诊应用在服务不足的群体中具有显著潜力,有助于改善早期皮肤癌检测,这对于长期患者预后至关重要。
- 皮肤镜图像揭示了肉眼无法看到的形态特征,但这些图像通常仅在皮肤科诊所中捕捉。对初级护理或非临床环境中的低质量图像进行评估的算法必须非常熟练。本次比赛利用三维全身照片(TBP)呈现了一个新数据集,涵盖来自三大洲的数千名患者的每一个单独病变,图像类似于手机照片。
- 基于此开发人工智能算法,以区分患者的组织学确认恶性皮肤病变和良性病变。工作将有助于通过将自动皮肤癌检测的好处扩展到更广泛的人群和环境中,改善早期诊断和疾病预后。
**评估**
**主要评分指标**
提交的结果将根据在80%真实阳性率(TPR)以上的接收者操作特征曲线(ROC曲线)的部分面积(pAUC)来评估,重点是对恶性样本的二分类。(请参见笔记本中的ISIC pAUC-aboveTPR实现。)
ROC曲线展示了给定二分类系统在其区分阈值变化时的诊断能力。然而,ROC空间中存在一些区域,在这些区域内,TPR的值在临床实践中是不合接受的。帮助癌症诊断的系统需要具有高度敏感性,因此此指标关注ROC曲线下的面积以及80% TPR以上的区域。因此,评分范围为[0.0, 0.2]。
以下示例中的阴影区域表示两个任意算法(Ca和Cb)在任意最低TPR下的pAUC:
“通过限制TPR定义的pAUC”由ProfGigio许可使用CC-BY-SA-4.0
**提交文件**
对于测试集中每个图像(),你必须预测该病变为恶性的概率()。文件应包含一个标题,并具有以下格式:
isic_id,target
ISIC_0015657,0.7
ISIC_0015729,0.9
ISIC_0015740,0.8
etc.
# 导入操作系统相关功能
import os
# 导入随机数生成
import random
# 导入时间处理功能
import time
# 导入日期时间功能
from datetime import datetime
# 导入数值计算库
import numpy as np
# 导入数据处理库
import pandas as pd
# 导入进度条显示功能
from tqdm import tqdm
# 导入图像处理库
from PIL import Image
# 导入字节流处理库
import io
# 导入HDF5数据格式支持库
import h5py
# 导入PyTorch库
import torch
from torch import nn
# 导入数据集和数据加载功能
from torch.utils.data import Dataset, DataLoader, random_split
# 导入图像转换功能
from torchvision import transforms
# 导入预训练模型库
import timm
# 导入分类评估指标
from sklearn.metrics import hamming_loss, f1_score, roc_curve, auc, classification_report
# 导入二值化处理功能
from sklearn.preprocessing import binarize
# 导入分组数据拆分功能
from sklearn.model_selection import GroupShuffleSplit
# 导入图像增强库
import albumentations as A
# 导入Albumentations与PyTorch张量转换的功能
from albumentations.pytorch import ToTensorV2
# 导入分组交叉验证工具
from sklearn.model_selection import GroupKFold, StratifiedGroupKFold
核心代码如下
# 确定使用的设备(GPU或CPU)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")
# 如果GPU可用,打印相关信息
if torch.cuda.is_available():
print(f"GPU: {torch.cuda.get_device_name(0)}") # 打印第一个GPU的名称
print(f"Number of GPUs: {torch.cuda.device_count()}") # 打印可用GPU的数量
# 设置随机种子以确保结果可重复
random_seed = 42
random.seed(random_seed) # 设置Python的随机种子
torch.manual_seed(random_seed) # 设置PyTorch的随机种子
np.random.seed(random_seed) # 设置NumPy的随机种子
if torch.cuda.is_available():
torch.cuda.manual_seed(random_seed) # 设置当前GPU的随机种子
torch.cuda.manual_seed_all(random_seed) # 设置所有GPU的随机种子
torch.backends.cudnn.deterministic = True # 确保卷积操作是确定性的
torch.backends.cudnn.benchmark = False # 禁用优化,以确保结果的可重复性
# 定义训练的周期数
num_epochs = 1
# 定义快速训练的记录数量
quick_train_record_count = 50000
df_train = pd.read_csv("/kaggle/input/isic-2024-challenge/train-metadata.csv", low_memory=False)
gkf = GroupKFold(5)
df_train["fold"] = -1
for (idx, (trn_idx, val_idx)) in enumerate(gkf.split(df_train, df_train['target'], groups=df_train["patient_id"])):
df_train.loc[val_idx, "fold"] = idx
fold_summary = df_train.groupby("fold")["patient_id"].nunique()
total_patients = df_train["patient_id"].nunique()
print("Fold Summary: ", fold_summary)
print("Total number of patients: ", total_patients)
def setup_model(num_classes=2):
# 创建EfficientNet-B1模型并加载预训练权重
model = timm.create_model('tf_efficientnet_b1',
checkpoint_path='/kaggle/input/tf-efficientnet/pytorch/tf-efficientnet-b1/1/tf_efficientnet_b1_aa-ea7a6ee0.pth',
pretrained=False)
# 修改分类器层以适应特定的类数
model.classifier = nn.Linear(model.classifier.in_features, out_features=num_classes)
return model.to(device) # 将模型移动到适当的设备
def print_trainable_parameters(model):
trainable_params = 0
all_param = 0
for name, param in model.named_parameters():
all_param += param.numel() # 计算所有参数的数量
if param.requires_grad:
trainable_params += param.numel() # 计算可训练参数的数量
print(
f"trainable params: {trainable