深度學習入門,Keras Conv2D類參數詳解
摘要
卷積神經網絡依賴于稱為卷積的計算機視覺/圖像處理技術。 CNN 會自動學習在訓練過程中應用于輸入圖像的內核。
在今天的教程中,我們將討論 Keras Conv2D 類,包括訓練自己的 卷積 神經網絡 (CNN) 時需要調整的最重要參數。我們將使用Keras Conv2D類實現一個簡單的CNN。然后,我們將在 CALTECH-101 數據集上培訓和評估此 CNN。
學完本文您能夠:
快速確定您是否需要使用Keras Conv2D 類的特定參數
決定該特定參數的適當值
有效訓練自己的卷積神經網絡
總的來說,我的目標是幫助減少使用Keras的Conv2D課程時的任何困惑、焦慮或挫折感。通過此教程后,您將對 Keras Conv2D 參數有很強的了解。
在本教程的第一部分,我們將討論 Keras Conv2D 類的參數。
從那里,我們將利用Conv2D類實現一個簡單的凸起神經網絡。
然后,我們將接受 CNN 實施,然后在 CALTECH-101 數據集上進行培訓。
最后,我們將評估網絡并檢查其性能。
讓我們繼續前進,開始吧!
Keras Conv2D 類
Keras Conv2D 類具有以下參數:
tensorflow.keras.layers.Conv2D(filters, kernel_size, strides=(1, 1), padding='valid', data_format=None, dilation_rate=(1, 1), activation=None, use_bias=True, kernel_initializer='glorot_uniform', bias_initializer='zeros', kernel_regularizer=None, bias_regularizer=None, activity_regularizer=None, kernel_constraint=None, bias_constraint=None)
L看起來有點讓人不知所措, 對吧?
你打算如何正確設置這些值?
不用擔心 - 讓我們單獨檢查每個參數,讓您不僅對每個參數控制有很強的了解,而且能夠正確設置每個參數。
filters(過濾器)
圖1: The Keras Conv2D parameter, filters determines 第一個需要的 Conv2D 參數是“過濾 器”卷積層將學習。
網絡架構早期的層(即更接近實際輸入圖像)學習的縱向過濾器更少,而網絡中較深的層(即更接近輸出預測)將學習更多的濾鏡。
與早期的 Conv2D 層相比,中間的 Conv2D 層將學習更多的濾鏡,但過濾器比接近輸出的層更少。讓我們繼續舉一個例子:
model.add(Conv2D(32, (3, 3), padding="same", activation="relu")) model.add(MaxPooling2D(pool_size=(2, 2))) ... model.add(Conv2D(64, (3, 3), padding="same", activation="relu")) model.add(MaxPooling2D(pool_size=(2, 2))) ... model.add(Conv2D(128, (3, 3), padding="same", activation="relu")) model.add(MaxPooling2D(pool_size=(2, 2))) ... model.add(Activation("softmax"))
在第一行,我們總共使用了32過濾器。然后,最大拼接用于減少輸出體積的空間尺寸。
然后,我們使用64的過濾器。同樣,最大池化用于減少空間尺寸。
最后的 Conv2D 層使用128過濾器。
請注意,隨著我們的輸出空間體積正在減少,我們學到的過濾器數量正在增加- 這是設計 CNN 架構的常見做法,我建議您也這樣做。至于選擇適當的數量過濾 器,我幾乎總是建議使用2的次方作為值。
您可能需要根據數據集的復雜性和 (2) 神經網絡的深度來調整確切值,但我建議從前面的 [32,64, 128]范圍內的過濾器開始,在更深的層中增加到[256,512,1024]。
同樣,值的確切范圍可能不同,但從較少的過濾器開始,僅在必要時增加。
kernel_size
圖2: 深度學習 Conv2D 參數,決定了內核的維度。常見的尺寸包括 1×1、3×3、5×5 和 *7×7,*這些尺寸可以以"或"tuples"的身份傳遞。 filter_size:(1, 1)、(3, 3)、(5, 5)、(7, 7)
您需要提供給 Keras Conv2D 類的第二個必需參數是 kernel_size ,它是一個 2 元組,指定了 2D 卷積窗口的寬度和高度。 kernel_size 也必須是奇數。 kernel_size 的典型值包括: (1, 1) , (3, 3) , (5, 5) , (7, 7) 。 很少看到大于 7×7 的內核大小。
那么,你什么時候使用每個?
如果您的輸入圖像大于 128×128,您可以選擇使用大于 3 的內核大小來這樣做的好處:
(1) 學習更大的空間過濾器
(2)幫助減小體積大小。
其他網絡,例如 VGGNet,在整個網絡中專門使用 (3, 3) 過濾器。 更高級的架構如 Inception、ResNet 和 SqueezeNet 設計了整個微架構,它們是網絡內部的“模塊”,可以學習不同尺度(即 1×1、3×3 和 5×5)的局部特征,然后結合輸出。 在下面的 Inception 模塊中可以看到一個很好的例子:
圖3: Inception/GoogLeNet CNN 架構在網絡內部使用“微架構”模塊,學習不同尺度(filter_size)的局部特征,然后組合輸出。
ResNet 架構中的 Residual 模塊使用 1×1 和 3×3 過濾器作為一種降維形式,這有助于保持網絡中的參數數量較少(或在給定網絡深度的情況下盡可能少) ):
圖4: ResNet“殘差模塊”使用 1×1 和 3×3 過濾器進行降維。 這有助于用更少的參數使整個網絡更小。
那么,您應該如何選擇 filter_size ? 首先,檢查你的輸入圖像——它是否大于 128×128? 如果是這樣,請考慮使用 5×5 或 7×7 內核來學習更大的特征,然后快速減少空間維度——然后開始使用 3×3 內核:
model.add(Conv2D(32, (7, 7), activation="relu")) ... model.add(Conv2D(32, (3, 3), activation="relu"))
如果您的圖像小于 128×128,您可能需要考慮堅持使用小點的 1×1 和 3×3 過濾器。
strides
strides 參數是一個 2 元組整數,指定沿輸入體積的 x 和 y 軸的卷積“步長”。
strides 值默認為 (1, 1) ,這意味著:
給定的卷積濾波器應用于輸入體積的當前位置
過濾器向右移動 1 個像素,然后過濾器再次應用于輸入體積
這個過程一直執行,直到我們到達體積的最右側邊界,我們將過濾器向下移動一個像素,然后從最左側重新開始
通常,您會將 strides 參數保留為默認 (1, 1) 值; 但是,您可以偶爾將其增加到 (2, 2) 以幫助減小輸出體積的大小(因為濾波器的步長較大)。 通常,您會看到 2×2 步幅作為最大池化的替代:
model.add(Conv2D(128, (3, 3), strides=(1, 1), activation="relu")) model.add(Conv2D(128, (3, 3), strides=(1, 1), activation="relu")) model.add(Conv2D(128, (3, 3), strides=(2, 2), activation="relu"))
在這里我們可以看到前兩個 Conv2D 層的步幅為 1×1。 最終的 Conv2D 層; 然而,它代替了最大池化層,而是通過跨步卷積減少了輸出體積的空間維度。
2014 年,Springenber 等人。 發表了一篇題為 Striving for Simplicity: The All Convolutional Net 的論文,該論文證明在某些情況下用跨步卷積替換池化層可以提高準確性。
ResNet 是一種流行的 CNN,已經接受了這一發現——如果您查看 ResNet 實現的源代碼(或自己實現它),您會看到 ResNet 響應跨步卷積而不是最大池化以減少兩者之間的空間維度 殘余模塊。
padding
圖5: 應用于帶有填充的圖像的 3×3 內核。 Keras Conv2D 填充參數接受“valid”(無填充)或“same”(填充 + 保留空間維度)。 此動畫貢獻給 StackOverflow。
Keras Conv2D 類的填充參數可以采用以下兩個值之一: valid 或 same 。 使用有效參數,輸入體積不會被零填充,并且空間維度可以通過卷積的自然應用減少。 下面的例子自然會減少我們體積的空間維度:
model.add(Conv2D(32, (3, 3), padding="valid"))
如果您想要保留體積的空間尺寸,以便輸出體積大小與輸入體積大小匹配,那么您需要為 padding 提供“same”的值:
model.add(Conv2D(32, (3, 3), padding="same"))
雖然默認的 Keras Conv2D 值是有效的,但我通常會將其設置為網絡中大多數層的相同值,
然后通過以下任一方式減少我的體積的空間維度:
最大池化
- 跨步卷積
我建議您也使用類似的方法來填充 Keras Conv2D 類。
data_format
圖 6: Keras 作為高級框架,支持多個深度學習后端。 因此,它包括對“channels last”和“channels last”通道排序的支持。
Conv2D 類中的數據格式值可以是 channels_last 或 channels_first : Keras 的 TensorFlow 后端使用最后排序的通道。 Theano 后端使用通道優先排序。
由于以下兩個原因,您通常不必像 Keras 那樣觸及此值:
- 您很有可能使用 TensorFlow 后端到 Keras
- 如果沒有,你可能已經更新了你的 ~/.keras/keras.json 配置文件來設置你的后端和相關的頻道排序
我的建議是永遠不要在你的 Conv2D 類中明確設置 data_format ,除非你有很好的理由這樣做。
dilation_rate
Figure 7: Keras 深度學習 Conv2D 參數 dilation_rate 接受一個 2 元組整數來控制膨脹卷積。
Conv2D 類的 dilation_rate 參數是一個二元組整數,控制膨脹卷積的膨脹率。 擴張卷積是一種基本卷積,僅應用于具有定義間隙的輸入體積,如上圖 7 所示。 您可以在以下情況下使用擴張卷積:
1、您正在處理更高分辨率的圖像,但細粒度的細節仍然很重要
2、 您正在構建一個參數較少的網絡
activation
圖8: Keras 提供了許多常見的激活函數。 Conv2D 的激活參數是一個方便的問題,它允許指定卷積后使用的激活函數。
Conv2D 類的激活參數只是一個方便的參數,允許您提供一個字符串,指定執行卷積后要應用的激活函數的名稱。 在以下示例中,我們執行卷積,然后應用 ReLU 激活函數:
model.add(Conv2D(32, (3, 3), activation="relu"))
等效于:
model.add(Conv2D(32, (3, 3))) model.add(Activation("relu"))
我的建議? 如果您可以使用激活參數,并且它有助于保持您的代碼更清晰——這完全取決于您,并且不會影響您的卷積神經網絡的性能。
use_bias
Conv2D 類的 use_bias 參數控制是否向卷積層添加偏置向量。 通常,您希望將此值保留為 True ,盡管 ResNet 的某些實現會忽略偏差參數。 我建議保持偏見,除非你有充分的理由不這樣做。
kernel_initializer 和bias_initializer
圖9: Keras 為 Conv2D 類提供了許多初始化器。 初始化器可用于幫助更有效地訓練更深的神經網絡。
kernel_initializer 控制用于在實際訓練網絡之前初始化 Conv2D 類中的所有值的初始化方法。 類似地,bias_initializer 控制在訓練開始之前如何初始化偏置向量。 完整的初始化器列表可以在 Keras 文檔中找到; 但是,這是我的建議:
1、不理會bias_initialization——默認情況下它會用零填充(你很少,如果有的話,必須改變bias初始化方法)。
2、kernel_initializer 默認為 glorot_uniform ,這是 Xavier Glorot 統一初始化方法,對于大多數任務來說是完美的; 然而,對于更深層的神經網絡,您可能希望使用 he_normal(MSRA/He 等人的初始化),當您的網絡具有大量參數(即 VGGNet)時,該方法特別有效。
在我實現的絕大多數 CNN 中,我要么使用 glorot_uniform 要么使用 he_normal——我建議你也這樣做,除非你有特定的理由使用不同的初始化程序。
kernel_regularizer、bias_regularizer 和 activity_regularizer
圖10: 應該調整正則化超參數,尤其是在處理大型數據集和非常深的網絡時。 我經常調整 kernel_regularizer 參數以減少過度擬合并增加模型泛化到不熟悉的圖像的能力。
kernel_regularizer 、bias_regularizer 和 activity_regularizer 控制應用于 Conv2D 層的正則化方法的類型和數量。 應用正則化可以幫助您: 減少過擬合的影響 提高模型的泛化能力 在處理大型數據集和深度神經網絡時,應用正則化通常是必須的。 通常你會遇到應用 L1 或 L2 正則化的情況——如果我檢測到過度擬合的跡象,我將在我的網絡上使用 L2 正則化:
from tensorflow.keras.regularizers import l2 ... model.add(Conv2D(32, (3, 3), activation="relu"), kernel_regularizer=l2(0.0005))
您應用的正則化量是您需要針對自己的數據集進行調整的超參數,但我發現 0.0001-0.001 的值是一個很好的開始范圍。
我建議不要管你的偏差正則化器——正則化偏差通常對減少過度擬合的影響很小。
我還建議將 activity_regularizer 保留為其默認值(即,沒有活動正則化)。
雖然權重正則化方法對權重本身進行操作,f(W),其中 f 是激活函數,W 是權重,但活動正則化器對輸出 f(O) 進行操作,其中 O 是層的輸出。
除非有非常具體的原因,您希望對輸出進行正則化,否則最好不要理會這個參數。
kernel_constraint 和bias_constraint
Keras Conv2D 類的最后兩個參數是 kernel_constraint 和 bias_constraint 。
這些參數允許您對 Conv2D 層施加約束,包括非負性、單位歸一化和最小-最大歸一化。
您可以在 Keras 文檔中查看受支持約束的完整列表。
同樣,除非您有特定原因對 Conv2D 層施加約束,否則我建議您單獨保留內核約束和偏差約束。
CALTECH-101(子集)數據集
圖11: CALTECH-101 數據集包含 101 個對象類別,每個類別有 40-80 張圖像。 今天博客文章示例的數據集僅包含其中 4 個類:人臉、豹子、摩托車和飛機(來源)。
CALTECH-101 數據集是一個包含 101 個對象類別的數據集,每個類別有 40 到 800 張圖像。
大多數圖像每類大約有 50 張圖像。
數據集的目標是訓練一個能夠預測目標類別的模型。 在神經網絡和深度學習重新興起之前,最先進的準確率僅為約 65%。
然而,通過使用卷積神經網絡,可以達到 90% 以上的準確率(正如 He 等人在他們 2014 年的論文《用于視覺識別的深度卷積網絡中的空間金字塔池化》中所證明的那樣)。
今天,我們將在數據集的 4 類子集上實現一個簡單而有效的 CNN,它能夠達到 96% 以上的準確率:
Faces: 436 images
Leopards: 201 images
Motorbikes: 799 images
Airplanes: 801 images
我們使用數據集的子集的原因是,即使您沒有 GPU,您也可以輕松地按照此示例從頭開始訓練網絡。
同樣,本教程的目的并不是要在 CALTECH-101 上提供最先進的結果——而是要教您如何使用 Keras 的 Conv2D 類來實現和訓練自定義卷積神經網絡的基礎知識 .
項目結構
數據集地址:
http://www.vision.caltech.edu/Image_Datasets/Caltech101/101_ObjectCategories.tar.gz
linux下載指令:
$ wget http://www.vision.caltech.edu/Image_Datasets/Caltech101/101_ObjectCategories.tar.gz $ tar -zxvf 101_ObjectCategories.tar.gz
項目的樹結構
$ tree --dirsfirst -L 2 -v . ├── 101_ObjectCategories ... │ ├── Faces [436 entries] ... │ ├── Leopards [201 entries] │ ├── Motorbikes [799 entries] ... │ ├── airplanes [801 entries] ... ├── pyimagesearch │ ├── __init__.py │ └── stridednet.py ├── 101_ObjectCategories.tar.gz ├── train.py └── plot.png
第一個目錄 101_ObjectCategories/ 是我們在上一節中提取的數據集。 它包含 102 個文件夾,因此我刪除了今天的博客文章我們不關心的行。 剩下的是前面討論過的四個對象類別的子集。
pyimagesearch/ 模塊不可通過 pip 安裝。 您必須使用“下載”來獲取文件。 在該模塊中,您將找到包含 StrdedNet 類的 stridendet.py。
除了 stridednet.py 之外,我們還將查看根文件夾中的 train.py。 我們的訓練腳本將使用 StridedNet 和我們的小數據集來訓練模型以用于示例目的。
訓練腳本將生成訓練歷史圖 plot.png 。
Keras Conv2D 示例
圖12: 一個名為“StridedNet”的深度學習 CNN 作為今天關于 Keras Conv2D 參數的博客文章的示例。 點擊 展開。
現在我們已經回顧了 (1) Keras Conv2D 類的工作原理和 (2) 我們將訓練網絡的數據集,讓我們繼續實施我們將訓練的卷積神經網絡。 我們今天將使用的 CNN,“StridedNet”,是我為本教程的目的而編寫的。 StridedNet 具有三個重要的特性:
它使用跨步卷積而不是池化操作來減小體積大小
第一個 CONV 層使用 7×7 過濾器,但網絡中的所有其他層使用 3×3 過濾器(類似于 VGG)
MSRA/He 等人。 正態分布算法用于初始化網絡中的所有權重
現在讓我們繼續并實施 StridedNet。
打開一個新文件,將其命名為 stridednet.py ,并插入以下代碼:
# import the necessary packages from tensorflow.keras.models import Sequential from tensorflow.keras.layers import BatchNormalization from tensorflow.keras.layers import Conv2D from tensorflow.keras.layers import Activation from tensorflow.keras.layers import Flatten from tensorflow.keras.layers import Dropout from tensorflow.keras.layers import Dense from tensorflow.keras import backend as K class StridedNet: @staticmethod def build(width, height, depth, classes, reg, init="he_normal"): # initialize the model along with the input shape to be # "channels last" and the channels dimension itself model = Sequential() inputShape = (height, width, depth) chanDim = -1 # if we are using "channels first", update the input shape # and channels dimension if K.image_data_format() == "channels_first": inputShape = (depth, height, width) chanDim = 1
我們所有的 Keras 模塊都在第 2-9 行導入,即 Conv2D。
我們的 StrdedNet 類在第 11 行定義,在第 13 行使用單個構建方法。
build 方法接受六個參數:
width :圖像寬度(以像素為單位)。
height :以像素為單位的圖像高度。
depth :圖像的通道數。
classes :模型需要預測的類數。
reg : 正則化方法。
init :內核初始化程序。
width 、 height 和 depth 參數影響輸入體積形狀。
對于“channels_last”排序,輸入形狀在第 17 行指定,其中深度是最后一個。 我們可以使用 Keras 后端檢查 image_data_format 以查看我們是否需要適應“channels_first”排序(第 22-24 行)。 讓我們看看如何構建前三個 CONV 層:
# our first CONV layer will learn a total of 16 filters, each # Of which are 7x7 -- we'll then apply 2x2 strides to reduce # the spatial dimensions of the volume model.add(Conv2D(16, (7, 7), strides=(2, 2), padding="valid", kernel_initializer=init, kernel_regularizer=reg, input_shape=inputShape)) # here we stack two CONV layers on top of each other where # each layerswill learn a total of 32 (3x3) filters model.add(Conv2D(32, (3, 3), padding="same", kernel_initializer=init, kernel_regularizer=reg)) model.add(Activation("relu")) model.add(BatchNormalization(axis=chanDim)) model.add(Conv2D(32, (3, 3), strides=(2, 2), padding="same", kernel_initializer=init, kernel_regularizer=reg)) model.add(Activation("relu")) model.add(BatchNormalization(axis=chanDim)) model.add(Dropout(0.25))
每個 Conv2D 都使用 model.add 堆疊在網絡上。
請注意,對于第一個 Conv2D 層,我們已經明確指定了 inputShape,以便 CNN 架構可以在某個地方開始和構建。然后,從這里開始,每次調用 model.add 時,前一層都充當下一層的輸入。
考慮到前面討論的 Conv2D 參數,您會注意到我們使用跨步卷積來減少空間維度而不是池化操作。
應用 ReLU 激活(參見圖 8)以及批量歸一化和 dropout。
我幾乎總是推薦批量歸一化,因為它傾向于穩定訓練并使調整超參數更容易。也就是說,它可以使您的訓練時間增加一倍或三倍。明智地使用它。
Dropout 的目的是幫助你的網絡泛化而不是過擬合。當前層的神經元以概率 p 與下一層的神經元隨機斷開連接,因此網絡必須依賴現有的連接。我強烈建議使用 dropout。
我們來看看更多層的StridedNet:
# our first CONV layer will learn a total of 16 filters, each # Of which are 7x7 -- we'll then apply 2x2 strides to reduce # the spatial dimensions of the volume model.add(Conv2D(16, (7, 7), strides=(2, 2), padding="valid", kernel_initializer=init, kernel_regularizer=reg, input_shape=inputShape)) # here we stack two CONV layers on top of each other where # each layerswill learn a total of 32 (3x3) filters model.add(Conv2D(32, (3, 3), padding="same", kernel_initializer=init, kernel_regularizer=reg)) model.add(Activation("relu")) model.add(BatchNormalization(axis=chanDim)) model.add(Conv2D(32, (3, 3), strides=(2, 2), padding="same", kernel_initializer=init, kernel_regularizer=reg)) model.add(Activation("relu")) model.add(BatchNormalization(axis=chanDim)) model.add(Dropout(0.25))
網絡越深,我們學習的過濾器就越多。 在大多數網絡的末尾,我們添加了一個全連接層:
# fully-connected layer model.add(Flatten()) model.add(Dense(512, kernel_initializer=init)) model.add(Activation("relu")) model.add(BatchNormalization()) model.add(Dropout(0.5)) # softmax classifier model.add(Dense(classes)) model.add(Activation("softmax")) # return the constructed network architecture return model
具有 512 個節點的單個全連接層被附加到 CNN。
最后,一個“softmax”分類器被添加到網絡中——這一層的輸出是預測值本身。
這是一個包裝。 如您所見,一旦您知道參數的含義(Conv2D 具有很多參數的潛力),Keras 語法就非常簡單。
讓我們學習如何編寫腳本來使用一些數據訓練 StridedNet!
實現訓練腳本
現在我們已經實現了我們的 CNN 架構,讓我們創建用于訓練網絡的驅動程序腳本。 打開 train.py 文件并插入以下代碼:
# set the matplotlib backend so figures can be saved in the background import matplotlib matplotlib.use("Agg") # import the necessary packages from pyimagesearch.stridednet import StridedNet from sklearn.preprocessing import LabelBinarizer from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report from tensorflow.keras.preprocessing.image import ImageDataGenerator from tensorflow.keras.optimizers import Adam from tensorflow.keras.regularizers import l2 from imutils import paths import matplotlib.pyplot as plt import numpy as np import argparse import cv2 import os
我們在第 2-18 行導入我們的模塊和包。 請注意,我們沒有在任何地方導入 Conv2D。 我們的 CNN 實現包含在 stridednet.py 中,我們的 StridedNet 導入處理它(第 6 行)。
我們的 matplotlib 后端設置在第 3 行——這是必要的,這樣我們可以將我們的繪圖保存為圖像文件,而不是在 GUI 中查看它。 我們在第 7-9 行從 sklearn 導入功能:
LabelBinarizer :用于“one-hot”編碼我們的類標簽。
train_test_split :用于拆分我們的數據,以便我們擁有訓練和評估集。
category_report :我們將使用它來打印評估的統計信息。
在 keras 中,我們將使用:
ImageDataGenerator :用于數據增強。 有關 Keras 數據生成器的更多信息,請參閱上周的博客文章。
Adam:SGD 的優化器替代方案。
l2 :我們將使用的正則化器。 向上滾動以閱讀有關正則化器的信息。 應用正則化可減少過擬合并有助于泛化。
我們將在運行時使用 argparse 來處理命令行參數,而 OpenCV (cv2) 將用于從數據集中加載和預處理圖像。
# construct the argument parser and parse the arguments ap = argparse.ArgumentParser() ap.add_argument("-d", "--dataset", required=True, help="path to input dataset") ap.add_argument("-e", "--epochs", type=int, default=50, help="# of epochs to train our network for") ap.add_argument("-p", "--plot", type=str, default="plot.png", help="path to output loss/accuracy plot") args = vars(ap.parse_args())
我們的腳本可以接受三個命令行參數:
--dataset :輸入數據集的路徑。
--epochs :要訓練的時期數。 默認情況下,我們將訓練 50 個 epoch。
--plot :我們的損失/準確度圖將輸出到磁盤。 此參數包含文件路徑。
默認情況下,它只是 “plot.png” 。 讓我們準備加載我們的數據集:
# initialize the set of labels from the CALTECH-101 dataset we are # going to train our network on LABELS = set(["Faces", "Leopards", "Motorbikes", "airplanes"]) # grab the list of images in our dataset directory, then initialize # the list of data (i.e., images) and class images print("[INFO] loading images...") imagePaths = list(paths.list_images(args["dataset"])) data = [] labels = []
在我們實際加載數據集之前,我們將繼續進行初始化:
LABELS :我們將用于訓練的標簽。
imagePaths :數據集目錄的圖像路徑列表。 我們將很快根據文件路徑中解析的類標簽過濾這些。
data :一個列表,用于保存我們的網絡將在其上訓練的圖像。
標簽:一個列表,用于保存與數據對應的類標簽。
讓我們填充我們的數據和標簽列表:
# loop over the image paths for imagePath in imagePaths: # extract the class label from the filename label = imagePath.split(os.path.sep)[-2] # if the label of the current image is not part of of the labels # are interested in, then ignore the image if label not in LABELS: continue # load the image and resize it to be a fixed 96x96 pixels, # ignoring aspect ratio image = cv2.imread(imagePath) image = cv2.resize(image, (96, 96)) # update the data and labels lists, respectively data.append(image) labels.append(label)
遍歷所有 imagePaths 。
在循環內,我們:
從路徑中提取標簽。
僅過濾 LABELS 集中的類。 這兩行使我們分別跳過不屬于 Faces、Leopards、Motorbikes 或 Airplanes 類的任何標簽。
加載并調整我們的圖像。
最后,將圖像和標簽添加到各自的列表中。
在下一個塊中有四個動作發生:
# convert the data into a NumPy array, then preprocess it by scaling # all pixel intensities to the range [0, 1] data = np.array(data, dtype="float") / 255.0 # perform one-hot encoding on the labels lb = LabelBinarizer() labels = lb.fit_transform(labels) # partition the data into training and testing splits using 75% of # the data for training and the remaining 25% for testing (trainX, testX, trainY, testY) = train_test_split(data, labels, test_size=0.25, stratify=labels, random_state=42) # construct the training image generator for data augmentation aug = ImageDataGenerator(rotation_range=20, zoom_range=0.15, width_shift_range=0.2, height_shift_range=0.2, shear_range=0.15, horizontal_flip=True, fill_mode="nearest")
這些行動包括:
將數據轉換為 NumPy 數組,每個圖像縮放到范圍 [0, 1]。
使用我們的 LabelBinarizer將我們的標簽二值化為“one-hot encoding”。 這意味著我們的標簽現在用數字表示,其中“one-hot”示例可能是: [0, 0, 0, 1] 表示“飛機” [0, 1, 0, 0] 代表“豹” 等等。
將我們的數據拆分為訓練和測試。
初始化我們的 ImageDataGenerator 以進行數據增強。 你可以在這里讀更多關于它的內容。
# initialize the optimizer and model print("[INFO] compiling model...") opt = Adam(lr=1e-4, decay=1e-4 / args["epochs"]) model = StridedNet.build(width=96, height=96, depth=3, classes=len(lb.classes_), reg=l2(0.0005)) model.compile(loss="categorical_crossentropy", optimizer=opt, metrics=["accuracy"]) # train the network print("[INFO] training network for {} epochs...".format( args["epochs"])) H = model.fit(x=aug.flow(trainX, trainY, batch_size=32), validation_data=(testX, testY), steps_per_epoch=len(trainX) // 32, epochs=args["epochs"])
為了評估我們的模型,我們將使用 testX 數據并打印一個分類報告:
# evaluate the network print("[INFO] evaluating network...") predictions = model.predict(x=testX, batch_size=32) print(classification_report(testY.argmax(axis=1), predictions.argmax(axis=1), target_names=lb.classes_))
對于 TensorFlow 2.0+,我們不再使用 .predict_generator 方法; 它被替換為 .predict 并具有相同的函數簽名(即,第一個參數可以是 Python 生成器對象)。
最后,我們將繪制我們的準確率/損失訓練歷史并將其保存到磁盤:
# plot the training loss and accuracy N = args["epochs"] plt.style.use("ggplot") plt.figure() plt.plot(np.arange(0, N), H.history["loss"], label="train_loss") plt.plot(np.arange(0, N), H.history["val_loss"], label="val_loss") plt.plot(np.arange(0, N), H.history["accuracy"], label="train_acc") plt.plot(np.arange(0, N), H.history["val_accuracy"], label="val_acc") plt.title("Training Loss and Accuracy on Dataset") plt.xlabel("Epoch #") plt.ylabel("Loss/Accuracy") plt.legend(loc="lower left") plt.savefig(args["plot"])
訓練和評估
此時,我們已準備好訓練我們的網絡! 打開一個終端,將目錄更改為您下載代碼和 CALTECH-101 數據集的位置,然后執行以下命令:
$ python train.py --dataset 101_ObjectCategories [INFO] loading images... [INFO] compiling model... [INFO] training network for 50 epochs... Epoch 1/50 52/52 [==============================] - 2s 45ms/step - loss: 2.0399 - accuracy: 0.4963 - val_loss: 1.4532 - val_accuracy: 0.5671 Epoch 2/50 52/52 [==============================] - 2s 38ms/step - loss: 1.5679 - accuracy: 0.6748 - val_loss: 1.9899 - val_accuracy: 0.4651 Epoch 3/50 52/52 [==============================] - 2s 39ms/step - loss: 1.3503 - accuracy: 0.7284 - val_loss: 2.0150 - val_accuracy: 0.5510 ... Epoch 48/50 52/52 [==============================] - 2s 38ms/step - loss: 0.5473 - accuracy: 0.9689 - val_loss: 0.5118 - val_accuracy: 0.9857 Epoch 49/50 52/52 [==============================] - 2s 38ms/step - loss: 0.5734 - accuracy: 0.9555 - val_loss: 0.7230 - val_accuracy: 0.9410 Epoch 50/50 52/52 [==============================] - 2s 38ms/step - loss: 0.5697 - accuracy: 0.9653 - val_loss: 0.6236 - val_accuracy: 0.9517 [INFO] evaluating network... precision recall f1-score support Faces 0.97 0.99 0.98 109 Leopards 1.00 0.76 0.86 50 Motorbikes 0.91 1.00 0.95 200 airplanes 0.98 0.93 0.95 200 accuracy 0.95 559 macro avg 0.97 0.92 0.94 559 weighted avg 0.95 0.95 0.95 559
圖13: 我使用 Keras 和 matplotlib 生成的準確率/損失圖用于訓練 StridedNet,這是一個展示 Keras Conv2D 參數的示例 CNN。
如您所見,我們的網絡在測試集上獲得了約 95% 的準確率,并且過擬合最小!
總結
在今天的教程中,我們討論了卷積層和 Keras Conv2D 類。 你現在知道:
Keras Conv2D 類最重要的參數是什么(過濾器、內核大小、步幅、填充)
這些參數的正確值是什么
如何使用 Keras Conv2D 類創建自己的卷積神經網絡
如何訓練您的 CNN 并在示例數據集上對其進行評估
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。