使用 Azure 机器学习大规模训练 PyTorch 模型

适用范围:Python SDK azure-ai-ml v2(当前版本)

本文介绍如何使用 Azure 机器学习 Python SDK v2 来训练、超参数优化和部署 PyTorch 模型。

你将使用示例脚本对鸡和火鸡图像进行分类,以基于 PyTorch 的迁移学习教程构建深度学习神经网络 (DNN)。 迁移学习是一种将解决某个问题时获得的知识应用于虽然不同但却相关的问题的技术。 与从头开始训练相比,迁移学习需要较少的数据、时间和计算资源,从而缩短了训练过程。 有关迁移学习的详细信息,请参阅深度学习与机器学习

无论是从头开始训练深度学习 PyTorch 模型,还是将现有模型引入云中,都请通过 Azure 机器学习使用弹性云计算资源来横向扩展开源训练作业。 你可以通过 Azure 机器学习来构建、部署和监视生产级模型以及对其进行版本控制。

先决条件

  • Azure 订阅。 如果还没有订阅,请创建试用版
  • 使用 Azure 机器学习计算实例或你自己的 Jupyter Notebook 运行本文的代码。
    • Azure 机器学习计算实例 - 无需下载或安装:
      • 完成快速入门:开始使用 Azure 机器学习,以创建一个预加载了 SDK 和示例存储库的专用笔记本服务器。
      • 在工作区的“笔记本”部分的“示例”选项卡下,导航至以下目录来查找已完成且展开的笔记本:SDK v2/sdk/python/jobs/single-step/pytorch/train-hyperparameter-tune-deploy-with-pytorch
    • Jupyter 笔记本服务器:

此外,还可以在 GitHub 示例页上找到本指南的完整 Jupyter 笔记本版本

设置作业

本部分会加载所需的 Python 包、连接到工作区、创建计算资源来运行命令作业,并创建用于运行作业的环境,从而设置作业来进行训练。

连接到工作区

首先,需要连接到你的 Azure 机器学习工作区。 工作区是服务的顶级资源。 它提供了一个集中的位置,用于处理使用 Azure 机器学习时创建的所有项目。

使用 DefaultAzureCredential 来访问工作区。 该凭据应能够处理大多数 Azure SDK 身份验证方案。

如果 DefaultAzureCredential 不适合你,请参阅 azure.identity 包设置身份验证以获取更多可用的凭据。

# Handle to the workspace
from azure.ai.ml import MLClient

# Authentication package
from azure.identity import DefaultAzureCredential

credential = DefaultAzureCredential()

如果你更喜欢使用浏览器进行登录和身份验证,应取消注释以下代码,而是改为使用它。

# Handle to the workspace
# from azure.ai.ml import MLClient

# Authentication package
# from azure.identity import InteractiveBrowserCredential
# credential = InteractiveBrowserCredential()

接下来,通过提供订阅 ID、资源组名称和工作区名称来获取工作区的句柄。 要查找这些参数:

  1. 在 Azure 机器学习工作室工具栏的右上角查找工作区名称。
  2. 选择工作区名称以显示资源组和订阅 ID。
  3. 将资源组和订阅 ID 的值复制到代码中。
# Get a handle to the workspace
ml_client = MLClient(
    credential=credential,
    subscription_id="<SUBSCRIPTION_ID>",
    resource_group_name="<RESOURCE_GROUP>",
    workspace_name="<AML_WORKSPACE_NAME>",
)

运行此脚本会得到一个工作区句柄,你可以使用它来管理其他资源和作业。

注意

创建 MLClient 不会将客户端连接到工作区。 客户端初始化是惰性操作,会等待其所需的首次调用。 在本文中,这发生在计算创建期间。

创建计算资源以运行作业

Azure 机器学习需要计算资源才能运行作业。 此资源可以是具有 Linux 或 Windows OS 的单节点或多节点计算机,也可以是 Spark 等特定计算结构。

在以下示例脚本中,我们预配了 Linux 计算群集。 可以查看 Azure 机器学习定价页面,了解 VM 大小和价格的完整列表。 我们需要对此示例使用 GPU 群集,因此让我们选取一个 STANDARD_NC6 模型并创建一个 Azure 机器学习计算。

from azure.ai.ml.entities import AmlCompute

gpu_compute_taget = "gpu-cluster"

try:
    # let's see if the compute target already exists
    gpu_cluster = ml_client.compute.get(gpu_compute_taget)
    print(
        f"You already have a cluster named {gpu_compute_taget}, we'll reuse it as is."
    )

