CNN(卷積神經網路)的操作?

Source: Deep Learning on Medium

Tensorflow版本的Convolution1D vs Convolution2D 說明

tensorflow中的conv1d和conv2d的區別:conv1d是單通道的,conv2d是多通道,所以conv1d適合處理文本序列,conv2d適合處理圖像。

conv1d

import tensorflow as tf
input = tf.Variable(tf.random_normal([1, 5, 20]))
params1 = {“inputs”: input, “filters”: 2048, “kernel_size”: 2,”strides”:1,”activation”: tf.nn.relu, “use_bias”: True,”padding”:’SAME’}
op01 = tf.layers.conv1d(**params1)
init = tf.initialize_all_variables()
with tf.Session() as sess:
sess.run(init)
print(sess.run(tf.shape(op01)))
>>>[1,5,2048]
  1. 輸入input第一維為batch_size,此處為1,即只有一個文本,第二維和第三維分別表示輸入的長和寬,在文本中就是word_embedding矩陣,句子長度為5,embedding維度為20。
  2. 在文本中,卷積的某一維大小往往為embedding長度,即在寬度上不需要窗口移動,寬度就是整個窗口。所以conv1d默認卷積的寬度就為embedding維度,長度是通過kernel_size來指定的,此處為2,即卷積核的大小為2*embedding_size(將此想像成一般圖片任務CNN的patching大小,只是寬度已固定,故只需指定kernal_size(即一個文本的序列長度中,一次要多少長度去做convolution(ps:寬士embedding大小))。
  3. strides為步長,此處為1,即卷積核每隔一個單詞移動一次。
  4. filters是卷積核的個數,即輸出的維度。
  5. padding有valid和same兩種選擇,valid在長度方向(寬度方向不padding)不進行padding,而same則在長度方向進行padding,保證輸入句子長度和卷積後輸出的句子長度一致,此處為5 。

conv2d

input = tf.Variable(tf.random_normal([1, 28, 28, 1]))
filter = tf.Variable(tf.random_normal([3, 3, 1, 32]))
op1 = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding=’SAME’)
  1. input輸入是1張28*28大小的圖片,圖像channel數是1(batch,長,寬,輸入通道數)有時batch會設-1(即不指定)
  2. filter卷積核是3*3大小,數量是1(長,寬,輸入通道數,輸出通道數(卷積核個數))[height, width, channel, out_size] //out_size自己指定
  3. strides步長是[1,1,1,1],第一維和最後一維保持1不變,第二維和第三維分別為長度方向和寬度方向的步長。
  4. 1張圖最後輸出的op1就是一個shape為[1,28,28,32]的張量,即得到一個3*3的feature map(batch,長,寬,輸出通道數)

Reference: https://blog.csdn.net/bobobe/article/details/87923618

# define placeholder for inputs to network
xs = tf.placeholder(tf.float32, [None, 784]) # 28x28
ys = tf.placeholder(tf.float32, [None, 10])
keep_prob = tf.placeholder(tf.float32)
x_image = tf.reshape(xs, [-1, 28, 28, 1])
# print(x_image.shape) # [n_samples, width, height, channel]
說明:
在此,我們定義輸入圖xs大小為784(28*28),ys為預測目標0~9,所以大小為10,
x_image 為 xs reshape後的結果
tf.reshape:
Given
tensor, this operation returns a tensor that has the same values as tensor with shape shape
## conv1 layer ### W_conv1:patch 5x5, in size 1, out size 32
W_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
說明:
在此,我們定義W_conv1大小為[5, 5, 1, 32]=>[卷積核長,卷積核寬,通道,out_size]out_size為自定義,其中5,5視為patch 5x5,在圖片cnn任務中即為filter大小,然後b_conv1為32是因為w的out_size是32,以32個w要配上b。
### ps start ###
#
conv2d => tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')
# max_pool_2x2 => tf.nn.max_pool(x, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')
### ps end ###
# h_conv1 output size 28x28x32
h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
# h_pool1 output size 14x14x32
h_pool1 = max_pool_2x2(h_conv1)
說明:
在此,我們定義h_conv1為conv2d(x_image, W_conv1)+b_conv1,
strides=[1, 1, 1, 1]的第2及第3個值為移動長和寬,在此都為1,padding使用SAME,表示輸出大小會與輸入大小一致(所以圖片大小仍為28*28),故大小為28*28*32,h_pool1及對h_conv進行pooling(池化),在此大小為2*2,故輸出會變成14*14*32
## conv2 layer ##
# patch 5x5, in size 32, out size 64
W_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
# h_conv2 output size 14x14x64
h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)
# h_pool2 output size 7x7x64
h_pool2 = max_pool_2x2(h_conv2)
說明:
在此,我們定義W_conv2大小[5, 5, 25, 50]=>[卷積核長,卷積核寬,通道,out_size]out_size為自定義,其中5,5視為patch 5x5,通道為32是因為h_conv2要做卷積2d時conv2d(h_pool1, W_conv2),在此h_pool1的第三維大小是32,故W_conv2通道為32。
h_pool2部分則是h_conv2經過pooling,故輸出為7*7*64
## fc1 layer ##
W_fc1 = weight_variable([7*7*64, 1024])
b_fc1 = bias_variable([1024])
說明:
在此,W_fc1為全連接層,故輸入大小是h_conv2大小7*7*64,而輸出我們希望為1024個神經節點(neural_nodes),自訂義大小為1024。
# [n_samples, 7, 7, 64] ->> [n_samples, 7*7*64]
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
說明:
h_pool2_flat為tf.reshape()將h_pool2的輸出值從一個三維的變為一維的數據, -1表示先不考慮輸入圖片例子維度,將上一個輸出結果展平。
## fc2 layer ##
W_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
prediction = tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)