Microsoft Translatorを使ったテキスト機械翻訳 －基本編

Microsoft Translatorは機械翻訳のためのSaaS APIです。現在はAzure Cognitive Servicesという人工知能サービスAPI群の一つとして提供されています。

>
以前はAzure DataMarketというサービスで提供されていましたが、DataMarketは2017年3月31日で提供終了、DataMarketでのMicrosoft Translatorへのアクセスも2017年4月30日で終了します。

このサービスはテキスト翻訳のためのTranslator Text APIと音声翻訳のためのTranslator Speech APIを提供していますが、ここではTranslator Text APIの特徴と基本的な使い方を紹介しようと思います。

## 特徴

- クラウドベースのAPIとして提供されているため、様々なアプリケーションに容易に組み込むことが可能

- Bing翻訳やOffice、Skype Translatorにも組み込まれており、アプリケーションとしてすぐ使えるものとしても提供している

- 日本語を含む60言語 (2017年2月) に対応している

- 中国語も簡体字、繁体字のみでなく、広東語 (繁体字) にも対応している

- 既存言語モデル、新規言語モデルの双方に対してカスタマイズ (学習) が可能

- 従来の統計的機械翻訳に加えて、人工知能型といえる深層学習型機械翻訳のアルゴリズムも提供開始 (深層学習型機械翻訳は2017年2月現在は日本語、英語を含む10か国語に対応していますが、今後増える予定です)

統計的機械翻訳は辞書登録だけで翻訳品質を上げることは難しく、対訳文 (日本語の文章と英語の文章のペアのような) で学習させることが必要と言われていますが、深層学習型機械翻訳は統計的機械翻訳よりもはるかに高い翻訳品質を実現するものとして期待されています。

## まずは試してみる

Microsoft Translatorを簡単に試してみるには、Bing翻訳を使うのがてっとり早いです。「category」GETパラメータで「generalnn」と指定するだけで、アルゴリズムが切り替わります。

