1. 程式人生 > >《TensorFlow:實戰Google深度學習框架》——6.3 卷積神經網路常用結構

《TensorFlow:實戰Google深度學習框架》——6.3 卷積神經網路常用結構

1、卷積層

圖6-8顯示了卷積層神經網路結構中重要的部分:濾波器(filter)或者核心(kernel)。

過濾器可以將當前層神經網路上的一個子節點矩陣轉化為下一層神經網路上的一個單位節點矩陣 。 單位節點矩陣指的是一個長和寬都為1,但深度不限的節點矩陣 。

在一個卷積層巾,過濾器所處理的節點矩陣的長和寬都是由人工指定的,這個節點矩陣的尺寸也被稱之為過濾器的尺寸。常用的過濾器尺寸有 3 × 3 或 5 × 5
過濾器的尺寸指的是一個過濾器輸入節點矩陣的大小(長和寬),而深度指的是輸出單位節點矩陣的深度。如圖 6-8 所示,左側小矩陣的尺寸為過濾器的尺寸,而右側單位矩陣的深度為過濾器的深度。


下邊通過一個樣例來說明卷積運算及前向傳播過程。樣例中將展示如何通過過濾器將一個 2 × 2 × 3 的節點矩陣變化為一個
1 × 1× 5 的單位節點矩陣 。

假設使用w_{x,y,z}^{i}來表示對於輸出單位節點矩陣中的第i個節點,過濾器輸入節點(x,y,z)的權重,使用b^{i}表示第i個輸出節點對應的偏置項引數,那麼單位矩陣中的第i個節點的取值g(i)為:

其中,a_{x,y,z}為過濾器中節點(x, y, z)的取值,f為啟用函式。圖6-9展示了再給定a,w^{0}b^{0}的情況下,使用ReLU作為啟用函式時g(0)的計算過程。

在圖6-9的左側給出了 a 和 w^{0}的取值,這裡通過 3 個二維矩陣來表示一個三維矩陣的取值,其中每一個二維矩陣表示三維矩陣在某一個深度上的取值 。點(·)符號表示點積

,也就是矩陣中對應元素乘積的和。圖 6-9 的右側顯示了g(0)的計算過程。如果給出 w^{1}w^{4}b^{1}b^{4}, 那麼也可以類似地計算出 g(1)到 g(4)的取值。

6-9 使用過濾器計算g(0)取值的過程示意圖

為了更好的視覺化過濾器的移動過程,圖6-10展示了在 3 × 3 矩陣上使用 2 × 2過濾器卷積層結構前向傳播的過程,這裡節點深度為1。

在這個過程中,首先將這個過濾器用於左上角子矩陣,然後移動到右上角矩陣,再到左下角矩陣,最後到右下角矩陣。過濾器每移動一次,可以計算得到一個值(當深度為k時會計算出 k個值) 。將這些數值拼接成一個新的矩陣,就完成了卷積層前向傳播的過程。圖 6-10的右側顯示了過濾器在移動過程中計算得到的結果與新矩陣中節點的對應關係 。

