Azure Machine Learning 推論 HTTP サーバーを使用してスコアリング スクリプトをデバッグする

Azure Machine Learning 推論 HTTP サーバーは、スコアリング関数を HTTP エンドポイントとして公開し、Flask サーバー コードと依存関係を単一のパッケージにラップしている Python パッケージです。 サーバーは、Azure Machine Learning でモデルをデプロイするときに使われる推論用の事前構築済み Docker イメージに含まれています。 パッケージだけを使って、運用用のモデルをローカル環境にデプロイし、ローカル開発環境でスコアリング (エントリ) スクリプトを簡単に検証できます。 スコアリング スクリプトに問題がある場合、サーバーからエラーとそのエラーが発生した場所が返されます。

サーバーを使用して、継続的インテグレーションとデプロイのパイプラインで検証ゲートを作成することもできます。 たとえば、候補のスクリプトでサーバーを起動し、ローカル エンドポイントに対してテスト スイートを実行することができます。

この記事では、推論サーバーを使ってローカル環境でデバッグを行いたい開発者をサポートし、Windows 上のオンライン エンドポイントで推論サーバーを使う方法について説明します。

前提条件

ローカル デバッグ用に Azure Machine Learning 推論 HTTP サーバーを使うには、構成に次のコンポーネントが含まれる必要があります。

  • Python 3.8 以降
  • Anaconda

Azure Machine Learning 推論 HTTP サーバーは、Windows と Linux をベースとするオペレーティングシステム上で動作します。

オンライン エンドポイント用のローカル デバッグ オプションを調べる

クラウドにデプロイする前にエンドポイントをローカル環境でデバッグすると、コードと構成のエラーを早期に発見できます。 ローカル環境でのエンドポイントのデバッグには、次のようないくつかのオプションがあります。

この記事では、Windows 上の Azure Machine Learning 推論 HTTP サーバーを使う方法について説明します。

次の表では、最適なオプションを選ぶのに役立つシナリオの概要を示します。

シナリオ 推論 HTTP サーバー ローカル エンドポイント
Docker イメージをリビルドすることなく、ローカルの Python 環境を更新する はい いいえ
スコアリング スクリプトを更新する はい はい
デプロイ構成を更新する (デプロイ、環境、コード、モデル) いいえ はい
Microsoft Visual Studio Code (VS Code) デバッガーを統合する はい はい

推論 HTTP サーバーをローカル環境で実行すると、デプロイ コンテナーの構成を気にすることなく、スコアリング スクリプトのデバッグに集中できます。

azureml-inference-server-http パッケージをインストールする

azureml-inference-server-http パッケージをインストールするには、次のコマンドを実行します。

python -m pip install azureml-inference-server-http

Note

パッケージの競合を避けるため、推論 HTTP サーバーは仮想環境にインストールします。 pip install virtualenv コマンドを使って、構成用の仮想環境を有効にできます。

スコアリング スクリプトをローカルでデバッグする

スコアリング スクリプトをローカル環境でデバッグするには、サーバーの動作をテストするためのオプションがいくつかあります。

  • ダミー スコアリング スクリプトを試します。
  • Visual Studio Code を使い、azureml-inference-server-http パッケージでデバッグします。
  • サンプル リポジトリから実際のスコアリング スクリプト、モデル ファイル、環境ファイルを実行します。

ダミー スコアリング スクリプトを使用してサーバーの動作をテストする

  1. ファイルを保持するために server_quickstart という名前のディレクトリを作成します。

    mkdir server_quickstart
    cd server_quickstart
    
  2. パッケージの競合を避けるため、myenv のような仮想環境を作成してアクティブにします。

    python -m virtualenv myenv
    

    Note

    Linux では、source myenv/bin/activate コマンドを実行して仮想環境をアクティブにします。

    サーバーのテストが済んだら、deactivate コマンドを実行して Python 仮想環境を非アクティブ化できます。

  3. Pypi フィードから azureml-inference-server-http パッケージをインストールします。

    python -m pip install azureml-inference-server-http
    
  4. エントリ スクリプトを作成します。 次の例では、基本的なエントリ スクリプトを作成して、score.py という名前のファイルに保存します。

    echo -e "import time def init(): \n\t time.sleep(1) \n\n def run(input_data): \n\t return {"message":"Hello, World!"}" > score.py
    
  5. azmlinfsrv コマンドでサーバーを起動し、score.py ファイルをエントリ スクリプトとして設定します。

    azmlinfsrv --entry_script score.py
    

    Note

    サーバーは 0.0.0.0 でホストされます。つまり、ホスティング マシンのすべての IP アドレスをリッスンします。

  6. curl ユーティリティを使って、スコアリング要求をサーバーに送信します。

    curl -p 127.0.0.1:5001/score
    

    サーバーは、次の応答を送信します。

    {"message": "Hello, World!"}
    
  7. テストが済んだら、Ctrl + C キーを押してサーバーを終了します。

