Tensorflow中的卷積函數(shù)
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None)
第一個(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
第六個(gè)參數(shù):name參數(shù)用以指定該操作的name
返回:Tensor廉侧,這個(gè)輸出,就是我們常說的feature map篓足,shape仍然是[batch, height, width, channels]這種形式段誊。
CNN中卷積的理解
這篇文章對(duì)CNN卷積的介紹較為詳細(xì), https://buptldy.github.io/2016/10/01/2016-10-01-im2col/
文中的兩個(gè)圖比較直觀栈拖,圖二中连舍,input features,可以理解為一個(gè)3x3圖片的3通道數(shù)據(jù)涩哟,卷積核為2x2大小三通道 2個(gè)卷積核索赏。單通道的圖片數(shù)據(jù)轉(zhuǎn)化為矩陣時(shí)盼玄,是按照卷積核的大小展開為一維向量。圖一的理解潜腻,則需要交換input和kernel的位置埃儿,output map逆時(shí)針旋轉(zhuǎn)90度。
圖一
圖二
實(shí)踐
用tensorflow的conv2d來驗(yàn)證圖2的數(shù)據(jù)融涣,其關(guān)鍵是輸入和filter的數(shù)據(jù)的構(gòu)造童番。
filter的維數(shù)[2, 2, 3, 2], 2x2維,3通道威鹿,2個(gè)卷積核剃斧,構(gòu)造出的數(shù)據(jù),不能直接按照卷積核的原始數(shù)據(jù)reshape得道忽你,而是要重新排列幼东,排列順序如圖。如果要到如圖中第一個(gè)卷積核的數(shù)據(jù)則用filter_arg[:, :, 0, 0](也可見代碼中的注釋部分科雳,通過直接賦值構(gòu)建filter的值)筋粗。同理可以構(gòu)造輸入圖片的數(shù)據(jù),最后執(zhí)行的結(jié)果和圖中一致炸渡。
數(shù)據(jù)構(gòu)建
import numpy as np
import tensorflow as tf
input_arg = tf.constant([
[[1, 0, 1], [2, 2, 2], [0, 1, 1]],
[[1, 0, 0], [1, 3, 1], [3, 2, 3]],
[[0, 1, 3], [2, 1, 3], [2, 0, 2]]], dtype = tf.float32)
# [filter_height, filter_width, in_channels, out_channels]
#filter_arg = np.array(np.arange(24)).astype("float32")
#filter_arg = np.reshape(filter_arg, [2, 2, 3, 2]).astype("float32")
#filter_arg[:, :, 0, 0] = [[1, 1], [2, 2]]
#filter_arg[:, :, 1, 0] = [[1, 1], [1, 1]]
#filter_arg[:, :, 2, 0] = [[0, 1], [1, 0]]
#filter_arg[:, :, 0, 1] = [[1, 0], [0, 1]]
#filter_arg[:, :, 1, 1] = [[2, 1], [2, 1]]
#filter_arg[:, :, 2, 1] = [[1, 2], [2, 0]]
filter_arg = tf.constant([
[[[1, 1],
[1, 2],
[0, 1]],
[[1, 0],
[1, 1],
[1, 2]]],
[[[2, 0],
[1, 2],
[1, 2]],
[[2, 1],
[1, 1],
[0, 0]]]], dtype = tf.float32)
input_arg_normal = tf.reshape(input_arg, [1, 3, 3, 3])
filter_arg_normal = tf.reshape(filter_arg, [2, 2, 3, 2])
op1 = tf.squeeze(tf.nn.conv2d(input_arg_normal, filter_arg_normal, strides=[1,1,1,1], use_cudnn_on_gpu=False, padding='VALID'))
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
input_out = sess.run(input_arg_normal)
print(input_out.shape)
print(input_out)
print("*" * 20)
filter_out = sess.run(filter_arg_normal)
print(filter_out.shape)
print(filter_out)
print("*" * 20)
print(sess.run(op1))
運(yùn)行結(jié)果
(1, 3, 3, 3)
[[[[1. 0. 1.]
[2. 2. 2.]
[0. 1. 1.]]
[[1. 0. 0.]
[1. 3. 1.]
[0, 1]],
[3. 2. 3.]]
[[0. 1. 3.]
[2. 1. 3.]
[2. 0. 2.]]]]
********************
(2, 2, 3, 2)
[[[[1. 1.]
[1. 2.]
[0. 1.]]
[[1. 0.]
[1. 1.]
[1. 2.]]]
[[[2. 0.]
[1. 2.]
[1. 2.]]
[[2. 1.]
[1. 1.]
[0. 0.]]]]
********************
[[[14. 12.]
[20. 24.]]
[[15. 17.]
[24. 26.]]]
參考文章
http://cs231n.github.io/convolutional-networks/
經(jīng)典卷積計(jì)算圖