Azure 机器学习推理 HTTP 服务器是一个 Python 包,它以 HTTP 终结点的形式公开评分函数,并将 Flask 服务器代码和依赖项包装到单一包中。 该服务器包含在用于推理的预生成 Docker 映像中,通过 Azure 机器学习部署模型时,会使用这些映像。 单独使用包,可以在本地部署模型以供生产,并在本地开发环境中轻松验证评分(入口)脚本。 如果评分脚本有问题,服务器将返回错误和出错位置。
该服务器还可以用于在持续集成和部署管道中创建验证入口。 例如,可以使用候选脚本启动服务器,并针对本地终结点运行测试套件。
本文帮助开发人员使用推理服务器进行本地调试,并介绍如何在 Windows 上将推理服务器与联机终结点配合使用。
先决条件
若要使用 Azure 机器学习推理 HTTP 服务器进行本地调试,配置中必须包含以下组件:
- Python 3.8 或更高版本
- Anaconda
Azure 机器学习推理服务器在基于 Windows 和 Linux 的操作系统上运行。
了解联机终结点的本地调试选项
在部署到云之前在本地调试终结点,可以提前发现代码和配置中的错误。 若要在本地调试终结点,可以使用多个选项,包括:
- Azure 机器学习推理 HTTP 服务器
- 本地终结点
本文介绍如何在 Windows 上使用 Azure 机器学习推理 HTTP 服务器。
下表概述了各种方案,以帮助你选择最佳选项:
场景 | 推理 HTTP 服务器 | 本地终结点 |
---|---|---|
更新本地 Python 环境,而无需重新生成 Docker 映像 | 是 | 否 |
更新评分脚本 | 是 | 是 |
更新部署配置(部署、环境、代码、模型) | 否 | 是 |
集成 Microsoft Visual Studio Code (VS Code) 调试器 | 是 | 是 |
在本地运行推理 HTTP 服务器时,你可以专注于调试评分脚本,而无需考虑部署容器的配置。
安装 azureml-inference-server-http 包
若要安装 azureml-inference-server-http
包,请运行以下命令:
python -m pip install azureml-inference-server-http
注意
为了避免包冲突,请在虚拟环境中安装推理 HTTP 服务器。
可以使用 pip install virtualenv
命令为配置启用虚拟环境。
在本地调试评分脚本
若要在本地调试评分脚本,可以使用多个选项来测试服务器行为:
- 尝试虚拟评分脚本。
- 使用 Visual Studio Code 通过 azureml-inference-server-http 包进行调试。
- 运行示例存储库中的实际评分脚本、模型文件和环境文件。
使用虚拟评分脚本测试服务器行为
创建一个名为 server_quickstart 的目录来保存文件:
mkdir server_quickstart cd server_quickstart
为了避免包冲突,请创建一个虚拟环境(例如 myenv)并激活它:
python -m virtualenv myenv
注意
在 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
注意
服务器托管在 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 集成
若要使用 VS Code 和 Python 扩展通过 azureml-inference-server-http 包进行调试,可以使用启动和附加模式。
对于启动模式,请在 VS Code 中设置 launch.json 文件,并在 VS Code 中启动 Azure 机器学习推理 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 机器学习推理 HTTP 服务器,并使用 VS Code 和 Python 扩展附加到进程:
注意
对于 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。
在命令窗口中,查看来自推理服务器的日志并找到
azmlinfsrv
命令(而不是gunicorn
)的进程 ID:在 VS Code 调试器中,输入
azmlinfsrv
命令的进程 ID。如果未看到 VS Code 进程选择器,可以在该工作区的 launch.json 文件的
processId
字段中手动输入进程 ID。
对于这两种模式,都可以设置断点并逐步调试脚本。
使用端到端示例
以下过程使用 Azure 机器学习示例存储库中的示例文件(评分脚本、模型文件和环境)在本地运行服务器。 有关如何使用这些示例文件的更多示例,请参阅使用联机终结点部署机器学习模型并对其进行评分。
克隆示例存储库:
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 上侦听以下路由:
名称 | 路由 |
---|---|
运行情况探测 | 127.0.0.1:5001/ |
分数 | 127.0.0.1:5001/score |
OpenAPI (swagger) | 127.0.0.1:5001/swagger.json |
查看服务器参数
推理 HTTP 服务器接受以下参数:
参数 | 必须 | 默认 | 说明 |
---|---|---|---|
entry_script |
True | 空值 | 标识评分脚本的相对路径或绝对路径。 |
model_dir |
False | 空值 | 标识用于推理的模型所在的目录的相对路径或绝对路径。 |
port |
False | 5001 | 指定服务器的服务端口。 |
worker_count |
False | 1 | 提供用于处理并发请求的工作线程数。 |
appinsights_instrumentation_key |
False | 空值 | 提供要在其中发布日志的 Application Insights 的检测密钥。 |
access_control_allow_origins |
False | 空值 | 为指定的源启用 CORS,多个源之间用逗号 (,) 分隔,例如 microsoft.com, bing.com 。 |
了解服务器请求处理
以下步骤说明了 Azure 机器学习推理 HTTP 服务器 (azmlinfsrv
) 如何处理传入请求:
Python CLI 包装器位于服务器的网络堆栈周围,用于启动服务器。
客户端向服务器发送请求。
服务器通过 Web 服务器网关接口 (WSGI) 服务器发送请求,该 WSGI 服务器将请求分派给 Flask 辅助角色应用程序:
Flask 辅助角色应用处理请求,这包括加载入口脚本和所有依赖项。
入口脚本接收请求。 入口脚本对已加载的模型进行推理调用并返回响应:
浏览服务器日志
可通过两种方式获取推理 HTTP 服务器测试的日志数据:
- 在本地运行
azureml-inference-server-http
包并查看日志输出。 - 使用联机终结点并查看容器日志。 推理服务器的日志名为“Azure 机器学习推理 HTTP 服务器 <版本>”。
注意
自版本 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>
:该条目的日志记录级别的第一个字符,例如E
表示错误,I
表示信息,依此类推。<logger name>
:与该日志条目关联的资源的名称。<message>
:日志消息的内容。
Python 中有六个日志记录级别,并根据严重性为级别分配数字值:
日志记录级别 | 数值 |
---|---|
严重 | 50 |
ERROR | 40 |
警告 | 30 |
信息 | 20 |
调试 | 10 |
未设置 | 0 |
排查服务器问题
以下部分提供了 Azure 机器学习推理 HTTP 服务器的基本故障排除技巧。 若要排查联机终结点问题,请参阅排查联机终结点部署问题。
检查已安装的包
按照以下步骤解决已安装的包的问题。
收集有关为 Python 环境安装的包和版本的信息。
确认环境文件中指定的
azureml-inference-server-http
Python 包版本与启动日志中显示的 Azure 机器学习推理 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 以下的服务器版本,你可能会遇到 Flask 依赖项问题,例如 "can't import name Markup from 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 要求中。
服务器启动期间出现 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,则会出现此错误。 azureml-inference-server-http
包版本 0.7.0 及更高版本,以及 azureml-defaults
包版本 1.44 及更高版本均支持 Flask 2。
如果你未在 Azure 机器学习 Docker 映像中使用 Flask 2 包,请使用最新版本的
azureml-inference-server-http
或azureml-defaults
包。如果你在 Azure 机器学习 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 机器学习工作室中的“终结点”页的“日志”下找到日志。
如果你使用 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'
如果你使用服务器版本 0.4.10 及更低版本,而这些版本不会将 Flask 依赖项固定到兼容的版本,则会发生导入和模块错误。 为防止出现此问题,请安装更高的服务器版本。