言語処理100本ノック2020 (99. 翻訳サーバの構築)

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

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

今回は第10章: 機械翻訳の最終問題、「99. 翻訳サーバの構築」を説明します。

本記事ではサーバを構築して、機械翻訳モデルが動くデモシステムができるまでを解説します。なお、今回サーバ構築で利用するGoogle Cloud Platform(GCP)は無料枠があり、初めて使う方でしたら全て無料枠で収まると思います。

# 前提
・fairseqを用いて構築した機械翻訳モデルがある
・Googleのアカウントを持っている
・登録できるクレジットカードを持っている(無料でできますが必要です)

# Google Cloud Platform(GCP)を始める
問題99ではクラウドサーバー上で問題98で作ったfairseqの機械翻訳モデルが動作させます。そのためにまず、クラウドサービスのアカウントを作りましょう。
下記の記事を参考に環境構築を進めてください。記事の「プロジェクトの作成」までできたら、本記事の次のステップに移ります。

https://qiita.com/Brutus/items/22dfd31a681b67837a74

# VMインスタンスを立てる
1. VMインスタンスをクリックします。
![スクリーンショット 2023-11-11 215616.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/a40ec4e8-855c-250a-5529-ca833eadfe5f.png)

2. 「インスタンスを作成」をクリックします
![スクリーンショット 2023-11-11 220652.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/9e477666-0559-34d3-480f-5bcfda39684e.png)

3. インスタンスの名前は適当に付けて、リージョンも無料でできるところならどこでもOKです。
![スクリーンショット 2023-11-11 221412.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/1b378171-08a2-9b01-8fb9-a18f53279209.png)

4. マシンタイプは「N2」を選択します。デフォルトはE2ですが4GBだとfairseqが動作しませんでした。
![スクリーンショット 2023-11-11 221159.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/c0276016-da32-68fd-658e-fe7ce6e2e62e.png)

5. ブートディスクのサイズは20GBにします。デフォルトのサイズだと機械翻訳に必要なモデルや辞書を入れると不足する可能性があります。
![スクリーンショット 2023-11-11 221256.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/60a4954e-ff5b-f842-d546-ddc675101cbb.png)

6. ファイアウォールの項目ではHTTP, HTTPSどちらも許可します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/f91d1f28-7645-dfe6-0023-977a0b3d00e6.png)

以上の設定で[作成]ボタンをクリックします。

# ファイアウォールの作成
Webブラウザから翻訳ページを開くために必要です。以下の記事の「3.ファイアウォールの作成」「4.Google Compute Engine (GCE)の変更」のみを実施します。

https://amdlaboratory.com/amdblog/gcpgoogle-cloud-platform%E3%81%A7compute-engine%E3%82%92%E7%AB%8B%E3%81%A6%E3%81%A6%E3%81%BF%E3%82%8B/

上記の記事通りですが、[ファイアウォール ルールの詳細]は以下のようにしました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/5ecf7d08-4417-b824-8dfd-a1eabd02062e.png)


[VMインスタンス]の[編集]から[ネットワーク タグ]に先ほど作成した「ファイアウォール ルール」を追加します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/95d15962-5644-fbd4-ee6b-d10891480622.png)


# VMインスタンスに機械翻訳用の環境を導入
インスタンスにSSH接続します。
![スクリーンショット 2023-11-11 231742.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/8ac7edab-b7fb-f00f-6ea0-2268c9ddde0c.png)

Python環境を構築してFlask、fairseq、Janomeをインストールするために、以下のコマンドを実行します。
```text:コマンド
$ sudo apt-get update
$ sudo apt-get install -y python3-pip
$ pip3 install Flask==2.2.5
$ pip3 install fairseq==0.12.2
$ pip3 install Janome==0.5.0
```

# ファイルをアップロード

機械翻訳に必要なファイルをVMサーバにアップロードします。VMサーバにアップロードするにあたり、Google Cloud SDKを利用すると機械学習モデルでもすぐアップロードできます。(SSHの[ファイルをアップロード]でやると鬼時間かかります。)
やることは1. Google Cloud SDKをインストールして、2. 必要なモジュールをVMサーバに送信です。直接的にやり方が書いてある記事が見つからなかったので、公式のドキュメントを参考にキーワードで調べながらやってみてください。

https://cloud.google.com/compute/docs/instances/transfer-files?hl=ja

今回は以下のファイルをVMサーバにアップロードします。

* checkpoint_best.pt
faireseqで構築した翻訳モデル
* dict.ja.txt
翻訳モデルの日本語辞書。fairseqのprocessで生成される。
* dict.en.txt
翻訳モデルの英語辞書。fairseqのprocessで生成される。
* main.py
webページを構築するために、Flaskを動かす。htmlをべた書きしてデモシステムを動かせる程度にしている。
```Python:main.py
from flask import Flask, request
from janome.tokenizer import Tokenizer
from fairseq.models.transformer import TransformerModel
app = Flask(__name__)
t = Tokenizer()

model = TransformerModel.from_pretrained(
    './model',
    checkpoint_file='checkpoint_best.pt',
)

@app.route('/' ,methods=['GET', 'POST'])
def translate_sentence():
    if request.method == 'POST':
        input_text = request.form['input_text']
        sentence = (" ").join(list(t.tokenize(input_text, wakati=True)))
        result =  model.translate(sentence)
        result = result.replace("<unk>", "@@@")
        return result + '''
            <form method="post">
                <input type="text" name="input_text">
                <input type="submit" value="Submit">
            </form>
        '''
    else:
        return '''
            <form method="post">
                <input type="text" name="input_text">
                <input type="submit" value="Submit">
            </form>
        '''
if __name__ == '__main__':
    app.run()
```

# 翻訳システムを起動

main.pyを動かして翻訳モデルを起動。
```text:コマンド
$ FLASK_APP=main.py flask run --host=0.0.0.0
```
※FlaskのPATHが通らない場合は以下を実行
```text:コマンド
$ export PATH=$PATH:~/.local/bin
```
VMインスタンスの外部IPを確認。Webブラウザで以下のURLを検索する。
「http://[外部IP]:5000」

![スクリーンショット 2023-11-18 191941.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/03a21fc8-617a-57c0-3d05-fc745f92e84b.png)

# Webブラウザで翻訳実行
「http://[外部IP]:5000」で以下のページに飛びます。入力欄に日本語を入れて、[Submit]を押すと翻訳結果が出力されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/6b2ac8c5-ac19-5551-b8a3-8fb6ded8c320.png)

↓[Submit]を押した後。入力文は「江戸幕府は崩壊した」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3579871/9c173afd-d987-ef71-ce20-2d981946a06e.png)

これで言語処理100本ノック2020を完走です！！！

# 【重要】VMインスタンスの削除
翻訳システムを使い終わったら、今回立ち上げたVMインスタンスを削除または停止してください。VMインスタンスが動いている限り課金され続け、無料枠を使い切ってしまう可能性があります。

# コメント
最後のサーバ構築で詰まる人も多いと思いますが、クラウドサーバーを使えば実現できます。言語処理100本ノック2020お疲れ様でした！

# 他章の解答例

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