将 MLflow 模型部署到联机终结点

适用于:Azure CLI ml 扩展 v2(当前版)

本文介绍如何将 MLflow 模型部署到联机终结点以进行实时推理。 将 MLflow 模型部署到联机终结点时,你无需指定评分脚本或环境,此功能称为无代码部署

对于无代码部署,Azure 机器学习:

  • 动态安装 conda.yaml 文件中提供的 Python 包。 因此,依赖项在容器运行时期间安装。
  • 提供 MLflow 基础映像/策展环境,其中包含以下各项:

提示

没有公用网络访问权限的工作区:必须打包模型(预览版),然后才能在没有传出连接的情况下将 MLflow 模型部署到联机终结点。 通过使用模型打包,不必进行 Internet 连接;如果使用其他方式,Azure 机器学习则需要进行 Internet 连接才能为 MLflow 模型动态安装必要的 Python 包。

关于示例

此示例演示如何将 MLflow 模型部署到联机终结点以执行预测。 此示例使用基于糖尿病数据集的 MLflow 模型。 该数据集包含 10 个基线变量、年龄、性别、体重指数、平均血压以及从 442 名糖尿病患者获得的六项血清测量值。 它还包含兴趣反应,即对基线后一年的疾病进展的定量测量。

该模型已使用 scikit-learn 回归量进行训练,所有必需的预处理都打包为管道,使此模型成为从原始数据到预测的端到端管道。

本文中的信息基于 azureml-examples 存储库中包含的代码示例。 若要在不复制/粘贴 YAML 和其他文件的情况下在本地运行命令,请克隆存储库,然后将目录更改为 cli(如果使用 Azure CLI)。 如果使用用于 Python 的 Azure 机器学习 SDK,请将目录更改为 sdk/python/endpoints/online/mlflow

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

在 Jupyter Notebook 中跟进操作

可以按照使用 Azure 机器学习 Python SDK 的步骤操作,方法是在克隆的存储库中打开将 MLflow 模型部署到联机终结点笔记本。

先决条件

在按照本文中的步骤操作之前,请确保满足以下先决条件:

  • Azure 订阅。 如果没有 Azure 订阅,可在开始前创建一个试用帐户。 尝试试用版订阅

  • Azure 基于角色的访问控制 (Azure RBAC) 用于授予对 Azure 机器学习中的操作的访问权限。 若要执行本文中的步骤,必须为用户帐户分配 Azure 机器学习工作区的所有者或参与者角色,或者分配一个允许 Microsoft.MachineLearningServices/workspaces/onlineEndpoints/* 的自定义角色。 有关角色的详细信息,请参阅管理对 Azure 机器学习工作区的访问权限

  • 必须具有已在工作区中注册的 MLflow 模型。 本文在工作区中注册了为糖尿病数据集训练的模型。

  • 此外,你还需要:

    • 安装 Azure CLI 和 Azure CLI 的 ml 扩展。 有关安装 CLI 的详细信息,请参阅安装和设置 CLI (v2)

连接到工作区

首先,连接到你将处理工作的 Azure 机器学习工作区。

az account set --subscription <subscription>
az configure --defaults workspace=<workspace> group=<resource-group> 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

注意

路径 $MODEL_PATH 是模型在运行中存储的位置。

将 MLflow 模型部署到联机终结点

  1. 配置要将模型部署到的终结点。 以下示例配置终结点的名称和身份验证模式:

    通过运行以下命令设置终结点名称(将 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

$schema: https://azuremlschemas.azureedge.net/latest/managedOnlineEndpoint.schema.json
name: my-endpoint
auth_mode: key
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 模型:

  1. 标识你的 MLflow 模型所在的文件夹。

    a. 转到 Azure 机器学习工作室

    b. 转到“模型”部分。

    c. 选择要部署的模型,然后转到其“工件”选项卡。

    d. 记下显示的文件夹注释。 注册模型时指定了此文件夹。

    Screenshot showing the folder where the model artifacts are placed.

  2. 创建评分脚本。 请注意你之前标识的文件夹名称 model 是如何包含在 init() 函数中的。

    score.py

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 模型推理的示例。 可以根据需要调整此脚本,或根据自己的方案更改其中的任何部分。

score.py

警告

MLflow 2.0 通告:提供的评分脚本适用于 MLflow 1.X 和 MLflow 2.X。 但请注意,这些版本的预期输入/输出格式可能会有所不同。 检查用于确保使用预期的 MLflow 版本的环境定义。 请注意,MLflow 2.0 仅在 Python 3.8+ 中受支持。

  1. 创建一个可以执行评分脚本的环境。 由于模型是 MLflow 模型,因此在模型包中也指定了 conda 要求。 有关 MLflow 模型中包含的文件的更多详细信息,请参阅 MLmodel 格式。 然后,你将使用文件中的 conda 依赖项构建环境。 但是,你还需要加入 Azure 机器学习中联机部署所需的包 azureml-inference-server-http

    conda 定义文件如下所示:

    conda.yml

     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
    

    注意

    azureml-inference-server-http 包已添加到原始 conda 依赖项文件。

    你将使用此 conda 依赖项文件来创建环境:

    将在部署配置中内联创建环境。

  2. 创建部署:

    创建部署配置文件 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.yml
    code_configuration:
      code: sklearn-diabetes/src
      scoring_script: score.py
    instance_type: Standard_F2s_v2
    instance_count: 1
    

    创建部署:

    az ml online-deployment create -f deployment.yml
    
  3. 部署完成后,它就可以服务请求了。 一种测试部署的方法是使用示例请求文件和 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]
       }}
    

    按如下所示向终结点提交请求:

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>

ml_client.online_endpoints.invoke(
    endpoint_name=endpoint_name,
    deployment_name=deployment.name,
    request_file="sample-request-sklearn.json",
)

响应类似于以下文本:

{
    "predictions": [ 
    11633.100167144921,
    8522.117402884991
    ]
}

警告

MLflow 2.0 公告:在 MLflow 1.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>