一步一步使用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其實就是輸入時候每個 的大小,而 就相當於有多個 ,對於這個例子剛好所有的 合起來就是一張圖片(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/