この後は、スコアリング スクリプト ファイル (score.py) を変更し、azmlinfsrv --entry_script score.py コマンドを使ってサーバーをもう一度実行して、変更をテストできます。

Visual Studio Code と統合する

azureml-inference-server-http パッケージによるデバッグのために VS Code と Python 拡張機能を使うには、起動モードとアタッチ モードを使用できます。

  • 起動モードでは、VS Code で launch.json ファイルを設定して、VS Code 内で Azure Machine Learning 推論 HTTP サーバーを起動します。

    1. VS Code を開始し、スクリプト (score.py) を含むフォルダーを開きます。

    2. VS Code のそのワークスペース用に、次の構成を launch.json ファイルに追加します。

      launch.json

      {
          "version": "0.2.0",
          "configurations": [
              {
                  "name": "Debug score.py",
                  "type": "python",
                  "request": "launch",
                  "module": "azureml_inference_server_http.amlserver",
                  "args": [
                      "--entry_script",
                      "score.py"
                  ]
              }
          ]
        }
      
    3. VS Code で、[実行]>[デバッグの開始] を選ぶか、キーボード ショートカット F5 を使って、デバッグ セッションを開始します。

  • アタッチ モードでは、コマンド ウィンドウで Azure Machine Learning 推論 HTTP サーバーを起動し、VS Code と Python 拡張機能を使ってプロセスにアタッチします。

    Note

    Linux の場合は、最初に sudo apt-get install -y gdb コマンドを実行して、gdb パッケージをインストールします。

    1. VS Code のそのワークスペース用に、次の構成を launch.json ファイルに追加します。

      launch.json

      {
          "version": "0.2.0",
          "configurations": [
              {
                  "name": "Python: Attach using Process Id",
                  "type": "python",
                  "request": "attach",
                  "processId": "${command:pickProcess}",
                  "justMyCode": true
              }
          ]
        }
      
    2. コマンド ウィンドウで、azmlinfsrv --entry_script score.py コマンドを使って推論 HTTP サーバーを開始します。

    3. VS Code でデバッグ セッションを開始します。

      1. [実行]>[デバッグの開始] を選ぶか、キーボード ショートカット F5 を使います。

      2. コマンド ウィンドウで、推論サーバーからのログを表示して、(gunicorn ではなく) azmlinfsrv コマンドのプロセス ID を見つけます。

        推論 HTTP サーバーからのログと、azmlinfsrv コマンドのプロセス ID が強調されている、コマンド ウィンドウを示すスクリーンショット。

      3. VS Code デバッガーで、azmlinfsrv コマンドのプロセス ID を入力します。

        VS Code のプロセス ピッカーが表示されない場合は、そのワークスペースの launch.json ファイルの processId フィールドにプロセス ID を手入力できます。

どちらのモードでも、ブレークポイントを設定して、スクリプトを 1 ステップずつデバッグできます。

エンド ツー エンドの例を使用する

