Azure 数据科学助理认证指南(二)

原文:annas-archive.org/md5/41ac68e0c7679ad41531572416d7e2b8

译者:飞龙

协议:CC BY-NC-SA 4.0

第三部分:高级数据科学工具和功能

在本节中,您将深入了解Azure 机器学习AzureML)Python SDK。该 SDK 允许您使用 Python 代码配置工作区并协调端到端的数据科学流程。在这里,您将更深入地了解 AzureML 平台的运作方式,这对于通过 DP-100 考试至关重要。

本节包含以下章节:

  • 第七章*,AzureML Python SDK*

  • 第八章*,使用 Python 代码进行实验*

  • 第九章,优化机器学习模型

  • 第十章*,理解模型结果*

  • 第十一章*,使用管道*

  • 第十二章*,通过代码实现模型操作*

第七章:第七章:AzureML Python SDK

本章中,你将了解 AzureML Python 软件开发工具包SDK)的结构,以及如何使用它,这对 DP-100 考试至关重要。你将学习如何使用内建于 AzureML Studio 网页门户中的笔记本功能,这是一个提高编码生产力的工具。使用笔记本编辑器,你将编写一些 Python 代码,更好地理解如何管理工作区中注册的计算目标、数据存储和数据集。最后,你将重新访问在 第二章中讨论过的 Azure CLI, 部署 Azure 机器学习工作区资源,通过 AzureML 扩展来执行工作区管理操作。这将允许你编写脚本并自动化工作区管理活动。

本章将涵盖以下主要主题:

  • Python SDK 概述

  • 使用 AzureML 笔记本

  • 使用 AzureML SDK 的基础编码

  • 使用 AzureML CLI 扩展

技术要求

你需要访问一个 Azure 订阅。在该订阅中,你需要一个packt-azureml-rg。你还需要拥有ContributorOwner权限的packt-learning-mlw,如 第二章中所述, 部署 Azure 机器学习工作区资源

你还需要具备基础的Python语言知识。本章中的代码片段适用于 Python 3.6 或更高版本。你应该了解 Jupyter 笔记本的基本工作原理,以及你在某个单元中定义的变量如何在其他单元的执行上下文中存在。

你可以在 GitHub 上找到本章的所有笔记本和代码片段,链接为bit.ly/dp100-ch07

Python SDK 概述

AzureML SDK是一个 Python 库,可以让你与 AzureML 服务进行交互。它还为你提供了数据科学模块,帮助你在机器学习过程中取得进展。AzureML SDK 通过一个 Python 与 R 的互操作包在 R 编程语言中也可用。

SDK 由多个包组成,这些包将不同类型的模块组织在一起,你可以将这些模块导入到代码中。所有 Microsoft 支持的模块都位于以azureml开头的包中,如azureml.coreazureml.train.hyperdrive。下图提供了 AzureML SDK 中最常用包的广泛概览,以及你将在本书和考试中看到的关键模块:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_001.jpg

图 7.1 – AzureML SDK 模块和重要类

请注意,azureml.core包中所有的关键类也可以从相应的子模块导入。例如,Experiment类可以通过以下两种方式导入:

from azureml.core import Experiment
from azureml.core.experiment import Experiment

这两个代码片段将加载相同的类,您只需要使用其中一个。第一个从 azureml.core 软件包加载类,而第二个从 experiment 模块(一个名为 experiment.py 的文件)加载类,该模块是 azureml.core 软件包的一部分。如果您在阅读各种代码示例时注意到这种类型的差异,请不要感到惊讶。

重要提示

在考试中,您无需记住这些软件包,但您需要从下拉列表中选择合适的一个。例如,您可能会被要求完成一些引用 AutoMLConfig 的代码,而您可能需要在 azureml.automl 软件包和 azureml.pipeline 软件包之间进行选择,这个选择在阅读完接下来的几章后会变得更加明显。书中的所有代码示例都会在脚本的顶部导入所有所需的软件包,帮助您熟悉类的位置。

在本章中,您将重点学习 SDK 类,这些类允许您控制 AzureML 工作区,以及在工作区中部署的计算资源、数据存储区和您可以在工作区中注册的数据集。

在接下来的部分,您将学习如何利用 AzureML Studio 内置的 笔记本 体验来编写 Python 脚本。

在 AzureML 笔记本中工作

AzureML Studio 提供与多个代码编辑器的集成,允许您编辑笔记本和 Python 脚本。这些编辑器由您在 第四章 中配置的计算实例提供支持,配置工作区。如果您为了节省费用停止了该计算实例,请导航至 管理 | 计算 并启动它。从此视图,您可以打开所有与 AzureML Studio 集成的第三方代码编辑器,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_002.jpg

图 7.2 – Azure Studio 集成的第三方代码编辑器列表

最广为人知的开源数据科学编辑器是 Jupyter Notebook 及其更新版本 JupyterLab。您可以通过点击前面截图中显示的相应链接打开这些编辑环境。这将打开一个新的浏览器标签页,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_003.jpg

图 7.3 – 计算实例提供的 JupyterLab 和 Jupyter 编辑体验

除了这些第三方代码编辑体验外,AzureML Studio 还提供了一个内置的增强型笔记本编辑器,允许你在 Studio 界面内编辑、共享和协作,如下图所示。这个编辑器建立在 Jupyter Notebook 服务之上,但提供了更改进的代码编辑体验,比如内联错误高亮、自动代码补全、弹出窗口显示即将调用的方法的参数信息等其他功能,这些功能统称为IntelliSense

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_004.jpg

图 7.4 – 内置于 AzureML Studio 中的增强型笔记本体验

笔记本编辑器带有一个嵌入式示例库,其中包含最新的笔记本目录,展示了最新 AzureML SDK 几乎所有的功能。一旦你找到相关的笔记本,你可以查看其内容,如果你想修改它,可以将其克隆到你的工作区,这个操作会复制 Jupyter 笔记本及与该笔记本相关的脚本和数据,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_005.jpg

图 7.5 – 帮助你快速掌握 AzureML SDK 功能的示例笔记本

重要提示

这些笔记本已更新为最新版本的 AzureML SDK。这些笔记本所在的代码库可以在 GitHub 上找到,网址为github.com/Azure/MachineLearningNotebooks/。你可以使用 GitHub 提交问题或通过 GitHub 的搜索功能查找代码片段。

每个 AzureML 工作区都配有一个存储帐户,正如在第二章中提到的,部署 Azure 机器学习工作区资源。此存储帐户包含一个以code-为前缀的文件共享,该共享托管工作区内所有可用的笔记本和脚本,如下图所示。你在 Studio 体验中看到的文件,就是存储在该文件共享位置中的文件,在Files选项卡中:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_006.jpg

图 7.6 – Azure 门户视图,显示托管所有 AzureML 工作区代码文件的文件共享

每个用户在Users文件夹下都有一个单独的文件夹,用于组织他们的文件。所有具有特定 AzureML 工作区访问权限的用户都可以访问这些文件。这使得代码共享变得非常容易。你可以通过在浏览器中打开文件,将其指向具有 AzureML 工作区访问权限的某个人;然后,你可以分享浏览器导航栏中的 URL。

在本节中,您将创建一个笔记本,在其中编写和执行本章中的代码片段。要处理您的文件,请导航到chapter07,然后创建一个名为chapter07.ipynb的笔记本。

点击用户名旁边的三个点,如下截图所示。从那里,您可以创建文件夹结构并从本地计算机上传文件。点击创建新文件夹选项,如下截图所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_007.jpg

图 7.7 – 在 AzureML Studio 的 Notebooks 体验区域中创建新文件夹选项

填写弹出的对话框以创建名为chapter07的文件夹。选择该文件夹,然后点击三个点。然后,选择Users/<username>/chapter07,这意味着该文件将放置在新创建的文件夹中。关于chapter07.ipynb并点击Create按钮,如下截图所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_008.jpg

图 7.8 – 创建笔记本以编写和执行本章 Python 脚本

这将在您的文件夹中创建两个文件:笔记本文件,将在编辑器窗格中打开,以及一个.amlignore文件,您将在第八章使用 Python 代码进行实验中详细了解该文件:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_009.jpg

图 7.9 – 在 AzureML Studio 中编辑笔记本

从前述截图的左侧开始,Notebooks 体验提供以下内容:

  1. 文件资源管理器,您可以在其中创建或上传新文件,并删除、下载、重命名或移动您或您的同事在此工作区中创建的现有文件。

  2. 正在打开文件的名称。请注意,如果您在名称旁边看到一个星号 – 例如,*** chapter07.ipynb** – 这意味着该文件尚未保存。您可以使用 Windows 和 Linux 的Ctrl + S快捷键或 macOS 的Cmd + S快捷键保存该文件。或者,您可以从文件选项菜单中选择保存选项,您将在下面阅读到。

  3. 文件选项菜单,提供保存操作和焦点模式等选项,焦点模式会将编辑器面板扩展到浏览器标签的大部分空间。这是一个动态菜单,取决于你当前正在编辑的文件类型。在前面的截图中,打开的是一个笔记本,菜单提供了其他操作,如清除输出、重启 Python 内核或查看当前加载的 Python 内核中的变量。你还可以通过点击菜单图标(即四个垂直线的图标)并从编辑器选项中选择相应的编辑器来在 Jupyter 或 JupyterLab 中编辑同一文件。特别是对于 VS Code,一个非常流行的跨平台免费代码编辑器,主栏中提供了在 VS Code 中编辑的选项。

  4. 管理当前正在编辑特定文件的计算实例的能力。在此部分,你可以快速创建一个新的计算实例或启动/停止现有的实例。

  5. 选择执行笔记本的环境的能力。默认情况下,选择的是 AzureML Python 内核,这是已安装 AzureML SDK 的环境。如果你正在编辑 R 文件,可以将内核更改为 R 内核,或者如果你想自定义工作环境,也可以创建自己的内核。

  6. 主编辑器面板。这是你可以修改选定文件的地方。

    在你的情况下,编辑器面板将为空,且只会显示一个空单元格,如下图所示。每个单元格可以包含Markdown格式的文本或 Python 代码。你可以通过点击弹出菜单并选择M****↓图标来将单元格转换为代码单元:

    https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_010.jpg

    图 7.10 – 一个空的代码单元格

  7. 点击M****↓图标,然后点击编辑图标,在单元格中添加以下 Markdown 文本:

    # Chapter 07 code snippets
    This notebook contains all code snippets from chapter 7.
    
  8. Shift + Enter键完成编辑,执行单元格,这将在本例中渲染格式化的文本,并将光标移到下一个单元格。默认情况下,下一个单元格将是代码单元。将以下 Python 代码添加到该单元格中:

    print('Hello world')
    

    请注意,当你开始输入时,会出现一个弹出窗口,其中包含代码建议,你可以使用箭头键选择。你可以通过按下键盘上的Enter键来确认选择。这个列表是智能的,它会显示与你输入的内容匹配的类名,并且还会显示一些常用类,可能是因为你拼写错误或者忘记输入某些字母。例如,以下截图显示了PermissionError类,因为你可能忘记输入print语句并且不完整,当代码中的部分存在语法错误时,会有波浪下划线标记。要执行代码单元,可以按Shift + Enter组合键,或者点击单元格左侧的圆形按钮:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_011.jpg

图 7.11 – IntelliSense 提示适合当前脚本范围的方法和类

如果在执行代码单元时发生错误,错误信息将显示在单元格的底部,Traceback 信息将出现在单元格的输出部分,如下图所示。你可以更新单元格的内容并重新运行单元格以修复此错误:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_012.jpg

图 7.12 – 笔记本单元执行期间的脚本错误

在本节中,你学习了如何使用内置的笔记本体验来编写 Python 脚本。在下一节中,你将开始编写利用 AzureML SDK 的代码片段。

使用 AzureML SDK 进行基础编码

你将要使用的第一个类是 AzureML 的 Workspace 类,这个类允许你访问工作区内的所有资源。要创建对工作区的引用,你需要以下信息:

  • ab05ab05-ab05-ab05-ab05-ab05ab05ab05。你可以在 Azure 门户中的 属性 标签下找到该订阅的 ID。

  • 资源组名称:包含 AzureML 工作区组件的资源组。

  • 工作区名称:AzureML 工作区的名称。

你可以通过运行以下赋值语句将这些信息存储在变量中:

subscription_id = '<Subscription Id>'
resource_group = 'packt-azureml-rg'
workspace_name = 'packt-learning-mlw'

创建工作区引用的第一种方法是实例化 Workspace 类,如以下代码片段所示。

from azureml.core import Workspace
ws = Workspace(subscription_id, resource_group, workspace_name)

这是你在 第四章 中看到的代码片段,配置工作区,当你创建数据集并探索该数据集的 消费 标签时。

重要说明

本书假设你将在上一节中创建的笔记本中编写代码,并通过执行 pip install azureml-sdk 命令使用 azureml-sdk 包编辑笔记本。在这种情况下,你将被提示使用交互式认证来验证设备,这一点你将在下一节中阅读到。

创建对 AzureML 工作区引用的另一种方法是使用 Workspace 类的 get() 方法,如以下代码片段所示:

from azureml.core import Workspace
ws = Workspace.get(name=workspace_name,
                   subscription_id=subscription_id,
                   resource_group=resource_group)

在这里,关于 ws 变量,你分配了一个引用,它指向与本节开始时在 workspace_namesubscription_idresource_group 变量中指定的 namesubscription_idresource_group 值相匹配的 AzureML 工作区。

重要说明

在 Python 中,你可以通过按名称或位置传递参数来调用函数。在之前的示例中,我们通过按名称传递参数来调用 Workspace.get()——也就是说,我们明确指定了对于 name 参数,我们传递的是 workspace_name 变量的值。使用这种方法时,参数的顺序并不重要。而在前一个示例中,我们通过按位置传递参数来实例化 Workspace 类。你没有使用 workspace_name=workspace_name 这种赋值方式。这意味着你是根据 Workspace 类构造函数声明参数的顺序来赋值的。本书以及考试中,你将看到这两种赋值方式。

前面提到的两种获取 AzureML 工作区引用的方式是相同的。然而,主要问题在于它们将工作区硬编码在了脚本中。假设你想和朋友分享一个笔记本,但你在笔记本中硬编码了订阅 ID、资源名称和工作区名称。你的朋友就必须手动去编辑那个单元格。这个问题在你想写一个能够在多个环境中运行的脚本时变得尤为明显,比如开发环境、质量保证环境和生产环境。

Workspace 类提供了 from_config() 方法来解决这个问题。该方法会搜索文件夹树结构中的 config.json 文件,文件格式如下,并包含本节开始时提到的所有信息:

{
  "subscription_id": "<Subscription Id>",
  "resource_group": "packt-azureml-rg",
  "workspace_name": "packt-learning-mlw"
}

对于计算实例来说,这个文件位于根文件夹(/config.json)中,并且当你在 AzureML 工作区中配置计算实例时会自动创建该文件。如果你想从本地计算机运行相同的脚本,可以创建一个类似的文件,将其放置在正在编辑的 Python 脚本旁边,然后编写以下代码来获取 AzureML 工作区的引用:

from azureml.core import Workspace
ws = Workspace.from_config()
print(f"Connected to workspace {ws.name}")

如果你想创建一个新的 AzureML 工作区,可以使用 Workspace.create() 方法来进行配置。以下代码片段将在西欧地区创建一个 AzureML 工作区:

from azureml.core import Workspace
new_ws = Workspace.create(
                   name='packt-azureml-sdk-mlw',
                   subscription_id=subscription_id,
                   resource_group='packt-azureml-sdk-rg',
                   create_resource_group=True,
                   location='westeurope')

这个代码片段将在指定 subscription_id 变量的订阅中创建一个名为 packt-azureml-sdk-mlw 的 AzureML 工作区。此资源将部署在 packt-azureml-sdk-rg 资源组中,如果该资源组不存在,将自动创建。

重要提示

Contributor role at the resource group level to be able to deploy the AzureML workspace with the SDK.

要删除你刚刚部署的工作区,可以使用以下代码片段:

new_ws.delete(delete_dependent_resources=True)

这段代码会删除由 new_ws 变量引用的工作区,并移除依赖资源,包括与 AzureML 工作区一起部署的存储账户、密钥库和应用洞察资源。

在本节中,您学习了如何通过 Python 代码引用和操作工作区资源。本节假定您一直在使用内置的笔记本编辑器,因此无需进行身份验证。如果您希望在自己的计算机上运行相同的代码,您需要进行身份验证以访问资源,这是我们将在下一节讨论的内容。

从您的设备进行身份验证

在 AzureML Studio 中的Notebooks体验需要您对计算实例进行身份验证。这是一个只需执行一次的过程,就像点击在 Notebooks 体验中可见的Authenticate按钮一样简单。如果您从本地计算机运行相同的代码,或者尝试在计算实例的终端中首次执行 Python 脚本,则必须运行 AzureML SDK 命令。一个提示将要求您进行身份验证,如下面的截图所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_013.jpg

图 7.13 – 在第一个命令执行期间请求的交互式身份验证

如果您看到此消息,请转到提供的链接,您将被要求输入提示中显示的请求代码。在这种情况下,代码是MYRNDCODE。此代码是使用您计算机位置的身份进行登录请求的唯一标识符。选择您计划用于访问各种 Azure 资源(包括 AzureML 工作区)的帐户。下图显示了整个交互式身份验证流程:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_014.jpg

图 7.14 – 在计算实例中使用交互式登录进行身份验证

重要提示

请求代码是短暂的,有效期为 15 分钟。如果您未能在该时间段内完成过程,将会出现错误,您将需要重新开始。

如果您的帐户可以访问多个Azure Active DirectoriesAADs),例如来自试用订阅的个人 AAD 和公司的 AAD,您可能需要手动指定要进行身份验证的 AAD 租户。这可以通过使用以下片段手动调用交互式身份验证过程来完成:

from azureml.core.authentication import \ 
                             InteractiveLoginAuthentication
InteractiveLoginAuthentication(tenant_id="<AAD tenant id>")

此代码启动了设备身份验证流程,如前面的图所示。<AAD tenant id>是您可以从 Azure 门户中获取的 GUID,访问 AAD 资源时会显示。

在这一部分,你学习了交互式身份验证,它允许你从任何设备访问你的 AzureML 工作区。当你尝试在远程计算机上执行脚本,或者尝试执行 Azure CLI 命令时,应该使用这种身份验证方法。一旦身份验证完成,令牌将存储在你执行InteractiveLoginAuthentication的计算机上,直到令牌过期之前,你将无需再次登录。

在下一部分,你将开始使用已认证的工作区引用来部署计算目标,以便远程执行脚本。

使用计算目标

正如我们在第四章中提到的,配置工作区部分的配置计算资源一节所述,计算资源是允许你远程执行脚本的机器。AzureML SDK 允许你列出工作区中现有的计算目标,或者在需要时配置新的目标。

若要列出你已配置或附加到工作区的计算目标,你可以使用分配给ws变量的 AzureML 工作区引用,方法是使用ws = Workspace.from_config()。工作区对象有一个名为compute_targets的属性。它是一个 Python 字典,所有计算实例的名称作为键,而该计算实例的引用作为值。要列出并打印出此列表,你可以使用以下代码:

for compute_name in ws.compute_targets:
    compute = ws.compute_targets[compute_name]
    print(f"Compute {compute.name} is a {type(compute)}")

输出应至少列出你正在执行脚本的ComputeInstance区域,以及你在第四章中创建的AmlCompute集群,配置工作区。你会注意到所有的计算类型都在azureml.core.compute包的模块中定义。

重要提示

这段代码假设你已经初始化了ws变量,这是你在笔记本中按照使用 AzureML SDK 进行基础编码部分的指示进行的操作。如果你关闭计算实例,内核将停止,并且你通过执行笔记本单元定义的所有变量将会丢失。如果你想继续在笔记本上工作,最简单的做法是重新运行所有单元,这将确保你已初始化所有变量。

获取计算目标引用的另一种方法是使用ComputeTarget构造函数。你需要传入Workspace引用和你要查找的计算目标的名称。如果目标不存在,将引发ComputeTargetException异常,你必须在代码中处理该异常,如以下脚本所示:

from azureml.core import ComputeTarget
from azureml.exceptions import ComputeTargetException
compute_name = 'gpu-cluster'
compute = None
try:
    compute = ComputeTarget(workspace=ws, name=compute_name)
    print(f"Found {compute_name} which is {type(compute)}")
except ComputeTargetException as e:
    print(f"Failed to get compute {compute_name}. Error: {e}")

ComputeTarget类提供了create()方法,允许你配置各种计算目标,包括计算实例(ComputeInstance类)、计算集群(AmlCompute类)和 Azure Kubernetes 服务(AKSCompute类)目标。

重要提示

每当您通过 AzureML Studio Web UI、Azure CLI 或 SDK 部署计算实例或计算集群时,计算目标将被配置在与您的机器学习工作区相同的资源组和 Azure 区域内。

要配置计算目标,您需要创建一个继承自 ComputeTargetProvisioningConfiguration 抽象类的配置对象。在以下示例中,脚本尝试定位名为 cpu-sm-cluster 的计算集群。如果集群存在,则将集群的引用分配给 cluster 变量。如果集群不存在,脚本将创建 AmlComputeProvisioningConfiguration 类的实例,并将其分配给 config 变量。这个实例是通过 AmlCompute 类的 provisioning_configuration() 方法创建的。此 config 用于创建集群并等待工作区中的注册完成,显示创建日志:

from azureml.core.compute import ComputeTarget, AmlCompute
compute_name = 'cpu-sm-cluster'
cluster = None
if compute_name in ws.compute_targets:
    print('Getting reference to compute cluster')
    cluster = ws.compute_targets[compute_name]
else:
    print('Creating compute cluster')
    config = AmlCompute.provisioning_configuration(
                           vm_size='Standard_D1', 
                           max_nodes=2)
    cluster = ComputeTarget.create(ws, compute_name, config)
    cluster.wait_for_completion(show_output=True)
print(f"Got reference to cluster {cluster.name}") 

该脚本指定了虚拟机的大小(vm_size 参数)。虚拟机将设置为 Standard_D1,这是 Standard_NC6Standard_NV24s_v3Standard_ND40rs_v2。注意所有的大小都以 N 开头。

该脚本仅指定计算集群的最大节点数(max_nodes 参数)。如果未指定最小节点数(min_nodes 参数),则该参数的默认值为 0。默认情况下,集群将缩减到 0 个节点,在没有作业运行时不会产生计算成本。您可以在微软官方 Python SDK 参考页面上找到 provisioning_configuration() 方法的所有参数的默认值,如以下截图所示,或者通过执行 help(AmlCompute.provisioning_configuration) 使用 Python help 命令:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_015.jpg

图 7.15 – AmlCompute 类的 provisioning_configuration 方法文档

将计算集群的最小节点数设置为 0 的一个缺点是,您必须等待计算节点分配后,您提交的作业才会执行。为了节省这段空闲时间,通常在工作日将集群的最小节点数甚至最大节点数扩大,然后在非工作时间调整这些值以节省成本。要更改计算集群的节点数,您可以使用 AzureML Studio Web UI、Azure CLI,甚至使用以下代码更新计算集群的 min_nodes 属性:

from azureml.core.compute import AmlCompute
for ct_name, ct in ws.compute_targets.items():
    if (isinstance(ct, AmlCompute)):
        print(f"Scalling down cluster {ct.name}")
        ct.update(min_nodes=0)

重要说明

通过 AzureML Studio Web 门户、CLI、SDK 和 ARM 模板,可以更改计算集群的最小节点数和最大节点数。在 2020 年 10 月之前,您还可以通过 Azure 门户更改节点数,但该功能已被移除。

在本节中,你了解了如何创建或获取计算目标的引用,以便你可以用它来执行脚本。在下一节中,你将学习如何通过 SDK 连接到各种数据源。

定义数据存储

如我们在第四章中提到的,配置工作区部分,在连接到数据存储小节中,数据存储是存放你数据的引擎,并为授权的人员提供访问权限。AzureML SDK 允许你附加现有的数据存储以访问底层数据。

在本节中,你将把存储帐户的 Blob 容器附加到你的工作区。假设你有一个名为mydatastg的存储帐户。这个存储帐户有一个名为existing-container的 Blob 容器,里面包含你想要分析并训练模型的 CSV 文件,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_016.jpg

图 7.16 – 在 Azure 门户中看到的 mydatastg 存储帐户中的容器

重要提示

从 Azure 门户配置新的存储帐户并添加容器是一项简单的任务,超出了本考试的范围。请注意,存储帐户有唯一的名称。这意味着你可能无法创建名为mydatastg的存储帐户,因为它属于其他人。你可以使用随 AzureML 工作区一起配置的现有存储帐户来执行这些步骤。你可以通过 Azure 门户将existing-container容器添加到该存储帐户中,或者你也可以使用已经存在的azureml容器。

要将此容器注册为你的 AzureML 工作区中的新数据存储,你需要按照以下步骤操作:

  1. 在进入你的笔记本之前,你需要获取存储帐户的名称和帐户密钥。这些信息位于 Azure 门户中的设置|访问密钥选项卡下,存储帐户资源中,如下图所示:https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_017.jpg

    图 7.17 – 连接存储帐户所需的存储帐户名称和密钥

  2. 打开你的chapter07.ipynb笔记本,在一个新的代码单元中,将这些信息赋值给以下 Python 变量:

    storage_name = 'mydatastg'
    storage_key = '<storagekey>'
    storage_container = 'existing-container'
    
  3. 要将 Blob 容器注册为一个名为my_data_store的新数据存储,你可以使用Datastore类的register_azure_blob_container()方法,如下所示:

    from azureml.core import Datastore
    dstore = Datastore.register_azure_blob_container(
        workspace=ws,
        datastore_name="my_data_store",
        container_name=storage_container,
        account_name=storage_name,
        account_key=storage_key,
        create_if_not_exists=False
    )
    

    正如预期的那样,该方法需要将Workspace区域的引用作为参数传递,新的数据存储将在该区域创建。另外,请注意,create_if_not_exists参数设置为False,这将导致方法在 Blob 容器不存在时抛出AzureMissingResourceHttpError异常,并带有ContainerNotFound的错误代码。

    与 Blob 容器类似,您可以通过 AzureML SDK 的 Datastore 类注册所有支持的数据存储类型,如以下屏幕截图所示。例如,您可以使用 register_azure_data_lake_gen2() 方法连接到 Azure 数据湖第二代数据存储,或者使用 register_azure_sql_database() 方法连接到 Azure SQL 数据库:

    https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_018.jpg

    图 7.18 – 来自官方文档页面的支持的数据存储服务类型

  4. 要获取连接的数据存储的引用,您可以使用 Datastore 类的构造函数,如以下代码片段所示:

    from azureml.core import Datastore
    dstore = Datastore.get(ws,"my_data_store")
    
  5. 第四章《配置工作区》中,在数据存储列表中,您将学习如何将注册的数据存储设置为 AzureML 工作区的默认数据存储。Workspace 类提供了一种快捷方式,可以通过 get_default_datastore() 方法引用该数据存储:

    dstore = ws.get_default_datastore()
    

    本书的其余部分,您将使用默认的数据存储来存储数据。

  6. 引用 Azure Blob 容器(AzureBlobDatastore 类)或 Azure 文件共享(AzureFileDatastore 类)的数据存储可以通过 SDK 上传和下载文件。以下代码片段加载 DataFrame,然后将其存储为本地 CSV 文件。文件存储后,脚本获取 Workspace 区域的默认数据存储的引用,该引用在 ws 变量中,并使用 upload() 方法将该文件上传到/samples/diabetes/v1/rawdata.csv

    from sklearn.datasets import load_diabetes
    import pandas as pd
    features, target = load_diabetes(return_X_y=True)
    diabetes_df = pd.DataFrame(features)
    diabetes_df['target']= target
    diabetes_df.to_csv('rawdata.csv', index=False)
    dstore = ws.get_default_datastore()
    dstore.upload_files(
                files=['rawdata.csv'],
                target_path="/samples/diabetes/v1", 
                overwrite=True,
                show_progress=True)
    
  7. 该文件将出现在与您的 AzureML 工作区一起创建的存储帐户中。您可以通过 Azure 门户找到它,方法是导航到存储帐户,选择名称以azureml-blobstore-开头的 Blob 容器,然后导航到samples / diabetes / v1文件夹,如以下屏幕截图所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_019.jpg

图 7.19 – 已上传的数据存储在注册为默认数据存储的 Blob 容器中

在本节中,您学习了如何将现有的 Azure Blob 容器附加到 AzureML 工作区中的新数据存储。您还学习了如何轻松获取工作区默认数据存储的引用,然后将 CSV 文件上传到该数据存储。在下一节中,您将学习如何定义数据集,这一构建可以帮助您独立于数据存储位置进行数据操作。

使用数据集

正如我们在第四章,《配置工作区》一节中提到的,在《使用数据集》部分中,数据集是你在训练和推理过程中使用的一个抽象层。它们包含对物理数据位置的引用,并提供一系列元数据,帮助你理解数据的形状和统计特性。数据集不会复制存储在数据存储中的数据。AzureML 提供了两种类型的数据集:

  • FileDataset允许你引用一个或多个文件,存储在一个或多个数据存储中。FileDataset的一个常见例子是用于训练计算机视觉模型的图像。

  • TabularDataset允许你引用存储在一个文件或多个文件中的表格结构数据,这些文件可能存储在数据存储中,或者直接存储在像 SQL 服务器这样的关系型数据存储中。你在上一节中加载的糖尿病DataFrame就是一个典型的表格数据集。你可以通过解析各种文件(包括 CSV、TSV、Parquet 和 JSON 文件)来创建TabularDataset。如果你的数据包含一个带有时间戳的列/特征,或者文件存储在包含日期模式的文件夹结构中,比如/<year>/<month>/file.csv,你可以启用TabularDataset的时间序列特性,这样可以进行基于时间的数据集筛选。

为了获得一些实际操作经验,你可以定义一个FileDataset,它引用了你在上一节中上传的默认数据存储中的 CSV 文件。虽然 CSV 表示表格数据,但它也可以是一个文件,FileDataset可以引用这样的文件。

  1. 在你的笔记本中新建一个单元格,输入以下代码:

    from azureml.core import Dataset
    dstore = ws.get_default_datastore()
    file_paths = [
        (dstore, "/samples/diabetes/v1")
    ]
    file_ds = Dataset.File.from_files(
        path = file_paths, validate=True
    )
    print("Files in FileDataset:")
    print(file_ds.to_path())
    

    在这段代码中,引用了工作站的默认数据存储。

  2. 现在,你可以创建一个包含Datastore及其相对路径的元组数组。每个元组引用一个特定Datastore中的文件或文件夹。在这种情况下,你引用的是默认Datastore中的samples/diabetes/v1文件夹。如果你愿意,可以使用通配符字符*来加载多个子文件夹或部分文件名。例如,以下元组数组加载了 2021 年所有月份的天气数据 CSV 文件,这些文件存储在/weather/<year>/<month>/<day>.csv路径下:

    file_paths = [
        (dstore, "/weather/2021/*/*.csv")
    ]
    
  3. 如果你只想显式加载 1 月(01.csv)、2 月(02)、和 3 月(03)的第一天数据,你可以使用以下元组数组:

    file_paths = [
        (dstore, "/weather/2021/01/01.csv"),
        (dstore, "/weather/2021/02/01.csv"),
        (dstore, "/weather/2021/03/01.csv")
    ]
    

    出于性能考虑,建议每个数据集的数组大小不要超过 100 个数据路径引用。

  4. 返回到本节开头的代码片段,现在您可以使用from_files()方法创建一个未注册的FileDataset。在此处,您必须将数据路径数组作为参数传递。您还必须验证数据是否可以通过该方法加载。如果文件夹不存在或数据存储由于私有端点受保护,不可直接从执行代码的计算资源访问,则会收到DatasetValidationErrorvalidate参数的默认值为True,您可以通过在该参数中传递False来禁用该验证。

  5. 创建了FileDataset之后,您可以通过调用to_path()方法获取被引用的文件列表。这两个打印的输出应如下所示:https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_020.jpg

    图 7.20 – 未注册的 FileDataset 引用单个 CSV 文件

  6. 对于 CSV 文件,更好的方法是定义一个TabularDataset,它可以解析文件并为我们提供 pandas DataFrame。为此,请将以下代码复制到一个新单元格中:

    tabular_dataset = Dataset.Tabular.from_delimited_files(
        path=file_paths, validate=False)
    df = tabular_dataset.to_pandas_dataframe()
    print(len(df))
    

    在此片段中,您正在重用创建FileDataset时使用的file_paths属性。这次,您正在使用from_delimited_files()方法创建一个未注册的TabularDataset。还请注意,您明确跳过验证,以便可以从当前计算资源加载数据(validate=False),加快声明过程。

    DataFrame,并在调用to_pandas_dataframe()方法时将其分配给df变量。调用len()方法时,您可以获取DataFrame的行数。

  7. 到目前为止,您创建的数据集都是未注册的,这意味着它们未在 AzureML 工作区中注册,也未在register()方法中列出:

    tabular_dataset.register(
        workspace=ws,
        name="diabetes",
        description="The sklearn diabetes dataset")
    

    重要提示

    如果您已经注册了同名的数据集,则无法重新运行此单元格。要注册数据集的新版本,必须使用以下方式使用create_new_version参数:tabular_dataset.register(workspace=ws, name="diabetes", create_new_version=True)

    此方法要求您指定要注册TabularDataset的工作区以及注册的名称。可选地,您可以传递描述、标签以及是否要使用已在工作区中注册的特定名称创建数据集的新版本。数据集注册后,您可以在 Studio Web UI 中查看注册信息,如下截图所示:

    https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_021.jpg

    图 7.21 – 注册在工作区中的表格数据集

  8. 如果您有一个 pandas DataFrame 而不是TabularDataset,并且想要注册它,可以使用register_pandas_dataframe()方法,如下面的代码片段所示:

    Dataset.Tabular.register_pandas_dataframe(
        dataframe=df,
        target=(dstore,"/samples/diabetes"),
        name="diabetes",
        description="The sklearn diabetes dataset")
    

    请注意,在这个代码片段中,你传递了 df pandas DataFrame 引用,并且请求将该 DataFrame 存储在由 dstore 变量引用的默认数据存储中,存储路径为 /samples/diabetes 文件夹。此方法将创建一个具有 GUID 名称的新文件夹,并将数据以 Parquet 文件格式存储。由于数据集已经注册并指向不同的路径,该命令将创建数据集的新版本。在 Studio 界面中,你会看到 版本 2 的数据集已被注册。这个版本有一个不同的 相对路径,如下面所示:

    https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_022.jpg

    图 7.22 – 从 pandas DataFrame 直接注册的新版本糖尿病数据集

    请注意,Parquet 文件格式是一种压缩格式,与用于数据集第一版的 CSV 文件相比,它的文件体积更小。

  9. 注册数据集后,无论是 FileDataset 还是 TabularDataset,你都可以使用 Dataset 类的 get_by_name() 方法来检索它,使用如下代码片段:

    from azureml.core import Dataset
    diabetes_dataset = Dataset.get_by_name(
        workspace=ws,
        name='diabetes')
    

    可选地,你可以指定 version 参数,默认值为 latest

  10. 上面的代码片段返回一个 TabularDataset 类的实例,但数据尚未加载。你可以通过 TabularDataset 类的各种方法部分加载数据集,如下所示的代码片段所示:

    partial_dataset = diabetes_dataset \
            .skip(10) \
            .take(2) \
            .keep_columns(['0','target'])
    
  11. partial_dataset 是从 diabetes_dataset 创建的 TabularDataset 实例。该数据集跳过了 diabetes_dataset 的前 10 行,保留了两行,并删除了所有列,除了名为 0target 的列。在执行此多行语句时没有加载任何数据。定义了这个未注册的 partial_dataset 数据集后,你可以使用以下代码将数据加载到 pandas DataFrame 中:

    df = partial_dataset.to_pandas_dataframe()
    df.head()
    

    这将显示一个由两行两列组成的小型表格,如下所示的屏幕截图所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_023.jpg

图 7.23 – 从切片表格数据集加载的小型 DataFrame

AzureML 数据集类的惰性加载功能让你可以灵活地对庞大的数据集进行切片和操作,而无需将其加载到内存中。

到目前为止,你已经学习了如何使用 Python SDK 部署计算目标、定义数据存储和创建数据集。在下一节中,你将学习如何使用在第二章中看到的 Azure CLI 工具执行类似操作,部署 Azure 机器学习工作区资源,该章节位于 使用 Azure CLI 部分。

使用 AzureML CLI 扩展

第二章部署 Azure 机器学习工作区资源》中,你学习了如何使用 Azure CLI,以及如何安装azure-cli-ml扩展。这个扩展使用你在本章看到的 Python SDK 执行各种操作。要使用 Azure CLI,你可以选择以下任一方法:

  1. 打开 Azure 门户中的云终端,就像你在第二章部署 Azure 机器学习工作区资源》中所做的那样。

  2. 打开你在本章中使用的计算实例的终端。

  3. 使用 Jupyter 笔记本的 shell 分配功能,允许你通过使用感叹号(!),也叫做bang,执行底层 shell 命令。

在本节中,你将使用笔记本,这将帮助你存储步骤,并在未来需要时重复这些步骤:

  1. 首先,你需要在你当前正在使用的计算实例的 Azure CLI 中安装azure-cli-ml扩展。创建一个新的代码单元格,并添加以下代码:

    ! az extension add -n azure-cli-ml
    

    请注意,在第二章部署 Azure 机器学习工作区资源》中,你执行了相同的命令,但没有感叹号前缀。此命令的输出应类似于以下内容:

    https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_024.jpg

    图 7.24 – 安装 AzureML 扩展

  2. 然后,你需要使用az login命令登录。此命令将触发设备认证过程,类似于你在本章开始时尝试通过 SDK 连接到工作区时使用的认证方式。运行以下命令:

    ! az login
    
  3. 如果你有多个 Azure 订阅的访问权限,你需要使用以下代码片段选择你正在使用的订阅:

    ! az account set --subscription "<subscription id>"
    

    从现在开始,你可以使用 AzureML CLI 对工作区执行操作。

    重要提示

    如果你在订阅中有多个 AzureML 工作区,你需要指定每个 AzureML CLI 命令的目标工作区和资源组。为此,你需要使用-g-w参数,我们在第二章部署 Azure 机器学习工作区资源》中已经介绍过。

  4. 要列出工作区中的所有计算目标,可以使用以下代码片段:

    ! az ml computetarget list -g packt-azureml-rg -w packt-learning-mlw -o table
    
  5. 然后,你可以使用以下命令更新cpu-sm-cluster,使其具有 0 个最小节点:

    ! az ml computetarget update amlcompute --name cpu-sm-cluster --min-nodes 0 -g packt-azureml-rg -w packt-learning-mlw
    
  6. 要获取在工作区中注册的默认数据存储,可以使用以下命令:

    ! az ml datastore show-default -g packt-azureml-rg -w packt-learning-mlw
    
  7. 最后,你可以使用以下代码列出工作区中注册的数据集:

    ! az ml dataset list -g packt-azureml-rg -w packt-learning-mlw -o table
    

    该命令的结果应类似于以下内容:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_025.jpg

图 7.25 – AzureML CLI 中数据集列表的表格格式输出

AzureML CLI 提供对 SDK 选项的完全访问权限,包括创建和分离计算目标、数据存储,甚至定义数据集的能力。对于考试,您不需要记住命令,只要您理解 CLI 在后台使用 SDK,并且大多数您可以用 SDK 做的事情都有对应的 CLI 命令即可。

总结

在本章中,您学习了 AzureML Python SDK 的结构。您还发现了 AzureML 笔记本编辑器,允许您编写 Python 脚本。接着,您使用了 SDK,并开始通过管理附加到 AzureML 工作区的计算目标来启动编码旅程。然后,您附加了新的数据存储并获取了现有数据存储的引用,包括工作区的默认数据存储。接下来,您处理了各种文件和基于表格的数据集,并学习了如何通过将它们注册到工作区中来重用这些数据集。

