深度學習之手寫數字識別——用bp神經網絡實現

任務

設計一個bp神經網絡是實現對MNIST手寫數字集的識別任務。
網路結構包含一個輸入層、一個隱層和一個輸出層。 其實總共只有兩個層級結構。

包、數據集載入

我們使用tensorflow來簡化我們的操作。

import tensorflow as tf
import numpy as np
from tensorflow.examples.tutorials.mnist import input_data

# 載入數據集
data = input_data.read_data_sets('MNIST_data/', one_hot=True)

層級結構設計

輸入層中輸入的張量設爲x,類型爲32位浮點型,x以佔位符形式定義,並且其維度爲784。並且每次迭代樣本個數並不確定,主要由迭代batch的大小決定。

x = tf.placeholder(dtype=tf.float32, shape=[None, 784])

隱層牽涉到權值參數與偏置項的設定。在未運行算法之前,需要對權重參數與偏置項進行初始化。
爲防止權重參數恆爲0,我們採用tensorflow的內置方法,將權重參數初始化爲擁有固定標準差的高斯分佈的張量,方法如下:

def weight_variable(shape):
    #權重的初始化
    initial = tf.truncated_normal(shape, stddev=0.1)
    return tf.Variable(initial)

對於偏置項,我們可以直接將其初始化爲某一固定常量,方法如下:

def bias_variable(shape):
    #偏置項的初始化
    initial = tf.constant(0.5, shape=shape)
    return tf.Variable(initial)

爲了增強模型的複雜度,令其擁有較強的識別能力,定義一個隱層來對輸入的圖像數據(28*28*1)進行相應的非線性映射和梯度傳播。

爲了防止命名衝突也爲了代碼邏輯清晰,設立兩個命名空間來存儲對應變量,其中隱層1位於命名空間hidden_layer中,輸出層位於命名空間output_layer中。

hidden_layer、output_layer中分別牽涉到變量w1、b1、w2、b2,分別代表隱層的突觸權重、偏置項,輸出層的突觸權重、偏置項。激活函數設定爲relu函數,隱層末尾添加dropout來隨機的斷開連接。

在經過兩個層級結構的計算和映射之後,將得到一個預測結果。故輸出層是一個由softmax函數作爲輸出單元,最終輸出是一個含10個概率值的行向量。設輸出爲y,則y的得出將根據上一個隱層計算出的張量L1得出,實現代碼如下:

# 定義神經網絡結構
def bp_nn(x, keep_prob):

    with tf.name_scope('hidden_layer'):
	    w1 = weight_varibal([784, 500])
	    b1 = bias_variabl([500])
	    h1 = tf.nn.relu(tf.matmul(x, w1) + b1)
	    L1 = tf.nn.dropout(h1, keep_prob=keep_prob)
	    
    with tf.name_scope('output_layer'):
	    w2 = weight_varibal([500, 10])
	    b2 = bias_variabl([10])
	    y = tf.nn.softmax(tf.matmul(L1, w2) + b2)
 
    return y

實現過程

在定義好了層級結構之後,我們還需要定義超參數、標籤、梯度下降優化器、損失函數等。
代碼如下:

# dropout隨機斷開的概率
keep_prob = tf.placeholder(dtype=tf.float32)

# 標籤
y_ = tf.placeholder(dtype=tf.float32, shape=[None, 10])

# 最終預測值
y = bp_nn(x, keep_prob)

# 定義交叉熵損失函數
cross_entropy = -tf.reduce_sum(y_ * tf.log(y))

# 梯度下降優化目標函數
train_step = tf.train.GradientDescentOptimizer(0.001).minimize(cross_entropy)

# 這是我們算法運行過程中需要判斷的模型準確率
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

要知道tensorflow是基於運算圖的框架,所以我們在定義了一系列佔位符、操作、變量等tensor後,需要在會話裏跑起來,不斷地迭代!
迭代代碼如下:

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    
    for i in range(10000):
        
        x_batch, y_batch = data.train.next_batch(100)
        
        sess.run(train_step, feed_dict={x: x_batch, y_: y_batch, keep_prob: 0.8,})
        
        if i % 1000 == 0:
            train_accuracy = sess.run(accuracy, feed_dict={x: x_batch, y_:y_batch, keep_prob:1.0})
            print('精度' + str(train_accuracy))
            
    print('-----------------------載入測試集----------------------')
    acc = []
    for i in range(1000):
        
        batch = data.test.next_batch(100)
        
        test_accuracy = sess.run(accuracy, feed_dict={x: batch[0], y_:batch[1], keep_prob:1.0})
        
        acc.append(test_accuracy)
    
    mean_accuracy = np.mean(acc)
    
    print(mean_accuracy)

最終輸出如下:

精度0.25
精度0.95
精度0.99
精度1.0
精度0.99
精度0.98
精度0.98
精度1.0
精度0.99
精度0.99
-----------------------載入測試集----------------------
0.97859997

精度不斷上升,並在dropout的作用下,並不穩定。最終測試集上的精度達到0.98。
我們將損失函數的變化記錄在tensorboard中,變化如下圖所示,可以看出來loss呈現明顯下降趨勢。
在這裏插入圖片描述

改進

爲了進一步提升模型準確率,我將在下一篇文章中採用卷積神經網絡(CNN)來解決該問題。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章