バッチ モデル デプロイを使用した画像処理

適用対象:Azure CLI ml extension v2 (現行)Python SDK azure-ai-ml v2 (現行)

バッチ モデル デプロイは、表形式データの処理だけでなく、画像などのその他のファイルの種類に対しても使用できます。 これらのデプロイは、MLflow とカスタムの両モデルでサポートされています。 この記事では、ImageNet 分類に従って画像を分類するモデルをデプロイする方法を学習します。

前提条件

  • Azure サブスクリプション。 Azure サブスクリプションをお持ちでない場合は、開始する前に無料アカウントを作成してください。 無料版または有料版の Azure Machine Learning をお試しください。

  • Azure Machine Learning ワークスペース。 ワークスペースを作成するには、「Azure Machine Learning ワークスペースの管理」を参照してください。

  • Machine Learning ワークスペースでの以下のアクセス許可があることを確認してください。

    • バッチ エンドポイントとバッチ デプロイを作成または管理する: 所有者または共同作成者のロール、あるいは Microsoft.MachineLearningServices/workspaces/batchEndpoints/* を許可するカスタム役割を使用します。
    • ワークスペース リソース グループ内での Azure Resource Manager デプロイの作成: 所有者、共同作成者、またはワークスペースがデプロイされるリソース グループ での Microsoft.Resources/deployments/write を許可するカスタム ロールを使用します。
  • Machine Learning を使用するには、以下のソフトウェアをインストールします。

    次のコマンドを実行して、Azure CLIml という Azure Machine Learning 用の拡張機能をインストールします。

    az extension add -n ml
    

    バッチ エンドポイントのパイプライン コンポーネント デプロイは、Azure CLI 用拡張機能 ml のバージョン 2.7 で導入されました。 az extension update --name ml コマンドを使用して、最新バージョンを取得します。


ワークスペースに接続する

ワークスペースは、Machine Learning の最上位のリソースです。 これは Machine Learning を使用する際に作成するすべての成果物を操作するための一元的な場所を提供します。 このセクションでは、デプロイ タスクを実行するワークスペースに接続します。

次のコマンドで、サブスクリプション ID、ワークスペース、場所、リソース グループの値を入力します。

az account set --subscription <subscription>
az configure --defaults workspace=<workspace> group=<resource-group> location=<location>

このサンプルについて

この記事では、TensorFlow と RestNet アーキテクチャを使用して構築されたモデルを使用します。 詳細については、「深い残差ネットワークでの ID マッピング」を参照してください。 このモデルのサンプルをダウンロードできます。 このモデルには以下の制約があります。

  • サイズ 244x244 ((224, 224, 3) のテンソル) の画像で動作します。
  • 入力を範囲 [0,1] にスケーリングする必要があります。

この記事の情報は、azureml-examples リポジトリに含まれているコード サンプルを基にしています。 YAML や他のファイルをコピー/貼り付けすることなくコマンドをローカルで実行するには、リポジトリをクローンします。 Azure CLI を使用している場合は cli/endpoints/batch/deploy-models/imagenet-classifier に、Python 用の SDK を使用している場合は 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 を開きます。

バッチ デプロイを使用した画像の分類

この例では、ImageNet の分類に従って与えられた画像を分類できるディープ ラーニング モデルをデプロイする方法を学習します。

エンドポイントを作成する

以下のようにしてモデルをホストするエンドポイントを作成します。

  1. エンドポイントの名前を指定します。

    ENDPOINT_NAME="imagenet-classifier-batch"
    
  2. 以下のバッチ エンドポイントを定義する 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
    

モデルを登録する

モデル デプロイでデプロイできるのは登録済みのモデルだけです。 モデルを登録する必要があります。 デプロイ対象のモデルが既に登録されている場合は、この手順をスキップできます。

  1. モデルのコピーをダウンロードします。

    wget https://azuremlexampledata.blob.core.windows.net/data/imagenet/model.zip
    unzip model.zip -d .
    
  2. モデルを登録します。

    MODEL_NAME='imagenet-classifier'
    az ml model create --name $MODEL_NAME --path "model"
    

スコアリング スクリプトを作成する

バッチ デプロイによって指定された画像を読み取り、モデルのスコアを返すことができるスコアリング スクリプトを作成します。

  • init メソッドが tensorflowkeras モジュールを使用してモデルを読み込みます。
  • 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 ハードウェアを介したバッチ デプロイはそのようなケースの 1 つです。 このアプローチを利用するスコアリング スクリプトについては、「高スループット デプロイ」を参照してください。

Note

ファイルを生成する生成モデルをデプロイしたい場合は、「バッチ デプロイでの出力のカスタマイズ」でスコアリング スクリプトを作成する方法を学習してください。

配置を作成する

スコアリング スクリプトを作成したら、それ用のバッチ デプロイを作成します。 次の手順に従います。

  1. デプロイを作成できるコンピューティング クラスターが作成済みであることを確認します。 この例では、gpu-cluster という名前のコンピューティング クラスターを使用します。 必須ではありませんが、GPU を使用すると処理が高速になります。

  2. どの環境でデプロイを実行するかを指定します。 この例では、モデルは TensorFlow 上で実行されます。 Azure Machine Learning には、必要なソフトウェアがインストールされた環境が既に用意されているため、この環境を再利用できます。 conda.yml ファイルに依存関係をいくつか追加する必要があります。

    環境定義はデプロイ ファイルに含まれています。

    compute: azureml:gpu-cluster
    environment:
      name: tensorflow212-cuda11-gpu
      image: mcr.microsoft.com/azureml/curated/tensorflow-2.12-cuda11:latest
    
  3. 配置を作成します。

    作成されたエンドポイントの下に新しいデプロイを作成するには、次の例のような 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
    
  4. エンドポイント内の特定のデプロイを呼び出すこともできますが、通常はエンドポイント自体を呼び出し、どのデプロイを使用するかはエンドポイントに判断させます。 このようなデプロイは、"既定" のデプロイと呼ばれます。

    このアプローチでは、エンドポイントを呼び出すユーザーとのコントラクトを変更することなく、既定のデプロイを変更してデプロイを提供するモデルを変更することができます。 既定のデプロイを更新するには、次のコードを使用します。

    az ml batch-endpoint update --name $ENDPOINT_NAME --set defaults.deployment_name=$DEPLOYMENT_NAME
    

これでバッチ エンドポイントを使用する準備ができました。

展開をテスト

エンドポイントをテストするために、元の ImageNet データセットからの 1,000 個の画像のサンプルを使用します。 バッチ エンドポイントは、クラウド内にあり、Azure Machine Learning ワークスペースからアクセスできるデータのみを処理できます。 それを Azure Machine Learning データ ストアにアップロードします。 スコアリングのためにエンドポイントを呼び出すために使用できるデータ資産を作成します。

Note

バッチ エンドポイントが受け取るデータは、複数の種類の場所に配置できます。

  1. 関連するサンプル データをダウンロードします。

    wget https://azuremlexampledata.blob.core.windows.net/data/imagenet/imagenet-1000.zip
    unzip imagenet-1000.zip -d data
    

    Note

    wget がローカルにインストールされていない場合は、それをインストールするか、ブラウザーを使用して .zip ファイルを取得します。

  2. ダウンロードしたデータからデータ資産を作成します。

    1. 以下のように imagenet-sample-unlabeled.yml という名前の YAML ファイル内にデータ資産定義を作成します。

      $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
      
    2. データ資産を作成します。

      az ml data create -f imagenet-sample-unlabeled.yml
      
  3. データがアップロードされ使用できるようになったら、エンドポイントを呼び出します。

    JOB_NAME=$(az ml batch-endpoint invoke --name $ENDPOINT_NAME --input azureml:imagenet-sample-unlabeled@latest --query name -o tsv)
    

    Note

    ユーティリティ jq がインストールされていない場合は、「jq のダウンロード」を参照してください。


ヒント

呼び出し操作ではデプロイ名を指定していません。 これは、エンドポイントによってジョブが既定のデプロイに自動的にルーティングされるからです。 エンドポイントにはデプロイが 1 つしかないため、そのデプロイが既定値となります。 引数またはパラメーター deployment_name を指定することで、特定のデプロイをターゲットにできます。

  1. バッチ ジョブはコマンドがリターンするとすぐに開始されます。 完了するまでジョブの状態を監視できます。

    az ml job show -n $JOB_NAME --web
    
  2. デプロイが完了したら、予測をダウンロードします。

    予測をダウンロードするには、次のコマンドを使用します。

    az ml job download --name $JOB_NAME --output-name score --download-path ./
    
  3. 予測は以下の出力のようになります。 読者の便宜上、予測はラベルと結合されています。 この効果を実現する方法の詳細については、関連するノートブックを参照してください。

    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 操作を使用して何らかのデータの前処理を行います。 パイプライン全体は、使用中の同じデバイス (CPU/GPU) で実行されます。

警告

一部のモデルでは、メモリ消費量の観点から入力のサイズと非線形の関係があります。 メモリ不足の例外を回避するには、(この例で行ったように) 再度バッチ処理を行うか、バッチ デプロイによって作成されるバッチのサイズを小さくします。

  1. 次のスコアリング スクリプト 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"]
        )
    
    • このスクリプトは、バッチ デプロイによって送信されたミニ バッチからテンソル データセットを構築します。 このデータセットは、関数 mapdecode_img 操作を使用して、モデルの予想されるテンソルを取得するために前処理されます。
    • このデータセットは、データをモデルに送信するために再度 (16) バッチ処理されます。 このパラメーターを使用して、メモリに読み込み、一度にモデルに送信できる情報の量を制御します。 GPU で実行している場合は、OOM 例外がぎりぎり発生しない GPU の最大使用率を達成するようにこのパラメーターを慎重に調整する必要があります。
    • 予測が計算されると、テンソルは numpy.ndarray に変換されます。
  2. 配置を作成します。

    1. 作成されたエンドポイントの下に新しいデプロイを作成するには、次の例のような 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
    
    1. 次のコマンドを使用してデプロイを作成します。
    az ml batch-deployment create --file deployment-by-batch.yml --endpoint-name $ENDPOINT_NAME --set-default
    
  3. この新しいデプロイは、先ほど示したサンプル データと共に使用できます。 このデプロイを呼び出すには、呼び出しメソッド内でデプロイの名前を指定するか、これを既定のデプロイとして設定する必要があることに注意してください。

画像を処理する 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 モデルの使用」を参照してください。

次のステップ