原文:
annas-archive.org/md5/41ac68e0c7679ad41531572416d7e2b8
译者:飞龙
第三部分:高级数据科学工具和功能
在本节中,您将深入了解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
。你还需要拥有Contributor
或Owner
权限的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.core
和azureml.train.hyperdrive
。下图提供了 AzureML SDK 中最常用包的广泛概览,以及你将在本书和考试中看到的关键模块:
图 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 集成的第三方代码编辑器,如下图所示:
图 7.2 – Azure Studio 集成的第三方代码编辑器列表
最广为人知的开源数据科学编辑器是 Jupyter Notebook 及其更新版本 JupyterLab。您可以通过点击前面截图中显示的相应链接打开这些编辑环境。这将打开一个新的浏览器标签页,如下图所示:
图 7.3 – 计算实例提供的 JupyterLab 和 Jupyter 编辑体验
除了这些第三方代码编辑体验外,AzureML Studio 还提供了一个内置的增强型笔记本编辑器,允许你在 Studio 界面内编辑、共享和协作,如下图所示。这个编辑器建立在 Jupyter Notebook 服务之上,但提供了更改进的代码编辑体验,比如内联错误高亮、自动代码补全、弹出窗口显示即将调用的方法的参数信息等其他功能,这些功能统称为IntelliSense:
图 7.4 – 内置于 AzureML Studio 中的增强型笔记本体验
笔记本编辑器带有一个嵌入式示例库,其中包含最新的笔记本目录,展示了最新 AzureML SDK 几乎所有的功能。一旦你找到相关的笔记本,你可以查看其内容,如果你想修改它,可以将其克隆到你的工作区,这个操作会复制 Jupyter 笔记本及与该笔记本相关的脚本和数据,如下图所示:
图 7.5 – 帮助你快速掌握 AzureML SDK 功能的示例笔记本
重要提示
这些笔记本已更新为最新版本的 AzureML SDK。这些笔记本所在的代码库可以在 GitHub 上找到,网址为github.com/Azure/MachineLearningNotebooks/
。你可以使用 GitHub 提交问题或通过 GitHub 的搜索功能查找代码片段。
每个 AzureML 工作区都配有一个存储帐户,正如在第二章中提到的,部署 Azure 机器学习工作区资源。此存储帐户包含一个以code-为前缀的文件共享,该共享托管工作区内所有可用的笔记本和脚本,如下图所示。你在 Studio 体验中看到的文件,就是存储在该文件共享位置中的文件,在Files选项卡中:
图 7.6 – Azure 门户视图,显示托管所有 AzureML 工作区代码文件的文件共享
每个用户在Users文件夹下都有一个单独的文件夹,用于组织他们的文件。所有具有特定 AzureML 工作区访问权限的用户都可以访问这些文件。这使得代码共享变得非常容易。你可以通过在浏览器中打开文件,将其指向具有 AzureML 工作区访问权限的某个人;然后,你可以分享浏览器导航栏中的 URL。
在本节中,您将创建一个笔记本,在其中编写和执行本章中的代码片段。要处理您的文件,请导航到chapter07
,然后创建一个名为chapter07.ipynb
的笔记本。
点击用户名旁边的三个点,如下截图所示。从那里,您可以创建文件夹结构并从本地计算机上传文件。点击创建新文件夹选项,如下截图所示:
图 7.7 – 在 AzureML Studio 的 Notebooks 体验区域中创建新文件夹选项
填写弹出的对话框以创建名为chapter07
的文件夹。选择该文件夹,然后点击三个点。然后,选择Users/<username>/chapter07
,这意味着该文件将放置在新创建的文件夹中。关于chapter07.ipynb
并点击Create按钮,如下截图所示:
图 7.8 – 创建笔记本以编写和执行本章 Python 脚本
这将在您的文件夹中创建两个文件:笔记本文件,将在编辑器窗格中打开,以及一个.amlignore
文件,您将在第八章,使用 Python 代码进行实验中详细了解该文件:
图 7.9 – 在 AzureML Studio 中编辑笔记本
从前述截图的左侧开始,Notebooks 体验提供以下内容:
-
文件资源管理器,您可以在其中创建或上传新文件,并删除、下载、重命名或移动您或您的同事在此工作区中创建的现有文件。
-
正在打开文件的名称。请注意,如果您在名称旁边看到一个星号 – 例如,*** chapter07.ipynb** – 这意味着该文件尚未保存。您可以使用 Windows 和 Linux 的Ctrl + S快捷键或 macOS 的Cmd + S快捷键保存该文件。或者,您可以从文件选项菜单中选择保存选项,您将在下面阅读到。
-
文件选项菜单,提供保存操作和焦点模式等选项,焦点模式会将编辑器面板扩展到浏览器标签的大部分空间。这是一个动态菜单,取决于你当前正在编辑的文件类型。在前面的截图中,打开的是一个笔记本,菜单提供了其他操作,如清除输出、重启 Python 内核或查看当前加载的 Python 内核中的变量。你还可以通过点击菜单图标(即四个垂直线的图标)并从编辑器选项中选择相应的编辑器来在 Jupyter 或 JupyterLab 中编辑同一文件。特别是对于 VS Code,一个非常流行的跨平台免费代码编辑器,主栏中提供了在 VS Code 中编辑的选项。
-
管理当前正在编辑特定文件的计算实例的能力。在此部分,你可以快速创建一个新的计算实例或启动/停止现有的实例。
-
选择执行笔记本的环境的能力。默认情况下,选择的是 AzureML Python 内核,这是已安装 AzureML SDK 的环境。如果你正在编辑 R 文件,可以将内核更改为 R 内核,或者如果你想自定义工作环境,也可以创建自己的内核。
-
主编辑器面板。这是你可以修改选定文件的地方。
在你的情况下,编辑器面板将为空,且只会显示一个空单元格,如下图所示。每个单元格可以包含Markdown格式的文本或 Python 代码。你可以通过点击弹出菜单并选择M****↓图标来将单元格转换为代码单元:
图 7.10 – 一个空的代码单元格
-
点击M****↓图标,然后点击编辑图标,在单元格中添加以下 Markdown 文本:
# Chapter 07 code snippets This notebook contains all code snippets from chapter 7.
-
按Shift + Enter键完成编辑,执行单元格,这将在本例中渲染格式化的文本,并将光标移到下一个单元格。默认情况下,下一个单元格将是代码单元。将以下 Python 代码添加到该单元格中:
print('Hello world')
请注意,当你开始输入时,会出现一个弹出窗口,其中包含代码建议,你可以使用箭头键选择。你可以通过按下键盘上的Enter键来确认选择。这个列表是智能的,它会显示与你输入的内容匹配的类名,并且还会显示一些常用类,可能是因为你拼写错误或者忘记输入某些字母。例如,以下截图显示了
PermissionError
类,因为你可能忘记输入print
语句并且不完整,当代码中的部分存在语法错误时,会有波浪下划线标记。要执行代码单元,可以按Shift + Enter组合键,或者点击单元格左侧的圆形按钮:
图 7.11 – IntelliSense 提示适合当前脚本范围的方法和类
如果在执行代码单元时发生错误,错误信息将显示在单元格的底部,Traceback 信息将出现在单元格的输出部分,如下图所示。你可以更新单元格的内容并重新运行单元格以修复此错误:
图 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_name
、subscription_id
和 resource_group
变量中指定的 name
、subscription_id
和 resource_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 命令。一个提示将要求您进行身份验证,如下面的截图所示:
图 7.13 – 在第一个命令执行期间请求的交互式身份验证
如果您看到此消息,请转到提供的链接,您将被要求输入提示中显示的请求代码。在这种情况下,代码是MYRNDCODE。此代码是使用您计算机位置的身份进行登录请求的唯一标识符。选择您计划用于访问各种 Azure 资源(包括 AzureML 工作区)的帐户。下图显示了整个交互式身份验证流程:
图 7.14 – 在计算实例中使用交互式登录进行身份验证
重要提示
请求代码是短暂的,有效期为 15 分钟。如果您未能在该时间段内完成过程,将会出现错误,您将需要重新开始。
如果您的帐户可以访问多个Azure Active Directories(AADs),例如来自试用订阅的个人 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_NC6
、Standard_NV24s_v3
和 Standard_ND40rs_v2
。注意所有的大小都以 N 开头。
该脚本仅指定计算集群的最大节点数(max_nodes
参数)。如果未指定最小节点数(min_nodes
参数),则该参数的默认值为 0。默认情况下,集群将缩减到 0 个节点,在没有作业运行时不会产生计算成本。您可以在微软官方 Python SDK 参考页面上找到 provisioning_configuration()
方法的所有参数的默认值,如以下截图所示,或者通过执行 help(AmlCompute.provisioning_configuration)
使用 Python help
命令:
图 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 文件,如下图所示:
图 7.16 – 在 Azure 门户中看到的 mydatastg 存储帐户中的容器
重要提示
从 Azure 门户配置新的存储帐户并添加容器是一项简单的任务,超出了本考试的范围。请注意,存储帐户有唯一的名称。这意味着你可能无法创建名为mydatastg的存储帐户,因为它属于其他人。你可以使用随 AzureML 工作区一起配置的现有存储帐户来执行这些步骤。你可以通过 Azure 门户将existing-container容器添加到该存储帐户中,或者你也可以使用已经存在的azureml容器。
要将此容器注册为你的 AzureML 工作区中的新数据存储,你需要按照以下步骤操作:
-
在进入你的笔记本之前,你需要获取存储帐户的名称和帐户密钥。这些信息位于 Azure 门户中的设置|访问密钥选项卡下,存储帐户资源中,如下图所示:https://github.com/OpenDocCN/freelearn-ds-pt4-zh/raw/master/docs/az-ds-ass-cert-gd/img/B16777_07_017.jpg
图 7.17 – 连接存储帐户所需的存储帐户名称和密钥
-
打开你的
chapter07.ipynb
笔记本,在一个新的代码单元中,将这些信息赋值给以下 Python 变量:storage_name = 'mydatastg' storage_key = '<storagekey>' storage_container = 'existing-container'
-
要将 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 数据库:图 7.18 – 来自官方文档页面的支持的数据存储服务类型
-
要获取连接的数据存储的引用,您可以使用
Datastore
类的构造函数,如以下代码片段所示:from azureml.core import Datastore dstore = Datastore.get(ws,"my_data_store")
-
在第四章《配置工作区》中,在数据存储列表中,您将学习如何将注册的数据存储设置为 AzureML 工作区的默认数据存储。
Workspace
类提供了一种快捷方式,可以通过get_default_datastore()
方法引用该数据存储:dstore = ws.get_default_datastore()
本书的其余部分,您将使用默认的数据存储来存储数据。
-
引用 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)
-
该文件将出现在与您的 AzureML 工作区一起创建的存储帐户中。您可以通过 Azure 门户找到它,方法是导航到存储帐户,选择名称以azureml-blobstore-开头的 Blob 容器,然后导航到samples / diabetes / v1文件夹,如以下屏幕截图所示:
图 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
可以引用这样的文件。
-
在你的笔记本中新建一个单元格,输入以下代码:
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())
在这段代码中,引用了工作站的默认数据存储。
-
现在,你可以创建一个包含
Datastore
及其相对路径的元组数组。每个元组引用一个特定Datastore
中的文件或文件夹。在这种情况下,你引用的是默认Datastore
中的samples/diabetes/v1
文件夹。如果你愿意,可以使用通配符字符*
来加载多个子文件夹或部分文件名。例如,以下元组数组加载了 2021 年所有月份的天气数据 CSV 文件,这些文件存储在/weather/<year>/<month>/<day>.csv
路径下:file_paths = [ (dstore, "/weather/2021/*/*.csv") ]
-
如果你只想显式加载 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 个数据路径引用。
-
返回到本节开头的代码片段,现在您可以使用
from_files()
方法创建一个未注册的FileDataset
。在此处,您必须将数据路径数组作为参数传递。您还必须验证数据是否可以通过该方法加载。如果文件夹不存在或数据存储由于私有端点受保护,不可直接从执行代码的计算资源访问,则会收到DatasetValidationError
。validate
参数的默认值为True
,您可以通过在该参数中传递False
来禁用该验证。 -
创建了
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 文件
-
对于 CSV 文件,更好的方法是定义一个
TabularDataset
,它可以解析文件并为我们提供 pandasDataFrame
。为此,请将以下代码复制到一个新单元格中: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
的行数。 -
到目前为止,您创建的数据集都是未注册的,这意味着它们未在 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 中查看注册信息,如下截图所示:图 7.21 – 注册在工作区中的表格数据集
-
如果您有一个 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
pandasDataFrame
引用,并且请求将该DataFrame
存储在由dstore
变量引用的默认数据存储中,存储路径为/samples/diabetes
文件夹。此方法将创建一个具有 GUID 名称的新文件夹,并将数据以 Parquet 文件格式存储。由于数据集已经注册并指向不同的路径,该命令将创建数据集的新版本。在 Studio 界面中,你会看到 版本 2 的数据集已被注册。这个版本有一个不同的 相对路径,如下面所示:图 7.22 – 从 pandas DataFrame 直接注册的新版本糖尿病数据集
请注意,Parquet 文件格式是一种压缩格式,与用于数据集第一版的 CSV 文件相比,它的文件体积更小。
-
注册数据集后,无论是
FileDataset
还是TabularDataset
,你都可以使用Dataset
类的get_by_name()
方法来检索它,使用如下代码片段:from azureml.core import Dataset diabetes_dataset = Dataset.get_by_name( workspace=ws, name='diabetes')
可选地,你可以指定
version
参数,默认值为latest
。 -
上面的代码片段返回一个
TabularDataset
类的实例,但数据尚未加载。你可以通过TabularDataset
类的各种方法部分加载数据集,如下所示的代码片段所示:partial_dataset = diabetes_dataset \ .skip(10) \ .take(2) \ .keep_columns(['0','target'])
-
partial_dataset
是从diabetes_dataset
创建的TabularDataset
实例。该数据集跳过了diabetes_dataset
的前 10 行,保留了两行,并删除了所有列,除了名为0
和target
的列。在执行此多行语句时没有加载任何数据。定义了这个未注册的partial_dataset
数据集后,你可以使用以下代码将数据加载到 pandasDataFrame
中:df = partial_dataset.to_pandas_dataframe() df.head()
这将显示一个由两行两列组成的小型表格,如下所示的屏幕截图所示:
图 7.23 – 从切片表格数据集加载的小型 DataFrame
AzureML 数据集类的惰性加载功能让你可以灵活地对庞大的数据集进行切片和操作,而无需将其加载到内存中。
到目前为止,你已经学习了如何使用 Python SDK 部署计算目标、定义数据存储和创建数据集。在下一节中,你将学习如何使用在第二章中看到的 Azure CLI 工具执行类似操作,部署 Azure 机器学习工作区资源,该章节位于 使用 Azure CLI 部分。
使用 AzureML CLI 扩展
在第二章《部署 Azure 机器学习工作区资源》中,你学习了如何使用 Azure CLI,以及如何安装azure-cli-ml
扩展。这个扩展使用你在本章看到的 Python SDK 执行各种操作。要使用 Azure CLI,你可以选择以下任一方法:
-
打开 Azure 门户中的云终端,就像你在第二章《部署 Azure 机器学习工作区资源》中所做的那样。
-
打开你在本章中使用的计算实例的终端。
-
使用 Jupyter 笔记本的 shell 分配功能,允许你通过使用感叹号(!),也叫做bang,执行底层 shell 命令。
在本节中,你将使用笔记本,这将帮助你存储步骤,并在未来需要时重复这些步骤:
-
首先,你需要在你当前正在使用的计算实例的 Azure CLI 中安装
azure-cli-ml
扩展。创建一个新的代码单元格,并添加以下代码:! az extension add -n azure-cli-ml
请注意,在第二章《部署 Azure 机器学习工作区资源》中,你执行了相同的命令,但没有感叹号前缀。此命令的输出应类似于以下内容:
图 7.24 – 安装 AzureML 扩展
-
然后,你需要使用
az login
命令登录。此命令将触发设备认证过程,类似于你在本章开始时尝试通过 SDK 连接到工作区时使用的认证方式。运行以下命令:! az login
-
如果你有多个 Azure 订阅的访问权限,你需要使用以下代码片段选择你正在使用的订阅:
! az account set --subscription "<subscription id>"
从现在开始,你可以使用 AzureML CLI 对工作区执行操作。
重要提示
如果你在订阅中有多个 AzureML 工作区,你需要指定每个 AzureML CLI 命令的目标工作区和资源组。为此,你需要使用
-g
和-w
参数,我们在第二章《部署 Azure 机器学习工作区资源》中已经介绍过。 -
要列出工作区中的所有计算目标,可以使用以下代码片段:
! az ml computetarget list -g packt-azureml-rg -w packt-learning-mlw -o table
-
然后,你可以使用以下命令更新
cpu-sm-cluster
,使其具有 0 个最小节点:! az ml computetarget update amlcompute --name cpu-sm-cluster --min-nodes 0 -g packt-azureml-rg -w packt-learning-mlw
-
要获取在工作区中注册的默认数据存储,可以使用以下命令:
! az ml datastore show-default -g packt-azureml-rg -w packt-learning-mlw
-
最后,你可以使用以下代码列出工作区中注册的数据集:
! az ml dataset list -g packt-azureml-rg -w packt-learning-mlw -o table
该命令的结果应类似于以下内容:
图 7.25 – AzureML CLI 中数据集列表的表格格式输出
AzureML CLI 提供对 SDK 选项的完全访问权限,包括创建和分离计算目标、数据存储,甚至定义数据集的能力。对于考试,您不需要记住命令,只要您理解 CLI 在后台使用 SDK,并且大多数您可以用 SDK 做的事情都有对应的 CLI 命令即可。
总结
在本章中,您学习了 AzureML Python SDK 的结构。您还发现了 AzureML 笔记本编辑器,允许您编写 Python 脚本。接着,您使用了 SDK,并开始通过管理附加到 AzureML 工作区的计算目标来启动编码旅程。然后,您附加了新的数据存储并获取了现有数据存储的引用,包括工作区的默认数据存储。接下来,您处理了各种文件和基于表格的数据集,并学习了如何通过将它们注册到工作区中来重用这些数据集。
最后,您已经使用了 AzureML CLI 扩展,这是一个客户端,利用了您在本章中探索的 Python SDK。
在下一章中,您将基于这些知识进一步学习如何在数据科学实验阶段使用 AzureML SDK。您还将学习如何跟踪数据科学实验中的指标,并了解如何通过在计算集群中运行脚本来将训练扩展到更大的计算资源。
问题
请回答以下问题,以检查您对本章所讨论的主题的理解:
-
AzureML 计算集群的默认最小节点数是多少?
a. 0
b. 1
c. 等于最大节点数
-
您将一个包含信用卡交易详情的 CSV 文件上传到默认数据存储库。您应该使用以下哪种方法来创建数据集引用?
a.
Dataset.File.from_files()
b.
Dataset.Tabular.from_delimited_files()
c.
Workspace.from_csv_files()
d.
Datastore.from_csv_files()
-
如何在注册 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 及本章中使用的各种第三方库的知识:
-
AzureML 中支持的数据存储服务类型:
docs.microsoft.com/en-us/azure/machine-learning/how-to-access-data#supported-data-storage-service-types
-
DataFrame
API 参考:pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.html
-
参考从 scikit-learn 库加载的糖尿病数据集:
scikit-learn.org/stable/modules/generated/sklearn.datasets.load_diabetes.html
-
AzureML SDK Python API 浏览器,列出了所有包、类和方法:
docs.microsoft.com/en-us/Python/api/?view=azure-ml-py
-
AzureML CLI 扩展参考:
docs.microsoft.com/cli/azure/ml(v1)?view=azure-cli-latest
-
免费电子书——《学习 Python 编程(第二版)》:
www.packtpub.com/free-ebook/learn-Python-programming-second-edition/9781788996662
第八章:第八章:使用 Python 代码进行实验
在本章中,你将了解如何训练 scikit-learn
库,它通常被称为 sklearn
。你将了解如何使用Azure 机器学习(AzureML)SDK 和 MLflow 来跟踪训练指标。接着,你将看到如何在计算集群中扩展训练过程。
本章将涵盖以下主题:
-
在笔记本中训练一个简单的
sklearn
模型 -
在实验中跟踪指标
-
扩展训练过程与计算集群
技术要求
你需要有一个 Azure 订阅。在该订阅下,你需要有一个 packt-azureml-rg
。你还需要有 Contributor
或 Owner
权限的 packt-learning-mlw
。如果你按照第二章《部署 Azure 机器学习工作区资源》中的说明进行操作,这些资源应该已经为你准备好了。
你还需要具备 Python 语言的基础知识。本章中的代码片段适用于 Python 3.6 或更高版本。你还应熟悉在 AzureML Studio 中使用笔记本的操作体验,这部分内容已在上一章中讲解过。
本章假设你已经在 AzureML 工作区中注册了 scikit-learn
的 diabetes
数据集,并且已经创建了一个名为 cpu-sm-cluster
的计算集群,正如在第七章《AzureML Python SDK》中的 定义数据存储、处理数据集 和 使用计算目标 部分所描述的那样。
你可以在 GitHub 上找到本章的所有笔记本和代码片段,链接:bit.ly/dp100-ch08
。
在笔记本中训练一个简单的 sklearn 模型
本节的目标是创建一个 Python 脚本,在你在第七章中注册的diabetes
数据集上,训练出一个简单的模型,《AzureML Python SDK》。该模型将获取数字输入,并预测一个数字输出。为了创建这个模型,你需要准备数据、训练模型、评估训练模型的表现,然后将其存储,以便未来可以重用,正如在图 8.1中所示:
图 8.1 - 生成糖尿病预测模型的过程
让我们从了解你将要使用的数据集开始。diabetes
数据集包含 442 名diabetes
患者的数据。每一行代表一个患者。每一行包含 10 个特征(target
,是记录特征后 1 年糖尿病病情发展的定量指标)。
你可以在 AzureML Studio 界面中进一步探索数据集,正如在图 8.2中所示:
图 8.2 – 已注册的糖尿病数据集
通常在准备阶段,您会加载原始数据,处理缺失值的行,规范化特征值,然后将数据集分为训练数据和验证数据。由于数据已经预处理,您只需加载数据并将其拆分为两个部分:
-
导航到
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 笔记本
-
在笔记本的第一个单元格中,添加以下代码:
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%的数据。这些数据集包含您要预测的特征和标签。使用TabularDataset
的drop_columns()
和keep_columns()
方法,您可以将特征与label
列分开。然后,您通过TabularDataset
的to_pandas_dataframe()
方法将数据加载到内存中。最终,您将得到四个 pandas 数据框:-
X_train
:包含 80%的行,每行有 10 列(0
到9
)。 -
y_train
:包含 80%的行,每行有 1 列(target
)。 -
X_validate
:包含 20%的行,每行有 10 列(0
到9
)。 -
y_validate
:包含 20%的行,每行有 1 列(target
)。
diabetes
数据集在科学文献中非常流行。它被用作训练回归模型的示例。scikit-learn
库提供了一个名为sklearn.linear_model
的专用模块,包含许多线性回归模型可供我们使用。现在您已经准备好了数据,接下来的任务是训练模型。 -
-
在此步骤中,您将训练一个
LassoLars
模型,它是LassoLars
类的缩写,该类接受一个名为alpha
的浮动参数,该参数被称为正则化参数或惩罚项。它的主要目的是保护模型免受训练数据集的过拟合。由于该参数控制训练过程,因此被称为超参数。一旦模型训练完成,这个参数不能再更改。在这个代码块中,您正在实例化一个未训练的模型,并将alpha
参数设置为0.1
。在下一章,第九章,优化机器学习模型,您将调整此参数,并尝试为您的数据集找到最佳值。然后,您将使用
X_train
和y_train
数据框来 fit()模型,这意味着您正在用训练数据集训练模型。经过这个过程后,model
变量引用一个已训练的模型,您可以使用该模型进行预测。 -
接下来的任务是基于某个指标评估你所生成的模型。评估回归模型时最常用的指标如下:
-
平均或中位数绝对误差。
-
均方误差或对数误差。该指标的另一种常见变体是
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所示:
-
图 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所示:
图 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所示:
图 8.6 – 在 Studio 体验中看到的 nrmse 的两个测量值
Run
类提供了丰富的日志记录方法,包括以下几种:
-
log_list
方法允许你为特定度量记录一系列值。该方法的示例如下代码:run.log_list("accuracies", [0.5, 0.57, 0.62])
这段代码将在
run
的Metrics部分生成图 8.7:
图 8.7 – 使用 log_list 方法记录的三个值的图表
-
log_table
和log_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)
这段代码片段将在
run
的Metrics部分生成图 8.8:
图 8.8 – 使用 log_table 和 log_row 方法记录的表格度量
-
专门的方法如
log_accuracy_table
、log_confusion_matrix
、log_predictions
和log_residuals
提供了日志数据的自定义呈现。 -
log_image
方法允许你从著名的matplotlib
Python 库或其他绘图库记录图形或图像。 -
upload_file
、upload_files
和upload_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
文件夹:
-
在你的
chapter08.ipynb
笔记本中添加一个单元格,并使用以下代码段删除outputs
文件夹:import shutil try: shutil.rmtree("./outputs") except FileNotFoundError: pass
-
下一步,你将把训练和评估的代码重构为一个单独的方法,传入
alpha
参数以及training
和validation
数据集: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_train
、y_train
、X_validate
和y_validate
变量的单元格。这表示 Python 内核已经重启,所有变量都已从内存中丢失。到目前为止,你已经重构了现有代码并保持了相同的功能。为了启用通过前一部分中探索的
Run
类进行日志记录,你需要将当前运行实例的引用传递给train_and_evaluate
方法。 -
在一个新的单元格中,添加以下代码片段,它将覆盖现有的
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.
-
拥有这个
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
变量超出作用域,它会自动标记为已完成。 -
在步骤 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
文件夹中,紧邻笔记本文件。
图 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所示:
图 8.11 – 使用 MLflow 库并将 AzureML 用作远程跟踪服务器时记录的度量
到目前为止,你一直在使用 AzureML 工作区中的计算实例,并且你是在Notebook内核中训练 ML 模型。对于小型模型或在示例数据上快速原型开发,这种方法效果很好。但在某些时候,你将需要处理更高负载的工作负载,这可能涉及更大的内存要求,甚至是在多个计算节点上进行分布式训练。你可以通过将训练过程委托给在第四章中创建的计算集群来实现这一目标,配置工作区。在下一节中,你将学习如何在 AzureML 计算集群中执行 Python 脚本。
使用计算集群扩展训练过程
在第七章,AzureML Python SDK中,你创建了一个名为cpu-sm-cluster
的计算集群。在这一节中,你将提交一个训练任务以在该集群上执行。为此,你需要创建一个将在远程计算目标上执行的 Python 脚本。
导航到你迄今为止正在使用的chapter08
文件夹中的greeter-job
。添加一个名为greeter.py
的 Python 文件:
图 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所示:
图 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)
在这段代码中,你正在执行以下操作:
-
获取工作区的引用,然后将
target
变量分配给cpu-sm-cluster
集群的引用。 -
创建一个
ScriptRunConfig
,以执行位于greeter-job
文件夹中的greeter.py
脚本。该脚本将在target
计算机上执行,并传递--greet-name
和packt
参数,它们将通过空格连接起来。 -
创建一个名为
greet-packt
的实验,并将脚本配置提交以在该实验下执行。submit
方法创建了一个新的Run
实例。 -
你可以使用
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标签页:
图 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
文件,这是由笔记本编辑器使用的临时文件:
图 8.15 – 临时文件上传至快照中
为了避免创建不需要的文件快照,你可以在脚本旁边的文件夹中添加.gitignore
或.amlignore
文件,并排除符合特定模式的文件。导航到greeter-job
文件夹中的.amlignore
文件,如果在创建文件夹时尚未添加该文件,如图 8.16所示:
图 8.16 – 添加.amlignore
文件以排除临时文件被添加到快照中
打开.amlignore
文件,并在其中添加以下行,以排除所有具有.amltmp
文件扩展名的文件以及你正在编辑的.amlignore
文件:
*.amltmp
.amlignore
打开chapter08.ipynb
笔记本,添加一个单元,并添加以下代码以重新提交脚本:
from azureml.widgets import RunDetails
run = exp.submit(script)
RunDetails(run).show()
你正在重新提交之前步骤中创建的ScriptRunConfig
的现有实例。如果你再次重启exp
和script
变量。
这次,你正在使用 AzureML SDK 提供的RunDetails
小部件。这是一个Jupyter Notebook小部件,用于查看脚本执行的进度。这个小部件是异步的,会在运行完成前不断更新。
如果你想打印运行状态,包括日志文件的内容,可以使用以下代码片段:
run.get_details_with_logs()
一旦运行完成,导航到该运行的Snapshot标签页。你会注意到临时文件已经消失。
注意,这次运行的执行时间显著减少。导航到运行的日志。注意,这次日志中没有出现20_image_build_log.txt
文件,如图 8.17所示:
图 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-Minimal
和 AzureML-AutoML
环境,它们仍然可以供你使用。如果遇到任何错误,请从本章的 GitHub 仓库下载最新的代码。
在图 8.18中,你可以看到与简化版的 AzureML-Minimal
环境相比,AzureML-AutoML
环境提供了多少额外的软件包:
图 8.18 - AzureML-Minimal 和 AzureML-AutoML 环境之间的 Python 包差异
图 8.18 显示了 AzureML-Minimal
环境 版本 46 与 AzureML-AutoML
环境 版本 61 的 Conda
环境定义。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
环境:
-
在你的笔记本中,添加一个新单元并加入以下代码:
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 定义。 -
添加一个新单元,并输入以下内容:
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-logs
中 55_azureml-execution-something.txt
文件的一部分。该行告知你它正在从 Microsoft 所拥有的 viennaglobal
容器注册表中拉取 Docker 镜像。与此相对,上一节中,在没有指定策划环境的运行中,镜像是从你自己的容器注册表中拉取的——即与你的 AzureML 工作区关联的容器注册表,如 图 8.19 所示:
图 8.19 – 在没有使用策划环境的情况下,从你自己的容器注册表中拉取的镜像
这个观察结果引出了下一个类型的 AzureML 支持的环境——系统管理环境——你将在下一节中进行探索。
定义系统管理环境
Conda
环境定义或简单的 pip
requirements.txt
文件。在上一节中,你没有在 ScriptRunConfig
构造函数中定义 environment
参数,因此使用了默认的 Conda
环境定义文件来创建存储在与 AzureML 工作区关联的 Azure 容器注册表 中的系统管理环境。现在,让我们显式地创建一个系统管理环境来与代码一起使用:
-
导航到你 AzureML 工作区的 笔记本 部分以及 文件 树视图。
-
点击
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 的新文件夹
-
打开新文件夹中的
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.
-
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,并安装了asciistuff
的 1.2.1 版本的pip
包。 -
若要基于你刚定义的
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 包。这样,你可以在本地和远程执行时都重复使用它。
-
若要使用这个新定义的环境,请在笔记本中添加一个新单元格,并输入以下代码:
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 中所示相似:
图 8.21 – 从环境变量读取的头部文本和基于横幅的问候语
正如你注意到的,在你刚刚创建的系统管理环境中,你没有指定任何关于基础操作系统的信息(例如,是否已在基础系统中安装了Conda
)。你只是指定了已安装的Conda
依赖项。如果你想要更大的灵活性,你可以显式配置环境并手动安装所有的软件要求。这些环境被称为用户管理环境。通常,这些用户管理环境是自定义的 Docker 镜像,封装了所有必需的依赖项。例如,你可能需要 PyTorch 框架的自定义构建,或者甚至是 Python 的自定义构建版本。在这些情况下,你需要负责安装 Python 包并配置整个环境。在本书中,你将使用经过精心策划或由系统管理的环境。
到目前为止,你已经探索了如何在远程计算机上执行一个简单的问候程序 Python 应用。在接下来的部分,你将继续训练你的diabetes
模型,并了解如何在远程计算集群上训练该模型。
在计算集群上训练糖尿病模型
在前面的部分中,你了解了如何通过在笔记本中调用exp.submit(script)
方法在远程计算集群上运行脚本,如图 8.22所示:
图 8.22 – 在计算集群上执行脚本
当你调用submit
方法时,后台发生了以下操作:
-
AzureML SDK 执行了一个
ScriptRunConfig
。 -
AzureML 工作区检查是否已经存在
Environment
的 Docker 镜像。如果没有,它会在 Azure 容器注册表中创建。 -
任务被提交到计算集群,集群会扩展以分配一个计算节点。在新分配的计算节点中执行以下操作:
-
带有环境的 Docker 镜像被拉取到计算节点上。
-
由
ScriptRunConfig
引用的脚本被加载到正在运行的 Docker 实例中。 -
指标和元数据存储在 AzureML 工作区中。
-
输出将存储回存储帐户。
在使用笔记本训练简单的 sklearn 模型部分中,你在 chapter08.ipynb
笔记本中创建了一个训练脚本。训练发生在 Jupyter 服务器的进程中,位于你的计算实例内部。要在计算集群上运行相同的训练,你需要执行以下操作:
-
将代码移动到 Python 脚本文件中。
-
创建一个 AzureML 环境来运行训练。
-
在实验中提交
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所示:
图 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_train
、y_train
、X_validate
和 y_validate
pandas 数据框,这些数据框您在本章的 在笔记本中训练简单的 sklearn 模型 部分中看到过。请注意,您在 random_split
方法中指定了 seed
参数。这个 seed
参数用于初始化 split
方法背后使用的随机函数的状态,以便从数据集中随机选择行。这样,每次调用该随机函数时,它都会生成相同的随机数。这意味着 training_data
和 validation_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
类的预期行为:
图 8.24 – 在本地运行训练脚本
到目前为止,您已经创建了训练脚本。在下一部分中,您将创建 AzureML 环境,该环境将包含执行该脚本所需的所有依赖项,以便在远程计算上运行。
创建用于运行训练脚本的 AzureML 环境
在追踪模型演变部分中创建的训练脚本使用了 scikit-learn
库,也称为 sklearn
。您在笔记本体验中使用的 Jupyter 内核已经安装了 sklearn
库。要查看当前在内核中安装的版本,请转到 chapter08.ipynb
笔记本,并在新的单元格中添加以下代码片段:
!pip show scikit-learn
该命令将使用 Python 的 pip
包管理器显示当前安装的 scikit-learn
包的详细信息,如 图 8.25 所示:
图 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_packages
和pip_packages
数组中来要求环境中包含多个包。请注意,由于你没有将包附加到默认的CondaDependencies
中,因此需要手动添加azureml-defaults
包,以便training.py
脚本能够访问azureml.core
模块。
你可能会问,为什么我们没有在 Python 依赖项中定义joblib
。scikit-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-learn
、MLflow
和matplotlib
等最常用的数据科学库。
到目前为止,你已经编写了训练脚本并定义了包含所需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 图所示:
图 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 功能,完全自动化模型选择、训练和调优。
问题
在每一章中,您会发现几个问题来检查您对讨论主题的理解:
-
你想记录你将在脚本中使用的验证行数。你将使用
Run
类中的哪个方法?a.
log_table
b.
log_row
c.
log
-
你想运行一个使用
scikit-learn
的 Python 脚本。你将如何配置 AzureML 环境?a. 添加
scikit-learn Conda 依赖项。
b. 添加
sklearn Conda 依赖项。
使用 AzureML 的
Azure-Minimal
环境,该环境已经包含所需的依赖项。 -
你需要使用
MLflow
跟踪实验中生成的指标,并将其存储在你的 AzureML 工作区中。你需要在 Conda 环境中安装哪两个 pip 包?a.
mlflow
b.
azureml-mlflow
c.
sklearn
d.
logger
-
你需要使用
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 和本章中使用的各种代码片段的知识:
-
LassoLars 模型文档,位于 scikit-learn 网站:
scikit-learn.org/stable/modules/linear_model.html#lars-lasso
-
plotly开源图形库:
github.com/plotly/plotly.py
-
MLflow 跟踪 API 参考:
mlflow.org/docs/latest/quickstart.html#using-the-tracking-api
-
.amlignore
和.gitignore
文件的语法:git-scm.com/docs/gitignore
-
Flake8 用于代码检查:
flake8.pycqa.org
第九章:第九章:优化机器学习模型
在本章中,你将学习两种可以帮助你发现数据集最佳模型的技术。你将首先探索HyperDrive包,这是 AzureML SDK 的一部分。这个包允许你通过调整其暴露的参数来优化模型的性能,这个过程也被称为超参数调优。接下来,你将探索自动化机器学习(AutoML)包,这是 AzureML SDK 的一部分,它允许你通过代码自动化模型选择、训练和优化过程。
在本章中,我们将涵盖以下主要内容:
-
使用 HyperDrive 进行超参数调优
-
使用代码运行 AutoML 实验
技术要求
你需要有 Azure 订阅权限。在该订阅中,你需要有一个名为packt-azureml-rg
的资源组。你还需要拥有Contributor
或Owner
权限的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')
此脚本将尝试使用selu
和relu
激活函数来寻找最佳模型。
重要提示
如果您对神经网络工作感兴趣,可能需要更好地理解这些激活函数。有一些很棒的书籍可以帮助您开始神经网络设计。对于 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)
图 9.2 – 高级离散和连续超参数值分布。样本值已排序。x 轴显示排序值的索引号
重要提示
在图 9.2中,在loguniform
和lognormal
的图表中,量化因子为 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
您将会在后面了解。它支持离散和连续的超参数。
让我们把到目前为止学到的所有知识付诸实践:
-
转到 AzureML Studio 网页界面的作者|笔记本部分。
-
创建一个名为
chapter09
的文件夹。 -
您需要在
training.py
脚本中创建一个名为diabetes-training
的文件夹。该脚本与第八章中《使用 Python 代码实验》一节中将代码移至 Python 脚本文件部分使用的脚本相同。您可以从那里复制内容。最终的文件结构图见图 9.3。 -
在 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 笔记本的文件树结构
-
在第一个单元格中添加以下初始化代码:
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
方法,而不是逐个添加包。 -
在新单元格中,定义将执行
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
对象自动附加。 -
在一个新单元格中添加并执行以下代码:
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
配置分配给HyperDriveConfig
的hyperparameter_sampling
参数。你还已配置
HyperDriveConfig
的run_config
属性,以使用你在第 6 步中定义的ScriptRunConfig
对象。注意,RandomParameterSampling
类将传递脚本所需的alpha
参数。然后,定义使用
primary_metric_name
参数评估生成的模型。你还指定了要最小化该值(primary_metric_goal
参数),因为它是你希望最小化的误差。最后的两个参数,
max_total_runs
和max_concurrent_runs
,控制你愿意投入到寻找最佳模型的资源。max_total_runs
参数控制实验的最大运行次数,可以在 1 到 1,000 次之间。这是一个必填参数。max_concurrent_runs
是一个可选参数,控制并发运行的最大次数。在这种情况下,你定义了 4,这意味着在ScriptRunConfig
中将仅配置四个节点。这意味着集群仍然会有一个未配置的节点,因为它能扩展到的最大节点数是五个,正如你在第七章 与计算目标的工作部分中定义的那样,AzureML Python SDK。还有一个可选参数可以用来限制搜索最佳模型的时间,max_duration_minutes
参数,你在上面的示例中没有指定,它定义了执行 超参数调优 过程的最大时长(分钟)。超过该时长后,所有后续调度的运行将自动取消。 -
在一个新单元格中,添加以下代码:
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
类。 -
你可以在 Studio Web UI 中查看该过程的结果。导航到
alpha
超参数。你可以通过视觉化探索alpha
参数的不同值对HyperDriveRun
(Run 1) 的alpha
值的影响。重要提示
在你的执行中,运行编号可能不同。每次你执行单元格时,都会创建一个新的运行编号,接着上一个编号。因此,如果你执行一个包含 20 个子运行的超参数调优运行,那么最后一个子运行将是第 21 号运行。下次执行相同代码时,超参数调优运行将从第 22 号开始,最后一个子运行将是第 42 号。此节中提到的运行编号是各个图示中显示的编号,观察到差异是正常的,尤其是在你需要重新运行某些单元格时。
-
导航到已完成的 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 中的日志文件,选取将并行执行的超参数空间中的前四个作业
该文件包含所有为完成超参数调优过程而计划的作业。实际的运行日志和存储的模型都保存在子运行中。如果你需要调试代码问题,你需要打开其中一个子运行查看脚本错误。
-
你还可以获取最佳模型的运行情况,并且相应的
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 所示:
图 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)
该脚本获取两个参数,a
和 b
,然后调用 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
,并在所有从1到4之间的值上进行网格搜索,观察fake_metric
在每个时期的演化。在图的右侧,你可以看到fake_metric
是如何受到不同a
和b
值的影响的,a
表现得比使用a
参数3和4训练的模型更好,关于fake_metric
:
](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)
图 9.9 – 使用激进的早期终止策略进行超参数调优
AzureML SDK 提供了一些内置的EarlyTerminationPolicy
实现,位于azureml.train.hyperdrive
模块中:
-
NoTerminationPolicy
:这是默认的停止策略,允许所有运行完成。 -
MedianStoppingPolicy
:中位数停止策略计算所有运行的运行平均值。然后,它会取消那些最佳表现差于运行平均值中位数的运行。你可以将此策略看作是将每次运行的表现与前面运行的平均表现进行比较。这个策略的优点在于它考虑了到目前为止所有的运行,而不仅仅是将当前的运行与迄今为止最好的运行进行比较。这一特点使得中位数停止策略能够避免陷入局部最优值。 -
BanditPolicy
:Bandit 策略计算当前运行和表现最佳的运行之间的距离,然后根据某些容差标准终止当前运行。你可以定义绝对距离(slack_amount
参数)或与表现最佳的运行的最大允许比率(slack_factor
参数)。 -
TruncationSelectionPolicy
:截断选择策略是最激进的策略,它取消某个百分比(由truncation_percentage
参数定义)的运行,这些运行在主要指标上的表现排在最后。当对一个相对较新的运行进行排名时,在早期的迭代中,该策略会将其与较老运行在同一迭代的表现进行比较。因此,这个策略力图通过考虑随着训练时间推移模型表现的提升来实现排名的公平性。
所有策略都接受两个可选参数:
-
evaluation_interval
:应用策略的频率。 -
delay_evaluation
:这将延迟第一次策略评估,直到指定的间隔次数,给予年轻运行足够的时间以达到成熟状态。
让我们使用最推荐的策略 MedianStoppingPolicy
,对你上面创建的脚本进行超参数调整:
-
转到将在超参数调整过程中使用的
ScriptRunConfig
对象。 -
在一个新单元格中,添加以下代码:
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 次迭代后评估所有运行,并在每次迭代中将它们的结果与当前的运行平均值的中位数进行比较。 -
在一个新单元格中,添加以下代码以开始执行你在 步骤 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 个提前终止:
图 9.10 – 使用中位数停止早期终止策略的超参数调整
重要提示
在上面的代码中,max_total_runs
参数的值为 50。这是潜在的子运行次数的上限。在这个示例中,你只有 16 种组合。这意味着实验将只运行 16 次,然后停止,因为整个搜索区域已经被搜索完毕。如果你希望 max_total_runs
参数生效,应指定一个小于 16 的值。
到目前为止,你已经看到了如何针对你拥有的数据优化特定的模型。在下一部分,你将看到如何通过 SDK 搜索最佳模型来运行 AutoML 实验,类似于你在第五章中所做的,让机器进行模型训练,通过 Studio 用户界面进行的操作。
使用代码运行 AutoML 实验
到目前为止,在本章中,你一直在微调一个 LassoLars
模型,执行超参数调整过程,以根据训练数据识别 alpha
参数的最佳值。在这一部分,你将使用 AutoML 和 AzureML SDK,自动选择最佳的数据预处理、模型和超参数设置,来匹配你的训练数据集。
要配置一个 AutoMLConfig
对象,你需要定义 任务类型、指标、训练数据 和 计算预算。该过程的输出是一个模型列表,你可以从中选择最佳的运行和与该运行相关的最佳模型,如图 9.11所示:
图 9.11 – AutoML 过程
根据你要建模的问题类型,你必须选择 task
参数,选择 classification
、regression
或 forecasting
,如图 9.12所示:
图 9.12 – AutoML 任务类型、算法和支持的指标
图 9.12 显示了 AzureML SDK 支持的部分算法。azureml.train.automl.constants.SupportedModels
包含 classification
、regression
和 forecasting
类,这些类列出了所有作为属性的支持算法。由于预测只是回归的一个更专门化的版本,因此回归的所有算法都可以使用。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.0 到 1.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
类包含以下常用参数:
-
time_column_name
:表示时间序列时间维度的列。 -
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 来解释模型结果。
问题
-
您想通过
model = run.get_output()[0]
获取最佳模型。b.
model = run.get_output()[1]
c.
model = run.get_outputs()[0]
d.
model = run.get_outputs()[1]
-
您想运行一个预测的
ForecastingParameters
类吗?a. forecast_horizon = 5 * 1
b. forecast_horizon = 5 * 24
c. forecast_horizon = 5 * 12
进一步阅读
本节提供了一些有用的网络资源列表,帮助您增加对 AzureML SDK 和本章中使用的各种代码片段的了解:
-
HyperDriveConfig
类:docs.microsoft.com/zh-cn/python/api/azureml-train-core/azureml.train.hyperdrive.hyperdriveconfig?view=azure-ml-py
-
AutoMLConfig
类:docs.microsoft.com/zh-cn/Python/api/azureml-train-automl-client/azureml.train.automl.automlconfig.automlconfig
-
自动化机器学习中的数据特征化:
docs.microsoft.com/zh-cn/azure/machine-learning/how-to-configure-auto-features
-
自动训练预测模型:
docs.microsoft.com/zh-cn/azure/machine-learning/how-to-auto-train-forecast
-
从 scikit-learn 库加载的糖尿病数据集参考:
scikit-learn.org/stable/modules/generated/sklearn.datasets.load_diabetes.html
第十章:第十章:理解模型结果
在本章中,你将学习如何分析机器学习模型的结果,以理解模型为何做出该推断。理解模型为何预测某个值是避免黑箱模型部署的关键,并且能够理解模型可能存在的局限性。在本章中,你将学习 Azure 机器学习的可用解释功能,并可视化模型解释结果。你还将学习如何分析潜在的模型错误,检测模型表现不佳的群体。最后,你将探索一些工具,帮助你评估模型的公平性,并让你能够缓解潜在问题。
本章将涵盖以下主题:
-
创建负责任的机器学习模型
-
解释模型的预测
-
分析模型错误
-
检测潜在的模型公平性问题
技术要求
你需要拥有一个 Azure 订阅。在该订阅中,你需要有一个名为packt-azureml-rg
的资源组。你还需要有Contributor
或Owner
权限的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,你可以将两个加密值A和B相加,得到一个值C,这个值只能通过加密值A和B的私钥解密,如下图所示:
图 10.1 – 使用 HE 在加密数据上执行操作
- 控制:控制和记录端到端过程是所有软件工程活动中的一个基本原则。DevOps 实践通常用于确保端到端过程的自动化和治理。DevOps 中的一个关键实践是记录每个步骤中的关键信息,让你在每个阶段做出负责任的决策。Azure 机器学习工作区允许你为你在端到端机器学习过程中的各种工件添加标签和描述。下图展示了你如何为在 第九章 中执行的 AutoML 运行添加描述,优化机器学习模型:
图 10.2 – 为运行添加描述以进行文档记录
类似于为运行添加描述,你可以为你生产的各种工件(如模型)添加标签。标签是键/值对,例如 PyTorch
是 Framework
标签键的值。你可能希望将以下信息作为模型 数据表 的一部分进行记录:
-
模型的预期用途
-
模型架构,包括使用的框架
-
使用的训练和评估数据
-
训练模型性能指标
-
公平性信息,你将在本章中阅读到
这些信息可以作为标签的一部分,而 数据表 可以是一个通过这些标签自动生成的 Markdown 文档。
本节中,你对帮助创建负责任 AI 的工具和技术进行了概述。所有三个支柱同等重要,但对于 DP100 考试,你将专注于理解类别中的工具,从模型可解释性开始,你将在下一节中深入了解。
解释模型的预测结果
能够解释模型的预测结果有助于数据科学家、审计员和商业领袖通过查看驱动模型预测的主要因素来理解模型行为。它还使他们能够进行假设分析,以验证特征对预测的影响。Azure 机器学习工作区与 InterpretML 集成,提供这些功能。
InterpretML 是一个开源社区,提供用于执行模型可解释性的工具。社区包含几个项目,其中最著名的如下:
-
Interpret 和 Interpret-Community 仓库,专注于解释使用表格数据的模型,例如你在本书中所使用的糖尿病数据集。你将在本节中使用 interpret-community 仓库。
-
interpret-text 扩展了解释工作到文本分类模型。
-
多样化反事实解释(DiCE)用于机器学习,可以帮助你检测在数据行中需要进行的最少修改,以改变模型的输出。例如,假设你有一个贷款审批模型,它刚刚拒绝了一笔贷款申请。客户问有什么可以做的来让贷款获得批准。DiCE可以提供批准贷款的最少修改,例如减少信用卡数量或将年薪提高 1%。
解释机器学习模型时有两种方法:
-
DecisionTreeClassifier
提供了feature_importances_
属性,允许你理解特征如何影响模型的预测。InterpretML 社区提供了几种更先进的玻璃盒模型实现。这些模型一旦训练完成,允许你获取解释器并查看哪些特征驱动了什么结果,这也被称为可解释性结果。这些模型的解释器是无损的,意味着它们准确地解释了每个特征的重要性。 -
黑盒解释:如果你训练的模型没有内置的解释器,你可以创建一个黑盒解释器来解释模型的结果。你需要提供训练好的模型和一个测试数据集,解释器会观察特征值的变化如何影响模型的预测。例如,在贷款审批模型中,这可能会调整一个被拒绝记录的年龄和收入,观察这些变化是否会改变预测结果。通过这些实验获取的信息可以用来生成特征重要性的解释。这项技术可以应用于任何机器学习模型,因此被认为是与模型无关的。由于它们的性质,这些解释器是有损的,意味着它们可能无法准确表示每个特征的重要性。在科学文献中,有一些著名的黑盒技术,例如Shapley 加法解释(SHAP)、局部可解释模型无关解释(LIME)、部分依赖(PD)、置换特征重要性(PFI)、特征交互和莫里斯敏感性分析。黑盒解释器的一个子类别是灰盒解释器,它利用模型结构的相关信息来获得更好、更快的解释。例如,有专门针对树模型(树解释器)、线性模型(线性解释器)甚至深度神经网络(深度解释器)的解释器。
模型解释器可以提供两种类型的解释:
-
局部或实例级特征重要性侧重于特征对特定预测的贡献。例如,它可以帮助回答为什么模型拒绝了某个特定客户的贷款申请。并非所有技术都支持局部解释。例如,基于PFI的方法不支持实例级特征重要性。
-
全局 或 聚合级特征重要性 解释了模型整体的表现,考虑到模型所做的所有预测。例如,它可以回答哪个特征对于贷款批准来说最为重要。
现在,你已经了解了模型解释的基本理论,是时候获得一些实践经验了。你将从训练一个简单的 sklearn 模型开始。
训练贷款批准模型
在本节中,你将对一个你将生成的贷款批准数据集训练一个分类模型。你将在接下来的章节中使用该模型分析其结果。让我们开始吧:
-
导航到
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 笔记本
-
你需要安装
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 内核
-
在重新启动内核后,在笔记本中添加一个新单元格。使用以下代码生成一个贷款数据集:
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
)是批准的贷款。 -
-
在本章后面,你将针对这个数据集运行一个 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")
如果你访问注册的数据集,可以查看数据集的简介,如下所示:
图 10.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 个样本的训练集。 -
下一步是初始化模型,并将其拟合到训练数据集。在第九章《优化 ML 模型》中,你学习了 Azure 机器学习的
datatransformer
步骤是一个ColumnTransformer
,它对所有特征应用MinMaxScaler
。这个转换器会缩放每个特征的值。 -
model
步骤是你正在训练的实际模型,即RandomForestClassifier
。
然后,你必须调用已实例化的管道的fit
方法,将其训练与训练数据集对齐。
重要提示
你不需要使用Pipeline
来受益于本章讨论的可解释性特性。你可以直接通过将模型赋值给model_pipeline
变量来使用该模型,例如model_pipeline=RandomForestClassifier()
。添加datatransformer
步骤是为了帮助你理解 AutoML 是如何构建管道的。使用MinMaxScaler
还提高了结果模型的准确性。你可以随意尝试不同的缩放器,以观察结果模型的差异。
-
现在你已经有了一个训练好的模型,可以进行测试。让我们测试三个虚构的客户:
-
一位 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]
,这意味着第一个客户的贷款将被拒绝,而第二个和第三个客户的贷款将被批准。这表明income
和credit_cards
特征可能在模型预测中起着重要作用。 -
-
由于训练后的模型是一个决策树,属于玻璃盒模型类别,你可以获取在训练过程中计算出的特征重要性。使用以下代码在新的笔记本单元格中:
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,这是一种黑箱技术,可以告诉你哪些特征在将预测从拒绝转为批准(或反之)的过程中发挥了什么作用。让我们开始吧:
-
在一个新的笔记本单元格中,添加以下代码:
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)。 -
使用这个解释器,你将获得局部或实例级别的特征重要性,以便更深入地理解模型在训练贷款批准模型部分的步骤 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**)的负值表明该特征推动模型拒绝贷款:
图 10.6 – 局部重要性特征展示了每个特征对每个测试样本的重要性
-
你还可以看到
收入
(income
)、年龄
(age
)以及信用卡数
(credit_cards
),它们对应的重要性值分别约为0.28
、0.09
和0.06
(实际值可能与你的执行结果有所不同)。请注意,这些值与训练贷款批准模型部分的步骤 8中获得的值不同,尽管顺序保持一致。这是正常现象,因为使用方法:shap.tree
,这表明TabularExplainer
使用树解释器对模型进行了解释,如本节步骤 1所提到的。 -
最后,你必须渲染解释仪表板,以查看你在步骤 3中生成的
global_explanation
结果。在笔记本中添加以下代码:from raiwidgets import ExplanationDashboard ExplanationDashboard(global_explanation, model_pipeline, dataset=x_test, true_y=y_test)
这将渲染一个交互式小部件,你可以用它来理解模型对你提供的测试数据集的预测。点击特征重要性汇总(Aggregate feature importance)标签,你应该会看到在步骤 3中看到的相同结果:
图 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}")
尽管特征重要性的顺序相同,但计算出来的特征重要性值是不同的,如下所示:
图 10.8 – 使用决策树玻璃盒子模型计算的 Mimic 解释器特征重要性
类似于 mimic_explainer
使用相同的代码来计算局部或实例级别的特征重要性,就像在上一节的步骤 2 中所做的那样。解释可以在以下屏幕截图中看到:
图 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_cards
和age
特征的重要性值非常相似,结果中它们的顺序可能会互换:
图 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,然后访问聚合特征重要性标签以查看解释仪表板,如下所示:
图 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,并打开模型标签,如下图所示:
图 10.12 – AutoML 运行中最佳模型的说明已可用
点击最佳模型的查看说明链接,进入训练该特定模型的子运行的说明标签。当你进入说明标签时,你会注意到AutoML存储了两个全局说明:一个是原始特征的说明,另一个是工程特征的说明。你可以通过选择屏幕左侧的适当 ID,在这两个说明之间切换,如下图所示。原始特征是来自原始数据集的特征。工程特征是经过预处理后得到的特征。这些工程特征是模型的内部输入。如果你选择较低的说明 ID并查看聚合特征重要性区域,你会注意到AutoML已将信用卡号转换为分类特征。此外,与模型训练中产生的三个特征相比,模型的输入是 12 个特征。
你可以在这里查看这些特征及其相应的特征重要性:
图 10.13 – 工程特征的全局说明
由于工程特征较难理解,请转到顶部的说明 ID,这是你目前为止使用的三个原始特征所在的位置。点击数据集浏览器标签,如下图所示:
图 10.14 – 数据集浏览器中的原始特征说明
在这里,我们可以看到以下内容:
-
Mimic解释器用于解释特定的模型(这是一个XGBoostClassifier,如图 10.12所示)。作为替代模型的glassbox模型是一个LGBMExplainableModel,如前面截图的左上角所示。
-
您可以编辑队列或定义新的队列,以便通过从 选择要探索的数据集队列 下拉菜单中选择它们来专注于特定的子组。要定义一个新的队列,您需要指定要应用的数据集过滤条件。例如,在前述截图中,我们定义了一个名为 年龄 _45 的队列,它有一个单一的过滤器(年龄 == 45)。在测试数据集中有 4 个数据点 由此解释仪表板使用。
-
您可以通过点击前述截图中标记为 3 的高亮区域来修改 x 轴和 y 轴字段。这使您可以改变视图并获得关于特征与预测值或基本事实之间相关性的见解,特征之间的相关性以及对您的模型理解分析有意义的任何其他视图。
在聚合特征重要性选项卡中,如所示,您可以查看您定义的所有数据或特定队列的特征重要性:
图 10.15 – 根据收入的原始特征与队列和依赖关系的聚合特征重要性
在本例中,收入 特征对于 年龄 _45 队列比一般公众更重要,由 所有数据 表示。如果您点击特征重要性条,下面的图表会更新,显示这个特征如何影响模型决定拒绝贷款请求(类别 0)。在这个例子中,您可以看到从 0 到略高于 5,000 的收入推动模型拒绝贷款,而从 6,000 开始的收入则产生负面影响,这意味着它们试图推动模型批准贷款。
解释仪表板中有大量的功能,而且随着对解释社区的贡献,新功能会不断出现。在本节中,您回顾了仪表板的最重要功能,这些功能帮助您理解模型为什么会做出预测以及如何可能调试性能不佳的边缘案例。
在下一节中,您将学习错误分析,这是微软整体负责人工智能小部件包的一部分。这个工具允许您了解模型的盲点,即模型表现不佳的情况。
分析模型错误
错误分析 是一种模型评估/调试工具,可以帮助你更深入地了解机器学习模型的错误。错误分析帮助你识别数据集中错误率高于其他记录的群体。你可以更密切地观察被错误分类和有误的数据点,查看是否能发现任何系统性模式,例如是否某些群体没有数据可用。错误分析也是描述当前系统缺陷并与其他利益相关者和审计人员沟通的有效方式。
该工具由多个可视化组件组成,可以帮助你了解错误出现的位置。
导航到 chapter10.ipynb
笔记本。在 菜单 中,点击 编辑器 子菜单下的 在 Jupyter 中编辑,以便在 Jupyter 中打开相同的笔记本并继续编辑,如下所示:
图 10.16 – 在 Jupyter 中编辑笔记本以更好地与小部件兼容
重要说明
在编写本书时,由于笔记本体验的安全限制,错误分析面板无法在笔记本环境中运行,这些限制会妨碍某些功能的正常工作。如果你尝试在笔记本中运行,它不会生成必要的可视化效果。因此,你需要在 Jupyter 中打开笔记本,而这一步在你阅读本书时可能不再需要。
在 Jupyter 环境中,在文件末尾添加一个新的单元格并输入以下代码:
from raiwidgets import ErrorAnalysisDashboard
ErrorAnalysisDashboard(global_explanation, model_pipeline,
dataset=x_test, true_y=y_test)
请注意,这段代码与你用来触发解释面板的代码非常相似。
重要说明
确保你关闭所有其他编辑环境中的笔记本,比如在 Azure 机器学习工作室中的笔记本体验。如果笔记本被其他编辑器意外修改,你可能会丢失部分代码。
该工具以全局视图打开,如下所示:
图 10.17 – 错误分析面板在 Jupyter 环境中的加载情况
在此视图中,你可以查看模型在整个数据集上的错误率。在这个视图中,你可以看到一棵二叉树,描述了在可解释子群体之间的数据分区,这些子群体具有出乎意料的高或低错误率。在我们的示例中,模型的所有错误都发生在收入小于或等于 6144 的数据中,这占 7.25% 的错误率,意味着 7.25% 的月收入小于 6144 的贷款被错误分类。错误覆盖率是所有错误中落入此节点的部分,在这种情况下,所有错误都位于该节点中(100%)。节点中的数字表示数据的分布情况。这里,69 条记录中有 5 条是错误的,它们属于这个节点。
一旦你选择了树图中的某个节点,你可以点击群体设置或群体信息,并将这些记录保存为一个感兴趣的群体。这个群体可以用于解释仪表板。在点击解释按钮后,你将进入数据探索器视图,如下所示:
图 10.18 – 针对树图中选择的特定群体的数据探索器
此视图已经预选了节点的群体。它具有类似于解释仪表板的功能,比如查看影响所选群体整体模型预测的特征重要性。此视图还提供了局部解释标签,允许你理解个别错误记录,甚至进行假设分析,了解模型何时会正确分类该记录。
通过点击小部件左上角的错误探索器链接,你将返回树图视图。在错误探索器:下拉菜单中,选择热力图,而不是当前选中的树图。这将引导你到错误热力图视图,如下所示:
图 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。结果显示在下面的截图中:
图 10.20 – 该模型的准确率为 0.96,但对于 65 岁的人群,其准确率为 0.5
尽管数据集已经生成,但你可以看到该模型对 65 岁的人群的准确率只有 50%。请注意,尽管该模型是在 18 至 85 岁之间的年龄段进行训练的,但数据集中只检测到 35 个子组,这表明我们可能没有对其进行准确测试。
与ExplanationDashboard
和ErrorAnalysisDashboard
类似,负责任的 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 岁),你可以修改分箱过程,甚至选择提供的视为分类变量选项,以让每个年龄单独处理。
-
性能指标:性能指标用于评估模型在总体和每个组中的质量。在这种情况下,你可以选择准确度,就像我们之前所做的那样。即使向导完成后,你也可以更改这个选项。
-
公平性指标:公平性指标表示性能指标的极端值之间的差异或比率,或者仅仅是任何组的最差值。此类指标的一个示例是准确度比率,它是任何两个组之间的最小准确度比率。即使向导完成后,你也可以更改这个选项。
生成的仪表板允许你深入了解模型对各子组的影响。它由两个区域组成——总结表格和可视化区域——你可以在这里选择不同的图形表示方式,如下所示:
图 10.21 – 展示不同年龄组中模型准确度的公平性仪表板
一旦你确定了模型中的公平性问题,你可以使用Fairlearn库来缓解这些问题。Fairlearn库提供了两种方法:
-
ThresholdOptimizer
,调整底层模型的输出以实现显式约束,比如均衡赔率的约束。在我们的二元分类模型中,均衡赔率意味着在各组之间,真正例和假正例的比率应该匹配。 -
sample_weight
参数是fit
sklearn 方法接受的。
使用这些技术,你可以通过牺牲一些模型的性能来平衡模型的公平性,以满足你的业务需求。
Fairlearn包正在不断发展,已经集成到 Azure 机器学习 SDK 和 Studio Web 体验中,允许数据科学家将模型公平性洞察上传到 Azure 机器学习运行历史记录中,并在 Azure 机器学习 Studio 中查看Fairlearn仪表板。
在本节中,你学习了如何检测模型可能存在的潜在不公平行为。你还了解了可以在Fairlearn包中实现的潜在缓解技术。这总结了由 Azure 机器学习工作区和开源社区提供的工具,它们帮助你理解模型并协助你创建人工智能。
总结
本章为你概述了几种可以帮助你理解模型的工具。你首先了解了 Interpret-Community 包,它能够帮助你理解模型做出预测的原因。你学习了各种解释技术,并探索了解释仪表板,其中提供了诸如特征重要性等视图。接着,你看到了错误分析仪表板,它能够帮助你确定模型表现不佳的地方。最后,你学习了公平性评估技术、相应的仪表板,能够让你探索潜在的不公平结果,并了解如何采取措施来缓解潜在的公平性问题。
在下一章,你将学习关于 Azure 机器学习管道的内容,管道可以让你以可重复的方式编排模型训练和模型结果的解释。
问题
在每一章中,你会发现一些问题,帮助你对每章讨论的主题进行知识检查:
-
你正在使用
TabularExplainer
来解释DecisionTreeClassifier
。将使用哪种底层的 SHAP 解释器?a.
DecisionTreeExplainer
b.
TreeExplainer
c.
KernelExplainer
d.
LinearExplainer
-
你想使用
MimicExplainer
来解释DecisionTreeClassifier
。你可以使用以下哪种模型作为explainable_model
参数?a.
LGBMExplainableModel
b.
LinearExplainableModel
c.
SGDExplainableModel
d.
DecisionTreeExplainableModel
e. 上述所有选项
-
你能使用
PFIExplainer
来生成局部特征重要性值吗?a. 是的
b. 否
进一步阅读
本节提供了一些有用的网络资源,帮助你增强对 Azure 机器学习 SDK 以及本章中使用的各种代码片段的理解:
-
SmartNoise 库,用于差分隐私:
github.com/opendp/smartnoise-core
-
同态加密资源:
www.microsoft.com/en-us/research/project/homomorphic-encryption/
-
部署加密推理 Web 服务:
docs.microsoft.com/en-us/azure/machine-learning/how-to-homomorphic-encryption-seal
-
Presidio,数据保护和匿名化 API:
github.com/Microsoft/presidio
-
用于数据科学项目中 aDevOps 过程的示例代码库,也称为MLOps:
aka.ms/mlOps
-
模型报告的模型卡:
arxiv.org/pdf/1810.03993.pdf
-
InterpretML 网站,提供了社区的 GitHub 仓库链接:
interpret.ml/
-
错误分析主页,包括如何使用工具包的指南:
erroranalysis.ai/
-
Fairlearn主页:
fairlearn.org/