Depthwise Separable Convolution(深度可分離卷積)的實現方式


按照普通卷積-深度卷積-深度可分離卷積的思路總結。

depthwise_conv2d來源於深度可分離卷積,如下論文:

Xception: Deep Learning with Depthwise Separable Convolutions

函數定義如下:

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

除去name參數用以指定該操作的name,data_format指定數據格式,與方法有關的一共五個參數:

input:
指需要做卷積的輸入圖像,要求是一個4維Tensor,具有[batch, height, width, in_channels]這樣的shape,具體含義是[訓練時一個batch的圖片數量, 圖片高度, 圖片寬度, 圖像通道數]

filter:
相當於CNN中的卷積核,要求是一個4維Tensor,具有[filter_height, filter_width, in_channels, channel_multiplier]這樣的shape,具體含義是[卷積核的高度,卷積核的寬度,輸入通道數,輸出卷積乘子],同理這里第三維in_channels,就是參數value的第四維

strides:
卷積的滑動步長。

padding:
string類型的量,只能是”SAME”,”VALID”其中之一,這個值決定了不同邊緣填充方式。

rate:
這個參數的詳細解釋見【Tensorflow】tf.nn.atrous_conv2d如何實現空洞卷積?

結果返回一個Tensor,shape為[batch, out_height, out_width, in_channels * channel_multiplier],注意這里輸出通道變成了in_channels * channel_multiplier
自定義卷積信息做實例:

img1 = tf.constant(value=[[[[1],[2],[3],[4]],[[1],[2],[3],[4]],[[1],[2],[3],[4]],[[1],[2],[3],[4]]]],dtype=tf.float32)
img2 = tf.constant(value=[[[[1],[1],[1],[1]],[[1],[1],[1],[1]],[[1],[1],[1],[1]],[[1],[1],[1],[1]]]],dtype=tf.float32)
img = tf.concat(values=[img1,img2],axis=3)

filter1 = tf.constant(value=0, shape=[3,3,1,1],dtype=tf.float32)
filter2 = tf.constant(value=1, shape=[3,3,1,1],dtype=tf.float32)
filter3 = tf.constant(value=2, shape=[3,3,1,1],dtype=tf.float32)
filter4 = tf.constant(value=3, shape=[3,3,1,1],dtype=tf.float32)
filter_out1 = tf.concat(values=[filter1,filter2],axis=2)
filter_out2 = tf.concat(values=[filter3,filter4],axis=2)
filter = tf.concat(values=[filter_out1,filter_out2],axis=3)
做普通卷積:

out_img = tf.nn.conv2d(input=img, filter=filter, strides=[1,1,1,1], padding='VALID')

普通卷積的實現過程如下系列圖:

做深度卷積:

out_img = tf.nn.depthwise_conv2d(input=img, filter=filter, strides=[1,1,1,1], rate=[1,1], padding='VALID')

 

形象的解釋一下depthwise_conv2d卷積了。看普通的卷積,我們對卷積核每一個out_channel的兩個通道分別和輸入的兩個通道做卷積相加,得到feature map的一個channel,而depthwise_conv2d卷積,我們對每一個對應的in_channel,分別卷積生成兩個out_channel,所以獲得的feature map的通道數量可以用in_channel* channel_multiplier來表達,這個channel_multiplier,就可以理解為卷積核的第四維。
做深度可分離卷積:

 如下,增加定義了point_filter 核。

import tensorflow as tf
img1 = tf.constant(value=[[[[1],[2],[3],[4]],[[1],[2],[3],[4]],[[1],[2],[3],[4]],[[1],[2],[3],[4]]]],dtype=tf.float32)
img2 = tf.constant(value=[[[[1],[1],[1],[1]],[[1],[1],[1],[1]],[[1],[1],[1],[1]],[[1],[1],[1],[1]]]],dtype=tf.float32)
img = tf.concat(values=[img1,img2],axis=3)
filter1 = tf.constant(value=0, shape=[3,3,1,1],dtype=tf.float32)
filter2 = tf.constant(value=1, shape=[3,3,1,1],dtype=tf.float32)
filter3 = tf.constant(value=2, shape=[3,3,1,1],dtype=tf.float32)
filter4 = tf.constant(value=3, shape=[3,3,1,1],dtype=tf.float32)
filter_out1 = tf.concat(values=[filter1,filter2],axis=2)
filter_out2 = tf.concat(values=[filter3,filter4],axis=2)
filter = tf.concat(values=[filter_out1,filter_out2],axis=3)

point_filter = tf.constant(value=1, shape=[1,1,4,4],dtype=tf.float32)
out_img = tf.nn.depthwise_conv2d(input=img, filter=filter, strides=[1,1,1,1],rate=[1,1], padding='VALID')
做深度分層卷積=做深度卷積,然后做pointwise卷積,因此在上代碼添加做pointwise卷積代碼即可完成,如下:

out_img = tf.nn.conv2d(input=out_img, filter=point_filter, strides=[1,1,1,1], padding='VALID')

輸出:

使用官方函數編碼查看結果,即:

out_img = tf.nn.separable_conv2d(input=img, depthwise_filter=filter, pointwise_filter=point_filter,strides=[1,1,1,1], rate=[1,1], padding='VALID')
輸出:

ok,愉快地結束。

 


免責聲明!

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



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