#ニューラル機械翻訳
事前準備
http://qiita.com/GushiSnow/private/c0dce54a1ed90fe16c26
ハンズオンのコードがあるgithub
https://github.com/SnowMasaya/Chainer_Machine_Translation_ipython_notebook.git
#ハンズオンのゴール
1:ニューラル翻訳モデルのエンコーダー、デコーダー部分の実装が出来る。
2:パラメータを調整して、ニューラル翻訳モデルの挙動を変更できる。
#アプリケーションの動作確認
仮想環境の有効化
Mac/Linux
source my_env/bin/activate
pyenv install 3.4.1
pyenv rehash
pyenv local 3.4.1
動作確認
直下で、以下を実行。
ipython notebook
Chainerのノートブックがこれで開きます。
#翻訳のEncoder-Decoderを作成するプロセスを体験する
iPython notebookのmachine_translation.ipynbを開いてください。こちらには翻訳のEncoder-Decoderの作成のための各ステップを順番に書いてあります。
iPython notebookでは文中のコードが実際に実行できるため、上から順に解説&実行をしていきましょう(詳しい使い方はこちらを参照してください)。

ここからコーディング箇所までipython notebookを見て下さい。
##翻訳のEncoder-Decoder設定(コーディング箇所)!!!!
class EncoderDecoderModelForward(EncoderDecoderModel):
def __init__(self):
pass
def __forward(self, is_training, src_batch, trg_batch = None, generation_limit = None):
m = self.__model
tanh = functions.tanh
lstm = functions.lstm
batch_size = len(src_batch)
src_len = len(src_batch[0])
src_stoi = self.__src_vocab.stoi
trg_stoi = self.__trg_vocab.stoi
trg_itos = self.__trg_vocab.itos
s_c = wrapper.zeros((batch_size, self.__n_hidden))
#--------Hands on------------------------------------------------------------------#
# encoding
"""
逆順にEncodingしていくため下記の手順になる。
1:翻訳元言語の末尾</s>を潜在空間に写像し、隠れ層に入力、lstmで出力までをバッチサイズ分行う。
2:翻訳元言語を逆順に1と同様の処理を行う。
3:次のミニバッチ処理のために最終結果をlstmで出力。翻訳の仮説用のリストを保持
"""
s_x = wrapper.make_var([src_stoi('</s>') for _ in range(batch_size)], dtype=np.int32)
s_i = tanh(m.w_xi(s_x))
s_c, s_p = lstm(s_c, m.w_ip(s_i))
for l in reversed(range(src_len)):
s_x = wrapper.make_var([src_stoi(src_batch[k][l]) for k in range(batch_size)], dtype=np.int32)
s_i = tanh(m.w_xi(s_x))
s_c, s_p = lstm(s_c, m.w_ip(s_i) + m.w_pp(s_p))
s_c, s_q = lstm(s_c, m.w_pq(s_p))
hyp_batch = [[] for _ in range(batch_size)]
# decoding
"""
学習と予測をコードしている。
学習部分
1:学習では損失の計算及び答えとなる翻訳先言語の長さを考慮する必要がある。(翻訳元言語と翻訳先言語で長さが異なるため)
2:ニューラルネットの処理は基本的にEncodingと同一であるが、損失計算と翻訳仮説候補の確保の処理が加わっている。
"""
"""
予測部分
1:予測では予測する翻訳言語の長さに制約をしないとニューラル翻訳モデルの性質上、無限に翻訳してしまう可能性があるので、長さに制約を設けている。
2:翻訳元言語を逆順に1と同様の処理を行う。
3:基本的に学習部分と同一であるが、ミニバッチサイズ分の翻訳仮説の末尾が</s>になったときにDecoding処理が終わるようになっている。
"""
if is_training:
accum_loss = wrapper.zeros(())
trg_len = len(trg_batch[0])
for l in range(trg_len):
s_j = tanh(m.w_qj(s_q))
r_y = m.w_jy(s_j)
s_t = wrapper.make_var([trg_stoi(trg_batch[k][l]) for k in range(batch_size)], dtype=np.int32)
accum_loss += functions.softmax_cross_entropy(r_y, s_t)
output = wrapper.get_data(r_y).argmax(1)
for k in range(batch_size):
hyp_batch[k].append(trg_itos(output[k]))
s_c, s_q = lstm(s_c, m.w_yq(s_t) + m.w_qq(s_q))
return hyp_batch, accum_loss
else:
while len(hyp_batch[0]) < generation_limit:
s_j = tanh(m.w_qj(s_q))
r_y = m.w_jy(s_j)
output = wrapper.get_data(r_y).argmax(1)
for k in range(batch_size):
hyp_batch[k].append(trg_itos(output[k]))
if all(hyp_batch[k][-1] == '</s>' for k in range(batch_size)): break
s_y = wrapper.make_var(output, dtype=np.int32)
s_c, s_q = lstm(s_c, m.w_yq(s_y) + m.w_qq(s_q))
return hyp_batch
#--------Hands on------------------------------------------------------------------#
def train(self, src_batch, trg_batch):
self.__opt.zero_grads()
hyp_batch, accum_loss = self.__forward(True, src_batch, trg_batch=trg_batch)
accum_loss.backward()
self.__opt.clip_grads(10)
self.__opt.update()
return hyp_batch
def predict(self, src_batch, generation_limit):
return self.__forward(False, src_batch, generation_limit=generation_limit)
#モデルを賢くして予測
<Handson #2 解説>
今回のHands Onでは限られた時間でしか学習していないのでひどい精度のモデルしかできていません。
そこでパラメータを調整してモデルを使って再作成してみましょう。
調整するパラメータ
#--------Hands on 2----------------------------------------------------------------#
parameter_dict["source"] = "source_wakati_kytea.txt"
parameter_dict["target"] = "target_stanford_parse.txt"
parameter_dict["vocab"] = 12892
parameter_dict["embed"] = 20
parameter_dict["hidden"] = 10
parameter_dict["epoch"] = 20
parameter_dict["minibatch"] = 64
parameter_dict["generation_limit"] = 256
parameter_dict["show_hands_on_number"] = 10
parameter_dict["show_i_epoch"] = 0
#--------Hands on 2----------------------------------------------------------------#
##それぞれのパラメータの役割
parameter_dict["source"]:翻訳元言語のデータを指定します。今回はkyteaを使用して分かち書きをしたデータを用意しています。
http://www.phontron.com/kytea/index-ja.html
parameter_dict["target"]:翻訳先言語のデータを指定します。今回はStanford Parserを使用して分かち書きをしたデータを用意しています。
http://nlp.stanford.edu/software/lex-parser.shtml
導入の方法:
http://qiita.com/yubessy/items/1869ac2c66f4e76cd6c5
parameter_dict["vocab"]:扱いたい単語の語彙数
parameter_dict["embed"]:潜在空間に写像する数。この値が小さいほど圧縮されるので処理が高速になるがその分、表現力が下がるので、精度が落ちる場合がある。逆に大きくすると表現力が上がるが速度が落ちる。
parameter_dict["hidden"]:embedと同様
parameter_dict["epoch"]:学習回数
parameter_dict["minibatch"]:同時に処理する文の数
parameter_dict["generation_limit"]:予測で生成する単語のサイズ
parameter_dict["show_hands_on_number"] :学習処理中に表示したい文字数
parameter_dict["show_i_epoch"] :学習回数が何回目の出力をみたいかを指定。
ハイパーパラメータの最適化についてもっと知りたい方は下記をご覧ください
#まだまだ勉強したい向上心のある方へ
今回のハンズオン資料の元となった論文です。
Sequence to Sequence Learning with Neural Networks
ニューラルネットワークを使用した翻訳の解説です。
Introduction to Neural Machine Translation with GPUs
#おまけ
今回は事前に分かち書きの処理をしたコーパスを用意しました。
今回使用したツール以外にも分かち書きのツールがあるので、ご紹介しておきます。
##日本語:mecab
##KyteaとMecabについて
##Mecabの資料について
##Kyteaについて
#参考サイト一覧
Sutskever, Ilya, Oriol Vinyals, and Quoc VV Le. "Sequence to sequence learning with neural networks." Advances in neural information processing systems. 2014.
Introduction to Neural Machine Translation with GPUs
Chainer example codes for NLP