except Exception:
    print("Creating a new gpu compute target...")

    # Let's create the Azure ML compute object with the intended parameters
    gpu_cluster = AmlCompute(
        # Name assigned to the compute cluster
        name="gpu-cluster",
        # Azure ML Compute is the on-demand VM service
        type="amlcompute",
        # VM Family
        size="STANDARD_NC6",
        # Minimum running nodes when there is no job running
        min_instances=0,
        # Nodes in cluster
        max_instances=4,
        # How many seconds will the node running after the job termination
        idle_time_before_scale_down=180,
        # Dedicated or LowPriority. The latter is cheaper but there is a chance of job termination
        tier="Dedicated",
    )

    # Now, we pass the object to MLClient's create_or_update method
    gpu_cluster = ml_client.begin_create_or_update(gpu_cluster).result()

print(
    f"AMLCompute with name {gpu_cluster.name} is created, the compute size is {gpu_cluster.size}"
)

创建作业环境

运行 Azure 机器学习作业需要一个环境。 Azure 机器学习环境封装了在计算资源上运行机器学习训练脚本所需的依赖项(例如软件运行时和库)。 此环境类似于本地计算机上的 Python 环境。

通过 Azure 机器学习可使用策展(或现成)环境或使用 Docker 映像或 Conda 配置创建自定义环境。 在本文中,请重复使用策展的 Azure 机器学习环境 AzureML-acpt-pytorch-2.2-cuda12.1。 请通过使用 @latest 指令来使用此环境的最新版本。

curated_env_name = "AzureML-pytorch-1.9-ubuntu18.04-py37-cuda11-gpu@latest"

配置并提交训练作业

在本部分,我们首先介绍用于训练的数据。 然后,我们介绍如何使用提供的训练脚本运行训练作业。 请学习如何通过配置用于运行训练脚本的命令来生成训练作业。 然后,请提交训练作业以在 Azure 机器学习中运行它。

获取训练数据

你可以使用此压缩文件中的数据集。 此数据集针对双个类(火鸡和鸡)分别包含了大约 120 个训练图像,每个类有 100 个验证图像。 这些图像是 Open Images v5 Dataset 的子集。 训练脚本 pytorch_train.py 会下载并提取数据集。

准备训练脚本

在先决条件部分,我们提供了训练脚本 pytorch_train.py。 实际上,你应该能够原样获取任何自定义训练脚本,并使用 Azure 机器学习运行它,而无需修改你的代码。

提供的训练脚本会下载数据、训练模型并注册模型。

生成训练作业

现在你已拥有运行作业所需的所有资产,是时候使用 Azure 机器学习 Python SDK v2 进行生成了。 我们为本示例创建一个 command

Azure 机器学习 command 是一种资源,用于指定在云中执行训练代码所需的所有详细信息。 这些详细信息包括输入和输出、要使用的硬件类型、要安装的软件以及代码运行方式。 command 包含用于执行单个命令的信息。

配置命令

请使用常规用途 command 来运行训练脚本并执行所需的任务。 创建一个 command 对象来指定训练作业的配置详细信息。

from azure.ai.ml import command
from azure.ai.ml import Input

job = command(
    inputs=dict(
        num_epochs=30, learning_rate=0.001, momentum=0.9, output_dir="./outputs"
    ),
    compute=gpu_compute_taget,
    environment=curated_env_name,
    code="./src/",  # location of source code
    command="python pytorch_train.py --num_epochs ${{inputs.num_epochs}} --output_dir ${{inputs.output_dir}}",
    experiment_name="pytorch-birds",
    display_name="pytorch-birds-image",
)
  • 此命令的输入包括 epoch 数、学习率、动量和输出目录。
  • 对于参数值:
    1. 提供为运行此命令而创建的计算群集 gpu_compute_target = "gpu-cluster"
    2. 提供前面已初始化的特选环境 AzureML-pytorch-1.9-ubuntu18.04-py37-cuda11-gpu
    3. 如果不使用 Samples 文件夹中已完成的笔记本,请指定 pytorch_train.py 文件的位置。
    4. 配置命令行操作本身 - 在这种情况下,命令为 python pytorch_train.py。 可通过 ${{ ... }} 表示法访问命令中的输入和输出。
    5. 配置显示名称和试验名称等元数据;其中一个试验是一个容器,包含在某个项目上所做的全部迭代。 在同一试验名称下提交的所有作业将在 Azure 机器学习工作室中彼此相邻地列出。

提交作业

现在可以提交要在 Azure 机器学习中运行的作业。 这次在 ml_client.jobs 上使用 create_or_update

ml_client.jobs.create_or_update(job)

