ニューラル機械翻訳の実践と理論(その2)

いよいよGoogle ColaboratoryでOpenNMTを実行する。

qiita.com

翻訳させるためには、まず学習させる必要がある。学習のために対訳コーパスと呼ばれるデータを用意する必要がある。例えば、英日翻訳の場合、英語の原文とそれを日本語訳した文章(対訳)が必要となる。

インターネット上には、いろいろな対訳データがある。

phontron.com

Qiitaの例と同じように、KFTTという京都に関するWikipediaを人手で翻訳した対訳コーパスを使用する。(京都に関する文章のみなので結構バイアスがあるデータになってしまうのが難点。。)

forest1040.hatenadiary.org

の手順で、ssh接続する。

あとは以下を実行する。注意点としては、python2がデフォルトなので、必ずpython3を使用すること。

# OpenNMT-pyをgitクローン
git clone https://github.com/OpenNMT/OpenNMT-py.git
cd OpenNMT-py
# 依存ライブラリをインストール
sudo python3 setup.py install

# kfttデータを持ってくる
cd ~
mkdir data
cd data
wget http://www.phontron.com/kftt/download/kftt-data-1.0.tar.gz
tar xzf kftt-data-1.0.tar.gz
cp -r kftt-data-1.0/data/tok ../OpenNMT-py/kftt

# 前処理を実行
cd ~/OpenNMT-py
onmt_preprocess -train_src kftt/kyoto-train.en -train_tgt kftt/kyoto-train.ja -valid_src kftt/kyoto-dev.en -valid_tgt kftt/kyoto-dev.ja -save_data kftt/demo

# 学習を実行(10000ステップまで1000ステップごとにモデルを保存)
onmt_train -gpu_ranks 0 --train_steps 10000 -data kftt/demo -save_model demo-model -save_checkpoint_steps 1000

# 翻訳を実行
onmt_translate -model demo-model_step_10000.pt -src data/src-test.txt -output pred.txt -replace_unk -verbose

前処理の詳細はおいおい説明したい。フォーマット等も解析しないと。。

今回の学習では、デフォルトのニューラルネットワーク(RNNベース)を使用している。学習を実行すると最初に以下のように、ネットワーク構成が表示される。

[2020-06-27 01:53:57,310 INFO] NMTModel(
(encoder): RNNEncoder(
(embeddings): Embeddings(
(make_embedding): Sequential(
(emb_luts): Elementwise(
(0): Embedding(50002, 500, padding_idx=1)
)
)
)
(rnn): LSTM(500, 500, num_layers=2, dropout=0.3)
)
(decoder): InputFeedRNNDecoder(
(embeddings): Embeddings(
(make_embedding): Sequential(
(emb_luts): Elementwise(
(0): Embedding(50004, 500, padding_idx=1)
)
)
)
(dropout): Dropout(p=0.3, inplace=False)
(rnn): StackedLSTM(
(dropout): Dropout(p=0.3, inplace=False)
(layers): ModuleList(
(0): LSTMCell(1000, 500)
(1): LSTMCell(500, 500)
)
)
(attn): GlobalAttention(
(linear_in): Linear(in_features=500, out_features=500, bias=False)
(linear_out): Linear(in_features=1000, out_features=500, bias=False)
)
)
(generator): Sequential(
(0): Linear(in_features=500, out_features=50004, bias=True)
(1): Cast()
(2): LogSoftmax()
)
)

詳細説明はおいおいになるが、Encoder(RNNEncoder)+Decoder(InputFeedRNNDecoder)+ generatorの構造になっている。

また後々の説明となるが、このネットワークでは、AttentionをDecoderの箇所でGlobalAttentionとして使用している。

取り敢えず今の所は、単語だけ覚えておくとよい。

 

学習が進んでいくと以下のようなログが表示されていく。

[2020-06-27 01:54:14,418 INFO] Step 50/10000; acc: 3.32; ppl: 272219.62; xent: 12.51; lr: 1.00000; 3746/4081 tok/s; 17 sec
[2020-06-27 01:54:23,089 INFO] Step 100/10000; acc: 3.43; ppl: 112228.97; xent: 11.63; lr: 1.00000; 7270/7793 tok/s; 26 sec
[2020-06-27 01:54:30,885 INFO] Step 150/10000; acc: 3.71; ppl: 50100.14; xent: 10.82; lr: 1.00000; 6898/7620 tok/s; 34 sec
[2020-06-27 01:54:40,337 INFO] Step 200/10000; acc: 3.68; ppl: 4956.98; xent: 8.51; lr: 1.00000; 6913/7733 tok/s; 43 sec
[2020-06-27 01:54:49,264 INFO] Step 250/10000; acc: 5.61; ppl: 1799.82; xent: 7.50; lr: 1.00000; 7435/7848 tok/s; 52 sec
[2020-06-27 01:54:58,311 INFO] Step 300/10000; acc: 7.89; ppl: 1163.46; xent: 7.06; lr: 1.00000; 6855/7916 tok/s; 61 sec

各値の意味も説明しないといけないが、取り敢えず指標だけ。。

  • acc(accuracy): 100に出来るだけ近いほうが良い。
  • ppl(perplexity): 1に出来るだけ近いほうが良い。
  • xent(CrossEntropy): 出来るだけ小さい数字が良い。

何を持って計算しているのか?どのように計算しているのか?学習ってなんなのか?

ソースコードを見ないといけないが、そもそもニューラルネットワークとは何かというところから初めていこう。

 

学習がある程度できたら、翻訳を実行してみればよい。

「-model demo-model_step_10000.pt」で指定しているのが、学習時に生成されるモデルデータである。今、1000ステップ毎にモデルを保存しているので、それを指定すればよい。

 

これで取り敢えず、翻訳できるところまで来た。

さらなる発展としては、「翻訳精度の向上」と「翻訳速度の向上」の2方向が考えられる。

 

  • 翻訳精度の向上
  1.  ニューラルネットワークに「Transformer」を使用する。
  2. 学習に使う 対訳コーパスの工夫を行う。
  • 翻訳速度の向上
  1. モデルの変換を行う(蒸留/量子化等)
  2. TorchScriptへの変換
  3. CTranslate2を使用する
  4. TPU等のハードウェアを使用する

だが、その前に ニューラルネットワーク自体の学習を積み上げて行く必要がある。