深度學習之卷積神經網絡(3)卷積層實現
?在TensorFlow中,既可以通過自定義權值的底層實現方式搭建神經網絡,也可以直接調用現成的卷積層類的高層方式快速搭建復雜網絡。我們主要以2D卷積為例,介紹如何實現卷積神經網絡層。
1. 自定義權值
?在TensorFlow中,通過tf.nn.conv2d函數可以方便地實現2D卷積運算。tf.nn.conv2d基于輸入X:[b,h,w,cin]\boldsymbol X:[b,h,w,c_{in}]X:[b,h,w,cin?]和卷積核W:[k,k,cin,cout]\boldsymbol W:[k,k,c_{in},c_{out}]W:[k,k,cin?,cout?]進行卷積運算,得到輸出O:[b,h′,w′,cout]\boldsymbol O:[b,h',w',c_{out}]O:[b,h′,w′,cout?],其中cinc_{in}cin?表示輸入通道數,coutc_{out}cout?表示卷積核的數量,也是輸出特征圖的通道數。
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, Sequential, losses, optimizers, datasetsx = tf.random.normal([2, 5, 5, 3]) # 模擬輸入,3通道,高寬為5
# 需要根據[k,k,cin,cout]格式創建w張量,4個3*3大小的卷積核
w = tf.random.normal([3, 3, 3, 4])
# 步長為1,padding為0
out = tf.nn.conv2d(x, w, strides=1, padding=[[0, 0], [1, 1], [1, 1], [0, 0]])
# 輸出張量的shape
print('out.shape=', out.shape)
運行結果如下圖所示:
其中padding參數的設置格式為:
padding=[[0, 0], [上, 下], [左, 右], [0, 0]]
例如,上下左右各填充一個單位,則padding參數設置為[[0,0],[1,1],[1,1],[0,0]][[0,0],[1,1],[1,1],[0,0]][[0,0],[1,1],[1,1],[0,0]],實現如下:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, Sequential, losses, optimizers, datasetsx = tf.random.normal([2, 5, 5, 3]) # 模擬輸入,3通道,高寬為5
# 需要根據[k,k,cin,cout]格式創建w張量,4個3*3大小的卷積核
w = tf.random.normal([3, 3, 3, 4])
# 步長為1,padding為1
out = tf.nn.conv2d(x, w, strides=1, padding=[[0, 0], [1, 1], [1, 1], [0, 0]])
# 輸出張量的shape
print('out.shape=', out.shape)
運行結果如下圖所示:
?特別地,通過設置參數padding=‘SAME’、strides=1可以直接得到輸入、輸出同大小的卷積層,其中padding的具體數量由TensorFlow自動計算并完成填充操作。例如:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, Sequential, losses, optimizers, datasetsx = tf.random.normal([2, 5, 5, 3]) # 模擬輸入,3通道,高寬為5
# 需要根據[k,k,cin,cout]格式創建w張量,4個3*3大小的卷積核
w = tf.random.normal([3, 3, 3, 4])
# 步長為1,padding設置為輸入、輸出同大小
# 需要注意的是,padding=same只有在strides=1時才是同大小
out = tf.nn.conv2d(x, w, strides=1, padding='SAME')
# 輸出張量的shape
print('out.shape=', out.shape)
運行結果如下圖所示:
當s<1時,設置padding=‘SAME’將使得輸出高、寬將成1s\frac{1}{s}s1?倍地減少。例如:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, Sequential, losses, optimizers, datasetsx = tf.random.normal([2, 5, 5, 3]) # 模擬輸入,3通道,高寬為5
# 需要根據[k,k,cin,cout]格式創建w張量,4個3*3大小的卷積核
w = tf.random.normal([3, 3, 3, 4])
# 高寬先padding成可以整除3的最小整數6,然后6按3倍減少,得到2*2
out = tf.nn.conv2d(x, w, strides=3, padding='SAME')
# 輸出張量的shape
print('out.shape=', out.shape)
運行結果如下圖所示:
?卷積神經網絡層與全連接層一樣,可以設置網絡帶偏置向量。tf.nn.conv2d函數是沒有實現偏置向量計算的,添加偏置只需要手動累加偏置向量即可。例如:
# 根據[out]格式創建偏置向量
b = tf.zeros([4])
# 在卷積輸出上疊加偏置向量,它會自動broadcasting為[b,h',w',cout]
out = out + b
2. 卷積層類
?通過卷積層類layers.Conv2D可以不需要手動定義卷積核W\boldsymbol WW和偏置b\boldsymbol bb張量,直接調用類實例即可完成卷積層的向前計算,實現更加高層和快捷。在TensorFlow中,API的命名有一定的規律,首字母大寫的對象一般表示類,全部小寫的一般表示函數,如layers.Conv2D表示卷積層類,nn.conv2d表示卷積運算函數。使用類方式會(在創建類時或build時)自動創建需要的權值張量和偏置向量等,用戶不需要記憶卷積核張量的定義格式,因此使用起來更簡單方便,但是靈活性也略低。函數方式的接口需要自行定義權值和偏置等,更加靈活和底層。
?在新建卷積層類時,只需要指定卷積核數量參數filters,卷積核大小kernel_size,步長strides,填充padding等即可。如下創建了4個3×33×33×3大小的卷積核的卷積層,步長為1,padding方案為‘SAME’:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, Sequential, losses, optimizers, datasetsx = tf.random.normal([2, 5, 5, 3]) # 模擬輸入,3通道,高寬為5
layer = layers.Conv2D(4, kernel_size=3, strides=1, padding='SAME')
out = layer(x)
print(out.shape)
運行結果如下圖所示:
?果卷積核高寬不等,步長行列方向不等,此時需要將kernel_size參數設計為tuple格式(kh,kw)(k_h,k_w)(kh?,kw?),strides參數設計為(sh,sw)(s_h,s_w)(sh?,sw?)。如下創建4個3×43×43×4大小的卷積核,豎直方向移動步長sh=2s_h=2sh?=2,水平方向移動步長為sw=1s_w=1sw?=1:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, Sequential, losses, optimizers, datasetsx = tf.random.normal([2, 5, 5, 3]) # 模擬輸入,3通道,高寬為5
layer = layers.Conv2D(4, kernel_size=(3, 4), strides=(2, 1), padding='SAME')
out = layer(x)
print(out.shape)
運行結果如下圖所示:
?創建完成后,通過調用實例即可完成向前計算,例如:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, Sequential, losses, optimizers, datasetsx = tf.random.normal([2, 5, 5, 3]) # 模擬輸入,3通道,高寬為5
layer = layers.Conv2D(4, kernel_size=3, strides=1, padding='SAME')
out = layer(x)
print(out.shape)
?在類Conv2D中,保存了卷積核張量W\boldsymbol WW和偏置b\boldsymbol bb,可以通過類成員trainable_variables直接返回W\boldsymbol WW和b\boldsymbol bb的列表,例如:
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers, Sequential, losses, optimizers, datasetsx = tf.random.normal([2, 5, 5, 3]) # 模擬輸入,3通道,高寬為5
layer = layers.Conv2D(4, kernel_size=3, strides=1, padding='SAME')
out = layer(x)
print(out.shape)
# 輸出所有待優化張量列表
print(layer.trainable_variables)
運行結果如下所示:
(2, 5, 5, 4)
[<tf.Variable 'conv2d/kernel:0' shape=(3, 3, 3, 4) dtype=float32, numpy=
array([[[[-0.06861021, 0.15635735, 0.23594084, 0.08823672],[-0.07579896, 0.28215882, -0.07285108, 0.15759888],[-0.04988965, -0.21231258, -0.08478491, 0.16820547]],…,dtype=float32)>, <tf.Variable 'conv2d/bias:0' shape=(4,) dtype=float32, numpy=array([0., 0., 0., 0.], dtype=float32)>]
通過調用`layer.trainable_variables可以返回Conv2D類維護的W\boldsymbol WW和b\boldsymbol bb張量,這個類成員在獲取網絡層的待優化變量時非常有用。也可以直接調用類實例layer.kernel、layer.bias名訪問W\boldsymbol WW和b\boldsymbol bb張量。
總結
以上是生活随笔為你收集整理的深度学习之卷积神经网络(3)卷积层实现的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。