完成后,该作业会在工作区中注册一个模型(这是训练的结果),并输出一个在 Azure 机器学习工作室中查看该作业的链接。

警告

Azure 机器学习通过复制整个源目录来运行训练脚本。 如果你有不想上传的敏感数据,请使用 .ignore 文件或不将其包含在源目录中。

在作业执行过程中发生的情况

执行作业时,会经历以下阶段:

  • 准备:根据所定义的环境创建 docker 映像。 将映像上传到工作区的容器注册表,缓存以用于后续运行。 还会将日志流式传输到作业历史记录,可以查看日志以监视进度。 如果指定策展环境,则使用支持该策展环境的缓存映像。

  • 缩放:如果群集执行运行所需的节点多于当前可用节点,则该群集将尝试纵向扩展。

  • 运行:脚本文件夹 src 中的所有脚本都上传到计算目标,装载或复制数据存储,然后执行脚本。 stdout 和 ./logs 文件夹中的输出会流式传输到作业历史记录,并可用于监视作业。

优化模型超参数

你已使用一组参数训练模型,现在看看是否可以进一步提高模型的准确性。 可使用 Azure 机器学习的 sweep 功能调整和优化模型的超参数。

要调整模型的超参数,请定义要在训练期间搜索的参数空间。 为此,请使用 azure.ml.sweep 包中的特殊输入替换传递给训练作业的一些参数。

由于训练脚本使用学习速率计划每隔几个周期衰减一次学习速度,因此你可以优化初始学习速率和动量参数。

from azure.ai.ml.sweep import Uniform

# we will reuse the command_job created before. we call it as a function so that we can apply inputs
job_for_sweep = job(
    learning_rate=Uniform(min_value=0.0005, max_value=0.005),
    momentum=Uniform(min_value=0.9, max_value=0.99),
)

然后,可以在命令作业上配置扫描,使用一些特定于扫描的参数,例如要监视的主要指标和要使用的采样算法。

在以下代码中,我们使用随机采样来尝试不同的超参数配置集,以尝试最大化我们的主要指标 best_val_acc

我们还定义了提前终止策略 BanditPolicy,以提前终止表现不佳的运行。 BanditPolicy 会终止任何不属于主要评估指标松弛因子的运行。 请在每个周期应用此策略(因为我们在每个周期报告 best_val_acc 指标,并且 evaluation_interval=1)。 请注意,我们会将首次策略评估延迟到完成前 10 个周期 (delay_evaluation=10) 之后。

from azure.ai.ml.sweep import BanditPolicy

sweep_job = job_for_sweep.sweep(
    compute="gpu-cluster",
    sampling_algorithm="random",
    primary_metric="best_val_acc",
    goal="Maximize",
    max_total_trials=8,
    max_concurrent_trials=4,
    early_termination_policy=BanditPolicy(
        slack_factor=0.15, evaluation_interval=1, delay_evaluation=10
    ),
)

现在,可以像之前一样提交此作业。 这一次,请运行一个扫描作业来扫描训练作业。

returned_sweep_job = ml_client.create_or_update(sweep_job)

# stream the output and wait until the job is finished
ml_client.jobs.stream(returned_sweep_job.name)

# refresh the latest status of the job after streaming
returned_sweep_job = ml_client.jobs.get(name=returned_sweep_job.name)

可使用在作业运行期间显示的工作室用户界面链接来监视作业。

找到最佳模型

所有运行完成后,可以找到生成具有最高准确度的模型的运行。

from azure.ai.ml.entities import Model

if returned_sweep_job.status == "Completed":

    # First let us get the run which gave us the best result
    best_run = returned_sweep_job.properties["best_child_run_id"]

    # lets get the model from this run
    model = Model(
        # the script stores the model as "outputs"
        path="azureml://jobs/{}/outputs/artifacts/paths/outputs/".format(best_run),
        name="run-model-example",
        description="Model created from run.",
        type="custom_model",
    )

else:
    print(
        "Sweep job status: {}. Please wait until it completes".format(
            returned_sweep_job.status
        )
    )

将模型部署为联机终结点

现在可将模型部署为联机终结点,即部署为 Azure 云中的 Web 服务。

若要部署机器学习服务,通常需要:

  • 要部署的模型资产。 这些资产包括已在训练作业中注册的模型文件和元数据。
  • 一些要作为服务运行的代码。 这些代码根据给定的输入请求(入口脚本)执行模型。 该入口脚本接收提交到已部署的 Web 服务的数据,并将此数据传递给模型。 模型处理数据后,脚本会将模型的响应返回到客户端。 该脚本特定于你的模型,并且必须识别模型需要和返回的数据。 使用 MLFlow 模型时,Azure 机器学习会自动为你创建此脚本。

