圖 4 中顯示了卷積層神經網路結構中最重要的部分,這個部分被稱之為過濾器(filter)或者核心(kernel)。因為 tensorflow 文件中將這個結構稱之為過濾器(filter),所以我們將統稱這個結構為過濾器。如圖 4 所示,過濾器可以將當前層神經網路上的乙個子節點
矩陣轉化為下一層神經網路上的乙個單位節點矩陣。單位節點矩陣指的是乙個長和寬都為 1,但深度不限的節點矩陣。
圖 4 卷積層過濾器結構示意圖
在乙個卷積層中,過濾器所處理的節點矩陣的長和寬都是由人工指定的,這個節點矩陣的尺寸也被稱之為過濾器的尺寸。常用的過濾器尺寸有3×3 或 5×5。因為過濾器處理的矩陣深度和當前層神經網路節點矩陣的深度是一致的,所以雖然節點矩陣是三維的,但過濾器的尺寸只需要指定兩個維度。過濾器中另外乙個需要人工指定的設定是處理得到的單位節點矩陣的深度,這個設定稱為過濾器的深度。注意過濾器的尺寸指的是乙個過濾器輸入節點矩陣的大小,而深度指的是輸出單位節點矩陣的深度。如圖 4 所示,左側小矩陣的尺寸為過濾器的尺寸,而右側單位矩陣的深度為過濾器的深度。
如圖 4 所示,過濾器的前向傳播過程就是通過左側小矩陣中的節點計算出右側單位矩陣中節點的過程。為了直觀地解釋過濾器的前向傳播過程,在下面的篇幅中將給出乙個具體的樣例。在這個樣例中將展示如何通過過濾器將乙個 2×2×3 的節點矩陣變化為乙個 1×1×5 的單位節點矩陣。乙個過濾器的前向傳播過程和全連線層相似,它總共需要 2×2×3×5+5=65個引數,其中最後的 +5 為偏置項引數的個數。假設使用 w (x,y,z)i 來表示對於輸出單位節點矩陣中的第 i 個節點,過濾器輸入節點 (x,y,z) 的權重,使用 b i 表示第 i 個輸出節點對應的偏置項引數,那麼單位矩陣中的第 i 個節點的取值 g(i) 為:
其中 a (x,y,z) 為過濾器中節點 (x,y,z) 的取值,f 為啟用函式。如果將 a 和w i 組織成兩個向量,那麼乙個過濾器的計算過程完全可以通過向量乘法來完成。卷積層結構的前向傳播過程就是通過將乙個過濾器從神經網路當前層的左上角移動到右下角,並且在移動中計算每乙個對應的單位矩陣得到的。圖 5 展示了卷積層結構前向傳播的過程。為了更好地視覺化過濾器的移動過程,圖 5 中使用的節點矩陣深度都為 1。在圖 5 中,展示了在 3×3矩陣上使用 2×2 過濾器的卷積層前向傳播過程。在這個過程中,首先將這個過濾器用於左上角子矩陣,然後移動到左下角矩陣,再到右上角矩陣,最後到右下角矩陣。過濾器每移動一次,可以計算得到乙個值(當深度為k 時會計算出 k 個值)。將這些數值拼接成乙個新的矩陣,就完成了卷積層前向傳播的過程。圖 5 的右側顯示了過濾器在移動過程中計算得到的結果與新矩陣中節點的對應關係。
在圖 5 中,只講解了移動過濾器的方式,沒有涉及到過濾器中的引數如何設定。在卷積神經網路中,每乙個卷積層中使用的過濾器中的引數都是一樣的。這是卷積神經網路乙個非常重要的性質。從直觀上理解,共享過濾器的引數可以使得影象上的內容不受位置的影響。以 mnist 手寫體數字識別為例,無論數字「1」出現在左上角還是右下角,的種類都是不變的。因為在左上角和右下角使用的過濾器引數相同,所以通過卷積層之後無論數字在影象上的哪個位置,得到的結果都一樣。
圖5 卷積層前向傳播過程示意圖
共享每乙個卷積層中過濾器中的引數可以巨幅減少神經網路上的引數。以 cifar-10 問題為例,輸入層矩陣的維度是 32×32×3。假設第一層卷積層使用尺寸為 5×5,深度為 16 的過濾器,那麼這個卷積層的引數個數為 5×5×3×16+16=1216 個。上文提到過,使用 500 個隱藏節點的全連線層將有 150 萬個引數。相比之下,卷積層的引數個數要遠遠小於全連線層。而且卷積層的引數個數和的大小無關,它只和過濾器的尺寸、深度以及當前層節點矩陣的深度有關。這使得卷積神經網路可以很好地擴充套件
到更大的影象資料上。
圖6 卷積層前向傳播過程樣例圖
結合過濾器的使用方法和引數共享的機制,圖 6 給出了使用了全 0 填充、移動步長為 2 的卷積層前向傳播的計算流程。下面的公式給出了左上角格仔取值的計算方法,其他格仔可以依次類推。
relu(0×1+0×(-1)+0×0+1×2+1)=relu(3)=3
tensorflow 對卷積神經網路提供了非常好的支援,下面的程式實現了乙個卷積層的前向傳播過程。從以下**可以看出,通過 tensorflow 實現卷積層是非常方便的。
# 通過tf.get_variable的方式建立過濾器的權重變數和偏置項變數。上面介紹了卷積層
# 的引數個數只和過濾器的尺寸、深度以及當前層節點矩陣的深度有關,所以這裡宣告的引數變
# 量是乙個四維矩陣,前面兩個維度代表了過濾器的尺寸,第三個維度表示當前層的深度,第四
# 個維度表示過濾器的深度。
filter_weight = tf.get_variable(
'weights', [5, 5, 3, 16],
initializer=tf.truncated_normal_initializer(stddev=0.1))
# 和卷積層的權重類似,當前層矩陣上不同位置的偏置項也是共享的,所以總共有下一層深度個不
# 同的偏置項。本樣例**中16為過濾器的深度,也是神經網路中下一層節點矩陣的深度。
biases = tf.get_variable(
'biases', [16], initializer=tf.constant_initializer(0.1))
# tf.nn.conv2d提供了乙個非常方便的函式來實現卷積層前向傳播的演算法。這個函式的第乙個輸
# 入為當前層的節點矩陣。注意這個矩陣是乙個四維矩陣,後面三個維度對應乙個節點矩陣,第一
# 維對應乙個輸入batch。比如在輸入層,input[0,:,:,:]表示第一張,input[1,:,:,:]
# 表示第二張,以此類推。tf.nn.conv2d第二個引數提供了卷積層的權重,第三個引數為不
# 同維度上的步長。雖然第三個引數提供的是乙個長度為4的陣列,但是第一維和最後一維的數字
# 要求一定是1。這是因為卷積層的步長只對矩陣的長和寬有效。最後乙個引數是填充(padding)
# 的方法,tensorflow中提供same或是valid兩種選擇。其中same表示新增全0填充,
# 「valid」表示不新增。
conv = tf.nn.conv2d(
input, filter_weight, strides=[1, 1, 1, 1], padding='same')
# tf.nn.bias_add提供了乙個方便的函式給每乙個節點加上偏置項。注意這裡不能直接使用加
# 法,因為矩陣上不同位置上的節點都需要加上同樣的偏置項。雖然下一層神經網路的大小為
# 2×2,但是偏置項只有乙個數(因為深度為1),而2×2矩陣中的每乙個值都需要加上這個
# 偏置項。
bias = tf.nn.bias_add(conv, biases)
# 將計算結果通過relu啟用函式完成去線性化。
actived_conv = tf.nn.relu(bias)
面向機器智慧型的TensorFlow實戰1 安裝
1 選擇安裝環境 三種環境 一般而言,如果準備在單機上安裝和使用tensorflow,建議採用virtualenv或conda,能夠以較小的代價解決依賴衝突問題,且易於設定。如果準備將tensorflow 部署到一台或多台伺服器上,則值得床架乙個docker容器映象。筆者不推薦既不使用虛擬環境,也不...
Flutter實戰入門系列 1
flutter是google力推的進行跨平台開發應用的工具。本系列文章的敘述環境為mac os 10.14.5,android studio 3.4.1,xcode 10.2.1 本系列將介紹開發環境的搭建和建立第乙個flutter應用。假設我們已經安裝了android studio和xcode。我...
Tensorflow實戰 張量
import tensorflow as tf tf.constant 是乙個計算,這個計算的結果為乙個張量,儲存在變數a中。a tf.constant 1.0,2.0 name a b tf.constant 2.0,3.0 name b result tf.add a,b,name add pr...