バッチ デプロイで MLflow モデルをデプロイする

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

この記事では、MLflow モデルを Azure Machine Learning にデプロイして、バッチ エンドポイントを使って両方のバッチ推論を行う方法について説明します。 MLflow モデルをバッチ エンドポイントにデプロイするとき、Azure Machine Learning は次の動作を行います。

  • Azure Machine Learning Batch ジョブを実行するために必要な依存関係を含む MLflow ベース イメージおよびキュレーション環境を提供します。
  • スコアリング スクリプトを使って、並列化を使ったデータの処理に使用できるバッチ ジョブ パイプラインを自動的に作成できます。

Note

サポートされている入力ファイルの種類と MLflow モデルの動作について詳しくは、「バッチ推論にデプロイするときの考慮事項」をご覧ください。

この例の概要

この例は、バッチ予測を実行するために、バッチ エンドポイントに MLflow モデルをデプロイする方法を示しています。 この例では、「UCI Heart Disease Data Set」(UCI 心臓病データ セット) に基づいた MLflow モデルを使います。 このデータベースには 76 個の属性が含まれていますが、そのうちの 14 個のサブセットを使用しています。 このモデルは、患者の心臓病の存在を予測しようと試みるものです。 これは 0 (存在しない) から 1 (存在する) の整数値です。

このモデルのトレーニングには XGBBoost 分類器が使われ、必要な前処理はすべて scikit-learn パイプラインとしてパッケージ化されているため、このモデルは生データから予測までを行うエンドツーエンドのパイプラインになっています。

この記事の例は、azureml-examples リポジトリに含まれているコード サンプルを基にしています。 YAML などのファイルをコピーして貼り付けることなくコマンドをローカルで実行するには、最初にリポジトリを複製してから、ディレクトリをそのフォルダーに変更します。

git clone https://github.com/Azure/azureml-examples --depth 1
cd azureml-examples/cli

この例のファイルは、次の場所にあります。

cd endpoints/batch/deploy-models/heart-classifier-mlflow

Jupyter ノートブックで経過をたどる

次のノートブックで、このサンプルの経過をたどることができます。 複製されたリポジトリで、ノートブック mlflow-for-batch-tabular.ipynb を開きます。

前提条件

この記事の手順に従う前に、次の前提条件が満たされていることをご確認ください。

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

  • Azure Machine Learning ワークスペース。 準備できていない場合は、Azure Machine Learning ワークスペースの管理に関する記事の手順を使用して作成します。

  • ワークスペースに次のアクセス許可があることを確認します。

    • バッチ エンドポイントとバッチ デプロイを作成または管理する: 所有者または共同作成者のロール、あるいは Microsoft.MachineLearningServices/workspaces/batchEndpoints/* を許可するカスタム ロールを使用します。

    • ワークスペース リソース グループに ARM デプロイを作成する: 所有者または共同作成者のロール、あるいはワークスペースがデプロイされているリソース グループで Microsoft.Resources/deployments/write を許可するカスタム ロールを使用します。

  • Azure Machine Learning を使用するには、次のソフトウェアをインストールする必要があります。

    Azure CLImlAzure Machine Learning 用の 拡張機能

    az extension add -n ml
    

    注意

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

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

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

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

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

手順

新しいデータに対してバッチ推論を実行するために、次の手順に従って MLflow モデルをバッチ エンドポイントにデプロイします。

  1. バッチ エンドポイントがデプロイできるのは登録済みのモデルのみです。 この場合、リポジトリにモデルのローカル コピーが既にあるので、ワークスペースのレジストリにモデルを発行するだけで済みます。 デプロイ対象のモデルが既に登録されている場合は、この手順をスキップできます。

    MODEL_NAME='heart-classifier-mlflow'
    az ml model create --name $MODEL_NAME --type "mlflow_model" --path "model"
    
  2. 先に進む前に、これから作成するバッチ デプロイが、何らかのインフラストラクチャ (コンピューティング) 上で実行できることを確認する必要があります。 バッチ デプロイは、ワークスペースに既に存在する Azure Machine Learning コンピューティング上で実行できます。 つまり、複数のバッチ デプロイが同じコンピューティング インフラストラクチャを共有できます。 この例では、cpu-cluster という Azure Machine Learning コンピューティング クラスター上で作業します。 ワークスペースにコンピューティングが存在することを確認し、存在しない場合は作成しましょう。

    次のようにコンピューティング クラスターを作成します。

    az ml compute create -n batch-cluster --type amlcompute --min-instances 0 --max-instances 5
    
  3. 次は、バッチ エンドポイントとデプロイを作成します。 まず、エンドポイントから始めましょう。 エンドポイントを作成するために必要なのは、名前と説明のみです。 このエンドポイントの名前は、エンドポイントに関連付けられている URI に記載されます。 そのため、バッチ エンドポイント名は Azure リージョン内で一意である必要があります。 たとえば、westus2 に存在できる mybatchendpoint という名前のバッチ エンドポイントは 1 つだけです。

    今回は、後で簡単に参照できるように、エンドポイント名を変数に配置しておきましょう。

    ENDPOINT_NAME="heart-classifier"
    
  4. エンドポイントを作成します。

    新しいエンドポイントを作成するには、次のような YAML 構成を作成します。

    endpoint.yml

    $schema: https://azuremlschemas.azureedge.net/latest/batchEndpoint.schema.json
    name: heart-classifier-batch
    description: A heart condition classifier for batch inference
    auth_mode: aad_token
    

    次に、次のコマンドでエンドポイントを作成します。

    az ml batch-endpoint create -n $ENDPOINT_NAME -f endpoint.yml
    
  5. 次はデプロイを作成しましょう。 MLflow モデルの場合、デプロイを作成するときに環境またはスコアリング スクリプトを指定する必要はありません。自動的に作成されます。 ただし、デプロイによる推論方法をカスタマイズする場合は、それらを指定できます。

    作成されたエンドポイントの下に新しいデプロイを作成するには、次のような YAML 構成を作成します。 追加のプロパティについては、完全なバッチ エンドポイント YAML スキーマを確認してください。

    deployment-simple/deployment.yml

    $schema: https://azuremlschemas.azureedge.net/latest/modelBatchDeployment.schema.json
    endpoint_name: heart-classifier-batch
    name: classifier-xgboost-mlflow
    description: A heart condition classifier based on XGBoost
    type: model
    model: azureml:heart-classifier-mlflow@latest
    compute: azureml:batch-cluster
    resources:
      instance_count: 2
    settings:
      max_concurrency_per_instance: 2
      mini_batch_size: 2
      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-simple/deployment.yml --endpoint-name $ENDPOINT_NAME --set-default
    

    重要

    モデルが 1 つのバッチで推論を実行するのにかかる時間に基づいて、デプロイでの timeout を構成します。 バッチ サイズが大きいほど、この値を長くする必要があります。 mini_batch_size は、サンプルの数ではなく、バッチ内のファイルの数を示すことに注意してください。 表形式データを処理するときは、各ファイルに複数の行が含まれている場合があり、バッチ エンドポイントが各ファイルを処理するのにかかる時間が長くなります。 その場合は、タイムアウト エラーにならないように高い値を使います。

  6. エンドポイント内で特定のデプロイを呼び出すこともできますが、通常はエンドポイント自体を呼び出し、使用するデプロイはエンドポイントで決定されるようにします。 このようなデプロイは、"既定" のデプロイと呼ばれます。 これにより、エンドポイントを呼び出すユーザーとのコントラクトを変更せずに、既定のデプロイを変更し、デプロイを提供するモデルを変更することができます。 既定のデプロイを更新するには、次の手順に従います。

    DEPLOYMENT_NAME="classifier-xgboost-mlflow"
    az ml batch-endpoint update --name $ENDPOINT_NAME --set defaults.deployment_name=$DEPLOYMENT_NAME
    
  7. この時点で、バッチ エンドポイントを使用する準備は完了です。

デプロイをテストする

このエンドポイントをテストするために、このリポジトリ内にあり、このモデルに使用できるラベルのないデータのサンプルを使用します。 バッチ エンドポイントは、クラウド内にあり、Azure Machine Learning ワークスペースからアクセスできるデータのみを処理できます。 この例では、これを Azure Machine Learning データ ストアにアップロードします。 具体的には、スコアリングのためにエンドポイントを呼び出すのに使用できるデータ資産を作成します。 ただし、バッチ エンドポイントは、さまざまな場所に配置されている可能性があるデータを受け入れることに注意してください。

  1. まず、データ資産を作成します。 このデータ資産は、バッチ エンドポイントを使って並列処理する複数の CSV ファイルを含む 1 つのフォルダーで構成されています。 データがデータ資産として既に登録されている場合、または別の入力の種類を使う場合、この手順はスキップできます。

    a. YAML にデータ資産定義を作成します。

    heart-dataset-unlabeled.yml

    $schema: https://azuremlschemas.azureedge.net/latest/data.schema.json
    name: heart-dataset-unlabeled
    description: An unlabeled dataset for heart classification.
    type: uri_folder
    path: data
    

    b. データ資産を作成します。

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

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

    注意

    ユーティリティ jq は、すべてのインストールでインストールされるとは限りません。 インストール手順はこのリンクで確認できます。

    ヒント

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

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

    az ml job show -n $JOB_NAME --web
    

出力の分析

デプロイ構成の指定に従い、出力予測が predictions.csv ファイル内に生成されます。 このジョブにより、このファイルが配置されている場所に score という出力が生成されます。 バッチ ジョブごとに 1 つのファイルのみが生成されます。

ファイルは次のような構造です。

  • モデルに送信されたデータ ポイントごとに 1 行があります。 表形式データの場合、ファイル (predictions.csv) には、処理された各ファイルに存在する行ごとに 1 行が含まれていることを意味します。 他のデータ型 (画像、オーディオ、テキストなど) の場合、処理されたファイルごとに 1 行あります。

  • このファイルには次の列が (順番どおりに) 含まれています。

    • row (省略可能): 入力データ ファイル内の対応する行インデックス。 これは、入力データが表形式の場合にのみ適用されます。 予測は入力ファイルの出現順と同じ順序で返されるため、対応する予測と一致する行番号に頼ることができます。
    • prediction: 入力データに関連付けられた予測。 この値は、モデルの predict(). 関数に指定された "そのまま" の形で返されます。
    • file_name: データの読み取り元のファイル名。 表形式データの場合、どの予測がどの入力データに属するかを把握するためにこのフィールドを使います。

ジョブ名を使って、その結果をダウンロードできます。

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

az ml job download --name $JOB_NAME --output-name score --download-path ./

ファイルがダウンロードされたら、お気に入りのツールを使って開くことができます。 次の例では、Pandas データフレームを使って予測を読み込みます。

import pandas as pd

score = pd.read_csv(
    "named-outputs/score/predictions.csv", names=["row", "prediction", "file"]
)

出力は次のようになります。

row prediction file
0 0 heart-unlabeled-0.csv
1 1 heart-unlabeled-0.csv
2 0 heart-unlabeled-0.csv
... ... ...
307 0 heart-unlabeled-3.csv

ヒント

この例では、入力データは CSV 形式の表形式データであり、4 種類の入力ファイル (heart-unlabeled-0.csv、heart-unlabeled-1.csv、heart-unlabeled-2.csv、heart-unlabeled-3.csv) があったことに注目してください。

バッチ推論にデプロイするときの考慮事項

Azure Machine Learning では、スコアリング スクリプトを示さなくても、バッチ エンドポイントに MLflow モデルをデプロイできます。 これは、大量のデータを一括して処理する必要があるモデルをデプロイするのに便利な方法です。 Azure Machine Learning は、MLflow モデル仕様の情報を使って推論プロセスを調整します。

worker での作業の分散

バッチ エンドポイントは、構造化データと非構造化データの両方について、ファイル レベルで作業を分散させます。 その結果、この機能では、URI ファイルURI フォルダーのみがサポートされます。 各 worker は一度に Mini batch size 個のファイルのバッチを処理します。 表形式データの場合、バッチ エンドポイントによって作業が分散されるとき、各ファイル内の行数は考慮されません。

警告

入れ子になったフォルダー構造は、推論中に探索されません。 フォルダーを使ってパーティション分割している場合は、事前に構造をフラット化してください。

バッチ デプロイにより、1 ファイルにつき 1 回、MLflow モデルの predict 関数が呼び出されます。 このため、複数の行を含む CSV ファイルの場合、基になるコンピューティングでメモリ不足が発生することがあり、モデルによる 1 つのファイルのスコア付けにかかる時間が長くなる可能性があります (特に、大規模言語モデルのようなコストがかかるモデルの場合)。 メモリ不足例外やログのタイムアウト エントリが複数発生する場合は、より少ない行数のファイルにデータを分割するか、モデルやスコアリングのスクリプト内で行レベルのバッチ処理を実装することを検討してください。

ファイルの種類のサポート

バッチ推論で環境とスコアリング スクリプトを使わずに MLflow モデルをデプロイする場合、次のデータ型がサポートされています。 異なるファイルの種類を処理する場合、またはバッチ エンドポイントの既定値とは異なる方法で推論を実行する場合は、「MLflow モデルとスコアリング スクリプトの使用」で説明されているように、スコアリング スクリプトを使ってデプロイをいつでも作成できます。

[ファイル拡張子] モデルの入力として返される値の型 シグネチャの要件
.csv.parquet.pqt pd.DataFrame ColSpec 指定しない場合、列の型指定は強制されません。
.png.jpg.jpeg.tiff.bmp.gif np.ndarray TensorSpec 入力はテンソルのシェイプと一致するように再シェイプされます (使用できる場合)。 使用できるシグネチャがない場合、型 np.uint8 のテンソルが推論されます。 その他のガイダンスについては、「画像を処理する MLflow モデルに関する考慮事項」を参照してください。

警告

入力データにサポートされていないファイルがあると、ジョブが失敗する可能性があることに注意してください。 次のようなエラー エントリが表示されます: "ERROR:azureml:Error processing input file: '/mnt/batch/tasks/.../a-given-file.avro'.File type 'avro' is not supported." (ERROR:azureml: 入力ファイルの処理エラー: '/mnt/batch/tasks/.../a-given-file.avro'。ファイルの種類 'avro' はサポートされていません。)

MLflow モデルに対するシグネチャの適用

入力のデータ型はバッチ デプロイ ジョブによって適用されますが、データの読み取りには、使用できる MLflow モデルのシグネチャが使われます。 つまり、データ入力はモデルのシグネチャに示された型に準拠する必要があります。 想定どおりにデータを解析できない場合、次のようなエラー メッセージが表示され、ジョブは失敗します: "ERROR:azureml:Error processing input file: '/mnt/batch/tasks/.../a-given-file.csv'. Exception: invalid literal for int() with base 10: 'value'" ("ERROR:azureml: 入力ファイルの処理エラー: '/mnt/batch/tasks/.../a-given-file.csv'。例外: ベース 10 の int() の無効なリテラル: 'value'")。

ヒント

MLflow モデルのシグネチャは省略可能ですが、データの互換性の問題を早期に検出する便利な方法として利用できるため、強くお勧めします。 シグネチャを使ってモデルのログを記録する方法の詳細については、「カスタムのシグネチャ、環境、またはサンプルを使ったモデルのログ記録」を参照してください。

MLflow モデルに関連付けられた MLmodel ファイルを開くことで、モデルのシグネチャを調べることができます。 シグネチャが MLflow でどのように機能するかの詳細については、MLflow のシグネチャに関する記事を参照してください。

フレーバーのサポート

バッチ デプロイは、フレーバーが pyfunc の MLflow モデルのデプロイのみをサポートします。 別のフレーバーをデプロイする必要がある場合は、「MLflow モデルとスコアリング スクリプトの使用」を参照してください。

スコアリング スクリプトを使用した MLflow モデル デプロイのカスタマイズ

デプロイ定義にスコアリング スクリプトを指定することなく、MLflow モデルをバッチ エンドポイントにデプロイできます。 ただし、推論の実行方法をカスタマイズするために、このファイル (通常は "バッチ ドライバー" と呼ばれます) を指定することもできます。

通常、次の場合にこのワークフローを選びます。

  • バッチ デプロイの MLflow デプロイでサポートされていないファイルの種類を処理する必要があります。
  • モデルの実行方法をカスタマイズする必要があります。たとえば、mlflow.<flavor>.load() を使って読み込むために特定のフレーバーを使います。
  • モデル自体で前処理または後処理が実行されない場合、スコアリング ルーチンで実行する必要があります。
  • モデルの出力を表形式データでうまく表現できません。 たとえば、画像を表すテンソルです。
  • メモリに制約があるため、モデルで各ファイルを一度に処理できず、複数のチャンクに分けて読み取る必要があります。

重要

MLflow のモデル デプロイに対してスコアリング スクリプトを示す場合は、デプロイが実行される環境も指定する必要があります。

手順

次の手順を使って、カスタムのスコアリング スクリプトを含む MLflow モデルをデプロイします。

  1. MLflow モデルが置かれているフォルダーを特定します。

    a. Azure Machine Learning ポータルに移動します。

    b. [モデル] セクションに移動します。

    c. デプロイ予定のモデルを選び、[成果物] タブをクリックします。

    d. 表示されたフォルダーをメモします。 モデルの登録時にこのフォルダーが示されました。

    モデル成果物が配置されているフォルダーを示すスクリーンショット。

  2. スコアリング スクリプトを作成します。 前に特定したフォルダー名 model がどのように init() 関数に含まれているか注意してください。

    deployment-custom/code/batch_driver.py

    # Copyright (c) Microsoft. All rights reserved.
    # Licensed under the MIT license.
    
    import os
    import glob
    import mlflow
    import pandas as pd
    import logging
    
    
    def init():
        global model
        global model_input_types
        global model_output_names
    
        # AZUREML_MODEL_DIR is an environment variable created during deployment
        # It is the path to the model folder
        # Please provide your model's folder name if there's one
        model_path = glob.glob(os.environ["AZUREML_MODEL_DIR"] + "/*/")[0]
    
        # Load the model, it's input types and output names
        model = mlflow.pyfunc.load(model_path)
        if model.metadata and model.metadata.signature:
            if model.metadata.signature.inputs:
                model_input_types = dict(
                    zip(
                        model.metadata.signature.inputs.input_names(),
                        model.metadata.signature.inputs.pandas_types(),
                    )
                )
            if model.metadata.signature.outputs:
                if model.metadata.signature.outputs.has_input_names():
                    model_output_names = model.metadata.signature.outputs.input_names()
                elif len(model.metadata.signature.outputs.input_names()) == 1:
                    model_output_names = ["prediction"]
        else:
            logging.warning(
                "Model doesn't contain a signature. Input data types won't be enforced."
            )
    
    
    def run(mini_batch):
        print(f"run method start: {__file__}, run({len(mini_batch)} files)")
    
        data = pd.concat(
            map(
                lambda fp: pd.read_csv(fp).assign(filename=os.path.basename(fp)), mini_batch
            )
        )
    
        if model_input_types:
            data = data.astype(model_input_types)
    
        # Predict over the input data, minus the column filename which is not part of the model.
        pred = model.predict(data.drop("filename", axis=1))
    
        if pred is not pd.DataFrame:
            if not model_output_names:
                model_output_names = ["pred_col" + str(i) for i in range(pred.shape[1])]
            pred = pd.DataFrame(pred, columns=model_output_names)
    
        return pd.concat([data, pred], axis=1)
    
  3. スコアリング スクリプトが実行される環境を作成しましょう。 モデルは MLflow であるため、conda 要件はモデル パッケージでも指定されます (MLflow モデルの詳細と、それに含まれるファイル については、「MLmodel 形式」を参照してください)。 次に、ファイルの conda 依存関係を使用して環境を構築します。 ただし、Batch デプロイに必要なパッケージazureml-coreも含める必要があります。

    ヒント

    モデルが既にモデル レジストリに登録されている場合は、Azure Machine Learning スタジオ> [モデル] > 一覧からモデルを選択 > [成果物] の順に操作して、モデルに関連付けられている conda.yml ファイルをダウンロードまたはコピーできます。 ナビゲーションでルート フォルダーを開き、 一覧表示されている conda.yml ファイルを選択します。 [ダウンロード] をクリックするか、コンテンツをコピーします。

    重要

    この例では、 /heart-classifier-mlflow/environment/conda.yamlで指定された conda 環境を使用します。 このファイルは、元の MLflow conda 依存関係ファイルを組み合わせ、パッケージ azureml-coreを追加することによって作成されました。 モデルから直接 conda.yml ファイルを使用することはできません

    環境定義は、匿名環境としてデプロイ定義自体に含まれます。 デプロイでは、次の行で確認できます。

    environment:
      name: batch-mlflow-xgboost
      image: mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04:latest
      conda_file: environment/conda.yaml
    
  4. デプロイを構成します。

    作成されたエンドポイントの下に新しいデプロイを作成するには、次のような YAML 構成を作成します。 追加のプロパティについては、完全なバッチ エンドポイント YAML スキーマを確認してください。

    deployment-custom/deployment.yml

    $schema: https://azuremlschemas.azureedge.net/latest/modelBatchDeployment.schema.json
    endpoint_name: heart-classifier-batch
    name: classifier-xgboost-custom
    description: A heart condition classifier based on XGBoost
    type: model
    model: azureml:heart-classifier-mlflow@latest
    environment:
      name: batch-mlflow-xgboost
      image: mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu20.04:latest
      conda_file: environment/conda.yaml
    code_configuration:
      code: code
      scoring_script: batch_driver.py
    compute: azureml:batch-cluster
    resources:
      instance_count: 2
    settings:
      max_concurrency_per_instance: 2
      mini_batch_size: 2
      output_action: append_row
      output_file_name: predictions.csv
      retry_settings:
        max_retries: 3
        timeout: 300
      error_threshold: -1
      logging_level: info
    
  5. 次はデプロイを作成しましょう。

    az ml batch-deployment create --file deployment-custom/deployment.yml --endpoint-name $ENDPOINT_NAME
    
  6. この時点で、バッチ エンドポイントを使用する準備は完了です。

リソースをクリーンアップする

次のコードを実行して、バッチ エンドポイントと基になるすべてのデプロイを削除します。 バッチ スコアリング ジョブは削除されません。

az ml batch-endpoint delete --name $ENDPOINT_NAME --yes

次の手順