最后,您已经使用了 AzureML CLI 扩展,这是一个客户端,利用了您在本章中探索的 Python SDK。

在下一章中,您将基于这些知识进一步学习如何在数据科学实验阶段使用 AzureML SDK。您还将学习如何跟踪数据科学实验中的指标,并了解如何通过在计算集群中运行脚本来将训练扩展到更大的计算资源。

问题

请回答以下问题,以检查您对本章所讨论的主题的理解:

  1. AzureML 计算集群的默认最小节点数是多少?

    a. 0

    b. 1

    c. 等于最大节点数

  2. 您将一个包含信用卡交易详情的 CSV 文件上传到默认数据存储库。您应该使用以下哪种方法来创建数据集引用?

    a. Dataset.File.from_files()

    b. Dataset.Tabular.from_delimited_files()

    c. Workspace.from_csv_files()

    d. Datastore.from_csv_files()

  3. 如何在注册 Azure Blob 存储数据存储库的过程中强制创建 Blob 容器?

    a. 将 force_create=True 参数传递给 Datastore.register_azure_blob_container() 方法。

    b. 将 create_if_not_exists=True 参数传递给 Datastore.register_azure_blob_container() 方法。

    c. 将 force_create=True 参数传递给 Datastore.register_container() 方法。

    b. 将 create_if_not_exists=True 参数传递给 Datastore.register_container() 方法。

进一步阅读

本节提供了一些有用的网络资源,这些资源将帮助您增强对 AzureML SDK 及本章中使用的各种第三方库的知识:

第八章:第八章:使用 Python 代码进行实验

在本章中,你将了解如何训练 scikit-learn 库,它通常被称为 sklearn。你将了解如何使用Azure 机器学习AzureMLSDKMLflow 来跟踪训练指标。接着,你将看到如何在计算集群中扩展训练过程。

本章将涵盖以下主题:

  • 在笔记本中训练一个简单的 sklearn 模型

  • 在实验中跟踪指标

  • 扩展训练过程与计算集群

技术要求

你需要有一个 Azure 订阅。在该订阅下,你需要有一个 packt-azureml-rg。你还需要有 ContributorOwner 权限的 packt-learning-mlw。如果你按照第二章《部署 Azure 机器学习工作区资源》中的说明进行操作,这些资源应该已经为你准备好了。

你还需要具备 Python 语言的基础知识。本章中的代码片段适用于 Python 3.6 或更高版本。你还应熟悉在 AzureML Studio 中使用笔记本的操作体验,这部分内容已在上一章中讲解过。

本章假设你已经在 AzureML 工作区中注册了 scikit-learndiabetes 数据集,并且已经创建了一个名为 cpu-sm-cluster 的计算集群,正如在第七章《AzureML Python SDK》中的 定义数据存储处理数据集使用计算目标 部分所描述的那样。

你可以在 GitHub 上找到本章的所有笔记本和代码片段,链接:bit.ly/dp100-ch08

在笔记本中训练一个简单的 sklearn 模型

本节的目标是创建一个 Python 脚本,在你在第七章中注册的diabetes数据集上,训练出一个简单的模型,《AzureML Python SDK》。该模型将获取数字输入,并预测一个数字输出。为了创建这个模型,你需要准备数据、训练模型、评估训练模型的表现,然后将其存储,以便未来可以重用,正如在图 8.1中所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_001.jpg

图 8.1 - 生成糖尿病预测模型的过程

让我们从了解你将要使用的数据集开始。diabetes 数据集包含 442 名diabetes患者的数据。每一行代表一个患者。每一行包含 10 个特征(target,是记录特征后 1 年糖尿病病情发展的定量指标)。

你可以在 AzureML Studio 界面中进一步探索数据集,正如在图 8.2中所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_002.jpg

图 8.2 – 已注册的糖尿病数据集

通常在准备阶段,您会加载原始数据,处理缺失值的行,规范化特征值,然后将数据集分为训练数据和验证数据。由于数据已经预处理,您只需加载数据并将其拆分为两个部分:

  1. 导航到chapter08,然后创建一个名为chapter08.ipynb的笔记本:https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_003.jpg

    图 8.3 – 创建您将要使用的 chapter08 笔记本

  2. 在笔记本的第一个单元格中,添加以下代码:

    from azureml.core import Workspace
    ws = Workspace.from_config()
    diabetes_ds = ws.datasets['diabetes']
    training_data, validation_data =\
    diabetes_ds.random_split(percentage = 0.8)
    X_train =\
    training_data.drop_columns('target').to_pandas_dataframe()
    y_train =\
    training_data.keep_columns('target').to_pandas_dataframe()
    X_validate =\
    validation_data.drop_columns('target').to_pandas_dataframe()
    y_validate =\
    validation_data.keep_columns('target').to_pandas_dataframe()
    

    在此代码片段中,您获取工作区的引用并检索名为diabetes的数据集。然后,您使用random_split()方法将其拆分为两个TabularDataset。第一个数据集是training_data,它包含 80%的数据,而validation_data数据集引用其余 20%的数据。这些数据集包含您要预测的特征和标签。使用TabularDatasetdrop_columns()keep_columns()方法,您可以将特征与label列分开。然后,您通过TabularDatasetto_pandas_dataframe()方法将数据加载到内存中。最终,您将得到四个 pandas 数据框:

    • X_train:包含 80%的行,每行有 10 列(09)。

    • y_train:包含 80%的行,每行有 1 列(target)。

    • X_validate:包含 20%的行,每行有 10 列(09)。

    • y_validate:包含 20%的行,每行有 1 列(target)。

    diabetes数据集在科学文献中非常流行。它被用作训练回归模型的示例。scikit-learn库提供了一个名为sklearn.linear_model的专用模块,包含许多线性回归模型可供我们使用。现在您已经准备好了数据,接下来的任务是训练模型。

  3. 在此步骤中,您将训练一个LassoLars模型,它是LassoLars类的缩写,该类接受一个名为alpha的浮动参数,该参数被称为正则化参数惩罚项。它的主要目的是保护模型免受训练数据集的过拟合。由于该参数控制训练过程,因此被称为超参数。一旦模型训练完成,这个参数不能再更改。在这个代码块中,您正在实例化一个未训练的模型,并将alpha参数设置为0.1。在下一章,第九章优化机器学习模型,您将调整此参数,并尝试为您的数据集找到最佳值。

    然后,您将使用X_trainy_train数据框来 fit()模型,这意味着您正在用训练数据集训练模型。经过这个过程后,model变量引用一个已训练的模型,您可以使用该模型进行预测。

  4. 接下来的任务是基于某个指标评估你所生成的模型。评估回归模型时最常用的指标如下:

    • 平均或中位数绝对误差。

    • 均方误差或对数误差。该指标的另一种常见变体是sklearn.metrics包中的mean_squared_error方法。该指标的常见问题是,当模型在具有更大值范围的数据上训练时,相比于在较小值范围的数据上训练的同一模型,其误差率更高。你将使用一种称为指标归一化的技术,该技术基本上是将指标除以数据的范围。计算得到的指标被称为X_validate数据框。你通过将预测结果与存储在y_validate数据框中的真实值进行比较,来计算 RMSE。接着,你使用ptp()方法计算值的范围(最大值减去最小值),得到0.2

      最后一步是将训练好的模型存储起来,以便将来能够重用。你将创建一个名为outputs的文件夹,并将模型持久化到一个文件中。Python 对象的持久化通过joblib库的dump()方法完成。

      在新的笔记本单元格中,输入以下源代码:

      import os
      import joblib
      os.makedirs('./outputs', exist_ok=True)
      model_file_name = f'model_{nrmse:.4f}_{alpha:.4f}.pkl'
      joblib.dump(value=model,
              filename=os.path.join('./outputs/',model_file_name))
      

      如果outputs文件夹不存在,你需要先创建它。然后,将模型存储在包含model_前缀的文件名中,后跟在步骤 4中计算的 NRMSE 指标,再加上一个_,然后是用于实例化模型的alpha参数。你应该能够在文件资源管理器中看到序列化的模型,如图 8.4所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_004.jpg

图 8.4 – 序列化模型存储在输出文件夹中

你在步骤 5中使用的命名规范帮助你跟踪模型的表现,以及记录你在本次运行中使用的参数。AzureML SDK 提供了多种方法来监控、组织和管理你的训练过程,这些内容你将在下一节中探讨。

在实验中跟踪指标

当你训练一个模型时,你是在进行一个试验,并且你正在记录该过程的各个方面,包括你需要比较模型表现的 NRMSE 等指标。AzureML 工作区提供了实验的概念——即用于将这些试验/运行归类的容器。

要创建一个新的实验,只需要指定你将使用的工作区,并提供一个包含最多 36 个字母、数字、下划线和破折号的名称。如果实验已经存在,你将获得对它的引用。在你的chapter08.ipynb笔记本中添加一个单元格,并添加以下代码:

from azureml.core import Workspace, Experiment
ws = Workspace.from_config()
exp = Experiment(workspace=ws, name="chapter08")

你首先获取现有 AzureML 工作区的引用,然后创建chapter08实验(如果它还不存在的话)。如果你导航到 Studio 界面中的资产 | 实验部分,你会注意到列表中会出现一个空的实验,如图 8.5所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_005.jpg

图 8.5 – 使用 SDK 创建的空实验

要在chapter08实验下创建一个run,你可以在新的单元格中添加以下代码:

run = exp.start_logging()
print(run.get_details())

run变量允许你访问 AzureML SDK 的Run类实例,该实例代表实验的单个试验。每个run实例都有一个唯一的 ID,用于标识工作区中特定的运行。

重要提示

扩展训练过程与计算集群部分中,你将使用Run类的get_context方法来获取当前执行 Python 脚本的run实例的引用。通常,当你提交脚本在实验下执行时,run会自动创建。start_logging方法较少使用,仅在你需要手动创建一个run并记录度量时使用。最常见的情况是你使用笔记本单元格来训练模型,或者在远程计算环境(如本地计算机或Databricks工作区)上训练模型时。

run类提供了丰富的日志记录 API。最常用的方法是通用的log()方法,它允许你通过以下代码记录度量:

run.log("nrmse", 0.01)
run.log(name="nrmse", value=0.015, description="2nd measure")

在这段代码中,你记录了nrmse度量的值0.01,然后记录了同一度量的值0.015,并传递了可选的description参数。

如果你进入chapter08实验,你会注意到目前有一个正在运行的run,并且当你切换到Metrics标签时,你会看到nrmse度量的两个测量值,以图表或表格的形式呈现,正如图 8.6所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_006.jpg

图 8.6 – 在 Studio 体验中看到的 nrmse 的两个测量值

Run类提供了丰富的日志记录方法,包括以下几种:

  • log_list方法允许你为特定度量记录一系列值。该方法的示例如下代码:

    run.log_list("accuracies", [0.5, 0.57, 0.62])
    

    这段代码将在runMetrics部分生成图 8.7

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_007.jpg

图 8.7 – 使用 log_list 方法记录的三个值的图表

  • log_tablelog_row方法允许你记录表格数据。请注意,使用此方法时,你可以指定与log_list方法不同的X轴标签:

    run.log_table("table", {"x":[1, 2], "y":[0.1, 0.2]})
    run.log_row("table", x=3, y=0.3)
    

    这段代码片段将在runMetrics部分生成图 8.8

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_008.jpg

图 8.8 – 使用 log_table 和 log_row 方法记录的表格度量

  • 专门的方法如log_accuracy_tablelog_confusion_matrixlog_predictionslog_residuals提供了日志数据的自定义呈现。

  • log_image方法允许你从著名的matplotlib Python 库或其他绘图库记录图形或图像。

  • upload_fileupload_filesupload_folder方法允许你上传实验残留文件并将其与当前运行关联。这些方法通常用于上传在run执行过程中生成的各种二进制工件,例如由开源库如plotly创建的交互式 HTML 图形。

你可以选择创建子运行以隔离试验的一个子部分。子运行记录它们自己的度量指标,你也可以选择登录到父运行。例如,以下代码段创建一个子运行,记录一个名为child_metric的度量(该度量仅在该运行中可见),然后在父运行的度量中记录metric_from_child

child_run = run.child_run()
child_run.log("child_metric", 0.01)
child_run.parent.log("metric_from_child", 0.02)

一旦你完成了运行,你需要更改其运行中状态。你可以使用以下方法之一:

  • complete方法表示运行已成功完成。此方法还会将outputs文件夹(如果存在)上传到runs工件中,而无需显式调用Run类的upload_folder方法。

  • cancel方法表示作业已被取消。你会注意到在 AutoML 实验中运行被取消,因为超出了超时限制。

  • 已弃用的fail方法表示发生了错误。

以下代码段取消了子运行并完成了根运行,打印状态,应该显示已完成

child_run.cancel()
run.complete()
print(run.get_status())

在这一部分,你了解了 AzureML 的日志记录功能。在下一部分,你将重构你在在笔记本中训练简单的 sklearn 模型部分编写的代码,并添加日志记录功能。

跟踪模型演化

在前面的部分,你可能已经注意到,当你执行complete方法时,本章在笔记本中训练简单的 sklearn 模型部分中创建的outputs文件夹会自动上传到运行中。为了避免上传那些过时的工件,你需要删除outputs文件夹:

  1. 在你的chapter08.ipynb笔记本中添加一个单元格,并使用以下代码段删除outputs文件夹:

    import shutil
    try:
      shutil.rmtree("./outputs")
    except FileNotFoundError: 
      pass
    
  2. 下一步,你将把训练和评估的代码重构为一个单独的方法,传入alpha参数以及trainingvalidation数据集:

    from sklearn.linear_model import LassoLars
    from sklearn.metrics import mean_squared_error
    def train_and_evaluate(alpha, X_t, y_t, X_v, y_v):
      model = LassoLars(alpha=alpha)
      model.fit(X_t, y_t)
      predictions = model.predict(X_v)
      rmse = mean_squared_error(predictions, y_v, squared = False)
      range_y_validate = y_v.to_numpy().ptp()
      nrmse = rmse/range_y_validate
      print(f"NRMSE: {nrmse}")
      return model, nrmse
    trained_model, model_nrmse = train_and_evaluate(0.1, 
                            X_train, y_train,
                            X_validate, y_validate) 
    

    这段代码与你在在笔记本中训练简单的 sklearn 模型部分编写的代码完全相同。现在,你可以通过使用train_and_evaluate并传入不同的alpha参数值来训练多个模型,这个过程被称为超参数调优。在这段代码的最后一行,你将获得训练好的模型及其 NRMSE 度量的引用。

    重要提示

    如果你遇到以下错误:NameError: name 'X_train' is not defined,你需要重新运行你定义了X_trainy_trainX_validatey_validate变量的单元格。这表示 Python 内核已经重启,所有变量都已从内存中丢失。

    到目前为止,你已经重构了现有代码并保持了相同的功能。为了启用通过前一部分中探索的Run类进行日志记录,你需要将当前运行实例的引用传递给train_and_evaluate方法。

  3. 在一个新的单元格中,添加以下代码片段,它将覆盖现有的train_and_evaluate方法声明:

    def train_and_evaluate(log and log_row methods to log the NRMSE metric of the trained model.Important noteIf you cannot type the *α* letter shown in the preceding example, you can use the *a* character instead.
    
  4. 拥有这个train_and_evaluate方法后,你可以进行超参数调优,并为多个αalpha)参数值训练多个模型,使用以下代码:

    from azureml.core import Workspace, Experiment
    ws = Workspace.from_config()
    exp = Experiment(workspace=ws, name="chapter08")
    with exp.start_logging() as run:
        print(run.get_portal_url())
        for a in [0.001, 0.01, 0.1, 0.25, 0.5]:
            train_and_evaluate(run, a, 
                                X_train, y_train,
                                X_validate, y_validate)
    

    注意,我们没有调用complete方法,而是使用了with .. as的 Python 设计模式。随着run变量超出作用域,它会自动标记为已完成。

  5. 步骤 4中使用get_portal_url,你打印了指向工作室的log方法调用的链接,而αalpha)参数是你使用log_row方法记录的内容。你应该看到类似于图 8.9所示的图表:

![图 8.9 – 糖尿病模型的 nrmse 指标演变]

](https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_009.jpg)

图 8.9 – 糖尿病模型的 nrmse 指标演变

重要提示

在本节中,你仅仅将指标存储在Run实例中,而不是实际的训练模型。你本可以通过生成.pkl文件并使用upload_file方法将其上传到运行的工件中来存储生成的模型。在第十二章使用代码实现模型操作,你将学习 AzureML SDK 的模型注册功能,它提供了一种更优的体验来跟踪实际模型。

在本节中,你看到了如何使用 AzureML SDK 启用指标日志记录。在跟踪实验指标方面,数据科学界使用了一个流行的开源框架——MLflow。在下一节中,你将学习如何使用该库在 AzureML 工作区中跟踪指标。

使用 MLflow 跟踪实验

MLflow 库是一个流行的开源库,用于管理数据科学实验的生命周期。该库允许你将工件和指标存储在本地或服务器上。AzureML 工作区提供了一个 MLflow 服务器,你可以用它来做以下事情:

  • 通过MLflow 跟踪组件跟踪和记录实验指标。

  • 通过MLflow 项目组件在 AzureML 计算集群上协调代码执行(类似于你将在第十一章中看到的管道,与管道合作)。

  • 在 AzureML 模型注册表中管理模型,你将在第十二章《用代码实现模型运营化》中看到该内容。

本节将重点介绍 MLflow Tracking 组件,用于跟踪度量。以下代码片段使用MLflow库跟踪你在前一节中创建的diabetes模型的参数和度量,实验名称为chapter08-mlflow

import mlflow
def train_and_evaluate(alpha, X_t, y_t, X_v, y_v):
  model = LassoLars(alpha=alpha)
  model.fit(X_t, y_t)
  predictions = model.predict(X_v)
  rmse = mean_squared_error(predictions, y_v, squared = False)
  range_y_validate = y_v.to_numpy().ptp()
  nrmse = rmse/range_y_validate
  mlflow.log_metric("nrmse", nrmse)
  return model, nrmse
mlflow.set_experiment("chapter08-mlflow")
with mlflow.start_run():
    mlflow.sklearn.autolog()
    trained_model, model_nrmse = train_and_evaluate(0.1, 
                                    X_train, y_train,
                                    X_validate, y_validate)

MLflow Tracking 组件最著名的特点之一是其提供的自动日志记录功能。在训练代码之前调用mlflow.sklearn.autolog()方法,可以自动记录sklearn的度量、参数和生成的模型。类似于sklearn特定的autolog方法,常见训练框架(如 PyTorch、fast.ai、Spark 等)也有对应的包。

使用log_metric方法,你显式地要求 MLflow 库记录一个度量。在此示例中,你记录了 NRMSE 度量,该度量不会通过自动日志记录功能自动捕获。

正如图 8.10所示,MLflow Tracking 组件将所有工件和训练模型以文件夹结构记录在mlruns文件夹中,紧邻笔记本文件。

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_010.jpg

图 8.10 – 使用 MLflow Tracking 组件的本地 FileStore 模式跟踪度量

这是默认设置,称为本地 FileStore。你可以将 AzureML 工作区用作远程跟踪服务器。为此,你需要使用mlflow.set_tracking_uri()方法连接到一个跟踪 URI。

要启用 MLflow 与 AzureML 的集成,你需要确保环境中安装了azureml-mlflow Python 库。该库已包含在 AzureML 计算实例中。如果你在 Databricks 工作区中工作,则需要通过pip install azureml-mlflow命令手动安装。

要获取跟踪URI并使用 AzureML 作为远程跟踪服务器运行相同的实验,请使用以下代码片段:

import mlflow
from azureml.core import Workspace
ws = Workspace.from_config()
mlflow.set_tracking_uri(ws.get_mlflow_tracking_uri())
mlflow.set_experiment("chapter08-mlflow")
with mlflow.start_run():
    mlflow.sklearn.autolog()
    trained_model, model_nrmse = train_and_evaluate(0.1, 
                                    X_train, y_train,
                                    X_validate, y_validate)

