DatawhaleAI夏令营-CV方向baseline理解

DatawhaleAI夏令营-CV方向baseline理解

本次夏令营的目标是完成一个CV方向的竞赛任务,写一点自己的心得体会吧。
竞赛链接:脑PET图像分析和疾病预测挑战赛
主办方给到的baseline分为以下几个步骤,有一种”麻雀虽小,五脏俱全“的感觉,其中涉及到了每个AI模型都需要解决的数据、模型、优化问题。
1. 数据准备与预处理(数据)
2. 特征提取及模型训练(模型、优化)
接下来从两个方面介绍一下我的学习感受和心得。

数据准备与预处理(数据)

数据预处理方面中,使用glob.glob()函数读取文件路径,随后使用np.random.shuffle()对读入路径进行打乱。

在本次学习中我第一次接触到了医学影像的处理,初步了解了nibabel库和.nii格式的图像。

读入.nii格式的图像时,使用如下的格式:

import nibabel as nib
img = nib.load(path)

读入img之后,打印输出一下其内容得到以下信息:

<class 'nibabel.nifti1.Nifti1Image'>
data shape (128, 128, 63, 1)
affine: 
[[  2.05940509   0.           0.         128.        ]
 [  0.           2.05940509   0.         128.        ]
 [  0.           0.           2.42500019  63.        ]
 [  0.           0.           0.           1.        ]]
metadata:
<class 'nibabel.nifti1.Nifti1Header'> object, endian='>'
sizeof_hdr      : 348
data_type       : b''
db_name         : b'041_S_1425'
extents         : 16384
session_error   : 0
regular         : b'r'
dim_info        : 0
dim             : [  4 128 128  63   1   0   0   0]
intent_p1       : 0.0
intent_p2       : 0.0
intent_p3       : 0.0
intent_code     : none
datatype        : uint16
bitpix          : 16
slice_start     : 0
pixdim          : [1.        2.059405  2.059405  2.4250002 0.        0.        0.
 0.       ]
vox_offset      : 0.0
scl_slope       : nan
scl_inter       : nan
slice_end       : 0
slice_code      : unknown
xyzt_units      : 2
cal_max         : 0.0
cal_min         : 0.0
slice_duration  : 0.0
toffset         : 0.0
glmax           : 32767
glmin           : 0
descrip         : b''
aux_file        : b''
qform_code      : scanner
sform_code      : unknown
quatern_b       : 0.0
quatern_c       : 0.0
quatern_d       : 0.0
qoffset_x       : 128.0
qoffset_y       : 128.0
qoffset_z       : 63.0
srow_x          : [0. 0. 0. 0.]
srow_y          : [0. 0. 0. 0.]
srow_z          : [0. 0. 0. 0.]
intent_name     : b''
magic           : b'n+1'

可以看到,.nii文件格式中含有的信息量是很大的。其中跟我们本次实验比较相关的是data shape信息和数据本身,从前者我们可以知道数据的维度信息,即128*128*63*1,四个维度分别代表长度、宽度、通道数baseline里给出了如何读取数据本身的信息,即img.dataobj(或通过img.get_data()函数)进行数据获取。

特征特征提取及模型训练(模型训练)

在传统的机器学习中,特征提取过程中提取到的信息的好坏往往会影响到模型的最终结果,baseline中给出了一些图像中提取到的像素特征用于模型训练。给出了以下特征用于计算:

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']

其中feat + ['NC']这样的方式可以在原本特征之后加入一个列表项,使列表长度+1,加后列表就变成了[..., ..., ... , 'NC']的格式。这是我第一次学到列表可以这么用。

在模型训练时,使用了sklearn这个经典的机器学习包,我们只需要定义模型model,然后通过model.fit()model.predict()分别进行数据拟合和对测试集预测,即可得到模型预测的结果,这对初学者来说是十分友好的。
baseline中使用了Logistic回归模型进行训练,其代码如下:

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]                       # 类别
)

同时,我用到了随机森林分类器进行比较,发现随着参数n_estimators的提升,模型的表现有一定提高。

from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier(n_estimators=2000,max_depth=20, n_jobs=-1, oob_score=True, random_state=10)

model.fit(
    np.array(train_feat)[:, :-1].astype(np.float32),  # 特征
    np.array(train_feat)[:, -1]                       # 类别
    )

当然,由于baseline和设计的特征都比较基础,我们得到的预测结果比较一般,甚至还不如投硬币得到的准确率高。会在接下来的实践中慢慢改进的。

你可能感兴趣的:(DatawhaleAI夏令营,机器学习,人工智能)