次の手順では、Azure Machine Learning のサンプル リポジトリから サンプル ファイル (スコアリング スクリプト、モデル ファイル、環境)を使って、サーバーをローカル環境で実行します。 これらのサンプル ファイルの使用方法の他の例については、「オンライン エンドポイントを使用して機械学習モデルをデプロイおよびスコア付けする」をご覧ください。

  1. サンプル リポジトリをクローンします。

    git clone --depth 1 https://github.com/Azure/azureml-examples
    cd azureml-examples/cli/endpoints/online/model-1/
    
  2. Conda を使って仮想環境を作成してアクティブにします。

    この例では、azureml-inference-server-http パッケージが自動的にインストールされます。 このパッケージは、azureml-defaults パッケージの依存ライブラリとして、conda.yml ファイルに含まれています。

    # Create the environment from the YAML file
    conda env create --name model-env -f ./environment/conda.yml
    # Activate the new environment
    conda activate model-env
    
  3. スコアリング スクリプトを確認します。

    onlinescoring/score.py

    import os
    import logging
    import json
    import numpy
    import joblib
    
    
    def init():
        """
        This function is called when the container is initialized/started, typically after create/update of the deployment.
        You can write the logic here to perform init operations like caching the model in memory
        """
        global model
        # AZUREML_MODEL_DIR is an environment variable created during deployment.
        # It is the path to the model folder (./azureml-models/$MODEL_NAME/$VERSION)
        # Please provide your model's folder name if there is one
        model_path = os.path.join(
            os.getenv("AZUREML_MODEL_DIR"), "model/sklearn_regression_model.pkl"
        )
        # deserialize the model file back into a sklearn model
        model = joblib.load(model_path)
        logging.info("Init complete")
    
    
    def run(raw_data):
        """
        This function is called for every invocation of the endpoint to perform the actual scoring/prediction.
        In the example we extract the data from the json input and call the scikit-learn model's predict()
        method and return the result back
        """
        logging.info("model 1: request received")
        data = json.loads(raw_data)["data"]
        data = numpy.array(data)
        result = model.predict(data)
        logging.info("Request processed")
        return result.tolist()
    
  4. スコアリング スクリプトとモデル ファイルを指定して、推論 HTTP サーバーを実行します。

    model_dir パラメーターで指定されているモデル ディレクトリは、AZUREML_MODEL_DIR 変数を使って定義されており、スコアリング スクリプトで取得されます。

    このケースでは、スコアリング スクリプトでサブディレクトリが model/sklearn_regression_model.pkl と指定されているため、現在のディレクトリ ./ を指定します。

    azmlinfsrv --entry_script ./onlinescoring/score.py --model_dir ./
    

    サーバーが起動してスコアリング スクリプトを正常に呼び出すと、スタートアップ ログの例が開きます。 そうでない場合は、ログでエラー メッセージが示されます。

  5. サンプル データを使ってスコアリング スクリプトをテストします。

    別のコマンド ウィンドウを開き、コマンドを実行したのと同じ作業ディレクトリに移動します。

    curl ユーティリティを使って要求の例をサーバーに送信し、スコアリング結果を受け取ります。

    curl --request POST "127.0.0.1:5001/score" --header "Content-Type:application/json" --data @sample-request.json
    

    スコアリング スクリプトに問題がない場合、スクリプトはスコアリングの結果を返します。 問題が発生した場合は、スコアリング スクリプトを更新し、サーバーをもう一度起動して、更新したスクリプトをテストしてみることができます。

サーバーのルートを確認する

推論 HTTP サーバーは、既定では次のルートでポート 5001 をリッスンします。

Name ルート
liveness probe 127.0.0.1:5001/
スコア 127.0.0.1:5001/score
OpenAPI (Swagger) 127.0.0.1:5001/swagger.json

サーバーのパラメーターを確認する

推論 HTTP サーバーは、次のパラメーターを受け入れます。

パラメーター 必須 Default Description
entry_script True 該当なし スコアリング スクリプトへの相対または絶対パスを示します。
model_dir False 該当なし 推論に使われるモデルを保持するディレクトリへの相対または絶対パスを示します。
port False 5001 サーバーのサービス提供ポートを指定します。
worker_count False 1 同時要求を処理するワーカー スレッドの数を提供します。
appinsights_instrumentation_key False 該当なし ログが発行されるアプリケーション分析情報へのインストルメンテーション キーを提供します。
access_control_allow_origins False 該当なし 指定した発行元に対する CORS を有効にします。複数の発行元はコンマ (,) で区切ります (例: microsoft.com, bing.com)。

サーバー要求の処理を調べる

