1. 程式人生 > >全連線網路基礎-MNIST資料集輸出手寫數字識別準確率

全連線網路基礎-MNIST資料集輸出手寫數字識別準確率

本節目標:搭建神經網路,在 mnist 資料集上訓練模型,輸出手寫數字識別準確率。

——————————————————————————————————————————————不可視的境界線

mnist 資料集:包含 7 萬張黑底白字手寫數字圖片,其中 55000 張為訓練集, 5000 張為驗證集,10000 張為測試集。每張圖片大小為 28*28 畫素,圖片中純黑色畫素值為 0,純白色畫素值為 1。資料集的標籤是長度為 10 的一維陣列,陣列中每個元素索引號表示對應數字出現的概率。 在將 mnist 資料集作為輸入喂入神經網路時,需先將資料集中每張圖片變為長度 784 一維陣列,將該陣列作為神經網路輸入特徵喂入神經網路。

例如: 一張數字手寫體圖片變成長度為 784 的一維陣列[0.0.0.0.0.231 0.235 0.459 ……0.219 0.0.0.0.]輸入神經網路。該圖片對應的標籤為[0.0.0.0.0.0.1.0. 0.0],標籤中索引號為 6 的元素為 1,表示是數字 6 出現的概率為 100%,則該圖 片對應的識別結果是 6。

使用 input_data 模組中的 read_data_sets()函式載入 mnist 資料集:  

 from tensorflow.examples.tutorials.mnist import input_data 

mnist = input_data.read_data_sets(’./data/’,one_hot=True) 

在 read_data_sets()函式中有兩個引數,第一個引數表示資料集存放路徑,第二個引數表示資料集的存取形式。當第二個引數為 Ture 時,表示以獨熱碼形式存取資料集。read_data_sets()函式執行時,會檢查指定路徑內是否已經有資料集,若指定路徑中沒有資料集,則自動下載,並將mnist資料集分為訓練集train、 驗證集 validation 和測試集 test 存放。在終端顯示如下內容:

Extracting ./data/train-images-idx3-ubyte.gz 

Extracting ./data/train-labels-idx1-ubyte.gz
Extracting ./data/tl0k-images-idx3-ubyte.gz
Extracting ./data/ tl0k-labels-idx1-ubyte.gz

返回 mnist 資料集中訓練集 train、驗證集 validation 和測試集 test 樣本數: 在 Tensorflow 中用以下函式返回子集樣本數:①返回訓練集 train 樣本數 print “train data size:”,mnist.train.mun_examples 輸出結果:train data size:55000②返回驗證集 validation 樣本數 print “validation data size:”,mnist.validation.mun_examples 輸出結果:validation data size:5000③返回測試集 test 樣本數 print “test data size:”,mnist.test.mun_examples 輸出結果:test data size:10000

使用 train.labels 函式返回 mnist 資料集標籤 例如: 在 mnist 資料集中,若想要檢視訓練集中第 0 張圖片的標籤,則使用如下函式 mnist.train.labels[0] 輸出結果:array([0.,0.,0.,0.,0.,0.,1.,0.,0.,0])

使用 train.images 函式返回 mnist 資料集圖片畫素值 例如: 在 mnist 資料集中,若想要檢視訓練集中第 0 張圖片畫素值,則使用如下函式 mnist.train.images[0] 輸出結果:array([0. ,0. ,0. ,0. ,0. ,0. ,0. ,0. ,0. ,… … …])

使用 mnist.train.next_batch()函式將資料輸入神經網路 例如:

BATCH_SIZE = 200
xs,ys = mnist.train.next_batch(BATCH_SIZE)
print “xs shape:”,xs.shape
print “ys shape:”,ys.shape

輸出結果:xs.shape(200,784) 輸出結果:ys.shape(200,10) 其中,mnist.train.next_batch()函式包含一個引數 BATCH_SIZE,表示隨機從訓練集中抽取 BATCH_SIZE 個樣本輸入神經網路,並將樣本的畫素值和標籤分別賦給 xs 和 ys。在本例中,BATCH_SIZE 設定為 200,表示一次將 200 個樣本的畫素值和標籤分別賦值給 xs 和 ys,故 xs 的形狀為(200,784),對應的 ys 的形狀為(200,10)。

實現“Mnist 資料集手寫數字識別”的常用函式:①tf.get_collection(“”)函式表示從 collection 集合中取出全部變數生成一個列表。 ②tf.add( )函式表示將引數列表中對應元素相加。 例如:

x=tf.constant([[1,2],[1,2]])
y=tf.constant([[1,1],[1,2]])
z=tf.add(x,y)
print z

輸出結果:[[2,3],[2,4]]③tf.cast(x,dtype)函式表示將引數 x 轉換為指定資料型別。 例如:

A = tf.convert_to_tensor(np.array([[1,1,2,4], [3,4,8,5]]))
print A.dtype
b = tf.cast(A, tf.float32)
print b.dtype

結果輸出: <dtype: 'int64'> <dtype: 'float32'> 從輸出結果看出,是將矩陣 A 由整數型變為 32 位浮點型。④tf.equal( )函式表示對比兩個矩陣或者向量的元素。若對應元素相等,則返回 True;若對應元素不相等,則返回 False。 例如:

A = [[1,3,4,5,6]]
B = [[1,3,4,3,2]]
with tf.Session( ) as sess:
    print(sess.run(tf.equal(A, B)))

輸出結果:[[ True True True False False]] 在矩陣 A 和 B 中,第 1、2、3 個元素相等,第 4、5 個元素不等,故輸出結果中,第 1、2、3 個元素取值為 True,第 4、5 個元素取值為 False。⑤tf.reduce_mean(x,axis)函式表示求取矩陣或張量指定維度的平均值。若不指定第二個引數,則在所有元素中取平均值;若指定第二個引數為 0,則在第一維元素上取平均值,即每一列求平均值;若指定第二個引數為 1,則在第二維元素上取平均值,即每一行求平均值。 例如:

x = [[1., 1.]
       [2., 2.]]
print(tf.reduce_mean(x))
#輸出結果:1.5
print(tf.reduce_mean(x, 0))
#輸出結果:[1.5, 1.5]
print(tf.reduce_mean(x, 1))
#輸出結果:[1., 1.]

⑥tf.argmax(x,axis)函式表示返回指定維度 axis 下,引數 x 中最大值索引號。 例如: 在 tf.argmax([1,0,0],1)函式中,axis 為 1,引數 x 為[1,0,0],表示在引數 x的第一個維度取最大值對應的索引號,故返回 0。⑦os.path.join()函式表示把引數字串按照路徑命名規則拼接。 例如:

import os
os.path.join('/hello/','good/boy/','doiido')
#輸出結果:'/hello/good/boy/doiido'

⑧字串.split( )函式表示按照指定“拆分符”對字串拆分,返回拆分列表。 例如: './model/mnist_model-1001'.split('/')[-1].split('-')[-1] 在該例子中,共進行兩次拆分。第一個拆分符為‘/’,返回拆分列表,並提取列表中索引為-1 的元素即倒數第一個元素;第二個拆分符為‘-’,返回拆分列表,並提取列表中索引為-1 的元素即倒數第一個元素,故函式返回值為 1001。⑨tf.Graph( ).as_default( )函式表示將當前圖設定成為預設圖,並返回一個上下文管理器。該函式一般與 with 關鍵字搭配使用,應用於將已經定義好的神經網路在計算圖中復現。 例如: with tf.Graph().as_default() as g,表示將在 Graph()內定義的節點加入到計算圖 g 中。

神經網路模型的儲存 在反向傳播過程中,一般會間隔一定輪數儲存一次神經網路模型,併產生三個檔案(儲存當前圖結構的.meta 檔案、儲存當前引數名的.index 檔案、儲存當前引數的.data 檔案),在 Tensorflow 中如下表示:

saver = tf.train.Saver() 
with tf.Session() as sess: 
    for i in range(STEPS):
         if i % 輪數 == 0:
             saver.save(sess, os.path.join(MODEL_SAVE_PATH,                 
                         MODEL_NAME),global_step=global_step)

其中,tf.train.Saver()用來例項化 saver 物件。上述程式碼表示,神經網路每迴圈規定的輪數,將神經網路模型中所有的引數等資訊儲存到指定的路徑中,並在存放網路模型的資料夾名稱中註明儲存模型時的訓練輪數。  

