【轉(zhuǎn)載】TF-卷積函數(shù) tf.nn.conv2d 介紹

原文:www.cnblogs.com/welhzh/p/6607581.html

tf.nn.conv2d是TensorFlow里面實(shí)現(xiàn)卷積的函數(shù),參考文檔對(duì)它的介紹并不是很詳細(xì),實(shí)際上這是搭建卷積神經(jīng)網(wǎng)絡(luò)比較核心的一個(gè)方法,非常重要

tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)

除去name參數(shù)用以指定該操作的name,與方法有關(guān)的一共五個(gè)參數(shù):

第一個(gè)參數(shù)input:指需要做卷積的輸入圖像,它要求是一個(gè)Tensor,具有[batch, in_height, in_width, in_channels]這樣的shape,具體含義是[訓(xùn)練時(shí)一個(gè)batch的圖片數(shù)量, 圖片高度, 圖片寬度, 圖像通道數(shù)],注意這是一個(gè)4維的Tensor,要求類型為float32和float64其中之一

第二個(gè)參數(shù)filter:相當(dāng)于CNN中的卷積核,它要求是一個(gè)Tensor,具有[filter_height, filter_width, in_channels, out_channels]這樣的shape,具體含義是[卷積核的高度,卷積核的寬度,圖像通道數(shù),卷積核個(gè)數(shù)],要求類型與參數(shù)input相同,有一個(gè)地方需要注意,第三維in_channels,就是參數(shù)input的第四維

第三個(gè)參數(shù)strides:卷積時(shí)在圖像每一維的步長(zhǎng),這是一個(gè)一維的向量,長(zhǎng)度4,strides取[1,stride,stride,1]

第四個(gè)參數(shù)padding:string類型的量,只能是"SAME","VALID"其中之一,這個(gè)值決定了不同的卷積方式(后面會(huì)介紹)

第五個(gè)參數(shù):use_cudnn_on_gpu:bool類型,是否使用cudnn加速,默認(rèn)為true

結(jié)果返回一個(gè)Tensor,這個(gè)輸出,就是我們常說(shuō)的feature map,shape仍然是[batch, height, width, channels]這種形式。

那么TensorFlow的卷積具體是怎樣實(shí)現(xiàn)的呢,用一些例子去解釋它:

1.考慮一種最簡(jiǎn)單的情況,現(xiàn)在有一張3×3單通道的圖像(對(duì)應(yīng)的shape:[1,3,3,1]),用一個(gè)1×1的卷積核(對(duì)應(yīng)的shape:[1,1,1,1])去做卷積,最后會(huì)得到一張3×3的feature map

2.增加圖片的通道數(shù),使用一張3×3五通道的圖像(對(duì)應(yīng)的shape:[1,3,3,5]),用一個(gè)1×1的卷積核(對(duì)應(yīng)的shape:[1,1,1,1])去做卷積,仍然是一張3×3的feature map,這就相當(dāng)于每一個(gè)像素點(diǎn),卷積核都與該像素點(diǎn)的每一個(gè)通道做卷積。

input = tf.Variable(tf.random_normal([1,3,3,5]))

filter= tf.Variable(tf.random_normal([1,1,5,1]))

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

3.把卷積核擴(kuò)大,現(xiàn)在用3×3的卷積核做卷積,最后的輸出是一個(gè)值,相當(dāng)于情況2的feature map所有像素點(diǎn)的值求和

input = tf.Variable(tf.random_normal([1,3,3,5]))

filter= tf.Variable(tf.random_normal([3,3,5,1]))

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

4.使用更大的圖片將情況2的圖片擴(kuò)大到5×5,仍然是3×3的卷積核,令步長(zhǎng)為1,輸出3×3的feature map

input = tf.Variable(tf.random_normal([1,5,5,5]))

filter= tf.Variable(tf.random_normal([3,3,5,1]))

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

注意我們可以把這種情況看成情況2和情況3的中間狀態(tài),卷積核以步長(zhǎng)1滑動(dòng)遍歷全圖,以下x表示的位置,表示卷積核停留的位置,每停留一個(gè),輸出feature map的一個(gè)像素

.....

.xxx.

.xxx.

.xxx.

.....

5.上面我們一直令參數(shù)padding的值為‘VALID’,當(dāng)其為‘SAME’時(shí),表示卷積核可以停留在圖像邊緣,如下,輸出5×5的feature map

input = tf.Variable(tf.random_normal([1,5,5,5]))

filter= tf.Variable(tf.random_normal([3,3,5,1]))

op= tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')

xxxxx

xxxxx

xxxxx

xxxxx

xxxxx

6.如果卷積核有多個(gè)

input = tf.Variable(tf.random_normal([1,5,5,5]))

filter= tf.Variable(tf.random_normal([3,3,5,7]))

op= tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')

此時(shí)輸出7張5×5的feature map

