バッチ モデル デプロイを使用した画像処理
適用対象:Azure CLI ml extension v2 (現行)Python SDK azure-ai-ml v2 (現行)
バッチ モデル デプロイは、表形式データの処理だけでなく、画像などのその他のファイルの種類にも使用できます。 これらのデプロイは、MLflow とカスタムの両モデルでサポートされています。 このチュートリアルでは、ImageNet 分類に従って画像を分類するモデルをデプロイする方法について説明します。
このサンプルについて
これから使用するモデルは、TensorFlow を RestNet アーキテクチャ (「ディープ残余ネットワークにおける ID マッピング」) と共に使用して作成されました。 このモデルのサンプルは、こちらからダウンロードできます。 このモデルには、デプロイに注意すべき次の制約があります。
- サイズ 244x244 (
(224, 224, 3)
のテンソル) の画像で動作します。 - 入力を範囲
[0,1]
にスケーリングする必要があります。
この記事の情報は、azureml-examples リポジトリに含まれているコード サンプルを基にしています。 YAML などのファイルをコピーまたは貼り付けすることなく、これらのコマンドをローカルで実行するには、リポジトリを複製した後、Azure CLI を使用している場合は cli/endpoints/batch/deploy-models/imagenet-classifier
に、SDK for Python を使用している場合は sdk/python/endpoints/batch/deploy-models/imagenet-classifier
にディレクトリを変更します。
git clone https://github.com/Azure/azureml-examples --depth 1
cd azureml-examples/cli/endpoints/batch/deploy-models/imagenet-classifier
Jupyter ノートブックで経過をたどる
Jupyter Notebook で、このサンプルに従って実行できます。 複製されたリポジトリで、ノートブック imagenet-classifier-batch.ipynb を開きます。
前提条件
この記事の手順に従う前に、次の前提条件が満たされていることをご確認ください。
Azure サブスクリプション。 Azure サブスクリプションをお持ちでない場合は、開始する前に無料アカウントを作成してください。 無料版または有料版の Azure Machine Learning をお試しください。
Azure Machine Learning ワークスペース。 準備できていない場合は、Microsoft Azure Machine Learning ワークスペースの管理に関する記事の手順を使用して作成します。
ワークスペースに次のアクセス許可があることを確認します。
バッチ エンドポイントとバッチ デプロイを作成または管理する: 所有者または共同作成者のロール、あるいは
Microsoft.MachineLearningServices/workspaces/batchEndpoints/*
を許可するカスタム役割を使用します。ワークスペース リソース グループに ARM デプロイを作成する: 所有者または共同作成者のロール、あるいはワークスペースがデプロイされているリソース グループで
Microsoft.Resources/deployments/write
を許可するカスタム役割を使用します。
Azure Machine Learning を使用するには、次のソフトウェアをインストールする必要があります。
ワークスペースに接続する
ワークスペースは、Azure Machine Learning の最上位のリソースで、Azure Machine Learning を使用するときに作成するすべての成果物を操作するための一元的な場所を提供します。 このセクションでは、デプロイ タスクを実行するワークスペースに接続します。
次のコードで、サブスクリプション ID、ワークスペース、場所、リソース グループの値を渡します。
az account set --subscription <subscription>
az configure --defaults workspace=<workspace> group=<resource-group> location=<location>
バッチ デプロイを使用した画像の分類
この例では、ImageNet の分類に従って特定の画像を分類できるディープ ラーニング モデルをデプロイする方法を説明します。
エンドポイントを作成する
まず、モデルをホストするエンドポイントを作成しましょう。
エンドポイントの名前を決めます。
ENDPOINT_NAME="imagenet-classifier-batch"
次の YAML ファイルは、バッチ エンドポイントを定義します。
endpoint.yml
$schema: https://azuremlschemas.azureedge.net/latest/batchEndpoint.schema.json
name: imagenet-classifier-batch
description: A batch endpoint for performing image classification using a TFHub model ImageNet model.
auth_mode: aad_token
次のコードを実行して、エンドポイントを作成します。
az ml batch-endpoint create --file endpoint.yml --name $ENDPOINT_NAME
モデルを登録する
モデル デプロイでデプロイできるのは登録済みのモデルのみのため、登録する必要があります。 デプロイ対象のモデルが既に登録されている場合は、この手順をスキップできます。
モデルのコピーをダウンロードします。
モデルを登録します。
スコアリング スクリプトを作成する
バッチ デプロイによって指定された画像を読み取り、モデルのスコアを返すことができるスコアリング スクリプトを作成する必要があります。 ここで使用するスクリプトの要件は次のとおりです。
keras
モジュールを使用してモデルtensorflow
に読み込むinit
関数を示す。- バッチデプロイによって提供されるミニバッチごとに実行される
run
関数を示す。 run
関数がファイルの画像を一度に 1 つずつ読み取る。run
メソッドがモデルの予想されるサイズに画像のサイズを変更します。run
メソッドが、モデルが期待する範囲[0,1]
のドメインに画像を再スケーリングする。- 予測に関連付けられているクラスと確率を返す。
code/score-by-file/batch_driver.py
import os
import numpy as np
import pandas as pd
import tensorflow as tf
from os.path import basename
from PIL import Image
from tensorflow.keras.models import load_model
def init():
global model
global input_width
global input_height
# AZUREML_MODEL_DIR is an environment variable created during deployment
model_path = os.path.join(os.environ["AZUREML_MODEL_DIR"], "model")
# load the model
model = load_model(model_path)
input_width = 244
input_height = 244
def run(mini_batch):
results = []
for image in mini_batch:
data = Image.open(image).resize(
(input_width, input_height)
) # Read and resize the image
data = np.array(data) / 255.0 # Normalize
data_batch = tf.expand_dims(
data, axis=0
) # create a batch of size (1, 244, 244, 3)
# perform inference
pred = model.predict(data_batch)
# Compute probabilities, classes and labels
pred_prob = tf.math.reduce_max(tf.math.softmax(pred, axis=-1)).numpy()
pred_class = tf.math.argmax(pred, axis=-1).numpy()
results.append([basename(image), pred_class[0], pred_prob])
return pd.DataFrame(results)
ヒント
画像はデプロイによってミニバッチで提供されますが、このスコアリング スクリプトは一度に 1 つの画像を処理します。 これは、バッチ全体を読み込んで一度にモデルに送信しようとすると、バッチ Executor (OOM の実行) にメモリ不足が発生する可能性があるため、一般的なパターンです。 ただし、スコアリング タスクで高いスループットを実現できる場合もあります。 これは、高い GPU 使用率を実現する GPU ハードウェアを介したバッチ デプロイの例です。 それを利用するスコアリング スクリプトの例については、「高スループットのデプロイ」を参照してください。
注意
生成モデル (ファイルを生成するモデル) をデプロイしようとしている場合は、複数のファイルを生成するモデルのデプロイに関するページで説明されているように、スコアリング スクリプトを作成する方法をご確認ください。
デプロイを作成する
スコアリング スクリプトが作成されたら、バッチ デプロイを作成します。 作成するには、次の手順を実施してください。
デプロイを作成できるコンピューティング クラスターが作成済みであることを確認します。 この例では、
gpu-cluster
という名前のコンピューティング クラスターを使用します。 必須ではありませんが、GPU を使用して処理を高速化します。デプロイを実行する環境を示す必要があります。 この例では、モデル
TensorFlow
で実行します。 Azure Machine Learning には、必要なソフトウェアがインストールされた環境が既に用意されているため、この環境を再利用できます。conda.yml
ファイルにいくつかの依存関係を追加するだけです。次はデプロイを作成します。
作成されたエンドポイントの下に新しいデプロイを作成するには、次のような
YAML
構成を作成します。 追加のプロパティについては、完全なバッチ エンドポイント YAML スキーマを確認してください。$schema: https://azuremlschemas.azureedge.net/latest/modelBatchDeployment.schema.json endpoint_name: imagenet-classifier-batch name: imagenet-classifier-resnetv2 description: A ResNetV2 model architecture for performing ImageNet classification in batch type: model model: azureml:imagenet-classifier@latest compute: azureml:gpu-cluster environment: name: tensorflow212-cuda11-gpu image: mcr.microsoft.com/azureml/curated/tensorflow-2.12-cuda11:latest conda_file: environment/conda.yaml code_configuration: code: code/score-by-file scoring_script: batch_driver.py resources: instance_count: 2 settings: max_concurrency_per_instance: 1 mini_batch_size: 5 output_action: append_row output_file_name: predictions.csv retry_settings: max_retries: 3 timeout: 300 error_threshold: -1 logging_level: info
次に、次のコマンドを使ってデプロイを作成します。
az ml batch-deployment create --file deployment-by-file.yml --endpoint-name $ENDPOINT_NAME --set-default
エンドポイント内で特定のデプロイを呼び出すこともできますが、通常はエンドポイント自体を呼び出し、エンドポイントで使用するデプロイは自動で決定されるようにします。 このようなデプロイは、"既定" のデプロイと呼ばれます。 これにより、エンドポイントを呼び出すユーザーとの契約を変更することなく、既定のデプロイを変更し、その結果、デプロイを提供するモデルを変更することができるようになります。 既定のデプロイを更新するには、次の手順に従います。
az ml batch-endpoint update --name $ENDPOINT_NAME --set defaults.deployment_name=$DEPLOYMENT_NAME
この時点で、バッチ エンドポイントを使用する準備は完了です。
デプロイをテストする
エンドポイントをテストするために、元の ImageNet データセットから 1000 個の画像サンプルを使用します。 バッチ エンドポイントは、クラウド内にあり、Azure Machine Learning ワークスペースからアクセスできるデータのみを処理できます。 この例では、Azure Machine Learning データ ストアにアップロードします。 具体的には、スコアリングのためにエンドポイントを呼び出すのに使用できるデータ資産を作成します。 ただし、バッチ エンドポイントは、さまざまな場所に配置されている可能性があるデータを受け入れることに注意してください。
関連するサンプル データをダウンロードします。
次に、ダウンロードしたデータからデータ資産を作成します。
YAML
にデータ資産定義を作成します。imagenet-sample-unlabeled.yml
$schema: https://azuremlschemas.azureedge.net/latest/data.schema.json name: imagenet-sample-unlabeled description: A sample of 1000 images from the original ImageNet dataset. Download content from https://azuremlexampledata.blob.core.windows.net/data/imagenet-1000.zip. type: uri_folder path: data
次にデータ資産を作成します。
az ml data create -f imagenet-sample-unlabeled.yml
データがアップロードされ、使用できるようになったので、エンドポイントを呼び出します。
JOB_NAME=$(az ml batch-endpoint invoke --name $ENDPOINT_NAME --input azureml:imagenet-sample-unlabeled@latest --query name -o tsv)
注意
ユーティリティ
jq
は、すべてのインストールでインストールされるとは限りません。 手順はこのリンクから確認できます。ヒント
呼び出し操作でデプロイ名を指定していないことに注意してください。 これは、エンドポイントによってジョブが既定のデプロイに自動的にルーティングされるからです。 このエンドポイントには 1 つのデプロイしかないので、その 1 つが既定値になります。 引数またはパラメーター
deployment_name
を指定することで、特定のデプロイをターゲットにできます。コマンドが戻ると、すぐにバッチ ジョブが開始されます。 ジョブの状態は、完了するまで監視できます。
デプロイが完了したら、予測をダウンロードできます。
出力は次のようになります。 閲覧者の利便性を高める目的で、予測がラベルと組み合わされていることに注意してください。 これを実現する方法の詳細については、関連するノートブックを参照してください。
import pandas as pd score = pd.read_csv("named-outputs/score/predictions.csv", header=None, names=['file', 'class', 'probabilities'], sep=' ') score['label'] = score['class'].apply(lambda pred: imagenet_labels[pred]) score
file class 確率 label n02088094_Afghan_hound.JPEG 161 0.994745 Afghan hound n02088238_basset 162 0.999397 basset n02088364_beagle.JPEG 165 0.366914 bluetick n02088466_bloodhound.JPEG 164 0.926464 bloodhound ... ... ... ...
高スループットのデプロイ
前述のように、先ほど作成したデプロイでは、バッチ デプロイでバッチが指定されている場合でも、一度に 1 つの画像が処理されます。 ほとんどの場合、これはモデルの実行方法を簡略化し、メモリ不足の問題を回避する最適な方法です。 ただし、特定の他のモデルでは、基になるハードウェアの使用率をできるだけ飽和させたい場合があります。 これは、たとえば GPU などがあります。
そのような場合は、データのバッチ全体に対して推論を実行することをお勧めします。 これは、画像のセット全体をメモリに読み込み、モデルに直接送信することを意味します。 次の例では、TensorFlow
を使用して画像のバッチを読み取り、それらを一度にスコアリングします。 また、TensorFlow
ops を使用してデータの前処理を行うため、使用されている同じデバイス (CPU/GPU) でパイプライン全体が実行されます。
警告
一部のモデルでは、メモリ消費量の観点から入力のサイズと非線形の関係があります。 (この例で行ったように) 再度バッチ処理を行うか、バッチ デプロイによって作成されたバッチのサイズを小さくして、メモリ不足の例外を回避します。
スコアリング スクリプトを作成します。
code/score-by-batch/batch_driver.py
import os import numpy as np import pandas as pd import tensorflow as tf from tensorflow.keras.models import load_model def init(): global model global input_width global input_height # AZUREML_MODEL_DIR is an environment variable created during deployment model_path = os.path.join(os.environ["AZUREML_MODEL_DIR"], "model") # load the model model = load_model(model_path) input_width = 244 input_height = 244 def decode_img(file_path): file = tf.io.read_file(file_path) img = tf.io.decode_jpeg(file, channels=3) img = tf.image.resize(img, [input_width, input_height]) return img / 255.0 def run(mini_batch): images_ds = tf.data.Dataset.from_tensor_slices(mini_batch) images_ds = images_ds.map(decode_img).batch(64) # perform inference pred = model.predict(images_ds) # Compute probabilities, classes and labels pred_prob = tf.math.reduce_max(tf.math.softmax(pred, axis=-1)).numpy() pred_class = tf.math.argmax(pred, axis=-1).numpy() return pd.DataFrame( [mini_batch, pred_prob, pred_class], columns=["file", "probability", "class"] )
ヒント
- このスクリプトは、バッチ デプロイによって送信されるミニバッチからテンソル データセットを構築していることに注意してください。 このデータセットは、関数
map
のdecode_img
操作を使用して、モデルの予想されるテンソルを取得するために前処理されます。 - データセットは再度バッチ処理され、データがモデルに送信されます。 このパラメーターを使用して、メモリに読み込み、一度にモデルに送信できる情報の量を制御します。 GPU で実行している場合は、OOM 例外が発生する直前に GPU の最大使用率に到達するように、このパラメーターを慎重に調整する必要があります。
- 予測が計算されると、テンソルは
numpy.ndarray
に変換されます。
- このスクリプトは、バッチ デプロイによって送信されるミニバッチからテンソル データセットを構築していることに注意してください。 このデータセットは、関数
次はデプロイを作成します。
作成されたエンドポイントの下に新しいデプロイを作成するには、次のような
YAML
構成を作成します。 追加のプロパティについては、完全なバッチ エンドポイント YAML スキーマを確認してください。$schema: https://azuremlschemas.azureedge.net/latest/modelBatchDeployment.schema.json endpoint_name: imagenet-classifier-batch name: imagenet-classifier-resnetv2 description: A ResNetV2 model architecture for performing ImageNet classification in batch type: model model: azureml:imagenet-classifier@latest compute: azureml:gpu-cluster environment: name: tensorflow212-cuda11-gpu image: mcr.microsoft.com/azureml/curated/tensorflow-2.12-cuda11:latest conda_file: environment/conda.yaml code_configuration: code: code/score-by-batch scoring_script: batch_driver.py resources: instance_count: 2 tags: device_acceleration: CUDA device_batching: 16 settings: max_concurrency_per_instance: 1 mini_batch_size: 5 output_action: append_row output_file_name: predictions.csv retry_settings: max_retries: 3 timeout: 300 error_threshold: -1 logging_level: info
次に、次のコマンドを使ってデプロイを作成します。
az ml batch-deployment create --file deployment-by-batch.yml --endpoint-name $ENDPOINT_NAME --set-default
この新しいデプロイは、先ほど示したサンプル データと共に使用できます。 このデプロイを呼び出すには、呼び出しメソッドでデプロイの名前を指定するか、既定のデプロイとして設定する必要があります。
画像を処理する MLflow モデルに関する考慮事項
Batch Endpoints の MLflow モデルでは、入力データとしての画像の読み取りがサポートされています。 MLflow デプロイではスコアリング スクリプトは必要ないため、使用する場合には次の点に注意してください。
- サポートされている画像ファイル:
.png
、.jpg
、.jpeg
、.tiff
、.bmp
、.gif
。 - MLflow モデルは、入力画像のサイズに一致する入力として
np.ndarray
を受け取ります。 各バッチで複数の画像サイズをサポートするために、バッチ Executor は画像ファイルごとに 1 回 MLflow モデルを呼び出します。 - MLflow モデルにはシグネチャを含めることを強くお勧めします。そうする場合、タイプは
TensorSpec
である必要があります。 入力はテンソルのシェイプと一致するように再シェイプされます (使用できる場合)。 使用できるシグネチャがない場合、型np.uint8
のテンソルが推論されます。 - シグネチャを含み、画像の可変サイズを処理することが予想されるモデルの場合は、それを保証できるシグネチャを含めます。 たとえば、次のシグネチャの例では、3 つのチャネル化された画像のバッチが許可されます。
import numpy as np
import mlflow
from mlflow.models.signature import ModelSignature
from mlflow.types.schema import Schema, TensorSpec
input_schema = Schema([
TensorSpec(np.dtype(np.uint8), (-1, -1, -1, 3)),
])
signature = ModelSignature(inputs=input_schema)
(...)
mlflow.<flavor>.log_model(..., signature=signature)
実際の例は、Jupyter Notebook imagenet-classifier-mlflow.ipynb にあります。 バッチ デプロイで MLflow モデルを使用する方法の詳細については、「バッチ デプロイでの MLflow モデルの使用」に関する記事を参照してください。