神經網路模型的載入 在測試網路效果時,需要將訓練好的神經網路模型載入,在 Tensorflow 中這樣表示:

with tf.Session() as sess:
    ckpt = tf.train.get_checkpoint_state(儲存路徑)
    if ckpt and ckpt.model_checkpoint_path:
        saver.restore(sess, ckpt.model_checkpoint_path)

在 with 結構中進行載入儲存的神經網路模型,若 ckpt 和儲存的模型在指定路徑中存在,則將儲存的神經網路模型載入到當前會話中。

載入模型中引數的滑動平均值 在儲存模型時,若模型中採用滑動平均,則引數的滑動平均值會儲存在相應檔案中。通過例項化 saver 物件,實現引數滑動平均值的載入,在 Tensorflow 中如下表示:

ema = tf.train.ExponentialMovingAverage(滑動平均基數)
ema_restore = ema.variables_to_restore()
saver = tf.train.Saver(ema_restore)

神經網路模型準確率評估方法 在網路評估時,一般通過計算在一組資料上的識別準確率,評估神經網路的效果。在 Tensorflow 中這樣表示:

correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

在上述中,y 表示在一組資料(即 batch_size 個數據)上神經網路模型的預測結果,y 的形狀為[batch_size,10],每一行表示一張圖片的識別結果。通過tf.argmax()函式取出每張圖片對應向量中最大值元素對應的索引值,組成長度為輸入資料 batch_size 個的一維陣列。通過 tf.equal()函式判斷預測結果張量和實際標籤張量的每個維度是否相等,若相等則返回 True,不相等則返回 False。通過 tf.cast() 函式將得到的布林型數值轉化為實數型,再通過tf.reduce_mean()函式求平均值,最終得到神經網路模型在本組資料上的準確率。

神經網路八股包括前向傳播過程、反向傳播過程、反向傳播過程中用到的正則化、指數衰減學習率、滑動平均方法的設定、以及測試模組。前向傳播過程(forward.py) 前向傳播過程完成神經網路的搭建,結構如下:

def forward(x, regularizer):
    w=
    b=
    y=
    return y
def get_weight(shape, regularizer):
def get_bias(shape):

前向傳播過程中,需要定義神經網路中的引數 w 和偏置 b,定義由輸入到輸出的網路結構。通過定義函式 get_weight()實現對引數 w 的設定,包括引數 w 的形狀和是否正則化的標誌。同樣,通過定義函式 get_bias()實現對偏置 b 的設定。反向傳播過程(backword.py) 反向傳播過程完成網路引數的訓練,結構如下:

def backward( mnist ):
x = tf.placeholder(dtype, shape )
y_ = tf.placeholder(dtype, shape )
#定義前向傳播函式
y = forward( )
global_step =
loss =
train_step = tf.train.GradientDescentOptimizer(learning_rate).
            minimize(loss, global_step=global_step)
#例項化 saver 物件
saver = tf.train.Saver()
with tf.Session() as sess:
    #初始化所有模型引數
tf.initialize_all_variables().run()
#訓練模型
for i in range(STEPS):
    sess.run(train_step, feed_dict={x: , y_: })
    if i % 輪數 == 0:
        print
        saver.save( )

反向傳播過程中,用 tf.placeholder(dtype, shape)函式實現訓練樣本 x 和樣本標籤 y_佔位,函式引數 dtype 表示資料的型別,shape 表示資料的形狀;y 表示定義的前向傳播函式 forward;loss 表示定義的損失函式,一般為預測值與樣本標籤的交叉熵(或均方誤差)與正則化損失之和;train_step 表示利用優化演算法對模型引數進行優化,常用優化演算法 GradientDescentOptimizer 、AdamOptimizer、MomentumOptimizer 演算法,在上述程式碼中使用的 GradientDescentOptimizer 優化演算法。接著例項化 saver 物件,其中利用 tf.initialize_all_variables().run()函式例項化所有引數模型,利用 sess.run( )函式實現模型的訓練優化過程,並每間隔一定輪數儲存一次模型。