次の手順では、Azure Machine Learning 推論 HTTP サーバー (azmlinfsrv) が着信要求を処理する方法を見ていきます。

  1. Python CLI ラッパーは、サーバーのネットワーク スタックの周囲に置かれ、サーバーを起動するために使用されます。

  2. クライアントからサーバーに要求が送信されます。

  3. サーバーは、Web Server Gateway Interface (WSGI) サーバーを介して要求を送信します。これにより、要求が Flask ワーカー アプリケーションにディスパッチされます。

  4. Flask ワーカー アプリは要求を処理します。これには、エントリ スクリプトとすべての依存関係の読み込みが含まれます。

  5. エントリ スクリプトが要求を受け取ります。 エントリ スクリプトは、読み込まれたモデルに対して推論の呼び出しを行い、応答を返します。

推論 HTTP サーバーが着信要求を処理する方法を示す図。

サーバーのログを調べる

推論 HTTP サーバーのテストのログ データを取得するには、2 つの方法があります。

  • azureml-inference-server-http パッケージをローカル環境で実行して、ログ出力を表示します。
  • オンライン エンドポイントを使って、コンテナー ログを表示します。 推論サーバーのログには、Azure Machine Learning Inferencing HTTP server <バージョン> という 名前が付いています。

Note

バージョン 0.8.0 以降、ログ形式が変更されています。 ログで想定とは異なるスタイルが使われている場合は、azureml-inference-server-http パッケージを最新バージョンに更新します。

スタートアップ ログを表示する

サーバーが起動したときのログでは、サーバーの初期設定が次のように示されます。

Azure Machine Learning Inferencing HTTP server <version>

Server Settings
---------------
Entry Script Name: <entry_script>
Model Directory: <model_dir>
Worker Count: <worker_count>
Worker Timeout (seconds): None
Server Port: <port>
Application Insights Enabled: false
Application Insights Key: <appinsights_instrumentation_key>
Inferencing HTTP server version: azmlinfsrv/<version>
CORS for the specified origins: <access_control_allow_origins>

Server Routes
---------------
Liveness Probe: GET   127.0.0.1:<port>/
Score:          POST  127.0.0.1:<port>/score

<logs>

たとえば、エンド ツー エンドの例に従ってサーバーを起動すると、ログは次のように表示されます。

Azure Machine Learning Inferencing HTTP server v0.8.0

Server Settings
---------------
Entry Script Name: /home/user-name/azureml-examples/cli/endpoints/online/model-1/onlinescoring/score.py
Model Directory: ./
Worker Count: 1
Worker Timeout (seconds): None
Server Port: 5001
Application Insights Enabled: false
Application Insights Key: None
Inferencing HTTP server version: azmlinfsrv/0.8.0
CORS for the specified origins: None

Server Routes
---------------
Liveness Probe: GET   127.0.0.1:5001/
Score:          POST  127.0.0.1:5001/score

2022-12-24 07:37:53,318 I [32726] gunicorn.error - Starting gunicorn 20.1.0
2022-12-24 07:37:53,319 I [32726] gunicorn.error - Listening at: http://0.0.0.0:5001 (32726)
2022-12-24 07:37:53,319 I [32726] gunicorn.error - Using worker: sync
2022-12-24 07:37:53,322 I [32756] gunicorn.error - Booting worker with pid: 32756
Initializing logger
2022-12-24 07:37:53,779 I [32756] azmlinfsrv - Starting up app insights client
2022-12-24 07:37:54,518 I [32756] azmlinfsrv.user_script - Found user script at /home/user-name/azureml-examples/cli/endpoints/online/model-1/onlinescoring/score.py
2022-12-24 07:37:54,518 I [32756] azmlinfsrv.user_script - run() is not decorated. Server will invoke it with the input in JSON string.
2022-12-24 07:37:54,518 I [32756] azmlinfsrv.user_script - Invoking user's init function
2022-12-24 07:37:55,974 I [32756] azmlinfsrv.user_script - Users's init has completed successfully
2022-12-24 07:37:55,976 I [32756] azmlinfsrv.swagger - Swaggers are prepared for the following versions: [2, 3, 3.1].
2022-12-24 07:37:55,977 I [32756] azmlinfsrv - AML_FLASK_ONE_COMPATIBILITY is set, but patching is not necessary.

ログのデータ形式を理解する

起動ツールのスクリプトを除き、推論 HTTP サーバーからのすべてのログでは、データが次の形式で示されます。

<UTC Time> | <level> [<pid>] <logger name> - <message>

