CNN中的卷積核及TensorFlow中卷積的各種實現


聲明:

1. 我和每一個應該看這篇博文的人一樣,都是初學者,都是小菜鳥,我發布博文只是希望加深學習印象並與大家討論。

2. 我不確定的地方用了“應該”二字

首先,通俗說一下,CNN的存在是為了解決兩個主要問題:

1. 權值太多。這個隨便一篇博文都能解釋

2. 語義理解。全連接網絡結構處理每一個像素時,其相鄰像素與距離很遠的像素無差別對待,並沒有考慮圖像內容的空間結構。換句話說,打亂圖像像素的輸入順序,結果不變。

然后,CNN中的卷積核的一個重要特點是它是需要網絡自己來學習的。這一點很簡單也很重要:一般的卷積核如sobel算子、平滑算子等,都是人們根據數學知識得到的,比如求導,平均等等。所以一般的人工卷積核是不能放進卷積層的,這有悖於“學習”的概念。我們神經網絡就是要自己學習卷積核的參數。來提取人們想不到甚至是無法理解的空間結構或特征。其他特征包括全局共享(一個卷積核滑動一整張圖像),多核卷積(用一個卷積核只能提取一種空間結構或特征)。

最后,說一說TensorFlow中卷積的各種實現API(經常用到的):

import tensorflow as tf #自己去加,下面用tf代替tensorflow模塊

1  tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, data_format=None, Name=None)

#輸入:

# input: 一個張量。數據類型必須是float32或者float64。記住這個張量為四維[batch, in_height, in_width, in_channels],batch應該是指每次feed給網絡的數據的個數,和mini-batch gradient descend有關;中間是長寬兩項;最后是通道,灰度為1,RGB等為3

# filter: 輸入的卷積核,也是四維[filter_height,filter_width,in_channels,channel_multiplier],前兩維是尺寸比如3x3,2x2(注意是可以2x2的,這個涉及到非對稱卷積核),第三維等於 in_channels,第四維是輸出通道數,也就是你要輸出的通道數,也就是你要使用的卷積核數

# strides: 一個長度是4的一維整數類型的數組,一般設為[1,1,1,1],注意第一個和第四個"1”固定不變(我試過改了結果不變,並且沒有意義)中間的兩個1,就是橫向步長和縱向步長,意思是卷積核不一定是一步一步的滑動的。

# padding: 有兩個值‘SAME’和'VALID',前者使得卷積后圖像尺寸不變;后者尺寸變化

# use_cudnn_on_gpu: 在gpu上處理,tensorflow-gpu都默認設為了True

# data_format=None, Name=None 這兩項請博友們自己查查,應該問題不大,Name應該與TensorFlow的圖結構以及Session(會話)有關系;data_format的默認值應該為'NHWC',及張量維度的順序應該是batch個數,高度,寬度和通道數。

可以說, tf.nn.conv2d就是處理的典型的卷積,例子和圖示如下:

1 input_data =tf.Variable(np.random.rand(10,9,9,3),dtype=np.float32)
2 filter_data = tf.Variable(np.random.rand(2,2,3,2),dtype=np.float32)
3 y = tf.nn.conv2d(input_data,filter_data,strides=[2,5,5,3],padding='SAME') #中間5,5大家自己設置一下,自己感受
4 y.shape

結果是 TensorShape([Dimension(10), Dimension(2), Dimension(2), Dimension(2)]) 

 

2  tf.nn.depthwise_conv2d(input, filter, strides, padding, rate=None, name=None, data_format=None)

與1的不同有有兩點:

1. depthwise_conv2d將不同的卷積核獨立地應用在in_channels的每個通道:我們一般對於三通道圖像做卷積,都是先加權求和再做卷積(注意先加權求和再卷積與先卷積再加權求和結果一樣),形象化描述就是我先把3通道壓扁成1通道,在把它用x個卷積核提溜成x通道(或者我先把3通道用x個卷積核提溜成3x個通道,再分別壓扁得到x通道); 而depthwise_conv2d就不加權求和了,直接卷積,所以最后輸出通道的總數是in_channels*channel_multiplier

2. rate參數是一個1維向量,of size 2,由兩個元素組成,這個參數與atrous convolution(孔卷積)和感受野有關,我下面會給出參考鏈接。注意, If it is greater than 1, then all values of strides must be 1. 

 

3 tf.nn.separable_conv2d(input, depthwise_filter, pointwise_filter, strides, padding, rate=None, name=None, data_format=None)

#特殊參數:

# depthwise_filter。一個張量,數據維度是四維[filter_height,filter_width,in_channels,channel_multiplier],如1中所述,但是卷積深度是1,如2中所述。

# pointwise_filter。一個張量,數據維度是四維[1,1,in_channels*channel_multiplier,out_channel]

tf.nn.separable_conv2d是利用幾個分離的卷積核去做卷積。首先用depthwise_filter做卷積,效果與depthwise_conv2d相同,然后用1x1的卷積核pointwise_filter去做卷積。實例圖如下:

這個理解困難就是最后一步,pointwise_filter是什么?需要說明的是,我只知道原理,我還不知道這樣做的目的是什么。最后pointwise原理很簡單,就和2中我說過的一樣,我先把DM*in_channels(即in_channels*channel_multiplier)個通道壓扁成1個通道,再用pointwise_filter這個1*1的卷積核提溜成out_channel個通道,所以pointwise_filter相當於out_channel個scalar。

例子如下:

1 1 input_data = tf.Variable(np.random.rand(10,9,9,3),dtype=np.float32)
2 2 depthwise_filter = tf.Variable(np.random.rand(2,2,3,5),dtype=np.float32)
3 3 pointerwise_filter = tf.Variable(np.random.rand(1,1,15,20),dtype=np.float32)
4 4 #out_channels >= channel_multiplier * in_channels
5 5 y =tf.nn.separable_conv2d(input_data, depthwise_filter, pointerwise_filter, strides = [1,1,1,1], padding='SAME')
6 y.shape

結果是 TensorShape([Dimension(10), Dimension(9), Dimension(9), Dimension(20)])

 

參考資料:

《深度學習原理與Tensorflow實踐》
《TensorFlow技術解析與實戰》

Tensorflow(API MASTERT),也就是API Documentation

孔卷積或者擴張卷積

圖的出處

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM