Azure Machine LearningのAutoMLで画像分類を試してみた

皆さん、AzureのAutoMLは活用していますでしょうか？
データさえ準備しておけば、Azure Machine Learning Studio(WEBブラウザ)からポチポチっとボタンをクリックするだけで、モデルの学習→評価→デプロイまで簡単に実行できます。
以前は「分類」「回帰」「時系列の予測」がWEBブラウザ経由の実行に対応していましたが、今年22年6月に「Computer Vision(画像)」「Natural Language Processing(自然言語処理)」がWEBブラウザ経由の実行に対応しました！

「Computer Vision」のタスクでは、「画像分類(複数クラス)」「画像分類(複数ラベル)」「物体検出」「インスタンスのセグメント化」が利用できます。
今回は「画像分類(複数クラス)」のAutoMLに関して解説していきます。
![画像52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/569c9d5e-2097-1bac-a0e1-9e26ec85ce7d.png)

# 問題設定
今回は与えられた画像が犬か猫かを判別する分類モデルを作っていきます。
画像は例のごとくkaggleから拝借しました。

https://www.kaggle.com/datasets/biaiscience/dogs-vs-cats

# 画像のラベル付け
まずは、画像の学習データから作っていきましょう。
AutoMLでは、画像のラベルをJSONL形式を準備する必要があります。※
```
[
{
   "image_url":"AmlDatastore://data_directory/../Image_name.image_format",
   "image_details":{
      "format":"image_format",
      "width":"image_width",
      "height":"image_height"
   },
   "label":"class_name",
},
{...}
]

```
1からJSONLを作るのはめんどくさいですが、Azureのデータラベル付けツールを使えば、簡単にJSONLを作れます。


※[自動機械学習を使用してコンピューター ビジョン モデルをトレーニングするためのデータ スキーマ](https://docs.microsoft.com/ja-jp/azure/machine-learning/reference-automl-images-schema)
## データセットの登録
ラベル付けツールを使う前に、画像データをデータセットとして登録しておきます。
画像データはAzure Data Lake Storage(ADLS)に下記の通り格納されています。
![画像1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/e60975c3-ca08-d211-8834-693a053f04c9.png)
※Azure Machine LearningからADLSにアクセスする方法は下記をご参照ください。

https://qiita.com/tmiyata25/items/3f2cc7890ca94ba7bfb2

Azure Machine Learning Studioにアクセスし、[データ]->[作成]->[データストアから]をクリックしましょう。
![画像56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/e333fd35-93cf-4616-74f6-d521a864526c.png)
学習用のデータセットから作っていきましょう。
データセット名を入力し、データセットの種類は「ファイル」を選択しましょう。
![画像3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/2d454873-f059-300e-4499-ffdd4c346572.png)
学習データが格納されているデータストアを選択します。次に、画像データのパスをワイルドカード(＊)を駆使して入力します。
今回はデータ量が多いので[データの検証をスキップ]にチェックを入れます※。

![画像4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/18897f06-8639-fd9d-1fe0-2084f598d4e1.png)

:::note warn
※[データの検証をスキップ]にチェック入れず次に進むと、スキャンするデータが多い場合はタイムアウトエラーが発生します。その場合は、パスをワイルドカードで指定せずに「image/dogcat/train.zip/train/cat.1.jpg」のように具体的に指定して、データ検証だけ行いましょう。そして、特にエラーが出なければ[戻る]をクリックし、再びワイルドカードでパスを指定し、[データの検証をスキップする]にチェックを入れて[次へ]をクリックしましょう。
:::

検証用のデータも同様の手順で登録します。すると、下記の通り学習用と検証用の２種類のデータセットが登録された状態になります。
![画像5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/f50cb4b2-27c5-b697-59e9-10421e7c97e5.png)

## データのラベル付け
次はこれらの画像にラベルを付けていきます。
### ラベル付けプロジェクトの作成
左メニューの一番下の[データのラベル付け]->[プロジェクトの追加]をクリックしましょう。
![画像53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/5bc75d22-bf68-4d44-4b52-2add22b1dd6d.png)
[プロジェクト名]を入力し、[メディアの種類]は「イメージを選択」、[タスクの種類]を「画像分類の複数クラス」を選択しましょう。
![画像6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/acfe829d-2ad0-434c-874b-afd356dc95a1.png)
人員の追加ではラベル付けタスクを別の会社に委託することができます。
今回必要はないので、[次へ]をクリックしましょう。
![画像9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/f61a5a8c-035a-9075-f5f1-7ef851a63ec8.png)
先ほど登録したデータセットから「dogcat-train」を選択します。
![画像8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/9c219213-52aa-a933-32ec-7faafe8347be.png)
増分更新を有効にすると、新しく画像データが追加された場合に、ラベリングタスクにその画像データを追加してくれます。
今回は特に必要ないので、[次へ]をクリックします。
![画像10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/c42ade38-a391-0dc9-cf92-aa659c6d821a.png)
ラベル名を定義します。今回は「dog」と「cat」を入力します。
![画像11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/d9a29519-f2d3-d116-b1df-d8597d7c6d95.png)
命令のラベル付けでは、タスク内容を記入することができます。
特に複数人数でラベリングする場合は、ラベルの判定基準を明記しておきましょう。
![画像12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/df222c0c-0838-9a63-51c1-807577c57007.png)
ML Assistにラベル付けを有効にすると、ラベル付け前のデータに対して機械学習モデルがラベルを予測して付与し、ラベリングの作業を高速化してくれます。今回は話を簡単にするためにあえて「無効」にしますが、便利な機能なのでまたの機会に解説するかもしれません。
最後に[プロジェクトの作成]をクリックしましょう。
![画像13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/a5c779f2-eb78-19ab-3880-a71e21854ad2.png)
### 画像のラベル付け
しばらく待つとプロジェクトが作成され、ラベルの進行状況も確認できます。
プロジェクト「dogcat-train-label」をクリックします。
![画像14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/e171da14-0f0b-53cd-8b79-f25985bc6764.png)
こちらから画面からはタスクの状況を確認できます。
右上の[ラベルデータ]をクリックし、ラベリングしていきましょう。。
![画像15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/2e17da59-31ba-9799-a12e-b4bf84369599.png)
１枚１枚画像を見て、犬か猫かのラベルを付けていきます。マウスではやってられないのでショートカットを使いましょう。
犬の場合は「１」猫の場合は「２」を押して、「E」ボタンでラベルを送信します。
![画像16.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/d646fe1c-098d-d172-b25f-20d9aa80d1a4.png)
何とか200枚ほどラベルを付け終わりました。10分程とは言え、長く感じます。。
本当は最低1000枚くらい学習データが欲しいところですが、今回はこの200枚を学習データにしようと思います。
[エクスポート]->[Azure ML データセット]をクリックし、ラベリング結果をデータにエクスポートしましょう。
こちらのラベリング結果(JSONL)は[データ]に登録されます。
![画像17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/f9ee63fb-50b6-f5f5-04f3-7f8614d0ef24.png)
左メニュー[データ]からエクスポートされたラベリング結果が確認できます。
![画像54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/52eca0e0-0263-ee70-aed0-4174256f1f15.png)
同じように検証用データもラベル付けを行いましょう。今回検証用データとして100枚ラベル付けを行いました。
# モデルの学習
## AutoMLのジョブ実行
左メニュー[自動 ML]->[新規の自動機械学習ジョブ]をクリックします。
![画像55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/e59a3135-5c31-deca-5f67-63ccf70e1c30.png)

学習データは、先ほど作成したラベリング結果「dogcat-train-label_20220712_063957」を選択します。
![画像19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/e266d3d9-df54-68d0-80f6-31de500e8bc5.png)
学習データを選択すると、自動的にタスクの種類は「画像分類(複数クラス)」と認識されます。
[新規作成]で実験名を入力し、ターゲット列は「label」を選択します。
コンピューティングは事前に作成してあるGPUクラスター「gpu-cluster-nc24」を選択します。
![画像20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/012f8db4-2917-8899-37e5-9ced649ce77e.png)

:::note warn
コンピューティングインスタンスの種類はNCファミリーかNDファミリーでないと怒られます。
![画像23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/6f30b6ec-d3d7-9267-a028-a37195c89c2b.png)
これらのインスタンスが利用できない場合は、リージョンを変えて作成できないか確認しましょう。
:::

次に、学習アルゴリズムの選択とハイパーパラメータチューニングです。
利用可能な学習アルゴリズムは[こちら](https://docs.microsoft.com/ja-jp/azure/machine-learning/how-to-auto-train-image-models?tabs=CLI-v2#supported-model-algorithms)、調整可能なハイパーパラメータは[こちら](https://docs.microsoft.com/ja-jp/azure/machine-learning/reference-automl-images-hyperparameters)をご参照ください。
今回はモデルを「mobilenet2」にし、簡単なハイパーパラメータを追加していきましょう。
![画像27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/6d2fe638-7bfb-2f2e-28fc-9048ffd3f6d5.png)
今回はトレーニングのバッチサイズを変更してみましょう。
[ハイパーパラメータ]に「training_batch_size」、[ディストリビューション]に「選択肢」、[値]に「16,32,64」を入力して、下の「保存」をクリックしましょう。
![画像28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/d3acfbbb-4df6-d03f-ab2e-14128e4dcea2.png)

全体としては、下記の通りハイパーパラメータの設定を追加しました。

| パラメータ名 | 説明 | 値 |
|:-|:-|:-|
| number_of_epochs  |トレーニング エポックの数   |  100 (Default:15) |
| early_stopping  |トレーニング中に早期停止ロジックを有効にします  | 0 (Default:1)   |
| training_batch_size  |トレーニング バッチ サイズ|[16,32,64] (Default:15)    |

ポイントとしては、デフォルトで早期停止が有効になっていているので、
学習曲線を見たい場合は早期停止を無効にし、エポック数を多めに取りましょう。
また、パラメータを追加する際、例えばエポック数を固定値で設定したい場合でも、ディストリビューションは「選択肢」を選びましょう。(「固定」を選択するとジョブ実行時エラーが発生しました。)
![画像31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/323cdf4e-1be2-a991-f6f8-08d7d3005126.png)


チューニングは下記の通り設定しました。

| パラメータ名 | 説明 | 値 |
|:-|:-|:-|
| サンプリング|パラメータのサンプリング方法 |  ランダム|
| イテレーション  | パラメータ探索の最大実行数 | 3 |
| 早期停止|早期停止方法| 中央値での停止   |
| コンカレントイテレーション|同時実行の最大数|3   |

イテレーションがDefaultの「1」になっていると、ハイパーパラメータの組み合わせのうち1パターンしか実行してくれませんので、注意しましょう。その他、早期停止ポリシー等の説明は[こちら](https://docs.microsoft.com/ja-jp/azure/machine-learning/how-to-tune-hyperparameters#what-is-hyperparameter-tuning)に記載されています。
![画像30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/60d87e01-cc0c-bd37-12da-4def263f6f45.png)

:::note info
パラメータの「early_stopping」とチューニング設定の「早期停止」の違いについて
パラメータの「early_stopping」は、学習ジョブ内のエポックに対する早期停止の有無です。
チューニング設定の「早期停止」は、学習ジョブ間のジョブに対する早期停止ポリシーです。
:::

「次へ」をクリックすると、最後に検証の種類を選択します。[検証の種類]を「ユーザ検証データ」に設定し、先ほど作成した検証用データセットを指定しましょう。[終了]をクリックするとジョブが実行されます。
![画像25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/5f152f22-0356-d673-b70b-a25310f3a26f.png)


## 学習結果の確認
左メニュー[ジョブ]をクリックすると「dogcat-auto-classification」が登録されていますね。クリックしましょう。
![画像33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/bf234643-415a-fea4-bdbf-f8a329cf3895.png)
こちらの画面では「dogcat-auto-classification」のジョブの一覧と各ジョブのベストプラクティスが確認できます。
先ほど実行した一番上のジョブ「gentle_jicama_bq4b8l3n」をクリックしましょう。
![画像34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/56c07a71-ef60-a220-66e1-e9ffaef82932.png)
こちらから親ジョブの概要を確認できます。
![画像36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/13d79558-0ffc-c882-55a8-1e530b1d555b.png)
子ジョブから各ハイパーパラメータの実行結果を確認することができます。
![画像35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/39c02ddb-507b-800b-3273-25eab0c01551.png)
子ジョブの「試用版」をクリックしましょう。
こちらの画面では各パラメータのaccuracyやlossを一覧で確認できます。
![画像57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/bee4bd8f-2fab-e79e-ff8c-2be80fea1922.png)

### 学習曲線
「log_loss」を選択すると、検証用データのロスを確認できます。
バッチサイズ32と64は収束していることが確認できます。バッチサイズ16は早期停止ポリシーが効いて、途中のエポックで終了しています。※子ジョブ名は変更しています。
![画像38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/bccfb457-e572-c0b5-5eda-2c5f382aec5f.png)
### 精度
「accuracy」を選択すると、検証用データの精度(正解数/全データ)を確認できます。
初期値が良かったのか最初のエポックでは精度が高いです。その後下がって学習が進むにつれ精度が安定的に向上していることを確認できます。バッチサイズ64の精度が最も良いですね。
![画像39.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/fbefa6b1-a4f6-f77e-4838-790e71f34014.png)

# モデルのデプロイ
それでは「batchsize_64」のモデルをマネージドエンドポイントにデプロイしましょう。
先ほどの子ジョブから「batchsize_64」をクリックし、[デプロイ]->[リアルタイムエンドポイントへのデプロイ]をクリックします。
![画像40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/1dfa4779-da00-98b0-dd09-92ab9ecececd.png)
 [エンドポイント名]を記入して、[次へ]をクリックします。
![画像41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/81b360f1-2bf2-e4da-c454-a3f95dafbd4f.png)
[次へ]をクリックします。
![画像42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/4fe6d325-4220-b6b6-ad4b-e088fe6c453c.png)
[次へ]をクリックします。
![画像43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/a77ed283-0b32-2f2a-aec1-ad4f0a602841.png)
[次へ]をクリックします。
![画像44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/382a719c-d520-2f7f-390f-aa3f70c4ce96.png)
今回[インスタンス数]は「1」にして、[次へ]をクリックします。
![画像45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/3e8debe1-6fbb-c43c-8b5a-ad746c8d6b73.png)
[次へ]をクリックします。
![画像46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/5c2e1aa4-8fa9-d339-cbb7-c349f7e3e932.png)
[作成]をクリックします。
![画像47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/3e9748af-5a93-b7f3-374c-518aaee417e2.png)
左メニュー[エンドポイント]から先ほど作成したエンドポイントが確認できます。
![画像48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/0cf75fb2-aa3d-0116-3b88-3c09955df042.png)
エンドポイントの新規作成時はDockerのイメージ作成等に時間が掛かり、10~15分程かかります。
作成が完了すると、プロビジョニングの状態が「成功」に変わります。
![画像49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/782ce0b5-84c8-e3e0-54af-8c9e2c1da553.png)
[使用]をクリックすると、エンドポイントの認証キーや使い方が確認できます。
今回はPythonでAPIで叩きたいので、コードをコピーします。
![画像51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/9a9200d2-7ff6-b1a9-df0b-2a55dad52333.png)

# モデルの推論
最後に作成した推論エンドポイントに画像を送って、結果を確かめましょう。

```python:infer.py
import urllib.request
import json
import os
import ssl

sample_image = './cat.3.jpg'

with open(sample_image, 'rb') as f:
    body = f.read()
    url = 'https://dogcat-classification-endpoint.japaneast.inference.ml.azure.com/score'
    api_key = 'XXXXXXXXXXXXXXXXXXXXXXXXXXX' # Replace this with the API key for the web service

    headers = {'Content-Type':'application/octet-stream', 'Authorization':('Bearer '+ api_key), 'azureml-model-deployment': 'default' }

    req = urllib.request.Request(url, body, headers)

    try:
        response = urllib.request.urlopen(req)
        result = response.read()
        print(result)
    except urllib.error.HTTPError as error:
        print("The request failed with status code: " + str(error.code))
        print(error.info())
        print(error.read().decode("utf8", 'ignore'))
```
cat.3.jpgの画像はこんな感じです。
![cat.3.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2681297/101d4956-d448-f32c-4235-21ebf57dfa5c.jpeg)

```cli:実行結果
b'{"filename": "/tmp/tmp_l6jwbuy/tmpe1_t5zb0", "probs": [0.7836150527000427, 0.2163849025964737], "labels": ["cat", "dog"]}\n'
```
各ラベルの確率が返ってきてきました！ちゃんと猫と認識されていますね。

# まとめ
今回はAzrreのAutoMLの画像分類を解説しましたが、いかがでしたでしょうか？
まずは、基本的なモデルで手軽に画像分類を試してみたい、という方にはピッタリのサービスだと思います。
慣れてきたらモデルやパラメータチューニングを変えてみて、性能がどのように変わるか試してみると良いかもしれませんね！