65.9K
CodeProject 正在变化。 阅读更多。
Home

在 Azure 上进行 Python 机器学习,第 1 部分:使用 Python、VS Code 和 Azure ML 创建 XGBoost 模型

starIconstarIconstarIconstarIconstarIcon

5.00/5 (2投票s)

2022年1月12日

CPOL

11分钟阅读

viewsIcon

9126

如何使用 Visual Studio Code 和机器学习扩展在 Azure 上训练 XGBoost 模型。

机器学习(ML)和数据科学的日益普及和盛行有目共睹。这一趋势是 Python 爆炸式流行的最大驱动力之一。截至 2021 年,Python 语言的流行度已正式超过 Java、C# 或 C++ 等久负盛名的老牌语言。它在 11 月的 TIOBE 指数中夺得第一名,并在 Stack Overflow 的 2021 年开发者调查中成为第三大最受欢迎的编程语言。当你想到机器学习代码时,你很可能就会想到 Python。

你几乎可以在任何设备上运行 Python 代码:PC、Mac 或树莓派(Raspberry Pi),使用 x86、x86-64、AMD64 或 ARM/ARM64 处理器,以及 Windows、Linux 或 macOS 操作系统。然而,机器学习通常需要强大的处理能力,这可能超出了你手头任何一台计算机的能力。Azure 是一个绝佳的平台,可以运行几乎任何规模的基于 Python 的机器学习工作负载。

在这个由三部分组成的系列中,我们将探讨几种在 Azure 上使用 Python 创建和使用机器学习模型的方法。你可以在 GitHub 上找到本文的示例代码。

我们将首先使用 XGBoost 库和 Azure 机器学习服务来训练和测试模型。而且,我们将(几乎)所有操作都在 Visual Studio Code 中完成,以使流程更加简化。

问题和数据集

本教程将使用著名的 MNIST 数据集来训练模型识别手写数字。为了更具通用性,我们不会依赖该数据集的现成版本,尽管它在许多框架中都可用。相反,我们将以一种你可以适用于任何你选择的图像分类任务的方式来使用它。

必备组件

要学习本文中的示例,你需要 Visual Studio Code、一个较新的 Python 版本,以及用于 Python 包管理的 Conda。如果你没有其他偏好,可以从 Miniconda 和 Python 3.9 开始。

安装 Python 和 Conda 后,创建并激活一个新环境。

$ conda create -n azureml python=3.9
$ conda activate azureml

此外,你还需要一个 Azure 订阅。如果你还没有,请注册一个免费的 Azure 帐户。

下载 MNIST 数据集

首先从微软的 Azure 开放数据集下载 MNIST 数据集。

import os
import urllib.request

然后,将以下代码保存到一个名为 download-dataset.py 的文件中。

DATA_FOLDER = 'datasets/mnist-data'
DATASET_BASE_URL = 'https://azureopendatastorage.blob.core.windows.net/mnist/'

os.makedirs(DATA_FOLDER, exist_ok=True)

urllib.request.urlretrieve(
    os.path.join(DATASET_BASE_URL, 'train-images-idx3-ubyte.gz'),
    filename=os.path.join(DATA_FOLDER, 'train-images.gz'))
urllib.request.urlretrieve(
    os.path.join(DATASET_BASE_URL, 'train-labels-idx1-ubyte.gz'),
    filename=os.path.join(DATA_FOLDER, 'train-labels.gz'))
urllib.request.urlretrieve(
    os.path.join(DATASET_BASE_URL, 't10k-images-idx3-ubyte.gz'),
    filename=os.path.join(DATA_FOLDER, 'test-images.gz'))
urllib.request.urlretrieve(
    os.path.join(DATASET_BASE_URL, 't10k-labels-idx1-ubyte.gz'),
    filename=os.path.join(DATA_FOLDER, 'test-labels.gz'))

你可以使用以下命令运行该代码。

$ python download-dataset.py

为机器学习准备 Visual Studio Code

Azure 机器学习是为端到端机器学习生命周期提供的一系列云服务和工具。为了更方便地在 Visual Studio Code 中使用它,我们可以使用一个新的专用扩展。

首先,点击 Visual Studio Code 侧边栏中的扩展图标。

现在,搜索并安装 Azure Machine Learning 扩展。

安装并激活扩展后(这可能需要重启 Visual Studio Code),侧边栏会出现一个新的 Azure 图标。

此外,我们还需要版本大于或等于 2.15.0 的 Azure 命令行工具 (azure-cli) 及其机器学习扩展。在撰写本文时,其版本为 2.0.2。要使用这些工具,请输入以下命令:

$ az extension add -n ml -y

准备 Azure ML 工作区