當過濾器的大小不為 1 × 1時,卷積層前向傳播得到的矩陣的尺寸要小於當前層矩陣的尺寸 ,一般是n-k+1,n為矩陣的大小,k為過濾器的大小。6-10 所示,當前層矩陣的大小為 3 × 3 (圖 6-10 左側矩陣〉,而通過卷積層前向傳播演算法之後,得到的矩陣大小為 2 × 2(圖 6-10 右側矩陣)。為了避免尺寸的變化,可以在當前層矩陣的邊界上加入全 0 填充( zero-padding)。這樣可以使得卷積層前向傳播結果矩陣的大小和 當前層矩陣保持一致。 圖 6- 11顯示 了使用全0填充後卷積層前向傳播過程示意圖。

除了使用全 0 填充,還可以通過設定過濾器移動的步長來調整結果矩陣的大小。在圖 10 和圖 6-11 中,過濾器每次都只移動一格。圖 6-12 中顯示了當移動步長為 2 且使用全 0 填充時,卷積層前向傳播的過程。

從圖 6-12上可以看出,當長和寬的步長均為 2 時,過濾器每隔 2 步計算一次結果,所以得到的結果矩陣的長和寬也就都只有原來的一半。以下公式給出了在同時使用全 0 填充時結果矩陣的大小 。

其中out_{length}表示輸出層矩陣的長度,它等於輸入層矩陣長度除以長度方向上的步長向上取整數out_{width}表示輸出層矩陣的寬度,它等於輸入層矩陣寬度除以寬度方向上的步長向上取整值

如果不使用全 0 填充,以下公式給出了結果矩陣的大小 。


在卷積神經網路中,每一個卷積層中使用的過濾器中的引數都是一樣(引數共享)的。這是卷積神經網路一個非常重要的性質。從直觀上理解,共享過濾器的引數可以使得影象上的內容不受位置的影響,同時也可以減少神經網路上的引數。

卷積層的引數個數和圖片的大小無關,它只和過濾器的尺寸、深度以及當前層節點矩陣的深度有關。這使得卷積神經網路可以很好地擴充套件到更大的影象資料上 。

結合過濾器的使用方法和引數共享的機制,圖 6-13 給出了使用了全 0 填充、步長為 2的卷積層前向傳播的計算流程 。
 

6-13 卷積層前向傳播過程樣例圖

圖 6-13 給出了過濾器上權重的取值以及偏置項的取值,通過圖 6-9 中所示的計算方法,可以得到每一個格子的具體取值 。 以下公式給出了左上角格子取值的計算方法,其他格子可以依次類推。


TensorFlow實現卷積計算前向傳播:

#!/usr/bin/env python
# -*- coding:utf-8 -*-

import tensorflow as tf

# 通過 tf.get_variable 的方式建立過濾器的權重變數和偏置項變數。
# 上面介紹了卷積層的引數個數只和濾波器的尺寸、深度以及當前層節點矩陣的深度有關,所以這裡宣告的引數變數是一個四維矩陣,
# 前面兩個維度代表了過濾器的尺寸,第三個維度表示當前層的深度,第四個維度表示過濾器的深度。
filter_weights = tf.get_variable('weights', [5, 5, 3, 16], initialzer=tf.truncated_normal_initializer(seed=0.1))

# 和卷積層的權重類似,當前層矩陣上不同位置的偏置項也是共辜的,所以總共有下個深度個不
# 同的偏E項。本樣例程式碼中 16 為過濾器的深度,也是神經網路中下一層節點矩陣的深度 。
biases = tf.get_variable('biases', [16], initializer=tf.constant_initializer(0.1))

# tf.nn.conv2d 提供了一個非常方便的函式來實現卷積層前向傳播的演算法。這個函式的第一個輸入為當前層的節點矩陣。
# 注意這個矩陣是一個四維矩陣,後面三個維度對應一個節點矩陣,第一維對應一個輸入batch。
# 比如在輸入層,input[O , :, :, :]表示第一張圖片, input[l, :, :, :]表示第二張圖片,以此類推。
# tf.nn.conv2d 第二個引數提供了卷積層的權重,第三個引數為不同維度上的步長。
# 雖然第三個引數提供的是一個長度為 4 的陣列,但是第一維和最後一維的數字要求一定是 l 。
# 這是因為卷積層的步長只對矩陣的長和寬有效。最後一個引數是填充(padding)的方法,
# TensorFlow中提供SAME或是VALID兩種選擇。其中SAME但表示新增全0填充,“VALID”表示不新增
conv = tf.nn.conv2d(input, filter_weights, strides=[1, 1, 1, 1], padding='SAME')

# tf.nn.bias_add提供了一個方便的函式給每一個節點加上偏置項。注意這裡不能直接使用加法!!1
# 因為知陣上不同位置上的節點都需要加上同樣的偏置項。
bias = tf.nn.bias_add(conv, biases)

# 將計算結果通過ReLU啟用函式完成去線性化
actived_conv = tf.nn.relu(bias)