
在 CNN 的一層中的 patch 中共享權重 w
,無論貓在圖片的哪個位置都可以找到。
當我們試圖識別一個貓的圖片的時候,我們並不在意貓出現在哪個位置。無論是左上角,右下角,它在你眼里都是一只貓。我們希望 CNNs 能夠無差別的識別,這如何做到呢?
如我們之前所見,一個給定的 patch 的分類,是由 patch 對應的權重和偏置項決定的。
如果我們想讓左上角的貓與右下角的貓以同樣的方式被識別,他們的權重和偏置項需要一樣,這樣他們才能以同一種方法識別。
這正是我們在 CNNs 中做的。一個給定輸出層學到的權重和偏置項會共享在輸入層所有的 patch 里。注意,當我們增大濾波器的深度的時候,我們需要學習的權重和偏置項的數量也會增加,因為權重並沒有共享在所有輸出的 channel 里。
共享參數還有一個額外的好處。如果我們不在所有的 patch 里用相同的權重,我們必須對每一個 patch 和它對應的隱藏層神經元學習新的參數。這不利於規模化,特別對於高清圖片。因此,共享權重不僅幫我們平移不變,還給我們一個更小,可以規模化的模型。
Padding

一個 5x5
的網格附帶一個 3x3
的濾波器。來源: Andrej Karpathy。
假設現在有一個 5x5
網格 (如上圖所示) 和一個尺寸為 3x3
stride值為 1
的濾波器(filter)。 下一層的 width 和 height 是多少呢? 如圖中所示,在水平和豎直方向都可以在3個不同的位置放置 patch, 下一層的維度即為 3x3
。下一層寬和高的尺寸就會按此規則縮放。
在理想狀態下,我們可以在層間保持相同的寬度和高度,以便繼續添加圖層,保持網絡的一致性,而不用擔心維度的縮小。如何實現這一構想?其中一種簡單的辦法是,在 5x5
原始圖片的外層包裹一圈 0
,如下圖所示。

加了 0
padding的相同網格。 來源: Andrej Karpathy。
這將會把原始圖片擴展到 7x7
。 現在我們知道如何讓下一層圖片的尺寸維持在 5x5
,保持維度的一致性。
維度
綜合目前所學的知識,我們應該如何計算 CNN 中每一層神經元的數量呢?
輸入層(input layer)維度值為W
, 濾波器(filter)的維度值為 F
(height * width * depth
), stride 的數值為 S
, padding 的數值為 P
, 下一層的維度值可用如下公式表示: (W−F+2P)/S+1
。
我們可以通過每一層神經元的維度信息,得知模型的規模,並了解到我們設定的 filter size 和 stride 如何影響整個神經網絡的尺寸。
介紹
接下來的幾個練習將檢測你對 CNNs 維度的理解,理解維度可以幫你在模型大小和模型質量上,做精確的權衡。你將會了解,一些參數對模型大小的影響會遠大於另外一些。
設置
H = height, W = width, D = depth
- 我們有一個輸入維度是 32x32x3 (HxWxD)
- 20個維度為 8x8x3 (HxWxD) 的濾波器
- 高和寬的stride(步長)都為 2。(S)
- padding 大小為1 (P)
計算新的高度和寬度的公式是:
new_height = (input_height - filter_height + 2 * P)/S + 1 new_width = (input_width - filter_width + 2 * P)/S + 1
卷積層輸出維度
輸出的維度(shape)是什么? 14x14x20
代入公式可以得到下列結果:
(32 - 8 + 2 * 1)/2 + 1 = 14 (32 - 8 + 2 * 1)/2 + 1 = 14
新的深度與濾波器的數量相同,都是 20。
對應如下代碼:
input = tf.placeholder(tf.float32, (None, 32, 32, 3)) filter_weights = tf.Variable(tf.truncated_normal((8, 8, 3, 20))) # (height, width, input_depth, output_depth) filter_bias = tf.Variable(tf.zeros(20)) strides = [1, 2, 2, 1] # (batch, height, width, depth) padding = 'VALID' conv = tf.nn.conv2d(input, filter_weights, strides, padding) + filter_bias
注意,這里的conv
輸出的是 [1, 13, 13, 20]。這是對應 batch size 的 4D 大小,重要的是它不是 [1, 14, 14, 20]。這是因為 TensorFlow 的 padding 算法與上面的並不完全相同。一個可替換方案是把 padding
從 'VALID'
改為'SAME'
,這樣得到的結果是 [1, 16, 16, 20]。如果你想了解 TensorFlow 中的 padding 如何工作,可以看這個文檔。
總之,TensorFlow 使用如下等式計算 SAME
、PADDING
SAME Padding, 輸出的高和寬,計算如下:
out_height
= ceil(float(in_height) / float(strides1))
out_width
= ceil(float(in_width) / float(strides[2]))
VALID Padding, 輸出的高和寬,計算如下:
out_height
= ceil(float(in_height - filter_height + 1) / float(strides1))
out_width
= ceil(float(in_width - filter_width + 1) / float(strides[2]))