本文原出处 https://aistudio.baidu.com/bd-cpu-01/user/2602285/6564384/lab 基于PaddleClas套件的脑PET图像分析和疾病预测挑战赛-baseline - 飞桨AI Studio (baidu.com)
AI夏令营 - CV实践教程 - 飞书云文档 (feishu.cn)
整理为个人学习所用。
近年来,深度学习在医学图像处理和疾病预测方面取得了显著的进展。脑PET(Positron Emission Tomography)图像是一种用于研究脑部功能和代谢活动的重要影像技术。本次挑战赛共给出了三种思路:
为研究基于脑PET图像的疾病预测,本次大赛提供了海量脑PET数据集作为脑PET图像检测数据库的训练样本,参赛者需根据提供的样本构建模型,对轻度认知障碍进行分析和预测。脑PET图像检测数据库,记录了老年人受试志愿者的脑PET影像资料,其中包括确诊为轻度认知障碍(MCI)患者的脑部影像数据和健康人(NC)的脑部影像数据。 被试者按医学诊断分为两类:
本次大赛所用脑PET图像检测数据库,图像格式为nii。
本次竞赛的评价标准采用F1_score,分数越高,效果越好。
数据集下载链接:https://ai-contest-static.xfyun.cn/2023/data/%E8%84%91PET%E5%9B%BE%E5%83%8F%E5%88%86%E6%9E%90%E5%92%8C%E7%96%BE%E7%97%85%E9%A2%84%E6%B5%8B%E6%8C%91%E6%88%98%E8%B5%9B%E5%85%AC%E5%BC%80%E6%95%B0%E6%8D%AE.zip
# 只需要运行一次
!pip install nibabel
# 解压数据集,只需要运行一次
!unzip /home/aistudio/data/data229672/脑PET图像分析和疾病预测挑战赛数据集.zip -d ./
# 重命名
!mv ─╘PET═╝╧ё╖╓╬Ў║═╝▓▓б╘д▓т╠Ї╒╜╚№╣л┐к╩¤╛▌ 脑PET图像分析和疾病预测挑战赛数据集
读取训练集和测试集的文件路径,并对它们进行随机打乱,以保证数据的随机性。
# 读取训练集文件路径
train_path = glob.glob('./脑PET图像分析和疾病预测挑战赛数据集/Train/*/*')
test_path = glob.glob('./脑PET图像分析和疾病预测挑战赛数据集/Test/*')
# 打乱训练集和测试集的顺序
np.random.shuffle(train_path)
np.random.shuffle(test_path)
对于深度学习任务,特征提取是非常重要的一步。在本例中,我们定义了一个函数`extract_feature`,用于从脑PET图像中提取特征。
`extract_feature`函数从文件路径加载PET图像数据,并从中随机选择10个通道。然后,它计算了一系列统计特征,如非零像素数量、零像素数量、平均值、标准差等。最后,函数根据文件路径判断样本类别,并将提取到的特征和类别作为返回值。
def extract_feature(path):
# 加载PET图像数据
img = nib.load(path)
# 获取第一个通道的数据
img = img.dataobj[:, :, :, 0]
# 随机筛选其中的10个通道提取特征
random_img = img[:, :, np.random.choice(range(img.shape[2]), 10)]
# 对图片计算统计值
feat = [
(random_img != 0).sum(), # 非零像素的数量
(random_img == 0).sum(), # 零像素的数量
random_img.mean(), # 平均值
random_img.std(), # 标准差
len(np.where(random_img.mean(0))[0]), # 在列方向上平均值不为零的数量
len(np.where(random_img.mean(1))[0]), # 在行方向上平均值不为零的数量
random_img.mean(0).max(), # 列方向上的最大平均值
random_img.mean(1).max() # 行方向上的最大平均值
]
# 根据路径判断样本类别('NC'表示正常,'MCI'表示异常)
if 'NC' in path:
return feat + ['NC']
else:
return feat + ['MCI']
在这一步骤中,我们将利用extract_feature
函数提取训练集和测试集的特征,并使用逻辑回归模型对训练集进行训练。
在这里,我们通过循环将特征提取过程重复进行30次,这是为了增加训练样本的多样性。然后,我们使用逻辑回归模型LogisticRegression
来训练数据。在训练完成后,模型已经学习到了从特征到类别的映射关系。
# 对训练集进行30次特征提取,每次提取后的特征以及类别('NC'表示正常,'MCI'表示异常)被添加到train_feat列表中。
train_feat = []
for _ in range(30):
for path in train_path:
train_feat.append(extract_feature(path))
# 对测试集进行30次特征提取
test_feat = []
for _ in range(30):
for path in test_path:
test_feat.append(extract_feature(path))
# 使用训练集的特征作为输入,训练集的类别作为输出,对逻辑回归模型进行训练。
from sklearn.linear_model import LogisticRegression
m = LogisticRegression(max_iter=1000)
m.fit(
np.array(train_feat)[:, :-1].astype(np.float32), # 特征
np.array(train_feat)[:, -1] # 类别
)
在`scikit-learn`(sklearn)中,除了逻辑回归(Logistic Regression)之外,还有许多其他的机器学习模型可以用于分类任务中,以下是一些常用于分类任务的机器学习模型:
1. 支持向量机(Support Vector Machines,SVM):用于二分类和多分类问题,通过构建一个超平面来区分不同类别的样本。
2. 决策树(Decision Trees):适用于二分类和多分类问题,通过对特征空间进行划分来分类样本。
3. 随机森林(Random Forests):基于多个决策树的集成算法,用于二分类和多分类问题,提高了模型的泛化能力。
4. K最近邻算法(K-Nearest Neighbors,KNN):根据最近邻样本的类别来分类新样本,适用于二分类和多分类问题。
5. 朴素贝叶斯(Naive Bayes):基于贝叶斯定理的分类方法,适用于文本分类等问题。
6. 多层感知器(Multi-layer Perceptrons,MLP):一种人工神经网络,用于解决复杂的分类问题。
7. 卷积神经网络(Convolutional Neural Networks,CNN):专用于处理图像和视觉数据的神经网络,在图像分类任务中表现出色。
这些模型在分类任务中有不同的应用场景和性能表现,取决于数据集的特征、样本数量和问题的复杂性。在实际应用中,通常需要根据数据集的特点和具体任务来选择合适的分类模型,并进行模型调参和性能评估,以达到最佳的分类效果。
在这一步骤中,我们使用训练好的逻辑回归模型对测试集进行预测,并将预测结果进行投票,选出最多的类别作为该样本的最终预测类别。最后,我们将预测结果存储在CSV文件中并提交结果。
具体来说,我们使用了Counter
来统计每个样本的30次预测结果中最多的类别,并将结果存储在test_pred_label
列表中。然后,我们将样本ID和对应的预测类别存储在一个DataFrame中,并将其按照ID排序后保存为CSV文件,这样我们就得到了最终的结果提交文件。
# 对测试集进行预测并进行转置操作,使得每个样本有30次预测结果。
test_pred = m.predict(np.array(test_feat)[:, :-1].astype(np.float32))
test_pred = test_pred.reshape(30, -1).T
# 对每个样本的30次预测结果进行投票,选出最多的类别作为该样本的最终预测类别,存储在test_pred_label列表中。
test_pred_label = [Counter(x).most_common(1)[0][0] for x in test_pred]
# 生成提交结果的DataFrame,其中包括样本ID和预测类别。
submit = pd.DataFrame(
{
'uuid': [int(x.split('/')[-1][:-4]) for x in test_path], # 提取测试集文件名中的ID
'label': test_pred_label # 预测的类别
}
)
# 按照ID对结果排序并保存为CSV文件
submit = submit.sort_values(by='uuid')
submit.to_csv('submit.csv', index=None)
本篇baseline介绍了如何使用Python编程语言和机器学习库处理脑PET图像数据,并构建逻辑回归模型来进行脑PET图像的疾病预测。特征提取是一个关键步骤,通过合适的特征提取方法,可以更好地表征图像数据。逻辑回归模型在本例中是一个简单而有效的分类器,但在实际应用中,可能需要更复杂的深度学习模型来提高预测性能。
PP-HGNet(High Performance GPU Net) 是百度飞桨视觉团队自研的更适用于 GPU 平台的高性能骨干网络,该网络在 VOVNet 的基础上使用了可学习的下采样层(LDS Layer),融合了 ResNet_vd、PPHGNet 等模型的优点,该模型在 GPU 平台上与其他 SOTA 模型在相同的速度下有着更高的精度。在同等速度下,该模型高于 ResNet34-D 模型 3.8 个百分点,高于 ResNet50-D 模型 2.4 个百分点,在使用百度自研 SSLD 蒸馏策略后,超越 ResNet50-D 模型 4.7 个百分点。与此同时,在相同精度下,其推理速度也远超主流 VisionTransformer 的推理速度。
PP-HGNet 作者针对 GPU 设备,对目前 GPU 友好的网络做了分析和归纳,尽可能多的使用 3x3 标准卷积(计算密度最高)。在此将 VOVNet 作为基准模型,将主要的有利于 GPU 推理的改进点进行融合。从而得到一个有利于 GPU 推理的骨干网络,同样速度下,精度大幅超越其他 CNN 或者 VisionTransformer 模型。
PP-HGNet 骨干网络的整体结构如下:
其中,PP-HGNet是由多个HG-Block组成,HG-Block的细节如下:
在 ppcls/configs/ImageNet/PPHGNet/PPHGNet_small.yaml
中提供了 PPHGNet_small 训练配置,按照下面的配置要求进行修改。
# 1.全局配置
Global:
checkpoints: null # 检查点保存路径,null表示不保存检查点
pretrained_model: https://paddle-imagenet-models-name.bj.bcebos.com/dygraph/legendary_models/PPHGNet_small_ssld_pretrained.pdparams # 预训练模型的路径
output_dir: ./output/ # 输出目录的路径
device: gpu # 使用的设备,此处为GPU
save_interval: 10 # 模型保存的间隔步数
eval_during_train: True # 训练过程中是否进行评估
eval_interval: 1 # 评估的间隔步数
epochs: 600 # 训练的总轮数
print_batch_step: 10 # 打印训练过程中的批次步数
use_visualdl: True # 是否使用VisualDL进行可视化
image_shape: [3, 224, 224] # 图像的形状,通道数为3,高度和宽度为224
save_inference_dir: ./inference # 导出预测模型的保存路径
to_static: False # 是否在静态模式下训练模型
use_dali: False # 是否使用DALI进行数据加载
# 2.混合精度训练
AMP:
scale_loss: 128.0 # 损失放缩的比例因子
use_dynamic_loss_scaling: True # 是否使用动态损失放缩
level: O1 # 混合精度级别,此处为O1级别,即混合精度浮点数
# 3.模型架构
Arch:
name: PPHGNet_small # 模型的名称
class_num: 2 # 分类的类别数
# 4.训练/评估过程中的损失函数配置
Loss:
Train: # 训练时的损失函数配置
- CELoss: # 交叉熵损失函数
weight: 1.0 # 损失函数的权重
epsilon: 0.1 # 避免计算中的除零错误的小常数
Eval: # 评估时的损失函数配置
- CELoss: # 交叉熵损失函数
weight: 1.0 # 损失函数的权重
# 5.优化器配置
Optimizer:
name: Momentum # 优化器的名称
momentum: 0.9 # 动量因子
lr: # 学习率配置
name: Cosine # 学习率衰减方式为余弦衰减
learning_rate: 0.001 # 初始学习率
warmup_epoch: 5 # 学习率预热的轮数
regularizer: # 正则化配置
name: 'L2' # 正则化方式为L2正则化
coeff: 0.00004 # 正则化系数
# 6.训练和评估的数据加载器配置
DataLoader:
# 6.1 训练数据加载器配置
Train:
dataset: # 数据集配置
name: ImageNetDataset # 数据集的名称
image_root: ./dataset/ # 图像文件的根目录路径
cls_label_path: ./dataset/train_list.txt # 分类标签文件的路径
transform_ops: # 数据预处理操作列表
- DecodeImage: # 图像解码操作
to_rgb: True # 转换为RGB格式
channel_first: False # 通道在最后一维
- RandCropImage: # 随机裁剪操作
size: 224 # 裁剪后的大小
interpolation: bicubic # 插值方法为双三次插值
backend: pil # 使用PIL库进行图像处理
- RandFlipImage: # 随机翻转操作
flip_code: 1 # 水平翻转
- TimmAutoAugment: # 图像自动增强操作
config_str: rand-m7-mstd0.5-inc1 # 增强配置字符串
interpolation: bicubic # 插值方法为双三次插值
img_size: 224 # 图像的大小
- NormalizeImage: # 图像归一化操作
scale: 1.0/255.0 # 缩放比例
mean: [0.485, 0.456, 0.406] # RGB图像的均值
std: [0.229, 0.224, 0.225] # RGB图像的标准差
order: '' # 通道顺序为空,表示使用RGB顺序
- RandomErasing: # 随机擦除操作
EPSILON: 0.25 # 擦除的像素值
sl: 0.02 # 擦除区域的最小比例
sh: 1.0/3.0 # 擦除区域的最大比例
r1: 0.3 # 擦除区域的纵横比范围
attempt: 10 # 尝试擦除的次数
use_log_aspect: True # 使用对数纵横比
mode: pixel # 擦除模式为像素级别
batch_transform_ops: # 批次预处理操作列表
- OpSampler: # 操作采样器
MixupOperator: # Mixup操作
alpha: 0.2 # Mixup的超参数alpha
prob: 0.5 # Mixup的概率
CutmixOperator: # CutMix操作
alpha: 1.0 # CutMix的超参数alpha
prob: 0.5 # CutMix的概率
sampler: # 数据采样器配置
name: DistributedBatchSampler # 采样器的名称
batch_size: 128 # 批次大小
drop_last: False # 是否丢弃最后一个不完整的批次
shuffle: True # 是否在每个epoch之前对数据进行洗牌
loader: # DataLoader配置
num_workers: 16 # 数据加载器使用的线程数
use_shared_memory: True # 是否使用共享内存进行数据加载
# 6.2 评估数据加载器配置
Eval:
dataset: # 数据集配置
name: ImageNetDataset # 数据集的名称
image_root: ./dataset # 图像文件的根目录路径
cls_label_path: ./dataset/val_list.txt # 分类标签文件的路径
transform_ops: # 数据预处理操作列表
- DecodeImage: # 图像解码操作
to_rgb: True # 转换为RGB格式
channel_first: False # 通道在最后一维
- ResizeImage: # 图像缩放操作
resize_short: 236 # 缩放后的短边大小
interpolation: bicubic # 插值方法为双三次插值
backend: pil # 使用PIL库进行图像处理
- CropImage: # 图像裁剪操作
size: 224 # 裁剪后的大小
- NormalizeImage: # 图像归一化操作
scale: 1.0/255.0 # 缩放比例
mean: [0.485, 0.456, 0.406] # RGB图像的均值
std: [0.229, 0.224, 0.225] # RGB图像的标准差
order: '' # 通道顺序为空,表示使用RGB顺序
sampler: # 数据采样器配置
name: DistributedBatchSampler # 采样器的名称
batch_size: 128 # 批次大小
drop_last: False # 是否丢弃最后一个不完整的批次
shuffle: False # 是否在每个epoch之前对数据进行洗牌
loader: # DataLoader配置
num_workers: 16 # 数据加载器使用的线程数
use_shared_memory: True # 是否使用共享内存进行数据加载
# 7.推理配置
Infer:
infer_imgs: docs/images/inference_deployment/whl_demo.jpg # 推理使用的图像路径
batch_size: 10 # 推理时的批次大小
transforms: # 推理数据预处理操作列表
- DecodeImage: # 图像解码操作
to_rgb: True # 转换为RGB格式
channel_first: False # 通道在最后一维
- ResizeImage: # 图像缩放操作
resize_short: 236 # 缩放后的短边大小
interpolation: bicubic # 插值方法为双三次插值
backend: pil # 使用PIL库进行图像处理
- CropImage: # 图像裁剪操作
size: 224 # 裁剪后的大小
- NormalizeImage: # 图像归一化操作
scale: 1.0/255.0 # 缩放比例
mean: [0.485, 0.456, 0.406] # RGB图像的均值
std: [0.229, 0.224, 0.225] # RGB图像的标准差
order: '' # 通道顺序为空,表示使用RGB顺序
- ToCHWImage: # 图像通道顺序转换操作,从HWC转换为CHW
# 8.推理后处理配置
PostProcess:
name: Topk # 后处理的名称
topk: 5 # 返回概率最高的前k个类别
class_id_map_file: ./dataset/labels.txt # 类别ID映射文件的路径
# 9.评估指标配置
Metric:
Train: # 训练时的评估指标配置
- TopkAcc: # Top-k准确率指标
topk: [1, 5] # 计算Top-1和Top-5准确率
Eval: # 评估时的评估指标配置
- TopkAcc: # Top-k准确率指标
topk: [1, 5] # 计算Top-1和Top-5准确率
%cd /home/aistudio/PaddleClas
# 通过如下脚本启动训练,断点恢复训练:-o Global.checkpoints="output/PPHGNet_small/latest"
!export CUDA_VISIBLE_DEVICES=0
!python3 -m paddle.distributed.launch \
--gpus="0" \
tools/train.py \
-c ppcls/configs/ImageNet/PPHGNet/PPHGNet_small.yaml \
训练好模型之后,可以通过以下命令实现对模型指标的评估。
# 其中 `-o Global.pretrained_model="output/PPHGNet_small/best_model"` 指定了当前最佳权重所在的路径,如果指定其他权重,只需替换对应的路径即可。
%cd /home/aistudio/PaddleClas
!python3 tools/eval.py \
-c ppcls/configs/ImageNet/PPHGNet/PPHGNet_small.yaml \
-o Global.pretrained_model=output/PPHGNet_small/best_model
Paddle Inference 是飞桨的原生推理库, 作用于服务器端和云端,提供高性能的推理能力。相比于直接基于预训练模型进行预测,Paddle Inference可使用MKLDNN、CUDNN、TensorRT 进行预测加速,从而实现更优的推理性能。更多关于Paddle Inference推理引擎的介绍,可以参考Paddle Inference官网教程。
当使用 Paddle Inference 推理时,加载的模型类型为 inference 模型。本案例提供了两种获得 inference 模型的方法,如果希望得到和文档相同的结果,请选择直接下载 inference 模型的方式。
此处,我们提供了将权重和模型转换的脚本,执行该脚本可以得到对应的 inference 模型:
!python3 tools/export_model.py \
-c ppcls/configs/ImageNet/PPHGNet/PPHGNet_small.yaml \
-o Global.pretrained_model=output/PPHGNet_small/best_model \
-o Global.save_inference_dir=deploy/models/PPHGNet_small_infer
执行完该脚本后会在 deploy/models/
下生成 PPHGNet_small_infer
文件夹,models
文件夹下应有如下文件结构:
├── PPHGNet_small_infer
│ ├── inference.pdiparams
│ ├── inference.pdiparams.info
│ └── inference.pdmodel
如果希望预测文件夹内的图像,可以直接修改配置文件中的 Global.infer_imgs
字段,也可以通过下面的 -o
参数修改对应的配置。
终端中会输出该文件夹内所有图像的分类结果,如下所示。
修改/home/aistudio/PaddleClas/deploy/python/predict_cls.py
中的 def main(config):
部分
def main(config):
cls_predictor = ClsPredictor(config)
image_list = get_image_list(config["Global"]["infer_imgs"])
batch_imgs = []
batch_names = []
cnt = 0
# 打开submit.csv文件并写入表头
csvfile = open('/home/aistudio/result.csv', 'w', newline='')
writer = csv.writer(csvfile)
writer.writerow(['filename', 'label'])
for idx, img_path in enumerate(image_list):
img = cv2.imread(img_path)
if img is None:
logger.warning(
"Image file failed to read and has been skipped. The path: {}".
format(img_path))
else:
img = img[:, :, ::-1]
batch_imgs.append(img)
img_name = os.path.basename(img_path)
batch_names.append(img_name)
cnt += 1
if cnt % config["Global"]["batch_size"] == 0 or (idx + 1
) == len(image_list):
if len(batch_imgs) == 0:
continue
batch_results = cls_predictor.predict(batch_imgs)
# 循环处理每个图片的结果
for number, result_dict in enumerate(batch_results):
filename = batch_names[number]
label_name = result_dict["label_names"][0]
# 写入CSV文件
writer.writerow([filename.split('.')[0], label_name])
batch_imgs = []
batch_names = []
if cls_predictor.benchmark:
cls_predictor.auto_logger.report()
csvfile.close()
return
# 使用下面的命令使用 GPU 进行预测,如果希望使用 CPU 预测,可以在命令后面添加 -o Global.use_gpu=False
%cd /home/aistudio/PaddleClas/deploy
# 将推理结果存储在result.csv中
!python3 python/predict_cls.py \
-c configs/inference_cls.yaml \
-o Global.inference_model_dir=models/PPHGNet_small_infer \
-o Global.infer_imgs=/home/aistudio/PaddleClas/dataset/Test
%cd /home/aistudio/
# 统计submit.csv中每张nii图片,推理成 MCI 和 NC 的次数,并将结果保存在 result1.csv 中
import csv
def count_labels(input_file):
counts = {} # 创建一个空字典用于存储每个filename前缀对应的NC和MCI的出现次数
with open(input_file, 'r') as csvfile:
reader = csv.reader(csvfile)
next(reader) # 跳过表头
for row in reader:
filename, label = row # 从CSV文件中读取每一行的文件名和标签
prefix = filename.split('_')[0] # 获取文件名的前缀部分
if prefix not in counts:
counts[prefix] = {'NC': 0, 'MCI': 0} # 如果前缀不在字典中,创建一个新的记录
counts[prefix][label] += 1 # 统计该前缀下对应标签的出现次数
return counts
def write_to_csv(output_file, counts):
with open(output_file, 'w', newline='') as csvfile:
writer = csv.writer(csvfile)
writer.writerow(['filename', 'result', 'NC', 'MCI']) # 写入表头
# 对counts字典按照filename进行排序
sorted_counts = sorted(counts.items(), key=lambda item: item[0])
for filename, label_counts in sorted_counts:
nc_count = label_counts.get('NC', 0) # 获取该前缀下NC标签的出现次数,如果不存在则默认为0
mci_count = label_counts.get('MCI', 0) # 获取该前缀下MCI标签的出现次数,如果不存在则默认为0
# 决定result标签,取NC和MCI中出现次数最多的标签
result_label = 'NC' if nc_count >= mci_count else 'MCI'
writer.writerow([filename, result_label, nc_count, mci_count]) # 写入前缀、NC和MCI标签的出现次数以及结果标签
if __name__ == "__main__":
input_file = "result.csv"
output_file = "result1.csv"
label_counts = count_labels(input_file) # 统计标签出现次数
write_to_csv(output_file, label_counts) # 将结果写入CSV文件
# 只写入当前行的前两列到result1.csv,将submit.csv作为结果进行提交
import csv
def write_result1(input_file, output_file):
with open(input_file, 'r') as csvfile:
reader = csv.reader(csvfile)
next(reader) # 跳过表头
with open(output_file, 'w', newline='') as result1file:
writer = csv.writer(result1file)
# 写入表头
writer.writerow(['uuid', 'label'])
for row in reader:
writer.writerow(row[:2])
if __name__ == "__main__":
input_file = "result1.csv"
output_file = "submit.csv"
write_result1(input_file, output_file)
卷积神经网络(Convolutional Neural Network,CNN)是一种深度学习模型,广泛用于图像识别、计算机视觉和模式识别任务中。CNN 在处理具有网格结构数据(如图像)时表现出色,它能够自动学习和提取图像中的特征,并在分类、定位和分割等任务中取得优秀的性能。
方法优缺点(运行时间20分钟,如果有GPU可以更快):
CNN带来的精度更好,但需要训练更长的时间
CNN模型调优需要GPU
import os, sys, glob, argparse
import pandas as pd
import numpy as np
from tqdm import tqdm
import cv2
from PIL import Image
from sklearn.model_selection import train_test_split, StratifiedKFold, KFold
import torch
torch.manual_seed(0)
torch.backends.cudnn.deterministic = False
torch.backends.cudnn.benchmark = True
import torchvision.models as models
import torchvision.transforms as transforms
import torchvision.datasets as datasets
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable
from torch.utils.data.dataset import Dataset
import nibabel as nib
from nibabel.viewers import OrthoSlicer3D
train_path = glob.glob('./脑PET图像分析和疾病预测挑战赛公开数据/Train/*/*')
test_path = glob.glob('./脑PET图像分析和疾病预测挑战赛公开数据/Test/*')
np.random.shuffle(train_path)
np.random.shuffle(test_path)
DATA_CACHE = {}
class XunFeiDataset(Dataset):
def __init__(self, img_path, transform=None):
self.img_path = img_path
if transform is not None:
self.transform = transform
else:
self.transform = None
def __getitem__(self, index):
if self.img_path[index] in DATA_CACHE:
img = DATA_CACHE[self.img_path[index]]
else:
img = nib.load(self.img_path[index])
img = img.dataobj[:,:,:, 0]
DATA_CACHE[self.img_path[index]] = img
# 随机选择一些通道
idx = np.random.choice(range(img.shape[-1]), 50)
img = img[:, :, idx]
img = img.astype(np.float32)
if self.transform is not None:
img = self.transform(image = img)['image']
img = img.transpose([2,0,1])
return img,torch.from_numpy(np.array(int('NC' in self.img_path[index])))
def __len__(self):
return len(self.img_path)
import albumentations as A
train_loader = torch.utils.data.DataLoader(
XunFeiDataset(train_path[:-10],
A.Compose([
A.RandomRotate90(),
A.RandomCrop(120, 120),
A.HorizontalFlip(p=0.5),
A.RandomContrast(p=0.5),
A.RandomBrightnessContrast(p=0.5),
])
), batch_size=2, shuffle=True, num_workers=1, pin_memory=False
)
val_loader = torch.utils.data.DataLoader(
XunFeiDataset(train_path[-10:],
A.Compose([
A.RandomCrop(120, 120),
])
), batch_size=2, shuffle=False, num_workers=1, pin_memory=False
)
test_loader = torch.utils.data.DataLoader(
XunFeiDataset(test_path,
A.Compose([
A.RandomCrop(128, 128),
A.HorizontalFlip(p=0.5),
A.RandomContrast(p=0.5),
])
), batch_size=2, shuffle=False, num_workers=1, pin_memory=False
)
class XunFeiNet(nn.Module):
def __init__(self):
super(XunFeiNet, self).__init__()
model = models.resnet18(True)
model.conv1 = torch.nn.Conv2d(50, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
model.avgpool = nn.AdaptiveAvgPool2d(1)
model.fc = nn.Linear(512, 2)
self.resnet = model
def forward(self, img):
out = self.resnet(img)
return out
model = XunFeiNet()
model = model.to('cuda')
criterion = nn.CrossEntropyLoss().cuda()
optimizer = torch.optim.AdamW(model.parameters(), 0.001)
def train(train_loader, model, criterion, optimizer):
model.train()
train_loss = 0.0
for i, (input, target) in enumerate(train_loader):
input = input.cuda(non_blocking=True)
target = target.cuda(non_blocking=True)
output = model(input)
loss = criterion(output, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if i % 20 == 0:
print(loss.item())
train_loss += loss.item()
return train_loss/len(train_loader)
def validate(val_loader, model, criterion):
model.eval()
val_acc = 0.0
with torch.no_grad():
for i, (input, target) in enumerate(val_loader):
input = input.cuda()
target = target.cuda()
# compute output
output = model(input)
loss = criterion(output, target)
val_acc += (output.argmax(1) == target).sum().item()
return val_acc / len(val_loader.dataset)
for _ in range(3):
train_loss = train(train_loader, model, criterion, optimizer)
val_acc = validate(val_loader, model, criterion)
train_acc = validate(train_loader, model, criterion)
print(train_loss, train_acc, val_acc)
def predict(test_loader, model, criterion):
model.eval()
val_acc = 0.0
test_pred = []
with torch.no_grad():
for i, (input, target) in enumerate(test_loader):
input = input.cuda()
target = target.cuda()
output = model(input)
test_pred.append(output.data.cpu().numpy())
return np.vstack(test_pred)
pred = None
for _ in range(10):
if pred is None:
pred = predict(test_loader, model, criterion)
else:
pred += predict(test_loader, model, criterion)
submit = pd.DataFrame(
{
'uuid': [int(x.split('/')[-1][:-4]) for x in test_path],
'label': pred.argmax(1)
})
submit['label'] = submit['label'].map({1:'NC', 0: 'MCI'})
submit = submit.sort_values(by='uuid')
submit.to_csv('submit2.csv', index=None)
AI环境配置:
视频讲解:AI夏令营:手把手带你配置AI环境_哔哩哔哩_bilibili
图文材料:https://gitee.com/anine09/learn-python-the-smart-way-v2/blob/main/slides/chapter_0-Installation.ipynb
其他材料
python环境的搭建请参考:
Mac设备:Mac上安装Anaconda最全教程
Windows设备:Anaconda超详细安装教程(Windows环境下)_菜鸟1号!!的博客-CSDN博客_windows安装anaconda
Jupyter 编辑器的使用请参考:
Jupyter Notebook最全使用教程,看这篇就够了!