现在我们可以开始配置我们的 Azure 资源了。首先,我们需要 Azure 机器学习工作区。接下来,我们在工作区内创建一个数据集、一个用于处理工作的计算集群以及训练作业。

我们使用已安装的 Azure Machine Learning 扩展来开始设置 Azure。

登录 Azure 帐户(或创建一个新帐户)后,我们会看到我们的订阅名称以及创建(机器学习)工作区的选项。

在本例中,在一个名为 azureml-rg 的新资源组中,创建一个名为 demo-ws 的新工作区,并选择离你最近的位置。这里我们选择了“西欧”。成功创建后,该工作区应显示在我们的订阅正下方。

当我们第一次尝试使用 Azure Machine Learning 扩展进行任何操作时,Visual Studio Code 会要求我们选择一个默认工作区。

不要忽略这个提示。如果没有默认工作区,大多数机器学习扩展的功能将无法工作,而且我们有时也得不到有意义的错误消息。如果你错过了这个提示,你随时可以手动设置默认工作区。一种方法是使用 Cmd/Ctrl+Shift+P,然后选择 Azure ML: Set Default Workspace 命令。

或者,你可以在 .vscode/settings.json 文件中设置默认工作区。

{
    "azureML.defaultWorkspaceId": "/subscriptions/<your-subscription-id>
    /resourceGroups/azureml-rg/providers/Microsoft.MachineLearningServices/workspaces/demo-ws"
}

在某些情况下,你可能需要重启 Visual Studio Code 才能使此更改生效(毕竟该扩展仍处于预览阶段)。

选择默认工作区后,你可以在 Azure: Machine Learning 扩展列表中看到它。

将数据集上传到机器学习工作区

现在我们可以开始使用我们的工作区了。任何机器学习项目首先需要的就是数据。在 Azure: Machine Learning 工作区中处理数据的首选方法是将其注册为数据集。

使用 Visual Studio Code 扩展点击 demo-ws 工作区的 Datasets 节点,然后点击加号 (+)。作为响应,Azure Machine Learning 扩展会生成一个数据集定义模板。

自动生成的模板与可接受的模式不兼容,后者不再支持 datastore 属性。不幸的是,在试用预览版代码时,我们可能会遇到这种情况。不过,我们可以轻松地创建一个正确的数据集定义,将我们之前下载的数据集文件上传到 Azure: Machine Learning

aml-mnist-dataset.yml 文件应包含以下内容:

$schema: https://azuremlschemas.azureedge.net/latest/dataset.schema.json
name: mnist-dataset
version: 1
local_path: datasets/mnist-data

现在,如果我们点击右上角的小图标(下面截图中红色矩形内),Azure Machine Learning 扩展应该会自动生成并执行正确的 azure-cli 命令。

如果这不起作用,请确保你已设置了默认的 Azure: Machine Learning 工作区。这里的错误消息可能很模糊。或者,你总是可以直接使用 Azure CLI。

$ export SUBSCRIPTION="<your-subscription-id>"
$ export GROUP="azureml-rg"
$ export WORKSPACE="demo-ws"

$ az ml dataset create --file aml-mnist-dataset.yml --subscription $SUBSCRIPTION 
  --resource-group $GROUP --workspace-name $WORKSPACE

选择计算选项

除了数据,我们还需要一个计算资源来运行我们的训练代码。如果我们在 demo-ws 工作区中展开 Compute 节点,可以看到几个选项:计算实例、计算集群、推理集群和附加的计算机。

我们使用计算实例来运行完整的实验环境——例如,在 JupyterLab 中使用 Jupyter notebook。我们将在本系列的第三篇文章中使用一个。

我们可以使用推理集群来处理对已训练和保存的模型的预测。附加的计算机允许使用现有的 Azure 资源而不是创建新的。我们没有任何现有的资源(虚拟机、HDInsight、Databricks 或 Kubernetes 集群),所以我们将创建一个新的计算集群。这类集群可以根据当前需求动态地扩展和缩减。这是一个很有用的功能,让我们只需为我们需要的计算资源付费。

如果我们点击 Compute clusters 节点右侧的加号 (+),我们会得到一个相对简短且不太有用的模板。

幸运的是,通过对引用的 JSON 模式以及 AmlCompute 类文档进行简短研究,我们就能将其填写完整。

$schema: https://azuremlschemas.azureedge.net/latest/compute.schema.json
name: ami-comp-cpu-01
type: amlcompute
size: Standard_DS3_v2
min_instances: 0
max_instances: 1
idle_time_before_scale_down: 3600
location: westeurope

你可以选择自己的值,例如名称、大小、实例数量等。在上面的例子中,我们确保最多只运行一台相对较小的虚拟机。这对我们的目的来说绰绰有余,但对于更大的模型,你可能需要从可用大小中选择一个大得多的配置。