正則化、指數衰減學習率、滑動平均方法的設定①正則化項 regularization 當在前向傳播過程中即 forward.py 檔案中,設定正則化引數 regularization 為1 時,則表明在反向傳播過程中優化模型引數時,需要在損失函式中加入正則化項。 結構如下:首先,需要在前向傳播過程即 forward.py 檔案中加入 if regularizer != None: tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(regularizer)(w)) 其次,需要在反向傳播過程即 backword.py 檔案中加入 ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1)) cem = tf.reduce_mean(ce) loss = cem + tf.add_n(tf.get_collection('losses')) 其中,tf.nn.sparse_softmax_cross_entropy_with_logits()表示 softmax()函式與交叉熵一起使用。②指數衰減學習率 在訓練模型時,使用指數衰減學習率可以使模型在訓練的前期快速收斂接近較優解,又可以保證模型在訓練後期不會有太大波動。運用指數衰減學習率,需要在反向傳播過程即 backword.py 檔案中加入:

learning_rate = tf.train.exponential_decay(
LEARNING_RATE_BASE,
global_step,
LEARNING_RATE_STEP, LEARNING_RATE_DECAY,
staircase=True)

③滑動平均 在模型訓練時引入滑動平均可以使模型在測試資料上表現的更加健壯。 需要在反向傳播過程即 backword.py 檔案中加入:

ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY,
           global_step)
ema_op = ema.apply(tf.trainable_variables())
with tf.control_dependencies([train_step, ema_op]):
    train_op = tf.no_op(name='train')

測試過程(test.py) 當神經網路模型訓練完成後,便可用於測試資料集,驗證神經網路的效能。結構如下: 首先,制定模型測試函式 test()

