はじめに
本記事は言語処理100本ノックの解説です。
100本のノックを全てこなした記録をQiitaに残します。
使用言語はPythonです。
今回は第10章: 機械翻訳(95. サブワード化)の解答例をご紹介します。
問題95は文章をサブワード化して問題91~94を再度実施するため、この問題単独で記事にしました。
95. サブワード化
トークンの単位を単語や形態素からサブワードに変更し,91-94の実験を再度実施せよ.
準備
データセットをサブワードするためにsubword-nmtを入れます。
$ pip install subword-nmt
コード
!subword-nmt learn-bpe -s 10000 < "[PATH]/kftt-data-1.0/sorce/kyoto-train.en"> "[PATH]/kftt-data-1.0/codec/en_codec.txt"
!subword-nmt learn-bpe -s 10000 < "[PATH]/kftt-data-1.0/sorce/kyoto-train.ja"> "[PATH]/kftt-data-1.0/codec/ja_codec.txt"
def Subword(name):
!subword-nmt apply-bpe -c "[PATH]/kftt-data-1.0/codec/en_codec.txt" < "[PATH]/kftt-data-1.0/sorce/kyoto-"$name".en" > "[PATH]/kftt-data-1.0/codec/"$name".en"
!subword-nmt apply-bpe -c "[PATH]/kftt-data-1.0/codec/ja_codec.txt" < "[PATH]/kftt-data-1.0/sorce/kyoto-"$name".ja" > "[PATH]/kftt-data-1.0/codec/"$name".ja"
Subword("train")
Subword("test")
Subword("dev")
コメント
OSコマンドを関数に組み込んでtrain, test, devのデータを作ります。そして、問題90-94を再び実施します。
95-90. データの準備
機械翻訳のデータセットをダウンロードせよ.訓練データ,開発データ,評価データを整形し,必要に応じてトークン化などの前処理を行うこと.ただし,この段階ではトークンの単位として形態素(日本語)および単語(英語)を採用せよ.
$ fairseq-preprocess -s ja -t en \
--trainpref "[PATH]/kftt-data-1.0/codec/train" \
--validpref "[PATH]/kftt-data-1.0/codec/dev" \
--testpref "[PATH]/kftt-data-1.0/codec/test" \
--destdir "[PATH]/kftt-data-1.0/processed-95/" \
--task translation \
--thresholdsrc 5 \
--thresholdtgt 5
コメント
問題90~95の記事と全く同じです。
95-91. 機械翻訳モデルの訓練
90で準備したデータを用いて,ニューラル機械翻訳のモデルを学習せよ(ニューラルネットワークのモデルはTransformerやLSTMなど適当に選んでよい).
$ fairseq-train "[PATH]/kftt-data-1.0/processed-95/" \
--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-95/" \
--restore-file "[PATH]/kftt-data-1.0/model-95/checkpoint_last.pt" \
| tee -a "[PATH]/kftt-data-1.0/log-95/train.log"
コメント
また、学習していきます。
95-92. 機械翻訳モデルの適用
91で学習したニューラル機械翻訳モデルを用い,与えられた(任意の)日本語の文を英語に翻訳するプログラムを実装せよ.
$ fairseq-generate "[PATH]/kftt-data-1.0/processed-95/" \
--path "[PATH]/kftt-data-1.0/model-95/checkpoint_best.pt" \
--task translation \
--gen-subset test \
| tee >(grep "^H" | cut -f3 > "[PATH]/kftt-data-1.0/processed-95/test-transform.txt")\
| grep "^T" | cut -f2 > "[PATH]/kftt-data-1.0/processed-95/test-true.txt"
出力結果
Some arg@@ ue that this caused the er@@ rors in their ages .
Emperor Tenchi ( Ten@@ ji )
1879 : Osaka Techn@@ ical College
" Ten@@ zo K@@ yok@@ un "
" Fu@@ sh@@ uku Han@@ ho "
Thus , er@@ rors were wrong .
Emperor Ten@@ ji ( also pronounced Ten@@ ji )
In 1879 , he became Osaka Sen@@ mon Gakko ( Osaka V@@ oc@@ ational School ) .
" Ten@@ z@@ oku-@@ kyo Sutra "
" H@@ ow to eat g@@ our@@ d rice "
これだと分からないので、サブワードから元の表記に戻します。
$ cat "[PATH]/kftt-data-1.0/processed-95/test-transform.txt" | sed -r 's/(@@ )|(@@ ?$)//g' > "[PATH]/kftt-data-1.0/processed-95/test-transform-decoded.txt"
$ cat "[PATH]/kftt-data-1.0/processed-95/test-true.txt" | sed -r 's/(@@ )|(@@ ?$)//g' > "[PATH]/kftt-data-1.0/processed-95/test-true-decoded.txt"
改めて翻訳結果と正解の文章は以下のようになります。
Thus , errors were wrong .
Emperor Tenji ( also pronounced Tenji )
In 1879 , he became Osaka Senmon Gakko ( Osaka Vocational School ) .
" Tenzoku-kyo Sutra "
" How to eat gourd rice "
Some argue that this caused the errors in their ages .
Emperor Tenchi ( Tenji )
1879 : Osaka Technical College
" Tenzo Kyokun "
" Fushuku Hanho "
コメント
例が悪いのかもですが、できている感じがしないですね。
95-93. BLEUスコアの計測
91で学習したニューラル機械翻訳モデルの品質を調べるため,評価データにおけるBLEUスコアを測定せよ.
サブワードで評価
$ fairseq-score --sys "[PATH]/kftt-data-1.0/processed-95/test-transform.txt"\
--ref "[PATH]/kftt-data-1.0/processed-95/test-true.txt"
元の文章に戻して評価
$ fairseq-score --sys "[PATH]/kftt-data-1.0/processed-95/test-transform-decoded.txt"\
--ref "[PATH]/kftt-data-1.0/processed-95/test-true-decoded.txt"
コメント
サブワードのままだと23.27、元の文章に戻すと20.94でした。サブワード化すると語彙を少なくできるため評価値が高くなるのかなと。サブワード化せずに学習、評価した結果が前記事で18.69でしたので、サブワード化は有効な手法だと言えますね。
95-94. ビーム探索
トークンの単位を単語や形態素からサブワードに変更し,91-94の実験を再度実施せよ.
from matplotlib import pyplot
beam_list = []
for i in range(1, 100):
try:
beam_temp = !fairseq-generate "[PATH]/kftt-data-1.0/processed-95/" \
--path "[PATH]/kftt-data-1.0/model-95/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)
コメント
だいたい23.25~23.50の間でまとまっていますね。
他章の解答例