创作用于批处理部署的评分脚本

适用范围:Azure CLI ml 扩展 v2(最新版)Python SDK azure-ai-ml v2(最新版)

使用批处理终结点,可以部署模型以大规模执行长期推理。 部署模型时,需要创建并指定评分脚本(也称为批处理驱动程序脚本)以指示我们应如何对输入数据使用模型来创建预测。 本文介绍如何针对不同的方案在模型部署中使用评分脚本以及对应的最佳做法。

提示

MLflow 模型不需要评分脚本,因为它会自动为你生成。 有关批处理终结点如何与 MLflow 模型配合工作的更多详细信息,请参阅专门的教程在批处理部署中使用 MLflow 模型

警告

如果要在批处理终结点下部署自动化 ML 模型,请注意自动化 ML 提供的评分脚本仅适用于联机终结点,而不适用于批处理执行。 请遵循该指南中的内容,了解如何根据模型的功能创建评分脚本。

了解评分脚本

该评分脚本是一个 Python 文件 (.py),其中包含有关如何运行模型和读取批处理部署执行程序提交的输入数据的逻辑。 每个模型部署都在创建时提供评分脚本(允许所需的任何其他依赖项)。 通常如下所示:

deployment.yml

code_configuration:
  code: code
  scoring_script: batch_driver.py

评分脚本必须包含两个方法:

init 方法

init() 方法用于任何成本较高的或者一般性的准备工作。 例如,使用它将模型加载到内存中。 此函数在整个批处理作业的开头处调用一次。 模型的文件在环境变量 AZUREML_MODEL_DIR 确定的路径中可用。 请注意,根据模型的注册方式,其文件可能包含在文件夹(在以下示例中,模型在名为 model 的文件夹中有多个文件)中。 请参阅《如何查找模型使用的文件夹》。

def init():
    global model

    # AZUREML_MODEL_DIR is an environment variable created during deployment
    # The path "model" is the name of the registered model's folder
    model_path = os.path.join(os.environ["AZUREML_MODEL_DIR"], "model")

    # load the model
    model = load_model(model_path)

请注意,在此示例中,我们将模型放置在全局变量 model 中。 使用全局变量提供对评分函数执行推理所需的资产。

run 方法

使用 run(mini_batch: List[str]) -> Union[List[Any], pandas.DataFrame] 方法对批处理部署生成的每个微批执行评分。 对于为输入数据生成的每个 mini_batch,会调用这种方法一次。 批处理部署根据部署的配置方式读取批中的数据。

import pandas as pd
from typing import List, Any, Union

def run(mini_batch: List[str]) -> Union[List[Any], pd.DataFrame]:
    results = []

    for file in mini_batch:
        (...)

    return pd.DataFrame(results)

该方法接收文件路径列表作为参数 (mini_batch)。 可以使用此列表来迭代每个文件并逐个处理文件,或者读取整个批并一次性处理该批。 最佳选择取决于计算内存和需要实现的吞吐量。 有关如何一次性读取整个数据批的示例,请参阅高吞吐量部署

注意

工作是如何分布的?

批处理部署在文件级别分配工作,这意味着,如果某个文件夹包含 100 个文件并以 10 个文件为一个微批,则会生成 10 个批,每批包含 10 个文件。 请注意,无论涉及的文件大小如何,都会发生这种情况。 如果文件太大因而无法按较大的微批进行处理,我们建议将文件拆分为较小的文件以实现更高的并行度,或减少每个微批的文件数。 目前,批处理部署无法处理文件大小分布的偏差。

run() 方法应返回 Pandas DataFrame 或数组/列表。 每个返回的输出元素指示输入 mini_batch 中成功运行一次输入元素。 对于文件或文件夹数据资产,返回的每个行/元素表示已处理的单个文件。 对于表格数据资产,返回的每个行/元素表示已处理的文件中的一行。

重要

如何写入预测?

run() 函数中返回的任何内容都将追加到批处理作业生成的输出预测文件中。 请务必从此函数返回正确的数据类型。 需要输出单个预测时,请返回数组。 需要返回多条信息时,请返回 pandas 数据帧。 例如,对于表格数据,你可能希望将预测追加到原始记录。 对于这种情况请使用 pandas 数据帧。 尽管 pandas 数据帧可能包含列名,但列名不会包含在输出文件中。

如果需要以其他方式编写预测,可以在批量部署中自定义输出

警告

不要在 run 函数中输出 pandas.DataFrame 之外的复杂数据类型(或复杂数据类型的列表)。 这些输出将转换为字符串,并且难以阅读。

生成的数据帧或数组将追加到指示的输出文件中。 对结果的基数没有要求(1 个文件可以在输出中生成 1 个或多个行/元素)。 结果数据帧或数组中的所有元素会按原样写入输出文件(假设 output_action 不是 summary_only)。

用于评分的 Python 包

需要在运行批处理部署的环境中指明你的评分脚本需要运行的任何库。 对于评分脚本,将为每个部署指明环境。 通常要使用 conda.yml 依赖项文件指明你的要求,该文件可能如下所示:

mnist/environment/conda.yaml

name: mnist-env
channels:
  - conda-forge
