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 をベースとするオペレーティングシステム上で動作します。
オンライン エンドポイント用のローカル デバッグ オプションを調べる
クラウドにデプロイする前にエンドポイントをローカル環境でデバッグすると、コードと構成のエラーを早期に発見できます。 ローカル環境でのエンドポイントのデバッグには、次のようないくつかのオプションがあります。
- Azure Machine Learning 推論 HTTP サーバー
- ローカル エンドポイント
この記事では、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 パッケージでデバッグします。
- サンプル リポジトリから実際のスコアリング スクリプト、モデル ファイル、環境ファイルを実行します。
ダミー スコアリング スクリプトを使用してサーバーの動作をテストする
ファイルを保持するために server_quickstart という名前のディレクトリを作成します。
mkdir server_quickstart cd server_quickstart
パッケージの競合を避けるため、myenv のような仮想環境を作成してアクティブにします。
python -m virtualenv myenv
Note
Linux では、
source myenv/bin/activate
コマンドを実行して仮想環境をアクティブにします。サーバーのテストが済んだら、
deactivate
コマンドを実行して Python 仮想環境を非アクティブ化できます。Pypi フィードから
azureml-inference-server-http
パッケージをインストールします。python -m pip install azureml-inference-server-http
エントリ スクリプトを作成します。 次の例では、基本的なエントリ スクリプトを作成して、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
azmlinfsrv
コマンドでサーバーを起動し、score.py ファイルをエントリ スクリプトとして設定します。azmlinfsrv --entry_script score.py
Note
サーバーは 0.0.0.0 でホストされます。つまり、ホスティング マシンのすべての IP アドレスをリッスンします。
curl
ユーティリティを使って、スコアリング要求をサーバーに送信します。curl -p 127.0.0.1:5001/score
サーバーは、次の応答を送信します。
{"message": "Hello, World!"}
テストが済んだら、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 サーバーを起動します。
VS Code を開始し、スクリプト (score.py) を含むフォルダーを開きます。
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" ] } ] }
VS Code で、[実行]>[デバッグの開始] を選ぶか、キーボード ショートカット F5 を使って、デバッグ セッションを開始します。
アタッチ モードでは、コマンド ウィンドウで Azure Machine Learning 推論 HTTP サーバーを起動し、VS Code と Python 拡張機能を使ってプロセスにアタッチします。
Note
Linux の場合は、最初に
sudo apt-get install -y gdb
コマンドを実行して、gdb
パッケージをインストールします。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 } ] }
コマンド ウィンドウで、
azmlinfsrv --entry_script score.py
コマンドを使って推論 HTTP サーバーを開始します。VS Code でデバッグ セッションを開始します。
[実行]>[デバッグの開始] を選ぶか、キーボード ショートカット F5 を使います。
コマンド ウィンドウで、推論サーバーからのログを表示して、(
gunicorn
ではなく)azmlinfsrv
コマンドのプロセス ID を見つけます。VS Code デバッガーで、
azmlinfsrv
コマンドのプロセス ID を入力します。VS Code のプロセス ピッカーが表示されない場合は、そのワークスペースの launch.json ファイルの
processId
フィールドにプロセス ID を手入力できます。
どちらのモードでも、ブレークポイントを設定して、スクリプトを 1 ステップずつデバッグできます。
エンド ツー エンドの例を使用する
次の手順では、Azure Machine Learning のサンプル リポジトリから サンプル ファイル (スコアリング スクリプト、モデル ファイル、環境)を使って、サーバーをローカル環境で実行します。 これらのサンプル ファイルの使用方法の他の例については、「オンライン エンドポイントを使用して機械学習モデルをデプロイおよびスコア付けする」をご覧ください。
サンプル リポジトリをクローンします。
git clone --depth 1 https://github.com/Azure/azureml-examples cd azureml-examples/cli/endpoints/online/model-1/
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
スコアリング スクリプトを確認します。
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()
スコアリング スクリプトとモデル ファイルを指定して、推論 HTTP サーバーを実行します。
model_dir
パラメーターで指定されているモデル ディレクトリは、AZUREML_MODEL_DIR
変数を使って定義されており、スコアリング スクリプトで取得されます。このケースでは、スコアリング スクリプトでサブディレクトリが model/sklearn_regression_model.pkl と指定されているため、現在のディレクトリ ./ を指定します。
azmlinfsrv --entry_script ./onlinescoring/score.py --model_dir ./
サーバーが起動してスコアリング スクリプトを正常に呼び出すと、スタートアップ ログの例が開きます。 そうでない場合は、ログでエラー メッセージが示されます。
サンプル データを使ってスコアリング スクリプトをテストします。
別のコマンド ウィンドウを開き、コマンドを実行したのと同じ作業ディレクトリに移動します。
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
) が着信要求を処理する方法を見ていきます。
Python CLI ラッパーは、サーバーのネットワーク スタックの周囲に置かれ、サーバーを起動するために使用されます。
クライアントからサーバーに要求が送信されます。
サーバーは、Web Server Gateway Interface (WSGI) サーバーを介して要求を送信します。これにより、要求が Flask ワーカー アプリケーションにディスパッチされます。
Flask ワーカー アプリは要求を処理します。これには、エントリ スクリプトとすべての依存関係の読み込みが含まれます。
エントリ スクリプトが要求を受け取ります。 エントリ スクリプトは、読み込まれたモデルに対して推論の呼び出しを行い、応答を返します。
サーバーのログを調べる
推論 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 サーバーの基本的なトラブルシューティングのヒントについて説明します。 オンライン エンドポイントのトラブルシューティングについては、オンライン エンドポイントのデプロイのトラブルシューティングに関する記事をご覧ください。
インストールしたパッケージを確認する
インストールされているパッケージに関する問題に対処するには、以下の手順に従います。
Python 環境にインストールされているパッケージとバージョンに関する情報を収集します。
環境ファイル内で指定されている
azureml-inference-server-http
Python パッケージのバージョンが、スタートアップ ログに表示される Azure Machine Learning 推論 HTTP サーバーのバージョンと一致していることを確認します。場合によっては、pip 依存関係リゾルバーによって予期しないパッケージ バージョンがインストールされます。 インストールされているパッケージとバージョンを修正するには、
pip
を実行する必要がある場合があります。ご利用の環境で Flask またはその依存関係を指定している場合は、それらの項目を削除します。
- 依存パッケージには、
flask
、jinja2
、itsdangerous
、werkzeug
、markupsafe
、click
が含まれます。 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 より前のサーバー バージョンでは、"can't import name Markup from jinja2" などの Flask の依存関係の問題が発生する場合があります。 |
可能であれば、バージョン 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 要件に追加されます。
サーバーのスタートアップ時に 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 が発生する
サーバーの起動時に、opencensus
、jinja2
、markupsafe
、click
など、特定のモジュールで ImportError
または ModuleNotFoundError
が発生する場合があります。 次の例は、エラー メッセージを示しています。
ImportError: cannot import name 'Markup' from 'jinja2'
インポートとモジュールのエラーは、Flask の依存関係を互換性のあるバージョンに固定しない 0.4.10 以前のバージョンのサーバーを使用すると発生します。 この問題を回避するには、それ以降のバージョンのサーバーをインストールします。