有关部署的详细信息,请参阅使用 Python SDK v2 部署使用托管联机终结点的机器学习模型并为其评分

创建新的联机终结点

部署模型的第一步是,需要创建联机终结点。 终结点名称在整个 Azure 区域中必须是唯一的。 在本文中,请使用通用唯一标识符 (UUID) 创建唯一名称。

import uuid

# Creating a unique name for the endpoint
online_endpoint_name = "aci-birds-endpoint-" + str(uuid.uuid4())[:8]
from azure.ai.ml.entities import ManagedOnlineEndpoint

# create an online endpoint
endpoint = ManagedOnlineEndpoint(
    name=online_endpoint_name,
    description="Classify turkey/chickens using transfer learning with PyTorch",
    auth_mode="key",
    tags={"data": "birds", "method": "transfer learning", "framework": "pytorch"},
)

endpoint = ml_client.begin_create_or_update(endpoint).result()

print(f"Endpoint {endpoint.name} provisioning state: {endpoint.provisioning_state}")

创建终结点后,可按如下方式检索它:

endpoint = ml_client.online_endpoints.get(name=online_endpoint_name)

print(
    f'Endpint "{endpoint.name}" with provisioning state "{endpoint.provisioning_state}" is retrieved'
)

将模型部署到终结点

现在可以使用入口脚本来部署模型。 一个终结点可以有多个部署。 然后,终结点可使用规则将流量定向到这些部署。

在以下代码中,你将创建单个部署来处理 100% 的传入流量。 我们为部署指定了任意颜色名称“aci-blue”。 还可对部署使用任何其他名称,例如 aci-green 或 aci-red。

用于将模型部署到终结点的代码:

  • 部署之前注册的模型的最佳版本。
  • 使用 score.py 文件对模型进行评分。
  • 使用前面指定的特选环境执行推理。
from azure.ai.ml.entities import (
    ManagedOnlineDeployment,
    Model,
    Environment,
    CodeConfiguration,
)

online_deployment_name = "aci-blue"

# create an online deployment.
blue_deployment = ManagedOnlineDeployment(
    name=online_deployment_name,
    endpoint_name=online_endpoint_name,
    model=model,
    environment=curated_env_name,
    code_configuration=CodeConfiguration(code="./score/", scoring_script="score.py"),
    instance_type="Standard_NC6s_v3",
    instance_count=1,
)

blue_deployment = ml_client.begin_create_or_update(blue_deployment).result()

注意

预计此部署需要一些时间才能完成。

测试已部署的模型

现在你已将模型部署到终结点后,接下来可对终结点使用 invoke 方法来预测已部署模型的输出。

为了测试终结点,让我们使用示例图像进行预测。 首先让我们显示图像。

# install pillow if PIL cannot imported
# %pip install pillow
import json
from PIL import Image
import matplotlib.pyplot as plt

%matplotlib inline
plt.imshow(Image.open("test_img.jpg"))

创建一个函数来设置图像的格式并调整其大小。

# install torch and torchvision iof needed
#%pip install torch
#%pip install torchvision

import torch
from torchvision import transforms


def preprocess(image_file):
    """Preprocess the input image."""
    data_transforms = transforms.Compose(
        [
            transforms.Resize(256),
            transforms.CenterCrop(224),
            transforms.ToTensor(),
            transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]),
        ]
    )

    image = Image.open(image_file)
    image = data_transforms(image).float()
    image = torch.tensor(image)
    image = image.unsqueeze(0)
    return image.numpy()

设置图像的格式并将其转换为 JSON 文件。

image_data = preprocess("test_img.jpg")
input_data = json.dumps({"data": image_data.tolist()})
with open("request.json", "w") as outfile:
    outfile.write(input_data)

然后,可以使用此 JSON 调用终结点并输出结果。

# test the blue deployment
result = ml_client.online_endpoints.invoke(
    endpoint_name=online_endpoint_name,
    request_file="request.json",
    deployment_name=online_deployment_name,
)

print(result)

清理资源

如果不再需要此终结点,请将其删除以停止使用资源。 在删除终结点之前,请确保没有其他任何部署正在使用该终结点。

ml_client.online_endpoints.begin_delete(name=online_endpoint_name)

注意

预计此清理需要一些时间才能完成。

后续步骤

在本文中,你使用 Azure 机器学习中的 PyTorch 训练并注册了一个深度学习神经网络。 你还将该模型部署到了联机终结点。 有关 Azure 机器学习的详细信息,请参阅以下其他文章。