7.步長(zhǎng)不為1的情況,文檔里說(shuō)了對(duì)于圖片,因?yàn)橹挥袃删S,通常strides取[1,stride,stride,1]

input = tf.Variable(tf.random_normal([1,5,5,5]))

filter= tf.Variable(tf.random_normal([3,3,5,7]))

op= tf.nn.conv2d(input, filter, strides=[1, 2, 2, 1], padding='SAME')

此時(shí),輸出7張3×3的feature map

x.x.x

.....

x.x.x

.....

x.x.x

8.如果batch值不為1,同時(shí)輸入10張圖

input = tf.Variable(tf.random_normal([10,5,5,5]))

filter= tf.Variable(tf.random_normal([3,3,5,7]))

op= tf.nn.conv2d(input, filter, strides=[1, 2, 2, 1], padding='SAME')

每張圖,都有7張3×3的feature map,輸出的shape就是[10,3,3,7]

最后,把程序總結(jié)一下:

import tensorflow as tf

# tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)

# 除去name參數(shù)用以指定該操作的name,與方法有關(guān)的一共五個(gè)參數(shù):

#

# 第一個(gè)參數(shù)input:指需要做卷積的輸入圖像,它要求是一個(gè)Tensor,具有[batch, in_height, in_width, in_channels]這樣的shape,具體含義是[訓(xùn)練時(shí)一個(gè)batch的圖片數(shù)量, 圖片高度, 圖片寬度, 圖像通道數(shù)],注意這是一個(gè)4維的Tensor,要求類型為float32和float64其中之一

#

# 第二個(gè)參數(shù)filter:相當(dāng)于CNN中的卷積核,它要求是一個(gè)Tensor,具有[filter_height, filter_width, in_channels, out_channels]這樣的shape,具體含義是[卷積核的高度,卷積核的寬度,圖像通道數(shù),卷積核個(gè)數(shù)],要求類型與參數(shù)input相同,有一個(gè)地方需要注意,第三維in_channels,就是參數(shù)input的第四維

#

# 第三個(gè)參數(shù)strides:卷積時(shí)在圖像每一維的步長(zhǎng),這是一個(gè)一維的向量,長(zhǎng)度4

#

# 第四個(gè)參數(shù)padding:string類型的量,只能是"SAME","VALID"其中之一,這個(gè)值決定了不同的卷積方式(后面會(huì)介紹)

#

# 第五個(gè)參數(shù):use_cudnn_on_gpu:bool類型,是否使用cudnn加速,默認(rèn)為true

#

# 結(jié)果返回一個(gè)Tensor,這個(gè)輸出,就是我們常說(shuō)的feature map

oplist=[]

# [batch, in_height, in_width, in_channels]

input_arg? = tf.Variable(tf.ones([1, 3, 3, 5]))

# [filter_height, filter_width, in_channels, out_channels]

filter_arg = tf.Variable(tf.ones([1 ,1 , 5 ,1]))

op2 = tf.nn.conv2d(input_arg, filter_arg, strides=[1,1,1,1], use_cudnn_on_gpu=False, padding='VALID')

oplist.append([op2, "case 2"])

# [batch, in_height, in_width, in_channels]

input_arg? = tf.Variable(tf.ones([1, 3, 3, 5]))

# [filter_height, filter_width, in_channels, out_channels]

filter_arg = tf.Variable(tf.ones([3 ,3 , 5 ,1]))

op2 = tf.nn.conv2d(input_arg, filter_arg, strides=[1,1,1,1], use_cudnn_on_gpu=False, padding='VALID')

oplist.append([op2, "case 3"])

# [batch, in_height, in_width, in_channels]

input_arg? = tf.Variable(tf.ones([1, 5, 5, 5]))

# [filter_height, filter_width, in_channels, out_channels]

filter_arg = tf.Variable(tf.ones([3 ,3 , 5 ,1]))

op2 = tf.nn.conv2d(input_arg, filter_arg, strides=[1,1,1,1], use_cudnn_on_gpu=False, padding='VALID')

oplist.append([op2, "case 4"])

# [batch, in_height, in_width, in_channels]

input_arg? = tf.Variable(tf.ones([1, 5, 5, 5]))

# [filter_height, filter_width, in_channels, out_channels]

filter_arg = tf.Variable(tf.ones([3 ,3 , 5 ,1]))

op2 = tf.nn.conv2d(input_arg, filter_arg, strides=[1,1,1,1], use_cudnn_on_gpu=False, padding='SAME')

oplist.append([op2, "case 5"])

# [batch, in_height, in_width, in_channels]

input_arg? = tf.Variable(tf.ones([1, 5, 5, 5]))

# [filter_height, filter_width, in_channels, out_channels]

filter_arg = tf.Variable(tf.ones([3 ,3 , 5 ,7]))

op2 = tf.nn.conv2d(input_arg, filter_arg, strides=[1,1,1,1], use_cudnn_on_gpu=False, padding='SAME')

oplist.append([op2, "case 6"])

# [batch, in_height, in_width, in_channels]

input_arg? = tf.Variable(tf.ones([1, 5, 5, 5]))

# [filter_height, filter_width, in_channels, out_channels]

filter_arg = tf.Variable(tf.ones([3 ,3 , 5 ,7]))

op2 = tf.nn.conv2d(input_arg, filter_arg, strides=[1,2,2,1], use_cudnn_on_gpu=False, padding='SAME')

oplist.append([op2, "case 7"])

# [batch, in_height, in_width, in_channels]

input_arg? = tf.Variable(tf.ones([4, 5, 5, 5]))

# [filter_height, filter_width, in_channels, out_channels]

filter_arg = tf.Variable(tf.ones([3 ,3 , 5 ,7]))

op2 = tf.nn.conv2d(input_arg, filter_arg, strides=[1,2,2,1], use_cudnn_on_gpu=False, padding='SAME')

oplist.append([op2, "case 8"])

with tf.Session() as a_sess:

a_sess.run(tf.global_variables_initializer())

for aop in oplist:

print("----------{}---------".format(aop[1]))

print(a_sess.run(aop[0]))

print('---------------------\n\n')

結(jié)果是這樣的:



----------case 6---------

[[[[ 20. 20. 20. 20. 20. 20. 20.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 20. 20. 20. 20. 20. 20. 20.]]

[[ 30. 30. 30. 30. 30. 30. 30.]

[ 45. 45. 45. 45. 45. 45. 45.]

[ 45. 45. 45. 45. 45. 45. 45.]

[ 45. 45. 45. 45. 45. 45. 45.]

[ 30. 30. 30. 30. 30. 30. 30.]]

[[ 30. 30. 30. 30. 30. 30. 30.]

[ 45. 45. 45. 45. 45. 45. 45.]

[ 45. 45. 45. 45. 45. 45. 45.]

[ 45. 45. 45. 45. 45. 45. 45.]

[ 30. 30. 30. 30. 30. 30. 30.]]

[[ 30. 30. 30. 30. 30. 30. 30.]

[ 45. 45. 45. 45. 45. 45. 45.]

[ 45. 45. 45. 45. 45. 45. 45.]

[ 45. 45. 45. 45. 45. 45. 45.]

[ 30. 30. 30. 30. 30. 30. 30.]]

[[ 20. 20. 20. 20. 20. 20. 20.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 20. 20. 20. 20. 20. 20. 20.]]]]

---------------------

----------case 7---------

[[[[ 20. 20. 20. 20. 20. 20. 20.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 20. 20. 20. 20. 20. 20. 20.]]

[[ 30. 30. 30. 30. 30. 30. 30.]

[ 45. 45. 45. 45. 45. 45. 45.]

[ 30. 30. 30. 30. 30. 30. 30.]]

[[ 20. 20. 20. 20. 20. 20. 20.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 20. 20. 20. 20. 20. 20. 20.]]]]

---------------------

----------case 8---------

[[[[ 20. 20. 20. 20. 20. 20. 20.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 20. 20. 20. 20. 20. 20. 20.]]

[[ 30. 30. 30. 30. 30. 30. 30.]

[ 45. 45. 45. 45. 45. 45. 45.]

[ 30. 30. 30. 30. 30. 30. 30.]]

[[ 20. 20. 20. 20. 20. 20. 20.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 20. 20. 20. 20. 20. 20. 20.]]]

[[[ 20. 20. 20. 20. 20. 20. 20.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 20. 20. 20. 20. 20. 20. 20.]]

[[ 30. 30. 30. 30. 30. 30. 30.]

[ 45. 45. 45. 45. 45. 45. 45.]

[ 30. 30. 30. 30. 30. 30. 30.]]

[[ 20. 20. 20. 20. 20. 20. 20.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 20. 20. 20. 20. 20. 20. 20.]]]

[[[ 20. 20. 20. 20. 20. 20. 20.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 20. 20. 20. 20. 20. 20. 20.]]

[[ 30. 30. 30. 30. 30. 30. 30.]

[ 45. 45. 45. 45. 45. 45. 45.]

[ 30. 30. 30. 30. 30. 30. 30.]]

[[ 20. 20. 20. 20. 20. 20. 20.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 20. 20. 20. 20. 20. 20. 20.]]]

[[[ 20. 20. 20. 20. 20. 20. 20.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 20. 20. 20. 20. 20. 20. 20.]]

[[ 30. 30. 30. 30. 30. 30. 30.]

[ 45. 45. 45. 45. 45. 45. 45.]

[ 30. 30. 30. 30. 30. 30. 30.]]

[[ 20. 20. 20. 20. 20. 20. 20.]

[ 30. 30. 30. 30. 30. 30. 30.]

[ 20. 20. 20. 20. 20. 20. 20.]]]]

---------------------

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容