言語処理100本ノック2020 (90~94)

# はじめに
本記事は言語処理100本ノックの解説です。
100本のノックを全てこなした記録をQiitaに残します。
使用言語はPythonです。

https://nlp100.github.io/2020/ja/

今回は第10章: 機械翻訳(90~94)までの解答例をご紹介します。
>本章では，日本語と英語の翻訳コーパスである京都フリー翻訳タスク (KFTT)を用い，ニューラル機械翻訳モデルを構築する．ニューラル機械翻訳モデルの構築には，fairseq，Hugging Face Transformers，OpenNMT-pyなどの既存のツールを活用せよ．

**準備**
fairseqを使ってTransformerモデルの構築を行います。
```text:コマンド
$ git clone https://github.com/pytorch/fairseq
$ pip install --editable fairseq/
```

# 90. データの準備
>機械翻訳のデータセットをダウンロードせよ．訓練データ，開発データ，評価データを整形し，必要に応じてトークン化などの前処理を行うこと．ただし，この段階ではトークンの単位として形態素（日本語）および単語（英語）を採用せよ．
```text:コマンド
$ fairseq-preprocess -s ja -t en \
--trainpref  "[PATH]/kftt-data-1.0/sorce/kyoto-train" \
--validpref "[PATH]/kftt-data-1.0/sorce/kyoto-dev" \
--testpref "[PATH]/kftt-data-1.0/sorce/kyoto-test" \
--destdir "[PATH]/kftt-data-1.0/processed/" \
--task translation \
--thresholdsrc 5 \
--thresholdtgt 5
```

**コメント**
ここでは学習データを作ります。以降はfairseqに前処理から学習、予測までお任せします。出現回数が5回以下の単語は\<unk>に置き換えます。

# 91. 機械翻訳モデルの訓練
>90で準備したデータを用いて，ニューラル機械翻訳のモデルを学習せよ（ニューラルネットワークのモデルはTransformerやLSTMなど適当に選んでよい）．

```text:コマンド
$ fairseq-train "[PATH]/kftt-data-1.0/processed/" \
  --task translation \
  --arch transformer \
  --tensorboard-logdir "logs" \
  --source-lang ja --target-lang en \
  --max-epoch 100 \
  --lr 1e-5 \
  --batch-size 32 \
  --optimizer adam \
  --save-interval 3 \
  --save-dir "[PATH]/kftt-data-1.0/model/" \
  --restore-file  "[PATH]/kftt-data-1.0/model/checkpoint_last.pt" \
| tee -a "[PATH]/kftt-data-1.0/log/train.log"
```

**コメント**
fairseqで学習します。学習係数、バッチサイズ、オプティマイザをこちらで指定できます。

# 92. 機械翻訳モデルの適用
>91で学習したニューラル機械翻訳モデルを用い，与えられた（任意の）日本語の文を英語に翻訳するプログラムを実装せよ．

```text:コマンド
$ fairseq-generate "[PATH]/kftt-data-1.0/processed/" \
--path "[PATH]/kftt-data-1.0/model/checkpoint_best.pt" \
--task translation \
--gen-subset test \
| tee >(grep "^H" | cut -f3 > "[PATH]/kftt-data-1.0/processed/test-transform.txt")\
| grep "^T" | cut -f2 >  "[PATH]/kftt-data-1.0/processed/test-true.txt"
```
**出力結果**
```text:予測
13 . Harajuku ( Numazu City , Shizuoka Prefecture )
Emperor Tenji ( also called Emperor Tenji )
In 1913 , he died of pneumonia .
<unk> software for family computer games sold from <unk> to <unk> .
Type 2 , Type <unk> : <unk> ( a <unk> car )
```
```text:正解
13 . <<unk>> Station ( Tokaido Road ) ( Numazu City , Shizuoka Prefecture )
Emperor Tenchi ( Tenji )
He died of pneumonia in 1913 .
Game software for family computers released by <<unk>>
Class C62 # 2 - Working ( registered )
```
**コメント**
今回使用するデータは正直整っているわけでは無いので、記号などが入り乱れた出力となっています。でも上手くいってそうです。特に3行目の「彼は1913年肺炎で亡くなった」は綺麗に訳せてます。


# 93. BLEUスコアの計測
>91で学習したニューラル機械翻訳モデルの品質を調べるため，評価データにおけるBLEUスコアを測定せよ．

```text:コマンド
$ fairseq-score --sys  "[PATH]/test-transform.txt"\
--ref  "[PATH]/processed/test-true.txt"
```
**出力結果**
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/84b2fa6d-9e1b-1fb2-4191-44850a2c183c.png)

**コメント**
BLEUスコアは18.69でした。一般的に40を超えると高品質らしいのでまだまだです。まあ、1個人が使用できるデータ量としては健闘した方だと思いたいです。

# 94. ビーム探索
>91で学習したニューラル機械翻訳モデルで翻訳文をデコードする際に，ビーム探索を導入せよ．ビーム幅を1から100くらいまで適当に変化させながら，開発セット上のBLEUスコアの変化をプロットせよ．

```python:コード
from matplotlib import pyplot
beam_list = []
for i in range(1, 100):
  try:
    beam_temp = !fairseq-generate "[PATH]/kftt-data-1.0/processed/" \
      --path "[PATH]/kftt-data-1.0/model/checkpoint_best.pt" \
      --task translation \
      --gen-subset test \
      --beam $i  | grep '^Generate'
    beam_list.append(float(beam_temp[-1].split(",")[0].split(" ")[-1]))
  except:
    break

pyplot.plot(beam_list)
```
**出力結果**
![download.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/8bcda6eb-d1de-6dd4-1168-d1f7f73b1d22.png)

**コメント**
notebookでやったのでOSコマンドをPython上にて"!"で実行しました。割と強引なアプローチな気がします。。beam幅を変えても19弱くらいですね。

# 他章の解答例

https://qiita.com/Dukapan100knock/items/d418f2aa37b2b3d16428