与数据集一样,如果点击右上角的蓝色符号不起作用,我们可以直接使用 Azure CLI。如果我们将计算定义保存到 aml-compute-cpu.yml 文件中,命令应该如下所示:

$ az ml compute create --file aml-compute-cpu.yml --subscription $SUBSCRIPTION 
--resource-group $GROUP --workspace-name $WORKSPACE

暂时不用担心 Azure 的费用。只要你将 `min_instances` 变量设置为 `0`,运行此脚本只会创建计算定义,而不会创建计算虚拟机本身。

准备训练代码

在配置好我们的数据集和计算资源后,我们终于可以准备我们的训练代码了。我们将训练代码存储在 code/train.py 文件中。

通常,我们从导入开始:

import os
import argparse
import gzip
import struct
import mlflow
import numpy as np
from azureml.core import Run
from azureml.core.model import Model
import xgboost as xgb
from sklearn.metrics import accuracy_score

然后,我们定义辅助方法来处理 Azure: Machine Learning 工作区和参数解析。在我们的例子中,我们只有一个参数 `data`,它包含了我们数据集文件的路径。

def get_aml_workspace():
    run = Run.get_context()
    ws = run.experiment.workspace
    return ws

def parse_arguments():
    parser = argparse.ArgumentParser()

    parser.add_argument('--data', type=str, required=True)
    args = parser.parse_known_args()[0]

    return args

现在,我们可以定义数据集加载方法。这个方法是特定于数据集的,我们主要借鉴了 Azure 开放数据集的示例。当然,当你使用自己的数据时,你需要替换它。

def load_dataset(dataset_path):
    def unpack_mnist_data(filename: str, label=False):
        with gzip.open(filename) as gz:
            struct.unpack('I', gz.read(4))
            n_items = struct.unpack('>I', gz.read(4))
            if not label:
                n_rows = struct.unpack('>I', gz.read(4))[0]
                n_cols = struct.unpack('>I', gz.read(4))[0]
                res = np.frombuffer(gz.read(n_items[0] * n_rows * n_cols), dtype=np.uint8)
                res = res.reshape(n_items[0], n_rows * n_cols) / 255.0
            else:
                res = np.frombuffer(gz.read(n_items[0]), dtype=np.uint8)
                res = res.reshape(-1)
        return res
   
    X_train = unpack_mnist_data(os.path.join(dataset_path, 'train-images.gz'), False)
    y_train = unpack_mnist_data(os.path.join(dataset_path, 'train-labels.gz'), True)
    X_test = unpack_mnist_data(os.path.join(dataset_path, 'test-images.gz'), False)
    y_test = unpack_mnist_data(os.path.join(dataset_path, 'test-labels.gz'), True)

     return X_train, y_train, X_test, y_test

接下来,我们可以添加训练和保存模型的方法。为了缩短训练时间,我们减少了 `max_depth` 和 `n_estimators` 参数的值。当然,这种减少会对我们模型的质量产生负面影响,所以如果你希望获得更好的结果,可以随意尝试这些值。

def create_model():
    return xgb.XGBClassifier(use_label_encoder=False, max_depth=3, n_estimators=10)

def train_model(X, y, model_filename):   
    model = create_model()
    model.fit(X, y, eval_metric='mlogloss', verbose=True)
    model.save_model(model_filename)

训练之后,我们使用测试数据来评估模型。下面的代码演示了如何加载和使用我们的模型进行推理。

def evaluate_model(X, y, model_filename):
    model = create_model()
    model.load_model(model_filename)
    preds = model.predict(X)
    accscore = accuracy_score(y, preds)
    mlflow.log_metric('accuracy', accscore)

请注意最后一条语句中使用了 MLflow 日志记录。这是推荐的方法,它允许在云端和本地运行中使用相同的代码。

训练后,我们可以注册模型以备将来使用。

def register_model(ws, model_filename):
    model = Model.register(
        workspace=ws,
        model_name=model_filename,
        model_path=model_filename
    )

所有部分都准备好后,我们现在将它们组合在一起。

def main():
    args = parse_arguments()

    ws = get_aml_workspace()
    mlflow.set_tracking_uri(ws.get_mlflow_tracking_uri())
    mlflow.start_run()

    X_train, y_train, X_test, y_test = load_dataset(args.data)

    model_filename = "mnist.xgb_model"
    train_model(X_train, y_train, model_filename)
    evaluate_model(X_test, y_test, model_filename)
    register_model(ws, model_filename)
   
if __name__ == "__main__":
    main()

确定训练作业的环境

