1. 程式人生 > >Tensorflow中tf.nn.conv2d理解

Tensorflow中tf.nn.conv2d理解

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

除去name引數用以指定該操作的name,與方法有關的一共五個引數:第一個引數input:指需要做卷積的輸入影象,它要求是一個Tensor,具有[batch, in_height, in_width, in_channels]這樣的shape,具體含義是[訓練時一個batch的圖片數量, 圖片高度, 圖片寬度, 影象通道數],注意這是一個4維的Tensor,要求型別為float32和float64其中之一;

第二個引數filter:相當於CNN中的卷積核,它要求是一個Tensor,具有[filter_height, filter_width, in_channels, out_channels]

這樣的shape,具體含義是[卷積核的高度,卷積核的寬度,影象通道數,卷積核個數],有一個地方需要注意,第三維in_channels,就是引數input的第四維,要求型別為float32和float64其中之一;

第三個引數strides:卷積時在影象每一維的步長,這是一個一維的向量,長度4;

第四個引數padding:string型別的量,只能是"SAME","VALID"其中之一,這個值決定了不同的卷積方式;

第五個引數use_cudnn_on_gpu:bool型別,是否使用cudnn加速,預設為true

結果返回一個Tensor,這個輸出,就是我們常說的feature map

那麼TensorFlow的卷積具體是怎樣實現的呢,用一些例子去解釋它:

1.考慮一種最簡單的情況,現在有一張3×3單通道的影象(對應的shape:[1,3,3,1]),用一個1×1的卷積核(對應的shape:[1,1,1,1])去做卷積,最後會得到一張3×3的feature map

2.增加圖片的通道數,使用一張3×3五通道的影象(對應的shape:[1,3,3,5]),用一個1×1的卷積核(對應的shape:[1,1,1,1])去做卷積,仍然是一張3×3的feature map,這就相當於每一個畫素點,卷積核都與該畫素點的每一個通道做點積

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.把卷積核擴大,現在用3×3的卷積核做卷積,最後的輸出是一個值,相當於情況2的feature map所有畫素點的值求和

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的圖片擴大到5×5,仍然是3×3的卷積核,令步長為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')

5.上面我們一直令引數padding的值為‘VALID’,當其為‘SAME’時,表示卷積核可以停留在影象邊緣,如下,輸出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')

6.如果卷積核有多個

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')

此時輸出7張5×5的feature map 

7.步長不為1的情況,文件裡說了對於圖片,因為只有兩維,通常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')

8.如果batch值不為1,同時輸入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]

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

個人總結:

ef weight_variable(shape):
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)
def bias_variable(shape):
    initial = tf.constant(0.1, shape=shape)
    return tf.Variable(initial)
def conv2d(x, W):#卷積
    return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

x_image = tf.reshape(xs, [-1,5,1, 3])
W_conv1 = weight_variable([2,2,3,32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)#shape=(?,5,1,32)

x_image的shape中-1表示輸入圖片數目不定,5表示圖片的高度,1表示圖片的寬度,3表示影象的通道數

W_conv1的shape中前兩個2分別表示卷積核的高度和寬度,3表示影象的通道數,與輸入的x_image的第三維是對應的,32表示卷積核的數目,它決定了生成的feature map的數目

由h_convl的shape我們可以看到第一維未知,就是輸入影象的數目,對應於-1,而5*1正是x_image中影象的高度和寬度,32則是卷積核的數目,也是生成的feature map的數目