Azure Machine Learning Studioで作成したモデルをプログラムから再トレーニングする

# はじめに
[Azure Machine Learning Studio](https://azure.microsoft.com/ja-jp/services/machine-learning-studio/)で機械学習のWebAPIを作成しました。このWebAPIを実運用する際には、日々モデルの再トレーニングが必要となってきます。そこで公式ドキュメント([https://docs.microsoft.com/ja-jp/azure/machine-learning/studio/retrain-classic-web-service](https://docs.microsoft.com/ja-jp/azure/machine-learning/studio/retrain-classic-web-service))を参考に進めていったのですが、かなり詰まってしまったのでやり方を共有しておきたいと思います。


# Webサービスのデプロイ
まずはWebサービス(WebAPI)の作成をします。詳しいやり方は公式ドキュメント([https://docs.microsoft.com/ja-jp/azure/machine-learning/studio/create-experiment](https://docs.microsoft.com/ja-jp/azure/machine-learning/studio/create-experiment))を参照してください。

## 予測Webサービスの作成
中のロジックはともかく、だいたいこのような図になるかと思います。
![train_model.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436187/f93b501a-e182-01ef-504e-38423a7495c4.png)

そこで`RUN` -> `SET UP WEB SERVICE` -> `Predictive Web service[Recommend]`

![predictive_model.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436187/bd740dcf-d9f3-61f7-1649-e48ee103a8ad.png)

`RUN` -> `DEPLOY WEB SERVICE` -> `Deploy Web Service[Classic]`

![deploy_predictive.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436187/a31f0668-2ad2-8c4d-d008-e0da6e9349f1.png)

これで予測Webサービスがデプロイされました。

## 再トレーニングWebサービスの作成
こちらのドキュメント([https://docs.microsoft.com/ja-jp/azure/machine-learning/studio/retrain-machine-learning-model](https://docs.microsoft.com/ja-jp/azure/machine-learning/studio/retrain-machine-learning-model))を参考に進めました。

`サイドバーのExperiments` -> `始めに作成したトレーニングWebサービス(Predictiveではないほう)` -> `SET UP WEB SERVICE` -> `Retraining Web Service`

![retrain_model.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436187/0b9d7ea1-d1f0-9aa4-bd1d-7c6da20193db.png)

`RUN` -> `SET UP WEB SERVICE` -> `Deploy Web Service[Classic]`

![deploy_retrain.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436187/4cf6ec8d-cd87-b540-0aee-db2154b07c01.png)

これで再トレーニングWebサービスがデプロイされました。


# 再トレーニングの実行
次に新しいデータセットを用いてモデルの再トレーニングを行います。

再トレーニングの流れは、

1. 新しいデータセットをローカルからBlobへアップロードする
2. Blobのデータセットで再トレーニングさせる
3. 再トレーニングモデルをBlobへアップロードする

となります。
そのため、事前準備としてAzure上にBlobを作成しておく必要があります（Azure Machine Learning Studio ワークスペースをAzureポータル上で作成した場合は自動的に作成されています）。


`サイドバーのWeb Services`　-> `再トレーニングWebサービス` -> `test`
![deploy_retrain_test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436187/af2144ad-4c38-7dde-cdcc-bcf9da910030.png)

`Consume` -> `Sample Code` -> `Batch`

![webservice_batch.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436187/26bf2b26-f226-2956-60d2-2d0af315a319.png)

サンプルコードを実行するため、Visual StudioからC#コンソールアプリケーションを作成します。
[新規] > [プロジェクト] > [Visual C#] > [Windows Classic Desktop] > [コンソール アプリ (.NET Framework)]

作成されたProgram.csにBatchのサンプルコードを貼り付けます。このとき、`apiKey`や`StorageAccountName`等を適切なものに置き換えます。
また、Nugetパッケージの`Microsoft.AspNet.WebApi.Client`をインストールします。

```
const string apiKey = "abc123"; // Replace this with the API key for the web service
```
`apiKey`：再トレーニングWebサービスのAPI Key
![deploy_retrain_apikey.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436187/580c67fd-f027-6f80-fbce-689098f7956d.png)


```
const string StorageAccountName = "mystorageacct"; // Replace this with your Azure Storage Account name
const string StorageAccountKey = "a_storage_account_key"; // Replace this with your Azure Storage Key
const string StorageContainerName = "mycontainer"; // Replace this with your Azure Storage Container name
```
`StorageAccountName`：ストレージアカウント名
`StorageAccountKey`：ストレージアカウントのアクセスキー
`StorageContainerName`：コンテナ名

```
UploadFileToBlob("input1data.file_extension" /*Replace this with the location of your input file, and valid file extension (usually .csv)*/,
                    "input1datablob.file_extension" /*Replace this with the name you would like to use for your Azure blob; this needs to have the same extension as the input file */,
                    StorageContainerName, storageConnectionString);
```
```
"input1",
    new AzureBlobDataReference()
    {
        ConnectionString = storageConnectionString,
        RelativeLocation = string.Format("{0}/input1datablob.file_extension", 
                           StorageContainerName)
    }
```
`input1data.file_extension`：新しいデータセットのアドレス
`input1datablob.file_extension`：保存するデータセットのBlob上での名前

```
{
    "output2",
        new AzureBlobDataReference()
        {
            ConnectionString = storageConnectionString,
                               RelativeLocation = string.Format("{0}/output2results.file_extension", StorageContainerName) /*Replace this with the location you would like to use for your output file, and valid file extension (usually .csv for scoring results, or .ilearner for trained models)*/
        }
},
{
    "output1",
        new AzureBlobDataReference()
        {
            ConnectionString = storageConnectionString,
                               RelativeLocation = string.Format("{0}/output1results.file_extension", StorageContainerName) /*Replace this with the location you would like to use for your output file, and valid file extension (usually .csv for scoring results, or .ilearner for trained models)*/
        }
},
```
`output2results.file_extension`：再トレーニング済みモデル名（拡張子を.ilearnerにする）
`output1results.file_extension`：再トレーニングのログ（拡張子を.csvにする）

コンソールアプリを実行すると再トレーニングが実行され、再トレーニング済みモデルがBlob Storageに出力されます。

# 再トレーニングモデルの適用
新たにエンドポイントを作成し、それに対して再トレーニングモデルの適用を行います。エンドポイントは予測Webサービスに追加します。

`サイドバーのWeb Services`　-> `予測Webサービス` -> `New Web Services Experience` -> `戻るボタン` -> `NEW`
適当な名前を付けてエンドポイントを作成します。
![deploy_predictive_webservice.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436187/318e127a-304e-4617-e6b1-788f25dbab10.png)
![webservice_back.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436187/96b37a99-320b-1be2-c703-0e8348b06fe3.png)
![webservice_new.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436187/d85af8a6-6d07-8ab0-69dd-e0aaa1c8d34c.png)

`エンドポイントの名前` -> `Consume` -> `PATCH api help`
![webservice_apihelp.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/436187/bfd02d5b-893a-0107-7e2e-baba3c8c4166.png)

再トレーニングと同様にコンソールアプリケーションを作成し、サンプルコードを貼り付けます。

`apikey`や`BaseLocation`等も適宜置き換えます。

作成したコンソールアプリケーションを実行すると、指定したBlob上の再トレーニングモデルが作成したエンドポイントへ適用されます。


# おわりに
いろいろ調べたのですが、Classic版でないとC#プログラム上からの更新はできないみたいでした（new版はPowerShellでの更新）。できるよ！ということであれば教えていただきたいです。

ともあれ、C#から更新ができたので他のAPIとの連携がしやすくなりました。