LSTM in tensorflow - step by step

原文:
https://jasdeep06.github.io/posts/Understanding-LSTM-in-Tensorflow-MNIST/?spm=5176.100239.blogcont202939.11.snhVUr

【啊我發現已經有人翻譯過了!】
https://yq.aliyun.com/articles/202939?spm=5176.100239.0.0.b7vTwx

瞭解如何用tf實現lstm,以及掌握其細節。以mnist舉例說明。

mnist數據集

mnist數據集包含手寫數字的圖像和對應的標籤。我們可以在tf內部下載並讀取數據:

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)

數據集分爲三個部分:

  • 訓練數據(mnist.train) - 55000張訓練圖片
  • 測試數據(mnist.test) - 10000 images of test data
  • 交叉驗證數據(mnist.validation) -5000 images of validation data.

shape of mnist

訓練集包括55000個圖片,size是28x28。這些784(28x28)個像素值被拉成了一維的向量,所有的55000個像素向量都存儲在numpy的array裏面,(55000,784),這就是mnist.train.images
所有訓練圖片都和一個label相關,label代表所屬的類別。在這裏,有十個類別,即(0,1,2,…,9)。所有lable都用one-hot編碼。所以label也存儲於一個numpy的array裏面,形狀(55000,10),這就是mnist.train.labels

why mnist?

lstm一般用於複雜的序列相關問題,比如包含NLP的word embedding,encoder等。這些問題自身就需要花很多時間去理解了。如果能夠先把這些理解放在一邊,單純的接入lstm的實現細節那當然就非常nice啦~ 所以mnist給了我們這個機會,輸入很簡單,無需過多的預處理,可以很容易的格式化這些數據,然後focus on實現細節~

實現

看代碼之前,先梳理一下實現框架。

普通RNN

這裏寫圖片描述

  • xt :時間t的輸入。
  • st :時間t處的隱藏狀態。可視化爲網絡的內存。
  • Ot :時間t的輸出。
  • UVW :所有時間共享的參數。該參數共享的意義在於,模型在不同時間不同輸入的時候可以執行相同的任務。
    通過RNN想要說明,在每一步,考慮到前一個單元的輸出,網絡都可以可視化爲前饋網絡。

Two caveats

實現隨着兩個概念而定(hinge upon),:

  • tf中LSTM細胞的解釋
  • 在把數據feed進入RNN之前將輸入格式化

Interpretation of LSTM cells in tensorflow

A basic LSTM cell is declared in tensorflow as-

tf.contrib.rnn.BasicLSTMCell(num_units)

num_units指的是lstm中的單位數。可以解釋爲前饋神經網絡的隱藏層,在網絡中,每個時間t,前饋神經網絡的節點數量都等於num_units
這裏寫圖片描述

每個LSTM單元都可以看做標準的LSTM單元:
這裏寫圖片描述

格式化輸入

tf中最簡單的RNN形式是 static_rnn,在tf中如下定義:

tf.static_rnn(cell,inputs)

還有其他參數,不過在此不做討論。

input : 接收形如[batch_size,input_size]的張量。列表長度爲網絡展開的時間長度,每個元素即每個時間t的輸入。


以下來自: link

對於我們的MNIST圖像的情況,我們有大小爲28X28的圖像。它們可以被推斷爲具有28行28像素的圖像。我們將通過28個時間步驟展開我們的網絡,使得在每個時間步長,我們可以輸入一行28像素(input_size),從而通過28個時間步長輸入完整的圖像。如果我們提供batch_size圖像的數量,每個時間步長將提供相應的batch_size圖像行。下圖應該可以解釋上述描述:
這裏寫圖片描述

生成的輸出static_rnn是形狀的張量列表[batch_size,n_hidden]。列表的長度是網絡展開的時間步長數,即每個時間步長的一個輸出張量。在這個實現中,我們將只關注最後時間的輸出,當圖像的所有行被提供給RNN時,即在最後時間步長將產生預測。

我們已經準備好編寫代碼了。如果一旦上述概念很清楚,編寫部分很簡單。

Code

