Advertisement

X射线肺炎图像的检测(Detecting Pneumonia in X-Ray Image)

阅读量:

灵感 :利用CNN网络从医学图像中检测和分类人类疾病的自动化方法。

在开始分析之前

如下图为随机的两张正常的X射线图片

这里写图片描述

下面的是患有肺炎的X射线图

这里写图片描述
这里写图片描述

对于普通用户而言,在没有任何医疗背景的情况下难以准确判断是否患有肺炎。若采用基于CNN网络的图像分类方法,则能够在一定程度上降低医生诊断肺炎患者的劳动强度。

本次数据集被划分为三个文件夹(train、test、val),其中val文件夹直接用于程序验证。每个文件夹下都包含对应影像分类的子文件夹。该数据集包含了5,863张JPEG格式的X射线影像,并划分为肺部病变与正常的两个类别。

相应的代码实现如下:

复制代码
    import numpy as np
    from tensorflow.python import keras
    from keras import layers
    from keras.models import Model, Sequential
    from keras.optimizers import Adam
    from keras.preprocessing.image import ImageDataGenerator
    from sklearn.metrics import classification_report, confusion_matrix
    from mlxtend.plotting import plot_confusion_matrix
    import matplotlib.pyplot as plt
    
      
      
      
      
      
      
      
      
      
    
    代码解读

引入所需的库,并使用Keras这一主要工具包来构建卷积神经网络(CNN)模型架构、配置优化器以及定义损失函数等关键组件(Keras官方文档:https://keras-cn.readthedocs.io/en/latest/)。
设置训练数据和测试数据文件夹路径。如果需要划分验证数据,则可以同时设置验证数据文件夹路径;本次实验中由于没有额外的数据需求,则直接采用了测试数据作为验证数据。

复制代码
    train_dir = "D:\ X-Picture\ chest_xray\ train\ "
    test_dir = "D:\ X-Picture\ chest_xray\ test\ "
    #可以使用print(os.listdir(train_dir))读取目录下的文件
    #create variable
    image_size = 150
    batch_size = 50
    nb_classes = 2
    #使用ImageDataGenerator进行图片预处理,作为图片生成器,
    train_datagen = ImageDataGerator(rescal = 1./255,#像素点的转换和表示,所有的颜色都在1到255之间。
                              width_shift_range=0.1, #数据提升时图片水平偏移的幅度
                              shear_range = 0.2,#设置剪切长度
                              height_shift_range=0.1,#数据提升时图片竖直偏移的幅度
                              horizontal_flip = True,
                              fill_mode ='nearest')#超出边界的点将根据本参数给定的方法进行处理,一般给定的有有‘constant’,‘nearest’,‘reflect’或‘wrap。
    test-datagen =ImageDateGenerator(1./255)
    #使用flom_from_directory()函数进行数据处理,生成经过数据提升/归一化后的数据,在一个无限循环中不断产生batch数据。
    train_datagen = train_datagen.flow_from_directory(train_dir,
                                               target_size=(image_size,image_size),
                                               batch_size=batch_size,
                                               class_mode='categorical')#class_mode为categorical", "binary", "sparse"或None之一,决定了返回的标签的数组形式,categorical返回的是one-hot编码标签。
    test_datagen = test_datagen.flow_from_directory(test_dir,
                                             target_size(image_size,image_size),
                                              batch_size =batch_size,
                                              class_mode='categorical')    
    #定义步数
    train_steps = train_datagen.samples//batch_size
    test_steps = test_datagen.samples//batch_size 
    #val_steps = val_datagen.samples//batch_size 如果不调用测试集,可以自己建立一个验证集                                                                                                              
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

2 、训练模型的搭建,使用keras模块的函数式模型搭建,代码如下

复制代码
    #create model
    #为了增加程序和模型的兼容能力,可以加入判断,规定输入image_input 的shape类型
    if K.image_data_format()=='channels_first':
       input_shape =(3,img_width,img_height)
    else:
       input_shape =(img_width,img_height,3)   
    img_input = layers.Input(shape=(image_size,image_size,3))
    x = layers.Conv2D(32,3,activation='relu')(img_input)
    x = layers.MaxPooling2D(2)(x)
    x = layers.Conv2D(64,3,activation='relu')(x)
    x = layers.MaxPooling2D(2)(x)
    x = layers.Conv2D(64,3,activation='relu')(x)
    x = layers.MaxPooling2D(2)(x)
    
    x = layers.Flatten()(x)#多维输入一维化
    x = layers.Dense(128,activation='sigmoid')(x)
    x = layers.Dropout(0.5)(x)#按一定的概率随机断开输入神经云,防止过拟合
    output = layers.Dense(2,activation='softmax')(x)
    
    model= Model(img_input,output)
    #给模型定义相应的参数
    model.compile(loss='categorical_crossentropy', #多类的对数损失,注意使用该目标函数时,需要将标签转化为形如(nb_samples, nb_classes)的二值序列
              optimizer =Adam(lr=0.0001),
              metrics = ['acc'] ) #指标列表metrics:对分类问题,我们一般将该列表设置为metrics=['accuracy']。
    epochs = 20  #设置相应的训练迭代次数
    #训练模型
    history =model.fit_generator(train_datagen,
                             steps_per_epoch=train_steps,
                             epochs=epochs,
                             validation_data=test_datagen,
                             validation_steps=test_steps )                                      
    
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

通过调用fit函数对模型进行训练,在每一次循环中从中提取50张图片用于模型更新。整个迭代过程将完成二十次迭代周期,并在每一步中输出当前的损失值和准确率指标作为监控指标。

这里写图片描述

随着迭代次数的提升,在训练过程中损失函数值(loss)逐步降低,在验证过程中准确率(acc)逐步提高。通过调用plt库进行绘图能够更好地理解模型的收敛过程及其性能变化规律。代码实现见下文:

复制代码
    acc = history.history['acc']
    val_acc = history.history['val_acc']
    loss = history.history['loss']
    val_loss = history.history['val_loss']
    epochs_range = range(1, epochs + 1)
    
    plt.figure(figsize=(8,4))
    plt.plot(epochs_range, acc, label='Train Set')
    plt.plot(epochs_range, val_acc, label='Test Set')
    plt.legend(loc="best")
    plt.xlabel('Epochs')
    plt.title('Model Accuracy')
    plt.show()
    
    plt.figure(figsize=(8,4))
    plt.plot(epochs_range, loss, label='Train Set')
    plt.plot(epochs_range, val_loss, label='Test Set')
    plt.legend(loc="best")
    plt.xlabel('Epochs')
    plt.title('Model Loss'))
    plt.show()
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

得到的图像规律变化如下:

这里写图片描述

经过多次训练循环后(系统的正确率持续提高),在第20步之后达到95%;然而,在经历了更多的训练步骤之后(验证集的表现逐渐下降)。

loss函数变化规律如下:

这里写图片描述

随着训练过程的进行,在训练集中定义的损失函数值持续下降。然而,在验证集中观察到的损失函数值并未发生变化,并且出现了上升的趋势。由此可见,即便在模型中引入了dropout层来辅助优化,仍然不可避免地会导致模型过拟合。这可能与训练集中样本数量不足有关,并且normal类别和pneumonia类别的样本数量失衡可能是导致这一现象的原因之一。

4

复制代码
    Y_pred = model.predict_generator(test_datagen,test_steps+1)
    y_pred = np.argmax(Y_pred,axis=1)
    CM =confusion_matrix(test_datagen.classes,y_pred)
    print("CM:",CM)
    
    pneumonia_precision= CM[1][1] / (CM[1][0]+CM[1][1])
    print("pnuemonia_precision:",pneumonia_precision)
    pnuemonia_recall = CM[1][1] / (CM[1][1]+CM[0][1])
    print('pnuemonia_recall:',pnuemonia_recall)
    accuracy = (CM[0][0]+CM[1][1])/(CM[0][0]+CM[0][1]+CM[1][0]+CM[1][1])
    
    #target_names = ['Normal', 'Pneumonia'] 
    #print(classification_report(test_datagen.classes, #y_pred, target_names=target_names))
    
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

输出结果如下:
CM=[ [ 163 71 ]
[ 18 342 ]]
Pnuemonia_pricision = 0.95
Pnuemonia_recall =0.82
Accuracy = 0.81
根据相应的结果可以知道,模型整体的平均准确率较低,但是模型本身的目的主要是追求Pneumonia的精确率,Pneumonia的精确率达到了0.88。

参考网站:https://www.kaggle.com/paultimothymooney/chest-xray-pneumonia

致谢:
Data:https://data.mendeley.com/datasets/rscbjbr9sj/2

License:CC BY 4.0

该研究提出的方法已在实验条件下展现出显著效果,并在Cell杂志上发表详细报告

全部评论 (0)

还没有任何评论哟~