我们有了数据、计算定义和训练代码。要运行代码,我们必须决定使用哪个环境。我们可以使用自定义的 Conda 环境或 Docker 镜像。或者,我们可以使用微软创建和策划的环境之一。在我们的例子中,我们选择后者。

如果你决定使用带 GPU 的计算集群,请记住选择一个支持 GPU 和 Nvidia CUDA 驱动的环境。否则,你将为无法使用的 GPU 时间付费。

要开始创建我们的训练作业定义,我们点击 Visual Studio Code 机器学习扩展的 Experiments 节点。然后我们选择 Command Job。它会创建以下模板:

除了 Command Jobs,我们还可以创建 Sweep JobPipeline JobSweep Jobs 通过运行多个具有预定义范围内各种值的实验来自动搜索最佳超参数。Pipeline Job 允许我们创建复杂的多步骤实验。在我们的例子中,一个简单的 Command Job 就足够了。

为了定义我们的训练,我们用以下内容填充模板:

$schema: https://azuremlschemas.azureedge.net/latest/commandJob.schema.json

code:
  local_path: code/train

command: python train.py --data ${{inputs.mnist_data}}

environment: azureml:AzureML-lightgbm-3.2-ubuntu18.04-py37-cpu:12

compute: azureml:aml-comp-cpu-01

inputs:
  mnist_data:
     dataset: azureml:mnist-dataset:1
     mode: ro_mount

experiment_name: my-mnist-experiment

aml-job-train.yml 文件中,我们设置了训练代码的路径并定义了运行它的命令。我们还选择了一个要使用的策划环境:AzureML-lightgbm-3.2-ubuntu18.04-py37-cpu:12,它拥有我们需要的所有依赖项。

我们选择想要使用的计算定义,并定义输入参数 (`inputs`/`mnist_data`)。请注意数据集的显式版本。我们使用 (`inputs`/`mnist_data`/`dataset: azureml:mnist-dataset:1`)。你可以删除 `:1` 后缀以使用最新版本,或在需要时更新此值。

现在我们准备好训练了!

开始模型训练

与之前的所有步骤一样,要开始训练,我们可以依赖 Visual Studio Code 机器学习扩展,或者我们可以直接使用 Azure CLI 运行代码。

$ az ml job create --file aml-job-train.yml --subscription $SUBSCRIPTION 
--resource-group $GROUP --workspace-name $WORKSPACE

如果我们使用扩展执行作业,我们会在日志中得到 RunId (guid) 和 WebView URL,格式如下:https://ml.azure.com/runs/<run_id>?wsid=/subscriptions/<subscription_id>/resourcegroups/azureml-rg/workspaces/demo-ws

点击此链接会将我们带到 ml.azure.com 控制台中我们的运行页面。

在我们的简单案例中,训练本身不会花费很长时间。最长的时间很可能是在准备计算资源。不过,如果我们使用自定义环境,时间可能会长得多,因为我们必须在首次使用前构建其镜像。

正如之前承诺的,我们也可以在不离开 Visual Studio Code 的情况下监控我们作业的进度。例如,日志可以直接在 Studio 的 Experiments 节点下访问。

如果你是 Azure 机器学习的新手,日志文件的数量可能会让你感到困惑。如果一切顺利,最重要的文件是 70_driver_log.txt。它包含了在计算实例上运行的训练代码生成的所有日志、控制台输出和错误。

请注意,根据你所在 Azure 区域的部署情况,你可能需要使用不同的 Azure ML 运行时,其日志文件结构也不同,来处理你的训练。如果你更喜欢旧版本,请确保将以下几行添加到你的训练作业定义中。

environment_variables:
  AZUREML_COMPUTE_USE_COMMON_RUNTIME: "false"

当训练作业完成时,我们应该能看到新注册的模型,或者每次运行后的模型版本。

让我们回到 Microsoft Azure Machine Learning Studio 门户网站。我们可以检查其他细节,包括我们的模型在测试数据集上的准确率,这个准确率是在训练结束时记录的。

结果还不错,但远未达到顶尖水平(即 1.0)。不过,我们要记住,我们使用的是一个配置受限的简单模型。我们相信你不需要花费太多精力就可以显著地改进它!

后续步骤

本文展示了如何在不离开 Visual Studio Code 的情况下,使用 Azure 云训练 XGBoost 模型来识别手写数字。如果你用其他图像替换 MNIST 数据集,你可以使用这种方法来训练任何图像分类任务。然而,XGBoost 模型可能不是做这件事的最佳模型。

下一篇文章将向你展示如何使用自定义的 PyTorch 模型做类似的事情,即使你没有 Visual Studio Code 也可以。

要了解开始使用 Azure Machine Learning 所需的所有内容,请查看快速入门:创建工作区资源

© . All rights reserved.