Azure Machine Learningで手書き数字認識モデルをデプロイしてみた…かった。

# 本記事について

## 要約

この記事は、Azure Machine Learning Studioを使用して手書き数字認識モデル(MNISTデータセット)をトレーニングし、APIとしてデプロイしようとした個人的な学習体験を記録したものです。
著者は、この経験を通じて、Azure上での機械学習モデルのデプロイプロセスを学びながら、同時に実践的な開発経験の難しさを実感しています。


## 目的

- 私自身がAzure開発の学習を進めたかったから。
- Azure上の開発を個人で練習しようという記事が少なかったから。

私の職場では実際にAzureの活用がとても進んでいるのですが、私は開発サイドではありません。だとしても、Azureの使い方をなんとなくでも知っておくことは有利にはたらくと思っていますし、いずれはそうした開発も経験してみたいなと考えています。
同じような境遇の方のお役にも立てると嬉しいです。


# Azureについて

Azureの始めかた・全体的な概要の知識について、本記事では割愛します。というのも、様々な教科書がすでに存在しているからです。

### 強いて私から言えるとすれば…

- 12か月の無料期間と1か月200ドルがあるうちにいろいろ試しましょう！

ということです。
特に初学者ですと、「何か変なところで請求されるかわからないからやめておこう…」と手を引きたくなる場面も出てくると思います。最初のクレジットカード登録の場面とか…。

もはや私は「少しくらい請求されてもいいや！」くらいの精神で臨んでいました。
一般的に考えて、初学者が練習のために小さな開発をしたところで請求される金額なんてそんなたいしたことないでしょうと。
これで何十万ときたら笑いますが、怖くなったら「”サブスクリプション”を停止する。」と覚えておけばいいかなと思います。

### 資格：Azure Fundamental AZ900

私はAZ900の資格を取得してから色々と触ってみています。事前にインプットがあったおかげで、なんとなく用語や関係性などはわかります。
資格を取るのが先でもAzureを触ってみるのが先でもどちらでもいいと思いますが、そこまで難しくないので取得をおすすめします。
対策としては、Udemyの過去問がおすすめです。

# それでは手を動かしていきましょう


## 前提

### 私は今回ほぼ初めてAzureを触っています。
わからなかったこと・未だわかっていないことがたくさんあります。本記事で間違っている箇所がありましたら優しく教えていただけると泣いて喜びます。


### 今回の開発の目標
手書き数字認識モデル（MNISTデータセット）をトレーニングし、AzureでAPIとしてデプロイすること。

### 使う技術
- Azure Machine Learning Studio
- Python
- scikit-learn
- TensorFlow/Keras




## 必要なファイル

### 利用するMNIST

こちらを参考ください。
画像認識分野の機械学習を学ぼうとすると必ず出会うデータセットです。

https://atmarkit.itmedia.co.jp/ait/articles/2001/22/news012.html


scikit-learn／Keras／TensorFlow／PyTorchなどのライブラリには、基本機能としてMNISTをロードする機能があります。

### ymlファイル
Pythonの仮想環境や依存関係を管理するための設定ファイルです。
このファイルは主に Anaconda/Miniconda 環境で使用され、特定の環境を作成または再現するための指示を記述します。
Azure Machine Learningでも、environment.yml ファイルを使用して、モデルのデプロイやトレーニングで必要なPythonのパッケージや依存関係を指定します。

```ruby:environment.yml
name: tensorflow-env
dependencies:
  - python=3.8
  - pip
  - pip:
      - tensorflow
      - azureml-defaults
```
Azure MLでのデプロイでは、```azureml-defaults``` もインストールする必要があります。
これが含まれていないと、エラーが発生します。


### エントリースクリプト
Azure MLでモデルをデプロイする際に使う、モデルの推論（予測）を行うために必要なものが、エントリースクリプトです。
このスクリプトの主な役割は、デプロイされたモデルを利用してデータを受け取り、予測を返す処理を定義することです。
今回は```score.py```で定義しています。

```ruby:score.py
import json
import numpy as np
import tensorflow as tf
from tensorflow.keras.models import load_model

# モデルのロード
def init():
    global model
    model = load_model('~~~~~~.ipynb')  # モデルファイルを指定

# 推論の実行
def run(input_data):
    try:
        # 入力データの整形
        input_data = np.array(json.loads(input_data))  # 必要に応じて整形します
        
        # 推論
        prediction = model.predict(input_data)
        
        # 結果を返す
        return json.dumps({"prediction": prediction.tolist()})
    except Exception as e:
        return str(e)
```

### Azure AI | Machine Learning Studioのイメージ

フォルダのなかに以下4つが入っています。
他フォルダにあるとパスの指定などが必要なので、同じフォルダ内に入れておくことをおすすめします。適宜VSCodeも使用しています。

- environment.yml
- mnist.model.h5
- score.py
- untitled.ipynb
（雑なファイル名で失礼します)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3780099/ce87dc6e-002d-1f1d-fff5-693d8275439a.png)


## コード全文

```ruby:ライブラリとデータのインポート.py

# 必要なパッケージをインストール
!pip install tensorflow scikit-learn azureml-sdk
import tensorflow as tf
from tensorflow.keras import layers, models
from sklearn.model_selection import train_test_split
from tensorflow.keras.datasets import mnist

# MNISTデータセットをロード
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# データの前処理
x_train = x_train.reshape((x_train.shape[0], 28, 28, 1)).astype('float32') / 255
x_test = x_test.reshape((x_test.shape[0], 28, 28, 1)).astype('float32') / 255

# モデルの構築（畳み込みニューラルネットワーク）
model = models.Sequential([
    layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.MaxPooling2D((2, 2)),
    layers.Conv2D(64, (3, 3), activation='relu'),
    layers.Flatten(),
    layers.Dense(64, activation='relu'),
    layers.Dense(10, activation='softmax')  # 10クラスの分類
])

# モデルのコンパイル
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# モデルのトレーニング
model.fit(x_train, y_train, epochs=5, batch_size=64)

# モデルを保存
model.save('モデル名.h5') #モデル名を指定

# Azure ML ワークスペースに接続
from azureml.core import Workspace, Model
ws = Workspace.from_config()

# モデルのアップロード
model = Model.register(model_path='モデル名.h5', #モデルパスを指定
                       model_name='モデル名', #モデル名を指定
                       workspace=ws)

# 環境を作成（必要に応じてカスタム環境を作成する）
from azureml.core.webservice import AciWebservice
from azureml.core.model import InferenceConfig
from azureml.core.environment import Environment
from azureml.core.webservice import Webservice

env = Environment.from_conda_specification(name="tensorflow-env", file_path="environment.yml")

# 推論設定
inference_config = InferenceConfig(entry_script='score.py', environment=env)

# デプロイ設定
aci_config = AciWebservice.deploy_configuration(cpu_cores=1, memory_gb=1)

# モデルをデプロイ
service = Model.deploy(workspace=ws,
                       name='モデル名', #モデル名を指定
                       models=[model],
                       inference_config=inference_config,
                       deployment_config=aci_config)

service.wait_for_deployment(show_output=True)

# APIのテスト
import json
import requests

# エンドポイントのURL
scoring_uri = service.scoring_uri

# 入力データ（手書きの数字画像データ）
input_data = json.dumps([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

# ヘッダー
headers = {'Content-Type': 'application/json'}

# リクエスト
response = requests.post(scoring_uri, data=input_data, headers=headers)
print(response.json())

```

# 困ったこと・行き詰った箇所

### 結局、リソースが足りずできなかった泣
そうなんです。ここまでいろいろやっておきながら最終的には形にできませんでした。というのも、リソースが不足していたからです。リソースを追加し、最後までもっていきたかったのですが、その他にも「これが足りない」「これを増やして」といろいろ案内があり、これ以上請求されるリスクが増えるのは怖いと折れてしまいました…。



### 凡ミスエラーの修正
上記は完成品を記載していますが、かなりエラーとその修正にてこずりました。
一番は「”score.py”というエントリースクリプトをどう設定するか」という箇所です。
結局凡ミスでした。
みなさんもファイル名の指定やファイル名すべて修正したかなど、気を付けられてください。
一応上記のコードに実行上のエラーはないと思っています。


# 感想

これまで機械学習モデルを何度か組み立てたことはありますが、どれもGoogle ColabやKaggle上で個人的にひっそりと…あまりビジネスでの活用を意識して動いたことはありませんでした。

そのため、今回Azure上で機械学習モデルを実装してみたいと考えたのですが、やはり実務として会社のライセンスを使用した開発が一番練習になると思います、

個人だと手出しできる範囲や規模が小さなくなり、できることがどうしても限られます。
当たり前ですし、それは事前にわかっていたのですが、痛感させられました。

エンジニアに”実務経験”が求められるのがよくわかりますが、「実務経験を持った人しか入れない世界は人口が減っていく…」という仕組み・課題感をどうにか解決したいなと今回もまた思わされました。