def test( mnist ):
    with tf.Graph( ).as_default( ) as g:
        #給 x y_佔位
        x = tf.placeholder(dtype,shape)
        y_ = tf.placeholder(dtype,shape)
    #前向傳播得到預測結果 y
    y = mnist_forward.forward(x, None) #前向傳播得到 y
     #例項化可還原滑動平均的 saver
     ema = tf.train.ExponentialMovingAverage(滑動衰減率)
     ema_restore = ema.variables_to_restore()
     saver = tf.train.Saver(ema_restore)
    #計算正確率
    correct_prediction = tf.equal(tf.argmax(y,1),tf.argmax(y_,
                        1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction,
                tf.float32))
    while True:
        with tf.Session() as sess:
            #載入訓練好的模型
            ckpt = tf.train.get_checkpoint_state(儲存路徑)
            #如果已有 ckpt 模型則恢復
            if ckpt and ckpt.model_checkpoint_path:
            #恢復會話
            saver.restore(sess, ckpt.model_checkpoint_path)
            #恢復輪數
            global_ste = ckpt.model_checkpoint_path.split
                        ('/')[-1].split('-')[-1]
            #計算準確率
            accuracy_score = sess.run(accuracy, feed_dict=
                            {x:測試資料, y_:測試資料標籤 })
            # 列印提示
            print("After %s training step(s), test accuracy=
                   %g" % (global_step, accuracy_score))
        #如果沒有模型
        else:
            print('No checkpoint file found') #模型不存在提示
            return
#其次,制定 main()函式
def main():
    #載入測試資料集
    mnist = input_data.read_data_sets("./data/", one_hot=True)
    #呼叫定義好的測試函式 test()
    test(mnist)
if __name__ == '__main__':
main()

通過對測試資料的預測得到準確率,從而判斷出訓練出的神經網路模型的效能好壞。當準確率低時,可能原因有模型需要改進,或者是訓練資料量太少導致過擬合。

實現手寫體 mnist 資料集的識別任務,共分為三個模組檔案,分別是描述網路結構的前向傳播過程檔案(mnist_forward.py)、描述網路引數優化方法的反向傳播過程檔案(mnist_backward.py )、驗證模型準確率的測試過程檔案(mnist_test.py)。

前向傳播過程檔案(mnist_forward.py) 在前向傳播過程中,需要定義網路模型輸入層個數、隱藏層節點數、輸出層個數,定義網路引數 w、偏置 b,定義由輸入到輸出的神經網路架構。實現手寫體 mnist 資料集的識別任務前向傳播過程如下:

#coding:utf-8
#1前向傳播過程
import tensorflow as tf
 
#網路輸入節點為784個(代表每張輸入圖片的畫素個數)
INPUT_NODE = 784
#輸出節點為10個(表示輸出為數字0-9的十分類)
OUTPUT_NODE = 10
#隱藏層節點500個
LAYER1_NODE = 500
 
 
def get_weight(shape, regularizer):
	#引數滿足截斷正態分佈,並使用正則化,
    w = tf.Variable(tf.truncated_normal(shape,stddev=0.1))
    #w = tf.Variable(tf.random_normal(shape,stddev=0.1))
	#將每個引數的正則化損失加到總損失中
    if regularizer != None: tf.add_to_collection('losses', tf.contrib.layers.l2_regularizer(regularizer)(w))
    return w
 
 
def get_bias(shape):  
	#初始化的一維陣列,初始化值為全 0
    b = tf.Variable(tf.zeros(shape))  
    return b
	
def forward(x, regularizer):
	#由輸入層到隱藏層的引數w1形狀為[784,500]
    w1 = get_weight([INPUT_NODE, LAYER1_NODE], regularizer)
	#由輸入層到隱藏的偏置b1形狀為長度500的一維陣列,
    b1 = get_bias([LAYER1_NODE])
	#前向傳播結構第一層為輸入 x與引數 w1矩陣相乘加上偏置 b1 ,再經過relu函式 ,得到隱藏層輸出 y1。
    y1 = tf.nn.relu(tf.matmul(x, w1) + b1)
    #由隱藏層到輸出層的引數w2形狀為[500,10]
    w2 = get_weight([LAYER1_NODE, OUTPUT_NODE], regularizer)
	#由隱藏層到輸出的偏置b2形狀為長度10的一維陣列
    b2 = get_bias([OUTPUT_NODE])
	#前向傳播結構第二層為隱藏輸出 y1與參 數 w2 矩陣相乘加上偏置 矩陣相乘加上偏置 b2,得到輸出 y。
	#由於輸出 。由於輸出 y要經過softmax oftmax 函式,使其符合概率分佈,故輸出y不經過 relu函式
    y = tf.matmul(y1, w2) + b2
    return y

由上述程式碼可知,在前向傳播過程中,規定網路輸入結點為 784 個(代表每張輸入圖片的畫素個數),隱藏層節點 500 個,輸出節點 10 個(表示輸出為數字 0-9的十分類)。由輸入層到隱藏層的引數 w1 形狀為[784,500],由隱藏層到輸出層的引數 w2 形狀為[500,10],引數滿足截斷正態分佈,並使用正則化,將每個參11數的正則化損失加到總損失中。由輸入層到隱藏層的偏置 b1 形狀為長度為 500的一維陣列,由隱藏層到輸出層的偏置 b2 形狀為長度為 10 的一維陣列,初始化值為全 0。前向傳播結構第一層為輸入 x 與引數 w1 矩陣相乘加上偏置 b1,再經過 relu 函式,得到隱藏層輸出 y1。前向傳播結構第二層為隱藏層輸出 y1 與引數 w2 矩陣相乘加上偏置 b2,得到輸出 y。由於輸出 y 要經過 softmax 函式,使其符合概率分佈,故輸出 y 不經過 relu 函式。

反向傳播過程檔案(mnist_backward.py) 反向傳播過程實現利用訓練資料集對神經網路模型訓練,通過降低損失函式值,實現網路模型引數的優化,從而得到準確率高且泛化能力強的神經網路模型。實現手寫體 mnist 資料集的識別任務反向傳播過程如下:

#coding:utf-8
#2反向傳播過程
#引入tensorflow、input_data、前向傳播mnist_forward和os模組
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import mnist_forward
import os
 
#每輪喂入神經網路的圖片數
BATCH_SIZE = 200
#初始學習率
LEARNING_RATE_BASE = 0.1
#學習率衰減率
LEARNING_RATE_DECAY = 0.99
#正則化係數
REGULARIZER = 0.0001
#訓練輪數
STEPS = 50000
#滑動平均衰減率
MOVING_AVERAGE_DECAY = 0.99
#模型儲存路徑
MODEL_SAVE_PATH="./model/"
#模型儲存名稱
MODEL_NAME="mnist_model"
 
 
def backward(mnist):
    #用placeholder給訓練資料x和標籤y_佔位
    x = tf.placeholder(tf.float32, [None, mnist_forward.INPUT_NODE])
    y_ = tf.placeholder(tf.float32, [None, mnist_forward.OUTPUT_NODE])
    #呼叫mnist_forward檔案中的前向傳播過程forword()函式,並設定正則化,計算訓練資料集上的預測結果y
	y = mnist_forward.forward(x, REGULARIZER)
	#當前計算輪數計數器賦值,設定為不可訓練型別
    global_step = tf.Variable(0, trainable=False)
 
    #呼叫包含所有引數正則化損失的損失函式loss
    ce = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=y, labels=tf.argmax(y_, 1))
    cem = tf.reduce_mean(ce)
    loss = cem + tf.add_n(tf.get_collection('losses'))
    #設定指數衰減學習率learning_rate
    learning_rate = tf.train.exponential_decay(
        LEARNING_RATE_BASE,
        global_step,
        mnist.train.num_examples / BATCH_SIZE, 
        LEARNING_RATE_DECAY,
        staircase=True)
 
    #使用梯度衰減演算法對模型優化,降低損失函式
    #train_step = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)
    train_step = tf.train.MomentumOptimizer(learning_rate,0.9).minimize(loss, global_step=global_step)
    #train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss, global_step=global_step)
    #定義引數的滑動平均
    ema = tf.train.ExponentialMovingAverage(MOVING_AVERAGE_DECAY, global_step)
    ema_op = ema.apply(tf.trainable_variables())
	#例項化可還原滑動平均的saver 
	#在模型訓練時引入滑動平均可以使模型在測試資料上表現的更加健壯
    with tf.control_dependencies([train_step,ema_op]):
        train_op = tf.no_op(name='train')
 
    saver = tf.train.Saver()
 
    with tf.Session() as sess:
		#所有引數初始化
        init_op = tf.global_variables_initializer()
        sess.run(init_op)
        #每次喂入batch_size組(即200組)訓練資料和對應標籤,迴圈迭代steps輪
        for i in range(STEPS):
            xs, ys = mnist.train.next_batch(BATCH_SIZE)
            _, loss_value, step = sess.run([train_op, loss, global_step], feed_dict={x: xs, y_: ys})
            if i % 1000 == 0:
                print("After %d training step(s), loss on training batch is %g." % (step, loss_value))
				#將當前會話載入到指定路徑
                saver.save(sess, os.path.join(MODEL_SAVE_PATH, MODEL_NAME), global_step=global_step)
 
 
