KZKY memo

自分用メモ.

TensorFlow: Recurrent Neural Networks

Introduction

まず,LSTM articleを読んだほうがいい.わかりやすいので読んだほうがいい.

rnn_cell.pyを見ると,

  • BasicRNNCell: 普通のRNN
  • BasicLSTMCell: peep-holeがないLSTM
  • LSTMCell: peep-holeがあるLSTM. さらに,cell clippingとprojection layerがoptionとして用意されている
  • GRUCell: Gated Recurrent Unit, input gateとforget gateを一緒にして,さらに,cell stateとhidden stateを一緒にしたLSTM簡易版

が,現時点(20151228)LSTMのアーキテクチャとして用意されている.

他にもいろいろバリアンスは考えれるけれど,Greff, et al. (2015)によると,どれも大差なく,forget gateの役割があることとoutput activation functionがあることが重要とのこと.また,Jozefowicz, et al. (2015)によると,LSTMのアーキテクチャは,タスク依存の部分もあるとのこと.なので,上記くらいのLSTMのアーキがあれば,基本は十分と思われる.

また,rnn_cell.pyをみると,InputProjectionWrapper, DropoutWrapper, EmbeddingWrapper, OutputProjectionWrapperと典型的にLSTM前後に挟むレイヤーのラッパーが用意されている.

ちなみに,この記事を書いている時点では,RNNCellはstateを保持しない実装になっている.この辺は議論されているよう.なので,python apiにはrnnの項目がまだない.

Language Modeling

単語列が与えられたらその次に出てくる単語を当てるという問題.Penn Tree Bank (PTB) Datasetを使って行う.

Tutorial Files

File Purpose
ptb_word_lm.py The code to train a language model on the PTB dataset.
reader.py The code to read the dataset

Download and Prepare the Data

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

で既に前処理済みのデータを持ってくる.10,000単語くらいあって,rare wordsは"<unk>" symbolになっていて,end-of-sentence markerも付いている.

simple-examples.tgzの中身をみると,data以外にも幾つかサンプルがある.charactor-basd RNNのサンプルも入っている.

./simple-examples/data/ptb.train.txt を見るとptbデータは非常に長い1doc分のデータのようになっている.

The Model

モデルの説明.

LSTM

RNNでもbatch単位で実行するのは一緒.擬似コードは以下.

lstm = rnn_cell.BasicLSTMCell(lstm_size)
# Initial state of the LSTM memory.
state = tf.zeros([batch_size, lstm.state_size])

loss = 0.0
for current_batch_of_words in words_in_dataset:
    # The value of state is updated after processing each batch of words.
    output, state = lstm(current_batch_of_words, state)

    # The LSTM output can be used to make next word predictions
    logits = tf.matmul(output, softmax_w) + softmax_b
    probabilities = tf.nn.softmax(logits)
    loss += loss_function(probabilities, target_words)

Truncated Backpropagation

長ーい系列を全部を見て,backpropするとうまく学習できないので,ある程度の長さでgradientを打ち切る.

が本問題のサンプルコードになっている.サンプルコード上は,PTBModelのinitでunrolled graphを作って,run_epochでデータセットを一回なめている.1 epoch経つとstateを0に戻す.

扱うタスクに依っては,RNNではbatch単位でstateを忘れたり(0に戻す)するが,ptbは,非常に長い系列なので,データの作り方を工夫(reader.py#ptb_iterator)して,batch単位でstateを忘れないようにし,batch単位でstateを引き継いでいる.そして,次のepochではstate を0にしている.

サンプルコードはいちからtruncated backprop用のunrolled graphを作っているが,rnn.pyにcellだけ指定すれば,RNNを作ってくれる便利モデルがある.

def rnn(cell, inputs, initial_state=None, dtype=None,
        sequence_length=None, scope=None):
  """Creates a recurrent neural network specified by RNNCell "cell".

こんな感じのインターフェイスになっているので,documentをまたぐとかuserをまたぐときに,initial_stateを0にして,前の状態を忘れればいいと思う.

Inputs

この次の単語予測の問題では,indexingされた単語が入力なので,

# embedding_matrix is a tensor of shape [vocabulary_size, embedding size]
word_embeddings = tf.nn.embedding_lookup(embedding_matrix, word_ids)

な感じで,word embeddingしてからLSTMに入れる.

これでは,線形変換の行列は,{ \displaystyle T_{2n, 4n} }{ \displaystyle 2n \rightarrow 4n }の変換だけれども,rnn_cell.pyのlinear関数では,{ \displaystyle (\sum input\ size + n) \rightarrow 4n }の変換になっており,わざわざcell sizeにprojectionしないでも良いようになっている.

Loss Fuction

over wordsで誤差を計算する.

{ \displaystyle
loss = -\frac{1}{N} \sum_{i=1}^{N} \ln p_{target_i}
}

このインプリは簡単だけど,sequence_loss_by_exampleが定義されているので,これを使って良いとのこと.

実際の典型的な評価基準は, average per-word perplexity (just called perplexity)を使う.

{ \displaystyle
\exp \left(-\frac{1}{N} \sum_{i=1}^{N} \ln p_{target_i} \right) = \exp(loss)
}

lossにexpをつけただけ.

Stacking multiple LSTMs

LSTMをstackしたかったら,interfaceが用意されていて,

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

な感じで,cellを作ってから,積み重ねたい分(number_of_layers)だけ,cellを積み重ねる.

Run the Code

とりあえず,動かしたいなら

cd tensorflow/models/rnn/ptb
python ptb_word_lm --data_path=${/tmp/simple-examples/data} --model small

こうする.

modelのサイズに依ってperplexityが変わることがわかる.small, medium, largeが用意されていて,largeなほどperplexityが小さくなる.