はじめに

ゼロからはじめるAzure、Azure Machine Learningの回もこれで最後です。前回の記事では、予測用のExperimentを作成し、Webサービスを公開しました。ゼロから作るととても面倒な予測用のExperimentの作成ですが、Machine Learning Studio(以降MLStudio)ではとても簡単に作成することができました。そして画面からとExcelからの二通りの方法でWebサービスを呼び出す方法をご紹介しました。

今回はAzure Resource Manager(ARM)対応版としてリリースされた新しいAzure Machine LearningのWebサービスの作成・使用方法をご紹介します。現在はまだPreviewですが、近い将来にARM対応版のWebサービスが正式版となるでしょう。

前回の状態の確認

まずは前回記事で作成した状態を確認しましょう。前回の記事では予測用のExperimentを作成しました。

[1] Experiment全体が正常終了していることを確認する

前回の記事の冒頭と同じ作業となりますが、アクティブになっているタブが「Predictive experiment」であることを確認し、Experiment全体の実行が正常終了しているかを確認してください。

  • Experiment全体が正常終了となっていることを確認する

    Experiment全体が正常終了となっていることを確認する

正常終了していない場合は、RUNボタンをクリックして正常終了させてください。

Webサービスをデプロイする(NEW版対応)

では今度は新しいWebサービスをデプロイしましょう。

[1]Webサービス(NEW)をデプロイする

画面下部の「DEPLOY WEB SERVICE」にマウスポインタを合わせて、表示される「Deploy Web Service [New] Preview」をクリックします。

  • 「Deploy Web Service [New] Preview」をクリックする

    「Deploy Web Service [New] Preview」をクリックする

すると新しい画面が立ち上がり、Webサービスポータル画面のWebサービスデプロイ画面が表示されます。

この画面ではデプロイするWebサービス名とプランを選択、もしくはプラン新規作成ができます。ここではWebサービス名はデフォルト名のままとし、プランは本記事の一番最初でAzure Machine LearningのWorkspaceを新規作成した時に作成したプラン「mynaviPlan」を選択して「Deploy」をクリックします。

  • Webサービスデプロイ画面が表示

    Webサービスデプロイ画面が表示

しばらく待つと画面が切り替わり、作成したWebサービスのQuickstart画面が表示されます。

  • WebサービスのQuickstart画面

    WebサービスのQuickstart画面

画面上でTestする

画面上で入力値をセットしてWebサービスを実行してみましょう。メニュー「Test」をクリックし、テキストボックスに入力値をセットしてから「Test Request-Response」ボタンをクリックします。入力値はClassicWebサービスの時と同じものを使用します。

入力したデータ

列名 入力値
AGE 45
WORKCLASS Private
EDUCATION Bachelors
EDUCATION-NUM 13
MARITAL-STATUS Never-married
RELATIONSHIP Not-in-family
RACE White
SEX Male
CAPITAL-GAIN 2174
CAPITAL-LOSS 0
HOURS-PER-WEEK 40
NATIVE-COUNTRY United-States
  • Test用にインプット値をセットして実行

    Test用にインプット値をセットして実行

画面の右側に結果が表示されます。Classicの時と同じ結果なのは当然ですが、かなり見やすくなっています。

  • 予測結果が表示される

    予測結果が表示される

Testの入力値にサンプル値を表示させることが可能です。メニュー「Configure」を開き、「Sample Data Enabled?」をYesにしてSaveしてください。再度Testを開くと、サンプル値が表示されます。

註:Sample Data Enabled?をYesにしておくことで、この後使用するサンプルソースにもサンプルデータがセットされた状態となり、テストが素早くできるようになります。

サンプルアプリでTestする

では最後にWebサービスをアプリケーションから起動してみましょう。

メニュー「Consume」を開きます。余談ですがExcelのリンクがあります。これをダウンロードすると前回記事のClassicWebサービス作成とテストでご紹介したExcelによるテストと全く同じことが可能です。

  • 「Consume」を開く

    「Consume」を開く

下へスクロールすると、サンプルソースが表示されます。これを使用してWebサービスを起動します。

[1]Visual Studioでプロジェクトを作成する

Visual Studioを起動します。ここではVisual Stduio 2017 Enterpriseを使用します。お持ちでない方は https://www.visualstudio.com/ja/ より無料のCommunityエディションをダウンロードをしてセットアップしてください。

ファイル > 新規作成 > プロジェクトを選択します。

  • ファイル > 新規作成 > プロジェクトを選択

    ファイル > 新規作成 > プロジェクトを選択

今回はコンソールアプリケーションでWebサービスを起動してみます。Visual C# の中からWindows クラシックデスクトップを選択すると、様々なプロジェクトが表示されます。その中からコンソールアプリ(.NET Framework)を選択します。名前と場所、ソリューション名にはお好きな名前と場所を入力してください。今回はデフォルトのままで作成します。

  • コンソールアプリ作成ダイアログの入力例

    コンソールアプリ作成ダイアログの入力例

[2]ソース修正

Program.csが開いた状態だと思います。

  • Program.csが開いている状態

    Program.csが開いている状態

ここへ先ほど表示させたサンプルソースを貼り付けます。その前にサンプルソースを見てみましょう。

 static async Task InvokeRequestResponseService()
 {
     using (var client = new HttpClient())  // ①リクエストをPOSTするためのHttpClientオブジェクトを生成
     {
         var scoreRequest = new
         {
             // ②Webサービスに渡す入力値をセット
             Inputs = new Dictionary<string, List<Dictionary<string, string>>> () {
                 {
                     "input1",// ※ポイント1
                     new List<Dictionary<string, string>>(){new Dictionary<string, string>(){
                                     {
                                         "age", "39"
                                     },
                                     // ・・・省略
                                     {
                                         "native-country", "United-States"
                                     },
                         }
                     }
                 },
             },
             GlobalParameters = new Dictionary<string, string>() {
             }
         };
         // ③Webサービスの認証情報をセット
         const string apiKey = "abc123"; // Replace this with the API key for the web service

         // ※ポイント2
         client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue( "Bearer", apiKey);

         // ④Webサービスのエンドポイントをセット
         client.BaseAddress = new Uri("https://<region>.services.azureml.net/subscriptions/<subscriptionId>/services/<serviceId>/execute?ion=2.0&format=swagger");

         // ⑤Webサービスへ問い合わせ
         HttpResponseMessage response = await client.PostAsJsonAsync("", scoreRequest);

         // ⑥問い合わせ結果を表示
         if (response.IsSuccessStatusCode)
         {
             string result = await response.Content.ReadAsStringAsync();
             Console.WriteLine("Result: {0}", result);
         }
         else
         {
             Console.WriteLine(string.Format("The request failed with status code: {0}", response.StatusCode));
             Console.WriteLine(response.Headers.ToString());
             string responseContent = await response.Content.ReadAsStringAsync();
             Console.WriteLine(responseContent);
         }
     }
 }

InvokeRequestResponseServiceというメソッドで全ての処理を行われています。このメソッドで、Webサービスのエンドポイントに対してリクエストをPOSTします。処理の流れは以下の通りです。
①リクエストをPOSTするためのHttpClientオブジェクトを生成
②Webサービスに渡す入力値をセット
③Webサービスの認証情報をセット
④Webサービスのエンドポイントをセット
⑤Webサービスへ問い合わせ
⑥問い合わせ結果を表示

特筆すべき点は特にありませんが、知っておくべきポイントが2つあります。1つは「②Webサービスに渡す入力値をセット」でscoreRequestという匿名型を使用しています。このscoreRequestの1つ目のディクショナリ型のパラメータ「Inputs」にKEY名「input1」で値をセットしていますが、このinput1というKEY名は、Webサービス用のExperimentを作成した時に自動的に挿入された「Web service input」モジュールのプロパティで定義されているものです。従って、このKEY名を修正したければExperimetを修正してから再度Webサービスを作成しなければなりません。

もう1つのポイントは「③Webサービスの認証情報をセット」でAPIキーをAuthorizationヘッダーにセットする実装です。サンプル実装では、HttpClientオブジェクトのDefaultRequestHeadersプロパティを使用して、AuthorizationヘッダーにAPIキーをセットしていますが、これはあくまでもサンプル実装だと思っておいた方が良いでしょう。

HttpClientは負荷が高い処理であるため、複数回の呼び出し時が発生する場合には再利用する前提で生成・使用します。作成するソフトウェアの特性にもよりますが、一般的にリクエストの度に生成することはしません。 そのためAPIキーのような認証情報は毎リクエストの度にセットするべきですが、DefaultRequestHeadersプロパティを使用するとAuthorizaionヘッダーがリセットされないためバグの元となります。

参考:https://blogs.msdn.microsoft.com/shacorn/2016/10/21/best-practices-for-using-httpclient-on-services/
註:HttpClient.DefaultRequestHeadersプロパティを使用しない場合は、System.Net.Http.HttpRequestMessageクラスとHttpClient.SendAsyncメソッドを使用します。実装例は以下の通りです。HttpClientを再利用する場合、System.Net.Http.HttpRequestMessageクラスはリクエストの度に作成します。
 // リクエスト終了時にコネクションを切断しない(clinet変数はHttpClientオブジェクト)
 client.DefaultRequestHeaders.ConnectionClose = false;

 // endpointにはWebサービスの接続先URIの文字列をセット
 var requestMessage = new HttpRequestMessage { Method = HttpMethod.Post, RequestUri = new Uri(endpoint) };
 requestMessage.Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(scoreRequest), Encoding.UTF8, "application/json");

 // apiKeyにはWebサービスの管理画面に表示されるKEYをセット
 requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);

 // リクエスト発行
 HttpResponseMessage response = await client.SendAsync(requestMessage);

それでは実装してみましょう。サンプルソースの右上にソースをコピーできるアイコンがありますのでクリックします。

  • サンプルソースをコピー

    サンプルソースをコピー

Program.csにデフォルトで実装されているコードを全て削除し、コピーしたサンプルソースをペーストします。

  • サンプルソースをペースト

    サンプルソースをペースト

System.Net.Http.Formattingが見つからなくてエラーとなっています。必要なライブラリが不足していることが原因です。 プロジェクトの中にある参照を右クリック > NuGet パッケージの管理をクリックします。

  • NuGet パッケージの管理を起動

    NuGet パッケージの管理を起動

タブを参照に切り替えてから、検索ボックスに「Microsoft.AspNet.WebApi.Client」と入力します。Microsoftが提供している 同名のモジュールを選択し、インストールボタンをクリックします。

  • Microsoft.AspNet.WebApi.Clientをインストール

    Microsoft.AspNet.WebApi.Clientをインストール

ライセンスへの同意を求めるダイアログがポップアップします。同意します。

  • 変更のプレビューのポップアップ

    変更のプレビューのポップアップ

  • ライセンス同意のポップアップ

    ライセンス同意のポップアップ

インストールが正常に終了すると、System.Net.Http.Formattingが見つからなくてエラーとなっていた箇所はエラーがなくなってます。

  • エラーが消えた

    エラーが消えた

1か所だけソースの修正が必要です。WebサービスへアクセスするためのAPIキーがソース内部にハードコーディングされているのですが、その値は「abc123」です。これを正規のキー値に書き換えます。

再度Webサービス画面の「Consume」メニューを開きます。画面上部にあるPrimary Keyの右側にあるコピーアイコンをクリックします。

  • API Keyをコピー

    API Keyをコピー

サンプルソースを貼り付けたProgram.csの79行目に、APIKeyの値をハードコーディングしている箇所があります。

  • API Keyを変更する場所

    API Keyを変更する場所

コピーしたAPIKeyを貼り付けます。

  • API Keyを変更

    API Keyを変更

[3]起動する

ソースには既にサンプルデータが実装されているはずです。(サンプルデータが実装されていない場合は、「Configure」の「Sample Data Enabled?」をYesにしてSaveして後に再度サンプルソースをコピーしてください)

デバッグ > デバッグなしで開始 を選択します。

  • デバッグなしで開始

    デバッグなしで開始

黒い画面が立ち上がり、しばらくすると結果が表示されます。

  • デバッグなしで開始

    デバッグなしで開始

画面でTestした時とは入力値が違うため、Scored Probabilitiesが異なる値となっていますが、無事に予測結果が取得できました。

最後に

いかがだったでしょうか。Azure Machine Learningを使うと環境構築からモデルの作成、評価から公開までがとても簡単に実装できることがおわかりいただけたかと思います。本番プロジェクトで機械学習を用いるには、データのクレンジングや使用するアルゴリズムの決定、パラメータの調整、再トレーニングをしたモデルを入れ替える方法について勉強する必要がありますが、まずは全体の概要と流れを掴むことが大事です。本記事がその助けとなるようでしたら、大変嬉しく思います。

WINGSプロジェクト 上坂 貴志(株式会社ネクストスケープ)著/山田祥寛監修
<WINGSプロジェクトについて>テクニカル執筆プロジェクト(代表山田祥寛)。海外記事の翻訳から、主にWeb開発分野の書籍・雑誌/Web記事の執筆、講演等を幅広く手がける。一緒に執筆をできる有志を募集中