天天看點

tensorflow LSTM

循環神經網絡

介紹

可以在 this great article 檢視循環神經網絡(RNN)以及 LSTM 的介紹。

語言模型

此教程将展示如何在高難度的語言模型中訓練循環神經網絡。該問題的目标是獲得一個能确定語句機率的機率模型。為了做到這一點,通過之前已經給出的詞語來預測後面的詞語。我們将使用 PTB(Penn Tree Bank) 資料集,這是一種常用來衡量模型的基準,同時它比較小而且訓練起來相對快速。

語言模型是很多有趣難題的關鍵所在,比如語音識别,機器翻譯,圖像字幕等。它很有意思--可以參看 here。

本教程的目的是重制 Zaremba et al., 2014 的成果,他們在 PTB 資料集上得到了很棒的結果。

教程檔案

本教程使用的下面檔案的目錄是

models/rnn/ptb

:

檔案 作用

ptb_word_lm.py

在 PTB 資料集上訓練一個語言模型.

reader.py

讀取資料集.

下載下傳及準備資料

本教程需要的資料在 data/ 路徑下,來源于 Tomas Mikolov 網站上的 PTB 資料集

http://www.fit.vutbr.cz/~imikolov/rnnlm/simple-examples.tgz

該資料集已經預先處理過并且包含了全部的 10000 個不同的詞語,其中包括語句結束标記符,以及标記稀有詞語的特殊符号

(<unk>)

。我們在

reader.py

中轉換所有的詞語,讓他們各自有唯一的整型辨別符,便于神經網絡處理。

模型

LSTM

模型的核心由一個 LSTM 單元組成,其可以在某時刻處理一個詞語,以及計算語句可能的延續性的機率。網絡的存儲狀态由一個零矢量初始化并在讀取每一個詞語後更新。而且,由于計算上的原因,我們将以

batch_size

為最小批量來處理資料。

基礎的僞代碼就像下面這樣:

lstm = rnn_cell.BasicLSTMCell(lstm_size)
# 初始化 LSTM 存儲狀态.
state = tf.zeros([batch_size, lstm.state_size])

loss = 0.0
for current_batch_of_words in words_in_dataset:
    # 每次處理一批詞語後更新狀态值.
    output, state = lstm(current_batch_of_words, state)

    # LSTM 輸出可用于産生下一個詞語的預測
    logits = tf.matmul(output, softmax_w) + softmax_b
    probabilities = tf.nn.softmax(logits)
    loss += loss_function(probabilities, target_words)
           

截斷反向傳播

為使學習過程易于處理,通常的做法是将反向傳播的梯度在(按時間)展開的步驟上照一個固定長度(

num_steps

)截斷。 通過在一次疊代中的每個時刻上提供長度為

num_steps

的輸入和每次疊代完成之後反向傳導,這會很容易實作。

一個簡化版的用于計算圖建立的截斷反向傳播代碼:

# 一次給定的疊代中的輸入占位符.
words = tf.placeholder(tf.int32, [batch_size, num_steps])

lstm = rnn_cell.BasicLSTMCell(lstm_size)
# 初始化 LSTM 存儲狀态.
initial_state = state = tf.zeros([batch_size, lstm.state_size])

for i in range(len(num_steps)):
    # 每處理一批詞語後更新狀态值.
    output, state = lstm(words[:, i], state)

    # 其餘的代碼.
    # ...

final_state = state
           

下面展現如何實作疊代整個資料集:

# 一個 numpy 數組,儲存每一批詞語之後的 LSTM 狀态.
numpy_state = initial_state.eval()
total_loss = 0.0
for current_batch_of_words in words_in_dataset:
    numpy_state, current_loss = session.run([final_state, loss],
        # 通過上一次疊代結果初始化 LSTM 狀态.
        feed_dict={initial_state: numpy_state, words: current_batch_of_words})
    total_loss += current_loss
           

輸入

在輸入 LSTM 前,詞語 ID 被嵌入到了一個密集的表示中(檢視 矢量表示教程)。這種方式允許模型高效地表示詞語,也便于寫代碼:

# embedding_matrix 張量的形狀是: [vocabulary_size, embedding_size]
word_embeddings = tf.nn.embedding_lookup(embedding_matrix, word_ids)
           

嵌入的矩陣會被随機地初始化,模型會學會通過資料分辨不同詞語的意思。

損失函數

我們想使目标詞語的平均負對數機率最小

實作起來并非很難,而且函數

sequence_loss_by_example

已經有了,可以直接使用。

論文中的典型衡量标準是每個詞語的平均困惑度(perplexity),計算式為

同時我們會觀察訓練過程中的困惑度值(perplexity)。

多個 LSTM 層堆疊

要想給模型更強的表達能力,可以添加多層 LSTM 來處理資料。第一層的輸出作為第二層的輸入,以此類推。

MultiRNNCell

可以無縫的将其實作:

lstm = rnn_cell.BasicLSTMCell(lstm_size)
stacked_lstm = rnn_cell.MultiRNNCell([lstm] * number_of_layers)

initial_state = state = stacked_lstm.zero_state(batch_size, tf.float32)
for i in range(len(num_steps)):
    # 每次處理一批詞語後更新狀态值.
    output, state = stacked_lstm(words[:, i], state)

    # 其餘的代碼.
    # ...

final_state = state
           

編譯并運作代碼

首先需要建構庫,在 CPU 上編譯:

bazel build -c opt tensorflow/models/rnn/ptb:ptb_word_lm
           

如果你有一個強大的 GPU,可以運作:

bazel build -c opt --config=cuda tensorflow/models/rnn/ptb:ptb_word_lm
           

運作模型:

bazel-bin/tensorflow/models/rnn/ptb/ptb_word_lm \
  --data_path=/tmp/simple-examples/data/ --alsologtostderr --model small
           

教程代碼中有 3 個支援的模型配置參數:"small", "medium" 和 "large"。它們指的是 LSTM 的大小,以及用于訓練的超參數集。

模型越大,得到的結果應該更好。在測試集中

small

模型應該可以達到低于 120 的困惑度(perplexity),

large

模型則是低于 80,但它可能花費數小時來訓練。

除此之外?

還有幾個優化模型的技巧沒有提到,包括:

  • 随時間降低學習率,
  • LSTM 層間 dropout.

繼續學習和更改代碼以進一步改善模型吧。

原文:Recurrent Neural Networks 翻譯:Warln

tensorflow LSTM