Azure Machine Learning で Scikit Learn ベースのモデルを開発する　～　最低限の実行

Azure Machine Learning Service （AMLS）を利用して、Scikit Learnのモデルを開発に応用するまでの手順です。
一からAMLSで作り上げるのではなく、手元にSKLearn系のプロジェクトがあり、かなり形になってきたので、MLOpsに移行したいなんて言う時によかろうかと思います。

ここでは、とっつきにくいと感じる向きにおすすめの、取り合えず載せるだけ、というパターンを紹介します。この時点では、サーバー側で実行するというメリットしかありませんが、それでも以下のようなメリットがあります。

* ローカルの環境の煩わしさからの解放。環境がおかしくなった時の対応が必要ない（毎回クリーン）。
* VMを立ち上げたり、閉じたりする管理が必要がない。オンデマンド実行である。（時間単価にしたら少々割高ですが、空走が無いのが大きい。）VM/コンテナのチョイスが多いので、一から構築する手間がほとんどない。
* Run履歴を管理できる。ローカルでやる場合よりも、整然と行うことができます。実際問題評価とかモデル保存とか、特殊な場合はAMLSの仕組みを使わない方が便利かもしれないので、この単純な方式でログを残すので十分な場合も多い。


# 準備

Azureのリソースが確保できていれば、驚くほど簡単に準備が完了します。
クライアントはVSCodeでなくてもazure ml SDKが使えれば、何でもよいはずです。

## VSCodeエクステンションのインストール
Visaul Studio Code で当該のExtensionをインストールします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/e218700a-d698-727d-b90d-7cff5d7b1729.png)

以前はVisual Studio Code Tools for AIと呼ばれていたものです。Visual Studioにも同様のものが存在します。
以下のようにエクステンションのページに書いてありますが、エクステンションを使って何か特殊な実行プロファイルができたりとか、オプション指定ができたりという事ではなくて、ライブラリのインストールと、AMLSのリソースビュアーがつくくらいのようです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/63a3b9b7-5deb-759d-6330-ba28cddb36ee.png)

# 使う

## 起動、接続
amlrun.pyというAMLSをクライアントから起動するスクリプトを書きます。

``` python
# base packages to work with AMLS
import azureml.core
from azureml.core import Workspace
# check core SDK version number
print("Azure ML SDK Version: ", azureml.core.VERSION)
# create workspace
ws = Workspace.from_config()
print(ws.name, ws.location, ws.resource_group, ws.location, sep='\t')
```

以下のようなメッセージを見ることができます。
Azureテナントへのログインがブラウザで促されるので、ログインします。
ワークスペースについての情報を出力しておくと、間違えて違うテナントやRGで作業していないか確認ができます。

```
Azure ML SDK Version:  1.12.0
Performing interactive authentication. Please follow the instructions on the terminal.
```

本来以下の通りパッケージをインストールする必要がありますが、上記のエクステンションのインストール時に解消しているようです。何らかの理由で無い場合は以下でOK。


``` python
pip install azureml-core
```

## experimentを作成

実験を設定します。ワークスペースの配下に実験ごとのオブジェクトを作成、登録することになります。
amlrun.pyというのはMSDNのサンプルによく出てくるAMLの実行スクリプトのことです。
私の場合はVSCodeでインタラクティブ実行をしています。

``` amlrun.py
experiment_name = 'experiment'
from azureml.core import Experiment
exp = Experiment(workspace=ws, name=experiment_name)
```

## クラスタ立ち上げ

サービス側でクラスタを起動します。既存のクラスタがあれば、それを再利用するようになっています。

``` amlrun.py
# Compute cluster creation.
from azureml.core.compute import ComputeTarget, AmlCompute
from azureml.core.compute_target import ComputeTargetException

# Choose a name for your CPU cluster
cpu_cluster_name = "amlcluster"
# Verify that cluster does not exist already
try:
    cpu_cluster = ComputeTarget(workspace=ws, name=cpu_cluster_name)
    print('Found existing cluster, use it.')
except ComputeTargetException:
    compute_config = AmlCompute.provisioning_configuration(vm_size='STANDARD_D2_V2',
                                                           max_nodes=4)
    cpu_cluster = ComputeTarget.create(ws, cpu_cluster_name, compute_config)
cpu_cluster.wait_for_completion(show_output=True)
```

## ランタイムの登録

ここでは特殊ですが、以前紹介した、pythonnetを利用したScikit-Learnラッパーを使っているので以下のように環境（environment)にインストールの手順を書いておきます。
なぜかpipではうまくいかない環境だったのでcondaでconda-forgeをチャネルに指定しています。
.NETのライブラリを pythonnet経由で叩くラッパーをさらにscikit-learn 用に インターフェイスを整えてラップしたものを、AMLSに登録しようとしています。ややこしいですね。
最後にyamlにセーブしておきます。

``` amlrun.py
from azureml.core import Environment
from azureml.core.environment import CondaDependencies
env = Environment(name="environment")
env.docker.enabled = True
env.python.conda_dependencies = CondaDependencies()
env.python.conda_dependencies.add_channel("conda-forge")
env.python.conda_dependencies.add_conda_package("scikit-learn")
env.python.conda_dependencies.add_conda_package(" pythonnet")
env.python.conda_dependencies.save_to_file(project_folder, "env.yml")
```

## ランタイムの構成

RunConfigというオブジェクトで実行を構成します。
estimator.pyというのが上記のscikit learn準拠のラッパーです。
ラッパーに渡す引数も指定します。ここではデータファイルを手動で指定しています。
ソースコードと同時にデータをアップロードするので、手元での管理は楽ですが、AMLS本来の使い方とは少し違う感じです。

``` amlrun.py
from azureml.core import ScriptRunConfig
from azureml.core.runconfig import DEFAULT_CPU_IMAGE

from azureml.train.sklearn import SKLearn
script_params = {
    '--datafile': 'sourcecsv',
    '--option': 'option',
   ....
}

estimator = SKLearn(source_directory=project_folder, 
                script_params=script_params,
                compute_target=cpu_cluster.name,
                environment_definition = env,
                entry_script='estimator.py')

```



## いざ実行

実行はいたってシンプル。以下のような形でestimatorをサブミットします。

``` amlrun.py
run = exp.submit(estimator)
run.wait_for_completion(show_output=True)
```

submitすると、データも同時に送り込んでいるので、以下のようなワーニングが出ますが、気にしません。データを毎回送るなんて、正気の沙汰ではないですが、最初はまあいいでしょう。

```
Submitting c:\Users\sources\project directory for run. The size of the directory >= 25 MB, so it can take a few minutes.
```

AMLSのコンソールでみると、確かにクラウド側に送られて実行されていることがわかります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/146939/6726a44c-1e30-5480-11f0-6aa162c4c059.png)

実行後は必要な情報がメトリックなどで確認できるので、それを見て実験の良しあしを判断することになります。
これだけだとＡＭＬＳの良さはあまり伝わって来ないですが、あとはデータソースの管理、モデルの管理、結果の管理をそれぞれのフィーチャーを担当する機能を使ってＡＭＬＳらいしい使い方にしていけば問題ないと思います。

全部をAMLS用に書き換えると、結構コード側の対応が多くなってしまうので、最初は実行だけクラウドに飛ばす、というのはとっつきやすいと思います。


## 参考URL

* [チュートリアル:MNIST データと scikit-learn を使用して画像の分類モデルをトレーニングする](https://docs.microsoft.com/ja-jp/azure/machine-learning/tutorial-train-models-with-aml)

* [Azure Machine Learning を使用して scikit-learn モデルを大規模にトレーニングする](https://docs.microsoft.com/ja-jp/azure/machine-learning/how-to-train-scikit-learn)

* [チュートリアル:個人の開発環境で Azure Machine Learning の使用を開始する (パート 1/4)](https://docs.microsoft.com/ja-jp/azure/machine-learning/tutorial-1st-experiment-sdk-setup-local)

* [Visual Studio Code の Azure Machine Learning (プレビュー) 拡張機能を設定する](https://docs.microsoft.com/ja-jp/azure/machine-learning/tutorial-setup-vscode-extension)

* [Azure Machine Learning documentation](https://docs.microsoft.com/en-us/azure/machine-learning/)