使用Python+OpenCV+Tensorflow+Flask实现检测X光中的新冠病毒
由于绝大多数胸部X光片都是PA型视图,所以这是用于训练模型的视图选择类型。定义用于训练DL模型的环境理想的做法是从一个新的Python环境开始,为此,使用Terminal定义一个工作目录(例如:X-Ray_Covid_development),然后在那里用Python创建一个环境(例如:TF_2_Py_3_7):mkdir X-Ray_Covid_developmentcd X-Ray_Covid_developmentconda create — name TF_2_Py_3_7 python=3.7 -yconda activate TF_2_Py_3_7进入环境后,安装TensorFlow 2.0:pip install — upgrade pippip install tensorflow从这里开始,安装训练模型所需的其他库。例如:conda install -c anaconda numpyconda install -c anaconda pandasconda install -c anaconda scikit-learnconda install -c conda-forge matplotlibconda install -c anaconda pillowconda install -c conda-forge opencvconda install -c conda-forge imutils创建必要的子目录:notebooks10_dataset — |_ covid [here goes the dataset for training model 1] |_ normal [here goes the dataset for training model 1]20_dataset — |_ covid [here goes the dataset for training model 2] |_ pneumo [here goes the dataset for training model 2]input - |_ 10_Covid_Imagens _ | |_ [metadata.csv goes here] | |_ images [Covid-19 images go here] |_ 20_Chest_Xray - |_ test _ |_ NORMAL [images go here] |_ PNEUMONIA [images go here] |_ train _ |_ NORMAL [images go here] |_ PNEUMONIA [images go here]modeldataset_validation _ |_ covid_validation [images go here] |_ non_covidcovid_validation [images go here] |_ normal_validation [images go here]数据下载下载数据集1(Covid-19),并将metadata.csv文件保存在/input/10_Covid_Images/和/input/10_Covid_Images/Images/下。下载数据集2(肺炎和正常),并将图像保存在/input/20_Chest_Xray/下(保持原始测试和训练结构)。第2部分-模型1-Covid/正常数据准备从GitHub下载Notebook:https://github.com/Mjrovai/covid19Xray/blob/master/10_X-Ray_Covid_development/notebooks/10_Xray_Normal_Covid19_Model_1_Training_Tests.ipynb,将其存储在 subdirectory /notebooks中。进入Notebook后,导入库并运行支持函数。构建Covid标签数据集从输入数据集(/input/10_Covid_Images/)创建用于训练模型1的数据集,该数据集将用于Covid和normal(正常)标签定义的图像分类。input_dataset_path = ‘../input/10_Covid_images’metadata.csv文件将提供有关/images/文件中的图像信息。csvPath = os.path.sep.join([input_dataset_path, “metadata.csv”])df = pd.read_csv(csvPath)df.shapemetadat.csv文件有354行28列,这意味着在subdirectory /notebooks中有354个X光图像。让我们分析它的一些列,了解这些图像的更多细节。
通过df.modality,共有310张X光图像和44张CT图像。CT图像我们丢弃。COVID-19 235Streptococcus 17SARS 16Pneumocystis 15COVID-19, ARDS 12E.Coli 4ARDS 4No Finding 2Chlamydophila 2Legionella 2Klebsiella 1从可视化角度看,COVID-19的235张确认图像,我们有:PA 142AP 39AP Supine 33L 20AP semi erect 1如引言中所述,只有142张PA型图像(后-前)用于模型训练,因为它们是胸片中最常见的图像(最终数据框:xray_cv)。“xray_cv.patiendid”列显示,这142张照片属于96个病人,这意味着在某些情况下,同一个病人拍摄了多张X光片。由于所有图像都用于训练(我们对图像的内容感兴趣),因此不考虑此信息。根据xray_cv.date,2020年3月拍摄的最新照片有8张,这些图像被分离在一个列表中,从模型训练中删除,因此以后这将用作最终模型的验证。imgs_march = [ ‘2966893D-5DDF-4B68–9E2B-4979D5956C8E.jpeg’, ‘6C94A287-C059–46A0–8600-AFB95F4727B7.jpeg’, ‘F2DE909F-E19C-4900–92F5–8F435B031AC6.jpeg’, ‘F4341CE7–73C9–45C6–99C8–8567A5484B63.jpeg’, ‘E63574A7–4188–4C8D-8D17–9D67A18A1AFA.jpeg’, ‘31BA3780–2323–493F-8AED-62081B9C383B.jpeg’, ‘7C69C012–7479–493F-8722-ABC29C60A2DD.jpeg’, ‘B2D20576–00B7–4519-A415–72DE29C90C34.jpeg’]下一步将构建指向训练数据集(xray_cv_train)的数据框,该数据框应引用134个图像(来自Covid的所有输入图像,用于稍后验证的图像除外):xray_cv_train = xray_cv[~xray_cv.filename.isin(imgs_march)]xray_cv_train.reset_index(drop=True, inplace=True)而最终的验证集(xray_cv_val )有8个图像:xray_cv_val = xray_cv[xray_cv.filename.isin(imgs_march)]xray_cv_val.reset_index(drop=True, inplace=True)为COVID训练图像创建文件要记住,在前一项中,只有数据框是使用从原始文件metada.csv中获取的信息创建的。我们知道了哪些图像要存储在最终的训练文件中,现在我们需要“物理地”将实际图像(以数字化格式)分离到正确的子目录(文件夹)中。为此,我们将使用load_image_folder support()函数,该函数将元数据文件中引用的图像从一个文件复制到另一个文件:def load_image_folder(df_metadata, col_img_name, input_dataset_path, output_dataset_path):
img_number = 0 # 对COVID-19的行进行循环 for (i, row) in df_metadata.iterrows(): imagePath = os.path.sep.join([input_dataset_path, row[col_img_name]]) if not os.path.exists(imagePath): print('image not found') continue filename = row[col_img_name].split(os.path.sep)[-1] outputPath = os.path.sep.join([f"{output_dataset_path}", filename]) shutil.copy2(imagePath, outputPath) img_number += 1 print('{} selected Images on folder {}:'.format(img_number, output_dataset_path))按照以下说明,134个选定图像将被复制到文件夹../10_dataset/covid/。input_dataset_path = '../input/10_Covid_images/images'output_dataset_path = '../dataset/covid'dataset = xray_cv_traincol_img_name = 'filename'load_image_folder(dataset, col_img_name, input_dataset_path, output_dataset_path)为正常图像创建文件夹对于数据集2(正常和肺炎图像),不提供包含元数据的文件,因此你只需将图像从输入文件复制到末尾,为此我们创建load_image_folder_direct()函数,该函数将许多图像(随机选择)从une文件夹复制到另一个文件夹:def load_image_folder_direct(input_dataset_path, output_dataset_path, img_num_select): img_number = 0 pathlist = Path(input_dataset_path).glob('**/*.*') nof_samples = img_num_select rc = [] for k, path in enumerate(pathlist): if k < nof_samples: rc.append(str(path)) # 路径不是字符串形式 shutil.copy2(path, output_dataset_path) img_number += 1 else: i = random.randint(0, k) if i < nof_samples: rc[i] = str(path) print('{} selected Images on folder {}:'.format(img_number, output_dataset_path))在../input/20_Chest_Xray/train/NORMAL文件夹重复同样的过程,我们将随机复制用于训练的相同数量图像 (len (xray_cv_train)),134个图像,这样用于训练模型的数据集是平衡的。input_dataset_path = '../input/20_Chest_Xray/train/NORMAL'output_dataset_path = '../dataset/normal'img_num_select = len(xray_cv_train)load_image_folder_direct(input_dataset_path, output_dataset_path, img_num_select)以同样的方式,我们分离出20个随机图像,以供以后在模型验证中使用。input_dataset_path = '../input/20_Chest_Xray/train/NORMAL'output_dataset_path = '../dataset_validation/normal_validation'img_num_select = 20load_image_folder_direct(input_dataset_path, output_dataset_path, img_num_select)尽管我们没有用显示肺炎症状的图像(Covid-19)来训练模型,但是观察最终模型如何与肺炎症状一起工作是很有趣的,因此我们还分离了其中的20幅图像,以供验证。input_dataset_path = '../input/20_Chest_Xray/train/PNEUMONIA'output_dataset_path = '../dataset_validation/non_covid_pneumonia_validation'img_num_select = 20load_image_folder_direct(input_dataset_path, output_dataset_path, img_num_select)下面的图片显示了在这个步骤结束时应该如何配置文件夹(无论如何在我的Mac上),此外红色标记的数字显示文件夹中包含的x光图像的相应数量。
绘制数据集由于文件夹中的图像数量不多,因此可以对其进行可视化检查,为此使用 plots_from_files():def plots_from_files(imspaths, figsize=(10, 5), rows=1, titles=None, maintitle=None): """Plot the images in a grid""" f = plt.figure(figsize=figsize) if maintitle is not None: plt.suptitle(maintitle, fontsize=10) for i in range(len(imspaths)): sp = f.add_subplot(rows, ceildiv(len(imspaths), rows), i + 1) sp.axis('Off') if titles is not None: sp.set_title(titles[i], fontsize=16) img = plt.imread(imspaths[i]) plt.imshow(img)def ceildiv(a, b): return -(-a // b)然后,定义将在训练中使用的数据集的路径和带有要查看的图像名称的列表:dataset_path = '../10_dataset'normal_images = list(paths.list_images(f"{dataset_path}/normal"))covid_images = list(paths.list_images(f"{dataset_path}/covid"))通过调用可视化支持函数,可以显示以下图像:plots_from_files(covid_images, rows=10, maintitle="Covid-19 X-ray images")
plots_from_files(normal_images, rows=10, maintitle="Normal X-ray images")
图像看起来不错。预训练的卷积神经网络模型该模型的训练是使用预定义的图像进行的,应用了称为“迁移学习”的技术。迁移学习是一种机器学习方法,其中为一个任务开发的模型被重用为第二个任务中模型的起点。Keras应用程序是Keras的深度学习库模块,它为几种流行的架构(如VGG16、ResNet50v2、ResNet101v2、Xception、MobileNet等)提供模型定义和预训练的权重。使用的预训练模型是VGG16,由牛津大学视觉图形组(VGG)开发,并在论文“Very Deep Convolutional Networks for Large-Scale Image Recognition”中描述。除了在开发公共的图像分类模型时非常流行外,这也是Adrian博士在其教程中建议的模型。理想的做法是使用几个模型(例如ResNet50v2、ResNet101v2)进行测试(基准测试),甚至创建一个特定的模型(如Zhang等人在论文中建议的模型:https://arxiv.org/pdf/2003.12338.pdf),但由于这项工作的最终目标只是概念上的验证,所以我们仅探索VGG16。
VGG16是一种卷积神经网络(CNN)体系结构,尽管在2014年已经开发出来,但今天仍然被认为是处理图像分类的最佳体系结构之一。VGG16体系结构的一个特点是,它们没有大量的超参数,而是专注于卷积层上,卷积层上有一个3x3滤波器(核)和一个2x2最大池层。在整个体系结构中始终保持一组卷积和最大池化层,最后该架构有2个FC(完全连接的层)和softmax激活输出。VGG16中的16表示架构中有16个带权重的层。该网络是巨大的,在使用所有原始16层的情况下,有将近1.4亿个训练参数。在我们的例子中,最后两层(FC1和FC2)是在本地训练的,参数总数超过1500万,其中大约有590000个参数是在本地训练的(而其余的是“frozen(冻结的)”)。
需要注意的第一点是,VNN16架构的第一层使用224x224x3的图像,因此我们必须确保要训练的X光图像也具有这些维度,因为它们是卷积网络的“第一层”的一部分,因此当使用原始权重(weights=“imagenet”)加载模型时,我们不保留模型的顶层(include_top=False),而这些层将被我们的层(headModel)替换。baseModel = VGG16(weights="imagenet", include_top=False, input_tensor=Input(shape=(224, 224, 3)))接下来,我们必须定义用于训练的超参数(在下面的注释中,将测试一些可能的值以提高模型的“准确性”):INIT_LR = 1e-3 # [0.0001]EPOCHS = 10 # [20]BS = 8 # [16, 32]NODES_DENSE0 = 64 # [128]DROPOUT = 0.5 # [0.0, 0.1, 0.2, 0.3, 0.4, 0.5]MAXPOOL_SIZE = (4, 4) # [(2,2) , (3,3)]ROTATION_DEG = 15 # [10]SPLIT = 0.2 # [0.1]然后构建我们的模型,将其添加到基础模型中:headModel = baseModel.outputheadModel = AveragePooling2D(pool_size=MAXPOOL_SIZE)(headModel)headModel = Flatten(name="flatten")(headModel)headModel = Dense(NODES_DENSE0, activation="relu")(headModel)headModel = Dropout(DROPOUT)(headModel)headModel = Dense(2, activation="softmax")(headModel)headModel被放置在基础模型之上,成为模型的一部分,进行实际训练(确定最佳权重)。model = Model(inputs=baseModel.input, outputs=headModel)重要的是要记住一个预训练过的CNN模型,如VGG16,被训练了成千上万的图像来分类普通图像(如狗、猫、汽车和人),我们现在需要做的是根据我们的需要定制它(分类X光图像)。理论上,模型的第一层简化了图像的部分,识别出其中的形状,这些初始信息非常通用(如直线、圆和正方形),因此我们不用再训练它们,我们只想训练网络的最后一层。下面的循环在基础模型的所有层上执行,“冻结”它们,以便在第一个训练过程中不会更新它们。for layer in baseModel.layers: layer.trainable = False此时,模型已经准备好接受训练,但首先,我们必须为模型的训练准备数据(图像)。数据预处理我们先创建一个包含存储图像的名称(和路径)列表:imagePaths = list(paths.list_images(dataset_path))那么对于列表中的每个图像,我们必须:提取图像标签(在本例中为covid或normal)将BGR(CV2默认值)的图像通道设置为RGB将图像大小调整为224x 224(VGG16的默认值)data = []labels = []for imagePath in imagePaths: label = imagePath.split(os.path.sep)[-2] image = cv2.imread(imagePath) image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) image = cv2.resize(image, (224, 224)) data.append(image) labels.append(label)数据和标签被转换成数组,每个像素的值从0到255改成从0到1,便于训练。data = np.array(data) / 255.0labels = np.array(labels)标签将使用一个one-hot编码技术进行数字编码。lb = LabelBinarizer()labels = lb.fit_transform(labels)labels = to_categorical(labels)此时,训练数据集分为训练集和测试集(训练80%,测试20%):(trainX, testX, trainY, testY) = train_test_split(data, labels, test_size=SPLIT, stratify=labels, random_state=42)最后但并非不重要的是,我们应该应用“数据增强”技术。数据增强如Chowdhury等人所建议,在他们的论文中,三种增强策略(旋转、缩放和平移)可用于为COVID-19生成额外的训练图像,有助于防止“过度拟合”:https://arxiv.org/pdf/2003.13145.pdf。
最新活动更多
-
11月28日立即报名>>> 2024工程师系列—工业电子技术在线会议
-
12月19日立即报名>> 【线下会议】OFweek 2024(第九届)物联网产业大会
-
即日-12.26火热报名中>> OFweek2024中国智造CIO在线峰会
-
即日-2025.8.1立即下载>> 《2024智能制造产业高端化、智能化、绿色化发展蓝皮书》
-
精彩回顾立即查看>> 2024 智能家居出海论坛
-
精彩回顾立即查看>> 【在线会议】多物理场仿真助跑新能源汽车
推荐专题
发表评论
请输入评论内容...
请输入评论/评论长度6~500个字
暂无评论
暂无评论