本文介绍如何将 MLflow 模型部署到 联机终结点 进行实时推理。 将 MLflow 模型部署到联机终结点时,无需指定评分脚本或环境,此功能称为无代码部署。
对于无代码部署的情况,Azure 机器学习:
- 动态安装 conda.yaml 文件中列出的 Python 包。 因此,系统会在容器运行时安装依赖项。
- 提供包含以下项的 MLflow 基本映像或特选环境:
-
azureml-inference-server-http包 -
mlflow-skinny包 - 用于推理的评分脚本
-
先决条件
Python 3.10 或更高版本。
Azure 订阅。 如果没有 Azure 订阅,可在开始前创建一个试用帐户。
至少具有以下 Azure 基于角色的访问控制(Azure RBAC)角色之一的用户帐户:
- Azure 机器学习工作区的所有者角色
- Azure 机器学习工作区的贡献者角色
- 具有
Microsoft.MachineLearningServices/workspaces/onlineEndpoints/*权限的自定义角色
有关详细信息,请参阅管理对 Azure 机器学习工作区的访问。
访问 Azure 机器学习:
安装 Azure CLI 和 Azure CLI 的
ml扩展。 有关安装步骤,请参阅安装和设置 CLI (v2)。
关于示例
本文的示例演示如何将 MLflow 模型部署到联机终结点以执行预测。 此示例使用基于糖尿病数据集的 MLflow 模型。 此数据集包含 10 个基线变量:年龄、性别、体重指数、平均血压和 6 个从 442 名糖尿病患者获得的血液血清测量。 它还包含兴趣反应,即对基线数据日期一年后的疾病进展进行的定量测量。
该模型是使用 scikit-learn 回归器训练的。 所有必需的预处理都打包为管道,因此此模型是一个从原始数据到预测的端到端管道。
本文中的信息基于 azureml-examples 存储库中的代码示例。 如果克隆存储库,则可以在本地运行本文中的命令,而无需复制或粘贴 YAML 文件和其他文件。 使用以下命令克隆存储库并转到编码语言的文件夹:
git clone https://github.com/Azure/azureml-examples --depth 1
cd azureml-examples/cli
请在 Jupyter Notebook 中进行跟随操作
若要遵循本文中的步骤,请参阅示例存储库中的 “将 MLflow 模型部署到联机终结点 笔记本”。
连接到工作区
连接到 Azure 机器学习工作区:
az account set --subscription <subscription-ID>
az configure --defaults workspace=<workspace-name> group=<resource-group-name> location=<location>
注册模型
只能将已注册的模型部署到联机终结点。 本文中的步骤使用了一个经过训练以适用于 糖尿病数据集的模型。 在这种情况下,克隆的存储库中已有模型的本地副本,因此只需将模型发布到工作区中的注册表。 如果要部署的模型已注册,则可以跳过此步骤。
MODEL_NAME='sklearn-diabetes'
az ml model create --name $MODEL_NAME --type "mlflow_model" --path "endpoints/online/ncd/sklearn-diabetes/model"
如果你在运行中记录模型会怎样?
如果您在一次运行中记录了模型,则可以直接注册它。
若要注册模型,需要知道其存储位置:
- 如果使用 MLflow
autolog功能,则模型的路径取决于模型类型和框架。 检查作业输出以标识模型文件夹的名称。 此文件夹包含一个名为MLModel的文件。 - 如果使用该方法
log_model手动记录模型,请将模型的路径作为参数传递给该方法。 例如,如果您使用mlflow.sklearn.log_model(my_model, "classifier")来记录模型,那么classifier就是存储模型的路径。
可以使用 Azure 机器学习 CLI v2 从训练作业输出创建模型。 以下代码使用 ID $RUN_ID 的作业工件来注册名为 $MODEL_NAME 的模型。
$MODEL_PATH 是作业用于存储模型的路径。
az ml model create --name $MODEL_NAME --path azureml://jobs/$RUN_ID/outputs/artifacts/$MODEL_PATH
将 MLflow 模型部署到联机终结点
- 使用以下代码配置要将模型部署到的终结点的名称和身份验证模式:
通过运行以下命令设置终结点名称。 首先将 YOUR_ENDPOINT_NAME 替换为一个唯一的名称。
set -e
# <set_endpoint_name>
export ENDPOINT_NAME="<YOUR_ENDPOINT_NAME>"
# </set_endpoint_name>
# endpoint name
export ENDPOINT_NAME=endpt-ncd-`echo $RANDOM`
AML_SKLEARN_MODEL_NAME=mir-sample-sklearn-ncd-model
echo $AML_SKLEARN_MODEL_NAME
AML_LIGHTGBM_MODEL_NAME=mir-sample-lightgbm-ncd-model
echo $AML_LIGHTGBM_MODEL_NAME
# <create_endpoint>
az ml online-endpoint create --name $ENDPOINT_NAME -f endpoints/online/ncd/create-endpoint.yaml
# </create_endpoint>
# check if create was successful
endpoint_status=`az ml online-endpoint show --name $ENDPOINT_NAME --query "provisioning_state" -o tsv`
echo $endpoint_status
if [[ $endpoint_status == "Succeeded" ]]
then
echo "Endpoint created successfully"
else
echo "Endpoint creation failed"
exit 1
fi
# cleanup of existing models
model_archive=$(az ml model archive -n $AML_SKLEARN_MODEL_NAME --version 1 || true)
model_archive=$(az ml model archive -n $AML_LIGHTGBM_MODEL_NAME --version 1 || true)
# <create_sklearn_deployment>
az ml online-deployment create --name sklearn-deployment --endpoint $ENDPOINT_NAME -f endpoints/online/ncd/sklearn-deployment.yaml --all-traffic
# </create_sklearn_deployment>
deploy_status=`az ml online-deployment show --name sklearn-deployment --endpoint $ENDPOINT_NAME --query "provisioning_state" -o tsv`
echo $deploy_status
if [[ $deploy_status == "Succeeded" ]]
then
echo "Deployment completed successfully"
else
echo "Deployment failed"
exit 1
fi
# <test_sklearn_deployment>
az ml online-endpoint invoke --name $ENDPOINT_NAME --request-file endpoints/online/ncd/sample-request-sklearn.json
# </test_sklearn_deployment>
# <create_lightgbm_deployment>
az ml online-deployment create --name lightgbm-deployment --endpoint $ENDPOINT_NAME -f endpoints/online/ncd/lightgbm-deployment.yaml
# </create_lightgbm_deployment>
deploy_status=`az ml online-deployment show --name lightgbm-deployment --endpoint $ENDPOINT_NAME --query "provisioning_state" -o tsv`
echo $deploy_status
if [[ $deploy_status == "Succeeded" ]]
then
echo "Deployment completed successfully"
else
echo "Deployment failed"
exit 1
fi
# <test_lightgbm_deployment>
az ml online-endpoint invoke --name $ENDPOINT_NAME --deployment lightgbm-deployment --request-file endpoints/online/ncd/sample-request-lightgbm.json
# </test_lightgbm_deployment>
# cleanup of models
model_archive=$(az ml model archive -n $AML_SKLEARN_MODEL_NAME --version 1 || true)
model_archive=$(az ml model archive -n $AML_LIGHTGBM_MODEL_NAME --version 1 || true)
# <delete_endpoint>
az ml online-endpoint delete --name $ENDPOINT_NAME --yes
# </delete_endpoint>
若要配置终结点,请创建一个名为 create-endpoint.yaml 包含以下行的 YAML 文件:
$schema: https://azuremlschemas.azureedge.net/latest/managedOnlineEndpoint.schema.json
name: my-endpoint
auth_mode: key
创建终结点:
az ml online-endpoint create --name $ENDPOINT_NAME -f endpoints/online/mlflow/create-endpoint.yaml配置部署。 部署是托管处理实际推理的模型所需的一组资源。
创建一个名为
sklearn-deployment.yaml包含以下行的 YAML 文件:$schema: https://azuremlschemas.azureedge.net/latest/managedOnlineDeployment.schema.json name: sklearn-deployment endpoint_name: my-endpoint model: name: mir-sample-sklearn-ncd-model version: 1 path: sklearn-diabetes/model type: mlflow_model instance_type: Standard_DS3_v2 instance_count: 1注意
仅
scoring_script模型风格支持自动生成environment和PyFunc。 若要使用不同的模型风格,请参阅 自定义 MLflow 模型部署。创建部署:
az ml online-deployment create --name sklearn-deployment --endpoint $ENDPOINT_NAME -f endpoints/online/ncd/sklearn-deployment.yaml --all-trafficaz ml online-deployment create --package-model --name sklearn-deployment --endpoint $ENDPOINT_NAME -f endpoints/online/ncd/sklearn-deployment.yaml --all-traffic将所有流量分配到部署。 到目前为止,终结点有一个部署,但没有为其分配任何流量。
如果在创建过程中使用标志,
--all-traffic则不需要在 Azure CLI 中执行此步骤。 如果需要更改流量,请使用az ml online-endpoint update --traffic命令。 有关如何更新流量的详细信息,请参阅 逐步更新流量。更新终结点配置:
如果在创建过程中使用标志,
--all-traffic则不需要在 Azure CLI 中执行此步骤。 如果需要更改流量,请使用az ml online-endpoint update --traffic命令。 有关如何更新流量的详细信息,请参阅 逐步更新流量。
调用端点
部署就绪后,您可以使用它来服务请求。 测试部署的一种方法是在部署客户端中使用内置调用功能。 在示例存储库中, sample-request-sklearn.json 该文件包含以下 JSON 代码。 可以将它用作部署的示例请求文件。
{"input_data": {
"columns": [
"age",
"sex",
"bmi",
注意
此文件使用 input_data 密钥而不是 inputsMLflow 服务使用的密钥。 Azure 机器学习需要不同的输入格式来自动生成终结点的 Swagger 协定。 有关预期输入格式的详细信息,请参阅 MLflow 内置服务器中的部署与 Azure 机器学习推理服务器中的部署。
向终结点提交请求:
az ml online-endpoint invoke --name $ENDPOINT_NAME --request-file endpoints/online/mlflow/sample-request-sklearn.json
响应应类似于以下文本:
[
11633.100167144921,
8522.117402884991
]
重要
对于 MLflow 无代码部署,目前不支持 通过本地终结点进行测试 。
自定义 MLflow 模型部署
将 MLflow 模型部署到联机终结点时,无需指定评分脚本。 但是,如果要自定义推理过程,可以添加评分脚本。
在以下情况下自定义你的 MLflow 模型部署:
- 此模型没有
PyFunc风格。 - 需要自定义运行模型的方式。 例如,需要使用
mlflow.<flavor>.load_model()特定风格来加载模型。 - 你需要在评分例程中预处理或后处理,因为模型不处理此处理。
- 模型输出不能在表格数据中很好地表示。 例如,输出是表示图像的张量。
重要
如果为 MLflow 模型部署指定评分脚本,则还需要指定部署的环境。
部署自定义评分脚本
若要部署使用自定义评分脚本的 MLflow 模型,请执行以下步骤。
标识模型文件夹
通过执行以下步骤确定包含 MLflow 模型的文件夹:
转到 Azure 机器学习工作室。
转到“模型”部分。
选择要部署的模型,然后转到其 “项目 ”选项卡。
记下显示的文件夹。 注册模型时,请指定此文件夹。
创建评分脚本
以下评分脚本 score.py 提供了如何使用 MLflow 模型执行推理的示例。 可以根据需要调整此脚本,或根据自己的方案更改其中的任何部分。 请注意,您之前标识的文件夹名称 model 包含在函数 init() 中。
import logging
import os
import json
import mlflow
from io import StringIO
from mlflow.pyfunc.scoring_server import infer_and_parse_json_input, predictions_to_json
def init():
global model
global input_schema
# "model" is the path of the mlflow artifacts when the model was registered. For automl
# models, this is generally "mlflow-model".
model_path = os.path.join(os.getenv("AZUREML_MODEL_DIR"), "model")
model = mlflow.pyfunc.load_model(model_path)
input_schema = model.metadata.get_input_schema()
def run(raw_data):
json_data = json.loads(raw_data)
if "input_data" not in json_data.keys():
raise Exception("Request must contain a top level key named 'input_data'")
serving_input = json.dumps(json_data["input_data"])
data = infer_and_parse_json_input(serving_input, input_schema)
predictions = model.predict(data)
result = StringIO()
predictions_to_json(predictions, result)
return result.getvalue()
警告
MLflow 2.0 公告:示例评分脚本适用于 MLflow 1.X 和 MLflow 2.X。 但是,这些版本的预期输入和输出格式可能会有所不同。 检查环境定义,查看所使用的 MLflow 版本。 MLflow 2.0 仅在 Python 3.8 及更高版本中受支持。
创建环境
下一步是创建可以运行评分脚本的环境。 由于模型是 MLflow 模型,因此 conda 要求也在模型包中指定。 有关 MLflow 模型中包含的文件的详细信息,请参阅 MLmodel 格式。 使用文件中的 conda 依赖项生成环境。 但是,还需要包括 azureml-inference-server-http 包和 azureml-ai-monitoring 包,这些包是 Azure 机器学习中在线部署所需的。
可以创建一个名为 conda.yaml 的 conda 定义文件,其中包含以下行:
channels:
- conda-forge
dependencies:
- python=3.9
- pip
- pip:
- mlflow
- scikit-learn==1.2.2
- cloudpickle==2.2.1
- psutil==5.9.4
- pandas==2.0.0
- azureml-inference-server-http
name: mlflow-env
注意
此 conda 文件的 dependencies 节包括 azureml-inference-server-http 和 azureml-ai-monitoring 包。
使用此 conda 依赖项文件创建环境:
你在部署配置中嵌入式创建环境。
创建部署
在 endpoints/online/ncd 文件夹中,创建一个部署配置文件, deployment.yml其中包含以下行:
$schema: https://azuremlschemas.azureedge.net/latest/managedOnlineDeployment.schema.json
name: sklearn-diabetes-custom
endpoint_name: my-endpoint
model: azureml:sklearn-diabetes@latest
environment:
image: mcr.microsoft.com/azureml/openmpi4.1.0-ubuntu22.04
conda_file: sklearn-diabetes/environment/conda.yaml
code_configuration:
code: sklearn-diabetes/src
scoring_script: score.py
instance_type: Standard_F2s_v2
instance_count: 1
创建部署:
az ml online-deployment create -f endpoints/online/ncd/deployment.yml
处理请求
部署完成后,即可为请求提供服务。 测试部署的一种方法是将 invoke 该方法与示例请求文件一起使用, sample-request-sklearn.json例如以下文件:
{"input_data": {
"columns": [
"age",
"sex",
"bmi",
"bp",
"s1",
"s2",
"s3",
"s4",
"s5",
"s6"
],
"data": [
[ 1.0,2.0,3.0,4.0,5.0,6.0,7.0,8.0,9.0,10.0 ],
[ 10.0,2.0,9.0,8.0,7.0,6.0,5.0,4.0,3.0,2.0]
],
"index": [0,1]
}}
向终结点提交请求:
az ml online-endpoint invoke --name $ENDPOINT_NAME --request-file endpoints/online/ncd/sample-request-sklearn.json
响应应类似于以下文本:
{
"predictions": [
1095.2797413413252,
1134.585328803727
]
}
注意
使用 MLflow 2.x 或更高版本时,响应包含 predictions 密钥。
清理资源
如果不再需要终结点,请删除其关联的资源:
set -e
# <set_endpoint_name>
export ENDPOINT_NAME="<YOUR_ENDPOINT_NAME>"
# </set_endpoint_name>
# endpoint name
export ENDPOINT_NAME=endpt-ncd-`echo $RANDOM`
AML_SKLEARN_MODEL_NAME=mir-sample-sklearn-ncd-model
echo $AML_SKLEARN_MODEL_NAME
AML_LIGHTGBM_MODEL_NAME=mir-sample-lightgbm-ncd-model
echo $AML_LIGHTGBM_MODEL_NAME
# <create_endpoint>
az ml online-endpoint create --name $ENDPOINT_NAME -f endpoints/online/ncd/create-endpoint.yaml
# </create_endpoint>
# check if create was successful
endpoint_status=`az ml online-endpoint show --name $ENDPOINT_NAME --query "provisioning_state" -o tsv`
echo $endpoint_status
if [[ $endpoint_status == "Succeeded" ]]
then
echo "Endpoint created successfully"
else
echo "Endpoint creation failed"
exit 1
fi
# cleanup of existing models
model_archive=$(az ml model archive -n $AML_SKLEARN_MODEL_NAME --version 1 || true)
model_archive=$(az ml model archive -n $AML_LIGHTGBM_MODEL_NAME --version 1 || true)
# <create_sklearn_deployment>
az ml online-deployment create --name sklearn-deployment --endpoint $ENDPOINT_NAME -f endpoints/online/ncd/sklearn-deployment.yaml --all-traffic
# </create_sklearn_deployment>
deploy_status=`az ml online-deployment show --name sklearn-deployment --endpoint $ENDPOINT_NAME --query "provisioning_state" -o tsv`
echo $deploy_status
if [[ $deploy_status == "Succeeded" ]]
then
echo "Deployment completed successfully"
else
echo "Deployment failed"
exit 1
fi
# <test_sklearn_deployment>
az ml online-endpoint invoke --name $ENDPOINT_NAME --request-file endpoints/online/ncd/sample-request-sklearn.json
# </test_sklearn_deployment>
# <create_lightgbm_deployment>
az ml online-deployment create --name lightgbm-deployment --endpoint $ENDPOINT_NAME -f endpoints/online/ncd/lightgbm-deployment.yaml
# </create_lightgbm_deployment>
deploy_status=`az ml online-deployment show --name lightgbm-deployment --endpoint $ENDPOINT_NAME --query "provisioning_state" -o tsv`
echo $deploy_status
if [[ $deploy_status == "Succeeded" ]]
then
echo "Deployment completed successfully"
else
echo "Deployment failed"
exit 1
fi
# <test_lightgbm_deployment>
az ml online-endpoint invoke --name $ENDPOINT_NAME --deployment lightgbm-deployment --request-file endpoints/online/ncd/sample-request-lightgbm.json
# </test_lightgbm_deployment>
# cleanup of models
model_archive=$(az ml model archive -n $AML_SKLEARN_MODEL_NAME --version 1 || true)
model_archive=$(az ml model archive -n $AML_LIGHTGBM_MODEL_NAME --version 1 || true)
# <delete_endpoint>
az ml online-endpoint delete --name $ENDPOINT_NAME --yes
# </delete_endpoint>