Workspace类的get_mlflow_tracking_uri方法返回一个有效期为 1 小时的 URL。如果你的实验超过一小时仍未完成,你将需要生成新的 URI,并使用set_tracking_uri方法将其分配,如前面代码片段所示。

你应该能够在 Studio 界面中看到运行情况和已跟踪的度量,如图 8.11所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_011.jpg

图 8.11 – 使用 MLflow 库并将 AzureML 用作远程跟踪服务器时记录的度量

到目前为止,你一直在使用 AzureML 工作区中的计算实例,并且你是在Notebook内核中训练 ML 模型。对于小型模型或在示例数据上快速原型开发,这种方法效果很好。但在某些时候,你将需要处理更高负载的工作负载,这可能涉及更大的内存要求,甚至是在多个计算节点上进行分布式训练。你可以通过将训练过程委托给在第四章中创建的计算集群来实现这一目标,配置工作区。在下一节中,你将学习如何在 AzureML 计算集群中执行 Python 脚本。

使用计算集群扩展训练过程

第七章AzureML Python SDK中,你创建了一个名为cpu-sm-cluster的计算集群。在这一节中,你将提交一个训练任务以在该集群上执行。为此,你需要创建一个将在远程计算目标上执行的 Python 脚本。

导航到你迄今为止正在使用的chapter08文件夹中的greeter-job。添加一个名为greeter.py的 Python 文件:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_012.jpg

图 8.12 – 向远程计算集群添加简单的 Python 脚本以执行

打开该文件并添加以下代码:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--greet-name', type=str, 
                    dest='name', help='The name to greet')
args = parser.parse_args()
name = args.name
print(f"Hello {name}!")

该脚本使用argparse模块中的ArgumentParser类来解析传递给脚本的参数。它试图查找一个--greet-name参数,并将找到的值分配给它返回的对象的name属性(args.name)。然后,它会打印出给定名称的问候消息。要尝试这个脚本,请打开终端并输入以下命令:

python greeter.py --greet-name packt

这个命令将产生如下所示的输出,如图 8.13所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_013.jpg

图 8.13 – 测试你将在远程计算机上执行的简单脚本

为了在远程计算集群上执行这个简单的 Python 脚本,请返回到chapter08.ipynb笔记本,添加一个新单元,并输入以下代码:

from azureml.core import Workspace, Experiment
from azureml.core import ScriptRunConfig
ws = Workspace.from_config()
target = ws.compute_targets['cpu-sm-cluster']
script = ScriptRunConfig(
    source_directory='greeter-job',
    script='greeter.py',
    compute_target=target,
    arguments=['--greet-name', 'packt']
)
exp = Experiment(ws, 'greet-packt')
run = exp.submit(script)
print(run.get_portal_url())
run.wait_for_completion(show_output=True)

在这段代码中,你正在执行以下操作:

  1. 获取工作区的引用,然后将target变量分配给cpu-sm-cluster集群的引用。

  2. 创建一个ScriptRunConfig,以执行位于greeter-job文件夹中的greeter.py脚本。该脚本将在target计算机上执行,并传递--greet-namepackt参数,它们将通过空格连接起来。

  3. 创建一个名为greet-packt的实验,并将脚本配置提交以在该实验下执行。submit方法创建了一个新的Run实例。

  4. 你可以使用get_portal_url方法获取特定Run实例的门户 URL。然后调用wait_for_completion方法,将show_output参数设置为True。为了等待运行完成,开启详细日志记录,并在单元格的输出中打印日志。

    重要说明

    在 AzureML SDK 的第一个版本中,你会使用Estimator类,而不是ScriptRunConfig,但该类已被弃用。此外,还有一些针对特定框架的已弃用专用Estimator类,例如TensorFlow类,它提供了一种运行特定于 TensorFlow 的代码的方式。这种方法已经被弃用,取而代之的是你将在下面的理解执行环境部分中阅读到的环境。然而,这些已弃用类的语法和参数与ScriptRunConfig非常相似。你应该能够毫无问题地阅读这些已弃用的代码。如果在认证考试中看到关于这些已弃用类的旧问题,记得这一点。

你已经成功完成了远程执行的运行。在下一部分,你将探索刚刚完成的运行日志,更好地理解 AzureML 的机制。

探索运行的输出和日志

在这一部分,你将探索在使用计算集群扩展训练过程部分中执行的远程执行输出。这将帮助你深入了解 AzureML 平台的工作原理,并帮助你排查在开发训练脚本时可能遇到的潜在错误。

使用get_portal_url方法打开你在前一部分中打印的链接,或者导航到greet-packt实验并打开Run 1。进入该运行的Outputs + logs标签页:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_014.jpg

图 8.14 – 实验运行的 Outputs + logs 标签页

这些输出对于排查潜在的脚本错误非常有帮助。azureml-logs文件夹包含平台日志。这些文件大部分是底层引擎的日志。包含你脚本标准输出的日志是70_driver_log.txt。这是你需要首先查看的日志文件,用于排查潜在的脚本执行失败。如果你有多个进程,你会看到多个带有数字后缀的文件,如70_driver_log_x.txt

logs文件夹是你可以在脚本中使用的特殊文件夹,用于输出日志。脚本写入该文件夹的所有内容会自动上传到你在实验中跟踪指标部分中看到的运行outputs文件夹。AzureML 还会在该文件夹下的azureml文件夹中输出系统日志,如图 8.14所示。

导航到ScriptRunConfig。该目录可以包含最多 300MB 的内容和最多 2,000 个文件。如果需要更多脚本文件,你可以使用数据存储。如果你在.py脚本中编辑了脚本文件以及一个.amltmp文件,这是由笔记本编辑器使用的临时文件:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_015.jpg

图 8.15 – 临时文件上传至快照中

为了避免创建不需要的文件快照,你可以在脚本旁边的文件夹中添加.gitignore.amlignore文件,并排除符合特定模式的文件。导航到greeter-job文件夹中的.amlignore文件,如果在创建文件夹时尚未添加该文件,如图 8.16所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_016.jpg

图 8.16 – 添加.amlignore文件以排除临时文件被添加到快照中

打开.amlignore文件,并在其中添加以下行,以排除所有具有.amltmp文件扩展名的文件以及你正在编辑的.amlignore文件:

*.amltmp
.amlignore

打开chapter08.ipynb笔记本,添加一个单元,并添加以下代码以重新提交脚本:

from azureml.widgets import RunDetails
run = exp.submit(script)
RunDetails(run).show()

你正在重新提交之前步骤中创建的ScriptRunConfig的现有实例。如果你再次重启expscript变量。

这次,你正在使用 AzureML SDK 提供的RunDetails小部件。这是一个Jupyter Notebook小部件,用于查看脚本执行的进度。这个小部件是异步的,会在运行完成前不断更新。

如果你想打印运行状态,包括日志文件的内容,可以使用以下代码片段:

run.get_details_with_logs()

一旦运行完成,导航到该运行的Snapshot标签页。你会注意到临时文件已经消失。

注意,这次运行的执行时间显著减少。导航到运行的日志。注意,这次日志中没有出现20_image_build_log.txt文件,如图 8.17所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_017.jpg

图 8.17 – 更快的运行执行和缺失的 20_image_build_log.txt 文件

这是用于执行脚本的环境的Docker镜像构建日志。这个过程非常耗时。这些镜像被构建并存储在与您的 AzureML 工作区一起部署的容器注册表中。由于你没有修改执行环境,AzureML 在后续的运行中重新使用了之前创建的镜像。在接下来的部分,你将更好地理解什么是环境以及如何修改它。

理解执行环境

在 AzureML 工作区的术语中,环境意味着执行脚本所需的软件要求列表。这些软件要求包括以下内容:

  • 你的代码需要安装的 Python 包

  • 可能需要的环境变量

  • 你可能需要的各种辅助软件,如 GPU 驱动程序或 Spark 引擎,以确保你的代码能够正常运行。

环境是管理版本化的实体,它们可以在不同的计算目标之间实现可重复、可审计和可移植的机器学习工作流。

AzureML 提供了一个 AzureML-Minimal 精选环境列表,包含仅用于启用运行跟踪所需的最小 Python 包,你在跟踪模型演变部分看到过。另一方面,AzureML-AutoML 环境是一个更大的精选环境,提供了运行 AutoML 实验所需的 Python 包。

重要提示

AzureML 服务正在不断更新,旧的环境已经被淘汰,取而代之的是更新的环境。即使在 AzureML Studio 的网页界面中看不到 AzureML-MinimalAzureML-AutoML 环境,它们仍然可以供你使用。如果遇到任何错误,请从本章的 GitHub 仓库下载最新的代码。

图 8.18中,你可以看到与简化版的 AzureML-Minimal 环境相比,AzureML-AutoML 环境提供了多少额外的软件包:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_018.jpg

图 8.18 - AzureML-Minimal 和 AzureML-AutoML 环境之间的 Python 包差异

图 8.18 显示了 AzureML-Minimal 环境 版本 46AzureML-AutoML 环境 版本 61Conda 环境定义。Conda 使用这个 YAML 文件来安装 Python 版本 3.6.2 和在 - pip: 标记下列出的 pip 依赖包。如你所见,所有 pip 包都定义了特定的版本,使用 ==x.x.x 的标记。这意味着每次使用该 YAML 文件时,都会安装相同的 Python 包,这有助于保持稳定的环境,从而确保实验的可重复性。

创建环境时安装软件包是一个耗时的过程。这时你在前一部分看到的 Docker 技术就派上用场了。Docker 是一个开源项目,旨在自动化将应用程序部署为便携式、自给自足的容器。这意味着,与你每次想要运行脚本时都创建一个新环境不同,你可以创建一个 Docker 容器镜像,也称为 Docker 镜像,在这个镜像中,所有的 Python 依赖都已经内嵌到镜像中。此后,你可以重复使用该镜像来启动容器并执行脚本。事实上,所有 AzureML 精选环境都可以作为 Docker 镜像,在 viennaglobal.azurecr.io 容器注册表中找到。

重要提示

尽管创建 Docker 镜像用于环境的配置是常见的做法,但并非总是必需的。如果你在本地计算机或 AzureML 计算实例上运行实验,你可以使用现有的 Conda 环境,而无需使用 Docker 镜像。如果你打算使用远程计算,例如 AzureML 计算集群,则需要使用 Docker 镜像,因为否则你无法确保所提供的机器会具备你的代码执行所需的所有软件组件。

