Recurrent Neural Networkについて調査してみた
皆さんこんにちは
お元気ですか。私は自由に元気です。
今日はRecurrent Neural Networkについて見て行きたいと思います。
Recurrent Neural Network
Recurrent Neural Networkは通常のネットワークと異なり、時系列が考慮されているニューラルネットワークです。
解ける問題としては、翻訳、文書生成、音声生成などに使えると思います。
最近では画像を説明する文章を生成する問題にも活用されていて、今後、特に使われる
ことになると考えています。
言語表現
各ワードは次のようなベクトルで表現できるとします。
入力の時には対応するワードのベクトルを入力します。
{犬,と,猫,と,狐,が,好き}といった文章があるとすると、
ワードベクトルのインデックスで表現するとなると{0,1,2,1,3,4,5}と表すことができる。
ネットワーク構成の概要
画像はhttp://aclweb.org/anthology//D/D13/D13-1169.pdfより
上記の図を数式にすると以下の通りです。
y(t)は現在の言葉の次の言葉の確率である。
(1)は現在のワードベクトルに重みUと前回の隠れ層の出力に重みWを掛けたベクトルを合計している
(2)は(1)のベクトルに重みを掛けて、今の言葉の次の言葉を予測します。
これを繰り返すことにより、次から次へと言葉を生成し、文章を作成していきます。
BPTT(Back Propagation Through Time)
通常のBack Propagationと異なり、最後の出力から何回か前の単語の誤差についても誤差を計算することになります。
数式とかは、他のサイトを参考にすると良いでしょう。
Source Code
ChainerにExampleが掲載されています。
ちょうど良いので、こちらを解説していきましょう。github.com
Model
Chainerにちょうど良い例があります。Long Short Term Memoryが含まれていますが、まぁ良いでしょう。
EmbedIDは言語へベクトルを変換する。
model = chainer.FunctionSet(embed=F.EmbedID(len(vocab), n_units), l1_x=F.Linear(n_units, 4 * n_units), l1_h=F.Linear(n_units, 4 * n_units), l2_x=F.Linear(n_units, 4 * n_units), l2_h=F.Linear(n_units, 4 * n_units), l3=F.Linear(n_units, len(vocab)))
1Stepの学習
def forward_one_step(x_data, y_data, state, train=True): x = chainer.Variable(x_data, volatile=not train) t = chainer.Variable(y_data, volatile=not train) h0 = model.embed(x) h1_in = model.l1_x(F.dropout(h0, train=train)) + model.l1_h(state['h1']) c1, h1 = F.lstm(state['c1'], h1_in) h2_in = model.l2_x(F.dropout(h1, train=train)) + model.l2_h(state['h2']) c2, h2 = F.lstm(state['c2'], h2_in) y = model.l3(F.dropout(h2, train=train)) state = {'c1': c1, 'h1': h1, 'c2': c2, 'h2': h2} return state, F.softmax_cross_entropy(y, t) def make_initial_state(batchsize=batchsize, train=True): return {name: chainer.Variable(mod.zeros((batchsize, n_units), dtype=np.float32), volatile=not train) for name in ('c1', 'h1', 'c2', 'h2')}
forward_one_stepの内部は少し通常のネットワークと変わっています。
h1_in = model.l1_x(F.dropout(h0, train=train)) + model.l1_h(state['h1'])
上記のコードはの数式と同一である。
state['h1']には、前回の隠れ層の出力を保存しています。
lstmについてはまた後日、解説したいと思います。
学習部分
for i in six.moves.range(jump * n_epoch): x_batch = np.array([train_data[(jump * j + i) % whole_len] for j in six.moves.range(batchsize)]) y_batch = np.array([train_data[(jump * j + i + 1) % whole_len] for j in six.moves.range(batchsize)]) state, loss_i = forward_one_step(x_batch, y_batch, state) accum_loss += loss_i cur_log_perp += loss_i.data.reshape(()) if (i + 1) % bprop_len == 0: optimizer.zero_grads() accum_loss.backward() accum_loss.unchain_backward() # truncate accum_loss = chainer.Variable(mod.zeros(())) optimizer.clip_grads(grad_clip) optimizer.update()
最低限の箇所だけを記載します。
基本的にシーケンスをバッチで入力していき、ある一定の入力があった場合に
BPTTを実行するとなっています。
感想
Chainer勉強するのにも結構いいよね。