使用Python+OpenCV+Tensorflow+Flask實現檢測X光中的新冠病毒
由于絕大多數胸部X光片都是PA型視圖,所以這是用于訓練模型的視圖選擇類型。定義用于訓練DL模型的環(huán)境理想的做法是從一個新的Python環(huán)境開始,為此,使用Terminal定義一個工作目錄(例如:X-Ray_Covid_development),然后在那里用Python創(chuàng)建一個環(huán)境(例如: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進入環(huán)境后,安裝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創(chuàng)建必要的子目錄: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/)創(chuàng)建用于訓練模型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光圖像。讓我們分析它的一些列,了解這些圖像的更多細節(jié)。
通過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訓練圖像創(chuàng)建文件要記住,在前一項中,只有數據框是使用從原始文件metada.csv中獲取的信息創(chuàng)建的。我們知道了哪些圖像要存儲在最終的訓練文件中,現在我們需要“物理地”將實際圖像(以數字化格式)分離到正確的子目錄(文件夾)中。為此,我們將使用load_image_folder support()函數,該函數將元數據文件中引用的圖像從一個文件復制到另一個文件:def load_image_folder(df_metadata, col_img_name, input_dataset_path, output_dataset_path):
img_number = 0 # 對COVID-19的行進行循環(huán) 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)為正常圖像創(chuàng)建文件夾對于數據集2(正常和肺炎圖像),不提供包含元數據的文件,因此你只需將圖像從輸入文件復制到末尾,為此我們創(chuàng)建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")
圖像看起來不錯。預訓練的卷積神經網絡模型該模型的訓練是使用預定義的圖像進行的,應用了稱為“遷移學習”的技術。遷移學習是一種機器學習方法,其中為一個任務開發(fā)的模型被重用為第二個任務中模型的起點。Keras應用程序是Keras的深度學習庫模塊,它為幾種流行的架構(如VGG16、ResNet50v2、ResNet101v2、Xception、MobileNet等)提供模型定義和預訓練的權重。使用的預訓練模型是VGG16,由牛津大學視覺圖形組(VGG)開發(fā),并在論文“Very Deep Convolutional Networks for Large-Scale Image Recognition”中描述。除了在開發(fā)公共的圖像分類模型時非常流行外,這也是Adrian博士在其教程中建議的模型。理想的做法是使用幾個模型(例如ResNet50v2、ResNet101v2)進行測試(基準測試),甚至創(chuàng)建一個特定的模型(如Zhang等人在論文中建議的模型:https://arxiv.org/pdf/2003.12338.pdf),但由于這項工作的最終目標只是概念上的驗證,所以我們僅探索VGG16。
VGG16是一種卷積神經網絡(CNN)體系結構,盡管在2014年已經開發(fā)出來,但今天仍然被認為是處理圖像分類的最佳體系結構之一。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光圖像)。理論上,模型的第一層簡化了圖像的部分,識別出其中的形狀,這些初始信息非常通用(如直線、圓和正方形),因此我們不用再訓練它們,我們只想訓練網絡的最后一層。下面的循環(huán)在基礎模型的所有層上執(zhí)行,“凍結”它們,以便在第一個訓練過程中不會更新它們。for layer in baseModel.layers: layer.trainable = False此時,模型已經準備好接受訓練,但首先,我們必須為模型的訓練準備數據(圖像)。數據預處理我們先創(chuàng)建一個包含存儲圖像的名稱(和路徑)列表: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-h(huán)ot編碼技術進行數字編碼。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。

請輸入評論內容...
請輸入評論/評論長度6~500個字