用tensorflow搭建RNN(LSTM)進行MNIST 手寫數字辨識(轉自http://www.cnblogs.com/sandy-t/p/6930608.html)

用tensorflow搭建RNN(LSTM)進行MNIST 手寫數字辨識

循環神經網絡RNN相比傳統的神經網絡在處理序列化數據時更有優勢,因爲RNN能夠將加入上(下)文信息進行考慮。一個簡單的RNN如下圖所示:

將這個循環展開得到下圖:

上一時刻的狀態會傳遞到下一時刻。這種鏈式特性決定了RNN能夠很好的處理序列化的數據,RNN 在語音識別,語言建模,翻譯,圖片描述等問題上已經取得了很到的結果。
根據輸入、輸出的不同和是否有延遲等一些情況,RNN在應用中有如下一些形態:

RNN存在的問題

RNN能夠把狀態傳遞到下一時刻,好像對一部分信息有記憶能力一樣,如下圖:

h3h3的值可能會由x1x1,x2x2的值來決定。
但是,對於一些複雜場景

由於距離太遠,中間間隔了太多狀態,x1x1,x2x2對ht+1ht+1的值幾乎起不到任何作用。(梯度消失和梯度爆炸)

LSTM(Long Short Term Memory)

由於RNN不能很好地處理這種問題,於是出現了LSTM(Long Short Term Memory)一種加強版的RNN(LSTM可以改善梯度消失問題)。簡單來說就是原始RNN沒有長期的記憶能力,於是就給RNN加上了一些記憶控制器,實現對某些信息能夠較長期的記憶,而對某些信息只有短期記憶能力。
如上圖所示,LSTM中存在Forget Gate,Input Gate,Output Gate來控制信息的流動程度。
RNN:

LSTN:

加號圓圈表示線性相加,乘號圓圈表示用gate來過濾信息。

Understanding LSTM中對LSTM有非常詳細的介紹。(對應的中文翻譯

LSTM MNIST手寫數字辨識

實際上,圖片文字識別這類任務用CNN來做效果更好,但是這裏想要強行用LSTM來做一波。
MNIST_data中每一個image的大小是28*28,以行順序作爲序列輸入,即第一行的28個像素作爲$x_{0}
,第二行爲,第二行爲x_1,...,第28行的28個像素作爲,...,第28行的28個像素作爲x_28$輸入,一個網絡結構總共的輸入是28個維度爲28的向量,輸出值是10維的向量,表示的是0-9個數字的概率值。這是一個many to one的RNN結構。

這裏outputs,final_state = tf.nn.dynamic_rnn(...).
final_state包含兩個量,第一個爲c保存了每個LSTM任務最後一個cell中每個神經元的狀態值,第二個量h保存了每個LSTM任務最後一個cell中每個神經元的輸出值,所以c和h的維度都是[BATCH_SIZE,NUM_UNITS]。
outputs的維度是[BATCH_SIZE,TIME_STEP,NUM_UNITS],保存了每個step中cell的輸出值h。
由於這裏是一個many to one的任務,只需要最後一個step的輸出outputs[:, -1, :],output = tf.layers.dense(inputs=outputs[:, -1, :], units=N_CLASSES) 通過一個全連接層將輸出限制爲N_CLASSES。

 

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

# 數據集路徑
data_dir='G:/code_materials/Machine_Learning/MNIST_data'

# 自動下載 MNIST 數據集
# mnist = input_data.read_data_sets(data_dir, one_hot=True)

# 如果自動下載失敗,則手工從官網上下載 MNIST 數據集,然後進行加載
# 下載地址  http://yann.lecun.com/exdb/mnist/
mnist=input_data.read_data_sets(data_dir,one_hot=True)

# 參數設置
BATCH_SIZE = 100        # BATCH的大小,相當於一次處理50個image
TIME_STEP = 28          # 一個LSTM中,輸入序列的長度,image有28行
INPUT_SIZE = 28         # x_i 的向量長度,image有28列
LR = 0.01               # 學習率
NUM_UNITS = 100         # 多少個LTSM單元
ITERATIONS=8000         # 迭代次數
N_CLASSES=10            # 輸出大小,0-9十個數字的概率

# 定義 placeholders 以便接收x,y
train_x = tf.placeholder(tf.float32, [None, TIME_STEP * INPUT_SIZE])       # 維度是[BATCH_SIZE,TIME_STEP * INPUT_SIZE]
image = tf.reshape(train_x, [-1, TIME_STEP, INPUT_SIZE])                   # 輸入的是二維數據,將其還原爲三維,維度是[BATCH_SIZE, TIME_STEP, INPUT_SIZE]
train_y = tf.placeholder(tf.int32, [None, N_CLASSES])

# 定義RNN(LSTM)結構
rnn_cell = tf.contrib.rnn.BasicLSTMCell(num_units=NUM_UNITS)
outputs,final_state = tf.nn.dynamic_rnn(
    cell=rnn_cell,              # 選擇傳入的cell
    inputs=image,               # 傳入的數據
    initial_state=None,         # 初始狀態
    dtype=tf.float32,           # 數據類型
    time_major=False,           # False: (batch, time step, input); True: (time step, batch, input),這裏根據image結構選擇False
)
output = tf.layers.dense(inputs=outputs[:, -1, :], units=N_CLASSES)


loss = tf.losses.softmax_cross_entropy(onehot_labels=train_y, logits=output)      # 計算loss
train_op = tf.train.AdamOptimizer(LR).minimize(loss)      #選擇優化方法

correct_prediction = tf.equal(tf.argmax(train_y, axis=1),tf.argmax(output, axis=1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction,'float'))  #計算正確率

sess = tf.Session()
sess.run(tf.global_variables_initializer())     # 初始化計算圖中的變量

for step in range(ITERATIONS):    # 開始訓練
    x, y = mnist.train.next_batch(BATCH_SIZE)
    test_x, test_y = mnist.test.next_batch(5000)
    _, loss_ = sess.run([train_op, loss], {train_x: x, train_y: y})
    if step % 500 == 0:      # test(validation)
        accuracy_ = sess.run(accuracy, {train_x: test_x, train_y: test_y})
        print('train loss: %.4f' % loss_, '| test accuracy: %.2f' % accuracy_)

 

 

 

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