为了更好地理解到目前为止你所阅读的内容,你将重新运行之前的 greeter.py 脚本,并使用 AzureML-Minimal 环境:

  1. 在你的笔记本中,添加一个新单元并加入以下代码:

    from azureml.core import Environment
    minimal_env =\
    Environment.get(ws, name="AzureML-Minimal")
    print(minimal_env.name, minimal_env.version)
    print(minimal_env.Python.conda_dependencies.serialize_to_string())
    

    这段代码检索了 AzureML-Minimal 环境,该环境在之前在笔记本中初始化的 ws 变量所引用的 AzureML 工作区中定义。然后,它打印环境的名称和版本,以及你在 图 8.18 中看到的 Conda 环境 YAML 定义。

  2. 添加一个新单元,并输入以下内容:

    from azureml.core import Experiment, ScriptRunConfig
    target = ws.compute_targets['cpu-sm-cluster']
    script = ScriptRunConfig(
        source_directory='greeter-job',
        script='greeter.py',
        environment argument in the ScriptRunConfig constructor.
    

查看运行执行的输出。如果你仔细观察,你将看到以下这一行:

Status: Downloaded newer image for viennaglobal.azurecr.io/azureml/azureml_<something>:latest

这一行是 azureml-logs55_azureml-execution-something.txt 文件的一部分。该行告知你它正在从 Microsoft 所拥有的 viennaglobal 容器注册表中拉取 Docker 镜像。与此相对,上一节中,在没有指定策划环境的运行中,镜像是从你自己的容器注册表中拉取的——即与你的 AzureML 工作区关联的容器注册表,如 图 8.19 所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_019.jpg

图 8.19 – 在没有使用策划环境的情况下,从你自己的容器注册表中拉取的镜像

这个观察结果引出了下一个类型的 AzureML 支持的环境——系统管理环境——你将在下一节中进行探索。

定义系统管理环境

Conda 环境定义或简单的 pip requirements.txt 文件。在上一节中,你没有在 ScriptRunConfig 构造函数中定义 environment 参数,因此使用了默认的 Conda 环境定义文件来创建存储在与 AzureML 工作区关联的 Azure 容器注册表 中的系统管理环境。现在,让我们显式地创建一个系统管理环境来与代码一起使用:

  1. 导航到你 AzureML 工作区的 笔记本 部分以及 文件 树视图。

  2. 点击 greeter-job 文件夹的三个点以打开上下文菜单(或者直接右击文件夹名称),然后选择 greeter-banner-job,如下面的截图所示:https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_020.jpg

    图 8.20 – 将 greeter-job 文件夹复制为一个名为 greeter-banner-job 的新文件夹

  3. 打开新文件夹中的 greeter.py 文件,并将代码更改为以下内容:

    import argparse
    Banner method from the asciistuff open source Python package. This method is used in the last print. This will output a fancy os module, which allows you to read the environment variables using the os.environ.get() method. The code tries to read the environment variable named GREET_HEADER, and if it is not defined, the default value, Message:, is assigned to the greet_header variable, which is printed before the banner message.Important noteIf you try to execute the modified `greeter.py` in a terminal within your AzureML *compute instance*, it will fail because you don't have the `asciistuff` package installed. To install it in your compute instance, you can use the `pip install asciistuff` command.
    
  4. asciistuff 包是一个 pip 包,你需要在执行环境中安装它,以确保代码能够正常运行。为了定义这个代码依赖,你将创建一个 Conda 环境定义文件。在 chapter08 文件夹中,添加一个名为 greeter-banner-job.yml 的新文件,并在其中添加以下内容:

    name: banner-env
    dependencies:
    - python=3.6.2
    - pip:
      - asciistuff==1.2.1 
    

    这个 YAML 文件定义了一个新的 Conda 环境,名为 banner-env,该环境基于 Python 版本 3.6.2,并安装了 asciistuff1.2.1 版本的 pip 包。

  5. 若要基于你刚定义的 Conda 环境创建一个 AzureML 环境,你需要进入 chapter08.ipynb 笔记本,添加一个单元格,并输入以下代码:

    from azureml.core import Environment
    banner_env = Environment.from_conda_specification(
                     name = "banner-env",
                     file_path = "greeter-banner-job.yml")
    banner_env.environment_variables["GREET_HEADER"] = \
                                     "Env. var. header:"
    

    这段代码创建了一个名为 banner-env 的 AzureML 环境,使用了 Environment 类的 from_conda_specification() 方法。banner_env 变量包含了新定义的环境。在随后的代码行中,你定义了 GREET_HEADER 环境变量,并为其赋值为 Env. var. header:。该环境未在工作区中注册,使用时不需要注册。如果你确实想要将它保存到工作区,以便像引用策划环境一样引用它,并希望保持版本记录,可以使用 register() 方法,使用 banner_env.register(ws) 代码,其中你传入一个指向工作区的变量,该工作区将是该环境的注册位置。

    重要说明

    如果你计划先在本地计算机上工作,然后再扩展到更强大的计算集群上,你应考虑创建并注册一个系统管理的环境,包含你所需的所有 Python 包。这样,你可以在本地和远程执行时都重复使用它。

  6. 若要使用这个新定义的环境,请在笔记本中添加一个新单元格,并输入以下代码:

    script = ScriptRunConfig(
        source_directory='ScriptRunConfig::*   The source directory has changed to point to the `greeter-banner-job` folder, which contains the updated script.*   The environment argument is specified, passing your very own defined `banner_env` environment. 
    

该实验的输出应与 图 8.21 中所示相似:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_021.jpg

图 8.21 – 从环境变量读取的头部文本和基于横幅的问候语

正如你注意到的,在你刚刚创建的系统管理环境中,你没有指定任何关于基础操作系统的信息(例如,是否已在基础系统中安装了Conda)。你只是指定了已安装的Conda依赖项。如果你想要更大的灵活性,你可以显式配置环境并手动安装所有的软件要求。这些环境被称为用户管理环境。通常,这些用户管理环境是自定义的 Docker 镜像,封装了所有必需的依赖项。例如,你可能需要 PyTorch 框架的自定义构建,或者甚至是 Python 的自定义构建版本。在这些情况下,你需要负责安装 Python 包并配置整个环境。在本书中,你将使用经过精心策划或由系统管理的环境。

到目前为止,你已经探索了如何在远程计算机上执行一个简单的问候程序 Python 应用。在接下来的部分,你将继续训练你的diabetes模型,并了解如何在远程计算集群上训练该模型。

在计算集群上训练糖尿病模型

在前面的部分中,你了解了如何通过在笔记本中调用exp.submit(script)方法在远程计算集群上运行脚本,如图 8.22所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_022.jpg

图 8.22 – 在计算集群上执行脚本

当你调用submit方法时,后台发生了以下操作:

  1. AzureML SDK 执行了一个 ScriptRunConfig

  2. AzureML 工作区检查是否已经存在Environment的 Docker 镜像。如果没有,它会在 Azure 容器注册表中创建。

  3. 任务被提交到计算集群,集群会扩展以分配一个计算节点。在新分配的计算节点中执行以下操作:

  4. 带有环境的 Docker 镜像被拉取到计算节点上。

  5. ScriptRunConfig引用的脚本被加载到正在运行的 Docker 实例中。

  6. 指标和元数据存储在 AzureML 工作区中。

  7. 输出将存储回存储帐户。

使用笔记本训练简单的 sklearn 模型部分中,你在 chapter08.ipynb 笔记本中创建了一个训练脚本。训练发生在 Jupyter 服务器的进程中,位于你的计算实例内部。要在计算集群上运行相同的训练,你需要执行以下操作:

  1. 将代码移动到 Python 脚本文件中。

  2. 创建一个 AzureML 环境来运行训练。

  3. 在实验中提交ScriptRunConfig

在接下来的部分中,你将看到如何将你在跟踪模型演变部分中使用的脚本转换,以便能够在远程计算集群上执行它。

将代码移动到 Python 脚本文件中

如果你查看你在跟踪模型演变部分创建的脚本,在进行训练的代码中,你使用了run变量来记录指标。这个变量引用了你在调用exp.start_logging()时获得的Run对象。在前一部分中,你了解了ScriptRunConfig,它在 Experiment 中提交并返回了一个Run类的实例。这个实例是在计算实例的笔记本中创建的。那么,如何让执行在远程集群上的脚本文件访问相同的Run对象呢?

AzureML 的Run类提供了一个叫做get_context()的方法,它返回当前服务执行上下文。对于ScriptRunConfig,这个执行上下文就是在调用exp.submit(script)时创建的相同Run对象:

from azureml.core.run import Run
run = Run.get_context()

除了run变量,在训练脚本中,你还使用了ws变量,它是指向 AzureML 工作区的引用。你使用该变量来访问diabetes数据集。你通过调用from_config方法来获取工作区的引用。这个方法的问题在于,当你第一次调用时,你需要手动进行身份验证并授权计算资源代表你访问工作区。这样的方法在远程计算环境中是不可行的。

run变量通过在 Experiment 属性中导航,再到该 Experiment 的工作区属性,为你提供了访问对应工作区的方式:

ws = run.experiment.workspace

然而,这些代码行有一个警告。你的代码假设 Python 脚本是通过ScriptRunConfig提交的。如果你在终端本地运行 Python 脚本,使用以下命令行,你将会遇到错误:

python training.py --alpha 0.1

get_context()方法将返回一个_OfflineRun类的对象,该类继承自Run类。这个类提供了你在实验中跟踪指标部分看到的所有日志功能,但它并不会将指标或工件上传到工作区,而是直接在终端中打印尝试结果。显然,这个run没有关联任何 Experiment,这会导致脚本抛出错误。因此,你需要使用你一直在使用的from_config()方法来检索工作区引用。由于终端是计算实例的一部分,脚本将在不提示身份验证的情况下执行,并且会传递你的凭据,正如你稍后在本节中看到的那样。如果你在本地计算机上运行这段代码,你将需要进行设备身份验证,正如你在第七章从设备进行身份验证部分中所看到的,AzureML Python SDK

允许你在终端离线运行并在计算集群中提交的完整代码如下:

from azureml.core import Workspace
from azureml.core.run import Run, _OfflineRun
run = Run.get_context()
ws = None
if type(run) == _OfflineRun:
    ws = Workspace.from_config()
else:
    ws = run.experiment.workspace

这些就是你需要对脚本做出的唯一修改,目的是为了提交到远程执行并利用 AzureML SDK 的功能。

重要提示

Python 开发者通常会在他们想标记为内部的类、属性或方法前加一个_前缀。这意味着标记的代码是供SDK库中的类使用,外部开发者不应该使用这些代码。标记的代码可能在未来发生变化而不会提前通知。通常不推荐使用以_开头的类,然而,_OfflineRun类在 AzureML SDK 的公共示例中被广泛使用,使用它是安全的。

让我们在工作区中进行这些更改。在文件树中,在chapter08下创建一个名为diabetes-training的文件夹,并在其中添加一个training.py文件,正如图 8.23所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_023.jpg

图 8.23 – 为远程糖尿病模型训练创建训练脚本

training.py脚本中添加以下代码块。你可以直接从本章技术要求部分提到的 GitHub 仓库中下载这些代码,而不需要手动输入:

from sklearn.linear_model import LassoLars
from sklearn.metrics import mean_squared_error
from azureml.core import Workspace
from azureml.core.run import Run, _OfflineRun
import argparse
import os
import joblib

这些是脚本文件中所需的所有导入。将所有import语句放在脚本文件顶部是一种良好的编程习惯,这样可以方便地发现代码执行所需的模块。如果你使用flake8来检查代码,它会提醒你如果没有遵循这一最佳实践:

parser = argparse.ArgumentParser()
parser.add_argument('--alpha', type=float, 
                  dest='alpha', help='The alpha parameter')
args = parser.parse_args()

这个脚本文件需要传入--alpha参数。在这个代码块中,使用你在使用计算集群扩展训练过程部分看到的argparse模块解析这个参数,并将float类型的值赋给args.alpha变量,正如在dest参数中指定的那样。如果你传递了未定义的参数给脚本,parse_args方法将会抛出错误。有些人更喜欢使用args, unknown_args = parser.parse_known_args(),代替代码块的第四行,这样即使脚本收到比预期更多的参数,也能执行,并将未知参数赋值给unknown_args变量:

run = Run.get_context()
ws = None
if type(run) == _OfflineRun:
    ws = Workspace.from_config()
else:
    ws = run.experiment.workspace

在这个代码块中,你通过开头部分看到的代码片段获取到Run对象和Workspace的引用。一旦获得Workspace的引用,你就可以加载diabetes数据集,正如下一个脚本块所示:

diabetes_ds = ws.datasets['diabetes']
training_data, validation_data = \
               diabetes_ds.random_split(
                            percentage = 0.8, seed=1337)
X_train = training_data.drop_columns('target') \
                       .to_pandas_dataframe()
y_train = training_data.keep_columns('target') \
                       .to_pandas_dataframe()
X_validate = validation_data.drop_columns('target') \
                            .to_pandas_dataframe()
y_validate = validation_data.keep_columns('target') \
                            .to_pandas_dataframe()

在这个代码块中,您获得 diabetes 数据集的引用,并将其拆分为所需的 X_trainy_trainX_validatey_validate pandas 数据框,这些数据框您在本章的 在笔记本中训练简单的 sklearn 模型 部分中看到过。请注意,您在 random_split 方法中指定了 seed 参数。这个 seed 参数用于初始化 split 方法背后使用的随机函数的状态,以便从数据集中随机选择行。这样,每次调用该随机函数时,它都会生成相同的随机数。这意味着 training_datavalidation_data 每次运行脚本时都会保持一致。拥有相同的训练和验证数据集有助于正确比较在不同 alpha 参数下执行相同脚本的多次结果:

def train_and_evaluate(run, alpha, X_t, y_t, X_v, y_v):
  model = LassoLars(alpha=alpha)
  model.fit(X_t, y_t)
  predictions = model.predict(X_v)
  rmse = mean_squared_error(predictions,y_v,squared=False)
  range_y_validate = y_v.to_numpy().ptp()
  nrmse = rmse/range_y_validate
  run.log("nrmse", nrmse)
  run.log_row("nrmse over α", α=alpha, nrmse=nrmse)
  return model, nrmse

在此代码块中,您定义了 train_and_evaluate 方法,这与本章 追踪模型演变 部分中使用的方法相同:

model, nrmse = train_and_evaluate(run, args.alpha,
                  X_train, y_train, X_validate, y_validate)

在定义方法后,您调用训练过程并传递所有必需的参数:

os.makedirs('./outputs', exist_ok=True)
model_file_name = 'model.pkl'
joblib.dump(value=model, filename=
           os.path.join('./outputs/',model_file_name))

最后一个代码块将模型存储在 outputs 文件夹中,该文件夹位于脚本的同一位置。

您可以在本地计算实例上运行脚本,您会注意到模型按预期进行训练,指标会记录在终端中,如 图 8.24 所示。这是您之前阅读过的 _OfflineRun 类的预期行为:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_024.jpg

图 8.24 – 在本地运行训练脚本

到目前为止,您已经创建了训练脚本。在下一部分中,您将创建 AzureML 环境,该环境将包含执行该脚本所需的所有依赖项,以便在远程计算上运行。

创建用于运行训练脚本的 AzureML 环境

追踪模型演变部分中创建的训练脚本使用了 scikit-learn 库,也称为 sklearn。您在笔记本体验中使用的 Jupyter 内核已经安装了 sklearn 库。要查看当前在内核中安装的版本,请转到 chapter08.ipynb 笔记本,并在新的单元格中添加以下代码片段:

!pip show scikit-learn

该命令将使用 Python 的 pip 包管理器显示当前安装的 scikit-learn 包的详细信息,如 图 8.25 所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_025.jpg

图 8.25 – 安装的 scikit-learn 库的包信息

重要提示

如果您不确定库的名称,可以使用 pip freeze 命令来获取当前 Python 环境中已安装包的完整列表。

您还可以通过在 Python 脚本中使用 sklearn.__version__ 属性(注意两个下划线)来查找已安装库的版本。在新的笔记本单元格中,添加以下 Python 代码行:

import sklearn
print(sklearn.__version__)

你应该能够在输出中看到完全相同的版本。大多数 Python SDK 和库都有这个__version__属性,比如 PyTorch 和 TensorFlow 框架。

有两种方法可以安装scikit-learn包:作为Conda包或作为pip包。Conda提供了一个精选的 Python 包列表,并且这是推荐的方式。在理解执行环境部分,你看到了如何使用Conda规范文件创建环境。在本部分,你将学习一种不同的方法,在 Python 代码中创建环境。在chapter08.ipynb笔记本中添加一个新单元格,并输入以下内容:

from azureml.core import Environment
from azureml.core.conda_dependencies import CondaDependencies 
import sklearn
diabetes_env = Environment(name="diabetes-training-env")
diabetes_env.Python.conda_dependencies = CondaDependencies()
diabetes_env.Python.conda_dependencies.add_conda_package(
                   f"scikit-learn=={sklearn.__version__}")
diabetes_env.python.conda_dependencies.add_pip_package("azureml-dataprep[pandas]")

在前面的代码片段中,你创建了一个新的系统管理环境,然后使用add_conda_package添加了特定版本的scikit-learn。你还使用add_pip_package添加了azureml-dataprep[pandas]包,这是为了在training.py脚本中使用to_pandas_dataframe方法所必需的。你本可以像之前安装的asciistuff包一样,添加其他的 pip 包。你可以通过使用CondaDependencies类的create方法来一次性添加多个包,如下面的代码片段所示:

diabetes_env.Python.conda_dependencies = \
CondaDependencies.create(
      conda_packages=[
                   f"scikit-learn=={sklearn.__version__}"],
      pip_packages=["azureml-defaults", "azureml-dataprep[pandas]"])

你可以通过将包添加到conda_packagespip_packages数组中来要求环境中包含多个包。请注意,由于你没有将包附加到默认的CondaDependencies中,因此需要手动添加azureml-defaults包,以便training.py脚本能够访问azureml.core模块。

你可能会问,为什么我们没有在 Python 依赖项中定义joblibscikit-learn包依赖于joblib包,它会自动安装在环境中。如果你愿意,可以通过以下代码显式地在依赖项列表中指定它:

import joblib
diabetes_env.Python.conda_dependencies.add_pip_package(f"joblib=={joblib.__version__}")

重要说明

虽然不是强制要求指定你要添加到环境中的包的版本,但这是一个好的做法。如果你写了add_conda_package("scikit-learn"),没有指定包的版本,AzureML 会假定你指的是最新版本。当你第一次在 AzureML 中使用环境时,Docker 镜像会被创建,安装当时最新版本的scikit-learn包。那个版本可能比你用于创建脚本的版本更新,且可能与您编写的代码不兼容。虽然次要版本的差异可能不会影响你的代码,但主要版本的变化可能会引入破坏性更改,就像 TensorFlow 从版本 1升级到版本 2时所做的那样。

如果你不想创建一个包含代码依赖的全新环境,可以使用其中一个由 AzureML 精心策划的环境。你可以选择高度专业化的基于 GPU 的AzureML-Scikit-learn0.24-Cuda11-OpenMpi4.1.0-py36环境,或者使用更通用的AzureML-Tutorial策划环境,该环境包含了如scikit-learnMLflowmatplotlib等最常用的数据科学库。

到目前为止,你已经编写了训练脚本并定义了包含所需sklearn库的 AzureML 环境。在下一节中,你将启动计算集群上的训练。

在 Experiment 中提交ScriptRunConfig

一旦你有了脚本和 AzureML 环境定义,你就可以提交ScriptRunConfig以在远程计算集群上执行。在chapter08.ipynb笔记本的新单元中,添加以下代码:

from azureml.core import Workspace, Experiment
from azureml.core import ScriptRunConfig
ws = Workspace.from_config()
target = ws.compute_targets['cpu-sm-cluster']
script = ScriptRunConfig(
    source_directory='diabetes-training',
    script='training.py',
    environment=diabetes_env,
    compute_target=target,
    arguments=['--alpha', 0.01]
)
exp = Experiment(ws, 'chapter08-diabetes')
run = exp.submit(script)
run.wait_for_completion(show_output=True)

这段代码与之前章节中提交greeter.py脚本的代码相同。你获得了对 AzureML 工作区和你将要执行作业的计算集群的引用。你定义了一个ScriptRunConfig对象,在其中定义了要执行的脚本位置、你在前一节中定义的环境和目标计算资源。你还将alpha参数传递给了脚本。在代码的最后一部分,你创建了一个 Experiment 并提交了ScriptRunConfig以执行。

通过这段代码,你触发了本章中第 8.22 图的流程,该流程出现在在计算集群上训练糖尿病模型一节中。

一旦训练完成,你就可以进入 Experiment,选择运行任务,并查看从训练过程中收集的指标,如第 8.26 图所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_08_026.jpg

图 8.26 – 来自远程计算集群上运行脚本的记录指标

到目前为止,你已经成功地在远程计算集群的单个节点上执行了diabetes模型训练脚本,并且已经在 AzureML Experiment 的运行记录中记录了指标和训练后的模型。

在下一节中,你将发现不同的方式来扩展你的计算工作,并充分利用计算集群中不止一个节点。

在模型训练过程中利用多个计算节点

正如你在第四章配置工作区部分看到的那样,集群可以从 0 个计算节点扩展到你需要的任意数量。你需要在模型训练阶段使用多个节点而不仅仅是一个节点的原因有几个,具体如下:

  • 不相关的模型训练实例的并行执行:当你在团队中工作时,通常会有多个 Experiment 并行运行。每个作业可以在单个节点上运行,就像你在前一节中所做的那样。

  • 单一模型的并行训练,也称为分布式训练:这是一个高级场景,您正在使用如Apache Horovod的分布式深度学习训练框架,该框架被 PyTorch 和 TensorFlow 所使用。分布式训练有两种类型:

    • 数据并行性:将训练数据分割成与计算节点数量相等的分区。每个节点对分配的数据执行一批模型训练,然后所有节点在进入下一批之前同步更新的模型参数。

    • 模型并行性:在不同的计算节点上训练模型的不同部分。每个节点只负责训练整个模型的一小段,并且在每次需要传播步骤时,节点之间会进行同步。

  • 您在前一节中训练的LassoLars模型的alpha参数。您可能希望探索这些参数的多个值,以选择在训练数据集上表现最好的模型。这是一个称为超参数调优的过程,您将在第九章中了解更多关于它的内容,优化 ML 模型

  • 并行训练多个模型以选择最佳备选方案:这是您在第五章中已经发现的 AutoML 过程,让机器做模型训练。您还将在第九章中再次看到这种方法,优化 ML 模型,在使用代码运行 AutoML 实验部分。

在本节中,您学习了利用计算集群中多个节点的不同方法。您将在第九章中深入探讨最后两种方法,优化 ML 模型

总结

在本章中,您概览了在 AzureML 工作区中创建 ML 模型的各种方式。您从一个简单的回归模型开始,该模型在 Jupyter notebook 的内核进程中进行训练。您学习了如何跟踪您训练的模型的指标。然后,您将训练过程扩展到在第七章中创建的cpu-sm-cluster计算集群中,AzureML Python SDK。在扩展到远程计算集群时,您了解了 AzureML 环境是什么,以及如何通过查看日志来排除远程执行的问题。

在下一章中,您将基于这些知识,使用多个计算节点执行并行的超参数调优过程,从而找到适合您模型的最佳参数。您还将学习如何使用 AzureML SDK 的 AutoML 功能,完全自动化模型选择、训练和调优。

问题

在每一章中,您会发现几个问题来检查您对讨论主题的理解:

  1. 你想记录你将在脚本中使用的验证行数。你将使用Run类中的哪个方法?

    a. log_table

    b. log_row

    c. log

  2. 你想运行一个使用scikit-learn的 Python 脚本。你将如何配置 AzureML 环境?

    a. 添加 scikit-learn Conda 依赖项。

    b. 添加 sklearn Conda 依赖项。

    使用 AzureML 的Azure-Minimal环境,该环境已经包含所需的依赖项。

  3. 你需要使用 MLflow 跟踪实验中生成的指标,并将其存储在你的 AzureML 工作区中。你需要在 Conda 环境中安装哪两个 pip 包?

    a. mlflow

    b. azureml-mlflow

    c. sklearn

    d. logger

  4. 你需要使用 MLflow 来跟踪 training_rate 指标的值 0.1。以下哪段代码可以实现此要求?假设所有类已在脚本顶部正确导入:

    a. mlflow.log_metric('training_rate', 0.1)

    b. run.log('training_rate', 0.1)

    c. logger.log('training_rate', 0.1)

深入阅读

本节提供了一些网络资源列表,帮助你扩展对 AzureML SDK 和本章中使用的各种代码片段的知识:

第九章:第九章:优化机器学习模型

在本章中,你将学习两种可以帮助你发现数据集最佳模型的技术。你将首先探索HyperDrive包,这是 AzureML SDK 的一部分。这个包允许你通过调整其暴露的参数来优化模型的性能,这个过程也被称为超参数调优。接下来,你将探索自动化机器学习AutoML)包,这是 AzureML SDK 的一部分,它允许你通过代码自动化模型选择、训练和优化过程。

在本章中,我们将涵盖以下主要内容:

  • 使用 HyperDrive 进行超参数调优

  • 使用代码运行 AutoML 实验

技术要求

你需要有 Azure 订阅权限。在该订阅中,你需要有一个名为packt-azureml-rg的资源组。你还需要拥有ContributorOwner权限的packt-learning-mlw,如第二章《部署 Azure 机器学习工作区资源》中所述。

你还需要对Python语言有基本的了解。本章中的代码片段适用于 Python 3.6 或更高版本。你还应当熟悉在 AzureML Studio 中的 Notebook 体验,这在第八章《使用 Python 代码实验》中有讲解。

本章假设你已经在 AzureML 工作区中注册了scikit-learn糖尿病数据集,并且已经创建了一个名为cpu-sm-cluster的计算集群,具体内容请参见第七章《AzureML Python SDK》中的定义数据存储处理数据集处理计算目标部分。

你可以在 GitHub 的bit.ly/dp100-ch09网址找到本章的所有笔记本和代码片段。

超参数调优使用 HyperDrive

第八章《使用 Python 代码实验》中,你训练了一个LassoLars模型,该模型接受alpha参数。为了避免过拟合训练数据集,LassoLars模型使用了一种技术,alpha参数指定了惩罚项的重要性,这直接影响训练结果。影响训练过程的参数被称为DecisionTreeClassifier类,该类位于scikit-learn库中。你可以通过max_depth来定义树的最大深度,max_depth是一个整数。在同一个模型中,你还可以通过为max_leaf_nodes超参数指定一个数值来控制叶节点的最大数量。

这些超参数控制决策树的大小,如图 9.1所示:

![图 9.1 – 决策树超参数]

](https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_09_001.jpg)

图 9.1 – 决策树超参数

超参数调整是找到产生最佳性能模型的超参数的最佳值的过程,用于对训练数据进行评估。要评估每个超参数组合的性能,必须训练模型并评估性能度量。在糖尿病模型的情况下,在第八章中,使用 Python 代码进行实验,您使用标准化根均方误差NRMSE)度量评估模型。

AzureML SDK 提供了HyperDriveConfig类,允许您执行HyperDriveConfig是您在第八章中使用的ScriptRunConfig类的包装器,使用 Python 代码进行实验。这意味着您需要在run_config参数中传递您要用于训练模型的ScriptRunConfig。您还需要指定代码正在记录的度量标准以及该度量标准的目标。在糖尿病案例中,您试图最小化在第八章中看到的submit方法,使用 Python 代码进行实验。显示端到端过程的伪代码,其中script变量是定义要使用的训练脚本的ScriptRunConfig对象,如下所示:

hd_config = HyperDriveConfig(
             run_config=script,
             primary_metric_name="nrmse",
             primary_metric_goal=PrimaryMetricGoal.MINIMIZE
             ,)
experiment = Experiment(ws, "chapter09-hyperdrive")
hyperdrive_run = experiment.submit(hd_config)

除了ScriptRunConfig,您还需要传递HyperDriveConfig将使用。超参数可以接受离散或连续值:

  • 典型的离散值示例是整数或字符串值。例如,在activation中,selu用于relu修正线性单元ReLU)。

  • 典型的连续值示例是浮点数值。您一直在训练的LassoLars模型中的alpha参数是接受浮点值的超参数

当您探索可能的azureml.train.hyperdrive.parameter_expressions模块时。

在离散choice函数的情况下,您可以使用以下脚本指定activation 超参数的选项列表,这是您之前看到的典型示例:

choice('selu','relu')

此脚本将尝试使用selurelu激活函数来寻找最佳模型。

重要提示

如果您对神经网络工作感兴趣,可能需要更好地理解这些激活函数。有一些很棒的书籍可以帮助您开始神经网络设计。对于 DP-100 考试,您不需要这些知识。

注意,即使在连续的alpha LassoLars模型的情况下,您仍然可以使用choice方法来定义要探索的离散值。例如,以下choice的使用等同于您在第八章跟踪模型演变部分所做的:

choice(0.001, 0.01, 0.1, 0.25, 0.5)

您还可以定义在探索搜索空间时将获得的样本的概率分布。例如,如果您想为所有值提供相等的机会,您将使用均匀分布。另一方面,您可以使用正态分布将搜索区域集中在搜索空间的中心。AzureML SDK 提供了一些方法,您可以使用它们,如uniform(low, high)loguniform(low, high)normal(μ, σ)lognormal(μ, σ)。对于离散值,您可以使用以q为前缀的等效方法,如quniform(low, high, q)qloguniform(low, high, q)qnormal(μ, σ, q)qlognormal(μ, σ, q),其中q参数是量化因子,用于将连续值转换为离散值。

在本书的 GitHub 页面上,您可以找到用于绘制生成 1,000 个样本并使用这些函数分布的代码。结果可以在图 9.2中看到:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_09_002.jpg

](https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_09_002.jpg)

