本篇文章是個人翻譯的,如有商業用途,請通知本人謝謝.
Convolutional Layer
CNN最重要的組成部分是卷積層:第一卷積層中的神經元不是連接到輸入圖像中的每一個像素(就像它們在前面的章節中那樣),而是僅僅連接到它們的局部感受野中的像素(參見圖13-2)。 進而,第二卷積層中的每個神經元只與位於第一層中的小矩形內的神經元連接。 這種架構允許網絡專注於第一隱藏層中的低級特徵,然後將其組裝成下一隱藏層中的高級特徵,等等。 這種層次結構在現實世界的圖像中是很常見的,這也是CNN在圖像識別方面效果很好的原因之一。
到目前爲止,我們所看到的所有多層神經網絡都有由一長串神經元組成的層,在輸入到神經網絡之前我們必須將輸入圖像壓縮成1D。 現在,每個圖層都以2D表示,這使得神經元與其相應的輸入進行匹配變得更加容易。
位於給定層的第i行第j列的神經元連接到位於前一層中的神經元的輸出的第i行到第行,第j列到第列.fh和fw是局部感受野的高度和寬度(見圖13-3)。 爲了使圖層具有與前一圖層相同的高度和寬度,通常在輸入周圍添加零,如圖所示。
這被稱爲零填充.
如圖13-4所示,通過將局部感受野隔開,還可以將較大的輸入層連接到更小的層。 兩個連續的感受野之間的距離被稱爲步幅。 在圖中,一個5×7的輸入層(加零填充)連接到一個3×4層,使用3×3的卷積核和一個步幅爲2(在這個例子中,步幅在兩個方向是相同的,但是它並不一定總是如此)。 位於上層第i行第j列的神經元與位於前一層中的神經元的輸出連接的第至行,第列, Sh和Sw是垂直和水平的步幅。
Filters(卷積核)
神經元的權重可以表示爲局部感受野大小的小圖像。 例如,圖13-5顯示了兩個可能的權重集,稱爲flters(或卷積核)。第一個表示爲中間有一條垂直的白線的黑色正方形(除了中間一列外,這是一個充滿0的7×7矩陣,除了中央垂直線是1)。 使用這些權重的神經元會忽略他們的局部感受野的一切,除了中央垂直線(因爲所有的inputs將得到0乘,除位於中央垂直線的)。第二個卷積核是一個黑色的正方形,中間有一條水平的白線。
再一次,使用這些權重的神經元將忽略除了中心水平線之外的局部感受野中的一切。
現在,如果一個圖層中的所有神經元都使用相同的垂直線濾波器(以及相同的偏置項),並且將網絡輸入到圖13-5(底部圖像)中所示的輸入圖像,則該圖層將輸出左上圖像。 請注意,垂直的白線得到增強,其餘的變得模糊。 類似地,如果所有的神經元都使用水平線濾波器,右上角的圖像就是你所得到的。 注意到水平的白線得到增強,其餘的則被模糊了。因此,使用相同濾波器的一個充滿神經元的圖層將爲您提供一個特徵圖,該特徵圖突出顯示圖像中與濾波器最相似的區域。
在訓練過程中,CNN爲其任務找到最有用的過濾器,並學習將它們組合成更復雜的模式(例如,交叉是圖像中垂直過濾器和水平過濾器都活動的區域)。
Stacking Multiple Feature Maps(疊加的多個特徵圖)
到目前爲止,爲了簡單起見,我們已經將每個卷積層表示爲一個薄的二維層,但是實際上它是由幾個相同大小的特徵圖組成的,所以它在3D中被更精確地表示(見圖13-6)。 在一個特徵映射中,所有神經元共享相同的參數(權值共享)(權重和偏置),但是不同的特徵映射可能具有不同的參數。
神經元的感受野與前面描述的相同,但是它延伸到所有先前的層的特徵圖。 簡而言之,卷積層同時對其輸入應用多個濾波器,使其能夠檢測輸入中的任何位置的多個特徵。
事實上,特徵地圖中的所有神經元共享相同的參數會顯着減少模型中的參數數量,但最重要的是,一旦CNN學會識別一個位置的模式,就可以在任何其他位置識別它。 相比之下,一旦一個常規DNN學會識別一個位置的模式,它只能在該特定位置識別它。
而且,輸入圖像也由多個子圖層組成:每個顏色通道一個。 通常有三種:紅色,綠色和藍色(RGB)。 灰度圖像只有一個通道,但是一些圖像可能更多 - 例如捕捉額外光頻(如紅外線)的衛星圖像。
具體地,位於給定卷積層L中的特徵映射k的i行,j列中的神經元連接到前一層(L-1)位於行,列的神經元的輸出.請注意,位於同一行第i列和第j列但位於不同特徵映射中的所有神經元都連接到上一層中完全相同神經元的輸出。
公式13-1在一個總結前面解釋的大的數學公式:它展示瞭如何計算卷積層中給定神經元的輸出。它是計算所有投入的加權總並且加上偏置。
- 是卷積層(L層)特徵映射k中位於第i行第j列的神經元的輸出.
- 如前所述,和是垂直和水平的步幅,和是感受野的高度和寬度,是前一層(第l - 1層)的特徵圖的數量。
- 是位於層L-1,i'行,j'列,特徵圖k'(或者如果前一層是輸入層的通道k')的神經元的輸出。
- 是特徵映射k的偏置項(在L層中)。 您可以將其視爲調整特徵映射k的整體亮度的旋鈕。
- 是層L的特徵映射k中的任何神經元與位於行u,列v(相對於神經元的感受野)的輸入之間的連接權重,以及特徵映射k'。
from sklearn.datasets import load_sample_image
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf
if __name__ == '__main__':
# Load sample images
china = load_sample_image("china.jpg")
flower = load_sample_image("flower.jpg")
dataset = np.array([china, flower], dtype=np.float32)
batch_size, height, width, channels = dataset.shape
# Create 2 filters
filters = np.zeros(shape=(7, 7, channels, 2), dtype=np.float32)
filters[:, 3, :, 0] = 1 # vertical line
filters[3, :, :, 1] = 1 # horizontal line
# Create a graph with input X plus a convolutional layer applying the 2 filters
X = tf.placeholder(tf.float32, shape=(None, height, width, channels))
convolution = tf.nn.conv2d(X, filters, strides=[1,2,2,1], padding="SAME")
with tf.Session() as sess:
output = sess.run(convolution, feed_dict={X: dataset})
plt.imshow(output[0, :, :, 1], cmap="gray") # plot 1st image's 2nd feature map
plt.show()
大部分代碼是不言而喻的,但conv2d()行值得解釋一下: - X是輸入最小批量(4D張量,如前所述)
- 卷積核是應用的一組卷積核(也是一個4D張量,如前所述)。
- 步幅是一個四元素的一維數組,其中兩個中心元素是垂直和水平的步幅(sh和sw)。 第一個和最後一個元素現在必須等於1.他們可能有一天會被用來指定批量步長(跳過一些實例)和頻道步幅(跳過上一層的特徵映射或通道)。
- padding必須是“VALID”或“SAME”:
例如,考慮具有5×5濾波器的卷積層,輸出200個尺寸爲150×100的特徵圖,步長爲1,使用SAME padding。 如果輸入是150×100 RGB圖像(三個通道),則參數的數量是(5×5×3 + 1)×200 = 15,200(+1對應於偏置項),這跟全連接層比較是相當小的.(具有150×100神經元的全連接層,每個連接到所有150×100×3輸入,將具有150 ^ 2×100 ^ 2×3 = 675,000,000個參數!)然而,200個特徵圖中的每一個包含150×100個神經元,並且這些神經元中的每一個都需要計算其5×5×3 = 75個輸入的權重和:總共2.25億次浮點乘法。不像完全連接的層那麼糟糕,但仍然是計算密集型的。 而且,如果使用32位浮點數來表示特徵映射,則卷積層的輸出將佔用RAM的200×150×100×32 = 9600萬位(大約11.4MB)。 這只是一個例子! 如果培訓批次包含100個實例,則該層將佔用超過1 GB的RAM!
一旦你理解了卷積層是如何工作的,池化層很容易掌握。 他們的目標是對輸入圖像進行二次抽樣(即收縮)以減少計算負擔,內存使用量和參數數量(從而限制過度擬合的風險)。 減少輸入圖像的大小也使得神經網絡容忍一點點的圖像移位(位置不變)。
池化層通常獨立於每個輸入通道工作,因此輸出深度與輸入深度相同。 接下來可以看到,在這種情況下,圖像的空間維度(高度和寬度)保持不變,但是通道數目可以減少。
import numpy as np
from sklearn.datasets import load_sample_image
import tensorflow as tf
import matplotlib.pyplot as plt
china = load_sample_image("china.jpg")
flower = load_sample_image("flower.jpg")
dataset = np.array([china, flower], dtype=np.float32)
batch_size, height, width, channels = dataset.shape
# Create 2 filters
filters = np.zeros(shape=(7, 7, channels, 2), dtype=np.float32)
filters[:, 3, :, 0] = 1 # vertical line
filters[3, :, :, 1] = 1 # horizontal line
X = tf.placeholder(tf.float32, shape=(None, height, width, channels))
max_pool = tf.nn.max_pool(X, ksize=[1,2,2,1], strides=[1,2,2,1],padding="VALID")
with tf.Session() as sess:
output = sess.run(max_pool, feed_dict={X: dataset})
plt.imshow(output[0].astype(np.uint8)) # plot the output for the 1st image
plt.show()
ksize參數包含沿輸入張量的所有四個維度的內核形狀:[批量大小,高度,寬度,通道]。 TensorFlow目前不支持在多個實例上合併,因此ksize的第一個元素必須等於1.此外,它不支持在空間維度(高度和寬度)和深度維度上合併,因此ksize [1] 和ksize [2]都必須等於1,否則ksize [3]必須等於1。
LeNet-5架構也許是最廣爲人知的CNN架構。 如前所述,它是由Yann LeCun於1998年創建的,廣泛用於手寫數字識別(MNIST)。 它由表13-1所示的層組成。
- MNIST圖像是28×28像素,但是它們被補零到32×32像素,並且在被喂到網絡之前被歸一化。 網絡的其餘部分不使用任何填充,這就是爲什麼隨着圖像在網絡中的進展,大小不斷縮小。
- 平均池化層比平常稍微複雜一些:每個神經元計算輸入的平均值,然後將結果乘以一個可學習的係數(每個特徵圖一個),並添加一個可學習的偏差項(每個特徵圖一個),然後最後應用激活函數。
- C3地圖中的大多數神經元僅在三個或四個S2地圖(而不是全部六個S2地圖)中連接到神經元。 有關詳細信息,請參閱原始紙張中的表1。
- 輸出層有點特殊:每個神經元不是計算輸入和權向量的點積,而是輸出其輸入向量和其權向量之間的歐幾里德距離的平方。 每個輸出測量圖像屬於特定數字類別的多少。 交叉熵損失函數現在是首選,因爲它更多地懲罰不好的預測,產生更大的梯度,從而更快地收斂。
- 是位於特徵映射i的神經元的標準化輸出,在某行u和列v(注意,在這個等式中我們只考慮位於這個行和列的神經元,所以u和v沒有顯示)。
- 是在ReLU步驟之後,但在歸一化之前的那個神經元的激活。
- k,α,β和r是超參數。 k稱爲偏置,r稱爲深度半徑。
- 是特徵圖的數量。
- 前兩層將圖像的高度和寬度除以4(使其面積除以16),以減少計算負擔。
- 然後,局部響應規範化層確保前面的層學習各種各樣的功能(如前所述)
- 接下來是兩個卷積層,其中第一個像瓶頸層一樣。 正如前面所解釋的,你可以把這一對看作是一個單一的更智能的卷積層。
- 再次,局部響應標準化層確保了先前的層捕捉各種各樣的模式。
- 接下來,最大池化層將圖像高度和寬度減少2,再次加快計算速度。
- 然後是九個“盜夢空間”模塊的高堆棧,與幾個最大池層交織,以降低維度並加速網絡。
- 接下來,平均池化層使用具有VALID填充的特徵映射的大小的內核,輸出1×1特徵映射:這種令人驚訝的策略被稱爲全局平均共享。 它有效地強制以前的圖層產生特徵圖,這些特徵圖實際上是每個目標類的置信圖(因爲其他類型的功能將被平均步驟破壞)。 這樣就不必在CNN的頂部有幾個完全連接的層(如AlexNet),大大減少了網絡中的參數數量,並限制了過度擬合的風險。
- 最後一層是不言自明的:正則化drop out,然後是具有softmax激活函數的完全連接層來輸出估計類的概率。
最後但並非最不重要的是,2015年ILSVRC挑戰賽的贏家Kaiming He等人開發的剩餘網絡(或ResNet),該網絡的打敗前5錯誤率低到3.6%,它使用了一個非常深的CNN,由152層組成。 能夠訓練如此深的網絡的關鍵是使用跳過連接(也稱爲快捷連接):喂到一個層的信號也被添加到位於比堆棧高一點的層的輸出。 讓我們看看爲什麼這是有用的.
TensorFlow還提供了一些其他類型的卷積層:
- conv1d()爲1D輸入創建一個卷積層。 例如,在自然語言處理中這是有用的,其中句子可以表示爲一維單詞陣列,並且接受場覆蓋一些鄰近單詞。
- conv3d()創建一個3D輸入的卷積層,如3D PET掃描。
- atrous_conv2d()創建了一個有趣的卷積層(“àtrous”是法語“with holes”)。 這相當於使用具有通過插入行和列(即,孔)而擴大的濾波器的規則卷積層。 例如,等於[[1,2,3]]的1×3濾波器可以以4的擴張率擴張,導致擴張的濾波器[[1,0,0,0,2,0,0,0,3]]。 這使得卷積層在沒有計算價格的情況下具有更大的局部感受野,並且不使用額外的參數。
- conv2d_transpose()創建了一個轉置卷積層,有時稱爲去卷積層,它對圖像進行上採樣(這個名稱是非常具有誤導性的,因爲這個層並不執行去卷積,這是一個定義良好的數學運算(卷積的逆)) 。這是通過在輸入之間插入零來實現的,所以你可以把它看作是一個使用分數步長的規則卷積層。例如,在圖像分割中,上採樣是有用的:在典型的CNN中,特徵映射越來越小當通過網絡時,所以如果你想輸出一個與輸入大小相同的圖像,你需要一個上採樣層。
- depthwise_conv2d()創建一個深度卷積層,將每個濾波器獨立應用於每個單獨的輸入通道。 因此,如果有fn濾波器和fn'輸入通道,那麼這將輸出fn×fn'特徵映射。
- separable_conv2d()創建一個可分離的卷積層,首先像深度卷積層一樣工作,然後將1×1卷積層應用於結果特徵映射。 這使得可以將濾波器應用於任意的輸入通道組。