1. 程式人生 > >神經網路實現Mnist手寫數字識別筆記

神經網路實現Mnist手寫數字識別筆記

目錄

1.Mnist手寫數字識別介紹

        Mnist手寫數字識別是Kaggle上一個很經典的機器學習資料集,裡邊包括55000張訓練資料和10000張圖片的測試資料,每張圖片大小為28*28畫素的單通圖片。該任務為通過機器學習來識別圖片中的數字屬於0,1,2,3,4,5,6,7,8,9中那個,是個典型的多分類問題。

       圖片長什麼樣呢?展示如下:

2.神經網路架構介紹

       神經網路在設計開始前,我們只能知道多少個訓練樣本、多少個特徵和最終需要怎樣的結果,對於中間層的神經元個數都是未知的,這常常需要在訓練過程中進行大量調整。對於手寫數字識別問題,我們知道訓練樣本為28*28的單色黑白影象,訓練樣本有55000個,最終要得出每張圖片的分類到底是數字0,1,2,3,4,5,6,7,8,9中哪一類。也就是說這是一個10分類問題。

      神經網路每一層的神經元個數和層數雖說有很大的經驗成分,但是神經元個數要和在輸入資料維數和輸出資料維數之間相“契合”。對於神經網路來說,輸入的一張28*28畫素的影象是將其“壓扁”為784畫素的一維向量,這784個畫素點最為784個特徵。一張影象有784個特徵,那麼將N張影象同時輸入,則相當於將N*784的資料輸入。這裡的N通常是批量處理時每一次輸入資料的批量大小,比如本例子中我們每次遍歷輸入100張圖片,那麼N就是100。

      神經網路中,上一層的輸出作為下一層的輸入。計算主要包括線性計算和非線性計算,線性計算就是x*w+bias,非線性計算則是對x*w+bias的計算結果進行非線性啟用,比如sigmod(

)函式和ReLu(max(0, x*w+bias)函式。本例子對網路架構定義如下圖所示,除了輸入層和輸出層外,增加了兩個隱藏層。隱藏層1設計了256個神經元,隱藏層2設計了128個神經元。那麼,我們就可以推倒出W1和W2的大小。W1維度為:784*256,W2維度為:256*128,W3維度為:128*10。

3.程式碼實現

import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow.examples.tutorials.mnist import input_data
#獲取手寫字型識別資料
mnist = input_data.read_data_sets('data/', one_hot=True)

#網路架構定義
#第一個隱層有256個神經元
n_hidden_1 = 256 
#第二個隱層有128個神經元
n_hidden_2 = 128
#輸入的樣本有784個特徵 
n_input    = 784
#手寫字分為0 1 2....9這10個類別
n_classes  = 10  

# 輸入和輸出
x = tf.placeholder("float", [None, n_input])
y = tf.placeholder("float", [None, n_classes])
    
# 各層網路引數定義
stddev = 0.1
weights = {
    'w1': tf.Variable(tf.random_normal([n_input, n_hidden_1], stddev=stddev)),
    'w2': tf.Variable(tf.random_normal([n_hidden_1, n_hidden_2], stddev=stddev)),
    'out': tf.Variable(tf.random_normal([n_hidden_2, n_classes], stddev=stddev))
}
biases = {
    'b1': tf.Variable(tf.random_normal([n_hidden_1])),
    'b2': tf.Variable(tf.random_normal([n_hidden_2])),
    'out': tf.Variable(tf.random_normal([n_classes]))
}

#前向傳播計算
def multilayer_perceptron(_X, _weights, _biases):
    #根據輸入_X計算第一層
    layer_1 = tf.nn.sigmoid(tf.add(tf.matmul(_X, _weights['w1']), _biases['b1']))
    #以第一層layer_1作為輸入計算第二層
    layer_2 = tf.nn.sigmoid(tf.add(tf.matmul(layer_1, _weights['w2']), _biases['b2']))
    #以第二層layer_2作為輸入計算第三層,也就是計算輸出層
    return (tf.matmul(layer_2, _weights['out']) + _biases['out'])

# 前向傳播進行預測
pred = multilayer_perceptron(x, weights, biases)

#求損失函式
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y))
#使用隨機梯度下降進行優化
optm = tf.train.GradientDescentOptimizer(learning_rate=0.001).minimize(cost)
#預測值和真實標籤進行對比,tf.argmax(pred, 1)返回的是pred中最大值的索引號
#tf.equal將預測的值和標籤值進行比較,相同為True,不相同為False
corr = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
#tf.cast為型別轉換函式,將corr轉換為float型別資料 
accr = tf.reduce_mean(tf.cast(corr, "float"))

