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

了解如何使用 Azure 机器学习 REST API 部署模型以进行批量评分。

REST API 使用标准 HTTP 谓词创建、检索、更新和删除资源。 REST API 适用于可发出 HTTP 请求的任何语言或工具。 REST 具有简单的结构,因此它是适合脚本编写环境和 MLOps 自动化的良好选择。

本文介绍如何使用新的 REST API 执行以下操作:

  • 创建机器学习资产
  • 创建批处理终结点和批处理部署
  • 调用批处理终结点以启动批量评分作业
  • 你对其拥有管理权限的 Azure 订阅 。 如果没有此类订阅,请尝试注册 免费或付费的个人订阅
  • 一个 Azure 机器学习工作区
  • 工作区中的服务主体。 管理 REST 请求使用 服务主体身份验证
  • 一个服务主体身份验证令牌。 请按照 检索服务主体身份验证令牌 中的步骤检索此令牌。
  • curl 实用工具。 在 适用于 Linux 的 Windows 子系统 或任何 UNIX 分发版中均已提供了 curl 程序。 在 PowerShell 中, curl Invoke-WebRequest 的别名,并且 curl -d "key=val" -X POST uri 变成了 Invoke-WebRequest -Body "key=val" -Method POST -Uri uri
  • jq JSON 处理器。
  • 本文中的代码片段假设使用的是 Bash shell。

    代码片段摘自 Azure 机器学习示例存储库 中的 /cli/batch-score-rest.sh 文件。

    设置终结点名称

    批处理终结点名称在 Azure 区域级别需是唯一的。 例如,westus2 中只能有一个名为 mybatchendpoint 的批处理终结点。

    export ENDPOINT_NAME=endpt-`echo $RANDOM`

    Azure 机器学习批处理终结点

    批处理终结点 简化了承载用于批量评分的模型的过程,使你可以将工作重心放在机器学习而不是基础结构上。 在本文中,你将创建一个批处理终结点和部署,并调用它来启动批量评分作业。 但首先必须注册部署所需的资产,包括模型、代码和环境。

    可通过多种方式创建 Azure 机器学习批处理终结点,包括 Azure CLI、适用于 Python 的 Azure 机器学习 SDK,以及在工作室中以视觉方式创建。 以下示例使用 REST API 创建批处理终结点和批处理部署。

    创建机器学习资产

    首先设置 Azure 机器学习资产以配置作业。

    在以下 REST API 调用中,我们使用了 SUBSCRIPTION_ID RESOURCE_GROUP LOCATION WORKSPACE 作为占位符。 将占位符替换为自己的值。

    管理 REST 请求一个 服务主体身份验证令牌 。 请将 TOKEN 替换为你自己的值。 可使用以下命令检索此令牌:

    TOKEN=$(az account get-access-token --query accessToken -o tsv)

    服务提供商使用 api-version 参数来确保兼容性。 api-version 参数因服务而异。 将 API 版本设置为变量以适应将来的版本:

    API_VERSION="2022-05-01"

    批量评分仅在云计算资源上运行,而不在本地运行。 云计算资源是一个可重用的虚拟计算机群集,可在其中运行批量评分工作流。

    创建计算群集:

    response=$(curl --location --request PUT "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/computes/batch-cluster?api-version=$API_VERSION" \ --header "Authorization: Bearer $TOKEN" \ --header "Content-Type: application/json" \ --data-raw "{ \"properties\":{ \"computeType\": \"AmlCompute\", \"properties\": { \"osType\": \"Linux\", \"vmSize\": \"STANDARD_D2_V2\", \"scaleSettings\": { \"maxNodeCount\": 5, \"minNodeCount\": 0 \"remoteLoginPortPublicAccess\": \"NotSpecified\" \"location\": \"$LOCATION\"

    若要改用现有计算,必须在 创建批处理部署 时指定完整的 Azure 资源管理器 ID。 完整 ID 采用 /subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/computes/<your-compute-name> 格式。

    获取存储帐户详细信息

    若要注册模型和代码,首先需要将其上传到存储帐户。 数据存储中提供了存储帐户的详细信息。 此示例将获取工作区的默认数据存储和 Azure 存储帐户。 使用 GET 请求查询工作区,以获取包含信息的 JSON 文件。

    可以使用工具 jq 分析 JSON 结果并获取所需的值。 也可以使用 Azure 门户找到相同的信息:

    # Get values for storage account response=$(curl --location --request GET "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/datastores?api-version=$API_VERSION&isDefault=true" \ --header "Authorization: Bearer $TOKEN") DATASTORE_PATH=$(echo $response | jq -r '.value[0].id') BLOB_URI_PROTOCOL=$(echo $response | jq -r '.value[0].properties.protocol') BLOB_URI_ENDPOINT=$(echo $response | jq -r '.value[0].properties.endpoint') AZUREML_DEFAULT_DATASTORE=$(echo $response | jq -r '.value[0].name') AZUREML_DEFAULT_CONTAINER=$(echo $response | jq -r '.value[0].properties.containerName') AZURE_STORAGE_ACCOUNT=$(echo $response | jq -r '.value[0].properties.accountName') export AZURE_STORAGE_ACCOUNT $(echo $AZURE_STORAGE_ACCOUNT) STORAGE_RESPONSE=$(echo az storage account show-connection-string --name $AZURE_STORAGE_ACCOUNT) AZURE_STORAGE_CONNECTION_STRING=$($STORAGE_RESPONSE | jq -r '.connectionString') BLOB_URI_ROOT="$BLOB_URI_PROTOCOL://$AZURE_STORAGE_ACCOUNT.blob.$BLOB_URI_ENDPOINT/$AZUREML_DEFAULT_CONTAINER"

    上传和注册代码

    获取数据存储后,可以上传评分脚本。 有关如何创作评分脚本的详细信息,请参阅 了解评分脚本 。 使用 Azure 存储 CLI 将 Blob 上传到默认容器中:

    az storage blob upload-batch -d $AZUREML_DEFAULT_CONTAINER/score -s endpoints/batch/mnist/code/ --connection-string $AZURE_STORAGE_CONNECTION_STRING

    也可以使用其他方法来上传,例如 Azure 门户或 Azure 存储资源管理器

    上传代码后,可以使用 PUT 请求指定代码:

    response=$(curl --location --request PUT "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/codes/score-mnist/versions/1?api-version=$API_VERSION" \ --header "Authorization: Bearer $TOKEN" \ --header "Content-Type: application/json" \ --data-raw "{ \"properties\": { \"description\": \"Score code\", \"codeUri\": \"$BLOB_URI_ROOT/score\"

    上传和注册模型

    与代码类似,上传模型文件:

    az storage blob upload-batch -d $AZUREML_DEFAULT_CONTAINER/model -s endpoints/batch/mnist/model --connection-string $AZURE_STORAGE_CONNECTION_STRING

    现在注册模型:

    response=$(curl --location --request PUT "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/models/mnist/versions/1?api-version=$API_VERSION" \ --header "Authorization: Bearer $TOKEN" \ --header "Content-Type: application/json" \ --data-raw "{ \"properties\": { \"modelUri\":\"azureml://subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/workspaces/$WORKSPACE/datastores/$AZUREML_DEFAULT_DATASTORE/paths/model\"

    部署需要在具有所需依赖关系的环境中运行。 使用 PUT 请求创建环境。 使用 Microsoft Container Registry 中的 Docker 映像。 可以使用 image 配置 Docker 映像,并使用 condaFile 添加 Conda 依赖项。

    运行以下代码以读取 json 中定义的 condaFile 。 源文件位于示例存储库中的 /cli/endpoints/batch/mnist/environment/conda.json

    CONDA_FILE=$(cat endpoints/batch/mnist/environment/conda.json | sed 's/"/\\"/g')

    现在,运行以下代码片段来创建环境:

    ENV_VERSION=$RANDOM response=$(curl --location --request PUT "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/environments/mnist-env/versions/$ENV_VERSION?api-version=$API_VERSION" \ --header "Authorization: Bearer $TOKEN" \ --header "Content-Type: application/json" \ --data-raw "{ \"properties\":{ \"condaFile\": $(echo \"$CONDA_FILE\"), \"image\": \"mcr.microsoft.com/azureml/openmpi3.1.2-ubuntu18.04:latest\"

    使用批处理终结点进行部署

    接下来,创建一个批处理终结点,一个批处理部署,并为该终结点设置默认部署。

    创建批处理终结点

    创建批处理终结点:

    response=$(curl --location --request PUT "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/batchEndpoints/$ENDPOINT_NAME?api-version=$API_VERSION" \ --header "Content-Type: application/json" \ --header "Authorization: Bearer $TOKEN" \ --data-raw "{ \"properties\": { \"authMode\": \"aadToken\" \"location\": \"$LOCATION\"

    创建批处理部署

    在终结点下创建批处理部署:

    DEPLOYMENT_NAME="nonmlflowedp" response=$(curl --location --request PUT "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/batchEndpoints/$ENDPOINT_NAME/deployments/$DEPLOYMENT_NAME?api-version=$API_VERSION" \ --header "Content-Type: application/json" \ --header "Authorization: Bearer $TOKEN" \ --data-raw "{ \"location\": \"$LOCATION\", \"properties\": { \"model\": { \"referenceType\": \"Id\", \"assetId\": \"/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/models/mnist/versions/1\" \"codeConfiguration\": { \"codeId\": \"/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/codes/score-mnist/versions/1\", \"scoringScript\": \"digit_identification.py\" \"environmentId\": \"/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/environments/mnist-env/versions/$ENV_VERSION\", \"compute\": \"/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/computes/batch-cluster\", \"resources\": { \"instanceCount\": 1 \"maxConcurrencyPerInstance\": \"4\", \"retrySettings\": { \"maxRetries\": 3, \"timeout\": \"PT30S\" \"errorThreshold\": \"10\", \"loggingLevel\": \"info\", \"miniBatchSize\": \"5\",

    在终结点下设置默认批处理部署

    一个终结点下只有一个默认的批处理部署,调用运行批量评分作业时将使用该部署。

    response=$(curl --location --request PUT "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/batchEndpoints/$ENDPOINT_NAME?api-version=$API_VERSION" \ --header "Content-Type: application/json" \ --header "Authorization: Bearer $TOKEN" \ --data-raw "{ \"properties\": { \"authMode\": \"aadToken\", \"defaults\": { \"deploymentName\": \"$DEPLOYMENT_NAME\" \"location\": \"$LOCATION\" operation_id=$(echo $response | jq -r '.properties' | jq -r '.properties' | jq -r '.AzureAsyncOperationUri') wait_for_completion $operation_id $TOKEN

    运行批量评分

    调用批处理终结点会触发批量评分作业。 响应中会返回作业 id ,该作业可用于跟踪批量评分进度。 在以下代码片段中, jq 用于获取作业 id

    调用批处理终结点以启动批量评分作业

    获取评分 URI 和访问令牌

    获取评分 URI 和访问令牌以调用批处理终结点。 首先获取评分 uri:

    response=$(curl --location --request GET "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/batchEndpoints/$ENDPOINT_NAME?api-version=$API_VERSION" \ --header "Content-Type: application/json" \ --header "Authorization: Bearer $TOKEN") SCORING_URI=$(echo $response | jq -r '.properties.scoringUri')

    获取批处理终结点访问令牌:

    SCORING_TOKEN=$(az account get-access-token --resource https://ml.azure.com --query accessToken -o tsv)

    使用不同输入选项调用批处理终结点

    接下来,调用批处理终结点以启动批量评分作业。 如果数据是一个文件夹(可能包含多个文件)并且可通过网络公开访问,则可使用以下代码段:

    response=$(curl --location --request POST $SCORING_URI \
    --header "Authorization: Bearer $SCORING_TOKEN" \
    --header "Content-Type: application/json" \
    --data-raw "{
        \"properties\": {
        	\"InputData\": {
        		\"mnistinput\": {
        			\"JobInputType\" : \"UriFolder\",
        			\"Uri\":  \"https://pipelinedata.blob.core.windows.net/sampledata/mnist\"
    JOB_ID=$(echo $response | jq -r '.id')
    JOB_ID_SUFFIX=$(echo ${JOB_ID##/*/})
    

    现在,让我们看看用于调用批处理终结点的其他选项。 当涉及到输入数据时,可选择多种方案,具体取决于输入类型(是指定文件夹还是单个文件)和 URI 类型(是使用 Azure 机器学习已注册的数据存储上的路径(是对 Azure 机器学习已注册的 V2 数据资产的引用)还会使用公共 URI)。

  • InputData 属性具有 JobInputTypeUri 键。 指定单个文件时,可使用 "JobInputType": "UriFile",指定文件夹时,可使用 'JobInputType": "UriFolder"

  • 当文件或文件夹位于已注册 Azure 机器学习的数据存储上时,Uri 的语法为 azureml://datastores/<datastore-name>/paths/<path-on-datastore>(适用于文件夹)和 azureml://datastores/<datastore-name>/paths/<path-on-datastore>/<file-name>(适用于特定文件)。 还可使用长格式来表示同一路径,例如 azureml://subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/workspaces/<workspace-name>/datastores/<datastore-name>/paths/<path-on-datastore>/

  • 当文件或文件夹作为 uri_folderuri_file 注册为 V2 数据资产时,Uri 的语法为 \"azureml://locations/<location-name>/workspaces/<workspace-name>/data/<data-name>/versions/<data-version>"(资产 ID 格式)或 \"/subscriptions/<subscription-id>/resourcegroups/<resource-group-name>/providers/Microsoft.MachineLearningServices/workspaces/<workspace-name>/data/<data-name>/versions/<data-version>\"(ARM ID 格式)。

  • 当文件或文件夹位于可公开访问的路径上时,URI 的语法为 https://<public-path>(适用于文件夹)和 https://<public-path>/<file-name>(适用于特定文件)。

    有关数据 URI 的详细信息,请参阅 Azure 机器学习数据引用 URI

    下面是使用不同类型的输入数据的一些示例。

  • 如果数据是已注册 Azure 机器学习的数据存储上的文件夹,你则可以:

  • 使用短格式表示 URI:
  • response=$(curl --location --request POST $SCORING_URI \
    --header "Authorization: Bearer $SCORING_TOKEN" \
    --header "Content-Type: application/json" \
    --data-raw "{
        \"properties\": {
            \"InputData\": {
                \"mnistInput\": {
                    \"JobInputType\" : \"UriFolder\",
                    \"Uri": \"azureml://datastores/workspaceblobstore/paths/$ENDPOINT_NAME/mnist\"
    JOB_ID=$(echo $response | jq -r '.id')
    JOB_ID_SUFFIX=$(echo ${JOB_ID##/*/})
    
  • 或者对同一 URI 使用长格式:
  • response=$(curl --location --request POST $SCORING_URI \
    --header "Authorization: Bearer $SCORING_TOKEN" \
    --header "Content-Type: application/json" \
    --data-raw "{
        \"properties\": {
        	\"InputData\": {
        		\"mnistinput\": {
        			\"JobInputType\" : \"UriFolder\",
        			\"Uri\": \"azureml://subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/workspaces/$WORKSPACE/datastores/workspaceblobstore/paths/$ENDPOINT_NAME/mnist\"
    JOB_ID=$(echo $response | jq -r '.id')
    JOB_ID_SUFFIX=$(echo ${JOB_ID##/*/})
    
  • 如果要将数据作为已注册 Azure 机器学习的 V2 数据资产进行管理,即 uri_folder,可以按照以下两个步骤操作:

  • 创建 V2 数据资产:
  • DATA_NAME="mnist"
    DATA_VERSION=$RANDOM
    response=$(curl --location --request PUT https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/data/$DATA_NAME/versions/$DATA_VERSION?api-version=$API_VERSION \
    --header "Content-Type: application/json" \
    --header "Authorization: Bearer $TOKEN" \
    --data-raw "{
        \"properties\": {
            \"dataType\": \"uri_folder\",
      \"dataUri\": \"https://pipelinedata.blob.core.windows.net/sampledata/mnist\",
      \"description\": \"Mnist data asset\"
    
  • 引用批处理评分作业中的数据资产:
  • response=$(curl --location --request POST $SCORING_URI \
    --header "Authorization: Bearer $SCORING_TOKEN" \
    --header "Content-Type: application/json" \
    --data-raw "{
        \"properties\": {
            \"InputData\": {
                \"mnistInput\": {
                    \"JobInputType\" : \"UriFolder\",
                    \"Uri": \"azureml://locations/$LOCATION_NAME/workspaces/$WORKSPACE_NAME/data/$DATA_NAME/versions/$DATA_VERSION/\"
    JOB_ID=$(echo $response | jq -r '.id')
    JOB_ID_SUFFIX=$(echo ${JOB_ID##/*/})
    
  • 如果数据是可通过 Web 公开访问的单个文件,则可以使用以下代码片段:

    response=$(curl --location --request POST $SCORING_URI \
    --header "Authorization: Bearer $SCORING_TOKEN" \
    --header "Content-Type: application/json" \
    --data-raw "{
        \"properties\": {
            \"InputData\": {
                \"mnistInput\": {
                    \"JobInputType\" : \"UriFile\",
                    \"Uri": \"https://pipelinedata.blob.core.windows.net/sampledata/mnist/0.png\"
    JOB_ID=$(echo $response | jq -r '.id')
    JOB_ID_SUFFIX=$(echo ${JOB_ID##/*/})
    
  • 如果要使用本地数据,可以将其上传到Azure 机器学习已注册的数据存储,并对云数据使用 REST API。
  • 如果对批处理终结点使用现有的 V1 FileDataset,建议将它们迁移到 V2 数据资产,并在调用批处理终结点时直接引用它们。 目前仅支持类型 uri_folderuri_file 的数据资产。 使用 GA CLIv2(2.4.0 及更高版本)或 GA REST API(2022-05-01 及更高版本)创建的批处理终结点不支持 V1 数据集。
  • 还可使用 az ml dataset show 命令和 --query 参数提取从 V1 FileDataset 中提取的数据存储上的 URI 或路径,并将该信息用于调用。
  • 虽然使用早期 API 创建的批处理终结点将继续支持 V1 FileDataset,但我们将使用最新 API 版本添加更多 V2 数据资产支持,以提高可用性和灵活性。 有关 V2 数据资产的详细信息,请参阅使用 SDK v2 处理数据。 有关新的 V2 体验的详细信息,请参阅什么是 v2
  • 配置输出位置并覆盖设置

    默认情况下,批量评分结果存储在工作区的默认 Blob 存储中按作业名称(系统生成的 GUID)命名的某个文件夹内。 可以配置在调用批处理终结点时用于存储评分输出的位置。 使用 OutputData 在 Azure 机器学习已注册的数据存储上配置输出文件路径。 OutputData 具有 JobOutputTypeUri 键。 UriFileJobOutputType 唯一支持的值。 Uri 的语法与 InputData 的语法相同,即都为 azureml://datastores/<datastore-name>/paths/<path-on-datastore>/<file-name>

    下面是用于为批处理评分结果配置输出位置的代码片段示例。

    response=$(curl --location --request POST $SCORING_URI \
    --header "Authorization: Bearer $SCORING_TOKEN" \
    --header "Content-Type: application/json" \
    --data-raw "{
        \"properties\": {
            \"InputData\":
                \"mnistInput\": {
                    \"JobInputType\" : \"UriFolder\",
                    \"Uri": \"azureml://datastores/workspaceblobstore/paths/$ENDPOINT_NAME/mnist\"
            \"OutputData\":
                \"mnistOutput\": {
                    \"JobOutputType\": \"UriFile\",
                    \"Uri\": \"azureml://datastores/workspaceblobstore/paths/$ENDPOINT_NAME/mnistOutput/$OUTPUT_FILE_NAME\"
    JOB_ID=$(echo $response | jq -r '.id')
    JOB_ID_SUFFIX=$(echo ${JOB_ID##/*/})
    

    必须使用唯一的输出位置。 如果输出文件已存在,批量评分作业将失败。

    检查批量评分作业

    批量评分作业通常会花费一段时间来处理整个输入集。 监视作业状态,并在作业完成后检查结果:

    该示例调用批处理终结点的默认部署。 若要调用非默认部署,请使用 azureml-model-deployment HTTP 头,并将值设置为部署名称。 例如,在 curl 中使用 --header "azureml-model-deployment: $DEPLOYMENT_NAME" 参数。

    wait_for_completion $SCORING_URI/$JOB_ID_SUFFIX $SCORING_TOKEN

    检查批量评分结果

    有关检查结果的信息,请参阅检查批量评分结果

    删除批处理终结点

    如果你将来不再使用该批处理终结点,应使用以下命令将其删除(这会删除该批处理终结点和所有基础部署):

    curl --location --request DELETE "https://management.azure.com/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP/providers/Microsoft.MachineLearningServices/workspaces/$WORKSPACE/batchEndpoints/$ENDPOINT_NAME?api-version=$API_VERSION" \ --header "Content-Type: application/json" \ --header "Authorization: Bearer $TOKEN" || true
  • 了解如何部署模型进行批评分
  • 了解如何排查批处理终结点问题
  •