dependencies:
  - python=3.8.5
  - pip<22.0
  - pip:
    - torch==1.13.0
    - torchvision==0.14.0
    - pytorch-lightning
    - pandas
    - azureml-core
    - azureml-dataset-runtime[fuse]

有关如何为你的模型指明环境的更多详细信息,请参阅 创建批量部署

以不同的方式编写预测

默认情况下,批处理部署会将模型的预测写入部署中所示的单个文件中。 但在部分情况下,需要在多个文件写入预测。 例如,如果输入数据已分区,则通常生成的输出也需要分区。 在此类情况下,可以在批处理部署中自定义输出以指示:

  • 用于编写预测的文件格式(CSV、parquet、json 等)。
  • 数据在输出中的分区方式。

若需查看演示如何实现该操作的示例,请阅读在批处理部署中自定义输出一文。

评分脚本的源代码管理

强烈建议将评分脚本置于源代码管理之下。

编写评分脚本的最佳做法

编写处理大量数据的评分脚本时,需要考虑几个因素,包括:

  • 每个文件的大小。
  • 每个文件的数据量。
  • 读取每个文件所需的内存量。
  • 读取整批文件所需的内存量。
  • 模型的内存占用情况。
  • 对输入数据运行模型时的模型内存占用情况。
  • 计算中的可用内存。

批处理部署在文件级别分配工作,这意味着,如果某个文件夹包含 100 个文件并以 10 个文件为一个微批,则会生成 10 个批,每批包含 10 个文件(不考虑涉及的文件的大小)。 如果文件太大因而无法按较大的微批进行处理,我们建议将文件拆分为较小的文件以实现更高的并行度,或减少每个微批的文件数。 目前,批处理部署无法处理文件大小分布的偏差。

并行度与评分脚本之间的关系

部署配置控制每个微批的大小以及每个节点上的辅助进程数量。 在决定是要读取整个小批量来执行推理,还是要逐个文件运行推理,或是逐行(适用于表格)推理时,请将其考虑在内。 请参阅《在小批量、文件或行级别运行推理》,以了解不同的方法。

请注意,在同一实例上运行多个辅助角色时,它们将共享内存。 一般而言,假设数据大小和计算 SKU 保持不变,如果每个节点的辅助进程数量增加,则小批量大小就会降低,或评分策略会发生更改。

在微批、文件或行级别运行推理

批处理终结点将在每个微批中调用一次评分脚本中的 run() 函数。 但如果数据是表格,就可以选择是要对整个批处理运行推理、一次对一个文件运行,还是一次对一行运行。

微批级别

如果要在批处理评分过程中实现高吞吐量,通常需要一次性对整个批处理运行推理。 例如,假设你想让推理设备达到饱和,且通过 GPU 运行推理。 如果不便将数据存储在内存中,也可能依赖于可以自行处理批处理的数据加载程序(如 TensorFlowPyTorch 数据加载程序)。 在这些情况下,可能需要考虑对整个批处理运行推理。

警告

在批处理级别运行推理可能需要高度控制输入数据大小,以便能准确衡量内存要求并避免出现内存不足异常。 能否在内存中加载整个微批取决于微批的大小、群集中实例的大小以及每个节点上的辅助进程数量。

若需查看有关实现方法的示例,请参阅高吞吐量部署。 此示例一次处理整批文件。

文件级别

执行推理的最简单方法之一是循环访问微批中的所有文件,并对其运行模型。 该方法非常适合类似于图像处理这样的情况。 如果数据是表格格式的,则可能需要对每个文件中的行数进行良好的估计,以估计模型是否满足内存要求,这样不仅能将数据整体加载到内存中,还能对其执行推理。 请记住,某些模型(尤其是基于循环神经网络的模型)将展开并产生可能不与行数成线性关系的内存占用量。 如果模型在内存方面成本高昂,请考虑在行级别运行推理。

提示

如果文件大至甚至无法一次性完成读取,请考虑将文件分解为多个较小的文件以达到更佳的并行度。

若需查看有关实现方法的示例,请参阅使用批处理部署进行图像处理。 此示例一次处理一个文件。

行级别(表格)

对于在输入大小方面存在挑战的模型,可以考虑在行级别运行推理。 批处理部署仍将为评分脚本提供微批文件,但将一次读取一个文件、一行。 这可能看起来效率低下,但对于某些深度学习模型来说,这可能是在不扩展硬件要求的情况下执行推理的唯一方法。

若需查看有关实现方法的示例,请参阅使用批处理部署进行文本处理。 此示例一次处理一行。

使用作为文件夹的模型

环境变量 AZUREML_MODEL_DIR 包含所选模型所在位置的路径,通常在 init() 函数中用于将模型加载到内存中。 但是,某些模型可能包含文件夹内的文件,在加载它们时可能需要考虑到这一点。 可按如下所示确定模型的文件夹结构:

  1. 转到 Azure 机器学习工作室门户

  2. 转到“模型”部分。

  3. 选择要尝试部署的模型,然后单击“项目”选项卡。

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

    Screenshot showing the folder where the model artifacts are placed.

然后,可以使用此路径加载模型:

def init():
    global model

    # AZUREML_MODEL_DIR is an environment variable created during deployment
    # The path "model" is the name of the registered model's folder
    model_path = os.path.join(os.environ["AZUREML_MODEL_DIR"], "model")

    model = load_model(model_path)

后续步骤