图 9.2 – 高级离散和连续超参数值分布。样本值已排序。x 轴显示排序值的索引号

重要提示

图 9.2中,在loguniformlognormal的图表中,量化因子为 1 的离散函数的线与连续函数的线重合。因此,您只能看到两条线。

定义了搜索空间之后,您需要指定将用于选择每个azureml.train.hyperdrive模块的采样策略:

  • 您在上面看到的choice方法。Azure ML SDK 将搜索这些离散值的所有可能超参数组合。假设您希望探索以下四种参数组合:

    • a=0.01,b=10

    • a=0.01,b=100

    • a=0.5,b=10

    • a=0.5,b=100

    以下代码片段定义了这四种组合的搜索空间:

    from azureml.train.hyperdrive import GridParameterSampling
    from azureml.train.hyperdrive import choice
    param_sampling = GridParameterSampling( {
            "a": choice(0.01, 0.5),
            "b": choice(10, 100)
        }
    )
    
  • RandomParameterSampling类。它允许您从可用选项中随机选择超参数值。它支持离散和连续的超参数

  • max_total_runs您将会在后面了解。它支持离散和连续的超参数

让我们把到目前为止学到的所有知识付诸实践:

  1. 转到 AzureML Studio 网页界面的作者|笔记本部分。

  2. 创建一个名为chapter09的文件夹。

  3. 您需要在training.py脚本中创建一个名为diabetes-training的文件夹。该脚本与第八章中《使用 Python 代码实验》一节中将代码移至 Python 脚本文件部分使用的脚本相同。您可以从那里复制内容。最终的文件结构图见图 9.3

  4. chapter09 文件夹中创建一个名为 chapter09.ipynb 的笔记本。图 9.3 显示了最终 文件 树的结构:https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_09_003.jpg

    图 9.3 – 包含代码和 chapter09 笔记本的文件树结构

  5. 在第一个单元格中添加以下初始化代码:

    from azureml.core import (
        Workspace, Environment
    )
    from azureml.core.conda_dependencies import \
         CondaDependencies 
    import sklearn
    ws = Workspace.from_config()
    diabetes_env = Environment(name=»diabetes-training-env»)
    diabetes_env.python.conda_dependencies = \
         CondaDependencies.create(
          conda_packages=[
              f"scikit-learn=={sklearn.__version__}"],
          pip_packages=["azureml-defaults",
                        "azureml-dataprep[pandas]"])
    target = ws.compute_targets['cpu-sm-cluster'] 
    

    这段代码与你在《第八章》 使用 Python 代码进行实验 部分中使用的代码类似。唯一的区别是你使用了 create 方法,而不是逐个添加包。

  6. 在新单元格中,定义将执行 training.py 脚本的 ScriptRunConfig 对象:

    from azureml.core import ScriptRunConfig
    script = ScriptRunConfig(
        source_directory='diabetes-training',
        script='training.py',
        environment=diabetes_env,
        compute_target=target
    )
    

    这个 ScriptRunConfig 对象与你在《第八章》 使用 Python 代码进行实验 部分中创建的几乎相同。唯一的区别是你没有传递 arguments 参数,特别是你没有指定 --alpha 参数。这个参数将由你在下一步配置的 HyperDriveConfig 对象自动附加。

  7. 在一个新单元格中添加并执行以下代码:

    from azureml.train.hyperdrive import HyperDriveConfig
    from azureml.train.hyperdrive import (
       RandomParameterSampling, uniform, PrimaryMetricGoal
    )
    param_sampling = RandomParameterSampling({
            'alpha': uniform(0.00001, 0.1),
        }
    )
    hd_config = HyperDriveConfig(
                   run_config=script,                          
                   hyperparameter_sampling=param_sampling,
                   primary_metric_name="nrmse", 
                   primary_metric_goal=                   
                              PrimaryMetricGoal.MINIMIZE,
                   max_total_runs=20,
                   max_concurrent_runs=4)
    

    在这段代码中,你定义了一个 RandomParameterSampling 方法,用来探索均匀分布的值,范围从 0.00001 到 0.1,用于传递给你在 第 3 步 中创建的训练脚本的 alpha 参数。这个训练脚本接受 --alpha 参数,随后该参数传递给 alpha LassoLars 模型。

    将此 RandomParameterSampling 配置分配给 HyperDriveConfighyperparameter_sampling 参数。

    你还已配置 HyperDriveConfigrun_config 属性,以使用你在第 6 步中定义的 ScriptRunConfig 对象。注意,RandomParameterSampling 类将传递脚本所需的 alpha 参数。

    然后,定义使用 primary_metric_name 参数评估生成的模型。你还指定了要最小化该值(primary_metric_goal 参数),因为它是你希望最小化的误差。

    最后的两个参数,max_total_runsmax_concurrent_runs,控制你愿意投入到寻找最佳模型的资源。max_total_runs 参数控制实验的最大运行次数,可以在 1 到 1,000 次之间。这是一个必填参数。max_concurrent_runs 是一个可选参数,控制并发运行的最大次数。在这种情况下,你定义了 4,这意味着在 ScriptRunConfig 中将仅配置四个节点。这意味着集群仍然会有一个未配置的节点,因为它能扩展到的最大节点数是五个,正如你在第七章 与计算目标的工作部分中定义的那样,AzureML Python SDK。还有一个可选参数可以用来限制搜索最佳模型的时间,max_duration_minutes 参数,你在上面的示例中没有指定,它定义了执行 超参数调优 过程的最大时长(分钟)。超过该时长后,所有后续调度的运行将自动取消。

  8. 在一个新单元格中,添加以下代码:

    from azureml.core import Experiment
    experiment = Experiment(ws, "chapter09-hyperdrive")
    hyperdrive_run = experiment.submit(hd_config)
    hyperdrive_run.wait_for_completion(show_output=True)
    

    在此代码中,你提交 HyperDriveConfig 以在 hyperdrive_run 变量下执行,该变量是 HyperDriveRun 的实例,继承自正常的 Run 类。

  9. 你可以在 Studio Web UI 中查看该过程的结果。导航到 alpha 超参数。你可以通过视觉化探索 alpha 参数的不同值对 HyperDriveRun (Run 1) 的 alpha 值的影响。

    重要提示

    在你的执行中,运行编号可能不同。每次你执行单元格时,都会创建一个新的运行编号,接着上一个编号。因此,如果你执行一个包含 20 个子运行的超参数调优运行,那么最后一个子运行将是第 21 号运行。下次执行相同代码时,超参数调优运行将从第 22 号开始,最后一个子运行将是第 42 号。此节中提到的运行编号是各个图示中显示的编号,观察到差异是正常的,尤其是在你需要重新运行某些单元格时。

  10. 导航到已完成的 Run 1 运行的 输出 + 日志 标签。你会注意到,在 azureml-logs 文件夹下有一个名为 hyperdrive.txt 的文件,如 图 9.5 所示:https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_09_005.jpg

    图 9.5 – HyperDriveRun 中的日志文件,选取将并行执行的超参数空间中的前四个作业

    该文件包含所有为完成超参数调优过程而计划的作业。实际的运行日志和存储的模型都保存在子运行中。如果你需要调试代码问题,你需要打开其中一个子运行查看脚本错误。

  11. 你还可以获取最佳模型的运行情况,并且相应的 get_best_run_by_primary_metric 方法可以检索 hyperdrive_run 变量所引用的 HyperDriveRun 的最佳运行结果。从那里,你可以读取 Run 对象的 get_metrics 方法,进而使用 get_details 方法获取执行详情。在这些详情中,有一个 runDefinition 对象,它包含一个 arguments 列表,如 图 9.6 所示:

![图 9.6 – 揭开最佳运行.get_details()[‘runDefinition’][‘arguments’] 代码的神秘面纱

](https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_09_006.jpg)

图 9.6 – 揭开最佳运行.get_details()[‘runDefinition’][‘arguments’] 代码的神秘面纱

在这一节中,你看到了如何运行 超参数调优 过程来找到模型 超参数 的最佳值。在下一节中,你将看到如何通过使用提前终止策略来优化寻找最佳值的时间。

使用提前终止策略

HyperDriveConfig 构造函数的参数之一是 policy。该参数接受一个 EarlyTerminationPolicy 对象,定义了可以提前终止运行的策略。默认情况下,这个参数的值为 None,意味着会使用 NoTerminationPolicy 类,允许每次运行执行直到完成。

要能够使用提前终止策略,你的脚本必须在每次运行中执行多个迭代。

Files 视图中,添加一个名为 termination-policy-training 的文件夹,并在其中添加一个 training.py 文件,如 图 9.7 所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_09_007.jpg

图 9.7 – 添加一个执行多个纪元的训练脚本

在训练脚本中添加以下代码:

from azureml.core.run import Run
import argparse
import time
parser = argparse.ArgumentParser()
parser.add_argument("--a", type=int, dest="a", help="The alpha parameter")
parser.add_argument("--b", type=int, dest="b", help="The beta parameter")
args = parser.parse_args()
if (args.a > 2):
    args.a = 0
run = Run.get_context()
def fake_train(run, a, b):
    time.sleep(5)
    metric = a + b
    run.log("fake_metric", metric)
for epoch in range(20):
    fake_train(run, args.a * epoch, args.b)

该脚本获取两个参数,ab,然后调用 fake_train 方法 20 次。在数据科学文献中,人们将这 20 次称为 20 个 纪元,它们是整个训练数据集上的训练周期。

在每个纪元中,a 参数会乘以迭代次数,该次数是从 0 一直到 19 的整数值,然后调用 fake_train 方法。fake_train 方法会暂停 5 秒钟以模拟训练过程,然后将修改后的 a 值加到 b 参数上。结果会记录在 fake_metric 指标中。

此外,在 第 8 行,代码检查传递给脚本的 a 参数。如果它大于 2,它会变为 0。这意味着你正在训练的虚拟模型在 a 值增加到 2 时表现更好,然后它的性能会下降,如 图 9.8 所示。

请注意,你不需要读取任何数据集,因此不需要引用Workspace。这就是为什么上面代码中的第 10 行不需要检查它是否是_OfflineRun对象,就像你在第八章中的将代码移到 Python 脚本文件部分所做的那样,使用 Python 代码进行实验

如果你运行HyperDriveConfig,并在所有从14之间的值上进行网格搜索,观察fake_metric在每个时期的演化。在图的右侧,你可以看到fake_metric是如何受到不同ab值的影响的,a表现得比使用a参数34训练的模型更好,关于fake_metric

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_09_008.jpg

](https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_09_008.jpg)

图 9.8 – 没有早期终止策略的超参数调优

理想情况下,你希望减少等待所有运行完成的时间。EarlyTerminationPolicy 允许你监控正在运行的任务,如果它们的表现比其他任务差,则提前取消它们。最终的输出将像图 9.9中所示,你可以看到有些任务在到达第二十个报告的间隔之前就被终止了(图表从 0 开始计数),节省了时间和计算资源:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_09_009.jpg

](https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_09_009.jpg)

图 9.9 – 使用激进的早期终止策略进行超参数调优

AzureML SDK 提供了一些内置的EarlyTerminationPolicy实现,位于azureml.train.hyperdrive模块中:

  • NoTerminationPolicy:这是默认的停止策略,允许所有运行完成。

  • MedianStoppingPolicy:中位数停止策略计算所有运行的运行平均值。然后,它会取消那些最佳表现差于运行平均值中位数的运行。你可以将此策略看作是将每次运行的表现与前面运行的平均表现进行比较。这个策略的优点在于它考虑了到目前为止所有的运行,而不仅仅是将当前的运行与迄今为止最好的运行进行比较。这一特点使得中位数停止策略能够避免陷入局部最优值。

  • BanditPolicy:Bandit 策略计算当前运行和表现最佳的运行之间的距离,然后根据某些容差标准终止当前运行。你可以定义绝对距离(slack_amount参数)或与表现最佳的运行的最大允许比率(slack_factor参数)。

  • TruncationSelectionPolicy:截断选择策略是最激进的策略,它取消某个百分比(由 truncation_percentage 参数定义)的运行,这些运行在主要指标上的表现排在最后。当对一个相对较新的运行进行排名时,在早期的迭代中,该策略会将其与较老运行在同一迭代的表现进行比较。因此,这个策略力图通过考虑随着训练时间推移模型表现的提升来实现排名的公平性。

所有策略都接受两个可选参数:

  • evaluation_interval:应用策略的频率。

  • delay_evaluation:这将延迟第一次策略评估,直到指定的间隔次数,给予年轻运行足够的时间以达到成熟状态。

让我们使用最推荐的策略 MedianStoppingPolicy,对你上面创建的脚本进行超参数调整:

  1. 转到将在超参数调整过程中使用的 ScriptRunConfig 对象。

  2. 在一个新单元格中,添加以下代码:

    from azureml.train.hyperdrive import (
        GridParameterSampling,    
        choice,
        MedianStoppingPolicy,
        HyperDriveConfig,
        PrimaryMetricGoal
    )
    param_sampling = GridParameterSampling(
        {
            "a": choice(1, 2, 3, 4),
            "b": choice(1, 2, 3, 4),
        }
    )
    early_termination_policy = MedianStoppingPolicy(
        evaluation_interval=1, delay_evaluation=5
    )
    hd_config = HyperDriveConfig(
        policy=early_termination_policy,
        run_config=script,
        hyperparameter_sampling=param_sampling,
        primary_metric_name="fake_metric",
        primary_metric_goal=PrimaryMetricGoal.MAXIMIZE,
        max_total_runs=50,
        max_concurrent_runs=4
    )
    

    这个 HyperDriveConfig 对象使用 MedianStoppingPolicy 作为其策略参数,在第一次 5 次迭代后评估所有运行,并在每次迭代中将它们的结果与当前的运行平均值的中位数进行比较。

  3. 在一个新单元格中,添加以下代码以开始执行你在 步骤 2 中定义的 HyperDriveConfig 对象:

    experiment = Experiment(ws, "chapter09-hyperdrive")
    hyperdrive_run = experiment.submit(hd_config)
    hyperdrive_run.wait_for_completion(show_output=True)
    

    图 9.10 显示了此 HyperDriveRun 运行的结果,其中 16 个作业中只有 8 个提前终止:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_09_010.jpg

图 9.10 – 使用中位数停止早期终止策略的超参数调整

重要提示

在上面的代码中,max_total_runs 参数的值为 50。这是潜在的子运行次数的上限。在这个示例中,你只有 16 种组合。这意味着实验将只运行 16 次,然后停止,因为整个搜索区域已经被搜索完毕。如果你希望 max_total_runs 参数生效,应指定一个小于 16 的值。

到目前为止,你已经看到了如何针对你拥有的数据优化特定的模型。在下一部分,你将看到如何通过 SDK 搜索最佳模型来运行 AutoML 实验,类似于你在第五章中所做的,让机器进行模型训练,通过 Studio 用户界面进行的操作。

使用代码运行 AutoML 实验

到目前为止,在本章中,你一直在微调一个 LassoLars 模型,执行超参数调整过程,以根据训练数据识别 alpha 参数的最佳值。在这一部分,你将使用 AutoML 和 AzureML SDK,自动选择最佳的数据预处理、模型和超参数设置,来匹配你的训练数据集。

要配置一个 AutoMLConfig 对象,你需要定义 任务类型指标训练数据计算预算。该过程的输出是一个模型列表,你可以从中选择最佳的运行和与该运行相关的最佳模型,如图 9.11所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_09_011.jpg

图 9.11 – AutoML 过程

根据你要建模的问题类型,你必须选择 task 参数,选择 classificationregressionforecasting,如图 9.12所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_09_012.jpg

图 9.12 – AutoML 任务类型、算法和支持的指标

图 9.12 显示了 AzureML SDK 支持的部分算法。azureml.train.automl.constants.SupportedModels 包含 classificationregressionforecasting 类,这些类列出了所有作为属性的支持算法。由于预测只是回归的一个更专门化的版本,因此回归的所有算法都可以使用。AutoML 支持一些额外的、更专门的预测算法,例如非常流行的 ARIMA 技术或 Facebook 的 Prophet 算法。

primary_metric 参数决定了模型训练过程中用于优化的指标。回归和预测的指标相同。分类算法使用不同的指标,如图 9.12所示。

训练数据可以通过 training_data 参数提供,可以是 pandas Dataset 对象的格式。训练数据是表格格式,并包括 target 列。你定义你希望预测的列名,传递 label_column_name 参数。默认情况下,AutoML 会使用该数据集进行训练和验证。如果数据集超过 20,000 行,则会进行数据集拆分,保留 10% 用于验证。如果数据集小于 20,000 行,则使用交叉验证。如果你想指定从 training_data 创建多少个折叠,你可以使用 n_cross_validations 参数。另一种方法是提供 validation_size 参数,指定从训练数据中保留并用作验证的百分比(值为 0.01.0)。如果你想手动将数据分割为训练数据和验证数据,你可以将验证数据分配给 validation_data 参数,如本节后面所述。

计算预算 是你愿意为找到最佳机器学习模型而投入的金钱。它由三部分组成:

  • 计算集群的节点类型:计算集群的类型具有的能力越多,运行 AutoML 作业时每秒的成本就越高。这是你在创建计算集群时配置的设置,除非你创建一个新集群,否则在此时无法更改。

  • max_concurrent_iterations参数允许使用最多计算集群中的节点数。这将允许你运行并行迭代,但会增加成本。默认情况下,这个参数是1,意味着一次只允许进行一个迭代。

  • experiment_timeout_hours参数,或者你可以定义experiment_exit_score参数,定义达到某个分数后停止进一步探索。限制计算支出的另一种方法是限制要探索的不同算法和参数组合的数量。默认情况下,AutoML 会探索 1,000 种组合,你可以通过指定iterations参数来限制这个数量。

现在你已经探索了所有需要在AutoMLConfig对象中配置的选项,导航到你的chapter09.ipynb笔记本,添加一个新的单元格,并输入以下代码:

from azureml.core import Workspace, Dataset
from azureml.train.automl import AutoMLConfig
ws = Workspace.from_config()
compute_target = ws.compute_targets["cpu-sm-cluster"]
diabetes_dataset = Dataset.get_by_name(workspace=ws, name='diabetes')
train_ds,validate_ds = diabetes_dataset.random_split(percentage=0.8, seed=1337)
experiment_config = AutoMLConfig(
    task = "regression",
    primary_metric = 'normalized_root_mean_squared_error',
    training_data = train_ds,
    label_column_name = "target",
    validation_data = validate_ds,
    compute_target = compute_target,
    experiment_timeout_hours = 0.25,
    iterations = 4
)

在这段代码中,你获取了工作空间、计算集群的引用以及diabetes数据集,你将其分为训练集和验证集。然后你创建了一个AutoMLConfig对象,用于处理target列。你还指定了validation_data参数。

重要提示

如果不想分割数据集,你可以将整个数据集传递给training_data参数,并跳过validation_data参数。由于数据集仅包含 442 行,AutoML 会将训练数据集分为 10 个折叠,用于执行交叉验证技术。

然后,你定义了用于此训练的compute_target实验,并通过允许实验运行一个小时四分之一(experiment_timeout_hours参数),即 15 分钟,并仅探索 4 种模型和参数组合(iterations参数),来确定你的计算预算。在你的案例中,iterations参数可能会是终止AutoML实验的原因。

重要提示

对于预测,你需要指定forecasting_parameters,除了你之前定义的回归参数外。ForecastingParameters类包含以下常用参数:

  1. time_column_name:表示时间序列时间维度的列。

  2. max_horizon:所需的预测时间范围,以时间序列的频率为单位。默认值为1,这意味着你的模型将能够预测未来的一个时间点。这个时间点是你的数据集所使用的频率。如果你的数据集每小时有 1 行,并且你想预测 7 天的时间范围,则max_horizon需要设置为 7 天×24 个时间点/天=168。

到目前为止,您已经创建了experiment_config,它包含了您即将执行的AutoML实验的配置。添加一个新单元格,并输入以下代码来启动 AutoML 训练过程:

from azureml.core.experiment import Experiment
my_experiment = Experiment(ws, 'chapter09-automl-experiment')
run = my_experiment.submit(experiment_config, 
                           show_output=True)

run变量包含对通过submit方法创建的AutoMLRun对象的引用。几分钟后,过程将完成。要获取当前最佳的运行和最佳模型,您可以使用get_output()方法,如以下代码片段所示:

best_run, best_model = run.get_output()

或者,您也可以直接通过相应的Tuple索引访问最佳运行和最佳模型,如以下代码片段所示:

best_run = run.get_output()[0]
best_model = run.get_output()[1]

在每个自动化机器学习实验中,您的数据会自动进行缩放或归一化,以帮助算法表现得更好。这一数据转换将成为训练模型的一部分。这意味着您的数据首先通过数据转换器,然后模型将使用新的特征名称进行训练,这些特征名称对您不可见。您将在第十章《理解模型结果》中看到sklearn.composeColumnTransformer的示例。要查看嵌入在 AutoML 模型中的实际步骤,您可以使用生成的模型的steps属性:

best_model.steps

第一步名为datatransformer,包含了用于我们的diabetes数据集的插补器。无论是回归任务还是分类任务,这一步骤都被命名为datatransformer。对于预测任务,这一步骤命名为timeseriestransformer,并包含了额外的基于日期的转换。要获取转换列表和工程特征的名称,您可以使用以下代码片段:

print(best_model.named_steps['datatransformer'] \
                 .get_featurization_summary())
feature_names=best_model.named_steps['datatransformer'] \
                 .get_engineered_feature_names()
print("Engineered feature names:")
print(feature_names)

在本节中,您通过AutoML寻找了针对糖尿病回归问题的最佳模型。这也总结了您可以根据特定数据集优化机器学习模型的最常用方法。

总结

在本章中,您探讨了优化特定模型以在数据集上表现良好的最常用方法,以及如何自动化模型选择过程。您首先通过执行并行化的HyperDriveConfig类来优化LassoLars模型的alpha参数,您正在该参数下训练diabetes数据集。接着,您自动化了模型选择,使用 AutoML 来检测最佳的算法和参数组合,从而预测diabetes数据集的target列。

在下一章中,您将以此为基础,学习如何使用 AzureML SDK 来解释模型结果。

问题

  1. 您想通过model = run.get_output()[0]获取最佳模型。

    b. model = run.get_output()[1]

    c. model = run.get_outputs()[0]

    d. model = run.get_outputs()[1]

  2. 您想运行一个预测的ForecastingParameters类吗?

    a. forecast_horizon = 5 * 1

    b. forecast_horizon = 5 * 24

    c. forecast_horizon = 5 * 12

进一步阅读

本节提供了一些有用的网络资源列表,帮助您增加对 AzureML SDK 和本章中使用的各种代码片段的了解:

第十章:第十章:理解模型结果

在本章中,你将学习如何分析机器学习模型的结果,以理解模型为何做出该推断。理解模型为何预测某个值是避免黑箱模型部署的关键,并且能够理解模型可能存在的局限性。在本章中,你将学习 Azure 机器学习的可用解释功能,并可视化模型解释结果。你还将学习如何分析潜在的模型错误,检测模型表现不佳的群体。最后,你将探索一些工具,帮助你评估模型的公平性,并让你能够缓解潜在问题。

本章将涵盖以下主题:

  • 创建负责任的机器学习模型

  • 解释模型的预测

  • 分析模型错误

  • 检测潜在的模型公平性问题

技术要求

你需要拥有一个 Azure 订阅。在该订阅中,你需要有一个名为packt-azureml-rg的资源组。你还需要有ContributorOwner权限的packt-learning-mlw。如果你按照第二章 部署 Azure 机器学习工作区资源中的指引操作,这些资源应该可以获得。

你还需要对Python语言有基本了解。本章中的代码片段针对 Python 3.6 或更高版本。你还应该熟悉在 Azure 机器学习工作室中的 Notebook 体验,这部分内容已在之前的章节中介绍。

本章假设你已经创建了一个名为cpu-sm-cluster的计算集群,如第七章 使用 AzureML Python SDK中“与计算目标协作”部分所述。

你可以在本书的仓库中找到本章的所有 Notebook 和代码片段,链接为bit.ly/dp100-ch10

创建负责任的机器学习模型

机器学习使你能够创建可以影响决策并塑造未来的模型。拥有强大的能力意味着肩负巨大的责任,这也是 AI 治理成为必需的原因,通常被称为负责任的 AI 原则与实践。Azure 机器学习提供了支持负责任 AI 创建的工具,具体体现在以下三个支柱上:

  • 理解:在发布任何机器学习模型之前,你需要能够解释和说明模型的行为。此外,你还需要评估并缓解针对特定群体的潜在模型不公平性。本章重点介绍那些帮助你理解模型的工具。

  • 保护:在这里,你部署了保护个人及其数据的机制。在训练模型时,使用的是来自真实人的数据。例如,在第八章《实验 Python 代码》中,你在糖尿病患者的医疗数据上训练了一个模型。尽管具体的训练数据集没有包含任何个人可识别信息PII),原始数据集却包含了这些敏感信息。有一些开源库,如SmartNoise,提供了基本的构建模块,能够利用经过验证和成熟的差分隐私研究技术来实现数据处理机制。

    例如,使用 SmartNoise 构建的查询引擎可以让数据科学家在敏感数据上执行聚合查询,并在结果中添加统计噪声,以防止意外识别数据集中某一行的单个数据。其他开源库,如presidio,提供了一种不同的数据保护方法,允许你快速识别并匿名化私密信息,如信用卡号、姓名、地点、财务数据等。这些库更多地关注原始文本输入,这是你在构建自然语言处理NLP)模型时通常使用的输入。它们提供了可以用来匿名化数据的模块,便于在训练模型之前处理数据。另一种保护个人及其数据的方法是加密数据,并使用加密数据集进行整个模型训练过程,而无需解密。这可以通过同态加密HE)实现,这是一种加密技术,允许在加密数据上执行某些数学操作,而无需访问私有(解密)密钥。计算结果是加密的,只有私钥的持有者才能揭示。这意味着,使用HE,你可以将两个加密值AB相加,得到一个值C,这个值只能通过加密值AB的私钥解密,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_001.jpg

图 10.1 – 使用 HE 在加密数据上执行操作

  • 控制:控制和记录端到端过程是所有软件工程活动中的一个基本原则。DevOps 实践通常用于确保端到端过程的自动化和治理。DevOps 中的一个关键实践是记录每个步骤中的关键信息,让你在每个阶段做出负责任的决策。Azure 机器学习工作区允许你为你在端到端机器学习过程中的各种工件添加标签和描述。下图展示了你如何为在 第九章 中执行的 AutoML 运行添加描述,优化机器学习模型

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_002.jpg

图 10.2 – 为运行添加描述以进行文档记录

类似于为运行添加描述,你可以为你生产的各种工件(如模型)添加标签。标签是键/值对,例如 PyTorchFramework 标签键的值。你可能希望将以下信息作为模型 数据表 的一部分进行记录:

  • 模型的预期用途

  • 模型架构,包括使用的框架

  • 使用的训练和评估数据

  • 训练模型性能指标

  • 公平性信息,你将在本章中阅读到

这些信息可以作为标签的一部分,而 数据表 可以是一个通过这些标签自动生成的 Markdown 文档。

本节中,你对帮助创建负责任 AI 的工具和技术进行了概述。所有三个支柱同等重要,但对于 DP100 考试,你将专注于理解类别中的工具,从模型可解释性开始,你将在下一节中深入了解。

解释模型的预测结果

能够解释模型的预测结果有助于数据科学家、审计员和商业领袖通过查看驱动模型预测的主要因素来理解模型行为。它还使他们能够进行假设分析,以验证特征对预测的影响。Azure 机器学习工作区与 InterpretML 集成,提供这些功能。

InterpretML 是一个开源社区,提供用于执行模型可解释性的工具。社区包含几个项目,其中最著名的如下:

  • InterpretInterpret-Community 仓库,专注于解释使用表格数据的模型,例如你在本书中所使用的糖尿病数据集。你将在本节中使用 interpret-community 仓库。

  • interpret-text 扩展了解释工作到文本分类模型。

  • 多样化反事实解释DiCE)用于机器学习,可以帮助你检测在数据行中需要进行的最少修改,以改变模型的输出。例如,假设你有一个贷款审批模型,它刚刚拒绝了一笔贷款申请。客户问有什么可以做的来让贷款获得批准。DiCE可以提供批准贷款的最少修改,例如减少信用卡数量或将年薪提高 1%。

解释机器学习模型时有两种方法:

  • DecisionTreeClassifier 提供了 feature_importances_ 属性,允许你理解特征如何影响模型的预测。InterpretML 社区提供了几种更先进的玻璃盒模型实现。这些模型一旦训练完成,允许你获取解释器并查看哪些特征驱动了什么结果,这也被称为可解释性结果。这些模型的解释器是无损的,意味着它们准确地解释了每个特征的重要性。

  • 黑盒解释:如果你训练的模型没有内置的解释器,你可以创建一个黑盒解释器来解释模型的结果。你需要提供训练好的模型和一个测试数据集,解释器会观察特征值的变化如何影响模型的预测。例如,在贷款审批模型中,这可能会调整一个被拒绝记录的年龄和收入,观察这些变化是否会改变预测结果。通过这些实验获取的信息可以用来生成特征重要性的解释。这项技术可以应用于任何机器学习模型,因此被认为是与模型无关的。由于它们的性质,这些解释器是有损的,意味着它们可能无法准确表示每个特征的重要性。在科学文献中,有一些著名的黑盒技术,例如Shapley 加法解释SHAP)、局部可解释模型无关解释LIME)、部分依赖PD)、置换特征重要性PFI)、特征交互莫里斯敏感性分析。黑盒解释器的一个子类别是灰盒解释器,它利用模型结构的相关信息来获得更好、更快的解释。例如,有专门针对树模型(树解释器)、线性模型(线性解释器)甚至深度神经网络(深度解释器)的解释器。

模型解释器可以提供两种类型的解释:

  • 局部实例级特征重要性侧重于特征对特定预测的贡献。例如,它可以帮助回答为什么模型拒绝了某个特定客户的贷款申请。并非所有技术都支持局部解释。例如,基于PFI的方法不支持实例级特征重要性。

  • 全局聚合级特征重要性 解释了模型整体的表现,考虑到模型所做的所有预测。例如,它可以回答哪个特征对于贷款批准来说最为重要。

现在,你已经了解了模型解释的基本理论,是时候获得一些实践经验了。你将从训练一个简单的 sklearn 模型开始。

训练贷款批准模型

在本节中,你将对一个你将生成的贷款批准数据集训练一个分类模型。你将在接下来的章节中使用该模型分析其结果。让我们开始吧:

  1. 导航到 chapter10,然后创建一个名为 chapter10.ipynb 的笔记本,如下所示:https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_003.jpg

    图 10.3 – 在 chapter10 文件夹中创建 chapter10 笔记本

  2. 你需要安装 interpret-community 库的最新包、微软的负责任 AI 小部件,以及 # 或删除该单元格:https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_004.jpg

    图 10.4 – 在安装必要的包后重新启动 Jupyter 内核

  3. 在重新启动内核后,在笔记本中添加一个新单元格。使用以下代码生成一个贷款数据集:

    from sklearn.datasets import make_classification
    import pandas as pd
    import numpy as np
    features, target = make_classification(
        n_samples=500, n_features=3, n_redundant=1, shift=0,
        scale=1,weights=[0.7, 0.3], random_state=1337)
    def fix_series(series, min_val, max_val):
        series = series - min(series)
        series = series / max(series)
        series = series * (max_val - min_val) + min_val
        return series.round(0)
    features[:,0] = fix_series(features[:,0], 0, 10000)
    features[:,1] = fix_series(features[:,1], 0, 10)
    features[:,2] = fix_series(features[:,2], 18, 85)
    classsification_df = pd.DataFrame(features, dtype='int')
    classsification_df.set_axis(
       ['income','credit_cards', 'age'],
       axis=1, inplace=True)
    classsification_df['approved_loan'] = target
    classsification_df.head()
    

    这段代码将生成一个包含以下正态分布特征的数据集:

    • income 的最小值为 0,最大值为 10000

    • credit_cards 的最小值为 0,最大值为 10

    • age 的最小值为 18,最大值为 85

    你将预测的标签是 approved_loan,这是一个布尔值,且在 500 个样本(n_samples)中,只有 30%(weights)是批准的贷款。

  4. 在本章后面,你将针对这个数据集运行一个 AutoML 实验。注册数据集,正如你在 第七章 中看到的,AzureML Python SDK。在你的笔记本中添加以下代码:

    from azureml.core import Workspace, Dataset
    ws = Workspace.from_config()
    dstore = ws.get_default_datastore()
    loans_dataset = \
    Dataset.Tabular.register_pandas_dataframe(
        dataframe=classsification_df,
        target=(dstore,"/samples/loans"),
        name="loans",
        description="A genarated dataset for loans")
    

    如果你访问注册的数据集,可以查看数据集的简介,如下所示:

    https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_005.jpg

    图 10.5 – 生成的数据集简介

  5. 为了能够训练和评估模型,你需要将数据集分割成训练集和测试集。使用以下代码来完成此操作:

    from sklearn.model_selection import train_test_split
    X = classsification_df[['income','credit_cards', 'age']]
    y = classsification_df['approved_loan'].values
    x_train, x_test, y_train, y_test = \
            train_test_split(X, y, 
                           test_size=0.2, random_state=42)
    

    首先,将数据集分成两部分,一部分包含特征,另一部分包含你要预测的标签。然后,使用 train_test_split 方法将 500 个样本的数据分割成包含 500 * 0.2 = 100 个测试记录的数据集,以及包含剩余 400 个样本的训练集。

  6. 下一步是初始化模型,并将其拟合到训练数据集。在第九章《优化 ML 模型》中,你学习了 Azure 机器学习的datatransformer步骤是一个ColumnTransformer,它对所有特征应用MinMaxScaler。这个转换器会缩放每个特征的值。

  7. model步骤是你正在训练的实际模型,即RandomForestClassifier

然后,你必须调用已实例化的管道的fit方法,将其训练与训练数据集对齐。

重要提示

你不需要使用Pipeline来受益于本章讨论的可解释性特性。你可以直接通过将模型赋值给model_pipeline变量来使用该模型,例如model_pipeline=RandomForestClassifier()。添加datatransformer步骤是为了帮助你理解 AutoML 是如何构建管道的。使用MinMaxScaler还提高了结果模型的准确性。你可以随意尝试不同的缩放器,以观察结果模型的差异。

  1. 现在你已经有了一个训练好的模型,可以进行测试。让我们测试三个虚构的客户:

    • 一位 45 岁、有两张信用卡、月收入为2000的人。

    • 一位 45 岁、有九张信用卡、月收入为2000的人。

    • 一位 45 岁、有两张信用卡、月收入为10000的人。

    要做到这一点,请在新的笔记本单元格中使用以下代码:

    test_df = pd.DataFrame(data=[
        [2000, 2, 45],
        [2000, 9, 45],
        [10000, 2, 45]
    ], columns= ['income','credit_cards', 'age'])
    test_pred = model_pipeline.predict(test_df)
    print(test_pred)
    

    打印结果是[0 1 1],这意味着第一个客户的贷款将被拒绝,而第二个和第三个客户的贷款将被批准。这表明incomecredit_cards特征可能在模型预测中起着重要作用。

  2. 由于训练后的模型是一个决策树,属于玻璃盒模型类别,你可以获取在训练过程中计算出的特征重要性。使用以下代码在新的笔记本单元格中:

    model_pipeline.named_steps['model'].feature_importances_
    

    这段代码获取实际的RandomForestClassifier实例,并调用feature_importances_。其输出类似于array([0.66935129, 0.11090936, 0.21973935]),这显示income(第一个值)是最重要的特征,但与我们在步骤 7中观察到的情况相比,age(第三个值)似乎比credit_cards(第二个值)更为重要。

    重要提示

    模型的训练过程是非确定性的,这意味着你的结果与书中示例中的结果会有所不同。数值应该相似,但不完全相同。

在本节中,你训练了一个简单的feature_importances_属性。在下一节中,你将使用一种更高级的技术,允许你解释任何模型。

使用表格解释器

到目前为止,你已经使用sklearn库的功能来训练并理解模型的结果。从现在开始,你将使用解释社区的包来更准确地解释你训练好的模型。你将使用SHAP,这是一种黑箱技术,可以告诉你哪些特征在将预测从拒绝转为批准(或反之)的过程中发挥了什么作用。让我们开始吧:

  1. 在一个新的笔记本单元格中,添加以下代码:

    from interpret.ext.blackbox import TabularExplainer
    explainer = TabularExplainer(
                  model_pipeline.named_steps['model'],
                  initialization_examples=x_train, 
                  features= x_train.columns,
                  classes=["Reject", "Approve"],
                  transformations=
                    model_pipeline.named_steps['datatransformer']) 
    

    这段代码创建了一个TabularExplainer,它是 SHAP 解释技术的一个封装类。这意味着该对象会根据传入的模型选择最合适的 SHAP 解释方法。在这种情况下,由于模型是基于树的,它将选择树解释器(tree explainer)。

  2. 使用这个解释器,你将获得局部实例级别的特征重要性,以便更深入地理解模型在训练贷款批准模型部分的步骤 7中为什么会给出这样的结果。在一个新的笔记本单元格中,添加以下代码:

    local_explanation = explainer.explain_local(test_df)
    sorted_local_values = \
        local_explanation.get_ranked_local_values()
    sorted_local_names = \
        local_explanation.get_ranked_local_names()
    for sample_index in range(0,test_df.shape[0]):
        print(f"Test sample number {sample_index+1}")
        print("\t", test_df.iloc[[sample_index]]
                             .to_dict(orient='list'))
        prediction = test_pred[sample_index]
        print("\t", f"The prediction was {prediction}")
        importance_values = \
            sorted_local_values[prediction][sample_index]
        importance_names = \
            sorted_local_names[prediction][sample_index]
        local_importance = dict(zip(importance_names,
                                    importance_values))
        print("\t", "Local feature importance")
        print("\t", local_importance)
    

    这段代码生成了以下截图所示的结果。如果你关注测试样本 2,你会注意到它显示信用卡数credit_cards)是该特定样本被预测为批准预测值为 1)的最重要原因(见0.33的值)。同样样本中收入(其值大约为**-0.12**)的负值表明该特征推动模型拒绝贷款:

    https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_006.jpg

    图 10.6 – 局部重要性特征展示了每个特征对每个测试样本的重要性

  3. 你还可以看到收入income)、年龄age)以及信用卡数credit_cards),它们对应的重要性值分别约为0.280.090.06(实际值可能与你的执行结果有所不同)。请注意,这些值与训练贷款批准模型部分的步骤 8中获得的值不同,尽管顺序保持一致。这是正常现象,因为使用方法:shap.tree,这表明TabularExplainer使用树解释器对模型进行了解释,如本节步骤 1所提到的。

  4. 最后,你必须渲染解释仪表板,以查看你在步骤 3中生成的global_explanation结果。在笔记本中添加以下代码:

    from raiwidgets import ExplanationDashboard
    ExplanationDashboard(global_explanation, model_pipeline, dataset=x_test, true_y=y_test)
    

    这将渲染一个交互式小部件,你可以用它来理解模型对你提供的测试数据集的预测。点击特征重要性汇总Aggregate feature importance)标签,你应该会看到在步骤 3中看到的相同结果:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_007.jpg

图 10.7 – 解释社区提供的解释仪表板

你将在查看解释结果部分更详细地探索这个仪表板。

到目前为止,你已经训练了一个模型,并使用 SHAP 解释技术解释了模型预测的特征重要性,无论是在全局还是局部层面上进行特定推理。接下来的部分,你将了解 Interpret-Community 包中可用的其他解释技术。

理解表格数据的解释技术

在上一节中,你使用了表格解释器自动选择了一个可用的 SHAP 技术。目前,解释社区支持以下 SHAP 解释器:

  • Tree explainer 用于解释决策树模型。

  • Linear explainer 解释线性模型,并且也可以解释特征间的相关性。

  • Deep explainer 为深度学习模型提供近似解释。

  • Kernel explainer 是最通用且最慢的解释器。它可以解释任何函数的输出,使其适用于任何模型。