エントリは、次のコンポーネントで構成されます。

  • <UTC Time>: エントリがログに入力された日時。
  • <pid>: エントリに関連付けられているプロセスの ID。
  • <level>: エントリのログ レベルの最初の文字。ERROR の E、INFO の I など。
  • <logger name>: ログ エントリに関連付けられているリソースの名前。
  • <message>: ログ メッセージの内容。

Python には 6 つのログ レベルがあり、重大度に応じて値が割り当てられています。

ログ記録レベル 数値
CRITICAL 50
ERROR 40
WARNING 30
INFO 20
DEBUG 10
NOTSET 0

サーバーの問題のトラブルシューティング

以下のセクションでは、Azure Machine Learning 推論 HTTP サーバーの基本的なトラブルシューティングのヒントについて説明します。 オンライン エンドポイントのトラブルシューティングについては、オンライン エンドポイントのデプロイのトラブルシューティングに関する記事をご覧ください。

インストールしたパッケージを確認する

インストールされているパッケージに関する問題に対処するには、次の手順に従います。

  1. Python 環境にインストールされているパッケージとバージョンに関する情報を収集します。

  2. 環境ファイル内で指定されている azureml-inference-server-http Python パッケージのバージョンが、起動ログに表示される Azure Machine Learning 推論 HTTP サーバーのバージョンと一致していることを確認します。

    • 場合によっては、pip 依存関係リゾルバーによって予期しないパッケージ バージョンがインストールされます。

    • インストールされているパッケージとバージョンを修正するには、pip を実行する必要がある場合があります。

  3. ご利用の環境で Flask またはその依存関係を指定している場合は、それらの項目を削除します。

    • 依存パッケージには、flaskjinja2itsdangerouswerkzeugmarkupsafeclick が含まれます。

    • flask は、サーバー パッケージの依存関係として一覧表示されます。 最適な方法は、推論サーバーが flask パッケージをインストールできるようにすることです。

    • 推論サーバーが新しいバージョンの Flask をサポートするように構成されている場合、このサーバーが利用可能になると、パッケージの更新プログラムを自動的に受け取ります。

サーバーのバージョンを確認する

サーバー パッケージ azureml-inference-server-http は PyPI に公開されています。 変更ログとすべての旧バージョンは、PyPI ページに列挙されています。

以前のバージョンのパッケージを使用する場合は、構成を最新のバージョンに更新することをお勧めします。

次の表は、安定したバージョン、よくある問題、推奨される調整をまとめたものです。

パッケージのバージョン 説明 問題 解決策
0.4.x 日付が 20220601 以前および azureml-defaults パッケージ バージョン .1.34 から 1.43 のトレーニング イメージにバンドルされています。 最新の安定バージョンは 0.4.13 です。 0.4.11 より前のバージョンのサーバーでは、Flask の依存関係の問題 (jinja2 から名前マークアップをインポートできないなど) が発生する可能性があります。 可能であれば、バージョン 0.4.13 または 0.8.x (最新バージョン) にアップグレードします。
0.6.x 20220516 以前の日付の推論イメージにプレインストールされています。 最新の安定バージョンは 0.6.1 です。 該当なし 該当なし
0.7.x Flask 2 をサポートします。 最新の安定バージョンは 0.7.7 です。 該当なし 該当なし
0.8.x ログの形式が変更されました。 Python 3.6 のサポートが終了しました。 該当なし 該当なし

パッケージの依存関係を確認する

サーバー azureml-inference-server-http に最も関連のある依存パッケージには、次のパッケージが含まれます。

  • flask
  • opencensus-ext-azure
  • inference-schema

Python 環境で azureml-defaults パッケージを指定した場合、azureml-inference-server-http パッケージは依存パッケージです。 依存関係は自動的にインストールされます。

ヒント

Python SDK v1 を使用していて、Python 環境で azureml-defaults を明示的には指定していない場合、SDK によりパッケージが自動的に追加される場合があります。 ただし、パッケージのバージョンは、SDK バージョンに関連してロックされます。 たとえば、SDK のバージョンが 1.38.0 の場合、azureml-defaults==1.38.0 エントリは、この環境の pip 要件に追加されます。

よく寄せられる質問

