1. 程式人生 > >一步一步使用Tensorflow實現LSTM對mnist分類

一步一步使用Tensorflow實現LSTM對mnist分類

一步一步使用Tensorflow實現LSTM對mnist分類

標籤: LSTM Tensorflow


關於RNN或者LSTM的介紹可以看這裡

讀入資料集以及定義超引數

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
tf.set_random_seed(1)
# import data
# 讀入資料 ./data 代表資料集 位置
mnist = input_data.read_data_sets('./data/',one_hot=True)
# 學習率
lr = 1e-3
# 迭代次數
training_iters = 100000
# 一個批次的大小
batch_size = 128
# 輸入的大小 相當於xt的大小
n_inputs = 28
# 對於LSTM要經過多少步,相當於time_steps
n_steps = 28
# 把輸入的資料過一下全連線層
n_in_units = 64
#lstmcell的結點個數
n_hidden_units = 128
# 類別個數(0-9)
n_classes = 10

關於n_inputs其實就是輸入時候每個 x t x_t 的大小,而 n _ s t

e p s n\_steps 就相當於有多個 x t x_t
,對於這個例子剛好所有的 n _ s t e p s n\_steps 合起來就是一張圖片(28*28)。

網路結構

在這裡插入圖片描述

從圖上可以看出來我們除了使用了LSTMcell,還增加了兩個全連線層,分別在輸入的位置和輸出的位置。


#define x,y
x = tf.placeholder(tf.float32,[None,n_steps,n_inputs])
y = tf.placeholder(tf.float32,[None,n_classes])
# init eights
weights ={
    # 輸入Lstm的最後一維度可以自己定義
    "in":tf.Variable(tf.random_normal([n_inputs,n_in_units])),
    "out":tf.Variable(tf.random_normal([n_hidden_units,n_classes]))
    }
biases ={
    "in":tf.Variable(tf.constant(0.1,shape=[n_in_units])),
    "out":tf.Variable(tf.constant(0.1,shape=[n_classes]))
    }
# define the model
def RNN(X,weights,biases):
    # 3D->2D (batch,n_step,n_inputs)->(batch*n_step,n_inputs)
    X = tf.reshape(X,[-1,n_inputs])
    X_in = tf.matmul(X,weights["in"])+biases["in"]
    # 2D->3D to feed into the RNN cell
    X_in = tf.reshape(X_in,[-1,n_steps,n_in_units])
    # define the RNN cell
    lstm_cell = tf.contrib.rnn.BasicLSTMCell(n_hidden_units)
    init_state = lstm_cell.zero_state(batch_size,dtype = tf.float32)
    # if inputs is (batches, steps, inputs) ==> time_major=False;
    # if inputs is (steps, batches, inputs) ==> time_major=True;
    #  state is (c_state, h_state) and the outputs is equal h_state
    # outputs (batch_size,n_steps,n_hidden_units)
    # final_state is a tuple (c,h) and the c (batch_size,n_hidden_units) ,h(batch_size,n_hidden_units)
    outputs,final_state = tf.nn.dynamic_rnn(lstm_cell,X_in,initial_state=init_state,time_major= False)
    # 從下面程式碼可以看出 final_state[1] 是h ,相當於最後一個輸出
    # ouputs 裡面有所有步的輸出,相當於所有步的h ,所以 output[-1] 等於 h
#     print(outputs)
#     print(final_state)
#     print(len(tf.unstack(tf.transpose(outputs, [1,0,2]))))
#     print(tf.unstack(tf.transpose(outputs, [1,0,2]))[-1])
#     outputs = tf.unstack(tf.transpose(outputs,[1,0,2]))
#     results = tf.matmul(outputs[-1],weights["out"])+biases["out"]
#  注意與sin那個區分,因為sin那個是每一步其實都代表一個數據,所以要所有步的輸出,相當於多對多
#而這裡是多步相當於一個圖片,所以要最後的狀態就行了
    results = tf.matmul(final_state[1],weights["out"])+biases["out"]
    return results

這段程式碼就定義了前向傳播過程,關於這個定義,有幾個地方需要指出。

lstm_cell = tf.contrib.rnn.BasicLSTMCell(n_hidden_units)
init_state = lstm_cell.zero_state(batch_size,dtype = tf.float32)  

這兩行程式碼第一行定義了一個lstm_cell,有n_hidden_units個結點,而第二句定義了初始的輸入,一般全零(因為lstm在輸入的時候除了x還有一個上層的輸出,而對於初始的時候,由於沒有上一層的輸出,所以用全零)。

outputs,final_state = tf.nn.dynamic_rnn(lstm_cell,X_in,initial_state=init_state,time_major= False)  

這句程式碼是代表執行了lstm_cell,並且能連續執行n_steps次,它使用的lstmc_cell就是上面定義的,然後X_in 是一個[batch_size,n_steps,n_in_units]形狀的三維陣列,而tf.nn.dynamic_rnn之所以知道要執行幾次只需要看n_steps為多少就行了,而time_major=False則代表X資料的輸入格式是[batch_size,n_steps,n_in_units],如果time_major=True則代表X資料的輸入格式是[n_steps,batch_size,n_in_units]。所以這個函式能連續執行n_stpes步,並且把每步執行的輸出都存入outputs中,而把最後的狀態返回給final_state。

對於這個例子最終outputs的形狀為[bathc_size,n_steps,n_hidden_units],而final_state是一個tuple裡面包含了兩個狀態一個c一個h,一般我們用h的比較多,其實h就是每步的輸出,所以這裡final_state中的h的形狀為(batch_size,n_hidden_units),就是相當於最後一個outputs。所以如果我們只需要最後一個輸出的時候我們用final_state中的h就行了,如果要全部步的輸出的話我們就用outputs,在這個例子裡面我們只需要最後一步的輸出,因為只有到了最後一步我們才能讀完一張圖片。

定義損失函式以及開始訓練

pre  = RNN(x,weights,biases)
# labels=None, logits=None,
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels = y,logits = pre))
train_op = tf.train.AdamOptimizer(lr).minimize(cost)
# print(tf.argmax(pre,1)==tf.argmax(y,1))
correct = tf.equal(tf.argmax(pre,1),tf.argmax(y,1))
acc = tf.reduce_mean(tf.cast(correct,tf.float32))
with tf.Session() as sess:
    tf.global_variables_initializer().run()
    step = 0
    while step*batch_size <training_iters:
        batch_xs,batch_ys = mnist.train.next_batch(batch_size)
        batch_xs =batch_xs.reshape([batch_size,n_steps,n_inputs])
        feed_dict={x:batch_xs,y:batch_ys}
        sess.run(train_op,feed_dict=feed_dict)
        if step%20==0:
            print(sess.run([cost,acc],feed_dict=feed_dict))
        step+=1

這裡損失就直接使用交叉熵,而優化方法使用AdamOptimizer,後面的都比較簡單了,喂入資料就行了,但是在喂入資料前一定要注意修改資料的格式變為[batch_size,n_steps,n_inputs]。

參考:

https://morvanzhou.github.io/tutorials/machine-learning/tensorflow/5-08-RNN2/