1. 程式人生 > >【深度學習】6:RNN遞迴神經網路原理、與MNIST資料集實現數字識別

【深度學習】6:RNN遞迴神經網路原理、與MNIST資料集實現數字識別

前言:自己學習研究完CNN卷積神經網路後,很久的一段時間因為要完成自己的畢業設計就把更新部落格給耽擱了。瞎忙了這麼久,還是要把之前留的補上來。因為“種一棵樹最好的時間是在十年前,其次就是現在!”
—-—-—-—-—-—-—-—-—-—-—-—–—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
—-—-—-—-—-—-—-—-—-—-—-—–—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-

遞迴神經網路與迴圈神經網路聯絡

  • CNN卷積神經網路和RNN遞迴神經網路都是由BP神經網路演化而來的。CNN卷積神經網路主要應用在影象識別領域;而RNN遞迴神經網路的改進版LSTM網路主要應用於自然語言處理中;
  • 為什麼我介紹RNN是叫——遞迴神經網路?這之前是一個困擾我很久的問題。因為在網上搜索RNN既有人說是遞迴神經網路,也有人說是迴圈神經網路,而且兩個的區別也不明顯,混淆很久,直到請教前輩——遞迴神經網路是從神經網路的執行狀態劃分的,由下面圖示就可以瞭解到這種神經網路在執行時像是自行迭代;而迴圈神經網路可以看作是遞迴神經網路的特例,以示區別就把遞迴神經網路總稱RNN,迴圈神經網路叫做RNNs

一、RNN原理介紹

RNN神經網路為什麼廣泛應用於自然語言處理?因為它是依靠時間序列具有記憶功能的——這一刻的輸出,除了考慮這一刻的輸入外,還有一部分是來自上一刻的輸出記憶。同時這一刻的輸出也會有一部分做為“記憶”傳給下一刻。

這裡寫圖片描述

上圖是RNN神經網路的結構示意圖。上左圖是簡化過程,介紹從上右圖說起:

  1. 上右圖包含t-1、t、t+1三個時刻的輸入與輸出;
  2. t時刻的輸入Xt經權值U、t-1時刻的狀態記憶經權值W共同作用構成t時刻的狀態St;
  3. t時刻的狀態St作為一部分記憶經權值W傳入下一時刻,也作為t時刻的輸出經權值V作用後輸出Ot。

形象的比喻——橫向的傳播就是遊戲的主線,遊戲過程中不斷有縱向的分線任務X傳入,每一個分線任務都對主線任務構成影響且都能生成一個預測結果O,最後一個輸出O就是遊戲的最終結果;

用RNNs結合MNIST資料集做圖片識別,輸入的一個X就是MNIST資料集中圖片的一行28個畫素點資料的向量。

在以下的資料維度說明中有更詳細的介紹。

二、用RNNs預測MNIST資料

之前介紹了BP神經網路、CNN卷積神經網路用MNIST資料集做影象識別,現在介紹用RNNs迴圈神經網路也是用MNIST資料集做影象識別。這個識別原理也非常有趣。(詳細解析處程式碼都是虛擬碼,原始碼在最後附上)

RNNs做影象識別原理:MNIST資料集中一張圖片資料包含28*28的畫素點。RNNs是將一張圖片資料的一行作為一個向量總體輸入一個X中。也就是說,RNNs有28個輸入X,一個輸入X有28個畫素點。t=1時刻輸入X1,得到中間狀態S1,由S1得到預測值O1(現在的O1由於只考慮一張圖片的一行資料而已,預測結果很不可靠),S1也作為一部分記憶,再與圖片下一行的輸入X2相作用,得到中間狀態S2,再得到預測值O2……迴圈迭代,直到將一張圖片的28行全都代入,輸出最後一個O28做為預測值。

2.1:MNIST資料集的讀取

from tensorflow.examples.tutorials.mnist import input_data  
mnist = input_data.read_data_sets('MNIST_data',one_hot = True)
batch_size = 100
batch_xs,batch_ys = mnist.train.next_batch(batch_size)

這個MNIST資料集的讀取我已經介紹了好多好多次了…如果本目錄下沒有MNIST資料集,程式會自動下載。讀取的資料先存入“mnist”陣列中,並按照每100個圖片作為一個批次,將訓練集的圖片資料存入“batch_xs”陣列,圖片標籤項存入“batch_ys ”。

2.2:輸入資料維度說明

n_inputs = n_steps = 28
# batch_xs shape = [100,28,28]
X = batch_xs.reshape([batch_size,n_steps,n_inputs])
...
# X shape = (100batch,28steps,28inputs) ==> (100batch*28steps,28inputs)
X = tf.reshape(X,[-1,n_inputs])
# X_in shape ==> (100batch*28steps,128hidden)
X_in = tf.matmul(X,weights['in'])+biases['in']
# X_in shape ==> (100batch,28steps,128hidden)
X_in = tf.reshape(X_in,[-1,n_steps,n_hidden_number])