以降のセクションでは、Azure Machine Learning 推論 HTTP サーバーについてよく寄せられる質問の解決策について説明します。

サーバーの起動時に TypeError が発生する

次のように、サーバーの起動時に TypeError が発生する可能性があります。

TypeError: register() takes 3 positional arguments but 4 were given

  File "/var/azureml-server/aml_blueprint.py", line 251, in register

    super(AMLBlueprint, self).register(app, options, first_registration)

TypeError: register() takes 3 positional arguments but 4 were given

このエラーは、Python 環境に Flask 2 がインストールされているが、azureml-inference-server-http パッケージ バージョンが Flask 2 をサポートしていない場合に発生します。 Flask 2 のサポートは、azureml-inference-server-http パッケージ バージョン 0.7.0 以降、および azureml-defaults パッケージ バージョン 1.44 以降で利用できます。

  • Azure Machine Learning Docker イメージで Flask 2 パッケージを使用しない場合は、最新バージョンの azureml-inference-server-http または azureml-defaults パッケージを使用します

  • Azure Machine Learning Docker イメージで Flask 2 パッケージを使用する場合は、イメージのビルド バージョンが 2022 年 7 月以降であることを確認します。

    イメージのバージョンは、コンテナー ログで確認できます。

    2022-08-22T17:05:02,147738763+00:00 | gunicorn/run | AzureML Container Runtime Information
    2022-08-22T17:05:02,161963207+00:00 | gunicorn/run | ###############################################
    2022-08-22T17:05:02,168970479+00:00 | gunicorn/run | 
    2022-08-22T17:05:02,174364834+00:00 | gunicorn/run | 
    2022-08-22T17:05:02,187280665+00:00 | gunicorn/run | AzureML image information: openmpi4.1.0-ubuntu20.04, Materialization Build:20220708.v2
    2022-08-22T17:05:02,188930082+00:00 | gunicorn/run | 
    2022-08-22T17:05:02,190557998+00:00 | gunicorn/run | 
    
    • イメージのビルド日は、Materialization Build 表記の後に表示されます。 この例では、イメージ バージョンは 20220708 または 2022 年 7 月 8 日です。 この例では、イメージは Flask 2 と互換性があります。

    • 類似のメッセージがコンテナー ログ内にない場合、そのイメージは古く、更新する必要があります。 コンピューティング統合デバイス アーキテクチャ (CUDA) イメージを使用していて、新しいイメージが見つからない場合は、AzureML-Containers でイメージが非推奨かどうかを確認します。 非推奨のイメージに対し、指定された代替バージョンを見つけることができます。

  • サーバーとオンライン エンドポイントを併用している場合は、Azure Machine Learning スタジオのオンライン エンドポイント ページの [デプロイ ログ] の下にもログを見つけることができます。

    • SDK v1 を使用してデプロイし、デプロイ構成でイメージを明示的には指定しない場合、サーバーはローカル SDK ツールセットに一致するバージョンの openmpi4.1.0-ubuntu20.04 パッケージを適用します。 ただし、インストールされるバージョンは、そのイメージの使用可能な最新バージョンではない可能性があります。 SDK バージョン 1.43 の場合、サーバーは既定で openmpi4.1.0-ubuntu20.04:20220616 パッケージ バージョンをインストールしますが、このパッケージ バージョンは SDK 1.43 と互換性がありません。 デプロイに最新の SDK を使用していることを確認します。
  • イメージを更新できない場合は、環境ファイルに azureml-defaults==1.43 エントリまたは azureml-inference-server-http~=0.4.13 エントリをピン留めすることで、一時的に問題を回避できます。 これらのエントリは、flask 1.0.x を使用して古いバージョンをインストールするようにサーバーに指示します。

サーバーの起動時に ImportError または ModuleNotFoundError が発生する

opencensusjinja2markupsafeclick など、サーバーの起動時に特定のモジュールで ImportError または ModuleNotFoundError が発生することがあります。 エラー メッセージの例を次に示します。

ImportError: cannot import name 'Markup' from 'jinja2'

インポートとモジュールのエラーは、Flask の依存関係を互換性のあるバージョンにピン留めしない古いバージョンのサーバー (バージョン 0.4.10 以前) を使用すると発生します。

この問題を回避するには、それ以降のバージョンのサーバーをインストールします。