<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          【深度學習】實戰(zhàn)深度學習檢測瘧疾

          共 13587字,需瀏覽 28分鐘

           ·

          2021-05-15 16:15

          作者 | Tommy

          編譯 | VK
          來源 | Towards Data Science

          在這個項目中,我們將通過美國國立衛(wèi)生研究院提供的一個數(shù)據(jù)集,從150名感染了惡性瘧原蟲寄生蟲的患者身上獲取27558張不同的細胞圖像,并與50名健康患者的細胞圖像混合,這些圖像可以通過這里的鏈接下載:

          https://www.kaggle.com/iarunava/cell-images-for-detecting-malaria

          我們的任務是建立一個機器學習/深度學習算法,能夠?qū)z測到的細胞是否被寄生蟲感染進行分類。

          在這個項目中,我們將使用一種深度學習算法,即卷積神經(jīng)網(wǎng)絡(Convolutional Neural Network, CNN)算法,它通過訓練來分類某個細胞的圖像是否被感染。由于這是一個超過330mb數(shù)據(jù)的大項目,我建議將其應用到jupiter Notebook中。

          首先,我們需要導入必要的起始庫:

          import pandas as pd
          import numpy as np
          import os
          import cv2
          import random

          你之前可能使用panda.read_csv()導入csv格式的數(shù)據(jù)集,但是,由于所有數(shù)據(jù)都是png格式的,因此可能需要使用os和cv2庫以不同的方式導入它們。

          OS是一個強大的Python庫,允許你與操作系統(tǒng)進行交互,無論操作系統(tǒng)是Windows、Mac OS還是Linux。

          另一方面,cv2是一個專門設計用于解決各種計算機視覺問題,如讀取和加載圖像。

          首先,我們需要設置一個變量來設置我們的路徑,因為我們以后會繼續(xù)使用它:

          root = '../Malaria/cell_images/'
          in = '/Parasitized/'
          un = '/Uninfected/'

          因此,從上面的路徑是名為“瘧疾(Malaria)”的文件夾是我的細胞圖像文件夾文件存儲的地方,這也是寄生和未感染細胞的圖像存儲的地方。這樣,我們就能更容易地操縱這些路徑。

          現(xiàn)在讓我們操作系統(tǒng)列表目錄(“path”)函數(shù)列出被寄生和未受感染文件夾中的所有圖像,如下所示:

          Parasitized = os.listdir(root+in)
          Uninfected = os.listdir(root+un)



          使用OpenCV和Matplotlib顯示圖像


          例如,與csv文件不同,我們只能使用pandas的函數(shù)head列出多個數(shù)據(jù),df.head(10) 顯示10行數(shù)據(jù),對于圖像,我們需要使用for循環(huán)和matplotlib庫來顯示數(shù)據(jù)。

          因此,首先讓我們導入matplotlib并為每個寄生和未感染的細胞圖像繪制圖像,如下所示:

          import matplotlib.pyplot as plt

          然后繪制圖像:

          plt.figure(figsize = (12,24))
          for i in range(4):
              plt.subplot(14, i+1)
              img = cv2.imread(root+in+ Parasitized[i])
              plt.imshow(img)
              plt.title('PARASITIZED : 1')
              plt.tight_layout()
          plt.show()

          plt.figure(figsize = (12,24))
          for i in range(4):
              plt.subplot(24, i+1)
              img = cv2.imread(root+un+ Uninfected[i+1])
              plt.imshow(img)
              plt.title('UNINFECTED : 0')
              plt.tight_layout()
          plt.show()

          因此,為了繪制圖像,我們需要matplotlib中的figure函數(shù),然后我們需要根據(jù)figsize函數(shù)確定每個圖形的大小。

          如上所示,其中第一個數(shù)字是寬度,第二個數(shù)字是高度。然后在for循環(huán)中,我們將使用i作為變量來迭代range()中指示的次數(shù)。

          在本例中,我們將只顯示4個圖像。隨后,我們將使用library中的subplot函數(shù)來指示某個迭代的行數(shù)、列數(shù)和繪圖數(shù),我們使用i+1來實現(xiàn)。

          由于我們已經(jīng)創(chuàng)建了子圖,但是子圖仍然是空的,因此,我們需要使用OpenCV庫,通過使用cv2.imread()函數(shù)導入圖像,并包括其中的路徑和變量i,這樣它將繼續(xù)循環(huán)到下一張圖片,直到提供的最大范圍為止。

          最后,我們將cv2庫導入的圖像用plt.imshow()函數(shù)繪出,我們將獲得以下輸出:



          將圖像和標簽分配到變量中


          接下來,我們要將所有圖像(無論是寄生細胞圖像還是未感染細胞圖像)及其標簽插入到一個變量中,其中1表示寄生細胞,0表示未感染細胞。因此,首先,我們需要為圖像和標簽創(chuàng)建一個空變量。但在此之前,我們需要使用Keras的img_to_array()函數(shù)。

          from tensorflow.keras.preprocessing.image import img_to_array

          假設存儲圖像的變量稱為data,存儲標簽的變量稱為labels,那么我們可以執(zhí)行以下代碼:

          data = []
          labels = []

          for img in Parasitized:
              try:
                  img_read = plt.imread(root+in+ img)
                  img_resize = cv2.resize(img_read, (100100))
                  img_array = img_to_array(img_resize)
                  data.append(img_array)
                  labels.append(1)
              except:
                  None

          for img in Uninfected:
              try:
                  img_read = plt.imread(root+un+ img)
                  img_resize = cv2.resize(img_read, (100100))
                  img_array = img_to_array(img_resize)
                  data.append(img_array)
                  labels.append(0)
              except:
                  None

          在為空數(shù)組賦值變量數(shù)據(jù)和標簽之后,我們需要使用for循環(huán)插入每一張圖像。

          這里有一些不同之處,for循環(huán)中還包含了try和except。try用于在for循環(huán)中正常運行代碼,另一方面,except用于代碼遇到錯誤或崩潰時,以便代碼可以繼續(xù)循環(huán)。

          與上面的圖像顯示代碼類似,我們可以使用plt.imread(“path”)函數(shù),但這一次,我們不需要顯示任何子圖。

          你可能想知道我們?yōu)槭裁从胮lt.imread()而不是cv2.imread()。它們的功能是一樣的,事實上,還有很多其他的圖像讀取庫,例如,Pillow庫的image.open()或Scikit-Image庫的io.imread()。

          然而,OpenCV以BGR或藍、綠、紅的順序讀取圖像,這就是為什么上面顯示的圖像是藍色的,盡管實際的圖片是粉色的。因此,我們需要使用以下代碼將其轉換回RGB順序:

          cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

          另一方面,Matplotlib、Scikit Image和Pillow Image reading函數(shù)會自動按RGB順序讀取圖像,因此,對于我們的單元格圖像實際顏色,我們不需要再進行轉換:

          plt.imshow(data[0])
          plt.show()

          之后,我們可以通過使用OpenCV的cv2.resize()函數(shù)來調(diào)整圖像的大小,以將加載的圖像設置為一個特定的高度和寬度,如上面所示的100 width和100 height。

          接下來,因為我們的圖像是抽象格式的,我們以后將無法對其進行訓練、測試或?qū)⑵洳迦胱兞恐校虼耍覀冃枰褂胟eras的img_to_array()函數(shù)將其轉換為數(shù)組格式。這樣,我們就可以使用.append()函數(shù)將每個圖像插入變量的方括號中,該函數(shù)用于在不改變原始狀態(tài)的情況下將對象插入數(shù)組的最后一個列表。

          所以在我們的循環(huán)中,我們不斷地在每個循環(huán)中添加一個新的圖像。


          預處理數(shù)據(jù)


          不像機器學習項目,我們可以立即分割我們的數(shù)據(jù),在深入學習,特別是神經(jīng)網(wǎng)絡,以減少方差,并減少過擬合。在Python中,有許多方法可以隨機化數(shù)據(jù),比如使用Sklearn,如下所示:

          from sklearn.utils import shuffle

          或使用如下所示的隨機方法:

          from random import shuffle

          但在這個項目中,我們將使用Numpy的隨機函數(shù)。因此,我們需要將數(shù)組轉換成Numpy的數(shù)組函數(shù),然后對圖像數(shù)據(jù)進行隨機化,如下所示:

          image_data = np.array(data)
          labels = np.array(labels)

          idx = np.arange(image_data.shape[0])
          np.random.shuffle(idx)
          image_data = image_data[idx]
          labels = labels[idx]

          首先,我們將數(shù)據(jù)和標簽變量轉換為Numpy格式。然后,我們可以使用np.arange()然后使用np.random.shuffle()功能。最后,我們將被隨機數(shù)據(jù)重新分配到它們的原始變量中,以確保被隨機的數(shù)據(jù)被保存。


          用于訓練、測試和驗證的拆分數(shù)據(jù)


          在數(shù)據(jù)被隨機之后,我們應該通過導入必要的庫將它們拆分為訓練、測試和驗證標簽和數(shù)據(jù),如下所示:

          from tensorflow.keras.utils import to_categorical
          from sklearn.model_selection import train_test_split

          然后我們設置一個函數(shù),將數(shù)據(jù)轉換為32位數(shù)據(jù)以保存:

          def prep_dataset(X,y):

              X_prep = X.astype('float32')/255
              y_prep = to_categorical(np.array(y))
              return (X_prep, y_prep)

          然后通過使用Sklearn庫,我們可以將數(shù)據(jù)分為訓練、測試和驗證:

          X_tr, X_ts, Y_tr, Y_ts = train_test_split(image_data,labels, test_size=0.15, shuffle=True,stratify=labels,random_state=42)
          X_ts, X_val, Y_ts, Y_val = train_test_split(X_ts,Y_ts, test_size=0.5, stratify=Y_ts,random_state=42)

          X_tr, Y_tr = prep_dataset(X_tr,Y_tr)
          X_val, Y_val = prep_dataset(X_val,Y_val)
          X_ts, _ = prep_dataset(X_ts,Y_ts)

          由于存在驗證數(shù)據(jù),因此需要執(zhí)行兩次拆分。在spliting函數(shù)中,我們需要在前兩個參數(shù)中分配數(shù)據(jù)和標簽,然后告訴它們被劃分成的百分比,隨機狀態(tài)是為了確保它們產(chǎn)生的數(shù)據(jù)總是以一致的順序排列。


          卷積神經(jīng)網(wǎng)絡模型的建立


          在建立CNN模型之前,讓我們從理論上對它有一點更深入的了解。CNN主要應用于圖像分類,自1998年發(fā)明以來,由于其高性能和高精度,一直受到人們的歡迎。那么它是如何工作的呢?

          正如我們從上面的插圖中看到的,CNN對圖像進行分類,取圖像的一部分,并將其通過幾層卷積處理來分類圖像。從這幾個層中,可以將它們分為三種類型的層,分別是卷積層、池化層和全連接層。

          卷積層

          第一層,卷積層是CNN最重要的方面之一,它的名字來源于此。其目的是利用核函數(shù)從輸入圖像中提取特征。該核將使用點積連續(xù)掃描輸入圖像,創(chuàng)建一個新的分析層,稱為特征圖/激活圖。其機理如下:

          2*1 + 4*2 + 9*3 + 2*(-4) + 1*7 + 4*4 + 1*2 + 1*(-5) + 2*1 = 51

          然后繼續(xù),直到所有特征圖的單元格都被填滿。

          池化層

          在我們創(chuàng)建了特征圖之后,我們將應用一個池化層來減小其大小以減少過擬合。此步驟中有幾個操作,但是,最流行的技術是最大池,其中特征圖的掃描區(qū)域?qū)H取最高值,如下圖所示:

          卷積和池的步驟可以重復,直到理想的大小是最后敲定,然后我們可以繼續(xù)分類部分,它被稱為全連接層。

          全連通層

          在這一階段,變換后的特征圖將被展平為一個列向量,該列向量將在每個迭代過程中經(jīng)過前饋神經(jīng)網(wǎng)絡和反向傳播過程,持續(xù)數(shù)個階段。最后,CNN模型將區(qū)分主要特征和非主要特征,利用Softmax分類對圖像進行分類。

          在Python中,我們需要從Keras庫導入CNN函數(shù):

          from tensorflow.keras import models, layers
          from tensorflow.keras.callbacks import EarlyStopping

          然后,我們將構建我們自己的CNN模型,包括4個卷積層和池化層:

          model = models.Sequential()

          #Input + Conv 1 + ReLU + Max Pooling
          model.add(layers.Conv2D(32,(5,5),activation='relu',padding='same',input_shape=X_tr.shape[1:]))

          model.add(layers.MaxPool2D(strides=4))
          model.add(layers.BatchNormalization())

          # Conv 2 + ReLU + Max Pooling
          model.add(layers.Conv2D(64,(5,5),padding='same',activation='relu'))

          model.add(layers.MaxPool2D(strides=2))
          model.add(layers.BatchNormalization())

          # Conv 3 + ReLU + Max Pooling
          model.add(layers.Conv2D(128,(3,3),padding='same',activation='relu'))

          model.add(layers.MaxPool2D(strides=2))
          model.add(layers.BatchNormalization())

          # Conv 4 + ReLU + Max Pooling
          model.add(layers.Conv2D(256,(3,3),dilation_rate=(2,2),padding='same',activation='relu'))
          model.add(layers.Conv2D(256,(3,3),activation='relu'))
          model.add(layers.MaxPool2D(strides=2))
          model.add(layers.BatchNormalization())

          # Fully Connected + ReLU
          model.add(layers.Flatten())

          model.add(layers.Dense(300, activation='relu'))
          model.add(layers.Dense(100, activation='relu'))

          #Output
          model.add(layers.Dense(2, activation='softmax'))

          model.summary()

          Keras中的卷積層

          好的,在這段代碼中,你可能會感到困惑的第一件事是model .sequential()。

          利用Keras構建深度學習模型有兩種選擇,一種是序列模型,另一種是函數(shù)模型。他們兩人之間的差異是序列模型只允許一層一層地建立一個模型,另一方面,函數(shù)模型允許層連接到前一層,多層,甚至任何層,你想建立一個更復雜的模型。由于我們正在構建一個簡單的CNN模型,所以我們將使用序列模型。

          我們之前了解到,CNN由卷積層組成,卷積層后來使用池化層進行簡化,因此,我們需要使用Keras函數(shù)model.add()添加層,然后添加我們喜歡的層。

          由于我們的圖像是2D形式,我們只需要2D卷積層,同樣使用卷積層的Keras函數(shù):layers.Conv2D(). 正如你在每一層所看到的,第一層有一個數(shù)字32,第二層有一個數(shù)字64,乘以2并以此類推。這叫做濾波器。它所做的是試圖捕捉圖像的模式。

          因此,隨著濾波器尺寸的增大,我們可以在較小的圖像上捕獲更多的模式,盡管沒有太多理論的證明,然而,這被認為是最優(yōu)方法。

          接下來,(5,5)和(3,3)矩陣是我們上面討論的用于創(chuàng)建特征圖的核。然后這里有兩個有趣的部分:ReLu的激活和填充。那些是什么?我們先來討論ReLu。它是由Rectified Linear Unit縮短而來的,其想法是采用更簡單的模型,提高訓練過程的效率。

          下一個問題是填充。如我們所知,卷積層不斷減小圖像的大小,因此,如果我們在新的特征圖的所有四個邊上添加填充,我們將保持相同的大小。所以我們在處理后的圖像周圍添加新的單元格,值為0,以保持圖像的大小。填充有兩個選項:相同或零。接下來就是input_shape,它只是我們的輸入圖像,只在第一層中用于輸入我們的訓練數(shù)據(jù)。

          Keras中的池化層

          讓我們轉到池化層,我們可以使用Keras的layers.MaxPool2D()。這里有一種東西叫做跨步(stride)。它是核將在輸入上每次移動的步數(shù)。因此,如果我們用5x5的核,并且跨步為4,核將計算圖像最左邊的部分,然后跳過右邊的4個單元格來執(zhí)行下一次計算。

          你可能會注意到,每個卷積層和池化層都以批標準化結束。為什么?因為在每一層中,都有不同的分布,訓練過程會變慢,因為它需要適應每一層。但是,如果強制所有層具有相似的分布,則可以跳過此步驟并提高訓練速度。這就是為什么我們在每一層中應用批標準化,通過如下所示的4個步驟對每一層中的輸入進行標準化:

          Keras全連接層

          現(xiàn)在我們已經(jīng)到了CNN的最后階段,也就是全連接的階段。但在進入這個階段之前,由于我們將在全連接階段使用“Dense”層,所以我們需要使用Keras層將處理過的數(shù)據(jù)平鋪成一維。Flatten()函數(shù)用于將垂直和水平的數(shù)據(jù)合并到單個列中。

          我們將數(shù)據(jù)展平后,現(xiàn)在需要使用layers.Dense()函數(shù)將它們?nèi)B接起來,然后指定要用作輸出的神經(jīng)元數(shù)量,考慮到當前的神經(jīng)元是1024個。所以我們先使用300個神經(jīng)元,然后是100個神經(jīng)元,并使用ReLu對其進行優(yōu)化。

          最后,我們到達輸出階段,這也是通過使用Dense函數(shù)來完成的,然而,由于我們的分類只有2個概率,即感染瘧疾或未感染瘧疾,因此,我們將輸出單位設置為2。此外,在分類任務中,我們在輸出層使用Softmax激活而不是ReLu,因為ReLu將所有負類設置為零。

          綜上所述,我們構建的模型如下:

          然后,我們將把我們的訓練和驗證數(shù)據(jù)整合到模型中:

          model.compile(optimizer='adam',
                       loss='categorical_crossentropy',
                       metrics=['accuracy'])

          es = EarlyStopping(monitor='val_accuracy',mode='max',patience=3,verbose=1)

          history= model.fit(X_tr,Y_tr,
                           epochs=20,
                           batch_size=50,
                           validation_data=(X_val,Y_val),
                           callbacks=[es])

          由于數(shù)據(jù)量很大,這個過程需要一些時間。如下圖所示,每個epoch平均運行9分鐘。



          評估


          我們可以通過繪制評估圖來評估模型性能,但在此之前,我們需要導入seaborn庫:

          import seaborn as sns

          然后將準確度和損失繪制如下:

          fig, ax=plt.subplots(2,1,figsize=(12,10))
          fig.suptitle('Train evaluation')

          sns.lineplot(ax= ax[0],x=np.arange(0,len(history.history['accuracy'])),y=history.history['accuracy'])
          sns.lineplot(ax= ax[0],x=np.arange(0,len(history.history['accuracy'])),y=history.history['val_accuracy'])

          ax[0].legend(['Train','Validation'])
          ax[0].set_title('Accuracy')

          sns.lineplot(ax= ax[1],x=np.arange(0,len(history.history['loss'])),y=history.history['loss'])
          sns.lineplot(ax= ax[1],x=np.arange(0,len(history.history['loss'])),y=history.history['val_loss'])

          ax[1].legend(['Train','Validation'])
          ax[1].set_title('Loss')

          plt.show()

          這將給我們一個輸出:

          它的平均性能似乎超過90%,這是非常好的,正如CNN模型所預期的。不過,為了讓我們更具體地了解數(shù)據(jù)性能,讓我們使用Sklearn構建一個混淆矩陣,并預測輸出:

          from sklearn.metrics import confusion_matrix, accuracy_score

          Y_pred = model.predict(X_ts)

          Y_pred = np.argmax(Y_pred, axis=1)

          conf_mat = confusion_matrix(Y_ts,Y_pred)

          sns.set_style(style='white')
          plt.figure(figsize=(12,8))
          heatmap = sns.heatmap(conf_mat,vmin=np.min(conf_mat.all()), vmax=np.max(conf_mat), annot=True,fmt='d', annot_kws={"fontsize":20},cmap='Spectral')
          heatmap.set_title('Confusion Matrix Heatmap\n?Is the cell infected?', fontdict={'fontsize':15}, pad=12)
          heatmap.set_xlabel('Predicted',fontdict={'fontsize':14})
          heatmap.set_ylabel('Actual',fontdict={'fontsize':14})
          heatmap.set_xticklabels(['NO','YES'], fontdict={'fontsize':12})
          heatmap.set_yticklabels(['NO','YES'], fontdict={'fontsize':12})
          plt.show()

          print('-Acuracy achieved: {:.2f}%\n-Accuracy by model was: {:.2f}%\n-Accuracy by validation was: {:.2f}%'.
                format(accuracy_score(Y_ts,Y_pred)*100,(history.history['accuracy'][-1])*100,(history.history['val_accuracy'][-1])*100))

          這將為我們提供以下準確度:



          錯誤樣本


          讓我們看看錯誤示例的樣子:

          index=0
          index_errors= []

          for label, predict in zip(Y_ts,Y_pred):
              if label != predict:
                  index_errors.append(index)
              index +=1

          plt.figure(figsize=(20,8))

          for i,img_index in zip(range(1,17),random.sample(index_errors,k=16)):
              plt.subplot(2,8,i)
              plt.imshow(np.reshape(255*X_ts[img_index], (100,100,3)))
              plt.title('Actual: '+str(Y_ts[img_index])+' Predict: '+str(Y_pred[img_index]))
          plt.show()

          輸出:

          盡管未感染,但錯誤的預測圖像似乎包含了細胞上的幾個紫色斑塊,因此,模型實際預測它們?yōu)楦腥炯毎强梢岳斫獾摹?/span>

          我想說CNN是一個非常強大的圖像分類模型,不需要做很多預處理任務,因為處理包含在卷積層和池化層中。

          希望通過本文的學習,讓你能夠利用卷積神經(jīng)網(wǎng)絡進行圖像分類。

          感謝你的閱讀。

          ?------------------------------------------------

          看到這里,說明你喜歡這篇文章,請點擊「在看」或順手「轉發(fā)」「點贊」。

          往期精彩回顧





          本站qq群851320808,加入微信群請掃碼:


          瀏覽 77
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  久久免费的精品国产v∧ | 人妻影院| 欧美操嫩逼网 | 国产欧美综合一区 | 国产精品伦子伦免费 |