def main():
	#讀入mnist
    mnist = input_data.read_data_sets("./data/", one_hot=True)
    #反向傳播
	backward(mnist)
 
if __name__ == '__main__':
    main()

由上述程式碼可知,在反向傳播過程中,首先引入 tensorflow、input_data、前向傳播 mnist_forward 和 os 模組,定義每輪喂入神經網路的圖片數、初始學習率、學習率衰減率、正則化係數、訓練輪數、模型儲存路徑以及模型儲存名稱等相關資訊。在反向傳播函式 backword 中,首先讀入 mnist,用 placeholder 給訓練資料 x 和標籤 y_佔位,呼叫 mnist_forward 檔案中的前向傳播過程 forword()函式,並設定正則化,計算訓練資料集上的預測結果 y,並給當前計算輪數計數器賦值,設定為不可訓練型別。接著,呼叫包含所有引數正則化損失的損失函式loss,並設定指數衰減學習率 learning_rate。然後,使用梯度衰減演算法對模型優化,降低損失函式,並定義引數的滑動平均。最後,在 with 結構中,實現所有引數初始化,每次喂入 batch_size 組(即 200 組)訓練資料和對應標籤,迴圈迭代 steps 輪,並每隔 1000 輪打印出一次損失函式值資訊,並將當前會話載入到指定路徑。最後,通過主函式 main(),載入指定路徑下的訓練資料集,並呼叫規定的 backward()函式訓練模型。

