そこそこ実用的な翻訳アプリを開発してみる (6) 学習用データの作成

そこそこ実用的な翻訳アプリを開発しましたので、その構成や作り方を記録しておきます。コードは MITライセンスですので、参考になるところがあれば部分的にでも使ってみてください。

# 目次

* [(1) 概要編](https://qiita.com/yamachan360/items/5b20e7181d663d70e924)
* [(2) 開発環境の準備](https://qiita.com/yamachan360/items/d5c4fb2e07d3b9693c37)
* [(3) 翻訳サービスの実装](https://qiita.com/yamachan360/items/fa4af5f7b18781e5f283)
* [(4) ログサービスの実装](https://qiita.com/yamachan360/items/92699a3fc55969337b46)
* [(5) フロントエンド側の実装](https://qiita.com/yamachan360/items/de57df20dc7de5665a44)
* (6) 学習用データの作成 【このページ】

# 今回のお題

翻訳アプリは無事に完成しましたので、最後に学習用データの作成にトライしてみましょう。可能であれば、翻訳モデルをちょっとだけでも改善(進化)させてみたいところです。

例えば International Business Machines という英単語を翻訳してみると、現在の翻訳アプリでは以下のような残念な訳になってしまいます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/10cbd185-30bc-21ba-719c-f7c881f545df.png)

これを改善することができるでしょうか？

# 翻訳モデルの改善

## 専用辞書(強制用語集)を用意する

[専用辞書(強制用語集)](https://qiita.com/yamachan360/items/5b20e7181d663d70e924#%E5%B0%82%E7%94%A8%E8%BE%9E%E6%9B%B8%E5%BC%B7%E5%88%B6%E7%94%A8%E8%AA%9E%E9%9B%86%E3%81%AE%E4%BD%9C%E6%88%90) を用意します。将来的には過去ログから候補を探し出す補助アプリが欲しいところですが、今回はテスト目的なのでシンプルに1つの単語だけを含んだ辞書を手動で作成します。

[マニュアルにあるサンプル](https://console.bluemix.net/docs/services/language-translator/customizing.html#structure) を参考に、glossary.tmx というファイル名で、以下のようなTMX形式のXMLファイルを作成します。

```xml:glossary.tmx
<?xml version="1.0" encoding="UTF-8"?>
<tmx version="1.4">
  <header creationtool="" creationtoolversion=""
    segtype="sentence" o-tmf="" adminlang="EN"
    srclang="en" datatype="rtf" o-encoding="UTF-8" />
  <body>
    <tu>
      <tuv xml:lang="en">
        <seg>International Business Machines</seg>
      </tuv>
      <tuv xml:lang="ja">
        <seg>International Business Machines</seg>
      </tuv>
    </tu>
  </body>
</tmx>
```

## 新しいモデルの存在確認

新しいモデルを作成する前に、検出ロジックを先に定義しておきましょう。`custom-en-ja` という名前で定義されたモデルを探し、もしあれば `model_id` 値を保持しておきます。

```javascript:Server.js
// Check Custom Tlanslation Model
let custom_model_id = '';
languageTranslator.listModels(
  {},
  function(error, response) {
    if (response.models) {
		let m = response.models.filter(m => m.name == 'custom-en-ja');
		if (m.length > 0) {
		  custom_model_id = m[0].model_id;
	  	} else {
			console.log("Can't find custom model: custom-en-ja");
			// ここに新しいモデルの作成ロジックを追加予定
		}
  	}
  }
)
```

ローカルでいったん Server.js を実行して、`Can't find custom model: custom-en-ja` メッセージが表示されることを確認しておきましょう。`custom-en-ja` という名前のモデルがまだ存在しないことの、念のための確認です。

## 新しいモデルの利用ロジック

ついでに、翻訳サービスのほうも対応しておきましょう。以下のように4行を追加し、さきほど存在を確認した新しいモデルがもし存在したら、そちらを優先的に使用するようにします。

```javascript:Server.js
app.use(bodyParser.json({strict: true}));
app.post('/translate', (req, res) => {
	languageTranslator.translate(
		!!custom_model_id && req.body.target == 'ja' ?	// 追加
		{
			text: req.body.text,						// 追加
			model_id: custom_model_id					// 追加
		} : {											// 追加
			text: req.body.text,
			source: req.body.source,
			target: req.body.target
		},
		function(err, translation) {
			if (err)  {
				res.status(500).send('error:' + err);
			} else  {
				res.status(200).send(translation.translations[0].translation);
			}
		}
	);
});
```

この状態で翻訳アプリを起動し、既存のモデルのまま問題なく動作することも確認しておきます。

## 新しいモデルを作成してみる

さて準備は整いました！ [Create model](https://cloud.ibm.com/apidocs/language-translator?code=node#create-model) 関数を使って、新しいモデルを作成してみます。

さきほどの検出ロジックにある `ここに新しいモデルの作成ロジックを追加予定` のコメントの部分に、以下のコードを追加します。

```javascript:Server.js
const fs = require('fs');

			languageTranslator.createModel(
				{
					name: 'custom-en-ja',
					base_model_id: 'en-ja',
					forced_glossary: fs.createReadStream('glossary.tmx')
				},
				function(error, response) {
					if (error)
						console.log('Create Model: ' + error);
					else
						console.log(JSON.stringify(response, null, 2));
				}
			);
```

さて、実行してみましょう！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/71536a2e-87d3-386d-a91d-154b2b8f9fa4.png)
おや、権限エラーが出ていますね。接続の権限は管理者なので、モデルの作成権限はあるはずなのですが…

ハッ！私は大きなミスをしておりました…

[翻訳サービスの作成](https://qiita.com/yamachan360/items/fa4af5f7b18781e5f283#%E7%BF%BB%E8%A8%B3%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%81%AE%E4%BD%9C%E6%88%90%E3%81%A8%E6%8E%A5%E7%B6%9A) をした際に、つい「ライト」プランを選択していたのです。ライトプランではカスタム・モデルの作成はできません…
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/ff325094-62d1-497d-7dd9-17dcfa6a8a5c.png)

## プランを変更して新しいモデルを作成してみる

仕方がありません。翻訳サービスをいったん削除して、「拡張」プランで作成と接続を実施します。ローカル実行用に [apiKey の値を入手](https://qiita.com/yamachan360/items/fa4af5f7b18781e5f283#%E3%82%B7%E3%83%B3%E3%83%97%E3%83%AB%E3%81%AB%E7%BF%BB%E8%A8%B3%E3%82%B5%E3%83%BC%E3%83%93%E3%82%B9%E3%82%92%E5%91%BC%E3%81%B3%E5%87%BA%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B) し直すのもお忘れなく！

とはいえ、拡張プランでカスタム・モデルを作成すると、月額で 1575円 かかります。日割り計算されるそうですので、利用日数と翻訳量を考え、ご利用は計画的にお願いします！
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/7fdbe6c8-ff90-b1f6-415d-7bff5014dd7e.png)
さて、改めて Server.js を実行してみましょう。今度はエラーにならず、新しいモデルが生成され、次のように作成されたモデルの情報が表示されます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/b66a7405-c493-8843-1e63-bb6ed966d139.png)

やはりプランの間違いでしたね！

ただ私の月額のお小遣いには限りがありますので、今回の動作を確認したら、いったん「ライト」プランに戻す予定です(涙)

## 新しいモデルで翻訳を試してみる

さあ、新しい翻訳モデルを試してみましょう。翻訳アプリに戻って、International Business Machines を日本語に翻訳してみましょう。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/ace84c3d-c33c-c8af-b5ab-edd58978a0a6.png)
良かった、ちゃんと学習されているようで、翻訳されません。文章に含まれている場合でも大丈夫そうです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/193519/1496b3dd-3576-022a-3760-fd4a03109c1f.png)
これで専用辞書(強制用語集)による学習の効果が確認できました。

# というわけで

6回に渡った翻訳アプリの説明も、これでようやく終了です。最終的なソースコードを  GitHub の [yamachan/rtk-lt](https://github.com/yamachan/rtk-lt) で公開しておきましたので、参照してみてください。

AI を使い、簡単ですが学習したモデルを作成したアプリの作成、なかなか楽しかったです。みなさんもいろいろ試してみてくださいね。

ではでは。