1. 程式人生 > >Tensorflow練手專案 - 使用CNN進行手寫數字識別

Tensorflow練手專案 - 使用CNN進行手寫數字識別

首先書寫如下的程式碼

程式碼有詳細的註釋,這裡就不一一解釋了


#coding=utf-8
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import  input_data
#引入資料集
mnist=input_data.read_data_sets('MNIST_data',one_hot=True)

#用於輸出準確度的函式
def compute_accuary(v_xs,v_ys):
    global  prediction
    y_pre=sess.run(prediction,feed_dict={xs:v_xs,keep_prob:1}) #這裡會帶入要預測的x_xs引數,使用run方法帶動整個由輸入到輸出的過程,產生預測softmax輸出y_pre(都是概率值)

    correct_prediction=tf.equal(tf.argmax(y_pre,1),tf.argmax(v_ys,1))#這裡每次會獲得y_pre和v_ys最大項的索引看是不是相同,相同的話cooe--矩陣對應位置為1
    #print 'correct_prediction:'+correct_prediction
    accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))#根據矩陣中1的比例得到準確率
    results=sess.run(accuracy,feed_dict={xs:v_xs,ys:v_ys,keep_prob:1})#用於啟動上面的計算過程
    return results


#初始化權重量
def weight_variable(shape):
    #truncated_normal用於從截斷的正太分佈中輸出隨機值   stddev是標準差  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):
    #定義一個卷積操作        莫煩這裡進行卷積操作時層大小是不發生變化的,估計是因為設定了SAME的原因
    #第一個引數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,具體含義是[卷積核的高度,卷積核的寬度,影象通道數,卷積核個數],要求型別與引數input相同,有一個地方需要注意,第三維in_channels,就是引數input的第四維
    # 第三個引數strides:卷積時在影象每一維的步長,這是一個一維的向量,長度4,  每步這裡水平,豎直都是誇的1步
    # 第四個引數padding:string型別的量,只能是"SAME", "VALID"  其中之一,這個值決定了不同的卷積方式  VALID是小於等於方式的抽取,SAME是大於等於抽取,不足的地方用0進行填充,能保留更多資訊
    return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')


def max_pool_2x2(x):
    #一個池化操作
    # 第一個引數value:需要池化的輸入,一般池化層接在卷積層後面,所以輸入通常是feature map,依然是[batch, height,width, channels]這樣的shape
    # 第二個引數ksize:池化視窗的大小,取一個四維向量,一般是[1, height, width, 1],因為我們不想在batch(批)和channels(通道)上做池化,所以這兩個維度設為了1
    # 第三個引數strides:和卷積類似,視窗在每一個維度上滑動的步長,一般也是[1, stride, stride, 1]
    # 第四個引數padding:和卷積類似,可以取'VALID'或者'SAME'返回一個Tensor,型別不變,shape仍然是[batch, height,width, channels]這種形式
    return tf.nn.max_pool(x,ksize=[1,2,2,1],strides=[1,2,2,1],padding='SAME')

#定義用於儲存資料的佔位符placeholder     None是指維度 預設是一維
xs=tf.placeholder(tf.float32,[None,784])#28*28 這是單通道上的
ys=tf.placeholder(tf.float32,[None,10])
keep_prob=tf.placeholder(tf.float32) #這裡定義佔位符是後面 進行dropout時的比例
x_image=tf.reshape(xs,[-1,28,28,1])# 指定影象資訊的形式   -1是指指定先不管影象維度n_samples,  1是channel因為這是黑白的指定1就行了
##############################定義圖結構 影象->卷積層->池化層->卷積層->池化層->全連線層->全連線層#####################
#定義第一個小結構 先卷積再池化
W_conv1=weight_variable([5,5,1,32]) #定義第一個連線上的W,patch大小為5*5,線W的總數很大,輸入厚度是1(影象是是1維的),輸出是32維對應是32張平鋪的圖
b_conv1=bias_variable([32])#每個池化層feature map對應一個b偏差值
h_conv1=tf.nn.relu(conv2d(x_image,W_conv1)+b_conv1)#傳入引數進行卷積運算   並進行非線性轉換  池化層神經元數量:28*28*32
h_pool1=max_pool_2x2(h_conv1)#一次指定視窗的池化  變成14*14*32
#定義第二個小結構 先卷積再池化
W_conv2=weight_variable([5,5,32,64]) #定義第一個連線上的W,patch大小為5*5,線W的總數很大,輸入厚度是1(影象是是1維的
b_conv2=bias_variable([64])#每個池化層feature map對應一個b偏差值
h_conv2=tf.nn.relu(conv2d(h_pool1,W_conv2)+b_conv2)#傳入引數進行卷積運算   並進行非線性轉換  池化層神經元數量:14*14*64
h_pool2=max_pool_2x2(h_conv2)#一次指定視窗的池化  變成7*7*64
#定義第一個全連線層      全連線的方式會先對講pool結果進行格式重置   之後使用一般的乘法得到目標矩陣
W_fc1=weight_variable([7*7*64,1024]) #因為這是一種全連線的方式,因此這裡可以 可以用入神經元數 出神經數這樣的方式指定,畢竟最後要構建的W數量是7*7*64*1024
b_fc1=bias_variable([1024])
h_pool2_flat=tf.reshape(h_pool2,[-1,7*7*64]) #先對h_pool進行轉換成一維度simple 由64維變成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)
#第二個全連線層
W_fc2=weight_variable([1024,10]) #因為這是一種全連線的方式,因此這裡可以 可以用入神經元數 出神經數這樣的方式指定,畢竟最後要構建的W數量是7*7*64*1024
b_fc2=bias_variable([10])
prediction=tf.nn.softmax(tf.matmul(h_fc1_drop,W_fc2)+b_fc2) #  使用softmax正好能夠轉化得到概率
############################################################################################################

#定義損失函式和訓練方式
cross_entropy=tf.reduce_mean(-tf.reduce_sum(ys*tf.log(prediction),reduction_indices=[1]))# 定義交叉商reduction_indices指定維度
train_step=tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
sess=tf.Session()
sess.run(tf.global_variables_initializer())
for i in range(1,1000):
    print('i:',i)
    batch_xs,batch_ys=mnist.train.next_batch(100)
    #print 'i:',batch_xs,'   ',batch_ys
    sess.run(train_step,feed_dict={xs:batch_xs,ys:batch_ys,keep_prob:0.5})
    if i%10==0:
        print(compute_accuary(mnist.test.images[:1000], mnist.test.labels[:1000]))



可以如下發現伴隨著訓練的進行,模型在測試機上的準確率如下:

 

最後模型在訓練100000次後結束,最後得分在0.95左右。