# INITIALIZER
init = tf.global_variables_initializer()

#訓練200個epoch
training_epochs = 200
#每一個batch取100個樣本
batch_size      = 100
display_step    = 4
# LAUNCH THE GRAPH
sess = tf.Session()
sess.run(init)
# 遍歷epoch
for epoch in range(training_epochs):
    avg_cost = 0.
    #計算batch次數
    total_batch = int(mnist.train.num_examples/batch_size)
    # 遍歷batch
    for i in range(total_batch):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)
        feeds = {x: batch_xs, y: batch_ys}
        sess.run(optm, feed_dict=feeds)
        avg_cost += sess.run(cost, feed_dict=feeds)
    avg_cost = avg_cost / total_batch
    # DISPLAY
    if (epoch+1) % display_step == 0:
        print ("Epoch: %03d/%03d cost: %.9f" % (epoch, training_epochs, avg_cost))
        feeds = {x: batch_xs, y: batch_ys}
        train_acc = sess.run(accr, feed_dict=feeds)
        print ("TRAIN ACCURACY: %.3f" % (train_acc))
        feeds = {x: mnist.test.images, y: mnist.test.labels}
        test_acc = sess.run(accr, feed_dict=feeds)
        print ("TEST ACCURACY: %.3f" % (test_acc))
print ("OPTIMIZATION FINISHED")

4.執行結果

執行結果如下,可以看出經過200輪訓練後,得到的測試精確度達到了0.884。

Epoch: 003/200 cost: 2.278398191
TRAIN ACCURACY: 0.260
TEST ACCURACY: 0.198
Epoch: 007/200 cost: 2.245890754
.......
Epoch: 191/200 cost: 0.457598143
TRAIN ACCURACY: 0.920
TEST ACCURACY: 0.883
Epoch: 195/200 cost: 0.452329346
TRAIN ACCURACY: 0.860
TEST ACCURACY: 0.883
Epoch: 199/200 cost: 0.447292094
TRAIN ACCURACY: 0.910
TEST ACCURACY: 0.884
OPTIMIZATION FINISHED

5.程式碼中部分方法介紹

  1.tf.random_normal

    功能:tf.random_normal()函式用於從服從指定正太分佈的數值中取出指定個數的值。     函式宣告:tf.random_normal(shape, mean=0.0, stddev=1.0, dtype=tf.float32, seed=None, name=None)     引數:shape: 輸出張量的形狀,必選                mean: 正態分佈的均值,預設為0                stddev: 正態分佈的標準差,預設為1.0                dtype: 輸出的型別,預設為tf.float32                seed: 隨機數種子,是一個整數,當設定之後,每次生成的隨機數都一樣                name: 操作的名稱

2.tf.nn.softmax_cross_entropy_with_logits

3.tf.equal(x, y, name=None)

功能:tf.equal用於判斷x和y是否相等,對於單個值直接進行判斷,相同返回True,不同返回False。對於向量則遍歷相同位置的數進行判斷,返回值也是向量,相同時對應位置為True,不相同時對應位置為False。

4.tf.cast(x, dtype, name=None)

功能:tf.cast為型別轉換函式,將x轉換為dtype型別資料。

5.tf.argmax(vector, 1)

功能:tf.argmax(vector, 1)返回的時vector中最大值的索引。如果vector是一個向量,那就返回其中最大值的索引,如果是一個矩陣,那就返回一個向量,這個向量的每一維都是對應矩陣行的最大值元素索引號。