閱讀979 返回首頁    go 阿裏雲 go 技術社區[雲棲]


一步一步帶你用TensorFlow玩轉LSTM

更多深度文章,請關注:https://yq.aliyun.com/cloud


LSTM,全稱為長短期記憶網絡(Long Short Term Memory networks),是一種特殊的RNN,能夠學習到長期依賴關係。LSTM由Hochreiter & Schmidhuber (1997)提出,許多研究者進行了一係列的工作對其改進並使之發揚光大。

LSTM在解決許多問題上效果非常好,現在被廣泛使用。它們主要用於處理序列數據。這個博客的主要目的是讓讀者了解在TensorFlow中,如何實現基本的LSTM網絡並掌握實現的細節。為了實現這一目標,我們把MNIST作為我們的數據集。

MNIST數據集:

MNIST數據集由手寫數字及其相應標簽的圖像組成。我們可以借助TensorFlow的內置功能下載和讀取數據:

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個圖像的測試數據。

驗證數據(mnist.validation)-5000個圖像的驗證數據。

數據形狀:

接下來我們介紹一下MNIST數據集的訓練數據的形狀。

訓練集包括55000個28×28像素的圖像。這些784(28X28)像素值以單個維度向量的形式被平坦化。所有這樣的55000個像素向量(每個圖像一個)的集合被存儲為numpy陣列的形式(55000,784),並被稱為mnist.train.images

這些55000個訓練圖像中的每一個與表示該圖像屬於的類的標簽相關聯。一共有10個這樣的類(0,1,2 ... 9)。標簽以一種熱編碼形式的表示。因此標簽被存儲為numpy形狀陣列的形式(55000,10)被稱為mnist.train.labels

為什麼是MNIST?

LSTM通常用於解決複雜序列的相關問題,如NLP領域的實驗:語言建模、字嵌入,編碼器等。MNIST給了我們解決這類問題的機會。這裏的輸入數據隻是一組像素值。我們可以輕鬆地格式化這些值,並集中應用到問題細節上。

實現

在我們沒有展示代碼之前,讓我們先來看一下這個實驗的實現方式。這會使編碼部分更加容易理解。

A vanilla RNN

經常性的神經網絡,通過時間展開,一般可以被圖像化視為:

5abd67bdcedeb92f5bca68011ca73751c67196bf

1.Xt是指時間步長t的輸入。

2.St是指時間步長t處的隱藏狀態。它可以被可視化為網絡的“內存”。

3.Ot指的是輸出在時間步長t。

4.U,V和W是所有時間步長共享的參數。該參數共享的意義在於,我們的模型在不同輸入的時間步長可以執行相同的任務。

我們通過展開RNN想要介紹的是,在每個時間步驟中,網絡可以被視為前饋網絡,同時要考慮到前一個時間步長的輸出(由時間步長之間的連接表示)。

兩個警告:

我們的實現將取決於兩個主要概念。

1.TensorFlow中LSTM細胞的解釋。

2.將輸入格式化,然後將其輸入到TensorFlow RNNs中。

TensorFlow中LSTM細胞的解釋:

基本的LSTM細胞單元在TensorFlow中聲明為:

tf.contrib.rnn.BasicLSTMCell(num_units)

這裏的num_units指的是LSTM單元中的單位數。

num_units可以解釋為前饋神經網絡隱藏層的類比。前饋神經網絡隱層中的節點num_units數目等於LSTM網絡每個時間步長的LSTM單元的數量。以下圖片應該可以幫助你理解:

5f26905707990fb8d84579c22bb760790d7f5788

每個num_unitsLSTM網絡都可以將它看作是一個標準的LSTM單元。

73c8331ebfb2eb1d73ed8c95c6d25f1af9c81d7c

上圖是從文章開頭的博客中得到,它精準的描述了LSTM的概念。

將輸入格式化,然後將其輸入到TensorFlow RNNs中

張量流(tensorflow)中最簡單的RNN形式是在static_rnn中定義:

tf.static_rnn(cell,inputs)

當然還有其他形式的定義方法,這裏我們隻需要用到最簡單的定義方法。

inputs參數是為了接受形狀張量列表[batch_size,input_size]。該列表的長度是網絡展開的時間步長數,即該列表的每個元素對應於我們展開網絡的相應時間步長的輸入。

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

6b5e0d6a38b0f438078cd61cae6a4300b57145d8

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

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

首先,可以導入必需的依賴項、數據集並聲明一些常量。我們將使用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
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_size784維度向量的批次,因此它們被重塑為[batch_size,time_steps,n_input]可以被占位符接受。

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

#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。

本文由北郵@愛可可-愛生活老師推薦,@阿裏雲雲棲社區組織翻譯。

文章原標題《Understanding LSTM in Tensorflow(MNIST dataset)

作者:jasdeep06 博客:https//jasdeep06.github.io/

譯者:袁虎 審閱:主題曲哥哥

文章為簡譯,更為詳細的內容,請查看原文



最後更新:2017-09-12 00:02:37

  上一篇:go  LSTM的“前生今世”
  下一篇:go  人工智能在細分及新興領域的應用