首先,可以導入必需的依賴項、數據集並聲明一些常量。我們將使用batch_size=128num_units=128

import tensorflow as tf
from tensorflow.contrib import rnn
#import mnist dataset
from tensorflow.examples.tutorials.mnist import input_data
mnist=input_data.read_data_sets("/tmp/data/",one_hot=True)
#define constants
#unrolled through 28 time steps
time_steps=28
#hidden LSTM units
num_units=128
#rows of 28 pixels
n_input=28
#learning rate for adam
learning_rate=0.001
#mnist is meant to be classified in 10 classes(0-9).
n_classes=10
#size of batch
batch_size=128

現在讓我們來聲明將其用於形狀的輸出轉換佔位符和權重及偏置變量[batch_size,num_units][batch_size,n_classes]

#weights and biases of appropriate shape to accomplish above task
out_weights=tf.Variable(tf.random_normal([num_units,n_classes]))
out_bias=tf.Variable(tf.random_normal([n_classes]))
#defining placeholders
#input image placeholder    
x=tf.placeholder("float",[None,time_steps,n_input])
#input label placeholder
y=tf.placeholder("float",[None,n_classes])

我們正在接收形狀的輸入[batch_size,time_steps,n_input],我們需要將其轉換成長度形狀[batch_size,n_inputs]的張量列表,time_steps是以便它可以被饋送到static_rnn

#processing the input tensor from [batch_size,n_steps,n_input] to "time_steps" number of [batch_size,n_input] tensors
input=tf.unstack(x ,time_steps,1)

現在我們準備定義我們的網絡。我們將使用一層BasicLSTMCell,使我們的static_rnn網絡脫穎而出。

#defining the network
#這裏原文寫的是n_hidden,其實不應當!應該把n_hidden改爲num_units
#或者在前面再定義一個n_hidden = 128

lstm_layer=rnn.BasicLSTMCell(n_hidden,forget_bias=1)
outputs,_=rnn.static_rnn(lstm_layer,input,dtype="float32")

由於我們要的是預測的結果,所以我們只考慮最後一步的輸入。

#converting last output of dimension [batch_size,num_units] to [batch_size,n_classes] by out_weight multiplication
prediction=tf.matmul(outputs[-1],out_weights)+out_bias

定義損失、優化器和準確性。

#loss_function
loss=tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=prediction,labels=y))
#optimization
opt=tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(loss)
#model evaluation
correct_prediction=tf.equal(tf.argmax(prediction,1),tf.argmax(y,1))
accuracy=tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

現在我們已經定義了圖,我們可以運行它。

#initialize variables
init=tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)
    iter=1
    while iter<800:
      batch_x,batch_y=mnist.train.next_batch(batch_size=batch_size)
        batch_x=batch_x.reshape((batch_size,time_steps,n_input))
        sess.run(opt, feed_dict={x: batch_x, y: batch_y})
       if iter %10==0:
            acc=sess.run(accuracy,feed_dict={x:batch_x,y:batch_y})
            los=sess.run(loss,feed_dict={x:batch_x,y:batch_y})
            print("For iter ",iter)
            print("Accuracy ",acc)
            print("Loss ",los)
            print("__________________")
        iter=iter+1

這裏要注意的一個關鍵點,我們的圖像基本上是被平坦化爲一個單一的維度矢量784。函數
next_batch(batch_size)必然返回batch_size爲784維度向量的批次,因此它們被重塑爲[batch_size,time_steps,n_input]可以被佔位符接受。

我們還可以計算我們的模型的測試精度:

#記得這一段要縮進到session裏面
#calculating test accuracy
test_data = mnist.test.images[:128].reshape((-1, time_steps, n_input))
test_label = mnist.test.labels[:128]
print("Testing Accuracy:", sess.run(accuracy, feed_dict={x: test_data, y: test_label}))

運行時,模型運行測試精度爲99.21%。

這個博客目的是讓讀者對張量流中RNN的實現細節有所瞭解。以便我們建立了一些更復雜的模型,以有效地在張量流中使用RNN。

實驗結果:

這裏寫圖片描述

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