TensorFlow搭建CNN卷積神經網絡
該教程採用TernsorFlow搭建CNN卷積神經網絡,並利用MNIST數據集進行數字的手寫識別
數據結構
- mnist原始圖片輸入,原始圖片的尺寸爲28×28,導入後會自動展開爲28×28=784的list
tensor : shape=[784]
- 卷積層輸入input_image: shape=[batch, height, width, channels]
bacth : 取樣數
height, width : 圖片的尺寸
channels : 圖片的深度;如果是灰度圖像,則爲1,rgb圖像,則爲3
- 卷積核filter: shape=[height, width, in_channels, out_channels]
height, width: 圖片的尺寸
in_channels: 圖片的深度
out_channels: 卷積核的數量
- 對於in_channels,灰度圖爲1,rgb圖爲3
函數
TensorFlow自帶的CNN操作函數
- 卷積函數[tf.nn.conv2d(x, filter, strides=[1,1,1,1], padding=’SAME’)]
x: 卷積層輸入 shape=[batch, height, width, channels]
filter: 卷積核 shape=[height, width, in_channels, out_channels]
stride: 卷積步長 shape=[batch_stride, height_stride, width_stride, channels_stride]
padding: 控制卷積核處理邊界的策略
- stride表示卷積核filter對應了input_image各維度下移動的步長;第一個參數對應input_image的batch方向上的移動步長,第二、三參數對應高寬方向上的步長,決定了卷積後圖像的尺寸,最後一個參數對應channels方向上的步長
- padding=’SAME’表示給圖像邊界加上padding,讓filter卷積後的圖像尺寸與原圖相同;’VALID’表示卷積後imgaeHeight_aterFiltered=imageHeight_inital-filterHeight+strideHeight,寬同理
- 池化函數tf.nn.max_pool(x, k_size=[1,2,2,1], strides=[1,2,2,1], padding=’SAME’)
x: 池化輸入input_image: shape=[batch, height, width, channels]
ksize: 池化窗口的尺寸
strides: 池化步長
padding: 處理邊界策略
- 池化輸入,tensor的shape同input_image, 一般爲卷積後圖像feature_map
- ksize對應輸入圖像各維度的池化尺寸;第一個參數對應batch方向上的池化尺寸,第二、三參數對應圖像高寬上的池化尺寸,第四個參數對應channels方向上的池化尺寸,一般不在batch和channel方向上做池化,因此通常爲[1,height,width,1]
- strides與padding同卷積函數tf.nn.conv2d()
爲了方便後續搭建,需要自己定義一些函數
- 卷積核filter初始化weight_variable(shape)
def weight_variable(shape):
initial=tf.truncated_normal(shape, mean=0.0, stddev=0.1)
return tf.Variable(inital)
- 對於CNN來說,weight實際上就是卷積核filter,因此shape應該與tf.nn.conv2d中filter的shape一致,即shape=[height, width, in_channels, out_channels]
- tf.truncated_normal()表示截斷正態分佈,即保留[mean-2×stddev,mean+2×stddev]範圍內的隨機數,mean表示平均數,stddev爲方差
- 偏置初始化bias_variable(shape)
def bias_variable(shape):
initial=tf.constant(0,1,shape=shape)
return tf.Vatiable(initial)
針對tensorFlow函數更詳細的使用,參見tensorFlow常用函數彙總
思路
MNIST數據導入
代碼這一行就是用於下載mnist數據,實際操作過程往往會出現socket error,因此需要事先下載好
from tensorflow.examples.tutorials.mnist import input_data
- 在程序的文件夾下建立MNIST_data文件夾,在執行完上述代碼後,會自動生成該文件夾
- 進入MNIST_data文件後,從github上直接下載數據集合
cd MNIST_data
git clone https://github.com/HIPS/hypergrad.git
#下載完成後,將下載文件中data/mnist下所有數據copy進MNIST_data中即可
完整代碼
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
#獲取mnist訓練集
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)
#交互式session
sess = tf.InteractiveSession()
#已將32×32的圖片展開成行向量,None代表該維度上數量不確定,程序中指的是取樣的圖像數量不確定
x=tf.placeholder(tf.float32, shape=[None,784])
#圖片的標籤
y_label=tf.placeholder(tf.float32, shape=[None,10])
-------------------------------------------------------------------------
#第一層網絡
#reshape()將按照設定的shape=[-1,28,28,1]對x:shape=[None,784]的結構進行重新構建
#參數-1代表該維度上數量不確定,由系統自動計算
x_image = tf.reshape(x, shape=[-1,28,28,1])
#32個卷積核,卷積核大小5×5
W_conv1 = weight_variable([5,5,1,32])
#32個前置,對應32個卷積核輸出
b_conv1 = bias_varibale([32])
#卷積操作
layer_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)
#池化操作
layer_pool1 = tf.nn.max_pool(layer_conv1)
-------------------------------------------------------------------------
#第二層網絡
#64個卷積核,卷積核大小5×5,32個channel
W_conv2 = weight_variable([5,5,32,64])
#64個前置,對應64個卷積核輸出
b_conv2 = bias_varibale([64])
#卷積操作
layer_conv2 = tf.nn.relu(conv2d(layer_pool1, W_conv2) + b_conv2)
#池化操作
layer_pool2 = tf.nn.max_pool(layer_conv2)
-------------------------------------------------------------------------
#full-connected網絡
#圖片尺寸變化28×28-->14×14-->7×7
#該層設定1024個神經元
layer_pool2_flat = tf.reshape(layer_pool2,[-1,7*7*64])
W_fc1 = weight_variable([7*7*64,1024])
b_fc1 = bias_variable([1024])
h_fc1 = tf.nn.relu(tf.matmul(layer_pool2_flat, W_fc1) + b_fc1)
-------------------------------------------------------------------------
#droput網絡
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)
-------------------------------------------------------------------------
#輸出層
W_fc2 = weight_variable([1024,10])
b_fc2 = bias_variable([10])
y_conv = tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2)+b_fc2)
-------------------------------------------------------------------------
#loss-function
cross_entropy = -tf.reduce_sum(y_lable*tf.log(y_conv))
#梯度下降
train = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
#tf.argmax(x,1)表示從x的第二維度選取最大值
correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_lable,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))
sess.run(tf.global_variables_initializer())
-------------------------------------------------------------------------
#訓練train
#訓練3000次
for i in range(3000)
#每次選取50訓練集
batch = mnist.train.next_batch(50)
if i%100 == 0:
train_accuracy = accuracy.eval(feed_dict={x:batch[0], y_labe: batch[1], keep_prob: 1.0})
print ("step %d, training accuracy %g"%(i, train_accuracy))
train.run(feed_dict={x: batch[0], y_label: batch[1], keep_prob: 0.5})
print ("test accuracy %g"%accuracy.eval(feed_dict={x: mnist.test.images, y_label: mnist.test.labels, keep_prob: 1.0}))