DataWhale CV方向 任务一的学习笔记
一、赛事背景 脑PET全称为脑部正电子发射计算机断层显像(brain positron emission tomography PET),是反映脑部病变的基因、分子、代谢及功能状态的显像。它是利用正电子核素标记葡萄糖等人体代谢物作为显像剂,通过病灶对显像剂的摄取来反映其代谢变化,从而为临床提供疾病的生物代谢信息,为脑癫痫病、脑肿瘤、帕金森病、阿尔茨海默综合征等提供了有效的检测手段。可利用脑PET图像检测出轻度认知障碍病灶,并提前介入治疗,从而延缓发病,对后续患者康复治疗有着积极的意义。因此本赛题以轻度认知障碍为例对脑PET图像进行分析与疾病预测。
二、赛事任务 为研究基于脑PET图像的疾病预测,本次大赛提供了海量脑PET数据集作为脑PET图像检测数据库的训练样本,参赛者需根据提供的样本构建模型,对轻度认知障碍进行分析和预测。
脑PET图像检测数据库,记录了老年人受试志愿者的脑PET影像资料,其中包括确诊为轻度认知障碍(MCI)患者的脑部影像数据和健康人(NC)的脑部影像数据。
被试者按医学诊断分为两类:
NC:健康
MCI:轻度认知障碍
赛事链接在:这里
目标:跑出逻辑回归baseline
1. 认识导入的库
下面先来安装nibabel库
!pip install nibabel
1.1 nibabel库介绍
"Nibabel"(NeuroImaging in Python - NIfTI and ANALYZE image library)是一个用于处理神经影像数据的Python库。它提供了读取、写入和操作NIfTI(Neuroimaging Informatics Technology Initiative)格式和ANALYZE格式的功能,这些格式通常用于存储和处理神经影像数据,如MRI(磁共振成像)和CT(计算机断层扫描)图像。
具体来说,"Nibabel" 提供了以下主要功能:
- 读取和写入图像数据: 它可以轻松读取和写入NIfTI和ANALYZE格式的图像文件,使您能够从文件中获取图像数据或将数据写入图像文件。
- 数据访问和操作: "Nibabel" 允许您访问和操作图像数据的各个方面,包括图像的像素值、尺寸、方向和其他元数据。
- 坐标空间转换: 处理神经影像数据时,可能需要将图像数据从一个坐标空间转换到另一个。"Nibabel" 提供了用于坐标空间转换的工具。
- 图像预处理: 您可以使用 "Nibabel" 对神经影像数据进行预处理,例如重新采样、平滑、剪裁等。
- 与其他Python库集成: "Nibabel" 与其他科学计算和图像处理库(如NumPy、SciPy等)兼容,可以方便地将神经影像数据与其他分析工具集成在一起。
这个包在神经科学研究和医学图像分析中非常有用,它使得处理神经影像数据变得更加容易和灵活。无论您是在进行学术研究还是医学图像分析,"Nibabel" 都是一个强大的工具。
1.2 具体安装问题 以及解决
由于使用的是线上环境,所以在pip前面要加上! ,如果是在本地的命令行输入,请把!去掉
由于一些网络原因或者是线上平台的问题,默认的源不可用,需要更改一成腾讯的源,更改后的代码如下
!pip install nibabel -i http://mirrors.cloud.tencent.com/pypi/simple --trusted-host mirrors.cloud.tencent.com
这样就可以正常安装啦
1.3 其它库的引入与介绍
import glob # 这个模块用于查找符合特定规则的文件路径名。在这里可能用于获取文件路径列表
import numpy as np # NumPy是一个用于科学计算的Python库,这里将其命名为np方便使用
import pandas as pd # pandas是一个用于数据分析和处理的库,将其命名为pd
import nibabel as nib # 引入nibabel
from nibabel.viewers import OrthoSlicer3D # 图像可视化 于进行医学图像的三维切片可视化。
from collections import Counter # 用于计数统计可迭代对象中各元素的出现次数。
其中,numpy和pandas是nibabel的依赖库,一般安装nibabel会装上这俩库,如果报错的话可以也与nibabel一样安装一下就好
2. 解压数据集
# 解压数据集
!unzip /home/aistudio/data/data229672/脑PET图像分析和疾病预测挑战赛数据集.zip -d ./
# 重命名
!mv ─╘PET═╝╧ё╖╓╬Ў║═╝▓▓б╘д▓т╠Ї╒╜╚№╣л┐к╩¤╛▌ 脑PET图像分析和疾病预测挑战赛数据集
这里是把比赛直接给的数据集解压出来,但是由于编码的问题直接解压出来文件名是乱码,所以要进行重命名
通过群友的帮助,这里可以使用CP936编码解压,就不用重命名,代码如下
!unzip -O CP936 /home/aistudio/data/data229672/脑PET图像分析和疾病预测挑战赛数据集.zip -d ./
注意,这是线上环境的代码,本地运行的话要改一下文件路径,并且把开头的!去掉,再在shell里运行,或者自己直接手动解压其实应该就行(自己写搞什么花里胡哨的)
3.数据预处理
3.1 导入数据集
由于上面导入库已经介绍过了,下面就把测试集和训练集都导入进来,然后打乱顺序
# 读取训练集文件路径
train_path = glob.glob('./脑PET图像分析和疾病预测挑战赛数据集/Train/*/*')
test_path = glob.glob('./脑PET图像分析和疾病预测挑战赛数据集/Test/*')
# 打乱训练集和测试集的顺序
np.random.shuffle(train_path)
np.random.shuffle(test_path)
函数对训练集和测试集的文件路径进行随机打乱,以改变它们的顺序。这种随机打乱可以有助于更好地训练和评估模型,避免模型学习到数据的特定顺序。
3.2 读取特征值
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']
这里是定义了个函数,用于读取指定路径的图像并计算出该特征值。我们先读取出其第一个通道的所有数据,然后随机(随机的原因是为了在数据处理中引入一些随机性,有助于模型更好地泛化和学习数据的多样性)取了其中的10个切片(这里10个也不是定死的,也可以自己调整来达到更好的效果),然后计算它们的各个特征值,目前是选择了这8个属性,后续可以再添加。最后就是给这张照片加上它是NC还是MCI这条属性,由于文件夹分好类了,所以根据路径就可以判断了。
4.模型训练
4.1逻辑回归模型介绍
本次采用的是逻辑回归模型,因为是第一次进行练习,逻辑回归对于我们小白来说有很多好处,先进行一下简单的介绍
逻辑回归是一种用于解决分类问题的统计学习方法。虽然名字中包含"回归"一词,但实际上它是一种分类算法,用于预测二分类问题中的类别标签。逻辑回归通过一个称为逻辑函数(或Sigmoid函数)的曲线来建模,并将线性回归模型的输出映射到0到1之间的概率值。
逻辑回归的基本思想是将输入特征与权重相乘并加上偏置项,得到一个线性组合,然后通过逻辑函数将线性组合转换为概率值。如果概率值大于一个阈值(通常是0.5),则预测为正类,否则预测为负类。
逻辑回归模型可以使用最大似然估计等方法进行训练,调整权重和偏置项,使得模型的预测尽可能接近实际标签。逻辑回归可用于二分类问题,也可通过技术扩展到多分类问题,如一对多法(One-vs-Rest)。
尽管逻辑回归在处理复杂数据时可能不如其他算法(如神经网络)效果好,但在许多实际应用中,它仍然是一种常用且有效的分类算法,尤其在解释性和计算效率方面具有优势。
- 简单而高效: 逻辑回归是一种简单且易于理解的模型,不需要太多的调参和复杂的设置。它在许多情况下能够提供良好的性能,尤其是在数据线性可分或近似线性可分的情况下。
- 可解释性强: 逻辑回归模型的结果很容易解释和理解。它输出的是概率值,可以直观地表示某个样本属于某个类别的可能性。
- 低计算成本: 逻辑回归的计算成本相对较低,适用于大规模数据集。它的训练速度通常较快。
特别是方便我们理解,跑通后可以提高自己的信心,也可以鼓励我们进行后续的改进
4.2 代码实现
# 对训练集进行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] # 类别
)
下面来分析一下代码
我们先对每个图片采了30次特征值,然后利用逻辑回归模型,使用训练集的特征作为输入,类别作为输出,进行了30次训练。这样,逻辑回归模型就将学习如何根据特征来区分正常和异常样本啦。
训练后的模型可以用于对测试数据进行分类,帮助预测样本是否为正常或异常。
5.预测与结果提交
# 对测试集进行预测并进行转置操作,使得每个样本有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)
在训练完模型后,运行这段代码就可以使用模型对测试集数据进行预测了,每个样本预测30次,并将预测结果转置以得到每个样本的多次预测。对每个样本的多次预测的结果进行投票,选出现最多次数的类别作为最终预测结果就基本完成啦,最后把样本ID和预测类别组成一个DataFrame,按照ID排序后保存为CSV文件就好啦。
最后只要提交到网站下来就会有自己的第一份成绩啦
虽然可能不是很理想,但是后续继续改进的信息已经有了,希望之后可以有更高分!
总结
这次通过老师们的讲解,和群友的帮助下,总算跑通了baseline,虽然模型可能有些简陋,但是真的学到了很多,我相信只要继续努力,一定会在后续的改进下,拿到一个好成绩! 希望之后会有更好的结果!!