使用Keras和TensorFlow 2.0建立深度學習模型對圖像進行分類

在本文中,我們將構建一個深度學習模型來對圖像中的對象進行分類。爲了構建卷積神經網絡,我們將使用Kaggle提供的這個數據集。(https://www.kaggle.com/c/dogs-vs-cats-redux-kernels-edition/data)CNN是一種主要用於視覺任務的神經網絡。該網絡將檢測動物的特徵,然後使用這些特徵將給定的輸入圖像分類爲貓或狗。

以下內容由公衆號:AIRX社區(國內領先的AI、AR、VR技術學習與交流平臺) 整理

導入必要的包文件

先激活虛擬環境

conda activate my_env

運行以下命令安裝keras和tensorflow:

conda install tensorflow keras pillow

在這裏,我們還安裝了pillow以便於以後加載圖像。

現在導入以下包:

  • 連續初始化人工神經網絡

  • 用於實現處理圖像的卷積網絡

  • MaxPooling2D用於添加池化層

  • Flatten轉換池的功能映射成一個列,將被饋送到全連接層

  • 這將爲神經網絡增加一個完全連接的層

from keras.models import Sequential
from keras.layers import Conv2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense

初始化神經網絡

接下來,我們將使用該Sequential包來初始化線性的圖層堆棧。對於像這樣的分類問題,我們通常創建一個分類變量。

classifier = Sequential()

我們現在有了一個神經網絡的實例,但它本身並不能做任何事情。我們需要對數據集應用一個函數,這意味着網絡需要一個卷積層。我們將在下一步中添加這一層。

添加捲積層

通過調用分類器上的add函數並傳遞所需的參數來添加層。傳遞參數是使用Convolution2D完成的。第一個參數(濾波器)是卷積中輸出濾波器的數量。它們也被稱爲特徵檢測器。

第二和第三參數代表2D卷積窗口的高度和寬度。input_shape是輸入圖像的形狀。黑白圖像轉換爲2D陣列,而彩色圖像轉換爲3D陣列。

卷積是涉及兩個函數的數學計算,旨在找出這兩個函數如何相互影響。

該過程涉及三個關鍵項目:輸入圖像,特徵檢測器和特徵圖。通過將輸入圖像逐個元素的矩陣表示與特徵檢測器相乘,可以獲得特徵圖。此過程旨在減小圖像的大小,並保留了對分類輸入圖像很重要的功能,並丟棄了不分類的功能。每個特徵圖都會檢測圖像獨特特徵的位置。

在這種情況下,我們正在處理彩色圖像。因此,我們將三個通道傳遞給該input_shape參數。我們還需要爲每個通道傳遞2D數組的尺寸。我們將傳遞的最後一個參數是激活函數。由於圖像分類是非線性任務,因此我們將使用整流器功能。這樣可以確保我們在操作過程中不會得到負值。

classifier.add(Conv2D(32, (3, 3), input_shape = (256, 256, 3), activation='relu'))

我們現在有一個CNN,它將檢測圖像數據集中的特徵。在下一步中,我們將使用池來減小這些特性的大小。這將有助於減少深度學習模型的計算時間

合併以減少要素圖的大小

現在,我們將向網絡中添加一個池層,以減少功能映射的大小。我們使用2x2池大小的最大池。這減少了圖像的大小,同時保留了重要的信息。

物體在圖像中的位置不會影響神經網絡感知其獨特特徵的能力。由於圖像在光照和拍攝角度方面有很大的不同,所以彙集確保了神經網絡能夠檢測出獨特的特徵,儘管存在這些差異。

Max pooling將一個2x2矩陣放入feature map中,並從中選擇最大的值。2x2矩陣在整個feature map中移動,並在每個移動中選擇最大的值。獲得的值形成一個矩陣,稱爲池功能映射。

最大池是重要的,因爲它保持了圖像的獨特功能,同時減少了圖像的大小。這個過程也減少了過度擬合,因爲CNN只接收對分類任務很重要的特徵。

classifier.add(MaxPooling2D(pool_size=(2,2)))

在下一步中,我們將把這些特徵映射轉換爲一種可被深度學習模型接受的格式。

扁平化特徵映射

是時候將所有的特徵映射平鋪成一個單獨的向量了。然後將這個向量傳遞給CNN進行處理。這是通過調用分類器上的Flatten()函數實現的。

classifier.add(Flatten())

在這一點上,特徵是在一個結構中,可以輸入到神經網絡。但是,我們必須添加一個層,在將特徵輸入到神經網絡後,它將爲我們提供輸出。這將是下一步的主題。

向神經網絡添加層

我們將使用上面得到的向量作爲神經網絡的輸入,使用Keras中的稠密函數。

它採用的第一個參數是units,units是隱藏層中的節點數。通過實驗可以確定最佳的單units。第二個參數是激活函數。這一層通常使用ReLu激活函數。

扁平的特徵圖被傳遞給CNN。這個過程涉及到輸入層、全連接層和輸出層。全連通層和人工神經網絡中的隱層是一樣的,只是現在它是全連通的。從輸出層獲得預測的圖像類。

該網絡計算預測和預測過程中的誤差。網絡通過誤差的反向傳播來改進預測。最後的結果是一個介於0和1之間的數字。這個數字表示每個類的概率。

classifier.add(Dense(units = 128, activation='relu'))

現在,我們準備添加輸出層。在這一層,我們將使用sigmoid激活函數,因爲我們期望一個二進制結果。如果我們期望有兩個以上的可能結果,我們就會使用softmax函數。這裏的單位是1,因爲我們只期望類的預測概率。

classifier.add(Dense(units=1, activation='sigmoid'))

我們現在已經有了深度學習模型的所有層。然而,在開始訓練模型之前,我們必須確保減少了訓練過程中出現的錯誤。這最大化了從模型中獲得良好結果的機會。因此,在下一個步驟中,我們將實現一個策略來減少訓練中的錯誤。

編譯CNN

用該compile函數完成CNN的編譯。該函數需要三個參數: 

  • 優化器 

  • 損失函數 

  • 績效指標 

我們將應用梯度下降作爲模型的優化器。在這種情況下,binary_crossentropy損失函數最合適,因爲這是二進制分類問題。梯度下降是一種優化策略,用於減少訓練過程中的誤差,以使誤差最小。這是通過找到成本函數最小的點來實現的。這被稱爲局部最小值,是通過對特定點的斜率求微分並降到成本函數的最小值而發現的。在這裏,我們將使用流行的Adam優化器。

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

現在,我們確定在訓練過程中可以正確處理錯誤,我們已經準備好將分類器適合訓練圖像。

擬合CNN

在擬合CNN之前,我們將使用Keras對圖像進行預處理,以減少過度擬合。這個過程稱爲圖像增強。爲此,我們將使用ImageDataGenerator函數。

from keras.preprocessing.image import ImageDataGenerator

該功能將縮放、縮放、剪切和翻轉圖像。rescale參數對圖像像素值進行重新排序,取值範圍爲0到1。horizontal_flip=真水平翻轉圖像。

train_datagen = ImageDataGenerator(rescale=1./255, shear_range=0.2, zoom_range=0.2, horizontal_flip=True)

之後,我們還需要使用ImageDataGenerator重新調整測試數據圖像。

test_datagen = ImageDataGenerator(rescale=1./255)

接下來,我們將使用train_datagen創建一個訓練集。使用flow_from_directory從當前工作目錄獲取圖像。傳入路徑作爲第一個參數,target_size作爲第二個參數。

target_size是圖像的大小。我們將使用256x256,因爲我們已經在上面指定了它。batch_size是必須通過網絡的圖像數量,以便更新權重。我們將class_mode指定爲二進制,因爲這確實是一個二進制分類問題。

運行以下命令來加載訓練圖像。因爲我們的筆記本和training_set在同一個文件夾中,所以加載圖像不會有任何錯誤。

training_set = train_datagen.flow_from_directory('training_set', target_size=(256, 256), batch_size=32, class_mode='binary')

現在我們將創建一個具有與上面類似參數的測試集。同樣,因爲我們的Jupyter筆記本和test_set在同一個文件夾中,所以測試集的圖像將被加載,沒有任何錯誤。

test_set = test_datagen.flow_from_directory('test_set', target_size=(256, 256), batch_size=32, class_mode='binary')

steps_per_epoch是在完成一個epoch之前從生成器獲得的步驟數。epochs是用來訓練CNN的迭代次數。validation_steps是在停止之前要驗證的步驟總數。

classifier.fit_generator(training_set, steps_per_epoch=40, epochs=25, validation_data=test_set, validation_steps=1000)
Output
Epoch 1/25
40/40 [==============================] - 7341s 1s/step - loss: 8.0578 - acc: 0.5000 - val_loss: 8.0575 - val_acc: 0.5001
<keras.callbacks.History at 0x7f87a8efb7f0>

回顧一下,在這一步中,我們加載了訓練和測試圖像,對它們進行預處理,並將訓練集安裝到我們創建的模型中。接下來就是測試的時候了~

預測

首先,我們必須對圖像進行預處理。這可以在numpy和image的幫助下實現。image將用於加載新圖像,而numpy將用於將它們轉換爲numpy數組。

import numpy as np
from keras.preprocessing import image

我們現在可以加載我們想要預測的圖像。這是使用圖像模塊中的load_img函數完成的。將圖像的位置作爲第一個參數傳遞,並將圖像的大小作爲第二個參數傳遞。使用與模型訓練時相同的圖像大小。

test_image = image.load_img('dog.jpg', target_size=(256, 256))

由於我們使用彩色圖像,我們必須將測試圖像轉換爲3D數組。我們可以使用圖像模塊中的img_to_array函數來實現這一點。在這一點上,我們應該有三維的圖像。然而,在進行預測之前,我們需要傳入第四個參數。此參數對應於批大小。

圖像現在是三維的。你可能已經注意到了,我們是分批傳遞圖像的。在本例中,我們將有一批一個輸入圖像。NumPy中的expand_dims方法將使我們能夠添加第四個維度。

我們傳遞給它的第一個參數是測試圖像,第二個參數是我們想要添加的維度的位置,將它添加到第一個位置,因爲這是神經網絡期望的位置。第一個位置對應軸0:

test_image = np.expand_dims(test_image, axis=0)

現在使用predict方法預測圖像屬於哪一類:

prediction = classifier.predict(test_image)

來自訓練集的class_indices屬性將幫助我們獲得類標籤。

training_set.class_indices

我們得到的輸出將是這樣的:

Output
{'cats': 0, 'dogs': 1}

總結

在這篇文章中,我們使用Keras構建了一個可以對圖像進行分類的深度學習模型。我們結合之前的人工神經網絡知識來實現這個目標。爲了進一步改進模型,可以嘗試使用keras中的不同激活函數或優化器函數。如果想了解更多關於CNNs的信息,可以查看Keras文檔:

https://keras.io/layers/convolutional/

關於更多機器學習、人工智能、增強現實資源和技術乾貨,可以關注公衆號:AIRX社區,共同學習,一起進步!

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章