TensorFlowとGPUインスタンスで英日翻訳

Deep learningのライブラリとして有名なTensorFlowには[英仏翻訳のチュートリアル](https://www.tensorflow.org/versions/r0.9/tutorials/seq2seq/index.html)がありますが、AWSのGPUインスタンスを使って英日翻訳で試してみたので紹介します。

# 環境
- TensorFlow 0.9
- AWS g2.2xlarge instance
- Ubuntu Server 14.04
- Python 3.5

TensorFlowをAWSのGPUインスタンスで動かす方法については、以下の記事の通りに行いました。
[Setting up TensorFlow 0.9 with Python 3.5 on AWS GPU-instance](
http://max-likelihood.com/2016/06/18/aws-tensorflow-setup/)

初期のTensorFlowはAWSとの相性が悪くパッチを当てる必要があると言われていましたが、バージョン0.9ではすんなりとインストールできました。

注意点として、GPUインスタンスの使用にはAWS側に申請して1日ほど待つ必要があったのと、そのままだとディスクサイズが足りなくなったので32GBに増やした点があります。

# データ
機械翻訳モデルの訓練には対訳コーパスが必要となります。グラムさんによる[日本語対訳データのリスト](http://phontron.com/japanese-translation-data.php?lang=ja)には無料のデータも載っていますが、量が足りなかったりドメインが偏っていたりして使いづらかったので、[英辞郎のデータ](http://www.eijiro.jp/)を約2000円で購入して使いました。英辞郎のデータには単語の辞書も含まれていますが、今回は例文データ（約60万文）のみを以下の前処理を行ったうえで使いました。

- 【出典】や〈俗〉などのタグの除去：[スクリプト](https://gist.github.com/yohokuno/befc328f843d5012ca9dc333161ef800)
- MeCab 0.996とunidic 2.1.2を用いた単語分割（英語は[basic_tokenizer](https://github.com/tensorflow/tensorflow/blob/r0.9/tensorflow/models/rnn/translate/data_utils.py#L105)でトークナイズされます）
- 訓練データ99%とテストデータ1%のランダム分割

前処理後のコーパスは以下のようになりました。

### 英語
> The "expert on international politics" is Sophia University Prof. Kuniko Inoguchi, former ambassador to the U.N. Conference on Disarmament in Geneva.

### 日本語
> 「 国際 政治 の エキスパート 」 は 、 駐 ジュネーブ 軍縮 会議 代表 部 の 前 大使 で ある 猪口 邦子 上智 大 教授 の こと だ 。

これらのファイルをAWSインスタンスにコピーして以下のようにリネームしておきます。

```
% ls eijiro-data
giga-fren.release2.en
giga-fren.release2.fr
newstest2013.en
newstest2013.fr
```

なお、英辞郎のデータで訓練した機械翻訳モデルの再配布は不可とのことなので、今回の記事には訓練済みのモデルは含まれていません。

# 訓練
機械翻訳モデルを訓練するためには、TensorFlow 0.9のチュートリアルで使われているスクリプト`translate.py`をダウンロードしてきて、対訳コーパスのあるディレクトリを指定して実行します。

なお、ニューロンの数とレイヤー数はデフォルトの1024と3だとg2.2xlargeのインスタンスではGPUのメモリに収まらなかったので512と2に設定してあります。語彙サイズは英語・日本語ともにデフォルトの40,000語です。チュートリアルによると、アテンション付きの翻訳モデル[Bahdanau+ 2015](http://arxiv.org/abs/1409.0473)が使われているようです。

```
% wget https://raw.githubusercontent.com/tensorflow/tensorflow/r0.9/tensorflow/models/rnn/translate/translate.py
% mkdir eijiro-model
% python translate.py --data_dir eijiro-data/ \
    --train_dir eijiro-model/ \
    --size=512 --num_layers=2
```

実行して3日ほど待つと340kステップが終了するので、それなりの翻訳ができるようになります。モデルの精度を表すパープレキシティ（低いほどよい）は3.3程度まで下がりました。

```
global step 353200 learning rate 0.0090 step-time 0.62 perplexity 3.32
  eval: bucket 0 perplexity 5.23
  eval: bucket 1 perplexity 5.00
  eval: bucket 2 perplexity 6.16
  eval: bucket 3 perplexity 7.34
```

入力ディレクトリには訓練データとテストデータのほかに、語彙ファイルと単語のID列が保存されています。

```
% ls eijiro-data/
giga-fren.release2.en
giga-fren.release2.fr
giga-fren.release2.ids40000.en
giga-fren.release2.ids40000.fr
newstest2013.en
newstest2013.fr
newstest2013.ids40000.en
newstest2013.ids40000.fr
vocab40000.en
vocab40000.fr
```

出力ディレクトリにはニューラルネットのパラメーターが保存されています。

```
% ls eijiro-model/
checkpoint
translate.ckpt-260600
translate.ckpt-260600.meta
（中略）
translate.ckpt-353000
translate.ckpt-353000.meta
```
必要なお金は、データを変えたりしながら3回ほど試したので全部で$152でした。

# 翻訳
訓練したモデルを使って翻訳するには、`--decode`オプションを指定して`translate.py`を実行します。注意点として、訓練に使ったのと同じパラメータを指定しないと行列のサイズが合わずにエラーになります。

```
% python translate.py --decode \
    --data_dir eijiro-data \
    --train_dir eijiro-model \
    --size=512 --num_layers=2
Reading model parameters from eijiro-model/translate.ckpt-352000
> Hi, how are you?
こんにちは 、 元気 ？
> I am a software engineer.
私 は エンジニア の エンジニア です 。
> My name is Yoh.
私 は _UNK と いう 名前 です 。
> This sentence is machine translated.
この 文 は 、 翻訳 文 を 翻訳 し ます 。
```

なお、一文の翻訳は軽い処理なのでGPUのないマシンでCPUだけで実行しても大丈夫です。

# 評価
機械翻訳の評価はテストデータ中の参照訳（翻訳家による翻訳）を用いるBLEUという評価指標がよく使われています。BLEUを計算するスクリプトは[コロナ社の機械翻訳（自然言語処理シリーズ）](http://amzn.to/2aTUyy2)を参考にして実装しました。

[BLEU: automatic evaluation for machine translation](https://gist.github.com/yohokuno/a6361d8292f9b1009419a6a98c9b483c)
```
% bleu.py eijiro-data/newstest2013.sys.fr =(head -22 eijiro-data/newstest2013.fr)
BLEU: 0.0886173562228986
Brevity Penalty: 0.8911913833655019
1-gram precision: 0.4384858044164038
2-gram precision: 0.14124293785310735
3-gram precision: 0.06432748538011696
4-gram precision: 0.024539877300613498
```
TensorFlowのスクリプトのバグで翻訳できない文があったためテストデータをすべて使うことはできていませんが、4-gramまでの一致率を見るBLEU-4は8%という結果になりました。

### 参照訳との比較
vimdiffコマンドを使って機械翻訳と参照訳を比較しました。左が機械翻訳、右が参照訳です。
<img width="1174" alt="Screen Shot 2016-08-14 at 12.33.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/23665/09c666d3-6180-9a6e-3993-f1f1b0a9ce2a.png">

## 感想
翻訳精度はまだ高いとは言いがたいものの、これだけ単純なモデルを訓練するだけでそれなりの翻訳ができるのはびっくりしました。ニューラル以前の機械翻訳ではアライメントと翻訳モデルと言語モデルで別々の目的関数を最適化したうえで組み合わせたりしていたので、単一の目的関数で機械翻訳を実現できたという意義が一番大きいのではないかと思いました。

一方でニューラル翻訳は重要な単語を翻訳しそびれたり、同じ単語を繰り返し翻訳したりする傾向があるので改善の余地があると感じました。フレーズベース翻訳ならフレーズテーブルに入っているもの以外は出てこないという安心感があったので、このあたりをどう対処していくかが実用的には重要になってきそうな予感がしました。