新冠肺炎患者图像分类
数据描述
由来自卡塔尔多哈卡塔尔大学及孟加拉国达卡大学的研究团队,并联合巴基斯坦及马来西亚的相关机构组成的研究人员与医疗专家团队协作开发
数据来源
https://www.heywhale.com/mw/dataset/6027caee891f960015c863d7
数据说明
该中心存储了涵盖COVID-19阳性病例、正常肺炎及病毒性肺炎患者的胸部CT影像数据存储库,并包含共计1,200例COVID-19相关CT影像、1,341例普通肺炎CT影像以及1,345例病毒性肺炎CT影像
这些包包含了常见的数据处理方法、图像处理功能以及深度学习相关的框架等基本功能
import os
import math
import zipfile
import random
import json
import cv2
import numpy as np
from PIL import Image
import paddle
import paddle.fluid as fluid
from paddle.fluid.dygraph import Linear,Conv2D,Pool2D
import matplotlib.pyplot as plt
paddle.enable_static()
这段代码用来创建一个执行器并初始化默认的启动程序。
具体解释如下:
fluid.CPUPlace() 负责创建CPU上的位置。
fluid.Executor(place) 负责根据给定位置配置执行器。
exe.run(fluid.default_startup_program()) 负责运行默认启动程序以完成模型参数初始化等操作。这些代码的作用是:首先在CPU上创建一个执行器,并根据前一步骤指定的位置进行配置;接着运行默认启动程序以完成模型参数的初始化等操作。
。
#创建执行器
place=fluid.CPUPlace()
exe=fluid.Executor(place)
exe.run(fluid.default_startup_program())
这段代码用于从之前保存的参数模型中加载数据(如果存在)。如果未找到存储的参数模型,则不会进行加载操作。
具体解释如下:
1. 用于存储模型参数的文件夹路径是 save_path。
2. 该操作会检查给定路径是否存在的操作。
3. 当模型文件夹存在时,则会输出一条提示信息并调用 fluid.io.load_params() 来加载参数。
- 将执行器设置为之前定义的那个执行器实例。
- 存储位置被指定为
save_path。
该代码片段将根据指定的模型参数文件夹路径来检查是否存在相应的模型。当发现存在该文件夹时,程序将加载对应的参数;若未发现该文件夹,则程序将不会执行此操作。
#加载之前的params_model模型,没有模型就不加载
save_path='save_model'
if os.path.exists(save_path):
print("使用参数模型作为预训练模型")
fluid.io.load_params(executor=exe,dirname=save_path)
这段代码负责从已保存的模型中提取预测过程所需的输入数据相关变量列表,并生成输出结果的相关变量。
具体解释如下:
save_path是指定为模型存储目录的有效路径。- 调用该函数可以加载对应训练好的推理模型,并同时返回预测阶段所需的程序入口信息以及相关的数据输入输出变量地址。
- 其中 dirname参数设置为 save_path 用于指定存储目录。
- 其中 exe参数被设置为当前执行器指针。
以上代码片段的作用是从指定的模型文件夹中导入模型,并提取预测程序、输入数据和输出结果的相关变量名称。
save_path='save_model'
#从模型中得到预测程序,输入数据名称列表和分类器
[infer_program,feeded_var_names,target_var]=fluid.io.load_inference_model(dirname=save_path,executor=exe)
这段代码负责配置各项参数:图像尺寸、分类数量、数据存储位置、解压目录位置、模型存储位置、学习速率以及批量处理数量和训练迭代次数。
具体解释如下:
输入尺寸配置:这里定义了图像输入尺寸为[3, 1024, 1024](通道数量×宽度×高度)。
分类数量设置:该参数设定为3个类别进行分类识别。
数据文件路径设置:指定数据压缩文件的位置位于'data/data82373/input_data.rar'。
解压文件夹位置:解压数据集到名为'input_data'的文件夹中进行处理。
模型存储目录:模型将被保存到名为'save_model'的目标目录下。
学习率设定:训练过程中采用的学习速率为固定值0.001。
批次大小设置:每批训练样本数量设定为32张图片。
训练周期次数:整个训练过程共计进行10个完整的训练周期。
以上代码片段的作用是配置一些参数,用于模型的训练和预测。
#一些参数的设置
configs = {
"input_size": [3, 1024,1024], #输入图片的shape
"class_dim":3, #分类数
'src_path':'data/data82373/input_data.rar', #数据的路径
'train_path':'input_data', #解压路径
'model_save_dir':'save_model', # 模型保存路径
'learning_rate':0.001, #学习率
'batch_size':32, #批次大小
'epoch':10 #学习次数
}
这段代码用于预处理胸透图片,并获取训练和测试数据集。
具体解释如下:
初始化为一个空列表COVID,并将其用于存储新冠肺炎患者的胸透图片路径。
同样地,请初始化COVID_label作为一个空列表,并用于存储新冠肺炎患者的分类标签。
类似地,请初始化NORMAL作为一个空列表,并用于存储正常人体Thoracic X光片的路径。
初始化NORMAL_label作为一个空列表,并用于存储正常人体Thoracic X光片对应的分类标签。
同样地,请初始化Viral_Pneumonia作为一个空列表,并用于存储病毒性肺炎患者的胸透图片路径。
同样地,请初始化Viral_Pneumonia_label作为另一个空列表,并用于存储病毒性肺炎患者的分类标签。
请定义函数get_files(file_path, ratio),该函数负责获取图片路径及其对应的分类标签,并将其划分为训练集与测试集两部分。
其中:
file_path表示待处理的胸透X光片图像文件夹所在的具体路径位置;
ratio参数设定为测试数据的比例值,默认取值范围在0至1之间;
该函数的功能包括:
- 根据文件夹下图片的不同分类类型分别提取相应的胸透X光片路径并存入对应的列表中
- 对每类图片设置相应的分类标签
- 通过示例代码展示了如何从文件夹中加载一张胸透X光片并输出其所属类别及对应标签
- 最后一步操作是将所有提取的图片路径和标签信息进行随机打乱排列后按设定比例分割为训练数据集与测试数据集两部分
该代码片段的主要作用是经过胸透图片的预处理,并完成训练与测试数据集的获取。
#预处理图片,获取训练和测试的数据集
COVID =[] #新冠肺炎患者的胸透图片
COVID_label = []
NORMAL = [] #正常人的胸透图片
NORMAL_label = []
Viral_Pneumonia = [] #病毒性肺炎患者的胸透图片
Viral_Pneumonia_label = []
# 获取所以图片的路径名
# 对应的列表中,同时贴上标签,存放到label列表中
def get_files(file_path, ratio):
for file in os.listdir(file_path + '/COVID'):
COVID.append(file_path + '/COVID' + '/' + file)
COVID_label.append(0) # 0为新冠肺炎患者
for file in os.listdir(file_path + '/NORMAL'):
NORMAL.append(file_path + '/NORMAL' + '/' + file)
NORMAL_label.append(1) # 1为正常人
for file in os.listdir(file_path + '/Viral_Pneumonia'):
Viral_Pneumonia.append(file_path + '/Viral_Pneumonia' + '/' + file)
Viral_Pneumonia_label.append(2) # 2为病毒性肺炎患者
#检测是否读取成功
for i in range(1):
# 解决中文显示问题
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
img = plt.imread(NORMAL[i+5])
plt.title('图片的类型是:'+str(NORMAL_label[i+5]))
plt.imshow(img)
plt.show()
#将新路径的图片进行打乱处理
image_list = np.hstack((COVID, NORMAL, Viral_Pneumonia))
label_list = np.hstack((COVID_label, NORMAL_label, Viral_Pneumonia_label))
# 利用shuffle打乱顺序
temp = np.array([image_list, label_list])
temp = temp.transpose()
np.random.shuffle(temp)
# 将所有的img和lab转换成list
all_image_list = list(temp[:, 0])
all_label_list = list(temp[:, 1])
# 将所得List分为两部分,一部分用来训练tra,一部分用来测试val
# ratio是测试集的比例,看情况填入0-1的一个小数
n_sample = len(all_label_list)
n_val = int(math.ceil(n_sample * ratio)) # 测试样本数
n_train = n_sample - n_val # 训练样本数
tra_images = all_image_list[0:n_train]
tra_labels = all_label_list[0:n_train]
tra_labels = [int(float(i)) for i in tra_labels]
val_images = all_image_list[n_train:-1]
val_labels = all_label_list[n_train:-1]
val_labels = [int(float(i)) for i in val_labels]
return tra_images, tra_labels, val_images, val_labels
这段代码定义了一个自定义的数据读取函数 data_reader。
具体解释如下:
1. data_reader(images, labels) 是一个函数,接受两个参数:images 是图片路径的列表,labels 是对应的标签列表。
2. reader() 是内部定义的一个生成器函数,用于生成每个样本的图片和标签。
3. 在生成器函数中,对于每个样本,通过路径读取图片,并进行一些预处理操作:
- 使用 OpenCV 的 cv2.imread() 函数读取图片。
- 使用 np.resize() 函数将图片大小调整为 (3, 256, 256)。
- 使用 np.array() 将图片转换为 numpy 数组,并进行 reshape 操作,使得图片数据的格式为 (3, 256, 256)。
- 将图片的数值范围归一化到 [0, 1],即将数据除以255.0。
4. 最后,通过 yield 关键字将处理后的图片和标签返回。
上述代码片段的功能在于创建自定义的数据加载函数,并负责读取图片数据以及执行预处理步骤。
#自定义读取数据函数
def data_reader(images,labels):
'''
自定义data_reader
'''
def reader():
for item in range(len(images)):
img_path = images[item]
lab = labels[item]
img = cv2.imread(img_path)
img = np.resize(img,(3,256,256))
img = np.array(img).reshape(3,256,256).astype('float32') #要reshape一下,因为输入数据的格式是[256,256,3],而paddle接受数据格式是[3,256,256]
img = img/255.0
yield img, int(lab)
return reader
这段代码定义了一个卷积神经网络模型 CNN_model。
具体解释如下:
CNN_model(tra_images) 该函数用于接收输入参数 tra_images(即该函数用于处理训练数据)。
2. 在模型的定义中,使用了三个卷积-池化层,和一个全连接输出层。
3. 第一个卷积-池化层:
通过 fluid.nets.simple_img_conv_pool 函数定义一个简单的卷积-池化层,并将输入设置为 tra_images。
配置滤波器尺寸为5,并数量设置为20。
将池化核尺寸设定为2×2,并步长设置为2。
选择ReLU作为激活函数。
对输出进行批标准化处理。
4. 第二个卷积-池化层:
该输入经第一个卷积-池化层计算得到 conv_pool_1。
配置滤波器尺寸设定于 5\times5 的数量共计 50 块。
采用池化核尺寸设定于 2\times2 并取样步长均为 2。
选中 ReLU 激活函数作为主要激活单元。
经过批量归一化的处理步骤。
5. 第三个卷积-池化层:
- 该输入基于第二个卷积池化层生成的输出结果
conv_pool_2。 - 该网络架构定义了一个5×5的滤波器尺寸,并配置总计50个滤波器。
- 该模块采用2×2的池化核并配合2步长的滑动策略。
- 网络选用了ReLU函数作为激活函数基底。
6. 全连接输出层:
- 输入来自第三个卷积-池化层计算得到的
conv_pool_3。 - 选择 softmax 函数作为激活函数,则输出维度大小为 3,并分别代表三个类别。
7. 最后,将输出的预测结果返回。
该段代码的主要功能是建立一个卷积神经网络模型,并旨在从输入数据中提取特征并进行分类。
# 定义训练的模型
def CNN_model(tra_images):
# 第一个卷积-池化层
conv_pool_1 = fluid.nets.simple_img_conv_pool(
input=tra_images, # 输入图像
filter_size=5, # 滤波器的大小
num_filters=20, # filter 的数量。它与输出的通道相同
pool_size=2, # 池化核大小2*2
pool_stride=2, # 池化步长
act="relu") # 激活类型
conv_pool_1 = fluid.layers.batch_norm(conv_pool_1)
# 第二个卷积-池化层
conv_pool_2 = fluid.nets.simple_img_conv_pool(
input=conv_pool_1,
filter_size=5,
num_filters=50,
pool_size=2,
pool_stride=2,
act="relu")
conv_pool_2 = fluid.layers.batch_norm(conv_pool_2)
# 第三个卷积-池化层
conv_pool_3 = fluid.nets.simple_img_conv_pool(
input=conv_pool_2,
filter_size=5,
num_filters=50,
pool_size=2,
pool_stride=2,
act="relu")
# 以softmax为激活函数的全连接输出层,因为是分成三类,所以size是三
prediction = fluid.layers.fc(input=conv_pool_3, size=3, act='softmax')
return prediction
这段代码基于预先训练好的卷积神经网络模型 CNN_model 实现了分类功能。
具体解释如下:
1. data_shape = [3,256,256] 定义了输入数据的形状。
tra_images 是一个输入数据的placeholder(占位符),用于接收图像数据(图片数据)。该函数通过 fluid.layers.data 定义(定义),在训练过程中会被输入实际的图像数据。
label 是一个占位符变量,在训练神经网络模型时被用来表示输入的数据标签。通过调用 fluid.layers.data 函数来定义这一占位符,在模型训练过程中会被赋值真实标签值。其形状为 [1]D 张量,并且数据类型设定为 int64 类型。
调用函数之前已建立好的 CNN_model 函数,并以 tra_images 为输入参数进行调用后输出结果为 predict
5. 打印预测结果的形状。
6. 定义损失函数和准确率:
- 采用交叉熵损失函数的计算基于预测值和真实标签输入。
- 通过调用
fluid.layers.mean函数来计算所有损失元素的均值。 - 利用
fluid.layers.accuracy计算预测准确性时采用预测结果与真实标签对齐的方法,并将结果存储在变量中。
7. 定义优化方法:
-
通过 Adam 优化器来实现学习率设置。
- 预设的学习率 configs['learning_rate'] 将被应用于 minimize 方法。 -
利用 Adam 优化器的 minimize 方法来最小化 avg_cost。
-
预设的学习率 configs['learning_rate'] 将被应用于 minimize 方法。
-
利用 Adam 优化器的 minimize 方法来最小化 avg_cost。
8. 打印输出 "完成"。
以上代码片段主要负责搭建一个分类器系统,在具体实现过程中涉及以下关键环节:首先是损失函数的具体计算过程;其次是模型准确率的评估步骤;最后是优化算法的设计与实现。
data_shape = [3,256,256]
tra_images = fluid.layers.data(name='image', shape=data_shape, dtype='float32')
label = fluid.layers.data(name='label', shape=[1], dtype='int64')
# 获取分类器,用cnn进行分类
#model = paddle.vision.models.resnet50(pretrained=True,num_classes=3)
#predict = model(tra_images)
predict = CNN_model(tra_images)
print(np.shape(predict))
# 获取损失函数和准确率
cost = fluid.layers.cross_entropy(input=predict, label=label) # 交叉熵
avg_cost = fluid.layers.mean(cost) # 计算cost中所有元素的平均值
acc = fluid.layers.accuracy(input=predict, label=label) #使用输入和标签计算准确率
# 定义优化方法
optimizer =fluid.optimizer.Adam(learning_rate=configs['learning_rate'])
optimizer.minimize(avg_cost)
print("完成")
这段代码克隆了用于测试模型的程序。
具体解释如下:
fluid.default_main_program() 函数被用来生成默认的主程序,在之前的阶段已经定义了神经网络模型以及相关的损失函数、准确率计算方式和优化方法等细节内容。
执行 clone(for_test=True) 方法以生成 test_program 并创建用于测试模型的专用程序。通过设置 for_test=True 来防止参数更新发生在测试过程中。
以上代码片段的作用是克隆用于测试模型的程序。
#克隆用于测试模型
test_program = fluid.default_main_program().clone(for_test=True)
这段代码构建了一个数据读取器模块,并配置了若干变量用于跟踪训练过程中的训练轮数、损失函数值以及模型准确率等关键指标。
具体解释如下:
该系统创建了一个数据喂养器(DataFeeder),负责将训练图像及其标签输入到神经网络中,并在指定位置放置 feed_list 参数。
2. all_train_iter=0$、all_train_iters=[]$、all_train_costs=[]$、all_train_accs=[]$ 初始化了几个变量,并通过这些变量来追踪训练过程中的各项数值。
3. data_shape = configs['input_size'] 获取输入数据的形状。
该函数用于获取训练图像、训练标签、验证图像和验证标签的路径。其中 configs['train_path'] 指定了训练图像所在的路径位置,并且参数 0.8 表示将所有数据按 8:2 的比例划分为训练集和验证集。
train_reader = paddle.batch(data_reader(train_image, train_label), batch_size=configs['batch_size'], drop_last=True) 实现了训练数据读取器的功能。通过 paddle batching 将 data_reader 输出的生成器封装为迭代器,并设置每个批次的大小为 configs['batch_size']。drop_last=True 表示在剩余样本不足一个批次时会丢弃这些样本。
根据该代码表示的用于处理验证数据的数据读取器eval_reader被定义为:使用paddle.batch函数将val_image和val_label传递给data_reader函数,并设置指定批次大小(batch_size)以及丢弃最后一个不完整批次(drop_last=True)。其结构与训练数据读取器相似。
7. test_reader = paddle.batch(data_reader(val_image,val_label), batch_size=1, drop_last=True) 实现了测试数据的数据读取器功能,并仅抽取单个样本用于测试
该代码片段的功能包括定义数据读取器,并同时初始化了用于记录训练过程中的迭代次数、损失值和准确率的变量。
feeder = fluid.DataFeeder(feed_list=[tra_images, label],place=place)
all_train_iter=0
all_train_iters=[]
all_train_costs=[]
all_train_accs=[]
#定义数据读取
data_shape = configs['input_size']
train_image, train_label, val_image, val_label =get_files(configs['train_path'], 0.8)
print(type(train_image[0]))
train_reader = paddle.batch(data_reader(train_image,train_label),
batch_size=configs['batch_size'],
drop_last=True)
eval_reader = paddle.batch(data_reader(val_image,val_label),
batch_size=configs['batch_size'],
drop_last=True)
test_reader = paddle.batch(data_reader(val_image,val_label),
batch_size=1,
drop_last=True)
这段代码基于提供的验证数据集 val_image 和对应的标签 val_label 对模型进行预测运算,并将预测结果进行可视化呈现。
具体解释如下:
包含了分类标签的列表 label_list = ['新冠肺炎患者', '正常人', '病毒性肺炎患者'] 用于将预测结果归类到相应的类别中。
2. 外层循环 for j in range(len(val_image)): 遍历验证数据集。
内部循环 for batch_id, data in enumerate(eval_reader()): 逐批处理验证数据
调用 exe.run 函数来执行测试程序,并输入验证数据 data 以获取预测结果 results
5. 将预测结果转换为列表形式并保存在 results_list 中。
6. 遍历 results_list,将预测结果可视化展示:
通过调用plt.imread函数获取验证图像数据,并将其赋值给变量名val_image[i]
为当前图像设置标题,并将其内容指定为对应的真实标签值
通过调用plt.imshow函数显示图像内容
利用上述方法呈现待分类图像
借助计算库中的方法确定预测结果索引值
将预测结果信息存储于变量名中完成整个操作流程
输出预测结果信息
7. 如果 i == 5,即查看了 5 张图片后,跳出内层循环。
两个嵌套的break语句各自负责跳转至外部循环和内部循环,并且仅输出单一批次的数据
该代码片段的功能是用来利用已训练好的模型对验证数据集执行预测操作,并通过可视化手段展示预测结果。
label_list = ['新冠肺炎患者','正常人','病毒性肺炎患者']
for j in range(len(val_image)):
for batch_id, data in enumerate(eval_reader()):
results = exe.run(program=test_program, #运行预测程序
feed=feeder.feed(data), #喂入要预测的img
fetch_list=predict) #得到推测结果
#print(results)
results_list = results[0].tolist()
#print(results_list)
for i in range(len(results_list)):
plt.rcParams['font.sans-serif'] = ['SimHei'] # 设置中文
plt.rcParams['axes.unicode_minus'] = False
img = plt.imread(val_image[i])
plt.title('图片的类型是:'+str(val_label[i]))
plt.imshow(img)
plt.show()
predict_result=label_list[np.argmax(results_list[i])]
print("预测结果为: \n", predict_result)
print('------------------------------------')
if i ==5: #根据自己想查看多少张,可以修改这个i的值
break
break
break
结果展示:



