创建一个像人类一样的神经网络来诊断肺癌

创建一个像人类一样的神经网络来诊断肺癌,第1张

肺癌是人类的主要癌症杀手,它带走的生命甚至超过乳腺癌、结肠癌和前列腺癌的总和,和其他所有种类的癌症一样,肺部结节是癌症的征兆。

医生需通过CT扫描肺部来确定肺中是否有结节。单个患者绘制多幅图像,从而可以形成肺部的3D图像。这些图像具有矢量图、冠状图和轴向视图,所以对于单个患者的扫描结果,甚至可以生成多达600张图像。而医生的任务就是在这些图像中识别结节,且结节必须明显。
根据结节大小,可以将肿瘤称为“良性”或“恶性”。

良性肿瘤更容易治疗,如果不及早发现和治疗,很容易发展成恶性肿瘤(在这种情况下,就被称为患有癌症)。

本文的重点是展示如何设计一种神经网络,该网络可用于将来自患者的CT扫描分类为有结节或无结节。

所需模块
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import os
import shutil
import cv2
import PIL
import pydicom as dicom
from tensorflow.keras.layers import Dense,Conv2D, Dropout,Flatten, AveragePooling2D
from tensorflow import keras
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import Adam
from sklearn.model_selection import train_test_split
from tensorflow.keras import backend as K
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.preprocessing.image import load_img

from sklearn.decomposition import PCA

从上往下:
1.numpy是神经网络分类信息可以接受的输入类型
2.panda用来从文件中读取数据: 肺癌图像数据库
3.matplotlib用来数据可视化的绘制
4.os用于访问Windows的文件结构和读取文件
5.shutil用于将文件复制并移动到适当的文件夹中以进行分类
6.CV2用于从图像读取像素数据或将像素数据写入图像
7.pydicom用于从.dcm文件读取数据,尤其是像素数据
8.Adam优化器将用于分类器
9.ImageDataGenerator将用于扩充图像,以匹配每个类别中的图像数量
10.PCA仅用于确定具有差异的列,以避免不必要的数据。

数据分析

首先,我们必须执行一些EDA以确保我们的数据正确,然后才能为模型提取必要的数据。

nodCount = pd.read_excel("lidc-idri nodule counts (6-23-2015).xlsx",sheet_name = 'Sheet1')

nodCount.isnull().any()
nodCount.drop(['Unnamed: 4','Unnamed: 5'], inplace = True,axis=1)
nodCount = nodCount.dropna(axis=0)
nodCount = nodCount.dropna(axis=0)

我们创建一个DataFrame并将其称为nodCount。然后,我试图消除所有具有空值的列和行。

分类患者档案
patID = nodCount["TCIA Patent ID"]
totalNodules = nodCount["Total Number of Nodules* "]

noNodules = []
position= 0
for i in totalNodules:
    if i == 0:
        noNodules.append(patID[position])
    position+=1
print(noNodules)

hvNodules = []
position = 0
for i in totalNodules:
    if i != 0:
        hvNodules.append(patID[position])
    position+=1 
print(hvNodules)

os.mkdir("Zero Nodules")
os.mkdir("Potentially Cancerous")

ORIGIN = "./data/LIDC/LIDC-IDRI"

folders = []
for f in os.listdir(ORIGIN):
    folders.append(f)
    

POTENTIALLY_CANCEROUS = []
ZERO_NODULES = []
count = 0
for folder in folders:
    if folder in hvNodules:
        POTENTIALLY_CANCEROUS.append(folder)
    else: 
        ZERO_NODULES.append(folder)
    count+=1
    
for i in POTENTIALLY_CANCEROUS:
    shutil.move((ORIGIN+'/'+i),"Potentially Cancerous")
    
for i  in ZERO_NODULES:
    shutil.move((ORIGIN+'/'+i),'Zero Nodules')

上面是一个二分类问题。因此,我们要创建两个文件夹,“无结节”和“有结节”。这些文件将存放没有结节的患者和至少有一个结节的患者的.dcm文件。

从分类文件夹读取图像
def convert_NoNodules():
    dcm_path = "C:/Users/Hp/Documents/Data Science/LIDC/Zero Nodules"
    jpg_path = "C:/Users/Hp/Documents/Data Science/LIDC/Zero Nodules/Images"
    patients = os.listdir(dcm_path)
    images_path = []
    os.mkdir(jpg_path)
    for i in patients:
      ##  images_path.append(os.path.join(dcm_path,i))
        images_path.append((dcm_path+"/"+i))
    for patient in images_path:
        print(patient)
        for img in os.listdir(patient):
            print(img)
            print(patient+'/'+img)
            ds = dicom.dcmread((patient+'/'+img),force = False)
            pixel_array_numpy = ds.pixel_array
            img = img.replace('.dcm','.png')
            os.chdir(jpg_path)
            cv2.imwrite(img,pixel_array_numpy)
            pixel_array = cv2.imread(img)
            print("done")
            
def convert_hvNodules():
    dcm_path = "C:/Users/Hp/Documents/Data Science/LIDC/Potentially Cancerous"
    jpg_path = "C:/Users/Hp/Documents/Data Science/LIDC/Potentially Cancerous/Images"
    patients = os.listdir(dcm_path)
    images_path = []
    count = 0
    #os.mkdir(jpg_path)
    for i in patients:
      ##  images_path.append(os.path.join(dcm_path,i))
        images_path.append((dcm_path+"/"+i))
    for patient in images_path:
        print(patient)
        for img in os.listdir(patient):
            print(img)
            print(patient+'/'+img)
            ds = dicom.dcmread((patient+'/'+img),force = False)
            pixel_array_numpy = ds.pixel_array
            img = img.replace('.dcm','.png')
            os.chdir(jpg_path)
            cv2.imwrite(img,pixel_array_numpy)
            pixel_array = cv2.imread(img)
            print("done")
            count+=1
            print(count)

CT扫描通常保存为.dcm文件。这些通常包含所有患者数据,所有这些数据都方便地存储为单个文件。这些.dcm文件中包含可用于创建图像的像素数据。

我使用了迭代循环,其中初始循环对每个类别中的所有患者文件夹执行此 *** 作,第二个循环对每个患者文件夹中的所有.dcm文件进行循环。

我们使用以下命令读取.dcm文件:
ds = dicom.dcmread((“patient id”),force = False)
“ force”设置为false以确保仅读取.dcm文件。

使用以下方法访问像素数据:
pixel_array_numpy = ds.pixel_array

然后使用以下命令将其写入新创建的图像文件中:
cv2.imwrite(img,pixel_array_numpy)

图像增强
 for i in os.listdir(ZERO_NODULES_IMG_PATH):    
        img_file = cv2.imread((ZERO_NODULES_IMG_PATH + "/"+i))
        print(ZERO_NODULES_IMG_PATH + "/"+i)
        img = img_to_array(img_file)
        img = np.expand_dims(img,axis=0)
        aug = ImageDataGenerator(zoom_range = 0.15,
                                width_shift_range = 0.2,
                                height_shift_range = 0.2,
                                shear_range = 0.15,
                                horizontal_flip = True,
                                fill_mode = 'nearest')
        img_gen = aug.flow(img, batch_size = 1,save_to_dir = ZERO_NODULES_IMG_PATH,save_prefix = "aug_img",save_format = 'jpg')

与没有结节的患者相比,有结节的患者数量存在巨大的不平衡。如果我们用这种不平衡数据集来训练我们的模型,它最终预测每次“都没有结节”。因此,解决方案是增加数据量较少的那个分类图像。图像增强包括了缩放,旋转,翻转等。

准备训练数据
X = []
y = []

for i in os.listdir('C:/Users/Hp/Documents/Data Science/LIDC/Potentially Cancerous/Images'):
    img_array = cv2.imread(('C:/Users/Hp/Documents/Data Science/LIDC/Potentially Cancerous/Images/'+i))
    X.append(img_array)
    y.append(0)
for i in os.listdir('C:/Users/Hp/Documents/Data Science/LIDC/Zero Nodules/Images'):
    img_array = cv2.imread(('C:/Users/Hp/Documents/Data Science/LIDC/Zero Nodules/Images/'+i))
    X.append(img_array)
    y.append(1)
   
X = np.array(X)
X = X/255
y = np.array(y)
print(X[0].shape)

在这里,我们创建了两个数组。X将包含训练数据,而y将包含目标数据。我们将“有结节”编码为0,将“无结节”编码为1。然后,我们需要将X和Y都转换为numpy数组。

下一步是归一化数据集。我们将X除以255,以减小X列的方差差异。
最后,打印了一个X的shape,以便获得神经网络的输入shape。

设计神经网络
classifier = Sequential()
classifier.add(Conv2D(32,kernel_size=(3,3),input_shape=(512,512,3,),activation = 'relu'))
classifier.add(MaxPooling2D(pool_size=(2,2)))
classifier.add(Flatten())
#classifier.add(Dense(256,activation='relu'))
classifier.add(Dense(1,activation = 'sigmoid'))

classifier.compile(optimizer='adam',loss='binary_crossentropy',metrics=['accuracy'])

classifier.summary()

classifier.fit(X,y,verbose = 1)

第一层即卷积层被设置为提取图像数据集的特征。数据的输入shape为X [0]或(512,512,3)。还要注意的是,向该形状添加了通道,因此从技术上讲,输入为(512,512,3,1)。我们使用以下方法检查是否添加了通道:

from tensorflow.keras import backend as K
print(K.image_data_format())
这个将打印"channels_last"

接下来是添加池化层。在这种情况下,我们将使用MaxPooling,该方法会接受设置的宽度和高度中的像素值,然后获得最大值。使用AveragePooling会使准确性降低4%。

接下来是Flatten层,它将我们的4d输入数组转换为2d数组。

最后,我们的输出层是全连接层。

由于这是二分类问题,所以output_shape设置为1。

summary()函数输出正在使用的模型,各层以及各层的输入形状以及各层上的参数数量。

我们使用X和y训练模型,并将verbose设为1,以提供有关准确率和loss的更多详细信息。

寻找最佳方案
X2 =X[1:,:,0,0] 
print(X2.shape)
print(X2)


X3 =X[1:,0,:,0] 
print(X3.shape)
print(X3)
      
pca = PCA().fit(X2)
plt.plot(np.cumsum(pca.explained_variance_ratio_))
plt.xlabel('number of components')
plt.ylabel('cumulative explained variance');

pca = PCA().fit(X3)
plt.plot(np.cumsum(pca.explained_variance_ratio_))
plt.xlabel('number of components')
plt.ylabel('cumulative explained variance');

pca = PCA(50)
X2_new = pca.fit_transform(X2)
X3_new = pca.fit_transform(X3)

之后的工作是为当前问题找到最佳解决方案。因此,我要做的是从我们拥有的4d数据集的每个平面中获取数据,并使用解释的累积方差相对于组件数量的图来获取构成方差一定百分比的患者。

我们可以看到512个患者中约有50个患者说明了数据集中的任何差异。因此,我们使用PCA将X2和X3减少到50个患者。

然后,我们可以使用此新数据重新训练模型。

预测结果

for i in os.listdir(PREDICTION_FOLDER):
    img = PREDICTION_FOLDER+"/"+i
    img = cv2.imread(img)
    Xpred.append(img_to_array(img))

Xpred = np.array(Xpred)
Xpred = Xpred/255

predictions = classifier.predict((Xpred),verbose = 1)

为了进行预测,我们需要设置图像所在的目录,并创建一个称为Xpred的新数组。然后,我们对Xpred进行标准化,并使用predict()函数。

Xpred的值1表示可能致癌,概率表示该人有91%的机会在其肺部出现癌性结节。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/715327.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-25
下一篇 2022-04-25

发表评论

登录后才能评论

评论列表(0条)

保存