測試過程檔案(mnist_test.py) 當訓練完模型後,給神經網路模型輸入測試集驗證網路的準確性和泛化性。注意,所用的測試集和訓練集是相互獨立的。實現手寫體 mnist 資料集的識別任務測試傳播過程如下:

#coding:utf-8
#驗證網路的準確性和泛化性
import time
import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
import mnist_forward
import mnist_backward
#程式5秒的迴圈間隔時間
TEST_INTERVAL_SECS = 5
 
def test(mnist):
	#利用tf.Graph()復現之前定義的計算圖
    with tf.Graph().as_default() as g:
		#利用placeholder給訓練資料x和標籤y_佔位
        x = tf.placeholder(tf.float32, [None, mnist_forward.INPUT_NODE])
        y_ = tf.placeholder(tf.float32, [None, mnist_forward.OUTPUT_NODE])
		#呼叫mnist_forward檔案中的前向傳播過程forword()函式
        y = mnist_forward.forward(x, None)
        #例項化具有滑動平均的saver物件,從而在會話被載入時模型中的所有引數被賦值為各自的滑動平均值,增強模型的穩定性
        ema = tf.train.ExponentialMovingAverage(mnist_backward.MOVING_AVERAGE_DECAY)
        ema_restore = ema.variables_to_restore()
        saver = tf.train.Saver(ema_restore)
		#計算模型在測試集上的準確率
        correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
        accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
 
        while True:
            with tf.Session() as sess:
				#載入指定路徑下的ckpt
                ckpt = tf.train.get_checkpoint_state(mnist_backward.MODEL_SAVE_PATH)
				#若模型存在,則加載出模型到當前對話,在測試資料集上進行準確率驗證,並打印出當前輪數下的準確率
                if ckpt and ckpt.model_checkpoint_path:
                    saver.restore(sess, ckpt.model_checkpoint_path)
                    global_step = ckpt.model_checkpoint_path.split('/')[-1].split('-')[-1]
                    accuracy_score = sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels})
                    print("After %s training step(s), test accuracy = %g" % (global_step, accuracy_score))
				#若模型不存在,則打印出模型不存在的提示,從而test()函式完成
                else:
                    print('No checkpoint file found')
                    return
            time.sleep(TEST_INTERVAL_SECS)
 
def main():
	#載入指定路徑下的測試資料集
    mnist = input_data.read_data_sets("./data/", one_hot=True)
    test(mnist)
 
if __name__ == '__main__':
    main()

在上述程式碼中,首先需要引入 time 模組、tensorflow、input_data、前向傳播mnist_forward、反向傳播 mnist_backward 模組和 os 模組,並規定程式 5 秒的迴圈間隔時間。接著,定義測試函式 test(),讀入 mnist 資料集,利用 tf.Graph()復現之前定義的計算圖,利用 placeholder 給訓練資料 x 和標籤 y_佔位,呼叫mnist_forward 檔案中的前向傳播過程 forword()函式,計算訓練資料集上的預測結果 y。接著,例項化具有滑動平均的 saver 物件,從而在會話被載入時模型中的所有引數被賦值為各自的滑動平均值,增強模型的穩定性,然後計算模型在測試集上的準確率。在 with 結構中,載入指定路徑下的 ckpt,若模型存在,則加載出模型到當前對話,在測試資料集上進行準確率驗證,並打印出當前輪數下的準確率,若模型不存在,則打印出模型不存在的提示,從而 test()函式完成。通過主函式 main(),載入指定路徑下的測試資料集,並呼叫規定的 test 函式,進行模型在測試集上的準確率驗證。執行以上三個檔案,可得到手寫體 mnist 資料集的識別任務的執行結果:

執行以上三個檔案,可得到手寫體 mnist 資料集的識別任務的執行結果:

從終端顯示的執行結果可以看出,隨著訓練輪數的增加,網路模型的損失函式值在不斷降低,並且在測試集上的準確率在不斷提升,有較好的泛化能力。修改mnist_forward.py中w和b的初始化方法、修改隱藏層節點個數和隱藏層層數,修改mnist_backward.py程式碼中的超引數,找出最快提升準確度的“全連線網路”解決方案。

#這一節內容好多啊,哭