這裡可以說是很煩人的地方了,輸入資料的維度出錯程式總是報錯,真的煩了很久:(因為批次的原因使得資料變成三維,而權重閾值計算是二維的

  • 之前我們確定的每一個批次有100張圖片資料,就相當於將100張28*28的圖片疊放在一起,讀取的就是一個三維立體的整體(長寬都是28,高100)。所以第3行程式碼先將讀取的整批圖片切割成[100,28,28]的單個圖片;
  • 依據上面介紹的RNNs做影象識別的原理出發,每個輸入X都是一張圖片的一行,再構造與圖片行數相同個數的輸入神經元就可以完成一張圖片的識別。但現在是100張圖片一起識別,就需要將三維立體的整體資料轉化為二維才能與閾值、權重代入計算,第6行程式碼就是降維運算;
  • 經過降維運算,RNNs神經網路輸入層28個神經元中每一個神經元輸入的維度是100*28,經過第8行權值閾值處理後,得到X_in。(隱藏層有128個神經元,所以X_in此時維度是[100*28,128])
  • 再將得到的X_in切割成[100,28,128],繼續後續cell核運算
  • -

2.3:RNNs的核運算

首先說明:這個“核運算”是我為書寫方便自創的

lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(n_hidden_number,forget_bias = 1.0)
# LSTM cell is divided into two parts(c_state,m_state)
init_state = lstm_cell.zero_state(batch_size,dtype=tf.float32)
outputs,states = tf.nn.dynamic_rnn(lstm_cell,X_in,initial_state=init_state,time_major=False)

這個核運算也是基於TensorFlow框架。

  • 首先建立RNN運算核——lstm_cell,選擇的cell是BasicLSTMCell(tf.nn.rnn中有許多,這裡不做介紹),引數是隱藏層神經元個數;
  • RNN的中間狀態會得到兩部分——一個是當前輸出outputs,另一個是下時刻的記憶states,RNN在init_state中用c_state、m_state分別儲存這兩部分;
  • 用dynamic_rnn的方法,用輸入值X_in進行核內運算,將輸出分別存入相應陣列中。

2.4:計算輸出

result = tf.matmul(states[1],weights['out'])+biases['out']
  • 在核內以X_in為輸入,得到輸出outputs與states,當所有行都代入計算得到最後的輸出預測值。其中states[1] = outputs[-1],相當於最後一個輸出值。

三、原始碼與效果展示

# -*- coding:utf-8 -*-
# -*- author:zzZ_CMing
# -*- 2018/02/05;09:58
# -*- python3.5

from tensorflow.examples.tutorials.mnist import input_data
import tensorflow as tf
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

mnist = input_data.read_data_sets('MNIST_data',one_hot = True)

training_iters = 50001
batch_size = 100          #批量大小

n_inputs = n_steps = 28
n_hidden_number = 128    #隱藏層神經元個數
n_outputs = 10           #輸出層神經元個數

x = tf.placeholder(tf.float32,[None,n_steps,n_inputs])
Y = tf.placeholder(tf.float32,[None,n_outputs])

weights = {
    # shape = (28,128)
    'in':tf.Variable(tf.random_normal([n_inputs,n_hidden_number])),
    # shape = (128,10)
    'out':tf.Variable(tf.random_normal([n_hidden_number,n_outputs]))}

biases = {
    # shape = (128,)
    'in':tf.Variable(tf.constant(0.1,shape = [n_hidden_number,])),
    # shape = (10,)
    'out':tf.Variable(tf.constant(0.1,shape = [n_outputs,]))}


def RNN(X,weights,biases):
    ### 輸入層到核運算 ###
    # X shape = (100batch,28steps,28inputs) ==> (100batch*28steps,28inputs)
    X = tf.reshape(X,[-1,n_inputs])
    # X_in shape ==> (100batch*28steps,128hidden)
    X_in = tf.matmul(X,weights['in'])+biases['in']
    # X_in shape ==> (100batch,28steps,128hidden)
    X_in = tf.reshape(X_in,[-1,n_steps,n_hidden_number])

    ### cell核內運算 ###
    lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(n_hidden_number,forget_bias = 1.0)
    # LSTM cell is divided into two parts-->(c_state,m_state)
    init_state = lstm_cell.zero_state(batch_size,dtype=tf.float32)
    outputs,states = tf.nn.dynamic_rnn(lstm_cell,X_in,initial_state=init_state,time_major=False)

    ### 核內運算到輸出層 ###
    result = tf.matmul(states[1],weights['out'])+biases['out']
    return  result


prediction = RNN(x,weights,biases)
#二次代價函式:預測值與真實值的誤差
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(labels=Y, logits=prediction))
#梯度下降法:資料龐大,選用AdamOptimizer優化器
train_step = tf.train.AdamOptimizer(1e-3).minimize(loss)
#結果存放在一個布林型列表中
correct_prediction = tf.equal(tf.argmax(prediction,1), tf.argmax(Y,1))
#求準確率
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

init = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)
    step = 0
    while step*batch_size < training_iters:
        batch_xs,batch_ys = mnist.train.next_batch(batch_size)
        # batch_xs shape = [100,28,28]
        batch_xs = batch_xs.reshape([batch_size,n_steps,n_inputs])
        train_step.run(feed_dict={x:batch_xs,Y:batch_ys,})
        if step%50 == 0:
            train_accuracy = accuracy.eval(feed_dict={x:batch_xs,Y:batch_ys,})
            print("step", step, "training accuracy", train_accuracy)
        step += 1

效果展示:
這裡寫圖片描述

—-—-—-—-—-—-—-—-—-—-—-—–—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
—-—-—-—-—-—-—-—-—-—-—-—–—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-

系列推薦: