Custom Translator 機械翻訳のカスタマイズ

#概要
　[Microsoft Translator Text API V3](https://docs.microsoft.com/ja-jp/azure/cognitive-services/translator/reference/v3-0-translate?tabs=curl) からカスタム翻訳システムを構築できる [Custom Translator](https://portal.customtranslator.azure.ai/) が利用できるようになりました。このサービスの具体的な利用方法に関して、[公式ドキュメント](https://docs.microsoft.com/ja-jp/azure/cognitive-services/translator/custom-translator/overview)を読んでも体系的にわかりずらかったので簡単にまとめてみました。

#辞書データの作成
　本検証では、気象庁の[緊急地震速報・津波警報の多言語辞書](https://www.jma.go.jp/jma/press/1510/29a/tagengo20151029_dictionary.pdf)を拝借して、フレーズ辞書（単語）、センテンス辞書（文章）を以下のように EXCEL で作成してみました。本辞書のサンプルデータは、[こちらよりダウンロードも可能](https://github.com/Yuichi-Ikeda/Dictionary-Data-for-Custom-Translator)です。

**フレーズ辞書（単語）**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/def4200b-58c3-1b9b-a027-f662f7b09e23.png)
**センテンス辞書（文章）**
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/25eb541e-ffa2-e4a0-14a0-60c9fa098a32.png)

#翻訳サービスのデプロイ
1. 最初に [Azure ポータル](https://portal.azure.com)で Translator Text サービスをデプロイします。無償プランでは Custom Translator 機能は利用できないので、ここでは S1 プランを選択してデプロイします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/a150feff-2e68-efa5-8842-1da7c14f9bd5.png)
2. デプロイ後に KEY 1 の値を確認し控えておきます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/8ca07a85-61c6-94b8-8dfc-3457c70262a4.png)
3. 次に [Custom Translator ポータル](https://portal.customtranslator.azure.ai/)にログインし、[Settings] から [+Add key] をクリックし、先に控えて置いたキーを設定します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/86b47c78-e95d-c80f-49d7-f2fdb613b703.png)
正常に登録されると、下記のようになります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/e53b4a44-1fd2-d796-ec5c-07df95efa11f.png)


#プロジェクト（カスタムモデル）の作成
1. [Custom Translator ポータル](https://portal.customtranslator.azure.ai/)で、新規プロジェクトをデプロイします。今回は日本語から英語への翻訳ペアを選択し、カテゴリは汎用の General を選択します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/0c769b3e-d637-4d1b-0ea8-4f1c01872add.png)

2. 作成された Project をクリックし、Upload files から、フレーズ辞書（単語）の EXCEL ファイルをアップロードします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/1d6a265a-53c6-bb6e-4c80-e9d291134bad.png)
3. 同様にセンテンス辞書（文章）をアップロードします。
4. 2 つの辞書のアップロードが完了したら、[Data] タブで両方の辞書を選択し、モデルの作成 [Create model] を実行します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/d518994c-00f5-188e-be03-c2f799369512.png)
5. モデルの作成には、それなりに時間がかかります。Status が Data processing から Training succeeded になるまで気長に待つ必要があります。Training succeeded になると Deploy ボタンが現れるので、ここからモデルをデプロイします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/cf38ba7f-091b-1f50-f783-73767b1cf887.png)
6. 日本に一番近い Asia Pacific にデプロイします。近い将来全てのリージョンにデプロイ可能となる予定です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/9ae3cd22-d9c4-4689-e5f9-78edd8f005c7.png)
7. デプロイも、それなりに時間がかかります。Status が Deploying から Deployed になるまで気長に待つ必要があります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/72aac550-e0de-411c-6096-03a6383df342.png)
上記のステータスとなっていればカスタムモデルのデプロイが完了しています。

#アプリケーションからの呼び出し
　作成したカスタムモデルをクライアントアプリケーションから呼び出してみます。こちらは .NET Framework 4.6.1 のコンソールアプリケーションの例となります。サンプルの詳細に関してはコード後の説明をご参照ください。

```c#:Program.cs
using System;
using System.Net.Http;
using System.Text;
using Newtonsoft.Json;

namespace MSTranslator_v3
{
    class Program
    {
        static void TranslateText()
        {
            string host = "https://api.cognitive.microsofttranslator.com";
            // Text Translator サービスのキーを設定します。
            string subscriptionKey = "5c96ef12085843bbb8f4bd79c52d852d";
            // category の指定でカスタムモデルの Category ID を指定します。
            string route = "/translate?api-version=3.0&from=ja&to=en&category=f802c0a4-e498-4f81-9f99-f034acc98c7d-GENERAL";

            System.Object[] body = new System.Object[] { new { Text = @"揺れがおさまるまで身を守ってください。" } };
            var requestBody = JsonConvert.SerializeObject(body);

            using (var client = new HttpClient())
            using (var request = new HttpRequestMessage())
            {
                // Set the method to POST
                request.Method = HttpMethod.Post;
                // Construct the full URI
                request.RequestUri = new Uri(host + route);
                // Add the serialized JSON object to your request
                request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
                // Add the authorization header
                request.Headers.Add("Ocp-Apim-Subscription-Key", subscriptionKey);
                // Send request, get response
                var response = client.SendAsync(request).Result;
                var jsonResponse = response.Content.ReadAsStringAsync().Result;
                // Print the response
                Console.WriteLine(jsonResponse);
                Console.WriteLine("Press any key to continue.");
            }
        }
        static void Main(string[] args)
        {
            TranslateText();
            Console.ReadLine();
        }
    }
}
```

#カスタムモデルと標準モデルの切り替え
　上記のサンプルで subscriptionKey は最初に控えた KEY1 の値となり、category の指定がカスタムモデルを呼び出す識別子となっています。この２つの識別子を実際の環境に合わせて変更いただく必要があります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/13769c9d-f9c6-1574-9312-3498381192b8.png)
　category は Custom Translator ポータルの下記箇所で確認いただけます。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/166732/fd6e1245-2ee9-6997-2d27-5df591c871fa.png)


　標準モデルを利用する場合、ここのカテゴリは既定値の general となります。また category はオプショナルパラメータのため省略した場合も、標準の MS Translator v3 のモデルが利用されます。この category 識別子を切り替えてアプリケーションを実行する事で、標準モデルとカスタムモデルとで翻訳結果の違いを確認できます。

#翻訳結果
　翻訳文の中に辞書に登録されたフレーズ（単語）やセンテンス（文章）が含まれている場合、以下のように翻訳結果が標準モデルとカスタムモデルで異なるのがわかります。センテンス（文章）の場合、完全一致でなく句読点などの揺らぎは吸収します。

| 原文    |       標準モデル |    カスタムモデル      |
|:-----------------|:------------------|:-------------------|
|気象庁からの緊急速報です。|This is an emergency earthquake report from JMA.|Earthquake Early Warning (EEW) from the Japan Meteorological Agency (JMA).|
|揺れがおさまるまで身を守ってください。|Please protect yourself until the shaking subsides.|Be prepared for strong tremors.|