SHAP 解释技术的替代方法是构建一个更容易解释的代理模型,例如解释社区提供的玻璃盒子模型,来重现给定黑盒的输出,并解释该代理模型。这个技术被Mimic 解释器使用,你需要提供以下的一个玻璃盒子模型:

  • LGBMExplainableModel,这是一个 LightGBM(一个基于决策树的快速高效框架)可解释模型

  • LinearExplainableModel,这是一个线性可解释模型

  • SGDExplainableModel,这是一个随机梯度下降可解释模型

  • DecisionTreeExplainableModel,这是一个决策树可解释模型

如果你想在上一节的步骤 1 中使用 Mimic 解释器,代码会像这样:

from interpret.ext.glassbox import (
    LGBMExplainableModel,
    LinearExplainableModel,
    SGDExplainableModel,
    DecisionTreeExplainableModel
)
from interpret.ext.blackbox import MimicExplainer
mimic_explainer = MimicExplainer(
           model=model_pipeline, 
           initialization_examples=x_train,
           explainable_model= DecisionTreeExplainableModel,
           augment_data=True, 
           max_num_of_augmentations=10,
           features=x_train.columns,
           classes=["Reject", "Approve"], 
           model_task='classification')

你可以从第 1 行中的 import 语句中选择任何代理模型。在这个示例中,你使用的是 DecisionTreeExplainableModel。要获取全局解释,代码与在步骤 3 中编写的代码相同,像这样:

mimic_global_explanation = \
       mimic_explainer.explain_global(x_test)
print("Feature names:", 
       mimic_global_explanation.get_ranked_global_names())
print("Feature importances:",
       mimic_global_explanation.get_ranked_global_values())
print(f"Method used: {mimic_explainer._method}")

尽管特征重要性的顺序相同,但计算出来的特征重要性值是不同的,如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_008.jpg

图 10.8 – 使用决策树玻璃盒子模型计算的 Mimic 解释器特征重要性

类似于 mimic_explainer 使用相同的代码来计算局部实例级别的特征重要性,就像在上一节的步骤 2 中所做的那样。解释可以在以下屏幕截图中看到:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_009.jpg

图 10.9 – 使用 Mimic 解释器的决策树玻璃盒子模型计算的局部特征重要性

Interpret-Community 提供的最后一个解释技术是基于PFI的技术。该技术会通过改变每个特征的值,观察模型预测的变化。要创建一个 PFI 解释器来解释你的模型,你需要以下代码:

from interpret.ext.blackbox import PFIExplainer
pfi_explainer = PFIExplainer(model_pipeline,
                             features=x_train.columns,
                             classes=["Reject", "Approve"])

获取全局解释需要传入true_labels参数,这是数据集的真实标签,即实际值:

pfi_global_explanation = \
        pfi_explainer.explain_global(x_test, 
                                     true_labels=y_test)
print("Feature names:", 
        pfi_global_explanation.get_ranked_global_names())
print("Feature importances:",
        pfi_global_explanation.get_ranked_global_values())
print(f"Method used: {pfi_explainer._method}")

此代码的结果可以在此处查看。由于credit_cardsage特征的重要性值非常相似,结果中它们的顺序可能会互换:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_010.jpg

图 10.10 – 通过 PFI 解释器计算的全局特征重要性

重要提示

由于PFI 解释器的性质,你不能使用它来创建局部实例级特征重要性。如果在考试中被问到该技术是否能提供局部解释,记住这一点。

在本节中,你了解了 Interpret-Community 包支持的所有解释技术。在下一节中,你将探索解释仪表板所提供的功能,以及该仪表板如何嵌入到 Azure 机器学习工作室中。

审查解释结果

Azure 机器学习与 Interpret-Community 的工作有着丰富的集成点。其中一个集成点是解释仪表板,它嵌入在每个运行中。你可以使用来自azureml.interpret包的ExplanationClient上传和下载模型解释到工作区。如果你使用TabularExplainer使用表格解释器一节中创建了全局解释,导航至chapter10.ipynb笔记本,在文件末尾添加一个新单元格,并输入以下代码:

from azureml.core import Workspace, Experiment
from azureml.interpret import ExplanationClient
ws = Workspace.from_config()
exp = Experiment(workspace=ws, name="chapter10")
run = exp.start_logging()
client = ExplanationClient.from_run(run)
client.upload_model_explanation(
    global_explanation, true_ys= y_test,
    comment='global explanation: TabularExplainer')
run.complete()
print(run.get_portal_url())

这段代码在chapter10实验中启动一个新的运行。通过该运行,你创建一个ExplanationClient,用来上传你生成的模型解释和真实标签(true_ys),这些有助于仪表板评估模型的表现。

如果你访问此代码输出的门户链接,你将进入一个运行页面,在解释标签中,你需要选择左侧的解释 ID,然后访问聚合特征重要性标签以查看解释仪表板,如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_011.jpg

图 10.11 – 审查存储在 Azure 机器学习工作区中的全局解释

ExplanationClient由 Azure 机器学习的chapter10.ipynb笔记本使用,并在新单元格中添加以下代码块:

from azureml.core import Workspace, Dataset, Experiment
from azureml.train.automl import AutoMLConfig
ws = Workspace.from_config()
compute_target = ws.compute_targets["cpu-sm-cluster"]
loans_dataset = Dataset.get_by_name(
                            workspace=ws, name='loans')
train_ds,validate_ds = loans_dataset.random_split(
                             percentage=0.8, seed=1337)

这段代码看起来非常类似于你在第九章中使用的代码,优化机器学习模型,位于使用代码运行 AutoML 实验部分。在这段代码中,你正在获取 Azure 机器学习工作区的引用,以及loans数据集,然后将数据集分割为训练集和验证集。

在相同或新建的单元格中,添加以下代码块:

experiment_config = AutoMLConfig(
    task = "classification",
    primary_metric = 'accuracy',
    training_data = train_ds,
    label_column_name = "approved_loan",
    validation_data = validate_ds,
    compute_target = compute_target,
    experiment_timeout_hours = 0.25,
    iterations = 4,
    model_explainability = True)
automl_experiment = Experiment(ws, 'loans-automl')
automl_run = automl_experiment.submit(experiment_config)
automl_run.wait_for_completion(show_output=True)

在这段代码中,你正在启动model_explainability(默认值为True)。这个选项会在AutoML过程完成后安排最佳模型的说明。一旦运行完成,转到该运行的 UI,并打开模型标签,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_012.jpg

图 10.12 – AutoML 运行中最佳模型的说明已可用

点击最佳模型的查看说明链接,进入训练该特定模型的子运行的说明标签。当你进入说明标签时,你会注意到AutoML存储了两个全局说明:一个是原始特征的说明,另一个是工程特征的说明。你可以通过选择屏幕左侧的适当 ID,在这两个说明之间切换,如下图所示。原始特征是来自原始数据集的特征。工程特征是经过预处理后得到的特征。这些工程特征是模型的内部输入。如果你选择较低的说明 ID并查看聚合特征重要性区域,你会注意到AutoML已将信用卡号转换为分类特征。此外,与模型训练中产生的三个特征相比,模型的输入是 12 个特征。

你可以在这里查看这些特征及其相应的特征重要性:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_013.jpg

图 10.13 – 工程特征的全局说明

由于工程特征较难理解,请转到顶部的说明 ID,这是你目前为止使用的三个原始特征所在的位置。点击数据集浏览器标签,如下图所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_014.jpg

图 10.14 – 数据集浏览器中的原始特征说明

在这里,我们可以看到以下内容:

  1. Mimic解释器用于解释特定的模型(这是一个XGBoostClassifier,如图 10.12所示)。作为替代模型的glassbox模型是一个LGBMExplainableModel,如前面截图的左上角所示。

  2. 您可以编辑队列或定义新的队列,以便通过从 选择要探索的数据集队列 下拉菜单中选择它们来专注于特定的子组。要定义一个新的队列,您需要指定要应用的数据集过滤条件。例如,在前述截图中,我们定义了一个名为 年龄 _45 的队列,它有一个单一的过滤器(年龄 == 45)。在测试数据集中有 4 个数据点 由此解释仪表板使用。

  3. 您可以通过点击前述截图中标记为 3 的高亮区域来修改 x 轴和 y 轴字段。这使您可以改变视图并获得关于特征与预测值或基本事实之间相关性的见解,特征之间的相关性以及对您的模型理解分析有意义的任何其他视图。

聚合特征重要性选项卡中,如所示,您可以查看您定义的所有数据或特定队列的特征重要性:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_015.jpg

图 10.15 – 根据收入的原始特征与队列和依赖关系的聚合特征重要性

在本例中,收入 特征对于 年龄 _45 队列比一般公众更重要,由 所有数据 表示。如果您点击特征重要性条,下面的图表会更新,显示这个特征如何影响模型决定拒绝贷款请求(类别 0)。在这个例子中,您可以看到从 0 到略高于 5,000 的收入推动模型拒绝贷款,而从 6,000 开始的收入则产生负面影响,这意味着它们试图推动模型批准贷款。

解释仪表板中有大量的功能,而且随着对解释社区的贡献,新功能会不断出现。在本节中,您回顾了仪表板的最重要功能,这些功能帮助您理解模型为什么会做出预测以及如何可能调试性能不佳的边缘案例。

在下一节中,您将学习错误分析,这是微软整体负责人工智能小部件包的一部分。这个工具允许您了解模型的盲点,即模型表现不佳的情况。

分析模型错误

错误分析 是一种模型评估/调试工具,可以帮助你更深入地了解机器学习模型的错误。错误分析帮助你识别数据集中错误率高于其他记录的群体。你可以更密切地观察被错误分类和有误的数据点,查看是否能发现任何系统性模式,例如是否某些群体没有数据可用。错误分析也是描述当前系统缺陷并与其他利益相关者和审计人员沟通的有效方式。

该工具由多个可视化组件组成,可以帮助你了解错误出现的位置。

导航到 chapter10.ipynb 笔记本。在 菜单 中,点击 编辑器 子菜单下的 在 Jupyter 中编辑,以便在 Jupyter 中打开相同的笔记本并继续编辑,如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_016.jpg

图 10.16 – 在 Jupyter 中编辑笔记本以更好地与小部件兼容

重要说明

在编写本书时,由于笔记本体验的安全限制,错误分析面板无法在笔记本环境中运行,这些限制会妨碍某些功能的正常工作。如果你尝试在笔记本中运行,它不会生成必要的可视化效果。因此,你需要在 Jupyter 中打开笔记本,而这一步在你阅读本书时可能不再需要。

在 Jupyter 环境中,在文件末尾添加一个新的单元格并输入以下代码:

from raiwidgets import ErrorAnalysisDashboard
ErrorAnalysisDashboard(global_explanation, model_pipeline, 
                       dataset=x_test, true_y=y_test)

请注意,这段代码与你用来触发解释面板的代码非常相似。

重要说明

确保你关闭所有其他编辑环境中的笔记本,比如在 Azure 机器学习工作室中的笔记本体验。如果笔记本被其他编辑器意外修改,你可能会丢失部分代码。

该工具以全局视图打开,如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_017.jpg

图 10.17 – 错误分析面板在 Jupyter 环境中的加载情况

在此视图中,你可以查看模型在整个数据集上的错误率。在这个视图中,你可以看到一棵二叉树,描述了在可解释子群体之间的数据分区,这些子群体具有出乎意料的高或低错误率。在我们的示例中,模型的所有错误都发生在收入小于或等于 6144 的数据中,这占 7.25% 的错误率,意味着 7.25% 的月收入小于 6144 的贷款被错误分类。错误覆盖率是所有错误中落入此节点的部分,在这种情况下,所有错误都位于该节点中(100%)。节点中的数字表示数据的分布情况。这里,69 条记录中有 5 条是错误的,它们属于这个节点。

一旦你选择了树图中的某个节点,你可以点击群体设置群体信息,并将这些记录保存为一个感兴趣的群体。这个群体可以用于解释仪表板。在点击解释按钮后,你将进入数据探索器视图,如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_018.jpg

图 10.18 – 针对树图中选择的特定群体的数据探索器

此视图已经预选了节点的群体。它具有类似于解释仪表板的功能,比如查看影响所选群体整体模型预测的特征重要性。此视图还提供了局部解释标签,允许你理解个别错误记录,甚至进行假设分析,了解模型何时会正确分类该记录。

通过点击小部件左上角的错误探索器链接,你将返回树图视图。在错误探索器:下拉菜单中,选择热力图,而不是当前选中的树图。这将引导你到错误热力图视图,如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_019.jpg

图 10.19 – 错误热力图视图

此视图根据左上角选定的特征,以一维或二维的方式对数据进行切分。热力图通过较深的红色来可视化具有较高错误的单元格,以引起用户对高错误差异区域的注意。带有条纹的单元格表示没有评估样本,这可能表明存在隐藏的错误区域。

在本节中,我们提供了错误分析仪表板的功能概述,并展示了它如何帮助你理解模型的错误发生位置。该工具可以帮助你识别这些错误区域,并通过设计新特征、收集更好的数据、舍弃部分当前的训练数据,或进行更好的超参数调整来减轻它们。

在接下来的部分,你将了解 Fairlearn,这是一种工具,能帮助你评估模型的公平性并缓解任何观察到的不公平问题。

检测潜在的模型公平性问题

机器学习模型可能由于多种原因表现不公平:

  • 社会中的历史偏见可能会反映在用于训练模型的数据中。

  • 模型开发者所做的决策可能存在偏差。

  • 用于训练模型的数据缺乏代表性。例如,某一特定人群的数据点可能太少。

由于很难确定导致模型表现不公平的实际原因,因此定义模型不公平行为的标准是根据它对人们的影响来判断的。模型可能造成的两种显著伤害类型是:

  • 资源分配损害:这是指模型拒绝为某个群体提供机会、资源或信息。例如,在招聘过程中或我们迄今为止处理的贷款贷款示例中,某些群体可能没有被聘用或获得贷款的机会。

  • 服务质量损害:这是指系统未能为每个人提供相同的服务质量。例如,面部识别在某些人群中的准确度较低。

基于此,很明显,模型公平性问题不能通过自动化解决,因为没有数学公式。Fairlearn是一个工具包,提供帮助评估和缓解分类和回归模型预测公平性的问题的工具。

在我们的案例中,如果将年龄分组视为一个敏感特征,我们可以使用以下代码分析模型基于准确率的行为:

from fairlearn.metrics import MetricFrame
from sklearn.metrics import accuracy_score
y_pred = model_pipeline.predict(x_test)
age = x_test['age']
model_metrics = MetricFrame(accuracy_score, y_test, 
                             y_pred, sensitive_features=age)
print(model_metrics.overall)
print(model_metrics.by_group[model_metrics.by_group < 1])

这段代码获取了你在训练贷款批准模型部分中训练的模型的预测结果,并为x_test数据集生成预测结果。然后,它将x_test['age']特征的所有值分配给age变量。接着,使用MetricFrame,我们可以计算模型的accuracy_score指标,既可以计算整个测试数据集的准确率(存储在overall属性中),也可以按组计算准确率(存储在by_group属性中)。这段代码会打印整体准确率和分组准确率,后者的值小于 1。结果显示在下面的截图中:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_020.jpg

图 10.20 – 该模型的准确率为 0.96,但对于 65 岁的人群,其准确率为 0.5

尽管数据集已经生成,但你可以看到该模型对 65 岁的人群的准确率只有 50%。请注意,尽管该模型是在 18 至 85 岁之间的年龄段进行训练的,但数据集中只检测到 35 个子组,这表明我们可能没有对其进行准确测试。

ExplanationDashboardErrorAnalysisDashboard类似,负责任的 AI 小部件(raiwidgets)包提供了一个FairnessDashboard,可以用来分析模型结果的公平性。

重要提示

在编写本书时,FairnessDashboard在 Jupyter 中工作。在 Notebook 体验中,存在一些技术问题。为了获得最佳体验,请在 Jupyter 中打开你的 Notebook。

在一个新单元格中,添加以下代码以调用公平性仪表板,使用你在前面的代码中定义的年龄敏感特征:

from raiwidgets import FairnessDashboard
FairnessDashboard(sensitive_features=age, 
                  y_true=y_test, y_pred=y_pred)

启动后,该小部件将引导你完成公平性评估过程,在此过程中你需要定义以下内容:

  • 敏感特征:在这里,你必须配置敏感特征。敏感特征用于将数据分组,正如我们之前看到的那样。在这种情况下,它将提示你为年龄组创建五个区间(18-29 岁、30-40 岁、41-52 岁、53-64 岁和 64-75 岁),你可以修改分箱过程,甚至选择提供的视为分类变量选项,以让每个年龄单独处理。

  • 性能指标:性能指标用于评估模型在总体和每个组中的质量。在这种情况下,你可以选择准确度,就像我们之前所做的那样。即使向导完成后,你也可以更改这个选项。

  • 公平性指标:公平性指标表示性能指标的极端值之间的差异或比率,或者仅仅是任何组的最差值。此类指标的一个示例是准确度比率,它是任何两个组之间的最小准确度比率。即使向导完成后,你也可以更改这个选项。

生成的仪表板允许你深入了解模型对各子组的影响。它由两个区域组成——总结表格和可视化区域——你可以在这里选择不同的图形表示方式,如下所示:

https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_10_021.jpg

图 10.21 – 展示不同年龄组中模型准确度的公平性仪表板

一旦你确定了模型中的公平性问题,你可以使用Fairlearn库来缓解这些问题。Fairlearn库提供了两种方法:

  • ThresholdOptimizer,调整底层模型的输出以实现显式约束,比如均衡赔率的约束。在我们的二元分类模型中,均衡赔率意味着在各组之间,真正例和假正例的比率应该匹配。

  • sample_weight 参数是 fit sklearn 方法接受的。

使用这些技术,你可以通过牺牲一些模型的性能来平衡模型的公平性,以满足你的业务需求。

Fairlearn包正在不断发展,已经集成到 Azure 机器学习 SDK 和 Studio Web 体验中,允许数据科学家将模型公平性洞察上传到 Azure 机器学习运行历史记录中,并在 Azure 机器学习 Studio 中查看Fairlearn仪表板。

在本节中,你学习了如何检测模型可能存在的潜在不公平行为。你还了解了可以在Fairlearn包中实现的潜在缓解技术。这总结了由 Azure 机器学习工作区和开源社区提供的工具,它们帮助你理解模型并协助你创建人工智能。

总结

本章为你概述了几种可以帮助你理解模型的工具。你首先了解了 Interpret-Community 包,它能够帮助你理解模型做出预测的原因。你学习了各种解释技术,并探索了解释仪表板,其中提供了诸如特征重要性等视图。接着,你看到了错误分析仪表板,它能够帮助你确定模型表现不佳的地方。最后,你学习了公平性评估技术、相应的仪表板,能够让你探索潜在的不公平结果,并了解如何采取措施来缓解潜在的公平性问题。

在下一章,你将学习关于 Azure 机器学习管道的内容,管道可以让你以可重复的方式编排模型训练和模型结果的解释。

问题

在每一章中,你会发现一些问题,帮助你对每章讨论的主题进行知识检查:

  1. 你正在使用 TabularExplainer 来解释 DecisionTreeClassifier。将使用哪种底层的 SHAP 解释器?

    a. DecisionTreeExplainer

    b. TreeExplainer

    c. KernelExplainer

    d. LinearExplainer

  2. 你想使用 MimicExplainer 来解释 DecisionTreeClassifier。你可以使用以下哪种模型作为 explainable_model 参数?

    a. LGBMExplainableModel

    b. LinearExplainableModel

    c. SGDExplainableModel

    d. DecisionTreeExplainableModel

    e. 上述所有选项

  3. 你能使用 PFIExplainer 来生成局部特征重要性值吗?

    a. 是的

    b. 否

进一步阅读

本节提供了一些有用的网络资源,帮助你增强对 Azure 机器学习 SDK 以及本章中使用的各种代码片段的理解:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值