- 統計的機械翻訳：[http://www.bing.com/translator:title=http://www.bing.com/translator](http://www.bing.com/translator:title=http://www.bing.com/translator)

- 深層学習型機械翻訳：[http://www.bing.com/translator?category=generalnn](http://www.bing.com/translator?category=generalnn)

例としてMicrosoft Translatorの製品ページにある以下の文章を訳してみます。

*Microsoft Translator Text API, part of the Microsoft Cognitive Services API collection, is a cloud-based machine translation service supporting multiple languages that reach more than 95% of world's gross domestic product (GDP). Translator can be used to build applications, websites, tools, or any solution requiring multilanguage support.*


統計的機械翻訳の場合：
*Microsoft Translator テキスト API、Microsoft 認知サービス API コレクションの一部は、世界の国内総生産 (GDP) の 95% 以上に達する複数の言語のサポート クラウド ベースの機械翻訳サービスです。アプリケーション、web サイト、ツール、または複数言語のサポートを必要とする任意のソリューションを構築するトランスレーターを使用することができます。*

個人目的として使う分にはよさそうですが、正式文書で使うには学習したほうがよさそうです。


深層学習型機械翻訳の場合：
*microsoft 認知サービス api コレクションの一部である Microsoft Translator テキスト api は、世界の国内総生産 (gdp) の 95% 以上に達する複数の言語をサポートするクラウドベースの機械翻訳サービスです。トランスレータは、アプリケーション、web サイト、ツール、または多言語サポートを必要とする任意のソリューションを構築するために使用できます。*

自然な文書になってますね。アルゴリズムを変えるだけで、ここまで訳に変化が出ています。

## Translator Text APIを使ってみる

それでは本題であるTranslator Text APIの使い方を紹介していきます。Translator Text APIでもアルゴリズムの変更は簡単にできますので、合わせて紹介していきます。
なお、Translator Text APIにはREST、SOAP、AJAXの3つの種類のAPIがありますが、ここではREST APIを使用します。

Translator Text APIを使用するには、以下の3つの手順が必要になります。

- Subscription Keyの取得
  認証トークンを取得するために必要になります。認証トークンの取得方法はAzure DataMarketで提供されていた時点のものから変更されていますので、ご注意ください。

- 認証サービスの呼出
  認証サービスを呼び出し、Subscription Keyから認証トークンを生成します。

- 翻訳サービスの呼出
  認証サービスを呼び出し、文章を翻訳します。

以下では、これらの基本的な使用方法について記述していきます。

### Subscription Keyの取得
まずはAzureが使用できるようにしてください。こちらについては各種情報があると思いますので、そちらをご参考に。

Azureポータルにログインしたら、左のメニューから「新規」→「Intelligence + analytics」→「Cognitive Services APIs」を選択します。

Cognitive Servicesアカウントの作成画面で、以下の項目を入力し、アカウントを作成します。
- Account name：アカウントの表示名を入力
- サブスクリプション：利用可能なサブスクリプションを選択
- API Type：Translator Text API
- 価格レベル：任意の価格レベル(F0を選択すると、200万文字まで利用可能な無料版となります)
- Resource Group：任意で作成もしくは既存のリソースグループを選択
- Resource group location：自分のいる場所に近いロケーションを選択

アカウントが作成されたら、作成したアカウントを選択し、「Keys」メニューを選択して「KEY 1」を確認します。こちらがSubscription Keyになりますので、記録しておいてください。

Subscription Keyの取得方法については、以下のドキュメントを参考にしてください。
[https://www.microsoft.com/ja-jp/translator/getstarted.aspx](https://www.microsoft.com/ja-jp/translator/getstarted.aspx)

### 認証サービスの呼出
Translator Text APIの呼出は、認証トークンによる認証が必要です。認証トークンは複数の認証サービスの呼出に対して再利用できますが、有効時間は10分となっているため、認証サービスを呼び出す際には有効時間を考慮する必要があります。

認証トークンは、認証サービスに対して「Ocp-Apim-Subscription-Key」ヘッダーにSubscription Keyをセットしてリクエストするか、「Subscription-Key」GETパラメータにSubscription Keyをセットしてリクエストすることで取得できます。認証サービスのURLは以下になります。
認証サービス：[https://api.cognitive.microsoft.com/sts/v1.0/issueToken](https://api.cognitive.microsoft.com/sts/v1.0/issueToken)


翻訳サービスの呼出時には、認証トークンをBearトークンとしてヘッダーにセットして渡します。


以下のコードは、認証サービスを呼び出すためのC#のサンプルクラスになります。

```
public class AzureAuthToken
    {
        // 認証サービスのURL
        private static readonly Uri ServiceUrl = new Uri("https://api.cognitive.microsoft.com/sts/v1.0/issueToken");
        // Subscription Keyを渡すときの要求ヘッダー
        private const string OcpApimSubscriptionKeyHeader = "Ocp-Apim-Subscription-Key";
        // 認証トークンの有効時間：5分
        private static readonly TimeSpan TokenCacheDuration = new TimeSpan(0, 5, 0);
        // 有効な認証トークンを格納
        private string storedTokenValue = string.Empty;
        // 有効な認証トークンの取得時間
        private DateTime storedTokenTime = DateTime.MinValue;

        /*
          Subscription Keyの取得
        */
        public string SubscriptionKey { get; private set; } = string.Empty;

        /*
         認証サービスへのリクエスト時のHTTPステータスコードの取得
        */
        public HttpStatusCode RequestStatusCode { get; private set; }

        /*
          認証トークンを取得するためのクライアント作成
          <param name="key">Subscription Key</param>
        */
        public AzureAuthToken(string key)
        {
            if (string.IsNullOrEmpty(key))
            {
                throw new ArgumentNullException("key", "Subscription Keyが必要です。");
            }

            this.SubscriptionKey = key;
            this.RequestStatusCode = HttpStatusCode.InternalServerError;
        }

        /*
          Subscriptionに紐づいた認証トークンの取得 (非同期)
        */
        public async Task<string> GetAccessTokenAsync()
        {
            if (SubscriptionKey == string.Empty) return string.Empty;

            // 認証トークンが有効な場合は有効な認証トークンを返す
            if ((DateTime.Now - storedTokenTime) < TokenCacheDuration)
            {
                return storedTokenValue;
            }

            // 認証トークンを取得
            using (var client = new HttpClient())
            using (var request = new HttpRequestMessage())
            {
                request.Method = HttpMethod.Post;
                request.RequestUri = ServiceUrl;
                request.Content = new StringContent(string.Empty);
                request.Headers.TryAddWithoutValidation(OcpApimSubscriptionKeyHeader, this.SubscriptionKey);
                client.Timeout = TimeSpan.FromSeconds(2);
                var response = await client.SendAsync(request);
                this.RequestStatusCode = response.StatusCode;
                response.EnsureSuccessStatusCode();
                var token = await response.Content.ReadAsStringAsync();
                storedTokenTime = DateTime.Now;
                storedTokenValue = "Bearer " + token;
                return storedTokenValue;
            }
        }

        /*
          Subscriptionに紐づいた認証トークンの取得 (同期)
        */
        public string GetAccessToken()
        {
            // 認証トークンが有効な場合は有効な認証トークンを返す
            if ((DateTime.Now - storedTokenTime) < TokenCacheDuration)
            {
                return storedTokenValue;
            }

            // 認証トークンを取得
            string accessToken = null;

            var task = Task.Run(async () =>
            {
                accessToken = await GetAccessTokenAsync();
            });

            while (!task.IsCompleted)
            {
                System.Threading.Thread.Yield();
            }

            if (task.IsFaulted)
            {
                throw task.Exception;
            }
            else if (task.IsCanceled)
            {
                throw new Exception("トークンの取得がタイムアウトしました。");
            }

            return accessToken;
        }
    }
```


認証サービスの使用方法については、以下のドキュメントを参考にしてください。
[http://docs.microsofttranslator.com/oauth-token.html](http://docs.microsofttranslator.com/oauth-token.html)

### 翻訳サービスの呼出
翻訳サービスは
[http://api.microsofttranslator.com/v2/Http.svc/](http://api.microsofttranslator.com/v2/Http.svc/)
こちらのURLで提供されています。複数のサービスが使用できますが、最も単純な翻訳サービスは以下になります。
[http://api.microsofttranslator.com/v2/http.svc/translate](http://api.microsofttranslator.com/v2/http.svc/translate)

このサービスに対して以下のGETパラメータを指定してリクエストすることで、翻訳が実行されます。

- text
  翻訳対象文書
- appId
  認証トークン(Bearトークン)
- from
  翻訳元言語
- to
  翻訳先言語
- category
  翻訳ドメイン
  デフォルトは統計的翻訳アルゴリズムを利用する「general」になりますが、深層学習型機械翻訳を利用する場合には「generalnn」、その他のドメイン(例えばユーザー定義言語モデルを使用する場合)を利用する場合には「(カテゴリ名)」を指定

以下のコードは、翻訳サービスを呼び出すためのC#のサンプルクラスになります。

```
public class CallTranslator
    {
        // Subscription Key
        private const string SubscriptionKey = "<Subscription Keyを入力>";
        // TranslateサービスのURL
        private static readonly Uri ServiceUrl = new Uri("http://api.microsofttranslator.com/v2/Http.svc/");

        /*
          翻訳の実施
          <param name="textToTransform">翻訳対象文書</param>
          <param name="fromLangCode">翻訳元言語</param>
          <param name="toLangCode">翻訳先言語</param>
          <param name="domain">翻訳ドメイン</param>
        */
        public string TranslateMethod(string textToTransform, string fromLangCode, string toLangCode, string domain)
        {
            // トークンの取得
            var authTokenSource = new AzureAuthToken(SubscriptionKey);
            var token = string.Empty;
            token = authTokenSource.GetAccessToken();

            // 翻訳サービスの呼出
            string uri = ServiceUrl + "Translate?text=" + System.Web.HttpUtility.UrlEncode(textToTransform) 
                + "&appid=" + token + "&from=" + fromLangCode + "&to=" + toLangCode + "&category=" + domain;
            HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(uri);
            WebResponse response = null;
            string translatedText = null;

            try
            {
                response = httpWebRequest.GetResponse();
                using (Stream stream = response.GetResponseStream())
                {
                    System.Runtime.Serialization.DataContractSerializer dcs = new System.Runtime.Serialization.DataContractSerializer(Type.GetType("System.String"));
                    translatedText = (string)dcs.ReadObject(stream);
                }
            } catch (Exception ex){
                Console.WriteLine("message: " + ex.Message);
                Console.WriteLine("stack trace: ");
                Console.WriteLine(ex.StackTrace);
                Console.ReadLine();
            }

            return translatedText;
        }
```


翻訳サービスの使用方法については、以下のドキュメントを参考にしてください。こちらではその他のサービスの使用方法についても記載されています。
[http://docs.microsofttranslator.com/text-translate.html#!/default/get_Translate](http://docs.microsofttranslator.com/text-translate.html#!/default/get_Translate)


上記のコードを使用したサンプルコードをGitHubで公開していますので、そちらも参考にしてみてください。サンプルコードでは、翻訳対象文書から翻訳元言語を自動識別するサービスも使っています。
[https://github.com/masakykato0526/SimpleMicrosoftTranslator](https://github.com/masakykato0526/SimpleMicrosoftTranslator)