Google-Vertex-AI-权威指南-全-
Google Vertex AI 权威指南(全)
原文:
annas-archive.org/md5/8868875aad4bcd1618fe77db5ab7a304
译者:飞龙
前言
你好!Google Vertex AI 终极指南是关于利用谷歌作为 Vertex AI 在 Google Cloud 中提供的框架和最佳实践加速现实世界机器学习解决方案开发和部署的全面指南。
开发大规模机器学习解决方案和管理生产中的机器学习工作流程对当今的每一家企业来说都至关重要。谷歌开发了一个统一的数据和人工智能平台,称为 Google Vertex AI,以帮助加速您的机器学习之旅和 MLOps 工具,用于工作流程管理。
本书是一本完整的指南,让您从入门到高级水平全面探索 Google Vertex AI 的所有功能,用于端到端机器学习解决方案开发。从数据管理、模型构建和实验到部署,Vertex AI 平台为您提供无代码、低代码以及完全定制的方法的工具。
本书还提供了在 Google Cloud Platform 上使用计算机视觉、NLP 和生成式人工智能等技术开发和部署一些实际应用的实战指南。此外,本书讨论了 Google 提供的预构建/即插即用解决方案,并展示了如何快速将它们集成到机器学习项目中。
本书面向对象
如果您是一位希望学习在 Google Cloud Platform 上使用 Google Vertex AI 提供的 MLOps 最佳实践和工具进行端到端机器学习解决方案开发旅程的机器学习从业者,这本书就是为您准备的。从数据存储和数据管理开始,本书带您了解 Vertex AI 提供的服务,以快速且可扩展的方式构建、实验、优化和部署机器学习解决方案。它还涵盖了与扩展、监控和管理您的机器学习工作负载相关的主题,这些都是在 Google Cloud 上使用 MLOps 工具的帮助下实现的。
本书涵盖内容
第一章,机器学习项目生命周期和挑战,介绍了典型机器学习项目的生命周期。它还突出了为现实世界用例开发机器学习解决方案的常见挑战和限制。
第二章,什么是 MLOps,为什么它对每个机器学习团队都如此重要?介绍了一组通常被称为 MLOps 的实践,成熟的机器学习团队将其作为其机器学习开发生命周期的一部分。
第三章,一切关于数据 – 存储和转换机器学习数据集的选项,概述了在 Google Cloud 中存储和分析数据的不同选项。它还帮助您根据需求选择最佳选项。
第四章,Vertex AI 工作台 – 一个满足 AI/ML 开发需求的一站式工具,展示了基于 Vertex AI 工作台的笔记本环境在端到端机器学习解决方案开发中的应用。
第五章,构建机器学习模型的无代码选项,涵盖了 GCP AutoML 功能,这些功能可以帮助用户构建业界领先的机器学习模型,而无需代码或深入的数据科学知识。
第六章, 构建机器学习模型的低代码选项,介绍了如何仅使用 SQL 使用BigQuery ML(BQML)构建和评估机器学习模型。
第七章,使用 Vertex AI 训练完全定制的机器学习模型,探讨了如何使用 Google Cloud 上可用的 Vertex AI 工具开发完全定制的机器学习解决方案。本章还展示了如何监控训练进度和评估机器学习模型。
第八章,机器学习模型可解释性,讨论了机器学习模型可解释性的相关概念,并描述了如何有效地将可解释模型融入您的机器学习解决方案,使用 Vertex AI。
第九章,模型优化 – 超参数调整和 NAS,解释了模型优化的必要性。它还详细介绍了两个模型优化框架 – 超参数调整和神经架构搜索(NAS)。
第十章,Vertex AI 部署和自动化工具 – 通过托管 Kubeflow 管道进行编排,概述了机器学习编排和自动化工具。本章还进一步介绍了使用 Cloud Composer 和 Vertex AI 管道的机器学习工作流编排的实现示例。
第十一章,使用 Vertex AI 的 MLOps 治理,描述了可以用于部署治理和监控控制的不同的 Google Cloud ML 工具。
第十二章, Vertex AI – 生成式 AI 工具,概述了 Vertex AI 最近推出的生成式 AI 功能,例如模型花园和生成式 AI 工作室。
第十三章,文档 AI – 处理文档的端到端解决方案,概述了 Google Cloud 上与文档处理相关的服务,例如 OCR 和表单解析器。本章还展示了如何结合预构建和定制的文档处理解决方案来开发定制的文档处理器。
第十四章, 视觉、自然语言处理和语音的机器学习 API,概述了谷歌为计算机视觉、自然语言处理和语音相关用例提供的预构建的业界领先解决方案。它还展示了如何将它们集成以解决现实世界的问题。
第十五章,推荐系统 – 预测用户想看的电影,概述了构建推荐系统的流行方法以及如何使用 Vertex AI 部署一个推荐系统。
第十六章,基于视觉的缺陷检测系统 – 机器现在可以看到,展示了如何使用 Google Cloud 上的 Vertex AI 工具开发端到端基于计算机视觉的定制解决方案,使您能够解决现实世界的用例。
第十七章,自然语言模型 – 检测假新闻文章,展示了如何在 Google Cloud 上开发与 NLP 相关的端到端定制机器学习解决方案。本章探讨了经典和基于深度学习的解决检测假新闻文章问题的方法。
要充分利用本书
您需要具备机器学习和深度学习技术的基本理解。您还应具备 Python 编程语言的入门级经验。
编码练习所需的 软件/硬件 | 操作系统要求 |
---|---|
Python 3.8 或更高版本 | Windows、macOS 或 Linux |
Google Cloud SDK | Windows、macOS 或 Linux |
Google Cloud 平台账户 | N/A |
为了确保在执行代码示例时使用正确的 Python 库版本,您可以查看本书的 GitHub 仓库,其中代码示例笔记本也包含版本信息。
如果您使用的是本书的数字版,我们建议您亲自输入代码或从本书的 GitHub 仓库(下一节中提供链接)获取代码。这样做将帮助您避免与代码复制粘贴相关的任何潜在错误。
下载示例代码文件
您可以从 GitHub(github.com/PacktPublishing/The-Definitive-Guide-to-Google-Vertex-AI
)下载本书的示例代码文件。如果代码有更新,它将在 GitHub 仓库中更新。
我们还有其他来自我们丰富图书和视频目录的代码包,可在github.com/PacktPublishing/
找到。查看它们吧!
使用的约定
本书使用了多种文本约定。
文本中的代码
:表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称。以下是一个示例:“默认情况下,Jupyter 服务器在端口8888
上启动,但在端口不可用的情况下,它会找到下一个可用的端口。”
代码块设置如下:
export PROJECT=$(gcloud config list project --format "value(core.project)")
docker build . -f Dockerfile.example -t "gcr.io/${PROJECT}/tf-custom:latest"
docker push "gcr.io/${PROJECT}/tf-custom:latest"
任何命令行输入或输出都应如下编写:
$ mkdir css
$ cd css
粗体:表示新术语、重要单词或屏幕上看到的单词。例如,菜单或对话框中的单词以粗体显示。以下是一个示例:“在环境字段中,选择自定义容器。”
小贴士或重要注意事项
看起来是这样的。
联系我们
我们始终欢迎读者的反馈。
一般反馈:如果您对此书的任何方面有疑问,请通过电子邮件发送至 customercare@packtpub.com,并在邮件主题中提及书名。
勘误:尽管我们已经尽一切努力确保内容的准确性,但错误仍然可能发生。如果您在此书中发现错误,我们将不胜感激,如果您能向我们报告,我们将不胜感激。请访问www.packtpub.com/support/errata并填写表格。
盗版:如果您在互联网上以任何形式遇到我们作品的非法副本,我们将不胜感激,如果您能提供位置地址或网站名称,我们将不胜感激。请通过 copyright@packt.com 与我们联系,并提供材料的链接。
如果您有兴趣成为作者:如果您在某个主题上具有专业知识,并且您有兴趣撰写或为书籍做出贡献,请访问authors.packtpub.com。
分享您的想法
一旦您阅读了《Google Vertex AI 终极指南》,我们很乐意听到您的想法!请点击此处直接进入此书的亚马逊评论页面并分享您的反馈。
您的评论对我们和科技社区非常重要,并将帮助我们确保我们提供高质量的内容。
下载此书的免费 PDF 副本
感谢您购买此书!
您喜欢随时随地阅读,但无法携带您的印刷书籍到任何地方吗?
您选择的设备是否与您的电子书购买不兼容?
请放心,现在,随着每本 Packt 书籍,您都可以免费获得该书的 DRM 免费 PDF 版本。
在任何地方、任何地点、任何设备上阅读。直接从您最喜欢的技术书籍中搜索、复制和粘贴代码到您的应用程序中。
优惠远不止于此,您还可以获得独家折扣、时事通讯和每日免费内容的每日电子邮件访问权限
按照以下简单步骤获取好处:
- 扫描下面的二维码或访问以下链接
packt.link/free-ebook/978-1-80181-526-0
-
提交您的购买证明
-
就这样!我们将直接将您的免费 PDF 和其他优惠发送到您的电子邮件地址
第一部分:在现实世界机器学习部署中 MLOps 的重要性
在本部分中,您将了解典型现实世界机器学习(ML)项目的生命周期。您还将了解在开发 ML 应用程序过程中遇到的常见挑战以及 ML 框架的一些关键限制。最后,您将了解机器学习操作(MLOps)实践及其在 ML 部署中的重要性。
本部分包含以下章节:
-
第一章,机器学习项目生命周期和挑战
-
第二章, 什么是 MLOps,为什么它对每个机器学习团队都如此重要?
第一章:机器学习项目生命周期和挑战
今天,机器学习(ML)和人工智能(AI)对于许多组织的业务战略来说是不可或缺的部分,每年都有更多的组织使用它们。这种采用的重大原因是机器学习和人工智能解决方案在增加收入、品牌价值和成本节约方面的力量。这种对 AI 和 ML 的采用增加需要更多有技能的数据和机器学习专家以及技术领导者。如果你是机器学习从业者或初学者,这本书将帮助你成为一位自信的机器学习工程师或数据科学家,并了解谷歌的最佳实践。在本章中,我们将讨论生命周期的基础以及开发实际应用时机器学习的挑战和限制。
机器学习项目通常涉及从问题陈述到部署的一系列定义明确的步骤。理解这些步骤的重要性以及其中常见的挑战对于完成一个成功且具有影响力的项目至关重要。在本章中,我们将讨论理解业务问题的必要性,典型机器学习项目生命周期中的常见步骤,以及机器学习在细节上的挑战和限制。这将帮助新的机器学习从业者了解基本的项目流程;此外,它还将为本书后续章节的展开奠定基础。
本章涵盖了以下主题:
-
机器学习项目生命周期
-
开发实际机器学习解决方案的常见挑战
-
机器学习的局限性
机器学习项目生命周期
在本节中,我们将了解机器学习项目的典型生命周期,从定义问题到模型开发,最后到模型的运营化。图 1.1显示了几乎每个机器学习项目都会经历的高级步骤。让我们详细地过一遍所有这些步骤。
图 1.1 – 典型机器学习项目生命周期
就像软件开发生命周期(SDLC)一样,机器学习项目(MDLC)指导了机器学习模型开发和运营的端到端过程。在高级别上,企业环境中典型机器学习项目的生命周期保持相对一致,包括八个关键步骤:
-
定义机器学习用例:任何机器学习项目的第一步是机器学习团队与业务利益相关者合作,评估预测分析的业务需求,并确定一个可以使用机器学习的用例,同时包括一些成功标准、性能指标和可能用于构建模型的可能数据集。
例如,如果 ABC 保险公司的销售/营销部门希望更好地利用其资源,以针对更有可能购买特定产品的客户,他们可能会联系机器学习团队构建一个解决方案,该解决方案可以筛选所有可能的潜在客户/客户,并根据每个潜在客户的(年龄、以往购买、保单历史长度、收入水平等)数据点,识别最有可能购买保单的客户。然后销售团队可以要求他们的客户代表优先联系这些客户,而不是盲目地联系所有可能的客户。这可以显著提高代表的外出电话结果,并提高与销售相关的关键绩效指标。
一旦定义了用例,下一步就是定义一组 KPI 来衡量解决方案的成功。对于这个销售用例,这可能是客户注册率——销售代表与多少比例的客户交谈后注册了新的保险政策?
为了衡量机器学习解决方案的有效性,销售团队和机器学习团队可能同意在机器学习模型上线后,测量客户注册率的增加或减少,并迭代改进模型以优化注册率。
在这个阶段,还将讨论可以用于模型训练的可能数据集。这些可能包括以下内容:
-
由营销和销售团队生成的内部客户/产品数据集,例如,客户元数据,如他们的年龄、教育背景、收入水平、以往购买行为、拥有的车辆数量和类型等。
-
可以通过第三方获取的外部数据集;例如,一个外部营销咨询公司可能已经收集了关于车主的保险购买行为的数据,基于他们拥有的汽车品牌。这些额外的数据可以用来预测他们购买 ABC 保险公司所售保险政策的可能性。
-
-
探索/分析数据:下一步是对数据集进行详细分析。这通常是一个迭代过程,其中机器学习团队与数据和业务领域的专家紧密合作,更好地理解现有数据集的细微差别,包括以下内容:
-
数据来源
-
数据粒度
-
更新频率
-
单个数据点的描述及其商业意义
这是一个关键步骤,数据科学家/机器学习工程师会分析现有数据,并决定哪些数据集可能与正在考虑的机器学习解决方案相关,分析数据的稳健性,并识别任何差距。团队在这个阶段可能识别出的问题可能与数据的清洁性和完整性,或者数据在生产中的及时可用性问题有关。例如,客户的年龄可能是一个很好的购买行为的指标,但如果它是在客户资料中的可选字段,那么可能只有少数客户提供了他们的出生日期或年龄。
因此,团队需要确定他们是否想使用该字段,如果是的话,如何处理缺失年龄的样本。他们还可以与销售和营销团队合作,确保在客户在线请求保险报价并在系统中生成潜在客户时,该字段成为必填字段。
-
-
选择机器学习模型类型:一旦确定了用例以及可能用于训练模型的数据库,下一步就是考虑可以使用哪些类型的模型来实现要求。在这里我们不会深入探讨一般模型选择的话题,因为关于这个话题可以写整本书,但在接下来的几章中,你将看到在 Vertex AI 中可以针对特定用例构建的不同模型类型。在非常高的层面上,这一阶段的关键考虑因素如下:
-
模型类型:例如,在保险客户/潜在客户排名示例中,我们可以构建一个分类模型,预测新客户购买保单的可能性是高/中/低。或者可以构建一个回归模型,为每个可能的客户输出销售概率数值。
-
传统的机器学习模型是否满足我们的要求,或者我们需要深度学习模型?
-
可解释性要求:是否需要对每个预测进行解释,说明为什么样本被分类为某种方式?
-
单个模型与集成模型:我们需要一个单一的模型来给出最终预测,还是需要使用一组相互关联的模型?例如,第一个模型可能将客户分配到特定的客户组,下一个模型可能使用该分组来确定最终购买的可能性。
-
模型分离:例如,有时我们可能需要为整个客户群构建一个单一的全局模型,或者由于不同地区产品和用户行为存在显著差异,我们可能需要为每个地区分别构建模型。
-
-
特征工程:这个过程通常是最耗时的,涉及以下几个步骤:
-
数据清理—在可能的情况下填补缺失值,删除具有太多缺失值的字段
-
数据和特征增强—将数据集合并以引入额外的字段,以及交叉合并现有特征以生成新特征
-
特征分析—计算特征相关性,分析共线性,检查特征中的数据泄露
由于这是一个极其广泛的话题,我们不会深入探讨,并建议你参考其他关于这个话题的书籍。
-
-
迭代模型设计/构建:机器学习模型的实际设计和构建是一个迭代过程,涉及以下关键步骤:
-
选择模型架构
-
将获取的数据分为训练/验证/测试子集
-
运行模型训练实验,调整超参数
-
使用测试数据集评估训练好的模型
-
排序并选择最佳模型
图 1**.2展示了典型的机器学习模型开发生命周期:
-
图 1.2 – 机器学习模型开发生命周期
-
对结果达成共识:一旦获得令人满意的模型,机器学习团队将与业务利益相关者分享结果,以确保结果完全符合业务需求,并执行额外的优化和后处理步骤,使模型预测对业务可用。为了确保业务利益相关者相信机器学习解决方案与业务目标一致,并且足够准确以驱动价值,机器学习团队可以使用多种方法之一:
-
使用历史测试数据集进行评估:机器学习团队可以将历史数据通过新的机器学习模型,并评估预测与真实值的一致性。例如,在之前讨论的保险用例中,机器学习团队可以取上个月关于客户潜在客户的资料,并使用机器学习模型预测哪些客户最有可能购买新的保险政策。然后,他们可以将模型的预测与上个月的实际购买历史进行比较,看看模型的预测有多准确。如果模型的输出接近客户的实际购买行为,那么模型按预期工作,并且可以将此信息展示给业务利益相关者,以使他们相信机器学习解决方案在驱动额外收入方面的有效性。相反,如果模型的输出与客户的行为有显著偏差,机器学习团队需要回过头来改进模型。这通常是一个迭代过程,可能需要多次迭代,具体取决于模型的复杂性。
-
使用实时数据进行评估:在某些情况下,一个组织可能会决定在一个生产环境中使用实时数据进行小规模的试点,以评估新机器学习模型的性能。这通常在以下情况下进行:
-
当没有可用历史数据进行评估,或者使用历史数据进行测试预期不会很准确时;例如,在 COVID 疫情初期,客户行为模式突然发生变化,以至于使用任何历史数据进行测试几乎毫无用处。
-
当生产环境中已经存在用于关键实时预测的现有模型时,新模型的合理性检查不仅需要在准确性方面,还需要在对其下游关键绩效指标(如每用户会话收入)的微妙影响方面进行。
-
在这种情况下,团队可能会在生产环境中部署模型,将少量预测请求转向新模型,并定期比较对关键绩效指标(KPIs)的整体影响。例如,在一个电子商务网站上部署的推荐模型,推荐模型可能会开始推荐比旧模型在生产中已有的预测更便宜的产品。在这种情况下,客户完成购买的可能性会增加,但与此同时,每个用户会话产生的收入会减少,从而影响组织的整体收入。因此,尽管可能看起来机器学习模型按预期工作,但可能不会被业务/销售利益相关者视为成功,还需要更多讨论来优化它。
-
-
实施模型:一旦模型获得在生产环境中部署的批准,机器学习团队将与组织的 IT 和数据工程团队合作,部署模型,以便其他应用程序可以开始利用它来生成洞察。根据组织的大小,这些团队所扮演的角色可能会有很大的重叠。
实际部署架构将取决于以下因素:
-
预测服务级别协议(SLAs) – 范围从周期性批量作业到需要亚秒级预测性能的解决方案。
-
合规性要求 – 用户数据能否发送到第三方云提供商,或者是否需要始终位于组织的数据中心内?
-
基础设施要求 – 这取决于模型的大小及其计算需求。小型模型可以从共享的计算节点提供服务。一些大型模型可能需要一个连接有大型 GPU 的节点。
我们将在后续章节中详细讨论这个主题,但以下图示显示了一些你可能考虑作为部署架构一部分的关键组件。
-
图 1.3 – 机器学习模型训练和部署的关键组件
-
监控和重新训练:似乎一旦模型实施完毕,机器学习团队的工作就完成了,但在现实世界的部署中,大多数模型需要定期或有时是持续的监控,以确保模型在所需的性能阈值内运行。模型性能可能因以下几个原因而变得次优:
-
数据漂移:用于生成预测的数据发生变化可能会显著影响,并影响模型的表现。正如我们之前讨论的,在 COVID 期间,客户行为发生了显著变化。在 COVID 前客户行为数据上训练的模型无法应对这种突然的使用模式变化。由于疫情引起的变化相对较少但影响较大,但预测输入数据中还有许多其他较小的变化可能会对模型的表现产生不利影响。影响可能从精度微妙下降到模型生成错误响应。因此,密切关注你机器学习解决方案的关键性能指标是很重要的。
-
预测请求量变化:如果你的解决方案被设计为每秒处理 100 个请求,但现在看到大约每秒 1,000 个请求的周期性流量激增,你的解决方案可能无法满足需求,或者延迟可能会超过可接受的水平。因此,你的解决方案也需要内置监控和一定程度的自动扩展来处理此类情况。对于流量量的较大变化,你可能甚至需要完全重新思考服务架构。
在某些情况下,通过监控,你会发现你的机器学习模型不再满足预测精度,需要重新训练。如果数据模式的变化是可以预期的,机器学习团队应该设计解决方案以支持自动定期重新训练。例如,在零售行业,产品目录、定价和促销活动不断演变,需要定期重新训练模型。在其他情况下,变化可能是渐进的或出乎意料的,当监控系统向机器学习团队发出模型性能下降的警报时,他们需要决定是否使用更近期的数据进行模型重新训练,或者甚至完全使用新特征重新构建模型。
-
既然我们已经对机器学习项目的生命周期有了很好的了解,让我们来了解一下机器学习开发者在创建和部署机器学习解决方案时面临的常见挑战。
开发现实世界机器学习解决方案的常见挑战
现实世界的机器学习项目总是充满了我们在不同阶段体验到的意外挑战。主要原因在于现实世界中的数据和机器学习算法并不完美。尽管这些挑战会妨碍整体机器学习设置的性能,但它们并不会阻止我们创建有价值的机器学习应用。在一个新的机器学习项目中,很难事先知道挑战。它们通常在项目的不同阶段被发现。其中一些挑战并不明显,需要熟练或有经验的机器学习从业者(或数据科学家)来识别它们,并采取对策来减少它们的影响。
在本节中,我们将了解在开发典型机器学习解决方案过程中遇到的一些常见挑战。以下列表展示了我们将更详细讨论的一些常见挑战:
-
数据收集和安全
-
非代表性训练集
-
数据质量差
-
训练数据集欠拟合
-
训练数据集过拟合
-
基础设施需求
现在,让我们详细了解这些常见挑战。
数据收集和安全
组织面临的最常见挑战之一是数据可用性。机器学习算法需要大量高质量的数据才能提供高质量的结果。因此,对于想要实施机器学习的业务来说,原始数据的可用性至关重要。有时,即使原始数据可用,收集数据也不是唯一的问题;我们通常需要以我们的机器学习算法支持的方式转换或处理数据。
数据安全是机器学习开发者经常面临的一个重要挑战。当我们从一家公司获取数据时,为了正确和高效地实施机器学习,区分敏感和非敏感信息是至关重要的。数据敏感部分需要存储在完全安全的服务器(存储系统)中,并且始终应保持加密。出于安全目的,应避免使用敏感数据,并且只应将不太敏感的数据访问权限授予在项目上工作的可信团队成员。如果数据包含个人身份信息(PII),则可以通过适当匿名化来使用。
非代表性训练数据
一个好的机器学习模型是在未见数据集和训练数据集上表现同样出色的模型。只有在你的训练数据是大多数可能业务场景的良好代表时,这才能实现。有时,当数据集较小时,它可能不是固有分布的真实代表,并且尽管在训练数据集上具有高质量的结果,但该模型在未见数据集上可能提供不准确的预测。这种非代表性数据要么是采样偏差的结果,要么是数据不可用。因此,在非代表性数据集上训练的机器学习模型在生产部署时可能价值较低。
如果无法为业务问题获取真实代表性的训练数据集,那么最好将问题范围限制在我们有足够训练样本的场景。这样,我们将在未见数据集中只获得已知场景,并且模型应该提供高质量的预测。有时,与业务问题相关的数据会随着时间的推移而不断变化,可能无法开发一个单一静态的模型来很好地工作;在这种情况下,对模型进行持续重新训练以使用最新数据变得至关重要。
数据质量差
机器学习算法的性能对训练样本的质量非常敏感。少数异常值、缺失数据案例或一些异常情况可能会显著影响模型的质量。因此,在训练任何机器学习算法之前,在分析数据时仔细处理这些情况非常重要。有多种方法用于识别和处理异常值;最佳方法取决于问题的性质和数据本身。同样,也有多种处理缺失值的方法。例如,均值、中位数、众数等是一些常用的方法来填充缺失数据。如果训练数据量足够大,删除少量带有缺失值的行也是一个不错的选择。
正如讨论的那样,如果我们希望我们的机器学习系统能够准确学习并在未见过的数据集上提供高质量的结果,那么训练数据集的质量是非常重要的。这意味着机器学习生命周期中的数据预处理部分应该非常认真对待。
欠拟合训练数据集
欠拟合机器学习模型意味着模型过于简单,无法学习训练数据集的固有信息或结构。这可能发生在我们尝试使用如线性回归这样的线性机器学习算法来拟合非线性分布时。当我们在训练模型时仅使用最小特征集(这些特征可能对目标分布的信息不多)时,也可能发生欠拟合。这种类型的模型可能过于简单,无法学习目标分布。欠拟合的模型从训练数据中学习得太少,因此在对未见或测试数据集的错误判断上。
解决欠拟合问题的方法有很多。以下是一些常见方法的列表:
-
特征工程——添加更多代表目标分布的特征
-
非线性算法——如果目标分布不是线性的,则切换到非线性算法
-
从数据中去除噪声
-
增加模型的力量——增加可训练参数,增加基于树的集成中的深度或树的数量
就像在训练数据上欠拟合模型一样,过拟合也是一个大问题。让我们深入探讨一下。
过拟合训练数据集
过拟合问题与欠拟合问题是相反的。过拟合是机器学习模型从训练数据中学习太多不必要信息,并且无法在测试或未见数据集上进行泛化的场景。在这种情况下,模型在训练数据集上表现极好,但指标值(如准确率)在测试集上非常低。过拟合通常发生在我们在简单数据集上实现一个非常复杂的算法时。
解决过拟合问题的常见方法如下:
-
增加训练数据量——机器学习模型通常在小型数据集上过拟合
-
使用更简单的模型——当问题简单或本质上是线性的,选择简单的机器学习算法
-
正则化 – 有多种正则化方法可以防止复杂模型在训练数据集上过度拟合
-
降低模型复杂度 – 使用更少的可训练参数,进行更少的训练轮数,并减少基于树的模型的深度
过度拟合和欠拟合是常见的挑战,应像之前讨论的那样仔细处理。现在,让我们讨论一些与基础设施相关的问题。
基础设施需求
机器学习成本高昂。典型的机器学习项目通常涉及处理包含数百万或数十亿样本的大型数据集。对这类数据集进行切片和切块需要大量的内存和高端的多核处理器。此外,一旦项目开发完成,还需要专用服务器来部署模型并匹配消费者的规模。因此,愿意实践机器学习的商业组织需要一些专用基础设施来高效地实施和消费机器学习。当与大型、深度学习模型(如变换器、大型语言模型(LLMs)等)一起工作时,这一需求进一步增加。这些模型通常需要一套加速器、图形处理单元(GPUs)或张量处理单元(TPUs)来进行训练、微调和部署。
正如我们之前讨论的,基础设施对于实践机器学习至关重要。缺乏此类基础设施的公司可以咨询其他公司或采用基于云的服务来开始开发基于机器学习的应用程序。
现在我们已经了解了在开发机器学习项目过程中面临的常见挑战,我们应该能够就这些问题做出更明智的决定。接下来,让我们了解一些机器学习的限制。
机器学习的限制
机器学习非常强大,但并非每个问题的答案。有些问题机器学习根本不适用,有些情况下由于技术或业务限制,机器学习无法应用。作为一名机器学习从业者,发展出在机器学习可以提供显著价值的相关业务问题中找到相关问题的能力非常重要,而不是盲目地将其应用于任何地方。此外,还有一些算法特定的限制,可能导致机器学习解决方案在某些商业应用中不可用。在本节中,我们将了解一些在寻找相关用例时应注意的常见机器学习限制。
请记住,我们在此节中讨论的限制非常普遍。在现实世界的应用中,由于我们解决问题的性质,可能存在更多可能的限制。我们将详细讨论的一些常见限制如下:
-
数据相关的担忧
-
问题的确定性
-
解释性和可重复性的缺乏
-
与成本和定制相关的担忧
-
伦理担忧和偏见
让我们现在深入探讨这些常见限制的每一个。
数据相关的担忧
机器学习模型的质量高度依赖于其提供的训练数据的质量。现实世界中的数据通常是嘈杂的、不完整的、未标记的,有时甚至无法使用。此外,大多数监督学习算法需要大量的正确标记的训练数据才能产生好的结果。某些算法(例如深度学习)的训练数据需求非常高,以至于手动标记数据都不是一个选项。即使我们设法手动标记数据,由于人类偏见,这也常常是容易出错的。
另一个主要问题是信息不完整或数据缺失。例如,考虑自动语音识别的问题。在这种情况下,模型结果高度偏向于训练数据集中存在的口音。一个训练于美式口音的模型在其他带口音的语音上无法产生好的结果。由于口音在我们前往世界不同地区时会发生显著变化,因此很难收集和标记与每个可能的口音相关的相关数量的训练数据。因此,开发一个适用于所有人的单一语音识别模型目前还不可行,因此,提供语音识别解决方案的科技巨头通常开发针对特定口音的模型。为每个新的口音开发新的模型并不具有很强的可扩展性。
问题的不确定性
机器学习在解决一些高度复杂的问题上取得了巨大的成功,例如数值天气预报。大多数当前机器学习算法的一个问题是它们本质上是随机的,因此在问题是确定性的情况下不能盲目信任。考虑到数值天气预报的案例,今天我们有机器学习模型可以以可接受的精度预测降雨、风速、气压等,但它们完全无法理解真实天气系统背后的物理。例如,一个机器学习模型可能会提供密度等参数的负值估计。
然而,在不久的将来克服这类限制的可能性非常大。机器学习领域的未来研究可能会发现足够智能的新算法,能够理解我们世界的物理。这样的模型将在未来开辟无限的可能性。
解释性和可重复性的缺乏
许多机器学习算法(以及通常神经网络)的一个主要问题是结果的可解释性不足。许多商业应用,如欺诈检测和疾病预测,需要为模型结果提供合理的解释。如果一个机器学习模型将一笔金融交易分类为欺诈,它也应该为这个决策提供坚实的证据;否则,这种输出可能对业务没有帮助。深度学习或神经网络模型通常缺乏可解释性,这类模型的可解释性是一个活跃的研究领域。已经为模型的可解释性或可解释性目的开发了多种方法。尽管这些方法可以为结果提供一些见解,但它们仍然远远不能满足实际需求。
另一方面,可重复性是机器学习解决方案中另一个复杂且日益增长的问题。一些最新的研究论文可能通过在固定数据集上使用一些技术进步,展示了结果的巨大改进,但在现实世界场景中,同样的方法可能不起作用。其次,机器学习模型通常是不稳定的,这意味着它们在训练不同数据集分区时会产生不同的结果。这是一个具有挑战性的情况,因为为某个业务部门开发的模型可能对另一个业务部门完全无用,尽管潜在的问题陈述是相似的。这使得它们的可重用性降低。
与成本和定制相关的担忧
开发和维护机器学习解决方案通常成本高昂,尤其是在深度学习算法的情况下。开发成本可能来自雇佣高度熟练的开发者以及用于数据分析和学习实验的基础设施。深度学习模型通常需要高性能计算资源,如 GPU 和 TPU 进行训练和实验。使用这些模型进行超参数调整作业的成本更高,耗时也更长。一旦模型准备就绪,它需要专门的资源进行部署、监控和维护。随着你将部署扩展到为大量客户服务,这种成本还会进一步增加,如果还有非常低的延迟要求,成本会更高。因此,在进入开发阶段之前,了解我们的解决方案将要带来的价值非常重要,并检查它是否值得投资。
另一个关于机器学习解决方案的担忧是它们缺乏定制性。机器学习模型通常很难定制,这意味着很难改变它们的参数或使它们适应新的数据集。预构建的通用机器学习解决方案通常在特定的商业用例上效果不佳,这使它们面临两个选择——要么从头开始开发解决方案,要么定制预构建的通用解决方案。尽管在这里定制预构建模型似乎是一个更好的选择,但在机器学习模型的情况下,即使是定制也不是一件容易的事情。机器学习模型的定制需要一组具有深厚技术概念(如深度学习、预测建模和迁移学习)理解的数据工程师和机器学习专家。
伦理问题和偏见
机器学习(ML)非常强大,并且今天被许多组织采用来指导他们的商业策略和决策。正如我们所知,这些机器学习算法中的一些是黑盒;它们可能不会提供其决策背后的原因。机器学习系统是在有限的数据集上训练的,它们可能不适用于某些现实世界场景;如果在未来遇到这些场景,我们无法预测机器学习系统将做出什么决策。与这种黑盒决策相关的伦理问题可能存在。例如,如果一辆自动驾驶汽车发生了交通事故,你应该责怪谁——司机、开发 AI 系统的团队,还是汽车制造商?因此,很明显,当前机器学习和人工智能的进步并不适合伦理或道德决策。此外,我们需要一个框架来解决涉及机器学习和人工智能系统的伦理问题。
机器学习解决方案的准确性和速度通常值得称赞,但这些解决方案并不总是可以信赖它们是公平和无偏见的。考虑一下识别给定图像中人脸或物体的 AI 软件;这个系统可能在相机无法正确捕捉种族敏感性照片时出错,或者它可能将某种类型的狗(与猫有些相似)分类为猫。这种偏见可能来自用于开发 AI 系统的有偏见的训练或测试数据集。现实世界中的数据通常由人类收集和标记;因此,人类中存在的偏见被转移到 AI 系统中。完全避免偏见是不可能的,因为我们都是人类,因此都有偏见,但我们可以采取一些措施来减少它。建立伦理文化并组建来自不同背景的团队可以是在一定程度上减少偏见的好步骤。
摘要
机器学习(ML)是任何企业战略和许多组织决策的不可或缺部分,因此正确地执行它非常重要。在本章中,我们了解了典型机器学习项目开发生命周期中涉及的一般步骤及其重要性。我们还强调了机器学习实践者在项目开发过程中面临的一些常见挑战。最后,我们列出了一些机器学习在现实场景中的常见局限性,以帮助我们选择合适的企业问题和相应的机器学习算法来解决它。
在本章中,我们学习了选择正确的企业问题的重要性,以便利用机器学习产生最大的影响。我们还了解了典型机器学习项目的总体流程。现在,我们应该对识别业务流程中潜在的机器学习相关挑战并做出明智的决策充满信心。最后,我们学习了机器学习算法的常见局限性,这将帮助我们更好地应用机器学习,从中获得最佳效果。
仅开发一个高性能的机器学习模型是不够的。真正的价值在于它在现实世界中的应用和部署。将机器学习模型投入生产并非易事,并且应该以正确的方式进行。下一章将详细介绍在将机器学习模型投入运营时应遵循的指南和最佳实践,这在深入研究本书后续章节之前将极为重要。
第二章:什么是 MLOps,为什么它对每个机器学习团队都如此重要?
机器学习运维 (MLOps) 是现代机器学习团队的关键实践,它融合了技术和操作的最佳实践。在其核心,MLOps 旨在解决将机器学习模型投入生产和促进数据科学家与 IT 团队之间更好协作的挑战。随着技术的快速进步和对机器学习解决方案的日益依赖,MLOps 正成为可持续和可扩展机器学习策略的支柱。本章将深入探讨 MLOps 的本质,详细阐述其重要性、其各种成熟度级别以及 Google 的 Vertex AI 在促进 MLOps 中的作用。到本章结束时,你将具备对 MLOps 原则的稳健理解,以及 Vertex AI 中可用于实施这些原则的工具。
在本章中,我们将涵盖以下主题:
-
为什么 MLOps 很重要?
-
MLOps 成熟度级别
-
Vertex AI 如何帮助实施 MLOps?
让我们开始这段启发性的旅程,掌握 Vertex AI 上的 MLOps。
为什么 MLOps 很重要?
随着机器学习模型在当今世界的开发和集成变得越来越普遍,对稳健的操作框架的需求比以往任何时候都更加迫切。MLOps 旨在通过简化开发、部署和监控机器学习模型的整个流程来满足这一需求。在本节中,我们将从以下方面讨论 MLOps 的重要性:
-
标准化和自动化 机器学习工作流程
MLOps 旨在标准化和自动化机器学习生命周期的各个阶段,从数据摄取和预处理到模型训练、评估和部署。通过这样做,它最小化了人为错误的可能性,促进了可重复性,并提高了整体效率。Google 的 Vertex AI 为机器学习工作流程的每个阶段提供托管服务,这有助于组织实现一致性、自动化流程并降低运营成本。
-
监控和管理 模型性能
MLOps 的一个关键方面是持续监控和管理已部署模型的表现。这是至关重要的,因为由于数据分布的变化、不可预见的边缘情况或用户行为的演变,机器学习模型的有效性可能会随时间推移而降低。Google 的 Vertex AI 通过提供监控模型性能的工具并在性能阈值被突破时生成警报来支持 MLOps。此外,它还支持与其他 Google Cloud 生态系统中的监控和日志记录服务的无缝集成。
-
确保可扩展性和灵活性
MLOps 通过提供一个框架来促进机器学习解决方案的扩展,该框架可以轻松适应增加的数据量、更复杂的模型和额外的基础设施需求。Google 的 Vertex AI 旨在处理这些需求,提供一系列自动扩展、支持分布式训练和预测以及允许用户为特定用例选择最佳硬件配置的服务和工具。
-
安全和合规性
MLOps 强调在机器学习工作流程中安全性和合规性的重要性,确保满足数据隐私和监管要求。Google 的 Vertex AI 通过提供安全的模型训练、存储和部署环境来支持这些目标。它与 Google Cloud 的身份和访问管理(IAM)集成,可以实现对资源访问的精细控制,同时加密选项保护数据在静态和传输过程中的安全。
在开发机器学习模型时,可能会采取许多捷径或忽略复杂性,这些都会随着时间的推移积累“债务”,导致系统维护困难或未来的失败。随着在生产中部署的机器学习解决方案的发展,开发者可能会添加更多功能以提高准确性和为用户提供整体价值。每个功能通常都有其自己的预处理、归一化和配置参数的具体方式。随着时间的推移,管理这些配置和相关变更可能会变得越来越复杂,解决方案可能会积累大量的技术债务。MLOps 提供了必要的实践和工具来管理和减轻这些债务,确保可持续和可扩展的机器学习部署。
总结来说,MLOps 在简化机器学习工作流程、增强协作以及确保模型安全、可扩展和良好维护方面发挥着至关重要的作用。Google 的 Vertex AI 凭借其全面的工具和服务套件,使组织能够拥抱 MLOps 并释放其机器学习解决方案的潜力。
现在,让我们来看看在行业中常见的典型 MLOps 实施的不同成熟度或复杂度级别。请记住,我们将讨论的架构只是不同复杂度级别的代表性样本。在现实世界中,你会看到这些实施方式的许多不同变体,每种实施方式都像使用它的组织一样独特。
实施不同的 MLOps 成熟度级别
大多数新的机器学习团队和组织在构建和改进他们的 MLOps 策略时,都会经历一个分阶段的 MLOps 旅程。他们通常从一个完全手动、一步一步的过程开始,其中数据科学/数据工程团队采取极其手动、临时的方法来构建和部署模型。一旦部署并稳定了几个模型,就会逐渐明显地看出这种手动过程的可扩展性不高,团队需要实施一些流程和自动化。
在这一点上,随着生产中出现问题,这种临时方法不易审计或重现也变得明显。随着机器学习解决方案的使用增加,它从仅仅是一个实验转变为组织越来越依赖的东西。合规团队和领导层也开始要求使模型部署过程更加有组织和可审计,以确保符合公司的 IT 政策。在这个阶段,团队领导需要根据他们可用的资源以及他们正在工作的项目解决方案路线图,制定一个高级 MLOps 策略和实施路线图。一些组织决定提前构建整个 MLOps 堆栈,而其他组织可能决定一步一步地通过不同的成熟度级别。
现在,让我们看看大多数机器学习(ML)组织通常经历的不同的成熟度级别。
MLOps 成熟度级别 0
这是组织刚开始尝试机器学习解决方案,还没有准备好一个成熟的 MLOps 策略的阶段,关于随着他们扩大机器学习采用的标准流程和工具看起来会是什么样子。在这个阶段,情况如下所示:
-
组织为每个业务单元只部署了 1-2 个模型到生产环境中
-
人工智能/机器学习(AI/ML)的开发由一个由数据科学家组成的小型集中团队处理
-
重点是部署速度而不是一致的过程
-
机器学习工具的选择尚不明确,领导层希望在承诺特定的机器学习平台之前弄清楚哪些有效,哪些无效
-
大多数,如果不是所有步骤都是手工完成的
下面的图表显示了成熟度级别 0 的 MLOps 解决方案的不同关键组件:
图 2.1 – MLOps 解决方案:成熟度级别 0
如前图所示,在 MLOps 成熟度级别 0,大多数从一项流程到下一项流程的交接都是手工完成的。这通过不需要构建和测试广泛的自动化流程,确保了快速的生产部署(当需要时)。显然,缺点是团队每次需要运行管道时都需要花费大量时间。因此,机器学习工程团队需要制定一个路线图/策略,随着时间的推移逐步增加自动化。
MLOps 成熟度级别 1 – 自动化基本机器学习步骤
MLOps 成熟度级别 1 的一个关键特征是完全自动化的数据和机器学习模型训练管道。在这个阶段,通过点击一个按钮或一个 API 调用,可以触发完整的数据获取和模型重新训练。
对于最接近解决方案开发团队的团队来说,最显著的瓶颈之一是数据获取和模型训练过程。在MLOps 成熟度水平 0部分,大多数关于数据摄取和模型构建的步骤都是手动完成的,即使重复类似步骤并稍微修改参数也容易出错。因此,数据和机器学习模型训练管道最终成为第一个需要自动化的组件。这也得益于大多数数据和机器学习管道工作都是在同一团队内完成的;也就是说,数据管道工作由数据团队完成,而机器学习模型设计和构建由数据科学/机器学习团队完成。这减少了团队之间的自动化依赖。显然,仍然需要依赖 IT 团队确保适当的编排和自动化工具的可用性。
图 2.2 – MLOps 成熟度水平 1
如前图所示,在 MLOps 管道中,大多数组件在此成熟度水平下都是自动化的。
自动化的机器学习管道组件如下:
-
数据导入:导入最新数据的过程几乎完全自动化,并通过外部触发器启动,这些触发器指示新数据的可用性。
-
特征/数据工程:在先前的数据传输步骤完成后自动触发。
-
数据验证:在此阶段,数据验证主要通过在数据/特征工程步骤结束时触发的编排脚本来处理。
-
模型训练:一旦数据验证成功完成,编排层就会触发模型训练步骤,使用新可用的数据重建模型。
-
模型验证:通过编排脚本来自动基准测试模型的预测性能,确保模型在获得生产部署批准之前满足业务和技术要求。
-
在集中式模型注册表中注册新模型:一旦模型经过验证,它就会被推送到一个集中式模型注册表,该注册表保存所有批准的模型的目录。
在此阶段引入的其他新组件,以支持自动化,如下所示:
-
代码仓库:为确保数据和管道执行的一致性,创建一个集中式仓库来托管管道代码/逻辑非常重要。为此,企业使用他们内部的 Git 实现,如 GitHub 或 GitLab,或者基于云的代码仓库工具,如Google Cloud Platform(GCP)云源代码仓库。(本书的范围不包括对这些工具的详细说明。)
-
特征存储:特征集中目录/存储库,可以使实验自动化/可重复性更容易且更一致。这可以通过使用独立的专用工具,如FEAST或 Vertex AI 特征存储,或者使用标准数据仓库工具的定制实现来完成。Vertex AI 特征存储在第十一章,“使用 Vertex AI 的 MLOps 治理”中详细讨论。
在这些基本的 MLOps 组件到位后,您的解决方案将更加高效,并且更不容易出现人为错误。
MLOps 成熟度级别 2 – 自动化模型部署
MLOps 成熟度级别 2 的关键特征是持续部署能力,可以自动将任何新的机器学习模型部署到生产环境中,并在模型精度检测到变化时,根据监控服务的触发器创建新的机器学习模型。
以下图示描绘了一个具有成熟度级别 2 的代表性 MLOps 实现。
图 2.3 – MLOps 成熟度级别 2
在成熟度级别 2 的架构中,数据采集和机器学习建模部分一旦实现自动化,下一个明显的瓶颈就是模型构建端与模型部署端的集成。这包括两个部分:
-
将经过验证步骤的新训练模型部署到生产中的过程。例如,通过验证测试的新模型应自动部署到生产中。
-
将监控服务收集的数据转化为可操作的见解,并触发模型更新。例如,生产中传入的特征值的变化可以触发使用新数据的机器学习模型的重新训练。
在这个阶段引入的另一个新组件是为了支持自动化,即元数据存储。这是在数据采集、特征生成、模型开发和部署的每个步骤中生成的所有元数据的存储库。在自动化部署和重新训练过程中,它作为模型开发历史记录的来源变得很重要。例如,为了监控生产中的模型以检测数据漂移或训练偏差,监控过程需要访问模型的 历史,以获取其训练的数据集。与自动化无关的另一个用例是元数据存储可以启用模型审计。如果在模型开发过程中,所有关于数据和模型的关键参数都被记录到元数据存储中,那么它可以向模型审计员提供关于模型的端到端可见性。以下图例展示了这一点,您可以看到模型的旅程:
图 2.4 – Vertex AI 元数据存储
现在我们来看一下您如何使用 Vertex AI 来实现端到端的 MLOps 解决方案。
Vertex AI 如何帮助实现 MLOps?
Google Cloud Vertex AI 是一个平台,提供工具和资源,以端到端的方式实现 ML 开发生命周期。
Vertex AI 通过提供自动模型构建和部署、模型版本控制和跟踪、以及在生产中监控和管理模型等功能来帮助 MLOps。此外,它还提供协作工具和资源共享,使团队能够共同进行大型和分布式 ML 项目。
Vertex AI 还可以帮助 MLOps 的其他方面,例如以下内容:
-
数据管理:Vertex AI 可以帮助进行数据准备、标注和管理,这对于构建准确的 ML 模型至关重要
-
实验:Vertex AI 可以帮助跟踪和管理实验,包括比较和选择最佳模型
-
模型治理:Vertex AI 可以帮助管理模型访问权限和监控模型漂移和合规性
-
持续集成和持续交付(CI/CD):Vertex AI 可以帮助自动化构建、测试和部署模型的过程,这对于保持模型更新并确保其在生产中始终运行顺畅非常重要
-
可扩展性:Vertex AI 可以帮助扩展 ML 模型以处理大量数据和流量,这对于在生产中维持模型性能至关重要
-
监控:Vertex AI 可以帮助监控和衡量生产中 ML 模型的性能,这对于了解模型工作情况良好与否以及识别改进领域至关重要
总体而言,Vertex AI 通过提供在 GCP 上管理整个 ML 生命周期的全面平台,从开发到部署和维护,简化了在生产中构建、部署和管理 ML 模型的过程。
此表显示了哪些 Vertex AI 工具或功能可以帮助您实现典型 MLOps 管道中的哪些组件:
MLOps 组件 | Vertex AI 工具 | 其他 GCP 工具 |
---|---|---|
特征管理 | Vertex AI 特征存储 | N/A |
数据管理 | Vertex AI 数据集 | BigQueryGoogle Cloud Storage |
数据探索与分析 | Vertex AI 工作台 | 数据融合 |
元数据存储 | Vertex AI 元数据存储 | N/A |
工作流编排 | Vertex AI 管道 | 基于 Google Kubernetes Engine (GKE)的 Kubeflow Composer(Airflow) |
模型注册 | Vertex AI 模型注册 | N/A |
模型开发 | Vertex AI 训练 Vertex AI 实验 | N/A |
模型服务/预测服务 | Vertex AI 批量预测 Vertex AI 端点 | 在 GCE 或 GKE 上的自定义部署 |
监控 | Vertex AI 监控 | N/A |
表 2.1 – MLOps 到 GCP 产品映射
让我们详细看看这些 Vertex AI 工具。
Vertex AI 工作台是一个基于 Jupyter Notebook 的完全托管开发环境,支持整个数据科学工作流程。主要功能包括以下内容:
-
与大多数 Google Cloud 数据源集成,例如 BigQuery 和 Google Cloud Storage
-
创建和使用高度可扩展的 Jupyter 虚拟机(VM)实例的能力
-
通过 软件开发 套件(SDK)触发和使用大多数 GCP 服务的能力
-
在 Dataproc(托管 Spark 服务)中启动集群和作业创建的能力
-
笔记本调度
以下截图显示了 Vertex AI 工作台仪表板,列出了所有部署的 Jupyter Notebook 实例:
图 2.5 – Vertex AI 工作台仪表板
Vertex AI 数据管理正如其名所示,是 Vertex AI 的原生数据集管理服务。它允许用户执行以下操作:
-
将数据导入 Vertex AI 并管理数据集
-
管理标签和多个注释集
-
当与元数据存储结合使用时,它有助于跟踪数据血缘以进行故障排除和审计
-
生成数据统计和可视化
以下截图显示了 Vertex AI 数据集仪表板,列出了使用该工具创建的所有数据集:
图 2.6 – Vertex AI 数据集仪表板
Vertex AI 特征存储是 Vertex AI 的一部分,是一个托管特征目录服务。主要功能包括以下内容:
-
导入和组织特征值的能力
-
以批量或实时模式提供特征值的能力
-
监测特征值随时间的变化并生成警报的能力
以下截图显示了 Vertex AI 特征存储仪表板,列出了工具中存在的所有特征和实体。
图 2.7 – Vertex AI 特征存储仪表板
Vertex AI 管道是 Vertex AI 平台中的托管 Kubeflow 服务,它帮助您编排复杂的数据和机器学习工作流程。主要功能包括以下内容:
-
支持 Kubeflow 管道 SDK
-
支持 TensorFlow 扩展(TFX)
-
将垂直可扩展组件作为容器部署的能力
-
与所有 Vertex AI 工具和大多数 Google Cloud 服务进行原生集成
以下截图显示了 Vertex AI 管道仪表板,列出了所有最近执行的管道。
图 2.8 – Vertex AI 管道仪表板
Vertex ML 元数据存储可以存储机器学习管道中的关键参数/工件,以实现以下功能:
-
对机器学习模型进行血缘跟踪和审计
-
模型可重现性
-
实验分析
-
跟踪机器学习工件的下游使用情况,以实现更好的治理和合规性
下面的截图显示了 Vertex AI 元数据存储仪表板。下图展示了描述机器学习管道世系的元数据存储样本工件。
图 2.9 – Vertex AI 元数据存储
Vertex AI 模型注册表是一个集中注册所有机器学习模型的注册表,无论它们是自定义模型还是使用 AutoML 功能生成的模型。主要功能包括以下内容:
-
完全管理的模型注册表
-
为批量或实时预测服务提供无缝模型部署
-
能够比较模型
下图展示了 Vertex AI 模型注册表的仪表板,其中包含已注册模型的列表。
图 2.10 – Vertex AI 模型注册表
Vertex AI 训练是 Vertex AI 中的核心管理训练服务,使用户能够在不管理底层基础设施的情况下运行复杂的机器学习模型训练作业。主要功能包括以下内容:
-
原生支持 TensorFlow、XGBoost 和 scikit-learn 自定义模型
-
能够使用自定义容器部署训练作业
-
自动化各种用例的机器学习
-
能够在极其可扩展的按需集群上部署模型
-
管理 TensorBoard
Vertex AI 实验是一个管理的实验编排功能,它使数据科学团队能够启动多个具有略微不同超参数的类似训练作业,作为模型设计的一部分。
下图展示了 Vertex AI 实验仪表板,其中包含已执行的训练实验列表。
图 2.11 – Vertex AI 实验仪表板
Vertex AI 批量预测为上传到模型注册表的模型提供完全管理的批量预测。
下图展示了 Vertex AI 批量预测仪表板,其中包含在平台上运行的批量预测作业列表。
图 2.12 – Vertex AI 批量预测仪表板
Vertex AI 端点是针对实时预测用例的管理模型服务能力。主要功能包括以下内容:
-
可配置的服务基础设施
-
自动扩展功能
-
能够检测与预测延迟增加、容量瓶颈等问题相关的性能问题数量
下图展示了 Vertex AI 端点的仪表板。
图 2.13 – Vertex AI 监控仪表板
Vertex AI 监控帮助自动化生产中部署模型的监控,以主动识别性能问题。主要功能包括以下内容:
-
漂移检测
-
训练-服务偏差检测
如您所见,Google Cloud Vertex AI 提供了一套全面且强大的工具,可以帮助您简化整个 ML 开发生命周期,从数据管理到模型部署和监控。
摘要
在本章中,我们深入探讨了 MLOps 的核心概念,并探讨了 MLOps 解决方案在现实场景中展现出的各种成熟度水平。我们还讨论了作为 Vertex AI 平台一部分的可用工具和资源,这些工具旨在帮助简化并自动化构建、部署和维护 ML 模型的过程。
在阅读本章后,我们希望您能够更好地阐述 MLOps 实践的基本原理,并为您的组织制定一个高级 MLOps 策略,考虑到您组织的独特需求和目标,并了解 Vertex AI 作为 GCP 的一部分如何在您的组织 MLOps 策略中发挥关键作用。
在下一章中,我们将介绍 Google Cloud 提供的数据存储选项,以支持您的 ML 解决方案的训练需求。我们还将讨论可用于帮助您在特征工程活动中转换大规模数据集的工具。
第二部分:Google Cloud 上自定义模型的机器学习工具
在本部分,您将了解 Google Cloud 提供的关键 ML 工具概述。您将学习关于 Google Vertex AI 中存储和转换数据、训练 ML 模型、模型优化、模型可解释性等不同选项。此外,您还将了解 Vertex AI 提供的部署工具、自动化工具和治理工具,这些工具用于 ML 编排。
本部分包含以下章节:
-
第三章, 一切关于数据 – 存储和转换 ML 数据集的选项
-
第四章, Vertex AI 工作台 – 满足 AI/ML 开发需求的单一工具
-
第五章, 构建 ML 模型的无代码选项
-
第六章, 构建 ML 模型的低代码选项
-
第七章, 使用 Vertex AI 训练完全自定义的 ML 模型
-
第八章, ML 模型可解释性
-
第九章, 模型优化 – 超参数调整和 NAS
-
第十章, Vertex AI 部署和自动化工具 – 通过托管 Kubeflow 管道进行编排
-
第十一章, 使用 Vertex AI 的 MLOps 治理
第三章:一切都是关于数据——存储和转换 ML 数据集的选项
在机器学习项目中,真正的工作只有在项目开发环境中可用所需数据之后才开始。有时,当数据变化非常频繁或用例需要实时数据时,我们可能需要设置一些数据管道,以确保所需数据始终可用于分析和建模目的。最佳的数据传输、存储或转换方式也取决于底层数据的大小、类型和性质。在现实世界中收集的原始数据通常规模庞大,可能属于多种类型,如文本、音频、图像、视频等。由于现实世界数据的性质、大小和类型的多样性,设置正确的基础设施来大规模存储、传输、转换和分析数据变得非常重要。
在本章中,我们将学习将数据移动到 Google Cloud 环境的不同选项、不同的数据存储系统以及高效地对大规模数据进行转换的方法。
在本章中,我们将探讨以下关于数据的话题:
-
将数据移动到 Google Cloud
-
数据存储位置
-
数据转换
将数据移动到 Google Cloud
当我们在Google Cloud Platform(GCP)上启动机器学习项目时,第一步是将所有与项目相关的数据移动到 Google Cloud 环境中。在向云传输数据时,需要关注的关键问题是可靠性、安全性、可扩展性和管理传输过程的便捷性。考虑到这些因素,Google Cloud 提供了四个主要的数据传输工具,以满足各种用例的客户需求。一般来说,这些工具对任何类型的数据传输目的都很有用,包括数据中心迁移、数据备份、内容存储和机器学习。鉴于我们目前的重点是使数据可用于机器学习用例,我们可以利用以下任何一种传输解决方案:
-
Google Cloud Storage 传输工具
-
BigQuery 数据传输服务
-
存储传输服务
-
传输设备
让我们了解每种传输解决方案。
Google Cloud Storage 传输工具
当我们的数据集不是太大(几 TB 以内即可)且我们希望将其存储在Google Cloud Storage(GCS)桶中时(GCS 是一个对象存储系统,与我们的计算机中的本地文件系统非常相似;我们将在下一节中了解更多关于它的信息),此选项是合适的。Google Cloud 提供了从我们的计算机直接上传数据到这些 GCS 桶的工具。我们可以使用以下方法之一上传一个或多个文件,甚至是一个包含文件的文件夹,并使用 Google Cloud 控制台中的上传进度窗口跟踪上传进度。
这里是上传文件或文件夹到 GCS 桶的三种方法:
-
使用 Google Cloud 控制台 UI
-
使用命令行
-
使用 REST API(JSON API)
让我们更详细地看看这些方法。
使用 Google Cloud 控制台 UI
使用云控制台用户界面上传文件或包含文件的文件夹到 GCS 非常简单。当我们上传一个文件夹时,文件夹内的层次结构也会被保留。按照以下简单步骤使用 UI 上传数据到 GCS 存储桶:
-
打开浏览器并访问Google Cloud 控制台页面。
-
在左侧面板中,点击云存储并打开存储桶页面。它将列出我们项目中所有现有的存储桶。
-
如果相关的存储桶已经存在,请点击其名称;否则,创建一个新的存储桶来存储上传的文件或文件夹。
-
一旦我们进入存储桶,我们将看到存储桶详情和现有内容。现在,我们可以直接使用上传文件或上传文件夹按钮上传数据。UI 还提供了创建新文件夹和下载或删除文件选项。
注意
文件夹上传仅支持使用 Chrome 浏览器。它可能与其他浏览器不兼容。
使用命令行
Google Cloud 还提供了一个名为GSUTIL的开源命令行实用工具。我们可以利用 GSUTIL 进行脚本数据传输,也可以使用简单的命令来管理我们的 GCS 存储桶。对于大规模流式数据,它支持多线程/多进程数据传输以推送脚本输出。它可以在rsync模式下操作并传输数据的增量副本。
GSUTIL 命令与 Unix 命令非常相似。以下示例展示了如何将文件复制到我们之前创建的 GCS 存储桶中:
$ gsutil cp Desktop/file.txt gs://my-bucket-name
同样,我们可以使用ls
命令列出存储桶的内容:
$ gsutil ls gs://my-bucket-name
$ gsutil ls gs://my-bucket-name/my-data-folder
REST API (JSON API)
JSON API 接口让我们能够以编程方式访问或操作 GCS 数据。这种方法更适合熟悉网络编程和创建使用 HTTP 请求消费网络服务的应用程序的软件开发人员。例如,我们可以使用以下 HTTP 请求列出特定存储桶的对象:
GET https://storage.googleapis.com/storage/v1/b/my-bucket/o
重要提示
要使用上述方法访问、操作或上传数据,我们必须拥有适当的身份和访问管理(IAM)权限。项目所有者可以向项目开发团队提供相关权限列表。
BigQuery 数据传输服务
BigQuery 数据传输服务目前支持从 Google 软件即服务 (SaaS)应用、外部云提供商、数据仓库如Teradata或Redshift以及一些第三方源加载数据。一旦数据可用,我们就可以直接在BigQuery (BQ)中进行分析或机器学习。它也可以用作数据仓库解决方案;我们将在接下来的章节中了解更多关于 BQ 的信息。
存储传输服务
与 GSUTIL 相比,存储传输服务是一种托管服务,适用于在不同云(AWS 和 Azure)、本地或谷歌云中不同存储桶之间快速且安全地传输数据。数据传输过程非常快,因为它利用了高带宽网络。它还处理重试并提供详细的传输日志。
转移设备
当我们想要迁移一个非常大的数据集且带宽有限时,此选项是合适的。转移设备是一种具有高内存容量的物理设备,可用于将数据传输并安全地运送到谷歌上传设施,在那里数据被上传到云存储。我们可以从云控制台订购设备,一旦收到设备,我们就可以开始复制我们的数据。最后,我们可以将设备运回谷歌,以将数据传输到指定的 GCS 存储桶。
对于大多数与机器学习相关的用例,前两种方法应该足以快速、安全且一致地传输数据。接下来,让我们更多地了解谷歌云上的 GCS 和 BQ 数据存储系统。
数据存储位置
GCS 和 BQ 是存储任何与机器学习用例相关的数据集的两个推荐选项,旨在实现高安全性和效率。如果底层数据是有结构的或半结构的,由于 BQ 具有现成的功能来操作或处理结构化数据集,因此 BQ 是推荐选项。如果数据包含图像、视频、音频和非结构化数据,那么 GCS 是存储它的合适选项。让我们更详细地了解这两个数据存储系统。
GCS – 对象存储
我们从现实世界应用中收集的大量数据是无结构的。一些例子包括图像、视频、电子邮件、音频文件、网页和传感器数据。以经济高效的方式管理和存储如此大量的非结构化数据是一项相当具有挑战性的任务。如今,对象存储已成为存储如此大量静态数据和备份的首选解决方案。对象存储是一种计算机数据架构,旨在高效地处理大量结构化数据。在基于对象的存储系统中,每个数据对象都被视为一个独立的单元,包含元数据和唯一的标识符,这对于快速检索和定位数据非常有用。
GCS 是 Google Cloud 中的一个基于对象的存储系统。由于它是基于云的,GCS 数据可以全球访问并提供大规模存储。它是一个适合从小型企业到大型企业以经济高效且易于检索的方式存储大量数据的理想选择。对于您只需写入一次数据但需要非常频繁地读取数据的应用程序,对象存储效率更高。虽然它非常适合静态数据,但不是动态数据的良好解决方案。如果数据不断变化,我们不得不反复写入整个数据对象来修改它,这是低效的。
由于其多样化的好处,GCS 经常被 Google Cloud 上的机器学习从业者使用。以下是存储数据在如 GCS 这样的对象存储系统中的常见好处:
-
大规模可扩展性:通过简单地添加更多服务器或设备,对象存储可以无限扩展。
-
更简单:与文件存储系统不同,对象存储中没有层次结构或文件夹结构,因此检索相当简单。
-
可搜索性:由于元数据也是对象的一部分,因此很容易搜索特定对象。我们可以使用标签使对象更容易过滤。
-
容错性:由于它可以自动复制数据并在多个设备或地理位置之间存储,因此无需担心数据丢失。
-
低成本:对象存储经济高效,因此非常适合存储大量数据。其次,我们只为使用的容量付费。
虽然有这么多优点,但基于对象的存储系统也有一些局限性:
-
由于延迟问题,在设计 Web 应用程序时不能替代传统数据库
-
它们不适合数据快速变化且需要非常频繁地大量写入文件的情况
-
它们与操作系统挂载不太兼容,需要额外的客户端或适配器才能工作
现在我们对对象存储系统的优点和局限性有了相当的了解,我们将在未来的项目中根据相关需求利用它们。现在,让我们更多地了解 BQ。
BQ – 数据仓库
BQ 是 Google Cloud 上提供的一个全托管和无服务器的数据仓库。它是一个可扩展分析大型数据集的皮字节级平台。BQ 的无服务器架构支持 SQL 查询以切片和切块大型数据集。其分析引擎非常可扩展,支持分布式分析,这样我们可以在几秒钟内查询千兆字节的数据,在几分钟内查询皮字节的数据。BQ 还支持机器学习,这意味着我们只需使用几个类似 SQL 的命令即可在 BQ 中训练和测试常见的 ML 模型。我们将在接下来的章节中学习BigQuery 机器学习(BQML)。
在幕后,BQ 以优化的列式存储格式存储数据,该格式针对分析查询进行了优化。BQ 内的数据通过具有行和列的表以数据库的形式呈现。它提供了类似于事务型数据库管理系统的原子性、一致性、隔离性和持久性(ACID)属性的全支持。BQ 通过在 Google Cloud 的多个位置和区域自动复制数据,为数据提供高可用性。除了 BQ 存储内部的数据外,它还提供了从外部源查询数据的灵活性,包括 GCS、Bigtable、Google Sheets 和 Spanner。
如果机器学习用例涉及结构化或半结构化数据,BQ 可以是存储和分析的最佳选择。在随后的章节中,我们将了解 BQ 是数据分析师和机器学习实践者极其有用的工具。以下是使用 BQ 作为数据仓库解决方案的一些常见好处:
-
速度和规模:使用 BQ,对大规模数据集进行查询只需几秒钟。BQ 被设计成轻松分析和存储非常大的数据集。它可以从千兆字节无缝扩展到艾字节。
-
实时分析:BQ 支持流数据摄取,并使其立即可用于查询。它与 BI 工具 Looker Studio 的集成使其能够提供实时和交互式的分析能力。
-
机器学习:BQ 提供了使用简单的 SQL 在结构化和非结构化数据上构建和运行机器学习模型的能力,时间非常短。BQ 模型可以直接导出,以便在 Vertex AI 预测服务上提供服务。
-
安全性:BQ 提供强大的安全性和细粒度的治理控制。数据默认在静态和传输过程中加密。
-
多云支持:BQ 允许在多个云平台之间进行数据分析。BQ 可以在不将数据移动到其他位置的情况下对数据进行分析,这使得它更加经济高效且灵活。
我们现在对两个流行的数据存储系统——GCS 和 BQ——及其优缺点有了相当的了解。根据具体的使用场景,我们现在应该能够选择合适的存储位置来存放我们的机器学习数据集。接下来,我们将深入了解 Google Cloud 上的数据转换选项。
数据转换
在现实世界应用中存在的原始数据通常是未结构化和嘈杂的。因此,不能直接将其输入到机器学习算法中。我们通常需要对原始数据进行多次转换,并将其转换为机器学习算法广泛支持的格式。在本节中,我们将了解在 Google Cloud 上以可扩展和高效的方式转换数据的多种选项。
在 GCP 环境中,这里有三种常见的数据转换选项:
-
在 Jupyter Notebooks 内进行临时转换
-
Cloud Data Fusion
-
可扩展的数据转换数据流管道
让我们更详细地了解这三种方法。
在 Jupyter Notebook 中的临时转换
机器学习算法是数学的,只能理解数值数据。例如,在计算机视觉问题中,图像在输入模型之前被转换为数值像素值。同样,在音频数据的情况下,它通常使用不同的转换(如快速傅里叶变换(FFT))转换为时频域。如果数据以表格格式存在,并且包含行和列,那么一些列可能包含非数值或分类类型的数据。这些分类列首先使用合适的转换转换为数值形式,然后输入到机器学习模型或神经网络中。这些转换中的一些可以直接在 Jupyter 笔记本中使用 Python 功能应用。
在将数据读入 Jupyter Notebook 后,我们可以应用任何所需的转换,使数据集准备好进行建模。一旦数据集准备就绪,我们可以将其保存到某个位置(例如,BQ 或 GCS),并附上版本号,以便可以直接将其读入多个不同的模型训练实验中。机器学习从业者经常通过应用不同的转换或特征工程来创建和保存多个版本的训练数据集。这使得比较不同版本数据的实验性能变得更容易。让我们了解一下在机器学习项目中非常频繁应用的一些常见转换。
从高层次来看,数据可以分为以下两类:
-
数值数据:正如其名所示,这种数据是数值的或可量化的——例如,年龄、身高和体重
-
分类数据:这种数据是字符串格式或定性数据——例如,性别、语言和口音
现在,让我们了解可以应用于这两种类型数据列的一些常见转换。
处理数值数据
数值数据可以是离散的或连续的。离散数据是可以计数的,例如,一个篮球队中的球员数量或一个国家中的城市数量。离散数据只能取某些值,例如 10、22、35、41 等等。另一方面,任何可测量的数据都称为连续数据——例如,一个人的身高或两辆赛车之间的距离。连续数据几乎可以取任何值,例如 2.3、11、0.0001 等等。
对数值数据应用两种常见的转换:
-
归一化:这是为了将不同的数值列调整到相同的尺度。建议将数值数据列归一化到相同的尺度,因为它有助于基于梯度下降的机器学习算法的收敛。如果一个数据列具有非常大的值,那么归一化它可以防止在训练模型时出现NaN错误。
-
分桶:在这种类型的转换中,数值数据被转换为分类数据。分桶通常在连续数值数据上执行,当数值列和目标列之间没有线性关系时。例如,一家汽车制造公司观察到价格最低或最高的汽车销售频率较低,而价格中等的汽车销售频率较高。在这种情况下,如果我们想使用汽车价格作为特征来预测销售的汽车数量,将汽车价格分桶到价格范围将是有益的。这样,模型将能够识别出销售汽车数量最多的中档价格桶,并为此特征分配更多的权重。
处理分类数据
分类数据可以分为两类——有序和名义。有序分类数据与其相关联的某些顺序有关——例如,电影评分(最差、差、好、优秀)和反馈(负面、中性、正面)。有序数据总是可以标记在量表上。另一方面,名义数据没有顺序。名义数据的例子包括性别、国家和语言。
一些算法,如决策树,可以很好地处理分类数据,但大多数机器学习算法不能直接处理分类数据。这些算法需要将分类数据转换为数值形式。在将分类数据转换为数值形式时,机器学习从业者会面临一些挑战:
-
高基数:基数意味着数据中的唯一性。具有高基数的数据列可能有很多不同的值——例如,国家层面的 ZIP 代码。
-
稀疏或频繁出现:数据列可能有一些很少出现或一些非常频繁出现的值。在这两种情况下,由于非常高的或非常低的方差,这个列可能不足以对模型产生影响。
-
动态值:数据列会不时地改变一些值——例如,在市列中,如果新城市被频繁添加或删除。
克服这些挑战的最佳方式高度依赖于我们处理的问题或数据类型。现在,让我们了解一些将分类数据转换为数值形式的常见方法:
-
标签编码:在这种技术中,我们将分类数据替换为从 0 到N-1 的整数。在这里,每个整数代表一个具有N个唯一值的分类数据列中的值。例如,如果有一个表示颜色的分类数据列,并且可能有 10 种独特的颜色值,在这种情况下,每种颜色将被映射并替换为 0 到 9 范围内的一个整数。这种方法可能不是所有情况都理想,因为模型可能会将数值视为分配给数据的权重。因此,这种方法更适合有序分类数据。
-
1
如果该颜色在给定行中存在;否则,它将是0
。One-hot 编码通常用于对分类数据进行编码。 -
嵌入:由于 One-hot 编码为每个唯一值创建一个新列,当唯一值的数量很大时,这可能会创建一个非常稀疏的数据表示。例如,如果我们有一个包含 20k 个唯一 ZIP 代码的 ZIP 代码列,One-hot 编码方法将创建 20k 个新的二进制列。这种稀疏数据需要大量的内存来存储,并增加了机器学习训练的复杂性。为了处理和表示具有大量唯一值的此类分类数据列,可以使用密集嵌入。然而,这些嵌入通常使用神经网络生成,因此它是一种现成的编码技术。这些嵌入将分类列中的每个值编码为一个小型的密集实数向量。训练和生成这些嵌入的一个简单方法是用内置的 Keras 嵌入层。
现在我们已经对在 Jupyter 笔记本中使用 Python 容易应用的一些常见数据转换有了很好的理解,让我们了解一些在 GCP 上进行数据转换的更多可扩展方法,例如 Cloud Data Fusion 和 Dataflow。
Cloud Data Fusion
Cloud Data Fusion 是 GCP 上的一个完全托管服务,用于快速构建和管理可扩展的数据管道。使用 Data Fusion UI,我们可以构建和部署数据管道,而无需编写任何代码(使用可视化点选界面)。Data Fusion UI 允许我们以完全托管的方式构建可扩展的数据集成解决方案,以清理、准备、混合、转换和传输数据(这意味着我们不需要管理基础设施)。Cloud Data Fusion 为批处理和实时数据处理提供了数百个预构建的转换,并快速构建 ETL/ELT 管道。
Cloud Data Fusion 的一些关键特性如下:
-
可移植性:Cloud Data Fusion 是使用名为 CDAP 的开源项目构建的,从而确保数据管道的可移植性
-
简单集成:Cloud Data Fusion 与 Google Cloud 的功能(如 GCS、Dataproc 和 BigQuery)的简单集成使开发更快、更简单,并确保安全性
-
无代码管道:即使非技术用户也可以使用 Cloud Data Fusion 的 Web 界面快速构建数据管道
-
混合:由于 Cloud Data Fusion 是一个开源项目,它提供了在混合和多云环境中构建标准化数据管道的灵活性
-
安全性:Cloud Data Fusion 提供了企业级的安全性和访问管理,结合 Google Cloud 的数据保护和合规性。
除了 Web UI 之外,我们还可以使用命令行工具创建和管理 Cloud Data Fusion 实例和管道。接下来,让我们了解 GCP 上的另一个数据转换工具——Dataflow。
可扩展的数据转换的 Dataflow 管道
Dataflow 是一个托管服务,用于在 Google Cloud 上执行使用Apache Beam SDK开发的数据处理或转换管道。它支持快速、成本效益和无服务器(这意味着我们不需要管理基础设施)的统一批处理和流数据处理。由于 Dataflow 是无服务器的,它让我们能够专注于表达数据管道的业务逻辑(使用 SQL 或代码),而无需担心操作任务和基础设施管理。由于其流式特性,Dataflow 非常适合构建用于异常检测、模式识别和预测等用例的实时管道。
通过将 Dataflow 与其他管理的 Google Cloud 服务相结合,我们可以简化与自管理解决方案相比的生产化数据管道的许多方面。例如,它可以与 Google Cloud 提供的产品,如 Pub/Sub 和 BQ 结合,开发一个能够处理、分析和生成宝贵实时业务洞察的流式解决方案。由于它是管理的,它会自动配置和扩展所需资源,从而减少在流分析解决方案上工作的数据工程师或数据分析师的时间和复杂性。
Dataflow 的一些关键特性如下:
-
智能自动扩展:Dataflow 支持工作节点的水平和垂直扩展。扩展是自动执行的,以确保以高效(成本效益)或最佳匹配的方式满足工作节点和其他管道扩展需求。
-
实时管道:Dataflow 的流式特性在构建实时流分析、机器学习预测和异常检测管道时非常有用。它还适用于以最小延迟同步或复制跨多个数据源(如 BQ、PostgreSQL 或 Cloud Spanner)的数据。
-
Dataflow SQL:可以使用简单的 SQL 命令直接从 BQ 构建 Dataflow 流式管道。
-
灵活调度:需要调度的批处理作业(如夜间作业)可以轻松地使用 Dataflow 的灵活资源调度(FlexRS)在成本效益的环境中进行调度。
摘要
有效地管理数据对于每个组织节省时间、成本和复杂性至关重要。机器学习从业者应该了解传输、存储和转换数据以更有效地构建机器学习解决方案的最佳选项。在本章中,我们学习了将数据带入 Google Cloud 环境的多种方式。我们讨论了根据数据特性存储的最佳选项。最后,我们讨论了多种不同的工具和方法,以可扩展的方式转换/处理数据。
阅读本章后,你应该对根据用例需求选择最佳方案将数据移动或传输到你的 Google Cloud 环境中充满信心。选择最佳的数据存储位置以及最佳的数据分析和转换策略应该更容易,因为我们现在已经了解了不同选项的优缺点。在下一章中,我们将深入探讨Vertex AI Workbench,这是一个 Vertex AI 内部的托管笔记本平台。
第四章:Vertex AI Workbench – AI/ML 开发需求的一站式工具
机器学习(ML)项目在本质上很复杂,需要与普通软件应用完全不同的开发环境。当数据量巨大时,数据科学家可能需要使用几个大数据工具来快速处理或预处理数据,而一个深度学习(DL)模型可能需要几个 GPU 来进行快速训练和实验。此外,还需要专门的计算资源来托管生产环境中的模型,以及更多资源来将其扩展到企业级。获取这些资源和工具成本很高,即使我们设法购买并设置好,也需要大量的努力和技术知识才能将它们整合到项目流程中。即便如此,仍然存在停机时间和数据安全的风险。
现在,基于云的解决方案非常流行,并且为我们处理所有的技术难题、扩展性和安全性方面的问题。这些解决方案让机器学习开发者能够更多地专注于项目开发和实验,无需担心基础设施和其他底层问题。作为一家以人工智能(AI)为先导的公司,谷歌将所有用于机器学习项目开发的重要资源都整合在一个名为 Vertex AI 的统一框架下。在本章中,我们将学习关于 Vertex AI Workbench 的内容,这是一个针对 Jupyter Notebook 内核的托管解决方案,可以帮助我们更快地将机器学习项目从原型推向生产。
本章涵盖以下主题:
-
什么是 Jupyter Notebook?
-
Vertex AI Workbench
-
Vertex AI Workbench 的自定义容器
-
在 Vertex AI 中安排笔记本
什么是 Jupyter Notebook?
Jupyter Notebook 是一个开源的基于网络的程序,用于编写和分享实时代码、文档、可视化等内容。Jupyter Notebook 在机器学习从业者中非常受欢迎,因为它们提供了动态运行代码和协作的灵活性,提供了快速的可视化,还可以用于演示。大多数数据科学家和机器学习从业者更喜欢 Jupyter Notebook 作为他们探索、可视化和预处理数据的主要工具,这些数据科学家和从业者使用强大的 Python 库,如 pandas 和 NumPy。Jupyter Notebook 对于探索性数据分析(EDA)非常有用,因为它们允许我们动态地运行小的代码块,并快速绘制图表来理解数据统计。笔记本还可以用于进行快速的机器学习建模实验。关于 Jupyter Notebook 的另一个优点是,它允许我们编写 Markdown 单元格。使用 Markdown,我们可以解释笔记本中的每个代码块,并将其转变为教程。Jupyter Notebook 在机器学习社区中很受欢迎,用于在 GitHub 和 Kaggle 等平台上分享和协作项目。
开始使用 Jupyter Notebook
Jupyter Notebook 应用程序可以通过简单的pip
命令(如下所示)在本地系统中安装。对于快速实验,我们还可以利用基于 Web 的笔记本内核,如 Colab 和 Kaggle,那里一切都已经设置好,我们可以直接运行 Python 代码。由于这些内核是公开的,如果我们有保密数据,我们无法使用它们,我们不得不在我们的系统上安装 Jupyter Notebook 应用程序。
我们可以通过以下pip
命令在我们的本地系统上安装 Jupyter 应用程序:
$ pip install jupyter
应用程序安装完成后,可以通过在终端输入以下命令来启动,它将在浏览器标签页中自动打开 Jupyter 应用程序:
$ jupyter notebook
如果它没有自动打开浏览器标签页,我们可以通过输入以下 URL 来启动应用程序:localhost:8888/tree
。默认情况下,Jupyter 服务器在端口8888
上启动,但如果该端口不可用,它会找到下一个可用的端口。如果我们有兴趣使用自定义端口,我们可以通过传递自定义端口号来启动 Jupyter。
这里是启动 Jupyter 应用程序在自定义端口9999
的终端命令:
$ jupyter notebook --port 9999
注意
在某些情况下,当我们尝试手动点击上述 URL 时,Jupyter 服务器可能会要求我们提供一个令牌(可能是在非默认浏览器的情况下)。在这种情况下,我们可以从提供令牌的 URL 中复制 URL。或者,我们可以在终端中运行jupyter notebook list
命令来获取令牌。
一旦我们能够在浏览器中启动应用程序服务器,Jupyter 服务器看起来就像这样:
图 4.1 – Jupyter 应用程序服务器 UI
现在,我们可以通过点击新建按钮来启动一个 Jupyter Notebook 实例。它创建一个新的笔记本,并将其保存在我们从终端启动 Jupyter Notebook 的同一目录中。我们现在可以在新标签页中打开那个笔记本并开始运行脚本。以下截图显示了一个空白的笔记本:
图 4.2 – Jupyter Notebook 实例
如前一个截图所示,Web UI 提供了多种操作笔记本、代码、单元格、内核等选项。一个笔记本单元格可以执行代码,或者可以通过更改下拉菜单中的类型将其转换为 Markdown 单元格。还有将笔记本导出为不同格式(如 HTML、PDF、Markdown、LaTeX 等)的选项,以便创建报告或演示文稿。在本书的进一步内容中,我们将大量使用笔记本进行数据处理、建模等。
现在我们对 Jupyter Notebook 的一般概念有了基本的了解,让我们看看 Vertex AI Workbench 如何提供一个更丰富的基于 Jupyter Notebook 环境的体验。
Vertex AI Workbench
在进行 ML 项目工作时,如果我们在一个本地环境中运行 Jupyter Notebook,或者使用类似 Colab 或 Kaggle 的基于网络的内核,我们可以快速进行一些实验,并从 ML 算法中获得一些初始准确度或结果。但是,当我们进行大规模实验、启动长时间运行的任务、托管模型以及模型监控时,我们会遇到障碍。此外,如果与项目相关的数据需要在安全和隐私方面有更细粒度的权限(对谁可以查看/访问数据的精细控制),在本地或类似 Colab 的环境中是不切实际的。所有这些挑战只需迁移到云端就可以解决。Google Cloud 中的 Vertex AI 工作台是一个基于 JupyterLab 的环境,可以用于典型数据科学项目的所有开发需求。JupyterLab 环境与 Jupyter Notebook 环境非常相似,因此我们将在整本书中使用这些术语交替使用。
Vertex AI 工作台提供了创建 托管笔记本实例 以及 用户管理笔记本实例 的选项。用户管理笔记本实例赋予用户更多控制权,而托管笔记本则附带一些关键额外功能。我们将在本节后面进一步讨论这些功能。Vertex AI 工作台笔记本套件的一些关键特性包括以下内容:
-
完全托管-Vertex AI 工作台提供了一个基于 Jupyter Notebook 的完全托管环境,该环境提供企业级规模,无需管理基础设施、安全和用户管理功能。
-
交互式体验 - 由于托管笔记本可以轻松与其他 Google Cloud 服务(如存储系统、大数据解决方案等)交互,因此数据探索和模型实验变得更加容易。
-
从原型到生产 AI - Vertex AI 笔记本可以轻松与其他 Vertex AI 工具和 Google Cloud 服务交互,从而提供一个从开发到部署的端到端 ML 项目运行环境,转换过程最小化。
-
多内核支持 - 工作台在单个托管笔记本实例中提供多内核支持,包括 TensorFlow、PyTorch、Spark 和 R 等工具的内核。每个内核都预装了有用的 ML 库,并允许我们根据需要安装额外的库。
-
笔记本排程 - Vertex AI 工作台允许我们根据需要和定期排程笔记本运行。此功能在快速设置和运行大规模实验时非常有用。此功能通过托管笔记本实例提供。关于此功能的更多信息将在后续章节中提供。
在此背景下,我们现在可以开始在 Vertex AI 工作台上使用 Jupyter Notebook。下一节将提供有关在 Vertex AI 上开始使用笔记本的基本指南。
开始使用 Vertex AI 工作台
前往 Google Cloud 控制台,从左侧面板的产品菜单或使用顶部搜索栏打开 Vertex AI。在 Vertex AI 中,点击 Workbench,它将打开一个与 图 4.3* 非常相似的页面。更多相关信息可在官方文档中找到 (cloud.google.com/vertex-ai/docs/workbench/introduction
)。
图 4.3 – Google Cloud 控制台中 Vertex AI 工作台 UI
如我们所见,Vertex AI Workbench 主要是作为服务的 Jupyter Notebook,同时具有使用托管以及用户托管笔记本的灵活性。用户托管笔记本适用于需要相对更高控制度的定制化环境的使用场景。关于用户托管笔记本的另一件好事是我们可以根据我们的开发需求选择合适的 Docker 容器;这些笔记本还允许我们通过重启来更改实例的类型/大小。
要为特定项目选择最佳的 Jupyter Notebook 选项,了解两种解决方案之间的常见差异很重要。表 4.1 描述了完全托管和用户托管笔记本之间的某些常见差异:
Vertex AI 管理笔记本 | Vertex AI 用户管理笔记本 |
---|---|
提供集成和功能,为我们提供一个端到端基于笔记本的生产环境,无需手动设置任何内容。 | 高度可定制的虚拟机实例(带有预构建的深度学习镜像),非常适合需要大量控制环境的用户。 |
可以在笔记本内部进行横向和纵向扩展(对于 vCPU 和 RAM),无需重新启动环境。 | 改变实例的大小/内存需要在 Workbench UI 中停止实例,并每次重新启动它。 |
管理笔记本让我们能够在不离开 Jupyter 环境的情况下浏览来自 Google Cloud Storage (GCS) 和 BigQuery 的数据(带有 GCS 和 BigQuery 集成)。 | 在用户管理笔记本中不支持 UI 级别的数据浏览。然而,我们可以使用笔记本中的 Python 读取数据并查看它。 |
支持一次性和重复性计划的自动化笔记本运行。执行器运行计划任务并保存结果,即使实例处于关闭状态。 | 在用户管理环境中尚不支持自动化运行。 |
对网络和安全的控制较少。 | 可根据需要实施所需的网络和安全功能以及 VPC 服务控制。 |
在设置笔记本时对基于深度学习的环境控制不多。 | 用户托管实例在创建笔记本时提供多个深度学习虚拟机选项。 |
表 4.1 – 管理和用户管理笔记本实例之间的差异
让我们创建一个用户管理的笔记本来检查可用的选项:
图 4.4 – Jupyter Notebook 内核配置
如前一个屏幕截图所示,用户管理的笔记本实例提供了几个自定义图像选项供选择。除了支持 TensorFlow Enterprise、PyTorch、JAX 等工具之外,它还允许我们决定是否想要使用 GPU(当然,根据需要可以稍后更改)。这些自定义图像为所需的框架预装了所有有用的库,并提供在实例内安装任何第三方软件包的灵活性。
选择合适的镜像后,我们可以获得更多选项来自定义笔记本名称、笔记本区域、操作系统、环境、机器类型、加速器等(参见以下屏幕截图):
图 4.5 – 配置新的用户管理的 Jupyter Notebook
一旦我们点击 创建 按钮,创建笔记本实例可能需要几分钟。一旦准备好,我们可以使用 Workbench 内提供的链接在浏览器标签页中启动 Jupyter 实例(参见 图 4**.6)。我们还有在不用它时暂时停止笔记本的选项(以降低成本):
图 4.6 – 运行的 Jupyter Notebook 实例
这个 Jupyter 实例可以被所有有权访问 Workbench 的团队成员访问,这有助于与其他团队成员协作和分享进度。一旦我们点击 打开 JupyterLab,它将在新标签页中打开一个熟悉的 Jupyter 环境(参见 图 4**.7):
图 4.7 – Vertex AI Workbench 中的用户管理的 JupyterLab 实例
由 Google 管理的 JupyterLab 实例看起来也非常相似(参见 图 4**.8):
图 4.8 – Vertex AI Workbench 中的由 Google 管理的 JupyterLab 实例
现在我们可以通过浏览器访问笔记本实例,我们可以启动一个新的 Jupyter Notebook 或终端,开始项目。一旦为服务账户提供了足够的权限,我们就可以通过 SDK 从 Jupyter Notebook 本身访问许多有用的 Google Cloud 服务,如 BigQuery、GCS、Dataflow 等。这使得 Vertex AI Workbench 成为每个机器学习开发需求的终极工具。
注
当我们不再使用 Vertex AI Workbench 实例或计划长时间不使用时,我们应该停止这些实例。这将帮助我们避免因长时间不必要的运行而产生费用。
在接下来的部分,我们将学习如何使用定制容器创建笔记本以及如何使用 Vertex AI 工作台安排笔记本。
适用于 Vertex AI 工作台的定制容器
Vertex AI 工作台还提供了基于定制容器的笔记本实例创建的灵活性。基于定制容器的笔记本的主要优势是它允许我们根据我们的特定需求自定义笔记本环境。假设我们想要使用当前作为预定义内核不可用的新的 TensorFlow 版本(或任何其他库)。我们可以创建一个包含所需版本的定制 Docker 容器,并使用此容器启动一个 Workbench 实例。定制容器由托管和非托管笔记本都支持。
以下是如何使用定制容器启动用户管理的笔记本实例的步骤:
-
第一步是根据要求创建一个定制容器。大多数情况下,派生容器(基于现有深度学习容器镜像的容器)设置起来会很容易。请参阅以下示例 Dockerfile;在这里,我们首先拉取现有的 TensorFlow GPU 镜像,然后从源安装新的 TensorFlow 版本:
FROM gcr.io/deeplearning-platform-release/tf-gpu:latest RUN pip install -y tensorflow
-
接下来,构建并推送容器镜像到容器注册库,使其对Google Compute Engine(GCE)服务账户可访问。请参阅以下源代码以构建和推送容器镜像:
export PROJECT=$(gcloud config list project --format "value(core.project)") docker build . -f Dockerfile.example -t "gcr.io/${PROJECT}/tf-custom:latest" docker push "gcr.io/${PROJECT}/tf-custom:latest"
注意,服务账户应提供足够的权限来构建和推送镜像到容器注册库,并且相应的 API 应该被启用。
-
前往用户管理笔记本页面,点击新建笔记本按钮,然后选择自定义。提供笔记本名称并选择合适的区域和区域值。
-
在环境字段中,选择定制容器。
-
在Docker 容器镜像字段中,输入定制镜像的地址;在我们的例子中,它看起来像这样:
gcr.io/${PROJECT}/tf-custom:latest
-
进行剩余的适当选择并点击创建按钮。
现在我们已经准备就绪。在启动笔记本时,我们可以选择定制容器作为内核,并开始在定制环境中工作。
现在我们可以成功启动 Vertex AI 笔记本,并在需要时创建基于定制容器的环境。在下一节中,我们将学习如何在 Vertex AI 中安排笔记本运行。
在 Vertex AI 中安排笔记本
Jupyter Notebook 环境非常适合进行一些初步实验。但是,当涉及到启动长时间运行的任务、具有不同输入参数(如超参数调整任务)的多个训练试验或向训练任务添加加速器时,我们通常会将代码复制到 Python 文件中,并使用自定义 Docker 容器或托管管道(如 Vertex AI 管道)来启动实验。考虑到这种情况,为了最小化工作重复,Vertex AI 管理笔记本实例为我们提供了在临时或重复基础上安排笔记本的功能。此功能允许我们在 Vertex AI 上逐个执行安排好的笔记本单元格。它为我们提供了无缝扩展处理能力和选择适合任务的硬件的灵活性。此外,我们还可以传递不同的输入参数以进行实验。
配置笔记本执行
让我们尝试配置笔记本执行以检查它提供的各种选项。想象我们正在构建一个玩具应用,它接受两个参数–user_name
和 frequency
–当执行时,它会将 user_name
参数打印出与 frequency
参数相同次数。现在,让我们启动一个托管笔记本并创建我们的应用,如下所示:
图 4.9 – Jupyter Notebook 内的一个简单 Python 应用
接下来,将所有参数放入单个单元格中,然后点击右上角的齿轮形按钮。将此单元格标记为 parameters。请参阅以下截图:
图 4.10 – 在 Jupyter Notebook 单元格内标记参数
我们的玩具应用现在已准备就绪。一旦您从工具栏中点击 执行 按钮,它就会提供自定义机器类型、加速器、环境(可以是自定义 Docker 容器)和执行类型–单次或重复执行的选项。请参阅以下截图:
图 4.11 – 配置笔记本执行以用于 Python 应用
接下来,让我们通过点击 高级选项 来更改我们的单次执行参数。在这里,我们可以为参数名称和值提供键值对。请参阅以下截图:
图 4.12 – 为单次执行设置参数
最后,点击 提交 按钮。然后,它将显示以下对话框:
图 4.13 – 已安排的单次执行
现在我们已经在 Vertex AI 上成功安排了笔记本运行,并带有自定义参数。我们可以在 Vertex AI UI 的 执行 部分找到它:
图 4.14 – 检查已执行笔记本实例的 EXECUTIONS 部分
我们现在可以通过点击查看结果来检查结果。查看以下截图了解它是如何覆盖输入参数的:
图 4.15 – 检查执行结果
同样,我们可以在不将代码移出笔记本的情况下安排大型一次性或重复性实验,并利用云平台的可扩展性。
我们刚刚看到了在 Vertex AI Workbench 中配置和安排笔记本运行是多么容易。这种能力使我们能够在保持笔记本中的代码的同时进行无缝实验。这也有助于在开发环境中设置重复性作业。
摘要
在本章中,我们学习了 Vertex AI Workbench,这是一个在 Google Cloud 上启动 Jupyter Notebook 应用程序的托管平台。我们讨论了在云环境中有笔记本相比于本地环境的优势。在云中拥有 Jupyter Notebook 使其非常适合协作、扩展、增加安全性和启动长时间运行的任务。我们还讨论了 Vertex AI Workbench 的一些附加功能,这些功能在处理 ML 项目开发的不同方面时非常有用。
在阅读本章之后,我们应该能够成功部署、管理和使用 Vertex AI 平台上的 Jupyter Notebook 来满足我们的 ML 开发需求。由于我们理解了托管和用户托管笔记本实例之间的区别,我们应该能够为我们的开发需求选择最佳解决方案。我们还应该能够根据需要创建基于自定义 Docker 容器的笔记本。最重要的是,我们现在应该能够根据需求安排笔记本运行,以进行重复性以及一次性执行。笔记本调度对于并行启动具有不同输入参数的多个模型训练实验也非常有用。现在我们已经对 Vertex AI Workbench 有了良好的背景知识,这将使我们更容易跟随即将到来的章节中的代码示例。
第五章:无代码构建机器学习模型选项
近年来,机器学习领域经历了深刻的变革,摆脱了专家数据科学家和工程师的领域,赋予更广泛的受众以力量。无代码机器学习平台的兴起引领了一个新时代,不同技能和背景的个人可以借助人工智能的力量解决复杂挑战,而无需编写任何代码。这种机器学习的民主化不仅加速了开发过程,还为企业和个人 alike 开辟了无数机会。
在本章中,我们将深入探讨无代码机器学习的基础,揭示 Google Cloud Vertex AI 提供的卓越工具和服务。我们将探讨用户如何利用预构建的机器学习模型、AutoML 功能和可视化界面轻松构建复杂且高度精确的模型。从计算机视觉到自然语言处理和表格数据分析,Google Cloud Vertex AI 覆盖了广泛的用例,使人工智能应用开发对每个人来说都变得民主化。
本章我们将涵盖的关键主题包括以下内容:
-
什么是 AutoML?
-
什么是 Vertex AI AutoML?
-
使用 Vertex AI AutoML 创建和部署模型
-
从部署的 Vertex AI 模型获取预测
让我们先看看 Google Cloud 提供的不同解决方案,以促进无需代码的模型创建。
Google Cloud 中的机器学习建模选项
Google Cloud 在 Vertex AI 和更广泛的 Google Cloud Platform (GCP) 内提供多种解决方案,用于构建和消费机器学习模型。这些解决方案在所需的数据科学和编码技能方面差异很大,满足高级 ML 工程师、相对不太技术化的商业分析师以及介于这两者之间的人员。以下三个主要的 GCP 模型创建解决方案如下:
-
Big Query ML (BQML):这是 BigQuery 平台的一部分,只需了解 SQL,用户就可以训练和使用模型在结构化数据上生成预测。关于 BQML 的更多细节将在 第六章 中介绍,低代码构建机器学习模型。
-
Vertex AI AutoML:这允许用户在无需编码甚至 SQL 知识的情况下构建模型,并且主要基于 GUI。然而,如果需要,它有可编程访问的 API。
-
Vertex AI 定制训练:此选项为用户提供在模型训练和部署方面的完全灵活性,但也要求具备基本的编码能力。
下表显示了 Google Cloud 中创建机器学习模型的不同选项的比较:
BQML | Vertex AI AutoML | Vertex AI 定制 | |
---|---|---|---|
编码要求 | 非常低 | 无 | 高 |
需要的机器学习工程专业知识 | 低 | 低 | 中等到高,取决于模型类型 |
数据大小限制 | 是。适用标准 BigQuery 配额和限制。 | 是。数据集限制因所使用的数据集类型而异(请参阅 GCP 文档了解当前限制)。 | 对于未管理的数据集,GCP 不设置限制。 |
支持的模型类型 |
-
线性回归
-
逻辑回归
-
KMEANS
-
矩阵分解
-
主成分分析
-
自动编码器
-
自动 ML 分类器
-
自动 ML 回归器
-
提升树分类器
-
提升树回归器
-
随机森林分类器
-
随机森林回归器
-
DNN 分类器
-
DNN 回归器
-
DNN 线性组合分类器
-
DNN 线性组合回归器
-
ARIMA PLUS
-
ARIMA PLUS XREG
-
TENSORFLOW
-
TENSORFLOW LITE
-
ONNX
-
XGBOOST
| 图像:
-
分类
-
目标检测
文本:
-
分类
-
实体提取
-
情感分析
视频:
-
行为识别
-
分类
-
目标跟踪
表格:
-
回归
-
分类
-
时间序列预测
构建任何类型机器学习的完全灵活性 |
---|
模型开发速度 |
对模型生成的灵活性/控制 |
工具是否支持特征工程? |
表 5.1 – Google Cloud 中机器学习模型创建选项
如前表所示,Vertex AI AutoML 是作为 Google Cloud 的一部分提供的无代码模型创建选项的关键。当 AutoML 最初作为 GCP 的一部分推出时,它曾经是一个独立的产品。现在,它是 Vertex AI 平台整体的一部分,并且遗留的 AutoML 产品正在计划中,将逐步淘汰。现在,让我们了解什么是 AutoML 以及您如何使用 GCP 中可用的 AutoML 功能。
什么是 AutoML?
AutoML 指的是自动化构建机器学习模型的过程的方法,包括数据预处理、特征工程、模型选择、超参数调整和模型部署。AutoML 旨在使机器学习对非专业人士更加易于访问和高效,通过减少构建模型中涉及的手动工作,为专家节省时间和资源。市场上不同类型的 AutoML 产品提供不同级别的自动化。有些只是自动化了训练和超参数部分,而有些则通过自动化数据预处理和特征生成的步骤实现了端到端的自动化。
AutoML 工具允许用户指定他们的要求,例如准确性、可解释性或训练时间,然后根据这些标准自动选择和训练最佳模型。它可以用于各种类型的机器学习任务,包括在结构化和非结构化数据集上的分类、回归和时间序列预测。近年来,AutoML 技术得到了快速发展,现在能够以最小的人为干预处理许多复杂的机器学习用例。然而,您需要小心过度依赖 AutoML。它不是机器学习和数据科学深入理解的替代品,而是一种可以帮助使这些过程更高效和易于访问的工具。当由不了解机器学习基础的人使用时,AutoML 工具可能存在风险,因为它们可以生成看似高性能的模型,同时仍然存在数据泄露和过拟合等常见问题。因此,现在我们已经对 AutoML 的概念有了基本的了解,它是与模型开发相关的,让我们来看看 Vertex AI 中可用的 AutoML 功能。
Vertex AI AutoML
Google Cloud 中的 AutoML 工具比 Vertex AI 存在的时间要长得多,Vertex AI 的推出主要是为了统一 GCP 中存在的多数独立的机器学习产品。GCP AutoML 利用 NASNet 等模型,并不断从 Alphabet 团队其他部门(如 Google DeepMind)的 AI 研究中受益。以下列出了该主题的一些有趣论文:
-
可扩展图像识别的可迁移架构学习。
arxiv.org/pdf/1707.07012.pdf
-
图像分类器架构正则化进化搜索。
arxiv.org/pdf/1802.01548.pdf
-
大规模图像分类器进化。
arxiv.org/pdf/1703.01041.pdf
Vertex AI AutoML 支持的使用案例如下:
-
表格数据:
-
分类(本章节有介绍示例)
-
回归
-
时间序列预测
-
-
图像数据:
-
图像分类(例如,在第 第八章 中有介绍)
-
目标检测
-
-
自然语言:
-
文本分类
-
实体提取
-
情感分析
-
如何使用表格数据创建 Vertex AI AutoML 模型
在以下使用案例中,我们将向您展示如何使用包含酒店预订数据的公共数据集构建分类模型的步骤。该模型的目标将是预测特定酒店预订被客户取消的概率,帮助酒店更好地规划未来客房的入住情况,并在他们预计有大量取消的日期可能允许超预订:
-
您可以在此处访问酒店预订数据集:
www.kaggle.com/datasets/jessemostipak/hotel-booking-demand
-
您可以从本书附带的 GitHub 仓库下载数据:
github.com/PacktPublishing/The-Definitive-Guide-to-Google-Vertex-AI
将数据导入到 Vertex AI AutoML 中使用
在计划使用 Vertex AI AutoML 功能时,第一步是导入您打算用于训练的 Vertex AI 数据集:
- 在 Google Cloud 控制台中导航到 Vertex AI | 数据集,然后点击 创建 以开始创建新的 Vertex AI 数据集。
图 5.1 – 创建 Vertex AI 数据集
- 输入数据集的名称,选择 表格 作为数据类型,选择 回归/分类,然后点击 创建。
图 5.2 – 选择数据集类型和模型目标
- 上传您之前从 GitHub 仓库下载的名为
hotel_reservation_data.csv
的文件。
![img/B17792_05_3.jpg]
图 5.3 – 指定数据源
- 输入您希望存储导入文件的 GCS 位置的路径。如果您之前还没有创建 GCS 存储桶,请点击
us-central1
。对于所有其他提示,您可以选择默认选项(图 5.4.4*)。
注意
在 GCP 上创建的资源位置一致性很重要,因此在这本书中,我们将尽量使用 us-central1
作为位置。
图 5.4 – 选择云存储位置
- 接下来,在您希望存储导入文件的存储桶中创建一个文件夹。点击右上角的 Folder+ 符号,然后为文件夹提供一个名称。然后,点击 创建。最后,突出显示刚刚创建的文件夹并点击 选择。
图 5.5 – 创建存储数据集的文件夹
-
一旦选择了存储桶和文件夹路径,请点击屏幕底部的 继续,这将开始将 CSV 文件导入到 Vertex AI 数据集中。
-
数据导入完成后,您将被带到
hotel_cancellation_prediction
或 <您为数据集指定的名称> 路径。在这里,所有特征统计信息都将为空。要生成这些统计信息,您可以点击 生成统计信息,这将启动分析特征数据并计算详细统计信息的过程。
![img/B17792_05_6.jpg]
图 5.6 – 为数据集生成统计信息
-
此过程完成后,您可以通过点击特定的特征来查看更多详细信息,例如以下内容:
-
独特值计数
-
字段中数据缺失的百分比
-
特征值分布
-
图 5.7 – 分析数据集的关键统计数据
上述截图显示了解释特征/字段“market_segment
”分布的图表。
现在,让我们看看如何使用上面讨论的数据集来训练一个 AutoML 分类 模型。
训练用于表格/结构化数据的 AutoML 模型
现在,让我们看看如何使用 Vertex AI AutoML 在表格数据上训练机器学习模型:
- 在您想要用于训练模型的数据集的 ANALYZE 选项卡中,点击 TRAIN NEW MODEL | 其他。
图 5.8 – 训练新模型
- 由于我们正在尝试根据预订的取消可能性对预订进行分类,因此选择模型目标为 分类。选择 AutoML 作为训练方法,它使用无代码的自动化训练选项。然后,点击 继续。
图 5.9 – 指定模型类型
-
在接下来的
is_canceled
。 -
如果您希望将 测试 结果导出到 BigQuery 以进行进一步分析,请选择 导出测试数据集到 BigQuery 选项,并提供一个 BigQuery 表路径,以便存储这些结果。Vertex AI 将在训练运行后创建该表。
-
如果您希望 Vertex AI 随机将数据分割成 训练、验证 和 测试 数据集,请保留默认选项 随机。如果您想要控制样本分配到 训练、验证 和 测试 数据集,请选择 手动 选项。在这种情况下,您需要提供一个列,其中提供 训练/验证/测试 分配。
图 5.10 – 配置模型训练选项
-
在接下来的
reservation_status
-
reservation_status_date
图 5.11 – 选择要删除的特征
此外,请确保 Vertex AI 默认为每个字段正确设置了转换类型。为了用于模型训练,表格数据必须经过针对每个数据特征的特定转换过程。这个过程表明了特定数据特征的功能。支持的转换类型如下:
-
分类: 当在 Vertex AI 中使用分类特征训练模型时,该特征会经过数据转换,有助于模型训练过程。Vertex AI 对该特征应用以下转换,并使用任何提供有用信息的转换:
-
分类字符串保持不变,没有对大小写、标点、拼写、时态和其他属性进行修改。
-
类别名称被转换为字典查找索引,并为每个索引生成一个嵌入。
-
在训练数据集中出现次数少于五次的类别被认为是未知类别。未知类别被分配一个唯一的查找索引,并为该类别生成嵌入。
-
-
文本:经过文本转换的特征被视为自由文本,通常由文本标记组成。文本被分词成单词,并从这些单词中生成 1-gram 和 2-gram。然后,每个n-gram 被转换为字典查找索引,并为每个索引生成嵌入。最后,使用平均值将所有元素的嵌入组合成一个单一的嵌入。
-
float32
类型的数据不包括在训练和预测过程中。 -
值被转换为
float32
。 -
计算值的z-分数。
-
值基于分位数进行分桶,桶大小为 100。
-
当值大于或等于 0 时,计算(
value+1
)的对数。如果值小于 0,则不应用此转换,该值被视为缺失值。 -
当值大于或等于 0 时,计算(
value+1
)的对数的z-分数。如果值小于 0,则不应用此转换,该值被视为缺失值。 -
被分配一个布尔值来指示该值是否为
null
。 -
时间戳:以下数据转换应用于特征,任何提供有用信息的都会用于训练:
-
确定时间戳的年、月、日和星期几,并将它们视为分类列
-
无效的数值,例如超出典型时间戳范围或极端值,不会被移除或特殊处理
-
对数值列的转换应用于特征
-
包含无效时间戳输入的行,例如无效的时间戳字符串,不包括在训练和预测过程中
-
-
如果您想向模型提供额外的权重以重新平衡数据集,您可以提供一个包含分配给每个数据样本的权重的额外列。
-
如以下截图所示,默认情况下,优化目标是设置为最大化 AUC ROC 曲线。
图 5.12 – 选择优化目标
虽然不是必需的,但您有选项更改优化目标。
对于分类问题,有五种不同的目标:
-
AUC ROC:在 AutoML 中,此目标最大化接收者操作特征曲线下的面积。这是二分类的默认选择,也可以选择以区分类别。
-
对数损失:此目标旨在最小化模型的对数损失。当目标是尽可能准确地预测概率时使用,并且是 AutoML 中多类分类模型唯一支持的目标。
-
AUC PR:此目标旨在最大化精度-召回曲线下的面积。它优化了对较少见类别的预测结果。
-
在特定召回率下的精度:此目标旨在在特定召回率值下最大化精度。
-
在特定精度下的召回率:此目标旨在在特定精度值下最大化召回率。
对于回归问题,有三个不同的目标:
-
RMSE:此目标旨在最小化均方根误差。它能够更准确地捕捉极端值。
-
MAE:此目标旨在最小化平均绝对误差。它将极端值视为对模型影响较小的异常值。
-
RMSLE:此目标旨在最小化均方根对数误差。它对相对大小而不是绝对值的误差进行惩罚,并且在预测值和实际值都相当大时特别有用。
- 提供您希望训练运行的最大时间。最小需要为一小时。在第一次运行期间,很难知道模型需要多长时间才能达到最高可能的准确度,并且您可能需要对新数据集和模型类型进行一些实验设置。
最佳实践
对于大多数小型数据集(< 1 百万个数据样本和< 20 个特征),两到四小时是一个良好的起点。如果启用早期停止选项开启,无论您为训练预留了多少小时,一旦 AutoML 确定进一步训练的轮次无法在模型目标上实现进一步改进,训练将停止。
- 最后,如图下截图所示,点击开始训练以启动训练过程。几小时后,您将有一个崭新的模型可供评估。
图 5.13 – 开始模型训练
一旦模型训练完成,让我们看看您如何评估 AutoML 创建的模型。
评估训练后的模型
每次训练机器学习模型时,评估其性能以确定其是否适用于现实世界应用至关重要。模型评估指标是基于模型对在训练期间未使用的部分数据集(称为测试数据集)的性能计算的。这种评估提供了模型如何泛化到新、未见数据的信息,并有助于识别任何问题或改进领域:
- 前往 Vertex AI 中的模型注册,如图下截图所示,找到您刚刚训练的模型。点击该模型,然后在下一屏幕上,点击您刚刚训练的模型版本。
图 5.14 – 模型注册
- 在评估选项卡上,您将看到 AutoML 使用在训练期间提供的测试数据集生成的测试结果详情。
图 5.15 – 模型评估指标
这里是根据模型类型在 Vertex AI 评估标签页中通常显示的关键信息:
-
置信度阈值:当与分类模型一起工作时,预测会被赋予一个置信度分数来表示预测类别正确的确定性水平。这个分数是一个数值评估,决定了模型对预测准确性的确信程度。例如,考虑一个预测客户是否会取消酒店预订的机器学习模型:
- 为了将分数转换为二元决策,使用了一个分数阈值。分数阈值是模型说“是的,置信度分数足够高,可以得出结论,客户将取消他们的预订”或“不,置信度分数不足以预测客户将取消预订”的值。分数阈值应根据特定用例确定,低分数阈值会增加误分类的风险。
-
精确度和召回率:在分类模型中,精确度和召回率是评估和总结模型如何捕捉信息以及避免错误的重要指标:
-
精确度:精确度回答了问题,“在所有预测的酒店预订取消中,实际取消了多少?”它衡量模型正预测的准确性——即所有预测正例中真实正例的百分比。
-
召回率:召回率回答了问题,“在所有取消的酒店预订中,模型正确预测了多少?”它衡量模型识别真实正例的能力——即所有实际正例中真实正例的百分比。
-
根据具体用例,你可能需要优化精确度或召回率。例如,如果你想最小化错误负例的数量(即被取消但模型未识别的酒店预订),那么你应该追求高召回率。如果你想减少错误正例的数量(即未被取消但被预测为取消的酒店预订),那么你应该追求高精确度。
除了精确度和召回率之外,还有其他几个分类指标可以用来评估机器学习模型的性能。以下是一些最常用的指标:
-
AUC PR:PR 曲线下的面积衡量了在不同分数阈值下精确度和召回率之间的权衡。AUC PR 的范围从零到一,其中更高的值表示质量更高的模型。
-
AUC ROC:ROC 曲线下的面积衡量了模型在所有可能的分数阈值下的性能。AUC ROC 的范围从零到一,其中更高的值表示质量更高的模型。
-
准确率:模型产生的分类预测中正确的比例。这是一个简单直观的指标,提供了对模型性能的整体衡量。
-
对数损失:对数损失,也称为交叉熵,是评估模型预测与实际目标值之间一致性的关键指标。该指标通过衡量模型的预测与实际世界结果之间的接近程度来量化模型性能的有效性。该指标的范围从零到无穷大,较低的日志损失表示质量更高的模型,展示了其做出更准确和自信预测的能力。
-
F1 分数:在寻求精确度和召回率之间的平衡,尤其是在类别分布不平衡的场景中,F1 分数成为一个有价值的指标。这个分数代表精确度和召回率的调和平均值,其范围从零到一。更高的 F1 分数表示质量更高的模型,表明它在具有挑战性的类别分布场景中能够有效地实现精确度和召回率。
通过使用这些指标,您可以更全面地了解模型的表现,并做出更明智的决策来改进它。
评估标签页还展示了两个额外的有用信息:
- 混淆矩阵:混淆矩阵是一种可视化工具,它显示了模型正确预测结果的频率,以及当模型错误预测结果时,矩阵显示了模型预测的内容。混淆矩阵是一种有助于理解模型可能在哪些方面“混淆”两个结果,以及诊断模型准确性和性能的有用方法。
图 5.16 – 混淆矩阵
- 特征重要性:模型特征重要性以每个特征的百分比表示,百分比越高表示对模型训练的影响越强。通过查看特征重要性值,我们可以更好地理解模型中不同特征的相对重要性以及它们如何有助于预测的准确性。以下截图显示了我们所训练的模型的特征重要性图。
图 5.17 – 特征重要性
因此,我们已经训练了一个模型并评估了其关键性能指标。现在,让我们看看如何部署它以及如何使用它来生成预测。
使用最近训练的模型生成预测
一旦 AutoML 模型训练完成,您可以使用以下两种方法之一生成预测:
-
批量预测:如名称所示,批量预测是为一批输入生成的异步预测。当不需要实时响应且您想提交单个请求处理多个数据实例时,会使用此功能。在 Vertex AI 中,可以直接向 Vertex AI 模型注册表中的模型提交批量预测请求,而无需将其部署到端点。
-
在线预测:如果您需要实时推理 – 例如,在响应应用程序输入时 – 您需要使用 Vertex AI 在线预测选项。要使用在线预测,您必须首先将模型部署到端点。此步骤配置基础设施资源,并使用指定的模型部署预测服务机制,使其能够以低延迟提供预测。部署模型的步骤将在下一节中展示。
重要提示
在 Vertex AI 端点上部署的模型将持续产生费用,无论其使用情况如何。这可能会根据底层 VM 类型快速增加,尤其是如果您正在使用 GPU。
在下一节中,我们将部署我们在 Vertex AI 上训练的 ML 模型以生成在线预测。
在 Vertex AI 中部署模型
现在,让我们带您了解在 Vertex AI 上部署训练模型以启用实时预测的步骤:
- 前往 模型注册表,点击模型,然后点击您想要部署的模型版本,在 部署 & 测试 选项卡上,点击 部署 到端点。
图 5.18 – 启动模型部署
- 输入要创建的 API 端点的期望名称,然后点击 继续。
-
您可以保留所有默认选项不变以进行快速测试部署,但这些都是您需要了解的设置:
-
流量分配:如果同一 API 端点部署了多个模型版本,此选项允许用户定义分配给特定版本的流量百分比。例如,在部署新模型时,您可能只想将 2% 的整体传入数据路由到新模型以进行测试,同时继续将剩余的 98% 数据发送到现有模型的版本。在将模型部署到新端点时,您需要将此值保留为 100%,因为没有其他模型来分担工作负载。
-
最小计算节点数:这是始终可用的最小计算节点数,用于处理推理请求。即使没有正在处理的请求,这些节点也将持续部署并产生费用。
-
最大计算节点数:在自动扩展过程中,随着 incoming 请求数量的增加,Vertex AI 将自动增加已部署节点的数量,直到达到这个数量。
-
机器类型:这涉及到支持在线推理的节点配置,包括 CPU 和内存。
-
可解释性选项:如果你希望每次推理都生成特征重要性值,请选择此选项。
-
在做出所需更改后,点击继续。
-
图 5.20 – 指定模型部署配置
- 在模型监控页面上,暂时关闭监控。我们将在*第十一章,Vertex AI 的 MLOps 治理中详细讲解模型监控。点击部署**。这将启动新端点的端点创建过程,然后是模型部署过程。
模型部署完成后,我们可以使用模型生成以下所示的实时预测。
生成预测
模型部署完成后,你将在部署 & 测试标签页中看到列出的端点。下面将有一个测试你的模型表格,列出生成预测所需的所有特征值。字段将基于用于 AutoML 训练的数据自动填充起始值,但你可以输入不同的值并点击预测来生成预测。
图 5.21 – 测试已部署的模型
一旦模型处理完提供的特征值,它将返回与每个标签相关的置信度分数。置信度分数最高的就是预测的标签。
图 5.22 – 预测结果
现在让我们看看开发者可以使用 Vertex AI 模型进行编程的选项。
以编程方式生成预测
要访问 Vertex AI 预测服务,你可以使用 Python 的 Vertex AI SDK,或者 Python、Java 和 Node.js 的可用客户端库。查看cloud.google.com/vertex-ai/docs/start/client-libraries
中的安装 Vertex AI 客户端库,了解如何安装 Java 或 Node.js 的客户端库。你可以在github.com/GoogleCloudPlatform/vertex-ai-samples
找到大量 Vertex AI 样本笔记本,包括社区生成和由 Google Cloud 团队发布的。
如果你的首选编程语言没有客户端库,你可以使用 Vertex AI REST API。
使用 REST API 提交预测请求
尽管 Vertex AI 中的部署与测试标签使通过少量样本测试模型变得容易,但在大多数典型用例中,模型的 API 端点将通过将输入样本发送到 API 并从其接收 JSON 响应来程序化访问。Vertex AI 通过生成示例代码来简化开始过程,如下面的截图所示。
图 5.23 – 一个样本 REST 请求
我们将使用 GCP 的本地 Cloud Shell 向 Vertex AI 中部署的模型提交一个样本预测请求。第一步是打开云壳,如下面的截图所示。
图 5.24 – 打开云壳
一旦 Cloud Shell 打开,将包含输入数据样本的 JSON 文件上传到 Cloud Shell 环境。我们将作为对 API 的请求的一部分提交此 JSON 有效负载。
图 5.25 – 上传 JSON 有效负载
在 Cloud Shell 中,复制并粘贴以下行以设置环境变量,在替换endpoint_id
、project_id
以及您上传的输入 JSON 文件的路径后。
注意,您需要替换endpoint-id
、project-id
以及您刚刚从各自的 GCP 环境中上传的 JSON 文件的本地路径:
ENDPOINT_ID="<your-endpoint-id"
PROJECT_ID="<your-project-id>"
INPUT_DATA_FILE="<path-to-input-json-file.json>"
现在,在 Cloud Shell 中运行以下命令(您可以从我们之前讨论的示例请求屏幕中复制并粘贴该命令):
curl \
-X POST \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
https://us-central1-aiplatform.googleapis.com/v1/projects/${PROJECT_ID}/locations/us-central1/endpoints/${ENDPOINT_ID}:predict \
-d "@${INPUT_DATA_FILE}"
一旦预测请求发送到 Vertex AI,它将通过端点托管的数据模型运行数据,如果一切顺利,您将收到 API 的 JSON 响应。
这是从 Vertex AI 端点收到的响应:
"predictions": [
{"scores": [
0.89472222328186035,
0.1052777245640755],
"classes": ["0","1"]},
{"classes": ["0","1"],
"scores": [
0.88255965709686279,
0.117440328001976]}],
"deployedModelId": "3558930023110934528",
"model": "projects/217932574390/locations/us-central1/models/6845069012347387904",
"modelDisplayName": "hotel_cancellation_prediction,"
"modelVersionId": "1"}
响应包含三个主要部分 – predictions
、deployedModelId
和model
。
predictions
部分包含模型实际做出的预测。在这种情况下,因为我们提交了两个样本进行预测,所以做出了两个预测,每个预测都有一个分数集和预测类别。分数代表模型对每个类别的信心,而类别代表模型对每个预测预测的标签或类别。
-
第一次预测的得分为类别
"0"
的 0.8947 和类别"1"
的 0.1053,这表明模型高度确信第一次预测属于类别"0"
。 -
第二次预测的得分为类别
"0"
的 0.8826 和类别"1"
的 0.1174,这也表明模型确信第二次预测属于类别"0"
,但比第一次预测的确定性要低。
deployedModelId
是已部署模型的唯一标识符。这对于跟踪在不同时间或不同位置部署的同一模型的多个版本非常有用。
模型
部分提供了有关用于做出预测的模型的信息。它包括模型的 ID、位置和显示名称,以及用于这些预测的模型版本(在本例中为版本 1)。这些信息有助于调试和排除模型或其预测中存在的问题。
在前面的端到端示例中,我们向您展示了如何构建用于表格/结构化数据的 AutoML 分类模型。在随后的章节中,我们还将提供如何使用图像数据构建 AutoML Vision 模型(第十六章)和文本数据构建 AutoML NLP 模型(第十七章)的示例。
摘要
在本章中,我们讨论了无代码平台在民主化人工智能和机器学习方面的变革性影响,使得没有专业编码知识的个人也能开发复杂的模型。您还了解了通过 Google Cloud 的 Vertex AI 工具集可用的无代码机器学习选项,以及我们探讨了使用 AutoML 模型构建、评估、部署和生成预测的步骤。本章为对利用 Google Cloud 的机器学习能力感兴趣但不想编写代码的用户提供了实用指南。
在下一章中,我们将探讨一些低代码选项来构建机器学习模型。虽然与本书中讨论的无代码选项相比,这需要一些额外的技术技能,但它也会让您对模型构建有更多的精细控制。
第六章:构建 ML 模型的低代码选项
BigQuery 机器学习,通常简称为 BQML,是 Google Cloud 提供的工具之一,它无缝地将数据仓库和 ML 世界融合在一起。设计用于弥合数据分析师和 ML 模型之间的差距,BQML 使个人能够在 BigQuery 的范围内直接构建、评估和预测 ML 模型,无需移动数据或掌握新的工具集。
这种集成不仅简化了模型创建的过程,还为熟悉 SQL 的人提供了一个直观的过渡。只需几个语句,您就可以从数据分析过渡到预测洞察。
在本章中,我们将讨论以下主题:
-
什么是 BQML?
-
使用 BQML 进行特征转换
-
使用 BQML 构建 ML 模型
-
使用 BQML 进行推理
什么是 BQML?
BQML 是 Google Cloud 提供的强大内置 ML 服务,允许用户使用熟悉的 SQL 查询创建、训练和部署 ML 模型。BQML 设计用于简化那些可能没有强大数据科学或编程背景的人构建和部署 ML 模型的过程。在本章中,我们将探讨 BQML 的关键特性和功能,以及您如何使用它来利用 Google Cloud AI 的力量为您的项目服务。
BQML 提供了一种无缝的方式将机器学习(ML)集成到您的数据分析工作流程中,无需深入了解 ML 概念或编程语言。使用 BQML,您可以做到以下几点:
-
使用 SQL 查询创建和训练 ML 模型
-
使用训练模型进行预测
-
评估您模型的性能
-
执行特征转换和超参数调整
-
理解模型解释和权重
-
导出和导入模型
利用 BQML 提供了许多优势:
-
BQML 消除了将数据加载到本地内存中的需求,从而解决了大型数据集带来的约束
-
BQML 通过处理标准任务,如将数据分为训练集和测试集、选择和调整学习率以及选择优化方法来简化 ML 流程
-
BQML 模型的自动版本控制使得跟踪变更并在需要时回滚到早期版本变得轻而易举
-
在提供预测时,BQML 模型可以无缝集成到 Vertex AI
使用 BQML 也有一些限制:
-
模型类型有限:BQML 支持一组受限的 ML 模型,如线性回归、逻辑回归、k-means 聚类、矩阵分解等。它可能无法满足需要高级或专用模型的项目需求。
-
可定制性:BQML 对 ML 的自动化方法意味着可定制的范围有限。用户可能无法像在其他 ML 框架中那样微调模型或尝试不同的模型架构。
-
可扩展性:尽管 BQML 设计用于处理大型数据集,但在处理极大数据集或复杂模型时,它可能不如其他分布式机器学习框架那样有效地扩展。
-
ML.PREDICT
函数根据图像进行预测。BQML 现在也支持将 远程模型 作为 API 端点添加,这为添加托管在 Vertex AI 端点上的任何模型或添加其他基于云的机器学习服务(如 Vision API)以支持更多用例打开了可能性。 -
特征工程:BQML 可能不是进行广泛特征工程的最佳选择,因为它更侧重于简化机器学习过程。用户可能需要在 BQML 之外执行特征工程以进行高级特征工程任务。我们将在本章的 特征工程 部分更详细地讨论这些限制。
-
外部数据源:BQML 主要与 Google BigQuery 数据一起工作,这限制了其在数据源方面的灵活性。如果您想使用来自不同来源或格式的数据,您可能需要首先将其导入到 BigQuery 中。
-
模型可移植性:BQML 模型与 Google Cloud 紧密集成。将模型导出以在 Google 生态系统之外使用可能具有挑战性,可能需要额外的工作。
现在,让我们看看您如何开始使用 BigQuery 解决机器学习问题。
开始使用 BigQuery
Google BigQuery 是一个无服务器、完全管理的数据仓库,它利用 Google 基础设施的强大处理能力进行超快的 SQL 查询。由于 BigQuery 不是 Vertex AI 的一部分,我们不会在本书中深入探讨该工具的功能,但这里有一个快速指南,介绍如何开始使用 BigQuery:这将提供足够的信息,帮助您跟随本章后面的练习。
-
设置 Google Cloud 项目:在您可以使用 BigQuery 之前,您需要设置一个 Google Cloud Platform(GCP)项目。前往 Google Cloud 控制台并创建一个新的项目。如果您之前从未使用过 GCP,您可能需要创建一个账户并设置账单信息。
-
启用 BigQuery API:在您的 GCP 项目中,导航到 API & Services 部分,并启用 BigQuery API。
-
访问 BigQuery 控制台:一旦启用 API,您可以通过 GCP 仪表板或直接通过 BigQuery 控制台链接(
console.cloud.google.com/bigquery
)访问 BigQuery 控制台。 -
创建数据集:数据集是 BigQuery 中表、视图和其他数据对象的容器。要创建一个数据集,请点击 BigQuery 控制台中您 GCP 项目名称旁边的垂直省略号,选择 创建数据集,并填写数据集的名称。然后,点击 创建数据集。
-
加载数据:BigQuery 支持多种数据格式,包括 CSV、JSON 等。你可以从 Google Cloud Storage 将数据加载到 BigQuery 中,通过 API 请求直接发送数据,或手动上传文件。要加载数据,请导航到左侧的 BigQuery 控制台中的数据集,点击 创建表,然后按照提示操作。
-
运行 SQL 查询:将数据加载到 BigQuery 后,你可以运行 SQL 查询。使用 BigQuery 控制台中的查询编辑器开始使用 SQL 分析你的数据。
现在,让我们看看如何使用 BigQuery 的原生函数进行大规模特征/数据转换,为机器学习模型准备训练数据。
使用 BQML 进行特征转换
BQML 支持两种类型的特征预处理:
-
自动预处理:在训练过程中,BQML 会执行自动预处理。有关更详细的信息,请执行自动预处理,如缺失数据插补、独热编码和时间戳转换与编码。
-
BQML 提供的
TRANSFORM
子句用于定义使用手动预处理函数的定制预处理。这些函数也可以在TRANSFORM
子句之外使用。
虽然 BQML 支持一些特征工程任务,但与更灵活且功能丰富的机器学习框架相比,它存在某些限制:
-
有限的预处理函数:BQML 提供了一组基本的 SQL 函数用于数据预处理,例如缩放和编码。然而,它可能缺乏其他机器学习库(如 scikit-learn 或 TensorFlow)中可用的某些高级预处理技术或专用函数。
-
无自动特征选择:BQML 不提供自动特征选择方法来识别数据集中最重要的变量。你必须根据你的领域知识和直觉手动选择和构建特征,或者使用外部工具进行特征选择。
-
复杂特征转换:基于 SQL 的 BQML 方法可能不适合某些涉及非线性组合、滚动窗口或数据中的序列模式等复杂特征转换。在这种情况下,你可能需要在使用 BQML 之前使用其他工具或编程语言对数据进行预处理。
-
自定义特征生成:BQML 缺乏创建自定义特征的灵活性,例如像更通用的机器学习库那样轻松创建特定领域的函数或转换。你可能需要在外部实现这些自定义特征,这可能会很繁琐且效率较低。
-
特征工程管道:BQML 不提供内置机制来创建和管理可重用的特征工程管道。相比之下,其他机器学习框架提供了构建模块化和可维护管道的功能,简化了将相同的转换应用于训练和验证数据集或在模型部署期间的过程。
虽然 BQML 简化了机器学习过程,但它可能不是需要大量或高级特征工程的项目最佳选择。在这种情况下,您可能需要使用外部工具或库预处理您的数据,然后将转换后的数据导入 BigQuery,以便使用 BQML 进行进一步分析。
手动预处理
BQML 提供了一系列手动预处理函数,可以使用 CREATE MODEL
语法在训练前预处理您的数据。这些函数也可以在 TRANSFORM
子句之外使用。这些预处理函数可以是标量,对单行进行操作,或者分析型,对所有行进行操作,并基于所有行收集的统计信息输出结果。当在训练期间 TRANSFORM
子句中使用 ML 分析函数时,相同的统计信息会自动应用于预测输入。
以下表格列出了 BigQuery 中所有支持的数据预处理函数:
函数名称 | 描述 |
---|---|
ML.BUCKETIZE |
根据提供的分割点将数值表达式分桶到用户定义的类别。 |
ML.POLYNOMIAL_EXPAND |
生成给定数值特征的指定度数的多项式组合。 |
ML.FEATURE_CROSS |
生成指定度数的分类特征的交叉特征。 |
ML.NGRAMS |
根据给定的 n 值范围从标记数组中提取 n-gram。 |
ML.QUANTILE_BUCKETIZE |
根据几个桶将数值表达式分桶到基于分位数的类别。 |
ML.HASH_BUCKETIZE |
将字符串表达式分桶到基于哈希的固定数量桶。 |
ML.MIN_MAX_SCALER |
将数值表达式缩放到范围 [0, 1],并在所有行中使用 MIN 和 MAX 进行限制。 |
ML.STANDARD_SCALER |
标准化数值表达式。 |
ML.MAX_ABS_SCALER |
通过除以最大绝对值将数值表达式缩放到范围 [-1, 1]。 |
ML.ROBUST_SCALER |
使用对异常值具有鲁棒性的统计方法缩放数值表达式。 |
ML.NORMALIZER |
使用给定的 p-范数将数组表达式归一化到单位范数。 |
ML.IMPUTER |
使用指定的值(例如,平均值、中位数或最频繁值)替换表达式中的 NULL 。 |
ML.ONE_HOT_ENCODER |
使用单热编码方案编码字符串表达式。 |
ML.LABEL_ENCODER |
将字符串表达式编码为 [0, n_categories] 范围内的 INT64 。 |
表 6.1 – 数据转换函数
这里列出了所有函数及其输入和输出,以及每个函数的示例:
-
ML.BUCKETIZE
根据提供的分割点将数值表达式分桶到用户定义的类别。
输入:
-
numerical_expression
: 用于分桶的数值表达式。 -
array_split_points
: 包含分割点的排序数值数组。 -
exclude_boundaries
(可选):如果为TRUE
,则从array_split_points
中移除两个边界。默认值为FALSE
。
输出:
STRING
是numerical_expression
字段分割成桶的名称。这里是一个示例 SQL 语句:
WITH dataset AS ( SELECT 21 AS age UNION ALL SELECT 33 AS age UNION ALL SELECT 45 AS age UNION ALL SELECT 59 AS age UNION ALL SELECT 66 AS age ) SELECT age, ML.BUCKETIZE(age, [18, 35, 50, 65]) AS age_bucket FROM dataset;
在 BigQuery 中提交此查询应生成以下输出:
age age_bucket 21 bin_2 33 bin_2 45 bin_3 59 bin_4 bin_5
-
-
ML.FEATURE_CROSS
这可以生成指定度数的分类特征的交叉特征:
Input: array_expression, degree Output: ARRAY<STRUCT<name STRING, value FLOAT64>>
这里是一个示例 SQL 语句:
WITH dataset AS ( SELECT "dog" AS animal, "brown" AS color UNION ALL SELECT "cat" AS animal, "black" AS color UNION ALL SELECT "bird" AS animal, "yellow" AS color UNION ALL SELECT "fish" AS animal, "orange" AS color) SELECT animal, color, ML.FEATURE_CROSS(STRUCT(animal, color)) AS animal_color FROM dataset;
在 BigQuery 中提交此查询应生成以下输出:
动物 | 颜色 | 动物 _ 颜色 |
---|---|---|
狗 | 棕色 | 狗 _ 棕色 |
猫 | 黑色 | 猫 _ 黑色 |
鸟 | 黄色 | 鸟 _ 黄色 |
鱼 | 橙色 | 鱼 _ 橙色 |
表 6.2 – BigQuery 查询输出
注意,如果 ARRAY
参数中包含更多列,则可以使用 ML.FEATURE_CROSS
函数创建多个列的交叉。
-
ML.NGRAMS
这根据给定的 n 值范围从标记数组中提取 n-gram。
输入:
-
array_input
:ARRAY
的STRING
。这些字符串是要合并的标记。 -
range
:ARRAY
的两个INT64
元素或单个INT64
。ARRAY
输入中的这两个排序的INT64
元素是要返回的 n-gram 大小范围。单个INT64
等同于 [x, x] 范围。 -
separator
: 可选的STRING
。separator
连接输出中的相邻标记。默认值是空格。
输出:
ARRAY
的STRING
。这里是一个示例 SQL 语句:
WITH dataset AS ( SELECT "apple" AS fruit, "cherry" AS fruit2,"pear" AS fruit3 UNION ALL SELECT "banana" AS fruit, "banana" AS fruit2,"melon" AS fruit3 UNION ALL SELECT "cherry" AS fruit, "cherry" AS fruit2, "pineapple" AS fruit3) SELECT fruit,fruit2,fruit3, ML.NGRAMS([fruit,fruit2,fruit3], [2]) AS fruit_ngrams FROM dataset;
在 BigQuery 中提交此查询应生成以下输出:
-
水果 | 水果 2 | 水果 3 | 水果 _ngrams |
---|---|---|---|
苹果 | 樱桃 | 梨 | [苹果 樱桃, 樱桃 梨] |
香蕉 | 香蕉 | 西瓜 | [香蕉 香蕉, 香蕉 西瓜] |
樱桃 | 樱桃 | 菠萝 | [樱桃 樱桃, 樱桃 菠萝] |
表 6.3 – BigQuery 输出
-
ML.QUANTILE_BUCKETIZE
这个功能将数值表达式根据几个桶划分为基于分位数的类别。
输入:
-
numerical_expression
: 要划分的数值表达式 -
num_buckets
:INT64
。将numerical_expression
分割成桶的数量
输出:
STRING
。这里是一个示例 SQL 语句:
WITH dataset AS ( SELECT 21 AS age UNION ALL SELECT 33 AS age UNION ALL SELECT 45 AS age UNION ALL SELECT 59 AS age UNION ALL SELECT 66 AS age) SELECT age, ML.QUANTILE_BUCKETIZE(age, 4) OVER() AS age_bucket FROM dataset ORDER BY age;
在此示例中,我们创建了一个包含五行年龄数据的虚拟表数据集。然后,我们使用
ML.QUANTILE_BUCKETIZE
函数将age
列划分为四个分位数桶。结果age_bucket
列显示了数据集的每一行属于哪个分位数桶。这里是输出示例:
age age_bucket 21 bin_1 33 bin_2 45 bin_3 59 bin_4 66 bin_4
-
-
ML.HASH_BUCKETIZE
这将字符串表达式划分为基于哈希的固定数量的桶。
输入:
-
string_expression
:STRING
。要划分的字符串表达式。 -
hash_bucket_size
:INT64
。桶的数量。预期hash_bucket_size >= 0
。如果hash_bucket_size = 0
,则函数仅对字符串进行哈希处理,而不对哈希值进行桶划分。
输出:
INT64
。这里是一个示例 SQL 语句:
WITH dataset AS ( SELECT "horse" AS animal UNION ALL SELECT "cat" AS animal UNION ALL SELECT "dog" AS animal UNION ALL SELECT "fish" AS animal) SELECT animal, ML.HASH_BUCKETIZE(animal, 2) AS animal_bucket FROM dataset;
在本例中,我们创建了一个包含四行数据的虚拟表数据集。然后,我们使用
ML.HASH_BUCKETIZE
函数将animal
列哈希到两个桶中。结果animal_bucket
列显示了数据集的每一行属于哪个哈希桶。注意,可以通过指定第二个参数的不同值来使用
ML.HASH_BUCKETIZE
函数将列的值哈希到不同数量的桶中。下面是输出:
animal animal_bucket horse 1 cat 0 dog 0 fish 0
在本例中,我们创建了一个包含四行数据的虚拟表数据集。然后,我们使用
ML.HASH_BUCKETIZE
函数将animal
列哈希到两个桶中。结果animal_bucket
列显示了数据集的每一行属于哪个哈希桶。 -
-
ML.MIN_MAX_SCALER
将数值表达式缩放到范围[0, 1],范围由所有行的
MIN
和MAX
值限制。输入:
numerical_expression
。要缩放的数值表达式。输出:
DOUBLE
。下面是一个示例 SQL 语句:
WITH dataset AS ( SELECT 10 AS age UNION ALL SELECT 20 AS age UNION ALL SELECT 30 AS age UNION ALL SELECT 40 AS age UNION ALL SELECT 50 AS age) SELECT age, ML.MIN_MAX_SCALER(age) Over() AS scaled_age FROM dataset;
在本例中,我们创建了一个包含五行年龄数据的虚拟表数据集。然后,我们使用
ML.MIN_MAX_SCALER
函数将age
列缩放到 0 到 1 的范围。请注意,可以通过指定不同的MIN
和MAX
参数值来使用ML.MIN_MAX_SCALER
函数将列的值缩放到不同的范围。下面是输出:
age scaled_age 50 1.0 20 0.25 40 0.75 10 0.0 30 0.5
-
ML.STANDARD_SCALER
此函数对数值表达式进行标准化。
输入:
numerical_expression
。要缩放的数值表达式。输出:
DOUBLE
。下面是一个示例 SQL 语句:
WITH dataset AS ( SELECT 10 AS age UNION ALL SELECT 20 AS age UNION ALL SELECT 30 AS age UNION ALL SELECT 40 AS age UNION ALL SELECT 50 AS age) SELECT age, ML.STANDARD_SCALER(age) OVER() AS scaled_age FROM dataset;
在本例中,我们创建了一个包含五行年龄数据的虚拟表数据集。然后,我们使用
ML.STANDARD_SCALER
函数将age
列标准化,使其均值为 0,标准差为 1。结果scaled_age
列显示了age
列的标准化值。下面是输出:
age scaled_age 40 0.63245553203367588 10 -1.2649110640673518 50 1.2649110640673518 20 -0.63245553203367588 30 0.0
-
ML.MAX_ABS_SCALER
此函数通过除以最大绝对值来将数值表达式缩放到范围[-1, 1]。
输入:
numerical_expression
。输出:
DOUBLE
。下面是一个示例 SQL 语句:
WITH dataset AS ( SELECT -10 AS age UNION ALL SELECT 20 AS age UNION ALL SELECT -30 AS age UNION ALL SELECT 40 AS age UNION ALL SELECT -50 AS age) SELECT age, ML.MAX_ABS_SCALER(age) OVER() AS scaled_age FROM dataset;
在本例中,我们创建了一个包含五行年龄数据的虚拟表数据集。然后,我们使用
ML.MAX_ABS_SCALER
函数缩放age
列,使得该列中最大绝对值元素的绝对值缩放到 1。结果scaled_age
列显示了age
列的缩放值。下面是输出:
age scaled_age -10 -0.2 -50 -1.0 20 0.4 40 0.8 -30 -0.6
-
ML.NORMALIZER
此函数使用给定的 p-norm 将
array_expression
归一化,使其具有单位范数。输入:
array_expression, p
。输出:
ARRAY<DOUBLE>
。下面是一个示例 SQL 语句:
WITH dataset AS ( SELECT 1 AS x, 2 AS y UNION ALL SELECT 3 AS x, 4 AS y UNION ALL SELECT 5 AS x, 6 AS y UNION ALL SELECT 7 AS x, 8 AS y UNION ALL SELECT 9 AS x, 10 AS y) SELECT x, y, ML.NORMALIZER([x, y], 1) AS norm_xy FROM dataset;
下面是输出:
x y norm_xy 1 2 "[0.4472135954999579,0.8944271909999158]" 3 4 "[0.6,0.8]" 5 6 "[0.6401843996644799,0.7682212795973758]" 7 8 "[0.658504607868518,0.75257669470687782]" 9 10 "[0.6689647316224497,0.7432941462471663]"
-
ML.IMPUTER
此函数使用指定的值(例如,均值、中位数或最频繁值)替换表达式中的
NULL
。输入:
expression, strategy
。输出:数值表达式的
DOUBLE
。STRING
表达式的STRING
。下面是一个示例 SQL 语句:
WITH dataset AS ( SELECT 10 AS age, 20 AS height UNION ALL SELECT 20 AS age, 30 AS height UNION ALL SELECT 30 AS age, 40 AS height UNION ALL SELECT 40 AS age, 50 AS height UNION ALL SELECT 50 AS age, NULL AS height) SELECT age, height, ML.IMPUTER(height,"median") OVER() AS imputed_height FROM dataset;
下面是输出:
age height imputed_height 20 30 30.0 10 20 20.0 40 50 50.0 50 null 30.0 30 40 40.0
-
ML.ONE_HOT_ENCODER
此函数使用单热编码方案对
string_expression
进行编码。输入:
-
string_expression
:要编码的STRING
表达式。 -
drop
(可选):这决定了在编码过程中要丢弃哪个类别。默认值是none
,意味着保留所有类别。 -
top_k
(可选):INT64
。这限制了编码词汇表只包含top_k
个最频繁的类别。默认值是 32,000,最大支持值是 1 百万,以避免因高维性而受到影响。 -
frequency_threshold
(可选):INT64
。它限制了编码词汇表只包含频率>= frequency_threshold
的类别。默认值是5
。
输出:它是一个包含编码值的
STRUCT
数组,其中index
是编码值的索引,value
是编码值的值。这里是一个示例 SQL 语句:
WITH input_data AS ( SELECT 'red' AS color UNION ALL SELECT 'blue' AS color UNION ALL SELECT 'green' AS color UNION ALL SELECT 'green' AS color UNION ALL SELECT 'purple' AS color), vocab AS ( SELECT color, COUNT(*) AS frequency FROM input_data GROUP BY color) SELECT color, ML.ONE_HOT_ENCODER(color) OVER() AS encoding FROM input_data
上述查询的结果如下所示:
-
颜色 | encoding.index | encoding.value |
---|---|---|
绿色 | 0 | 1.0 |
红色 | 0 | 1.0 |
紫色 | 0 | 1.0 |
蓝色 | 0 | 1.0 |
绿色 | 0 | 1.0 |
表 6.4:前一个查询的输出
-
ML.LABEL_ENCODER
此函数将字符串值转换为指定范围内的
INT64
数字。该函数按字母顺序组织编码术语,且在此词汇表中未找到的任何类别将表示为0
。当在TRANSFORM
子句中使用时,训练过程中省略的词汇表和类别将无缝应用于预测。输入:
-
string_expression
:要编码的STRING
表达式。 -
top_k
:可选的INT64
。这限制了编码词汇表只包含top_k
个最频繁的类别。默认值是 32,000,最大支持值是 1 百万,以避免因高维性而受到影响。 -
frequency_threshold
:可选的INT64
。这限制了编码词汇表只包含频率>= frequency_threshold
的类别。默认值是5
。
输出:
INT64
。这是指定范围内字符串表达式的编码值。这里是一个示例 SQL 语句:
WITH data AS ( SELECT 'apple' AS fruit UNION ALL SELECT 'banana' UNION ALL SELECT 'orange' UNION ALL SELECT 'apple' UNION ALL SELECT 'pear' UNION ALL SELECT 'kiwi' UNION ALL SELECT 'banana') SELECT fruit, ML.LABEL_ENCODER(fruit, 2,2) OVER() AS encoded_fruit FROM data
上述查询的结果如下所示:
-
水果 | encoded_fruit |
---|---|
橙子 | 0 |
梨 | 0 |
香蕉 | 2 |
苹果 | 1 |
草莓 | 0 |
苹果 | 1 |
香蕉 | 2 |
表 6.5:前一个查询的输出
现在我们来看看你可以使用 BQML 构建的不同类型的机器学习模型。
使用 BQML 构建机器学习模型
BQML 支持多种不同用例的模型训练。目前支持的关键模型类别包括监督学习模型、无监督学习模型、时间序列模型、导入的模型和远程模型。
下表展示了 BigQuery 支持的一些关键机器学习模型类型:
模型类型 | 模型类型 | 手动定义 特征预处理 | 在 BQML 中的超参数调整 |
---|---|---|---|
监督学习 | 线性和逻辑回归 | 支持 | 支持 |
监督学习 | 深度神经网络 | 支持 | 支持 |
监督学习 | 广度与深度 | 支持 | 支持 |
监督 | 提升树 | 支持 | 支持 |
监督 | 随机森林 | 支持 | 支持 |
监督 | AutoML 表格 | 不支持 | 自动 |
无监督 | k-means | 支持 | 支持 |
无监督 | 矩阵分解 | 不支持 | 支持 |
无监督 | PCA | 支持 | 不支持 |
无监督 | 自动编码器 | 支持 | 不支持 |
时间序列 | ARIMA_PLUS |
仅自动预处理 | 支持(``auto.ARIMA4)* |
时间序列 | ARIMA_PLUS_XREG |
仅自动预处理 | 支持(``auto.ARIMA4)* |
表 6.6 – 支持的关键机器学习模型的功能
在 BigQuery 中,有两个其他重要的模型创建选项可供您使用,以帮助您利用 BigQuery 外部构建的机器学习模型 – 导入模型和远程模型。
BQML 允许您导入在 BigQuery 外部训练的模型,以便可以在 BigQuery 内部进行推理。
支持以下模型框架用于导入:
-
TensorFlow
-
TensorFlow Lite
-
ONNX
-
XGBoost
BQML 允许您将现有的 Vertex AI 端点注册为远程模型。一旦在 BigQuery 中注册,您就可以从 BigQuery 内部向 Vertex AI 端点发送预测请求以进行推理。
创建 BQML 模型
用于启动模型创建的 BigQuery 函数被称为CREATE
。在本节中,我们将探讨当用户使用CREATE
函数创建不同类型的 BQML 模型时可供使用的选项。您目前不一定需要阅读每个模型的详细信息。这应该更多地用作参考,按需使用。
线性或逻辑回归模型
下面的语法用于创建回归模型,以及您需要在查询中提供的一些必需和可选参数:
{CREATE OR REPLACE MODEL} model_name
[OPTIONS(MODEL_TYPE = { 'LINEAR_REG' | 'LOGISTIC_REG' },
INPUT_LABEL_COLS = string_array,
OPTIMIZE_STRATEGY = { 'AUTO_STRATEGY' },
L1_REG = float64_value,
L2_REG = float64_value,
MAX_ITERATIONS = int64_value,
LEARN_RATE_STRATEGY = { 'LINE_SEARCH' | 'CONSTANT' },
LEARN_RATE = float64_value,
EARLY_STOP = { TRUE },
MIN_REL_PROGRESS = float64_value,
DATA_SPLIT_METHOD = { 'AUTO_SPLIT'},
DATA_SPLIT_EVAL_FRACTION = float64_value,
DATA_SPLIT_COL = string_value,
LS_INIT_LEARN_RATE = float64_value,
WARM_START = { FALSE },
AUTO_CLASS_WEIGHTS = { TRUE },
CLASS_WEIGHTS = struct_array,
ENABLE_GLOBAL_EXPLAIN = { FALSE },
CALCULATE_P_VALUES = { FALSE },
FIT_INTERCEPT = { FALSE },
CATEGORY_ENCODING_METHOD = { 'ONE_HOT_ENCODING`, 'DUMMY_ENCODING' })];
可以在CREATE MODEL
语句中指定的关键选项如下:
-
MODEL_TYPE
:指定所需的模型类型(例如,线性或逻辑回归)。 -
INPUT_LABEL_COLS
:定义训练数据中的标签列名。 -
OPTIMIZE_STRATEGY
:选择训练线性回归模型的方法:-
AUTO_STRATEGY
:根据几个条件选择训练方法:-
如果指定了
l1_reg
或warm_start
,则采用batch_gradient_descent
策略 -
batch_gradient_descent
如果训练特征的总体基数超过 10,000 也会被使用 -
当可能存在过拟合问题时,特别是当训练样本数小于总基数 10 倍时,选择
batch_gradient_descent
-
-
对于所有其他场景,实现
NORMAL_EQUATION
策略 -
BATCH_GRADIENT_DESCENT
:在模型训练中启用批量梯度下降方法,通过使用梯度函数优化损失函数。 -
NORMAL_EQUATION
: 使用解析公式推导线性回归问题的最小二乘解。在以下情况下不允许使用NORMAL_EQUATION
策略:-
l1_reg
被定义 -
warm_start
被定义 -
训练特征的总基数超过 10,000
-
-
-
L1_REG
: 设置应用的 L1 正则化的量。 -
L2_REG
: 设置应用的 L2 正则化的量。 -
MAX_ITERATIONS
: 确定训练迭代的最大次数或步骤。 -
LEARN_RATE_STRATEGY
: 选择在训练期间指定学习率的策略。 -
LEARN_RATE
: 定义梯度下降的学习率。 -
EARLY_STOP
: 指示是否在第一次迭代后,如果相对损失改进最小,则停止训练。 -
MIN_REL_PROGRESS
: 设置继续训练的最小相对损失改进。 -
DATA_SPLIT_METHOD
: 选择将输入数据分割为训练集和评估集的方法。这里的选项有'AUTO_SPLIT'
、'RANDOM'
、'CUSTOM'
、'SEQ'
和'NO_SPLIT'
。 -
DATA_SPLIT_EVAL_FRACTION
: 指定在'RANDOM'
和'SEQ'
分割中用于评估的数据的分数。 -
DATA_SPLIT_COL
: 识别用于分割数据的列。 -
LS_INIT_LEARN_RATE
: 为'LINE_SEARCH'
策略设置初始学习率。 -
WARM_START
: 使用新的训练数据、新的模型选项或两者重新训练模型。 -
AUTO_CLASS_WEIGHTS
: 使用每个类别的权重来平衡类别标签,这些权重与该类别的频率成反比。 -
CLASS_WEIGHTS
: 定义每个类别标签使用的权重。 -
ENABLE_GLOBAL_EXPLAIN
: 使用可解释 AI 计算全局特征重要性评估的全局解释。 -
CALCULATE_P_VALUES
: 在训练期间计算 p 值和标准误差。 -
FIT_INTERCEPT
: 在训练期间将截距拟合到模型中。 -
CATEGORY_ENCODING_METHOD
: 指定对非数值特征使用的编码方法。
创建深度神经网络模型和宽深度模型
这是创建深度学习模型的语法,以及作为查询一部分需要提供的不同必需和可选参数:
{CREATE OR REPLACE MODEL} model_name
[OPTIONS(MODEL_TYPE= {'DNN_CLASSIFIER'},
ACTIVATION_FN = { 'RELU' },
AUTO_CLASS_WEIGHTS = { TRUE | FALSE },
BATCH_SIZE = int64_value,
CLASS_WEIGHTS = struct_array,
DROPOUT = float64_value,
EARLY_STOP = { TRUE | FALSE },
HIDDEN_UNITS = int_array,
L1_REG = float64_value,
L2_REG = float64_value,
LEARN_RATE = float64_value,
INPUT_LABEL_COLS = string_array,
MAX_ITERATIONS = int64_value,
MIN_REL_PROGRESS = float64_value,
OPTIMIZER={'ADAGRAD'},
WARM_START = { FALSE },
DATA_SPLIT_METHOD={'AUTO_SPLIT'},
DATA_SPLIT_EVAL_FRACTION = float64_value,
DATA_SPLIT_COL = string_value,
ENABLE_GLOBAL_EXPLAIN = { FALSE },
INTEGRATED_GRADIENTS_NUM_STEPS = int64_value,
TF_VERSION = { '2.8.0' })];
以下选项可以作为模型创建请求的一部分指定:
-
model_name
: 你正在创建或替换的 BQML 模型名称。 -
model_type
: 指定模型的类型,可以是'DNN_CLASSIFIER'
或'DNN_REGRESSOR'
。 -
activation_fn
: 对于 DNN 模型类型,这指定了神经网络的激活函数。选项有'RELU'
、'RELU6'
、'CRELU'
、'ELU'
、'SELU'
、'SIGMOID'
和'TANH'
。 -
auto_class_weights
: 指定是否使用每个类别的权重来平衡类别标签,这些权重与该类别的频率成反比。仅与DNN_CLASSIFIER
模型一起使用。 -
batch_size
: 对于 DNN 模型类型,这指定了输入到神经网络的样本的迷你批大小。 -
class_weights
: 用于每个类别标签的权重。如果AUTO_CLASS_WEIGHTS
为TRUE
,则不能指定此选项。 -
data_split_method
: 将输入数据分割为训练集和评估集的方法。选项有'AUTO_SPLIT'
、'RANDOM'
、'CUSTOM'
、'SEQ'
和'NO_SPLIT'
。 -
data_split_eval_fraction
: 与'RANDOM'
和'SEQ'
分割一起使用。它指定用于评估的数据比例。 -
data_split_col
: 识别用于分割数据的列。 -
dropout
: 对于 DNN 模型类型,这指定了神经网络中单元的丢弃率。 -
early_stop
: 是否在相对损失改进小于为MIN_REL_PROGRESS
指定的值的第一次迭代后停止训练。 -
enable_global_explain
: 指定是否使用可解释人工智能来计算全局解释,以评估全局特征对模型的重要性。 -
hidden_units
: 对于 DNN 模型类型,这指定了神经网络的隐藏层。 -
input_label_cols
: 训练数据中的标签列名称。 -
integrated_gradients_num_steps
: 指定在解释示例及其基线之间采样步数的数量,以近似积分梯度属性方法中的积分。 -
l1_reg
: 优化器的 L1 正则化强度。 -
l2_reg
: 优化器的 L2 正则化强度。 -
learn_rate
: 训练的初始学习率。 -
max_iterations
: 训练迭代的最大次数。 -
optimizer
: 对于 DNN 模型类型,这指定了训练模型的优化器。选项有'ADAGRAD'
、'ADAM'
、'FTRL'
、'RMSPROP'
和'SGD'
。 -
warm_start
: 是否使用新的训练数据、新的模型选项或两者重新训练模型。 -
tf_version
: 指定模型训练的 TensorFlow 版本。
创建提升树和随机森林模型
创建提升树和随机森林模型的语法,以及作为查询一部分需要提供的不同必需和可选参数:
{CREATE OR REPLACE MODEL} model_name
[OPTIONS(MODEL_TYPE = { 'BOOSTED_TREE_CLASSIFIER' },
BOOSTER_TYPE = {'GBTREE' },
NUM_PARALLEL_TREE = int64_value,
DART_NORMALIZE_TYPE = {'TREE' },
TREE_METHOD={'AUTO' },
MIN_TREE_CHILD_WEIGHT = int64_value,
COLSAMPLE_BYTREE = float64_value,
COLSAMPLE_BYLEVEL = float64_value,
COLSAMPLE_BYNODE = float64_value,
MIN_SPLIT_LOSS = float64_value,
MAX_TREE_DEPTH = int64_value,
SUBSAMPLE = float64_value,
AUTO_CLASS_WEIGHTS = { TRUE },
CLASS_WEIGHTS = struct_array,
INSTANCE_WEIGHT_COL = string_value,
L1_REG = float64_value,
L2_REG = float64_value,
EARLY_STOP = { TRUE },
LEARN_RATE = float64_value,
INPUT_LABEL_COLS = string_array,
MAX_ITERATIONS = int64_value,
MIN_REL_PROGRESS = float64_value,
DATA_SPLIT_METHOD = {'AUTO_SPLIT'},
DATA_SPLIT_EVAL_FRACTION = float64_value,
DATA_SPLIT_COL = string_value,
ENABLE_GLOBAL_EXPLAIN = { TRUE},
XGBOOST_VERSION = {'1.1'})];
在创建模型请求中可以指定的选项包括:
-
MODEL_TYPE
: 指定模型是提升树分类器、提升树回归器、随机森林分类器还是随机森林回归器。选项有'BOOSTED_TREE_CLASSIFIER'
、'BOOSTED_TREE_REGRESSOR'
、'RANDOM_FOREST_CLASSIFIER'
和'RANDOM_FOREST_REGRESSOR'
。 -
BOOSTER_TYPE
(仅适用于Boosted_Tree_Models
):指定用于提升树模型的提升器类型。GBTREE代表梯度提升树,DART代表Dropouts meet Multiple Additive Regression Trees。 -
NUM_PARALLEL_TREE
: 指定要生长的并行树的数量。较大的数字可以提高性能,但也会增加训练时间和内存使用。 -
DART_NORMALIZE_TYPE
(仅适用于Boosted_Tree_Models
):指定用于'TREE'
的归一化方法,表示在提升过程中根据丢弃的树的数量进行归一化,而'FOREST'
表示根据森林中树的总数进行归一化。 -
TREE_METHOD
: 指定用于构建集成中每个决策树的方法。'AUTO'
表示算法将根据数据选择最佳方法,'EXACT'
表示精确贪婪算法,'APPROX'
表示近似贪婪算法,而'HIST'
表示基于直方图的算法。 -
MIN_TREE_CHILD_WEIGHT
: 指定树的孩子节点中所需的实例权重最小总和。如果总和低于此值,则节点将不会分割。 -
COLSAMPLE_BYTREE
: 指定为每棵树随机采样的列的比例。 -
COLSAMPLE_BYLEVEL
: 指定为树的每个级别随机采样的列的比例。 -
COLSAMPLE_BYNODE
: 指定为树的每个分割节点随机采样的列的比例。 -
MIN_SPLIT_LOSS
: 指定分割节点所需的最低损失减少量。 -
MAX_TREE_DEPTH
: 指定每棵树的最大深度。 -
SUBSAMPLE
: 指定为每棵树随机采样的训练实例的比例。 -
AUTO_CLASS_WEIGHTS
: 如果设置为TRUE
,算法将根据数据自动确定分配给每个类的权重。 -
CLASS_WEIGHTS
: 指定分配给每个类的权重。这可以用于平衡数据,如果类别不平衡的话。 -
INSTANCE_WEIGHT_COL
: 指定包含实例权重的列的名称。 -
L1_REG
: 指定 L1 正则化参数。 -
L2_REG
: 指定 L2 正则化参数。 -
EARLY_STOP
: 如果设置为TRUE
,当性能提升低于某个阈值时,训练过程将提前停止。选项是TRUE
和FALSE
。 -
LEARN_RATE
(仅适用于Boosted_Tree_Models
):指定学习率,它控制提升过程中每次迭代的步长大小。 -
INPUT_LABEL_COLS
: 指定包含输入特征和标签的列的名称。 -
MAX_ITERATIONS
(仅适用于Boosted_Tree_Models
):指定要执行的提升迭代次数的最大值。 -
MIN_REL_PROGRESS
: 指定继续训练过程所需的最低相对进度。 -
DATA_SPLIT_METHOD
: 指定用于将数据分割为训练集和验证集的方法。'AUTO_SPLIT'
表示算法将自动分割数据,'RANDOM'
表示随机分割,'CUSTOM'
表示用户自定义分割,'SEQ'
表示顺序分割,而'NO_SPLIT'
表示不分割(使用所有数据进行训练)。 -
DATA_SPLIT_EVAL_FRACTION
: 指定分割数据时用于验证的数据比例。 -
DATA_SPLIT_COL
: 指定用于分割数据的列的名称。 -
ENABLE_GLOBAL_EXPLAIN
: 如果设置为TRUE
,则算法将计算全局特征重要性分数。选项有TRUE
和FALSE
。 -
XGBOOST_VERSION
: 指定要使用的 XGBoost 版本。
导入模型
BQML 还允许您导入在 BigQuery 外部训练的深度学习模型。这是一个非常有用的功能,因为它为您提供了使用 BigQuery 外部更定制设置训练模型的灵活性,同时还能使用 BigQuery 的计算基础设施进行推理。
这是您可以使用导入功能的方式:
{CREATE OR REPLACE MODEL} model_name
[OPTIONS(MODEL_TYPE = {'TENSORFLOW'} ,
MODEL_PATH = string_value)]
这里是作为导入功能一部分的可用选项:
-
MODEL_TYPE
: 指定模型是 TensorFlow、TensorFlow Lite 还是 ONNX 模型。选项有'TENSORFLOW'
、'ONNX'
和'TENSORFLOW_LITE'
。 -
MODEL_PATH
: 提供要导入到 BQML 的模型的云存储 URI。
k-means 模型
这里是创建 k-means 模型的语法,以及您需要作为查询一部分提供的不同必需和可选参数:
{CREATE OR REPLACE MODEL} model_name
[OPTIONS(MODEL_TYPE = { 'KMEANS' },
NUM_CLUSTERS = int64_value,
KMEANS_INIT_METHOD = { 'RANDOM' },
KMEANS_INIT_COL = string_value,
DISTANCE_TYPE = { 'EUCLIDEAN' | 'COSINE' },
STANDARDIZE_FEATURES = { TRUE },
MAX_ITERATIONS = int64_value,
EARLY_STOP = { TRUE },
MIN_REL_PROGRESS = float64_value,
WARM_START = { FALSE })];
让我们看看可以作为模型创建查询一部分指定的选项:
-
MODEL_TYPE
: 指定模型类型。此选项是必需的。 -
NUM_CLUSTERS
(可选):对于 k-means 模型,这指定了在输入数据中要识别的簇的数量。默认值为log10(n)
,其中n
是训练示例的数量。 -
KMEANS_INIT_METHOD
(可选):对于 k-means 模型,这指定了初始化簇的方法。默认值为'RANDOM'
。选项有'RANDOM'
、'KMEANS++'
和'CUSTOM'
。 -
KMEANS_INIT_COL
(可选):对于 k-means 模型,这标识了将用于初始化质心的列。此选项只能在KMEANS_INIT_METHOD
的值为CUSTOM
时指定。相应的列必须是BOOL
类型,并且NUM_CLUSTERS
模型选项必须在查询中存在,其值必须等于此列中TRUE
行的总数。BQML 不能使用此列作为特征,并自动将其排除在特征之外。 -
DISTANCE_TYPE
(可选):对于 k-means 模型,这指定了计算两点之间距离的度量类型。默认值为'EUCLIDEAN'
。 -
STANDARDIZE_FEATURES
(可选):对于 k-means 模型,这指定了是否标准化数值特征。默认值为TRUE
。 -
MAX_ITERATIONS
(可选):最大训练迭代次数或步骤。默认值为20
。 -
EARLY_STOP
(可选):是否在相对损失改进小于为MIN_REL_PROGRESS
指定值的第一次迭代后停止训练。默认值为TRUE
。 -
MIN_REL_PROGRESS
(可选):当EARLY_STOP
设置为TRUE
时,继续训练所需的最低相对损失改进。例如,0.01 的值指定每次迭代必须将损失降低 1%,以便继续训练。默认值为0.01
。 -
WARM_START
(可选): 是否使用新的训练数据、新的模型选项或两者重新训练模型。除非明确覆盖,否则用于训练模型的初始选项将用于热启动运行。MODEL_TYPE
的值和训练数据模式必须在热启动模型的重新训练中保持不变。默认值是FALSE
。
现在让我们看看 BQML 对超参数调优的支持。
BQML 的超参数调优
BQML 允许您在构建机器学习模型时通过使用 CREATE MODEL
语句来微调超参数。这个过程称为超参数调优,是一种常用的方法,通过找到最佳的超参数集来提高模型精度。
这里是一个 BigQuery SQL 语句的示例:
{CREATE OR REPLACE MODEL} model_name
OPTIONS(Existing Training Options,
NUM_TRIALS = int64_value, [, MAX_PARALLEL_TRIALS = int64_value ]
[, HPARAM_TUNING_ALGORITHM = { 'VIZIER_DEFAULT' | 'RANDOM_SEARCH' | 'GRID_SEARCH' } ]
[, hyperparameter={HPARAM_RANGE(min, max) | HPARAM_CANDIDATES([candidates]) }... ]
[, HPARAM_TUNING_OBJECTIVES = { 'R2_SCORE' | 'ROC_AUC' | ... } ]
[, DATA_SPLIT_METHOD = { 'AUTO_SPLIT' | 'RANDOM' | 'CUSTOM' | 'SEQ' | 'NO_SPLIT' } ]
[, DATA_SPLIT_COL = string_value ]
[, DATA_SPLIT_EVAL_FRACTION = float64_value ]
[, DATA_SPLIT_TEST_FRACTION = float64_value ]
) AS query_statement
让我们看看可以作为模型创建查询一部分指定的选项:
-
NUM_TRIALS
-
描述:这确定了要训练的最大子模型数量。在训练
num_trials
个子模型或搜索空间耗尽后,将停止调优。最大值是 100。 -
参数:
int64_value
必须是一个范围从 1 到 100 的INT64
值。
-
注意
建议至少使用 (num_hyperparameters
* 10) 次试验来进行模型调优。
-
MAX_PARALLEL_TRIALS
-
描述:这表示可以同时运行的试验的最大数量。默认值是 1,最大值是 5。
-
参数:
int64_value
必须是一个范围从 1 到 5 的INT64
值。
-
注意
较大的 max_parallel_trials
值可以加快超参数调优的速度,但对于 VIZIER_DEFAULT
调优算法,它可能会降低最终模型的质量,因为并行试验无法从并发训练结果中受益。
-
HPARAM_TUNING_ALGORITHM
-
描述:这确定了超参数调优的算法,并支持以下值:
-
VIZIER_DEFAULT
(默认并推荐): 使用默认的 Vertex AI Vizier 算法,该算法结合了贝叶斯优化和高斯过程等高级搜索算法,并采用迁移学习来利用先前调优的模型。 -
RANDOM_SEARCH
: 采用随机搜索来探索搜索空间。 -
GRID_SEARCH
: 使用网格搜索来探索搜索空间。这仅在每个超参数的搜索空间都是离散的情况下才可用。
-
-
-
HYPERPARAMETER
语法:
hyperparameter={HPARAM_RANGE(min, max) | HPARAM_CANDIDATES([candidates]) }...
此参数配置超参数的搜索空间。请参考每种模型类型的超参数和目标,以了解哪些可调超参数受支持:
-
HPARAM_RANGE(min, max)
: 指定超参数的连续搜索空间 – 例如,learn_rate
=HPARAM_RANGE(0.0001, 1.0)
-
HPARAM_CANDIDATES([candidates])
: 指定具有离散值的超参数 – 例如,OPTIMIZER=HPARAM_CANDIDATES([
adagrad,
sgd,
ftrl]
)`
-
-
HPARAM_TUNING_OBJECTIVES
此参数指定模型的客观指标。候选指标是模型评估指标的一个子集。目前仅支持一个客观指标。请参阅表 6.7,以查看支持的模型类型、超参数和调整目标。
模型类型 | 超参数目标 | 超参数 |
---|---|---|
LINEAR_REG |
-
mean_absolute_error
-
mean_squared_error
-
mean_squared_log_error
-
median_absolute_error
-
r2_score (默认)
-
explained_variance
|
-
l1_reg
-
l2_reg
|
LOGISTIC_REG |
---|
-
precision
-
recall
-
accuracy
-
f1_score
-
log_loss
-
roc_auc (默认)
|
-
l1_reg
-
l2_reg
|
KMEANS |
---|
davies_bouldin_index
num_clusters |
---|
`MATRIX_FACTORIZATION ( 隐式/显式``) |
-
mean_average_precision (``显式模型``)
-
mean_squared_error (隐式/显式)
-
normalized_discounted_cumulative_gain (``显式模型``)
-
average_rank (``显式模型``)
|
-
num_factors
-
l2_reg
-
wals_alpha(隐式模型仅)
|
DNN_CLASSIFIER |
---|
-
precision
-
recall
-
accuracy
-
f1_score
-
log_loss
-
roc_auc (默认)
|
-
batch_size
-
dropout
-
hidden_units
-
learn_rate
-
optimizer
-
l1_reg
-
l2_reg
-
activation_fn
|
DNN_REGRESSOR |
---|
-
mean_absolute_error
-
mean_squared_error
-
mean_squared_log_error
-
median_absolute_error
-
r2_score (默认)
-
explained_variance
|
BOOSTED_TREE_``CLASSIFIER |
---|
-
precision
-
recall
-
accuracy
-
f1_score
-
log_loss
-
roc_auc (默认)
|
-
learn_rate
-
l1_reg
-
l2_reg
-
dropout
-
max_tree_depth
-
subsample
-
min_split_loss
-
num_parallel_tree
-
min_tree_child_weight
-
colsample_bytree
-
colsample_bylevel
-
colsample_bynode
-
booster_type
-
dart_normalize_type
-
tree_method
|
BOOSTED_TREE_``REGRESSOR |
---|
-
mean_absolute_error
-
mean_squared_error
-
mean_squared_log_error
-
median_absolute_error
-
r2_score (默认)
-
explained_variance
|
RANDOM_FOREST_``CLASSIFIER |
---|
-
precision
-
recall
-
accuracy
-
f1_score
-
log_loss
-
roc_auc (默认)
|
-
l1_reg
-
l2_reg
-
max_tree_depth
-
subsample
-
min_split_loss
-
num_parallel_tree
-
min_tree_child_weight
-
colsample_bytree
-
colsample_bylevel
-
colsample_bynode
-
tree_method
|
RANDOM_FOREST_``REGRESSOR |
---|
-
mean_absolute_error
-
mean_squared_error
-
mean_squared_log_error
-
median_absolute_error
-
r2_score (默认)
-
explained_variance
|
表 6.7 – 模型类型支持的超参数目标
cloud.google.com/bigquery/docs/reference/standard-sql/bigqueryml-hyperparameter-tuning
现在我们来看看在尝试评估机器学习模型时可以使用的 BQML 功能。
评估训练模型
一旦训练了 BQML 模型,您将想要评估关键性能统计指标,具体取决于模型类型。您可以通过使用ML.EVALUATE
函数来实现,如下所示:
ML.EVALUATE(MODEL model_name
[, {TABLE table_name | (query_statement)}]
[, STRUCT<threshold FLOAT64,
perform_aggregation BOOL,
horizon INT64,
confidence_level FLOAT64> settings]))])
让我们看看您可以在评估查询中指定的选项:
-
model_name
:正在评估的模型名称 -
table_name
(可选):包含评估数据的表的名称 -
query_statement
(可选):用于生成评估数据的查询 -
threshold
(可选):在评估期间用于二分类模型的自定义阈值值 -
perform_aggregation
(可选):标识预测准确度评估级别的布尔值 -
horizon
(可选):用于计算评估指标的预测时间点的数量 -
confidence_level
(可选):预测区间内未来值的百分比
ML.Evaluate
函数的输出取决于正在评估的模型类型:
模型类型 | 返回字段 |
---|---|
回归模型 |
-
mean_absolute_error
-
mean_squared_error
-
mean_squared_log_error
-
median_absolute_error
-
r2_score
-
explained_variance
|
分类模型 |
---|
-
precision
-
recall
-
accuracy
-
f1_score
-
log_loss
-
roc_auc
|
k-means 模型 |
---|
-
Davies-Bouldin 指数
-
均方距离
|
带有隐式反馈的矩阵分解模型 |
---|
-
mean_average_precision
-
mean_squared_error
-
normalized_discounted_cumulative_gain
-
average_rank
|
带有显式反馈的矩阵分解模型 |
---|
-
mean_absolute_error
-
mean_squared_error
-
mean_squared_log_error
-
median_absolute_error
-
r2_score
-
explained_variance
|
PCA 模型 |
---|
total_explained_variance_ratio
|
带有输入数据和 perform_aggregation = false 的时序 ARIMA_PLUS 或 ARIMA_PLUS_XREG 模型 |
---|
-
time_series_id_col
或time_series_id_cols
-
time_series_timestamp_col
-
time_series_data_col
-
forecasted_time_series_data_col
-
lower_bound
-
upper_bound
-
absolute_error
-
absolute_percentage_error
|
带有输入数据和 perform_aggregation = true 的时序 ARIMA_PLUS 或 ARIMA_PLUS_XREG 模型 |
---|
-
time_series_id_col
或time_series_id_cols
-
mean_absolute_error
-
mean_squared_error
-
root_mean_squared_error
-
mean_absolute_percentage_error
-
symmetric_mean_absolute_percentage_error
|
没有输入数据的时序 ARIMA_PLUS 模型 |
---|
-
time_series_id_col
或time_series_id_cols
-
non_seasonal_p
-
non_seasonal_d
-
non_seasonal_q
-
has_drift
-
log_likelihood
-
AIC
-
variance
-
seasonal_periods
-
has_holiday_effect
-
has_spikes_and_dips
-
has_step_change
|
自动编码器模型 |
---|
-
mean_absolute_error
-
mean_squared_error
-
mean_squared_log_error
|
远程模型 |
---|
remote_eval_metrics
|
表 6.8 – ML.Evaluate 输出
在下一节中,我们将探讨如何使用您的 BQML 模型进行推理。
使用 BQML 进行推理
在监督式机器学习中,最终目标是使用训练好的模型对新数据进行预测。BQML 提供了 ML.PREDICT
函数来实现这一目的。使用此函数,您可以通过向训练好的模型提供新数据来轻松预测结果。只要至少完成了一次迭代,该函数就可以在模型创建期间、创建后或失败后使用。该函数返回一个与输入表行数相同的表,其中包含输入表的所有列以及模型的所有输出列,输出列名称以 predicted_
为前缀。
ML.PREDICT(MODEL model_name,
{TABLE table_name | (query_statement)}
[, STRUCT<threshold FLOAT64,
keep_original_columns BOOL> settings)])
ML.PREDICT
函数的输出字段取决于所使用的模型类型:
模型类型 | 输出列 |
---|---|
线性回归 Boosted 树回归器随机森林回归器 DNN 回归器 | predicted_<label_column_name> |
二元逻辑回归 Boosted 树分类器随机森林分类器 DNN 分类器多类逻辑回归 | predicted_<label_column_name>, predicted_<label_column_name>_probs |
k-means | centroid_id, nearest_centroids_distance |
PCA | principal_component_<index>, 输入列(如果 keep_original_columns 设置为 true) |
自编码器 | latent_col_<index>, 输入列 |
TensorFlow Lite | TensorFlow Lite 模型预测方法的输出 |
远程模型 | 包含所有 Vertex AI 端点输出字段的输出列,以及包含 Vertex AI 端点状态消息的 remote_model_status 字段 |
ONNX 模型 | ONNX 模型预测方法的输出 |
XGBoost 模型 | XGBoost 模型预测方法的输出 |
表 6.9 – ML.Predict 输出
现在,让我们通过一个实际操作练习来使用 BQML 训练一个机器学习模型,并使用它进行预测。
用户练习
请参阅本书 GitHub 仓库中 第六章 的笔记本,构建 ML 模型的低代码选项,以进行围绕训练 BQML 模型的实际操作练习。在这个练习中,您将使用 BigQuery 中可用的公共数据集之一来训练一个模型,预测客户下个月违约的可能性。
摘要
BQML 是一种强大的工具,适用于希望轻松训练机器学习模型且使用低代码选项在 GCP 中构建和部署模型的数据科学家和分析师。使用 BQML,用户可以利用 BigQuery 的强大功能,快速轻松地创建模型,而无需编写复杂的代码。
在本章中,我们探讨了 BQML 的功能和优势。我们看到了它如何通过 SQL 查询提供简单直观的界面来训练模型。我们还探讨了 BQML 的关键特性,包括在 BigQuery 中直接执行数据预处理和特征工程的能力,以及通过原生评估函数评估模型性能的能力。
BQML 的一个关键优点是它与 BigQuery 的集成,这使得它易于扩展和管理大数据集。这使得它成为处理大量数据并需要快速构建和部署模型的公司和组织的一个很好的选择。
BQML 的另一个优点是它支持广泛的 ML 模型,包括线性回归、逻辑回归、k-means 聚类等。这使得它成为一个多功能的工具,可以用于各种用例,从预测客户流失到聚类数据进行分析。
我们还讨论了 BQML 的一些局限性。例如,虽然它提供了低代码选项来构建和部署模型,但它可能不适合需要自定义模型或大量特征工程更复杂的使用场景。此外,虽然 BQML 提供了一系列用于评估模型性能的指标,但用户可能需要进行额外的分析才能完全理解他们模型的有效性。
尽管存在这些局限性,BQML 仍然是数据科学家和分析人员快速轻松构建和部署 ML 模型的有力工具。它与 BigQuery 和其他 GCP 服务的集成使其成为需要处理大量数据的公司和组织的一个很好的选择,而其对广泛模型和指标的支持使其成为各种用例的多功能工具。
总体而言,BQML 是 GCP 中可用的 ML 工具套件中的一个宝贵补充。它的低代码界面、与 BigQuery 的集成以及对广泛模型的支撑,使其成为数据科学家和分析人员的一个很好的选择,他们希望专注于数据和洞察,而不是复杂的代码和基础设施。使用 BQML,用户可以快速轻松地构建和部署模型,从而从他们的数据中提取有价值的见解并做出数据驱动的决策。
在下一章中,我们将探讨如何在 Vertex AI 上使用其无服务器训练功能来训练完全自定义的 TensorFlow 深度学习模型。这一章还将深入探讨使用 TensorFlow 构建模型、打包以提交给 Vertex AI、监控训练进度以及评估训练后的模型。
第七章:使用 Vertex AI 训练完全自定义的 ML 模型
在前面的章节中,我们学习了如何使用最小技术专长训练无代码(Auto-ML)以及低代码(BQML)机器学习(ML)模型。当解决常见的机器学习问题时,这些解决方案非常实用。然而,有时问题或数据本身非常复杂,需要开发自定义的人工智能(AI)模型,在大多数情况下是大型基于深度学习的模型。在自定义模型上工作需要机器学习、深度学习和人工智能领域的显著技术专长。有时,即使拥有这种专长,由于资源、计算能力和适当的元数据跟踪机制不足,管理大规模自定义深度学习模型的训练和实验也变得非常困难。
为了使机器学习开发者的生活更轻松,Vertex AI 提供了一个托管环境,用于启动大规模的自定义训练作业。Vertex AI 管理的作业让我们能够跟踪有用的元数据,通过 Google Cloud 控制台 UI 监控作业,并且无需主动监控即可启动大规模批量推理作业。在本章中,我们将学习如何在 Google Vertex AI 上使用自定义深度学习模型。具体来说,我们将涵盖以下主题:
-
使用 TensorFlow 构建基本的深度学习模型
-
将模型打包以提交给 Vertex AI 进行训练作业
-
监控模型训练进度
-
评估训练后的模型
技术要求
本章需要具备深度学习框架 TensorFlow 和神经网络的入门级知识。代码工件可以在以下 GitHub 仓库中找到 - github.com/PacktPublishing/The-Definitive-Guide-to-Google-Vertex-AI/tree/main/Chapter07
使用 TensorFlow 构建基本的深度学习模型
TensorFlow,简称TF,是一个用于构建机器学习模型的端到端平台。TensorFlow 框架的主要重点是简化深度神经网络的开发、训练、评估和部署。当涉及到处理非结构化数据(例如图像、视频、音频等)时,基于神经网络的解决方案比主要依赖于手工特征的传统的机器学习方法取得了显著更好的结果。深度神经网络擅长从高维数据点中理解复杂模式(例如,包含数百万像素的图像)。在本节中,我们将使用 TensorFlow 开发一个基本的基于神经网络的模型。在接下来的几节中,我们将看到 Vertex AI 如何帮助设置可扩展和系统化的自定义模型训练/调优。
重要提示
需要注意的是,TensorFlow 并不是 Vertex AI 支持的唯一机器学习框架。Vertex AI 支持许多不同的机器学习框架和开源项目,包括 Pytorch、Spark 和 XGBoost。Pytorch 是增长最快的机器学习框架之一,借助 Vertex AI 的 Pytorch 集成,我们可以轻松地在生产环境中训练、部署和编排 PyTorch 模型。Vertex AI 提供了预构建的训练和托管容器,并支持 PyTorch 模型的优化分布式训练。同样,Vertex AI 为包括 XGBoost、TensorFlow、Pytorch 和 Scikit-learn 在内的多个机器学习框架提供了预构建的训练、托管和可解释性功能。
实验 – 将黑白图像转换为彩色图像
在这个实验中,我们将开发一个基于 TensorFlow 的深度学习模型,该模型以黑白图像为输入,并将它们转换为彩色图像。由于这个练习需要开发一个自定义模型,我们将从 Jupyter Notebook 中的初始开发工作开始。第一步是在 Vertex AI Workbench 中使用预配置的 TensorFlow 图像创建一个用户管理的 Jupyter Notebook。有关如何成功创建 Vertex AI Workbench 笔记本实例的更多详细信息,请参阅第四章,Vertex AI Workbench。接下来,让我们从 JupyterLab 应用程序启动一个 Jupyter Notebook。我们现在已经准备好开始我们的实验了。
我们将在笔记本的第一个单元格中开始导入有用的库(预构建的 Python 包)。在这个实验中,我们将使用以下 Python 库 – numpy
用于多维数组操作,TensorFlow 用于开发深度学习模型,OpenCV(或cv2
)用于图像处理,以及matplotlib
用于绘制图像或图表:
import numpy as np
import tensorflow
import glob
import cv2
import matplotlib.pyplot as plt
%matplotlib inline
我们需要一个包含至少几千张图像的图像数据集来训练和测试我们的模型。在这个实验中,我们将使用Oxford-IIIT Pet数据集,这是一个公开且免费使用的数据集。该数据集包含来自 30 多个不同标注类别的约 7k 张宠物图像。数据集可以从以下网站下载:www.robots.ox.ac.uk/~vgg/data/pets/
。
我们也可以使用以下终端命令下载这个数据集:
wget https://thor.robots.ox.ac.uk/~vgg/data/pets/images.tar.gz
wget https://thor.robots.ox.ac.uk/~vgg/data/pets/annotations.tar.gz
下载完成后,将压缩文件放在与我们的笔记本相同的目录中。现在,让我们在笔记本单元格中创建一个!
符号,这样我们就可以在 Jupyter Notebook 中运行终端命令了):
!mkdir data
!tar -xf images.tar.gz -C data
!mkdir labels
!tar -xf annotations.tar.gz -C labels
由于我们当前的实验是关于将黑白图像转换为彩色版本,我们将不会使用标注。现在,让我们快速在一个新单元格中验证是否已成功将所有图像复制到data文件夹中:
all_image_files = glob.glob("data/images/*.jpg")
print("Total number of image files : ", \
len(all_image_files))
在这里,glob
模块通过列出数据目录内所有的.jpg
图像路径来帮助我们。这个列表的长度将与图像数量相等。前面的代码应该打印出以下输出:
Total number of image files : 7390
现在我们已经成功下载并提取了数据,让我们检查一些图像以确保一切正常。下面的代码块将绘制一些带有注释的随机图像:
for i in range(3):
plt.figure(figsize=(13, 13))
for j in range(6):
img_path = np.random.choice(all_image_files)
img = cv2.imread(img_path)
img_class = img_path.split("/")[-1].split("_")[0]
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.subplot(660 + 1 + j)
plt.imshow(img)
plt.axis('off')
plt.title(img_class)
plt.show()
在这里,我们通过从图像路径名称本身提取图像类别(或注释),因为所有图像的文件名中都有宠物类别。前面代码的输出应该类似于图 7.1中所示。
图 7.1 – 宠物数据集的一些样本
现在我们已经验证了我们的数据集,让我们将这些图像分成三个集合——训练集、验证集和测试集——就像我们通常为训练/验证和测试机器学习模型所做的那样。我们将保留 60%的图像用于训练,20%用于验证,剩下的 20%用于测试。完成这些分割的一个简单方法如下:
train_files = all_image_files[:int( \
len(all_image_files)*0.6)]
validation_files = all_image_files[int( \
len(all_image_files)*0.6):int(len(all_image_files)*0.8)]
test_files = all_image_files[int( \
len(all_image_files)*0.8):]
print(len(train_files), len(validation_files), \
len(test_files))
本实验的主要重点是开发一个深度学习模型,该模型可以将黑白图像转换为彩色图像。为了学习这种映射,模型将需要黑白图像及其对应的彩色版本对来学习这种映射。我们的数据集已经包含了彩色图像。我们将利用 OpenCV 库将它们转换为灰度(黑白)图像,并将它们作为模型输入。我们将比较输出与它们的彩色版本。需要注意的是,我们的深度学习模型将接受固定大小的图像作为输入,因此我们还需要将所有输入图像调整到相同的分辨率。在我们的实验中,我们将所有图像的分辨率更改为 80x80。我们已经有图像路径的训练、验证和测试分割。我们现在可以读取这些文件,为训练、验证和测试准备数据。下面的代码块可以用来准备之前描述的数据集。
让我们先定义空列表来分别存储训练、验证和测试数据:
train_x = []
train_y = []
val_x = []
val_y = []
test_x = []
test_y = []
在这里,我们读取训练图像,将它们调整到所需的大小,为每个图像创建一个黑白版本,并将它们存储为目标图像:
for file in train_files:
try:
img = cv2.imread(file)
img = cv2.resize(img, (80,80))
color_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
black_n_white_img = cv2.cvtColor(color_img, \
cv2.COLOR_RGB2GRAY)
except:
continue
train_x.append((black_n_white_img-127.5)/127.5)
train_y.append((color_img-127.5)/127.5)
同样,我们对验证文件重复相同的流程:
for file in validation_files:
try:
img = cv2.imread(file)
img = cv2.resize(img, (80,80))
color_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
black_n_white_img = cv2.cvtColor(color_img, \
cv2.COLOR_RGB2GRAY)
except:
continue
val_x.append((black_n_white_img-127.5)/127.5)
val_y.append((color_img-127.5)/127.5)
现在,以类似的方式准备测试文件:
for file in test_files:
try:
img = cv2.imread(file)
img = cv2.resize(img, (80,80))
color_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
black_n_white_img = cv2.cvtColor(color_img, \
cv2.COLOR_RGB2GRAY)
except:
continue
test_x.append((black_n_white_img-127.5)/127.5)
test_y.append((color_img-127.5)/127.5)
注意,图像是用 0 到 255 之间的像素值表示的。我们通过减去并除以 127.5 来归一化像素值,并将它们带入[-1, 1]的范围内。数据归一化使得深度学习模型的优化更加平滑和稳定。
现在我们已经成功地将数据集准备好,包括训练集、验证集和测试集的分割,让我们检查一些样本以确认数据已经被正确准备。下面的代码块选择了一些随机的训练集图像并将它们绘制出来。
让我们绘制一些输入图像,以了解数据:
# input images
indexes = np.random.choice(range(0,4000), size=3)
print("Input Samples (black and white): ")
plt.figure(figsize=(7,7))
for i in range(3):
plt.subplot(330+1+i)
plt.imshow((train_x[indexes[i]]+1.0)/2.0, cmap='gray')
plt.axis('off')
plt.show()
我们还将绘制这些随机选择的图像的输出版本(彩色版本):
# corresponding output images
print("Output Samples (colored): ")
plt.figure(figsize=(7,7))
for i in range(3):
plt.subplot(330+1+i)
plt.imshow((train_y[indexes[i]]+1.0)/2.0)
plt.axis('off')
plt.show()
如果一切正确,我们应该看到输入-输出对图像与图 7**.2中的非常相似。
图 7.2 – 数据验证的样本输入-输出对
由于我们在这里处理图像数据,我们将使用基于卷积神经网络(CNN)的模型,以便我们可以从图像数据中提取有用的特征。当前的研究表明,CNN 在从图像数据中提取特征和其他有用信息方面非常有用。由于我们将在这里使用 CNN,我们需要将我们的图像数据集转换为 NumPy 数组,并且还需要为每个黑白输入图像添加一个通道维度(CNN 接受图像输入为一个三维数组,每个维度分别对应宽度、高度和通道)。彩色图像已经具有三个通道,每个通道对应一个颜色值 – R、G 和 B。以下代码块根据之前描述的步骤准备我们的最终数据集:
train_x = np.expand_dims(np.array(train_x),-1)
val_x = np.expand_dims(np.array(val_x),-1)
test_x = np.expand_dims(np.array(test_x),-1)
train_y = np.array(train_y)
val_y = np.array(val_y)
test_y = np.array(test_y)
现在,再次检查我们数据集分割的维度:
print(train_x.shape, train_y.shape, val_x.shape, \
val_y.shape, test_x.shape, test_y.shape)
应该打印出类似以下内容:
(4430, 80, 80, 1) (4430, 80, 80, 3) (1478, 80, 80, 1) (1478, 80, 80, 3) (1476, 80, 80, 1) (1476, 80, 80, 3)
从数据角度来看,一切看起来都很不错。让我们跳转到定义我们的神经网络架构。
在这个实验中,我们将定义一个基于 TensorFlow 的 CNN,它以黑白图像为输入,并预测它们的彩色变体作为输出。模型架构可以大致分为两部分 – 编码器和解码器。模型的编码器部分以黑白图像为输入,并通过四个下采样卷积层从中提取有用的特征。每个卷积层后面跟着 LeakyReLU 激活层和批归一化层,除了最后一层,它用dropout层代替了批归一化层。通过编码器模型后,一个尺寸为(80, 80, 1)的输入图像变成了一个尺寸为(5, 5, 256)的特征向量。
模型的第二部分被称为解码器。解码器部分从编码器的输出中获取特征向量,并将其转换回对应输入图像的彩色版本。解码器由四个转置卷积或上采样层组成。每个解码器层后面跟着 ReLU 激活层和批归一化层,除了最后一层,它有 tanh 激活而没有归一化层。tanh 激活将最终输出向量的值限制在[-1,1]的范围内,这是我们输出图像所期望的。
以下代码块定义了 TensorFlow 模型:
def tf_model():
black_n_white_input = tensorflow.keras.layers.Input( \
shape=(80, 80, 1))
enc = black_n_white_input
编码器部分从这里开始,在同一个函数内:
#Encoder part
enc = tensorflow.keras.layers.Conv2D(32, kernel_size=3, \
strides=2, padding='same')(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(enc)
enc = tensorflow.keras.layers.Conv2D(64, kernel_size=3, \
strides=2, padding='same')(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(enc)
enc = tensorflow.keras.layers.Conv2D(128, \
kernel_size=3, strides=2, padding='same')(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(enc)
enc = tensorflow.keras.layers.Conv2D(256, \
kernel_size=1, strides=2, padding='same')(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.Dropout(0.5)(enc)
解码器部分从这里开始,在同一个函数内:
#Decoder part
dec = enc
dec = tensorflow.keras.layers.Conv2DTranspose(256, \
kernel_size=3, strides=2, padding='same')(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
dec = tensorflow.keras.layers.Conv2DTranspose(128, \
kernel_size=3, strides=2, padding='same')(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
dec = tensorflow.keras.layers.Conv2DTranspose(64, \
kernel_size=3, strides=2, padding='same')(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
dec = tensorflow.keras.layers.Conv2DTranspose(32, \
kernel_size=3, strides=2, padding='same')(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
dec = tensorflow.keras.layers.Conv2D(3, kernel_size=3,\
padding='same')(dec)
最后,添加 tanh 激活函数以获得所需输出的彩色图像:
color_image = tensorflow.keras.layers.Activation('tanh')(dec)
return black_n_white_input, color_image
现在,让我们创建一个 TensorFlow 模型对象并打印我们模型的摘要:
black_n_white_input, color_image = tf_model()
model = tensorflow.keras.models.Model( \
inputs=black_n_white_input, outputs=color_image)
model.summary()
这应该会打印出如图图 7.3所示的模型摘要。
图 7.3 – TensorFlow 模型摘要(在 GitHub 上查看完整摘要)
从摘要中我们可以看出,我们的模型大约有 110 万个可训练参数。下一步是编译 TensorFlow 模型:
_optimizer = tensorflow.keras.optimizers.Adam(\
learning_rate=0.0002, beta_1=0.5)
model.compile(loss='mse', optimizer=_optimizer)
我们使用学习率为 0.0002 的 Adam 优化器以及值为 0.5 的beta_1
参数。在这里,beta_1
代表第一矩估计的指数衰减率,学习率告诉优化器在训练期间更新模型参数值的速率。其余的参数值保持默认。我们的想法是传递一个黑白图像并重建其彩色版本,因此我们将使用均方误差(MSE)作为像素级别的重建损失函数。
现在我们已经准备好开始训练了。我们将在这个实验中使用 128 个批次的尺寸,训练模型大约 100 个周期,并检查结果。以下代码片段开始训练:
history = model.fit(
train_x,
train_y,
batch_size=128,
epochs=100,
validation_data=(val_x, val_y),
)
输出日志应类似于以下内容:
Epoch 1/100
35/35 [==============================] - 25s 659ms/step - loss: 0.2940 - val_loss: 0.1192
Epoch 2/100
35/35 [==============================] - 20s 585ms/step - loss: 0.1117 - val_loss: 0.0917
Epoch 3/100
35/35 [==============================] - 20s 580ms/step - loss: 0.0929 - val_loss: 0.0784
Epoch 4/100
35/35 [==============================] - 20s 577ms/step - loss: 0.0832 - val_loss: 0.0739
Epoch 5/100
35/35 [==============================] - 20s 573ms/step - loss: 0.0778 - val_loss: 0.0698
. . . . .
. . . . .
. . . . .
. . . . .
Epoch 100/100
35/35 [==============================] - 20s 559ms/step - loss: 0.0494 - val_loss: 0.0453
为了检查我们的训练是否顺利,我们可以查看history
变量中的损失图表:
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'val'], loc='upper right')
plt.show()
前面的代码片段将绘制所有训练周期的训练和验证损失作为折线图。输出图表应类似于图 7.4。正如我们所见,随着训练的进行,训练和验证损失持续下降。我们的训练朝着正确的方向进行,这让人感到放心。
图 7.4 – 训练和验证损失
最后一步是检查一个未见过的测试数据集上的结果。以下代码从test_set
中选择一些随机样本并为它们生成模型输出。我们还绘制了输入图像、模型生成的彩色图像和实际彩色图像,以便理解。
samples = np.random.choice(range(0, len(test_files)), size=5)
绘制几个测试图像以验证模型输出:
# show input images
print("Black-n-White Input images!")
plt.figure(figsize=(8,8))
for i in range(5):
plt.subplot(550+1+i)
plt.imshow((test_x[samples[i]]+1.0)/2.0, cmap='gray')
plt.axis('off')
plt.show()
在这里,模型生成一个彩色版本:
# generate color images from model
print("Model Outputs!")
plt.figure(figsize=(8,8))
for i in range(5):
plt.subplot(550+1+i)
model_input = test_x[samples[i]]
output = model.predict(np.array([model_input]))
plt.imshow((output[0]+1.0)/2.0)
plt.axis('off')
plt.show()
此外,还可以绘制一个参考的彩色版本:
# show real color output images
print("Real Color Version!")
plt.figure(figsize=(8,8))
for i in range(5):
plt.subplot(550+1+i)
plt.imshow((test_y[samples[i]]+1.0)/2.0)
plt.axis('off')
plt.show()
当绘制模型输出或输入图像时,我们将 1.0 加到图像数组上,然后除以 2.0。我们这样做是因为在数据预处理过程中,我们将图像像素值归一化到[-1,1]的范围内。但理想情况下,图像像素值不能为负,因此我们需要对图像绘制目的进行逆变换。所以,加 1.0 并除以 2.0 将像素值带入[0,1]的范围内,这是 Matplotlib 绘图所支持的。参见图 7.5。
图 7.5 – 黑白到彩色模型输出
如前所述的输出所示,我们的模型正在学习某种着色,这当然不是理想的,但看起来仍然相当不错。一个有趣的现象是它不是随机填充颜色渐变;我们可以清楚地看到主要对象,因为它们与背景有不同的对比度。鉴于我们有一个非常小的模型和小的训练数据集,这种性能相当有希望。
然而,这并不是解决图像着色问题的最佳模型架构。如今,生成模型如 生成对抗网络(GANs)为这类问题提供了最佳结果。我们将在本书的后面部分研究 GANs,但现在,让我们继续这个简单的实验。接下来,我们将使用其他 Vertex AI 工具,这些工具将使我们的实验更容易进行。
将模型打包以提交给 Vertex AI 作为训练作业
上一节演示了在 Vertex AI Workbench 笔记本上进行的小型图像着色实验。笔记本非常适合小规模和快速实验,但当涉及到大规模实验(具有更多的计算和/或内存需求)时,建议将其作为 Vertex AI 作业启动,并指定所需的机器规格(如果需要,指定加速器如 GPU 或 TPU)以实现最佳实验。Vertex AI 作业还允许我们并行执行大量实验,而无需等待单个实验的结果。使用 Vertex AI 作业进行实验跟踪也非常简单,因此,借助保存的元数据和 Vertex AI UI,比较您最新的实验与过去的实验变得更加容易。现在,让我们使用上一节中的模型实验设置,并将其作为 Vertex AI 训练作业启动。
重要注意事项
Vertex AI 作业在容器化环境中运行,因此为了启动一个实验,我们必须将我们的整个代码(包括读取数据、预处理、模型构建、训练和评估)打包成一个在容器内运行的单一脚本。Google Cloud 提供了大量的预构建容器镜像用于训练和评估(预先安装了所需的框架依赖,如 TensorFlow、PyTorch 等)。此外,我们还可以灵活地定义我们自己的自定义容器,包含我们可能需要的任何类型的依赖。
对于上一节中的实验,由于我们将开源数据下载到我们的 Jupyter 环境中,这些数据尚未存在于 Google Cloud Storage(GCS)(即 GCS 存储桶或 BigQuery)。因此,首先,我们需要将这些数据存储在某个地方,以便我们的 Vertex AI 训练作业可以在训练容器内读取它。为了让我们更容易操作,我们将我们的预处理数据上传到存储桶中。这将节省我们在作业容器内再次准备数据的精力。我们可以使用以下脚本将我们的准备数据保存到 GCS 存储桶中:
from io import BytesIO
import numpy as np
from tensorflow.python.lib.io import file_io
dest = 'gs://data-bucket-417812395597/' # Destination to save in GCS
## saving training data
np.save(file_io.FileIO(dest+'train_x', 'w'), train_x)
np.save(file_io.FileIO(dest+'train_y', 'w'), train_y)
## saving validation data
np.save(file_io.FileIO(dest+'val_x', 'w'), val_x)
np.save(file_io.FileIO(dest+'val_y', 'w'), val_y)
## saving test data
np.save(file_io.FileIO(dest+'test_x', 'w'), test_x)
np.save(file_io.FileIO(dest+'test_y', 'w'), test_y)
注意,在执行此代码之前,我们必须创建一个存储桶,用于存储这些 NumPy 数组。在这种情况下,我们已创建了一个名为 data-bucket-417812395597
的存储桶。
我们可以使用以下脚本在任意数量的训练作业/实验中读取这些 NumPy 数组:
train_x = np.load(BytesIO(file_io.read_file_to_string( \
dest+'train_x', binary_mode=True)))
train_y = np.load(BytesIO(file_io.read_file_to_string( \
dest+'train_y', binary_mode=True)))
val_x = np.load(BytesIO(file_io.read_file_to_string( \
dest+'val_x', binary_mode=True)))
val_y = np.load(BytesIO(file_io.read_file_to_string( \
dest+'val_y', binary_mode=True)))
test_x = np.load(BytesIO(file_io.read_file_to_string( \
dest+'test_x', binary_mode=True)))
test_y = np.load(BytesIO(file_io.read_file_to_string( \
dest+'test_y', binary_mode=True)))
我们的数据需求现在已经全部设置好了。接下来,让我们着手设置我们的 Vertex AI 训练作业。
首先,我们将安装一些必要的包,这些包用于定义和启动 Vertex AI 作业:
# Install the packages
! pip3 install --upgrade google-cloud-aiplatform \
google-cloud-storage \
pillow
一旦完成包安装,我们将转到一个新的笔记本并导入有用的库:
import numpy as np
import glob
import matplotlib.pyplot as plt
import os
from google.cloud import aiplatform
%matplotlib inline
接下来,我们将定义我们的项目配置:
PROJECT_ID='41xxxxxxxxx7'
REGION='us-west2'
BUCKET_URI='gs://my-training-artifacts'
注意,我们已经创建了一个名为 my-training-artifacts
的存储桶,用于存储 Vertex AI 作业产生的所有中间元数据和工件。
接下来,让我们使用我们的项目配置初始化 Vertex AI SDK:
aiplatform.init(project=PROJECT_ID, location=REGION, \
staging_bucket=BUCKET_URI)
对于我们的实验,我们将使用预构建的 TensorFlow 图像作为我们的模型也是基于 TensorFlow。让我们定义要使用的图像:
TRAIN_VERSION = "tf-cpu.2-9"
DEPLOY_VERSION = "tf2-cpu.2-9"
TRAIN_IMAGE = "us-docker.pkg.dev/vertex-ai/training/{}:latest".format(TRAIN_VERSION)
DEPLOY_IMAGE = "us-docker.pkg.dev/vertex-ai/prediction/{}:latest".format(DEPLOY_VERSION)
在本节中,我们只是启动一个简单的训练作业。在下一节中,我们还将部署和测试我们的训练好的模型。
接下来,让我们为训练定义一些命令行参数(这些可以根据需要修改):
JOB_NAME = "vertex_custom_training"
MODEL_DIR = "{}/{}".format(BUCKET_URI, JOB_NAME)
TRAIN_STRATEGY = "single"
EPOCHS = 20
STEPS = 100
CMDARGS = [
"--epochs=" + str(EPOCHS),
"--steps=" + str(STEPS),
"--distribute=" + TRAIN_STRATEGY,
]
我们还应该提供一个有意义的作业名称;这将帮助我们区分我们的实验与其他并行运行的实验。
下一步是写下我们的整个训练脚本——从读取数据、定义模型、训练到将模型保存到一个文件中。我们将把上一节中的整个代码写入一个名为 task.py
的文件。以下是我们 task.py
文件的内容:
%%writefile task.py
# Single, Mirror and Multi-Machine Distributed Training
import tensorflow as tf
import tensorflow
from tensorflow.python.client import device_lib
import argparse
import os
import sys
from io import BytesIO
import numpy as np
from tensorflow.python.lib.io import file_io
文件的下述部分解析命令行参数:
# parse required arguments
parser = argparse.ArgumentParser()
parser.add_argument('--lr', dest='lr', \
default=0.001, type=float, \
help='Learning rate.')
parser.add_argument('--epochs', dest='epochs', \
default=10, type=int, \
help='Number of epochs.')
parser.add_argument('--steps', dest='steps', \
default=35, type=int, \
help='Number of steps per epoch.')
parser.add_argument('--distribute', dest='distribute', \
type=str, default='single', \
help='distributed training strategy')
args = parser.parse_args()
在这里,我们打印一些版本和环境配置以跟踪当前设置:
print('Python Version = {}'.format(sys.version))
print('TensorFlow Version = {}'.format(tf.__version__))
print('TF_CONFIG = {}'.format(os.environ.get('TF_CONFIG', \
'Not found')))
print('DEVICES', device_lib.list_local_devices())
在这里,我们定义了一个训练策略:
# Single Machine, single compute device
if args.distribute == 'single':
if tf.test.is_gpu_available():
strategy = tf.distribute.OneDeviceStrategy(device="/gpu:0")
else:
strategy = tf.distribute.OneDeviceStrategy(device="/cpu:0")
# Single Machine, multiple compute device
elif args.distribute == 'mirror':
strategy = tf.distribute.MirroredStrategy()
# Multiple Machine, multiple compute device
elif args.distribute == 'multi':
strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy()
# Multi-worker configuration
print('num_replicas_in_sync = {}'.format(strategy.num_replicas_in_sync))
现在,我们准备用于训练、验证和测试的数据集:
# Preparing dataset
BUFFER_SIZE = 10000
BATCH_SIZE = 128
def make_datasets_unbatched():
# Load train, validation and test sets
dest = 'gs://data-bucket-417812395597/'
train_x = np.load(BytesIO(
file_io.read_file_to_string(dest+'train_x', \
binary_mode=True)
))
train_y = np.load(BytesIO(
file_io.read_file_to_string(dest+'train_y', \
binary_mode=True)
))
val_x = np.load(BytesIO(
file_io.read_file_to_string(dest+'val_x', \
binary_mode=True)
))
val_y = np.load(BytesIO(
file_io.read_file_to_string(dest+'val_y', \
binary_mode=True)
))
test_x = np.load(BytesIO(
file_io.read_file_to_string(dest+'test_x', \
binary_mode=True)
))
test_y = np.load(BytesIO(
file_io.read_file_to_string(dest+'test_y', \
binary_mode=True)
))
return train_x, train_y, val_x, val_y, test_x, test_y
现在,我们像之前讨论的那样定义我们的 TensorFlow 模型:
def tf_model():
black_n_white_input = tensorflow.keras.layers.Input(shape=(80, 80, 1))
enc = black_n_white_input
这里是 TF 模型编码器部分的定义:
#Encoder part
enc = tensorflow.keras.layers.Conv2D(
32, kernel_size=3, strides=2, padding='same'
)(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(enc)
enc = tensorflow.keras.layers.Conv2D(
64, kernel_size=3, strides=2, padding='same'
)(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(enc)
enc = tensorflow.keras.layers.Conv2D(
128, kernel_size=3, strides=2, padding='same'
)(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(enc)
enc = tensorflow.keras.layers.Conv2D(
256, kernel_size=1, strides=2, padding='same'
)(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.Dropout(0.5)(enc)
编码器部分现在已经完成。接下来,我们在同一个函数中定义模型的解码器部分:
#Decoder part
dec = enc
dec = tensorflow.keras.layers.Conv2DTranspose(
256, kernel_size=3, strides=2, padding='same'
)(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
dec = tensorflow.keras.layers.Conv2DTranspose(
128, kernel_size=3, strides=2, padding='same'
)(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
dec = tensorflow.keras.layers.Conv2DTranspose(
64, kernel_size=3, strides=2, padding='same'
)(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
dec = tensorflow.keras.layers.Conv2DTranspose(
32, kernel_size=3, strides=2, padding='same'
)(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
dec = tensorflow.keras.layers.Conv2D(
3, kernel_size=3, padding='same'
)(dec)
Here, we apply tanh activation function to get the colored output image -
color_image = tensorflow.keras.layers.Activation('tanh')(dec)
return black_n_white_input, color_image
现在,我们已经准备好构建和编译我们的 TensorFlow 模型:
# Build the and compile TF model
def build_and_compile_tf_model():
black_n_white_input, color_image = tf_model()
model = tensorflow.keras.models.Model(
inputs=black_n_white_input,
outputs=color_image
)
_optimizer = tensorflow.keras.optimizers.Adam(
learning_rate=0.0002,
beta_1=0.5
)
model.compile(
loss='mse',
optimizer=_optimizer
)
return model
下面的代码块使用定义的设置启动训练,并将训练好的模型保存下来:
# Train the model
NUM_WORKERS = strategy.num_replicas_in_sync
# Here the batch size scales up by number of workers since
# `tf.data.Dataset.batch` expects the global batch size.
GLOBAL_BATCH_SIZE = BATCH_SIZE * NUM_WORKERS
MODEL_DIR = os.getenv("AIP_MODEL_DIR")
train_x, train_y, _, _, _, _ = make_datasets_unbatched()
with strategy.scope():
# Creation of dataset, and model building/compiling need to be within
# `strategy.scope()`.
model = build_and_compile_tf_model()
model.fit(
train_x,
train_y,
epochs=args.epochs,
steps_per_epoch=args.steps
)
model.save(MODEL_DIR)
现在我们已经设置了所有配置,并且我们的训练脚本 task.py
已经准备好了,我们就可以定义并启动我们的自定义训练作业在 Vertex AI 上。
让我们定义我们的自定义 Vertex AI 训练作业:
job = aiplatform.CustomTrainingJob(
display_name=JOB_NAME,
script_path="task.py",
container_uri=TRAIN_IMAGE,
requirements=[],
model_serving_container_image_uri=DEPLOY_IMAGE,
)
最后一步是启动作业:
MODEL_DISPLAY_NAME = "tf_bnw_to_color"
# Start the training job
model = job.run(
model_display_name=MODEL_DISPLAY_NAME,
args=CMDARGS,
machine_type = "n1-standard-16",
replica_count=1,
)
此设置在 n1-standard-16
机器上启动一个 Vertex AI 自定义训练作业,正如前面 job.run
方法中定义的参数。当我们在一个笔记本单元中启动作业时,它给我们一个 Google Cloud 控制台 UI 的 URL。通过点击它,我们可以在 Vertex AI UI 中监控我们的作业日志。
Vertex AI 训练作业在 Google Cloud 控制台 UI 中看起来类似于 图 7**.6。在这里,我们可以重新验证我们在启动时定义的作业配置和参数:
图 7.6 – Vertex AI 训练作业
Vertex AI UI 允许我们监控所有训练/定制作业的近乎实时日志。我们可以在 UI 中监控我们的训练,看起来类似于 图 7**.7:
图 7.7 – Google Cloud 控制台上的 Vertex AI 训练作业实时日志
通过日志来监控训练进度可能不是最佳方式,因为我们可能想要跟踪一些参数,例如损失和准确度。在下一节中,我们将学习如何设置基于 TensorBoard 的实时监控训练进度。然而,这些日志对于调试目的来说确实非常有用;如果我们的管道在执行成功完成之前失败,我们总是可以检查这些日志来识别根本原因。
监控模型训练进度
在上一节中,我们看到了如何轻松地使用所需的配置和机器类型启动 Vertex AI 定制训练作业。这些 Vertex AI 训练作业对于运行需要高计算能力(多个 GPU 或 TPUs)的大型实验非常有用,这些实验可能需要运行几天。在基于 Jupyter Notebook 的环境中运行这种长时间运行的实验并不可行。启动 Vertex AI 作业的另一个优点是,所有元数据和血缘关系都以系统化的方式跟踪,这样我们就可以稍后回来查看过去的实验,并以简单准确的方式与最新的实验进行比较。
另一个重要方面是监控训练作业的实时进度(包括损失和准确度等指标)。为此,我们可以在 Vertex AI 作业中轻松设置 Vertex AI TensorBoard,并以近乎实时的方式跟踪进度。在本节中,我们将为之前的实验设置一个 TensorBoard 实例。
大多数代码/脚本将与上一节相似。在这里,我们只需检查设置 TensorBoard 监控所需的修改。
首先,我们需要在 task.py
文件中进行一些小的修改,以考虑 TensorFlow 回调,因为我们想监控训练损失。为了保持整洁,我们将修改一个重命名为 task2.py
的 task.py
文件副本。以下是在 model.fit
函数中的更改:
### Create a TensorBoard callback and write to the gcs path provided by AIP_TENSORBOARD_LOG_DIR
tensorboard_callback = tf.keras.callbacks.TensorBoard(
log_dir=os.environ['AIP_TENSORBOARD_LOG_DIR'],
histogram_freq=1)
model.fit(
train_x,
train_y,
epochs=args.epochs,
steps_per_epoch=args.steps,
callbacks=[tensorboard_callback],
)
在前面的脚本中,我们只定义了一个 TensorFlow 回调对象,并将其传递到 model.fit
函数中。
使用 TensorBoard 需要一个服务账户(而不是个人用户账户)。如果我们还没有设置服务账户,我们可以使用以下脚本快速设置一个服务账户。服务账户用于在 Google Cloud 上授予服务、虚拟机和其他工具的权限:
SERVICE_ACCOUNT="dummy-sa"
IS_COLAB=False
if (
SERVICE_ACCOUNT == ""
or SERVICE_ACCOUNT is None
or SERVICE_ACCOUNT == "dummy-sa"
):
# Get your service account from gcloud
if not IS_COLAB:
shell_output = ! gcloud auth list 2>/dev/null
SERVICE_ACCOUNT = shell_output[2].replace("*", \
"").strip()
如果我们在使用 colab,以下代码片段将相应地创建一个服务账户:
else: # IS_COLAB:
shell_output = ! gcloud projects describe $PROJECT_ID
project_number = shell_output[-1].split(":")[1].strip().replace("'", "")
SERVICE_ACCOUNT = f"{project_number}-compute@developer.gserviceaccount.com"
print("Service Account:", SERVICE_ACCOUNT)
下一步是创建一个我们将用于监控训练的 Vertex AI TensorBoard 实例。
设置 TensorBoard 实例:
TENSORBOARD_NAME = "training-monitoring" # @param {type:"string"}
if (
TENSORBOARD_NAME == ""
or TENSORBOARD_NAME is None
or TENSORBOARD_NAME == "training-monitoring"
):
TENSORBOARD_NAME = PROJECT_ID + "-tb-" + TIMESTAMP
tensorboard = aiplatform.Tensorboard.create(
display_name=TENSORBOARD_NAME, project=PROJECT_ID, \
location=REGION
)
Let's verify if the TensorBoard instance was successfully created or not - TENSORBOARD_RESOURCE_NAME = tensorboard.gca_resource.name
print("TensorBoard resource name:", TENSORBOARD_RESOURCE_NAME)
我们需要一个用于我们的 Vertex AI 作业的临时存储桶,以便它可以将事件日志写入该位置:
BUCKET_URI = "gs://tensorboard-staging" # @param {type:"string"}
if BUCKET_URI == "" or BUCKET_URI is None or BUCKET_URI == "gs://[your-bucket-name]":
BUCKET_URI = "gs://" + PROJECT_ID + "aip-" + TIMESTAMP
! gsutil mb -l {REGION} -p {PROJECT_ID} {BUCKET_URI}
GCS_BUCKET_OUTPUT = BUCKET_URI + "/output/"
我们现在已经准备好定义我们的自定义训练作业:
JOB_NAME = "tensorboard-example-job-{}".format(TIMESTAMP)
BASE_OUTPUT_DIR = "{}{}".format(GCS_BUCKET_OUTPUT, JOB_NAME)
job = aiplatform.CustomTrainingJob(
display_name=JOB_NAME,
script_path="task2.py",
container_uri=TRAIN_IMAGE,
requirements=[],
model_serving_container_image_uri=DEPLOY_IMAGE,
staging_bucket=BASE_OUTPUT_DIR,
)
我们现在可以使用以下脚本启动 Vertex AI 作业。在这里,我们可以选择机器类型,还可以指定replica_count
参数,该参数控制当前作业要运行的副本数量:
MODEL_DISPLAY_NAME = "tf_bnw_to_color_tb"
# Start the training job
model = job.run(
model_display_name=MODEL_DISPLAY_NAME,
service_account=SERVICE_ACCOUNT,
tensorboard=TENSORBOARD_RESOURCE_NAME,
args=CMDARGS,
machine_type = "n1-standard-8",
replica_count=1,
)
一旦我们启动作业,它将给我们一个 URL,用于在 Google Cloud 控制台 UI 中定位 Vertex AI 作业,就像上一节中那样;但这次,它还会给我们一个指向 Vertex TensorBoard UI 的 URL。使用这个 URL,我们将能够以近乎实时的方式监控我们的训练。
这就是我们的小实验看起来像什么(见图 7.8):
图 7.8 – 用于实时监控实验的 Vertex TensorBoard
我们可以配置它以显示更多我们实验中所需的指标。现在我们能够启动 Vertex AI 训练、监控它,并且还能保存我们的 TensorFlow 训练模型,让我们继续到模型评估部分。
评估训练模型
在本节中,我们将从上一节中提取已经训练好的模型,并在测试数据上启动一个批量推理作业。这里的第一个步骤将是将我们的测试数据加载到 Jupyter Notebook 中:
from io import BytesIO
import numpy as np
from tensorflow.python.lib.io import file_io
dest = 'gs://data-bucket-417812395597/'
test_x = np.load(BytesIO(file_io.read_file_to_string(dest+'test_x',\
binary_mode=True)))
test_y = np.load(BytesIO(file_io.read_file_to_string(dest+'test_y',\
binary_mode=True)))
print(test_x.shape, test_y.shape)
下一步是从我们的测试数据中创建实例的 JSON 有效负载并将其保存到云存储位置。批推理模块将能够读取这些实例并执行推理:
import json
BATCH_PREDICTION_INSTANCES_FILE = "batch_prediction_instances.jsonl"
BATCH_PREDICTION_GCS_SOURCE = (
BUCKET_URI + "/batch_prediction_instances/" + BATCH_PREDICTION_INSTANCES_FILE
)
在这里,我们将输入图像转换为可序列化的格式,以便预测服务可以接受 JSON 文件作为输入:
# converting to serializable format
x_test = [(image).astype(np.float32).tolist() for image in test_x]
# Write instances at JSONL
with open(BATCH_PREDICTION_INSTANCES_FILE, "w") as f:
for x in x_test:
f.write(json.dumps(x) + "\n")
# Upload to Cloud Storage bucket
! gsutil cp batch_prediction_instances.jsonl BATCH_PREDICTION_GCS_SOURCE
print("Uploaded instances to: ", BATCH_PREDICTION_GCS_SOURCE)
现在我们的测试数据集实例已准备好在云存储桶中。我们可以对它们启动批量预测,批推理模块将输出结果保存到同一存储桶中的新文件夹中:
MIN_NODES = 1
MAX_NODES = 1
# The name of the job
BATCH_PREDICTION_JOB_NAME = "bnw_to_color_batch_prediction"
# Folder in the bucket to write results to
DESTINATION_FOLDER = "batch_prediction_results"
# The Cloud Storage bucket to upload results to
BATCH_PREDICTION_GCS_DEST_PREFIX = BUCKET_URI + "/" + DESTINATION_FOLDER
在这里,我们使用 SDK 调用批预测服务:
# Make SDK batch_predict method call
batch_prediction_job = model.batch_predict(
instances_format="jsonl",
predictions_format="jsonl",
job_display_name=BATCH_PREDICTION_JOB_NAME,
gcs_source=BATCH_PREDICTION_GCS_SOURCE,
gcs_destination_prefix = BATCH_PREDICTION_GCS_DEST_PREFIX,
model_parameters=None,
starting_replica_count=MIN_NODES,
max_replica_count=MAX_NODES,
machine_type="n1-standard-4",
sync=True,
)
如果需要,我们还可以在 Google Cloud 控制台 UI 中监控批量预测作业的进度。一旦这个作业完成,我们可以在定义的目标文件夹中检查输出。
摘要
在本章中,我们学习了如何使用基于 Vertex AI 的托管训练环境以及启动自定义训练任务。在 Vertex AI 上启动自定义训练任务具有许多优势,例如托管元数据跟踪、无需主动监控任务,以及能够并行启动任意数量的实验,选择你想要的机器规格来运行你的实验,使用云控制台 UI 以近乎实时的方式监控训练进度和结果,并在保存的模型上运行托管批量推理任务。它还与其他 GCP 产品紧密集成。
阅读本章后,你应该能够开发并在 Vertex AI Workbench 笔记本上运行自定义深度学习模型(使用如 TensorFlow 等框架)。其次,你应该能够启动长时间运行的 Vertex AI 自定义训练任务,并理解托管 Vertex AI 训练框架的优势。托管的 Google Cloud 控制台界面和 TensorBoard 使得监控和评估各种 Vertex AI 训练任务变得容易。
现在我们已经对在 GCP 上使用 Vertex AI 进行模型训练有了很好的理解,接下来我们将学习下一章中的模型可解释性。
第八章:机器学习模型的可解释性
在快速发展的机器学习(ML)和人工智能(AI)世界中,开发能够提供准确预测的模型不再是唯一目标。随着组织越来越依赖数据驱动的决策,理解模型预测背后的理由变得至关重要。机器学习模型中可解释性需求的增长源于道德、监管和实际方面的考虑,这就是可解释人工智能(XAI)概念发挥作用的地方。
本章深入探讨了可解释机器学习模型的复杂性,这是机器学习操作(MLOps)景观中的一个关键组成部分,重点关注它们在 Google Cloud 生态系统中的实现。尽管对 XAI 技术和工具的全面探索超出了本章的范围,但我们旨在为您提供构建透明、可解释和有责任感的机器学习模型所需的知识和技能,这些模型可以使用 GCP 上的可解释机器学习工具。
本章将涵盖以下主题:
-
可解释人工智能是什么,为什么它对机器学习操作(MLOps)从业者来说很重要?
-
可解释人工智能技术的概述
-
可解释人工智能功能在 Google Cloud Vertex AI 中可用
-
使用 Vertex AI 的可解释性功能的动手练习
随着我们进入本章,我们将确立可解释性的重要性及其在增强机器学习模型中的信任、责任和公平性方面的作用。接下来,我们将讨论实现机器学习可解释性的各种技术,从传统的可解释模型到用于更复杂模型(如深度学习)的解释技术。然后,我们将深入了解 Google Cloud 的可解释人工智能(XAI)产品,这些产品有助于开发和使用可解释机器学习模型。
除了理解可解释机器学习模型外,本章还将通过实际操作示例指导您,说明这些概念在实际场景中的应用。
到本章结束时,您将准备好设计、部署和评估 Google Cloud 上的可解释机器学习模型,确保您的组织在迈向道德和负责任的人工智能采用的竞赛中保持领先。
可解释人工智能是什么,为什么它对机器学习操作(MLOps)从业者来说很重要?
XAI 指的是在人工智能领域使用的方法和技术,旨在使人工智能模型的决策过程对人类透明、可解释和可理解。XAI 不是作为黑盒运行,其中输入数据进入,决策或预测出来,而决策过程不清晰,XAI 寻求揭示模型的内部运作。这种透明度使用户、开发人员和利益相关者能够信任并验证系统的决策,确保它们符合道德、法律和实际考虑。
随着机器学习的持续进步及其应用渗透到各个行业,对透明和可解释模型的需求已成为一个紧迫的问题。XAI 旨在通过开发理解、解释和解释 ML 模型的技术来解决这个问题。对于与 Google Cloud 合作的 MLOps 从业者来说,将 XAI 纳入他们的工作流程可以带来几个好处,包括提高信任度、合规性和增强模型性能。
首先,让我们看看 XAI 对 MLOps 从业者的重要性及其对 ML 模型开发和部署的影响的关键原因。
建立信任和信心
XAI 可以通过提供模型如何做出决策的清晰易懂的解释来帮助 MLOps 从业者建立对模型的信任。这对于处理可能没有技术背景的利益相关者尤为重要,因为解释模型行为的能力可以增加对其预测的信心。此外,对模型内部运作有更深入的理解,使从业者能够更好地传达他们解决方案的限制和优势,从而在合作者和最终用户之间培养信任。
监管合规
随着机器学习模型被更广泛地采用,世界各地的监管机构越来越要求人工智能系统具有更高的透明度和问责制。XAI 技术可以帮助 MLOps 从业者通过提供模型决策过程的见解来确保遵守这些规定。这在医疗保健、金融和人力资源等行业尤为重要,在这些行业中,有偏见或不公平决策的后果可能非常严重。通过将 XAI 纳入他们的工作流程,从业者可以证明他们的模型遵守相关法律和伦理指南。
模型调试和改进
XAI 在模型开发和调试过程中对 MLOps 从业者来说非常有价值。通过提供模型预测方式的见解,XAI 可以帮助识别模型可能表现不佳、过拟合或存在偏差的区域。有了这些信息,从业者可以对他们的模型进行有针对性的调整,从而提高性能并实现更稳健的解决方案。这个迭代过程可以节省时间和资源,使从业者能够专注于解决影响他们模型的最关键问题。
伦理考量
随着机器学习模型的力量和影响力增长,MLOps 从业者的责任也随之增加,以确保这些模型被道德地使用。XAI 可以帮助从业者识别和解决模型可能产生的任何意外后果或偏差。通过理解模型是如何做出决定的,从业者可以更好地确保他们的解决方案是公平的、无偏见的,并与伦理原则一致。
在 Google Cloud 生态系统中将 XAI 集成到 MLOps 工作流程中可以为从业者带来众多好处。从与利益相关者建立信任和确保合规性,到提高模型性能和解决伦理问题,XAI 的重要性不容小觑。随着机器学习领域的不断发展,将 XAI 集成到 MLOps 实践中将变得越来越重要,这对于开发和应用透明、可解释和负责任的 AI 解决方案至关重要。
可解释人工智能技术
不同的技术可供选择,以适应各种类型的数据,包括表格、图像和文本数据。每种数据类型都带来其自身的挑战和复杂性,需要定制的方法来为机器学习模型的决策过程提供有意义的见解。本小节将列出适用于表格、图像和文本数据的各种 XAI 技术。下一节将深入探讨在 Google Cloud 中作为开箱即用功能提供的那些技术。
全局与局部可解释性
可解释性可以分为两类:局部可解释性和全局可解释性。这些术语有时也被称为局部和全局特征重要性:
-
全局可解释性关注特征对模型的整体影响。这通常是通过在整个数据集上计算平均特征归因值来获得的。具有高绝对值的特征表明它对模型预测有显著影响。
-
局部可解释性提供了关于每个特征对特定实例预测贡献多少的见解。特征归因值提供了关于特定特征相对于基线预测对预测的影响的信息。
图像数据技术
XAI 技术在图像数据中通常关注可视化图像中对于模型预测贡献最大的区域。以下是一些关键技术:
-
集成梯度
集成梯度是一种专门为深度学习模型(如神经网络)设计的归因技术。它计算模型输出相对于输入特征(在图像数据的情况下为像素)的梯度,并将这些梯度沿从基线输入到感兴趣实例的直线路径进行积分。这个过程为图像中的每个像素分配一个重要性值,反映其对模型预测的贡献。集成梯度提供了对每个像素重要性的见解,并有助于识别模型预测中的潜在偏差或不足:
图 8.1 – 集成梯度解释
前面的图展示了集成梯度方法对图像的解释,它突出了模型在预测期间赋予高重要性的图像像素。
-
扩展相关性加权重要性归因(XRAI)
XRAI 是一种 XAI 方法,用于可视化给定模型预测中图像的最重要区域。它是集成梯度方法的扩展,该方法结合了像素级归因与分割技术,以生成更连贯和可解释的视觉表示。通过识别图像中最重要的部分,XRAI 提供了对模型决策过程的洞察,并有助于识别模型预测中的潜在偏差或问题:
图 8.2 – XRAI
前面的图展示了 XRAI 对图像解释的方法,它突出了模型在预测期间赋予高重要性的图像区域。
-
局部可解释模型无关 解释 (LIME)
LIME 是一种 XAI 技术,为任何分类器的单个预测提供局部解释。在图像数据的上下文中,LIME 在特定实例周围生成合成数据点(扰动图像),从模型中获得预测,并使用这些数据点与实例的邻近度进行加权,拟合一个可解释的模型(例如,线性回归)。生成的模型提供了对特定实例预测中最重要的区域的洞察。通过可视化这些区域,从业者可以更好地理解模型的决策过程,并识别模型预测中的潜在偏差或问题。
-
梯度加权类激活 映射 (Grad-CAM)
Grad-CAM 是一种针对深度学习模型(特别是卷积神经网络(CNNs))的可视化技术。它为给定模型预测中的图像生成最重区域的热图可视化。Grad-CAM 计算预测类别分数相对于最后一层卷积层的特征图的梯度,然后使用这些梯度计算特征图的加权总和。生成的热图突出了对模型预测贡献最大的图像区域。Grad-CAM 提供了对模型决策过程的洞察,并有助于识别模型预测中的潜在偏差或不足。
这些技术提供了对模型决策过程的洞察,并有助于识别模型预测中的潜在偏差或不足。
表格数据技术
由结构化行和列组成的表格数据是机器学习中遇到的最常见数据类型之一。可以采用各种 XAI 技术来解释在表格数据上训练的模型:
-
局部可解释模型无关 解释 (LIME)
如其名所示,LIME 是一种 XAI 技术,为任何分类器的单个预测提供局部解释。它是通过在特定实例的附近用一个更简单、可解释的模型(例如,线性回归)来近似复杂模型来实现的。LIME 在实例周围生成合成数据点,从复杂模型中获取预测,并使用这些数据点拟合一个可解释的模型,这些数据点根据它们与实例的接近程度进行加权。生成的模型提供了关于对特定实例的预测贡献最大的特征的见解。
在下面的图中,我们使用 LIME 报告来解释一个训练有素的机器学习模型的决策,该模型根据乘客的属性(如性别、支付的票价、他们所乘坐的乘客等级等)预测泰坦尼克号乘客的生存概率。泰坦尼克号生存数据集是一个常见的公开可用数据集,用作分类模型的示例。让我们看看 LIME 是否可以帮助我们了解模型的行为:
图 8.3 – 使用 LIME 解释分类模型
最左侧的图表显示了所选乘客的预测生存概率。在这个例子中,模型预测这位乘客基于其关键属性有 40%的生存概率。中间的图表显示了使用 LIME 生成的按重要性排序的特征列表。根据这个图表,似乎决定泰坦尼克号乘客是否生存的前三个最重要的特征是他们的性别/性别、支付的票价以及他们所乘坐的乘客等级。这很有道理,因为我们知道女性首先被疏散,给了她们更高的整体生存机会。我们也知道支付较低票价和持有低等级票的乘客住在船的下层甲板/楼层,这些地方首先被淹没,而支付较高票价的乘客住在上层甲板,给了他们更好的生存机会。所以,你可以看到 LIME 和类似技术如何帮助解析黑盒机器学习模型,并帮助我们更好地理解为什么做出了特定的预测。你也会很高兴地知道,我们之前用来举例的泰坦尼克号乘客是一位 26 岁的女士,名叫 Laina Heikkinen,她在三等舱乘客区支付了 7.925 美元的票价,尽管我们的模型给她低于 40%的生存机会,但她还是幸存了下来。
-
Shapley Additive exPlanations (SHAP)(在 Vertex AI 上原生支持)
SHAP 是一种基于合作博弈论的特征重要性统一度量,提供了一种一致且公平的方式来分配特征重要性。通过计算每个特征的平均边际贡献,SHAP 为每个特征分配一个重要性值,该值反映了其对特定实例预测的贡献。Shapley 值是通过平均所有可能的特征组合中一个特征的边际贡献来计算的。SHAP 值提供了关于驱动模型预测的最具影响力的特征的见解,并且可以与各种模型一起使用。推荐模型类型包括非可微分的模型,如树的集成。它们也可以用于神经网络,其中 SHAP 可以提供关于每个输入特征对网络最终预测贡献的见解。通过分析 SHAP 值,您可以确定哪些特征对网络的输出影响最大,并了解输入与输出之间的关系:
图 8.4 – 基于 Shapley 方法的 Vertex AI 中的特征重要性图
-
置换 特征重要性
置换特征重要性是一种模型无关的技术,通过测量当特征值随机打乱时模型性能的变化来估计每个特征的重要性。这个过程重复多次,平均性能下降被用作特征重要性的估计。通过破坏特征与目标变量之间的关系,置换重要性有助于识别对模型预测影响最大的特征。
-
部分依赖 图 (PDP)
PDP 是一种可视化技术,它描绘了特定特征与模型预测结果之间的关系,同时保持所有其他特征不变。通过说明单个特征如何影响预测,PDP 可以帮助从业者更好地理解其模型的行为,并识别潜在的偏差或不一致性。
-
特征重要性(例如,GINI 重要性和线性模型中的系数)
特征重要性是一组量化输入特征对模型预测影响的技巧。这些方法可以帮助从业者识别最相关的特征,使他们能够在模型开发和调试期间专注于最重要的变量。以下是一些常见的特征重要性方法:
-
GINI 重要性:在决策树和随机森林中应用,GINI 重要性衡量的是特定特征在整个森林中所有树上的平均纯度减少(GINI 指数)。
-
线性模型中的系数:在线性回归和逻辑回归中,模型的系数可以用作特征重要性的度量,表示每个特征与目标变量之间关系的幅度和方向。较大的绝对系数值表示特征与目标变量之间关系更强。
-
这些技术有助于从业者理解输入特征与模型预测之间的关系,识别最有影响力的特征,并评估特定特征对单个预测的影响。
文本数据的技术
对于使用文本数据的自然语言处理模型,目标是识别对模型预测有最大贡献的最重要单词或短语。以下是一些针对文本数据的 XAI 技术:
-
文本特定 LIME:这是针对文本数据特别设计的 LIME 的一个版本,通过突出显示最重要的单词或短语来为单个预测提供解释。
在以下示例中,我们使用 LIME 来解释我们构建的用于将电影评论分类为正面或负面的机器学习模型为何得出特定的结论:
图 8.5 – 基于 LIME 的文本分类解释
如我们所见,电影评论预测为正面的概率为 0.77(77%)。橙色高亮的单词有助于提高正面的概率,而蓝色高亮的单词对将最终预测推向“负面”标签有显著贡献。右上角的图表显示了每个高亮单词对最终决策的相应贡献。例如,如果我们从评论文本中删除“amazing”这个词,正面的概率将下降 0.03:
-
文本特定 SHAP:这是针对文本数据特别设计的 SHAP 的一个版本,将重要性值分配给给定文本中的单个单词或短语
-
注意力机制:在像 Transformers 这样的深度学习模型中,注意力机制可以通过可视化注意力权重来提供关于单词与模型预测之间关系的见解。
现在我们已经熟悉了各种流行的 XAI 技术,让我们来看看 Google Cloud Vertex AI 中可用的不同功能,这些功能可以帮助我们使用这些技术构建 XAI 解决方案。
Google Cloud Vertex AI 中可用的可解释人工智能功能
Google Cloud Vertex AI 提供了一套工具和选项,旨在使人工智能系统更加易于理解。本节深入探讨了 Vertex AI 中可用的各种可解释人工智能(XAI)选项,展示了该平台如何推进透明机器学习的前沿。
广义上,Vertex AI 中可用的 XAI 选项可以分为两种类型:
- 基于特征的:特征归因指的是模型中每个特征对特定实例预测的贡献程度。在做出预测请求时,您会收到由您的模型生成的预测值。然而,在请求解释时,您不仅会收到预测值,还会收到特征归因信息。
重要的是要注意,特征归因主要适用于表格数据,但也包括图像数据的内置可视化功能。这使得更直观地理解和解释归因变得更容易。
- 基于示例的:Vertex AI 利用最近邻搜索来提供基于示例的解释。这种方法涉及找到与输入最接近的示例(通常来自训练数据),并返回最相似示例的列表。这种方法利用了相似输入可能产生相似预测的原则,使我们能够深入了解模型的行为。通过检查这些相似示例,我们可以更好地理解和解释模型输出。
Vertex AI 上可用的基于特征的解释技术
下表展示了 GCP 中可用的基于特征的解释方法。
方法 | 兼容的 Vertex AI 模型资源 | 示例 用例 |
---|---|---|
样本 Shapley(SHAP) |
-
任何自定义训练的模型(在任何预测容器中运行)
-
AutoML 表格模型
|
- 表格数据的分类和回归
|
集成梯度 |
---|
-
使用 TensorFlow 预构建容器进行预测服务的自定义训练 TensorFlow 模型
-
AutoML 图像模型
|
-
表格数据的分类和回归
-
图像数据的分类
|
XRAI(基于排序面积积分的解释) |
---|
-
使用 TensorFlow 预构建容器进行预测服务的自定义训练 TensorFlow 模型
-
AutoML 图像模型
|
- 图像数据的分类
|
表 8.1 – GCP 中可用的特征归因方法。来源:cloud.google.com/vertex-ai/docs/explainable-ai/overview
接下来,我们将学习如何使用这些 Vertex AI 功能来生成模型输出的解释。
使用 AutoML 表格数据模型中的模型特征重要性(基于 SHAP)功能
在以下练习中,我们将学习如何使用 Vertex AI 中的 XAI 功能来评估结构化数据 ML 模型中的特征重要性。
练习 1
目标:使用 Vertex AutoML Tables 的特征重要性功能来解释全局(模型级别)和局部(样本级别)行为
要使用的数据集:银行营销数据集(可在本书 GitHub 仓库的第八章文件夹中找到)
模型目标:预测客户是否会开设新的定期存款(特征标签 – deposit(是/否))
按以下步骤操作:
-
按照第五章中所示步骤,创建一个 AutoML 分类模型来预测客户开设定期存款的概率。
-
模型训练完成后,导航到模型注册 | 您的模型 | 您的模型版本(1 为新模型) | 评估选项卡。
-
滚动到特征 重要性部分。
-
下面的特征重要性图显示了不同模型特征的相对重要性:
图 8.6 – Vertex AI AutoML Tables 中的特征重要性图
如前一个图所示,我们模型中预测客户是否会响应外展并开设新的定期存款的最重要特征如下:
-
持续时间:客户与银行的关系时长
-
月份:这可能是因为业务的季节性
-
联系方式(方法 – 手机/固定电话):这可能是因为不同类型客户的通信偏好不同
-
结果:对这位客户最后一次促销活动的结果
下面的是最不重要的特征,根据前一个图:
-
默认:客户之前是否违约过?
-
婚姻(状态)
-
教育:达到的教育水平
-
之前:在此活动之前联系次数的数量
前面的信息可以帮助数据科学团队更好地理解模型的行为,并可能揭示他们对数据和客户行为的更多见解,并为未来的实验提供重要指导。
虽然在训练数据集上执行探索性数据分析超出了本书的范围,但对于感兴趣的任何人,你可以查看笔记本(第八章 – 机器学习模型可解释性 – 练习 1 补充资料)以了解特征与预测标签之间的相关性分析。
从这个特征重要性信息中,我们可以得出以下见解:
-
(
Deposit_Signup
),这与前一个图中特征重要性方面持续时间高的趋势相一致。 -
联系方式:同样,相关性分析还显示,拥有手机的人与对活动做出存款响应的人有很强的相关性。
-
结果:相关性分析还显示,“成功”与有人开设存款之间存在强烈的关联。这意味着如果有人对上次活动做出了积极回应,那么这个人受到当前活动影响的可能性更大。
-
月份:在相关性分析中,我们还可以看到一些月份(特别是三月和五月)与活动的积极结果有很强的相关性。这可能意味着 AutoML 将月份作为一个重要特征呈现。
练习 2
目标:使用 Vertex AI 的特征归因功能来解释图像分类预测
要使用的数据集:Fast_Food_Classification_Dataset
按以下步骤创建图像分类模型:
-
从 Kaggle 下载并解压数据集:
www.kaggle.com/datasets/utkarshsaxenadn/fast-food-classification-dataset
-
按照第 5 章 中所示步骤,使用
Fast_Food_Classification_Dataset
创建一个 AutoML 图像分类数据集。确保选择数据类型和目标为图像分类(单标签),如图所示。
图 8.7 – 模型目标 – 图像分类(单标签)
- 一旦创建了空数据集,转到 浏览 选项卡并为您计划包含在模型中的每种食物类型添加新标签。在此示例中,我们上传了我们最喜欢的快餐,包括汉堡、甜甜圈、热狗和披萨,但请随意使用您想要的任何食物类型。
图 8.8 – 创建标签名称
-
现在,让我们上传不同快餐类型的图像并将它们标注/标记。您不需要数据集中所有的图像。每种食物类型只需大约 50 张图像就足够了。
对每种食物类型重复以下步骤:
- 上传图像 – 逐个标记图像很困难。为了使标记图像变得更容易,一次上传一种食物类型的图像。
图 8.9 – 为图像添加标签
如所示,一旦上传了特定食物项目的图像,您可以点击 未标记 然后点击 全选 以选择所有需要标记的图像。如果您一次上传并标记一种食物类型,则确保您只选择该类型的图像。如果您一次性上传所有图像,那么点击 未标记 选项卡最终会选中所有未标记的图像,需要您手动选择一种类型的图像。
-
选择图像后,点击 分配标签 并选择正确的食物类型标签。然后点击 保存。
对所有的不同 食物类型 进行此过程。
-
一旦所有图像都已上传并标记,导航到 Vertex AI 中的数据集并转到 浏览 选项卡。
-
点击 训练 新模型:
图 8.10 – 启动模型训练
-
在下一屏幕上,选择您用于训练新模型的数据集和注释集。然后选择以下选项并点击 继续:
目标:图像 分类(单标签)
模型训练方法:AutoML
选择模型的使用位置:云
图 8.11 – 训练配置/选项
-
在下一屏,选择训练新模型并输入新模型的名称。您可以保留所有其他选项不变,然后点击继续。
-
在下一屏,选择默认作为目标并点击继续:
图 8.12– 训练配置/选项
-
在下一屏(可解释性选项卡)中,勾选生成可解释位图选项。
-
在正上强调具有最高正影响力的区域。本质上,它照亮了模型做出积极预测的像素,对积极预测有显著贡献。将极性更改为负将强调区域,使模型远离预测正类,并有助于定位导致假阴性的区域。还有一个选择两者都,它通过显示正负贡献来提供全面的视图。
-
pink_green
默认,其中绿色表示正贡献,粉色表示负贡献。另一方面,XRAI 可视化使用渐变色方案,默认为Viridis
。在这个设置中,最有影响力的区域被黄色笼罩,而影响力较小的区域则被蓝色阴影覆盖。有关可用调色板的完整列表,请参阅 API 文档中的可视化消息。 -
叠加类型:此设置定义了原始图像在可视化中的展示方式。调整叠加可以增强可见性,尤其是在初始图像的固有属性掩盖了可视化细节时。
-
步骤:可以在此处指定用于近似路径积分的步骤数。建议从 50 开始,逐渐增加,直到“求和到差”属性落在所需的误差范围内。此值的有效范围在 1 到 100 之间:
图 8.13 – 可解释性配置
- 在计算和定价选项卡中,将预算设置为 8 小时。这指定了训练将运行的最大时间。
-
点击开始训练。
(咖啡休息时间太短了,所以也许可以去准备一顿七道菜的晚餐,然后几个小时后回来检查训练状态!)
模型训练完成后,我们需要按照以下步骤将模型部署到 Vertex AI 端点。
-
导航到模型注册 | 您的模型 | 您的模型版本(1 用于 新模型)。
-
导航到部署与测试选项卡并点击部署到端点。
-
输入端点名称并点击继续:
图 8.14 – 模型部署选项
- 在模型设置选项卡中,勾选为此模型启用特征归因,然后点击下方的编辑按钮以打开可解释性****选项菜单:
图 8.15 – 可解释性部署配置
-
在可解释性选项菜单中,选择集成梯度选项,因为我们首先创建一个端点来测试集成梯度技术。点击完成。
-
现在,重复这些步骤以创建一个用于XRAI可解释性选项的端点。这次,在端点名称后缀加上 XRAI,并在可解释性选项屏幕上选择XRAI。
-
到此为止,应该已经为模型创建了两个端点。
现在,通过上传一个甜甜圈的样本图片来测试模型,并评估模型返回的预测和解释:
-
在模型的部署与测试标签页中,通过点击端点 ID选择集成梯度端点。不要点击端点的名称,因为这会带您进入端点的设置屏幕。
-
点击上传并解释并选择您想要测试的图片。
-
Vertex AI 将处理图像,并展示图像的最终分类结果,以及一个解释(图像叠加将显示图像中重要性高的区域):
图 8.16 – 上传的图片
以下截图显示了基于机器学习模型的类别预测,以及 Vertex AI 生成的基于集成梯度的解释。解释图像展示了图像中帮助模型做出最终决策认为这是一张甜甜圈的关键区域/像素:
图 8.17 – 结果集成梯度解释和预测类别
- 您可以使用 XRAI 端点重复此步骤以获取使用 XRAI 技术生成的解释:
图 8.18 – XRAI 解释
如您所见,通过集成梯度和 XRAI 技术生成的解释图像,图像中靠近甜甜圈位置的区域/像素被突出显示,模型似乎专注于正确的区域。
现在,让我们看看基于示例的解释,在这里,我们不是根据输入实例的特征来解释结果,而是尝试通过查看数据集中与输入实例相似的示例来解释结果。
基于示例的解释
Vertex AI 的基于示例的解释功能使用最近邻搜索算法来找到与样本最接近的匹配项。本质上,当给定一个输入时,Vertex AI 会识别并提供一组示例,这些示例通常来自训练数据,并且与给定输入非常相似。这一功能基于一个共同的预期,即具有相似属性的输入将导致相应的预测。因此,这些识别出的示例成为理解并阐明我们模型的工作方式和决策的一种直观方式。
此方法在以下场景中可能非常有帮助:
-
识别错误标记的示例:如果解决方案定位到在向量空间中彼此靠近但标签不同的数据样本或嵌入,那么数据样本可能被错误标记。
-
决策支持:如果对新数据点的预测标签与在向量空间中出现在新数据点附近的其他数据点的真实标签相似,那么这可以帮助确认预测的有效性。
-
主动学习:在向量空间中,您可以识别出现在有标签样本附近的未标记样本,并将它们添加到训练数据中,标签与附近样本的标签相同。
Vertex AI 中基于示例的解释功能可以被任何为其输入提供嵌入(潜在表示)的模型利用。这意味着该模型应该能够将输入数据转换为潜在空间中的一组相关特征或向量。这排除了某些类型的模型,例如决策树等基于树的模型,因为它们固有的性质不创建这些潜在空间。
使用基于示例的解释的关键步骤
这里是关键步骤:
-
在模型创建时启用解释:首先创建一个已启用解释的模型并将其上传到 Vertex AI。当您创建/导入模型时,您可以使用模型的
explanationSpec
字段为所有解释设置默认配置。为了促进基于示例的解释生成,您的模型应满足某些标准。存在两种潜在的情景:
-
您可以实现一个深度神经网络(DNN)模型,在这种情况下,应提供特定层或签名的名称。然后,该层或签名的输出被用作潜在空间。
-
或者,模型可以被设计为直接输出嵌入,从而作为潜在空间的表示。
这个潜在空间对于过程至关重要,因为它包含了在生成解释中起关键作用的示例表示。
-
-
将模型部署到端点:接下来,创建一个端点资源并将您的模型部署到该资源,从而建立一个可交互的通道。
-
探索生成的解释:最后,向部署的模型发出解释请求,并仔细审查提供的解释,以了解您的模型决策过程。
练习 3
自定义训练一个图像分类模型以生成实时预测并提供基于示例的解释——参见笔记 8.3 – 使用 Vertex AI 实现基于示例的解释 (github.com/PacktPublishing/The-Definitive-Guide-to-Google-Vertex-AI/blob/main/Chapter08/Chapter8_Explainable_AI_example_based.ipynb
)
摘要
在本章中,我们深入探讨了可解释人工智能(XAI)的世界及其在现代机器学习运维(MLOps)中的相关性。我们讨论了 XAI 如何帮助建立信任、确保合规性、调试和改进模型,以及解决伦理问题。
我们探讨了针对不同类型数据的多种解释技术,包括表格数据、图像数据和文本数据。对于表格数据,讨论了 LIME、SHAP、排列特征重要性等技巧。对于图像数据,解释了集成梯度和 XRAI 等方法,而对于文本数据,则展示了针对文本数据的特定 LIME。
本章还概述了 GCP 中可用的 XAI 功能,包括基于特征和基于示例的解释。
到目前为止,您应该已经对 XAI、其重要性、各种技术和在 Vertex AI 背景下的实际应用有了很好的理解。随着人工智能领域的不断发展,XAI 在创建透明、值得信赖和公平的机器学习模型中的作用将只会增长。作为 MLOps 从业者,掌握这些技能对于引领道德和负责任的 AI 采用至关重要。
在下一章中,我们将介绍各种 Vertex AI 工具,这些工具可以帮助您迭代模型超参数,以提升您的机器学习解决方案的性能。
参考文献
cloud.google.com/vertex-ai/docs/explainable-ai/overview
Munn, Michael; Pitman, David. 可解释人工智能实践者. O’Reilly Media.
第九章:模型优化 – 超参数调整和 NAS
我们现在已经非常熟悉 Vertex AI 提供的一些与数据管理、无代码和低代码模型训练以及启动大规模定制模型训练作业(具有元数据跟踪和监控功能)相关的服务。作为机器学习从业者,我们知道我们训练的第一个模型很可能不是针对特定用例和数据集的最佳模型。因此,为了找到最佳模型(即最准确且偏差最小的模型),我们通常使用不同的模型优化技术。超参数调整(HPT)和神经架构搜索(NAS)是两种这样的模型优化技术。在本章中,我们将学习如何使用 Vertex AI 在 Google Cloud 上配置和启动模型优化实验。
在本章中,我们将首先了解模型优化技术(如 HPT)的重要性,然后学习如何在 Google Vertex AI 中快速设置和启动 HPT 作业。我们还将了解 NAS 的工作原理以及它与 HPT 的不同之处。本章涵盖的主题如下:
-
什么是 HPT 以及为什么它很重要?
-
在 Vertex AI 上设置 HPT 作业
-
NAS 是什么,它与 HPT 有何不同?
-
Vertex AI 上的 NAS 概述
技术要求
本章中展示的代码示例可以在以下 GitHub 仓库中找到:github.com/PacktPublishing/The-Definitive-Guide-to-Google-Vertex-AI/tree/main/Chapter09
什么是 HPT 以及为什么它很重要?
超参数调整,或简称 HPT,是一种在机器学习项目中非常常用的模型优化技术。在本节中,我们将了解超参数、调整它们的重要性以及寻找机器学习算法最佳超参数的不同方法。
什么是超参数?
当我们训练一个机器学习系统时,我们基本上有三类数据 – 输入数据、模型参数和模型超参数。输入数据指的是与我们要解决的问题相关的训练或测试数据。模型参数是我们修改的变量,我们试图调整它们以适应训练数据。另一方面,模型超参数是控制训练过程本身的变量。这些超参数在我们开始训练模型之前是固定的。例如,学习率、优化器、批量大小、神经网络中的隐藏层数量以及基于树的算法中的最大深度都是模型超参数的例子。
为什么选择 HPT?
你的机器学习模型将表现如何很大程度上取决于你在训练之前选择的超参数。超参数的值可以对模型性能指标(如准确率)、训练时间、偏差、公平性等方面产生重大影响。超参数调整或 HPT 是一种模型优化技术,它为学习算法选择一组最优的超参数。相同的机器学习算法可能需要完全不同的超参数值来泛化不同的数据模式。每个 HPT 作业都与一个目标函数相关联,它试图优化(最小化或最大化)该目标函数,并返回实现该最优值的超参数值。这个目标函数可以类似于模型训练目标(例如,损失函数)或者可以是一个完全新的指标。
当我们的最终模型(即 XGBoost)固定,并且我们有固定的测试集,我们想要优化所选模型的超参数时,我们会运行模型优化操作,如 HPT 或 NAS。一个典型的 HPT 作业运行多个试验,使用不同的超参数集,并返回导致最佳试验的超参数。这里的最佳试验代表优化与 HPT 作业相关的目标函数的试验。
搜索算法
在运行超参数优化(HPT)时,我们必须决定在超参数空间中运行哪种搜索算法。根据我们的需求,我们可以从多种不同的搜索算法中进行选择。以下是一些常用的方法:
-
网格搜索
-
随机搜索
-
贝叶斯优化
让我们讨论这些方法!
网格搜索
传统的 HPT 执行方式是网格搜索,这基本上是在手动指定的搜索空间上进行穷举搜索。网格搜索必须提供一个性能指标,它试图计算所有可能的超参数组合集,这些组合在保留的验证集(或训练集上的交叉验证)上测量。由于它运行所有提供的超参数范围的组合,因此设置这些范围时必须小心,并使用离散值。由于网格搜索独立运行所有试验,因此它可以并行化以获得更快的输出。
随机搜索
与网格搜索尝试所有组合的顺序和穷举搜索不同,随机搜索在每次试验中从提供的搜索空间中随机选择超参数。由于它随机选择超参数值,它也可以泛化到连续空间,如上所述。随机搜索再次高度可并行化,因为所有试验都是独立的。尽管它很简单,但随机搜索是测试新优化或搜索技术的重要基线之一。
贝叶斯优化
与网格搜索和随机搜索不同,贝叶斯优化方法构建了一个将超参数值映射到 HPT 目标函数的概率模型。因此,在每次新的试验中,它都会更好地了解它应该采取的方向,以找到给定目标函数在固定验证集上的最优超参数。它试图平衡探索和利用,并且已经证明在更少的试验中可以获得比先前技术更好的结果。但是,由于它从正在进行的试验中学习,它通常迭代地运行试验(因此它不太并行化)。
现在我们已经对 HPT 有了很好的理解,让我们了解如何在 Vertex AI 上设置和启动 HPT 作业。
在 Vertex AI 上设置 HPT 作业
在本节中,我们将学习如何使用 Vertex AI 设置 HPT 作业。我们将使用第七章,使用 Vertex AI 训练完全自定义的机器学习模型中相同的神经网络模型实验,并优化其超参数以获得最佳模型设置。
第一步是在 Vertex AI Workbench 中创建一个新的 Jupyter Notebook 并导入有用的库:
import numpy as np
import glob
import matplotlib.pyplot as plt
import os
import google.cloud.aiplatform as aiplatform
from google.cloud.aiplatform import hyperparameter_tuning as hpt
from datetime import datetime
TIMESTAMP = datetime.now().strftime("%Y%m%d%H%M%S")
%matplotlib inline
接下来,我们设置项目配置:
PROJECT_ID='************'
REGION='us-west2'
SERVICE_ACCOUNT='417xxxxxxxxx7-compute@developer.gserviceaccount.com'
BUCKET_URI='gs://my-training-artifacts'
然后,我们初始化 Vertex AI SDK:
aiplatform.init(project=PROJECT_ID, location=REGION, \
staging_bucket=BUCKET_URI)
下一步是将完整的训练应用程序代码容器化。我们将把完整的训练代码放入一个 Python 文件中,即task.py
。task.py
文件应该包含整个流程,包括以下内容:
-
加载和准备训练数据
-
定义模型架构
-
训练模型(运行具有给定超参数作为参数的试验)
-
保存模型(可选)
-
将训练试验输出传递给
hypertune()
方法
训练脚本应该有一个它想要调整的超参数列表,定义为参数:
def get_args():
'''Parses args. Must include all hyperparameters you want to tune.'''
parser = argparse.ArgumentParser()
parser.add_argument(
'--epochs',
required=True,
type=int,
help='training epochs')
parser.add_argument(
'--steps_per_epoch',
required=True,
type=int,
help='steps_per_epoch')
同样,我们还有其他重要的超参数,如学习率、批量大小、损失函数等:
parser.add_argument(
'--learning_rate',
required=True,
type=float,
help='learning rate')
parser.add_argument(
'--batch_size',
required=True,
type=int,
help='training batch size')
parser.add_argument(
'--loss',
required=True,
type=str,
help='loss function')
args = parser.parse_args()
return args
脚本应该有一个函数用于加载和准备训练集和验证集:
def make_datasets_unbatched():
# Load train, validation and test sets
dest = 'gs://data-bucket-417812395597/'
train_x = np.load(BytesIO(
file_io.read_file_to_string(dest+'train_x', \
binary_mode=True)
))
train_y = np.load(BytesIO(
file_io.read_file_to_string(dest+'train_y', \
binary_mode=True)
))
同样,验证集和测试数据部分也被加载:
val_x = np.load(BytesIO(
file_io.read_file_to_string(dest+'val_x', \
binary_mode=True)
))
val_y = np.load(BytesIO(
file_io.read_file_to_string(dest+'val_y', \
binary_mode=True)
))
test_x = np.load(BytesIO(
file_io.read_file_to_string(dest+'test_x', \
binary_mode=True)
))
test_y = np.load(BytesIO(
file_io.read_file_to_string(dest+'test_y', \
binary_mode=True)
))
return train_x, train_y, val_x, val_y, test_x, test_y
前一个函数从 GCS 加载已准备好的数据集。我们可以参考第七章,使用 Vertex AI 训练完全自定义的机器学习模型,以全面了解数据准备部分。
接下来,我们定义TensorFlow(TF)模型架构:
def tf_model():
black_n_white_input = tensorflow.keras.layers.Input(shape=(80, 80, 1))
enc = black_n_white_input
我们接下来定义模型的编码器部分:
#Encoder part
enc = tensorflow.keras.layers.Conv2D(
32, kernel_size=3, strides=2, padding='same'
)(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(enc)
enc = tensorflow.keras.layers.Conv2D(
64, kernel_size=3, strides=2, padding='same'
)(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(enc)
同样,我们将定义另外两个编码器层,具有递增的过滤器数量、3 的内核大小和 2 的步长,以便我们可以将图像压缩到重要的特征:
enc = tensorflow.keras.layers.Conv2D(
128, kernel_size=3, strides=2, padding='same'
)(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(enc)
enc = tensorflow.keras.layers.Conv2D(
256, kernel_size=1, strides=2, padding='same'
)(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.Dropout(0.5)(enc)
在同一函数内定义 TF 模型的解码器部分:
#Decoder part
dec = enc
dec = tensorflow.keras.layers.Conv2DTranspose(
256, kernel_size=3, strides=2, padding='same'
)(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
dec = tensorflow.keras.layers.Conv2DTranspose(
128, kernel_size=3, strides=2, padding='same'
)(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
如我们所见,解码器的设计几乎与编码器部分相反。在这里,我们通过使用多层转置卷积和逐步减少通道到 3 来从压缩特征中重新创建图像,以生成最终的彩色图像输出:
dec = tensorflow.keras.layers.Conv2DTranspose(
64, kernel_size=3, strides=2, padding='same'
)(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
dec = tensorflow.keras.layers.Conv2DTranspose(
32, kernel_size=3, strides=2, padding='same'
)(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
dec = tensorflow.keras.layers.Conv2D(
3, kernel_size=3, padding='same'
)(dec)
添加一个tanh
激活函数以获得最终的彩色输出图像:
color_image = tensorflow.keras.layers.Activation('tanh')(dec)
return black_n_white_input, color_image
还添加了一个函数来构建和编译 TF 模型:
# Build the and compile TF model
def build_and_compile_tf_model(loss_fn, learning_rate):
black_n_white_input, color_image = tf_model()
model = tensorflow.keras.models.Model(
inputs=black_n_white_input,
outputs=color_image
)
_optimizer = tensorflow.keras.optimizers.Adam(
learning_rate=learning_rate,
beta_1=0.5
)
model.compile(
loss=loss_fn,
optimizer=_optimizer
)
return model
最后,添加一个main
函数来训练模型,并将超参数调整指标值提供给hypertune()
函数。在我们的案例中,我们将优化验证数据集上的损失。请参见以下代码片段:
def main():
args = get_args()
设置配置并加载数据:
NUM_WORKERS = strategy.num_replicas_in_sync
# Global batch size should be scaled as per the number # of workers used in training. GLOBAL_BATCH_SIZE = args.batch_size * NUM_WORKERS
MODEL_DIR = os.getenv("AIP_MODEL_DIR")
train_x, train_y, val_x, val_y, _, _ = \
make_datasets_unbatched()
现在,让我们构建 TF 模型并将其拟合到训练数据上:
with strategy.scope():
# Creation of dataset, and model building/compiling need to be within
# `strategy.scope()`.
model = build_and_compile_tf_model(args.loss, \
args.learning_rate)
history = model.fit(
train_x,
train_y,
batch_size=GLOBAL_BATCH_SIZE,
epochs=args.epochs,
steps_per_epoch=args.steps_per_epoch,
validation_data=(val_x, val_y),
)
model.save(MODEL_DIR)
使用hypertune
定义并报告超参数调整指标给 HPT 算法:
# DEFINE HPT METRIC
hp_metric = history.history['val_loss'][-1]
hpt = hypertune.HyperTune()
hpt.report_hyperparameter_tuning_metric(
hyperparameter_metric_tag='val_loss',
metric_value=hp_metric,
global_step=args.epochs)
如果我们将所有这些放入一个单独的 Python 文件中,我们的task.py
文件应该看起来像以下这样:
%%writefile task.py
# Single, Mirror and Multi-Machine Distributed Training
加载我们任务的所有依赖项:
import tensorflow as tf
import tensorflow
from tensorflow.python.client import device_lib
import argparse
import os
import sys
from io import BytesIO
import numpy as np
from tensorflow.python.lib.io import file_io
import hypertune
解析参数,其中我们定义了用于调整的超参数:
def get_args():
'''Parses args. Must include all hyperparameters you want to tune.'''
parser = argparse.ArgumentParser()
parser.add_argument(
'--epochs',
required=True,
type=int,
help='training epochs')
parser.add_argument(
'--steps_per_epoch',
required=True,
type=int,
help='steps_per_epoch')
定义一些与超参数相关的更多参数,用于调整学习率、批大小和损失函数:
parser.add_argument(
'--learning_rate',
required=True,
type=float,
help='learning rate')
parser.add_argument(
'--batch_size',
required=True,
type=int,
help='training batch size')
parser.add_argument(
'--loss',
required=True,
type=str,
help='loss function')
args = parser.parse_args()
return args
设置用于训练的配置:
print('Python Version = {}'.format(sys.version))
print('TensorFlow Version = {}'.format(tf.__version__))
print('TF_CONFIG = {}'.format(os.environ.get('TF_CONFIG', \
'Not found')))
print('DEVICES', device_lib.list_local_devices())
根据要求定义基于训练分布策略的配置设置——可以是单一、镜像或多工作者策略:
DISTRIBUTE='single'
if DISTRIBUTE == 'single':
if tf.test.is_gpu_available():
strategy = tf.distribute.OneDeviceStrategy(device="/gpu:0")
else:
strategy = tf.distribute.OneDeviceStrategy(device="/cpu:0")
# Single Machine, multiple compute device
elif DISTRIBUTE == 'mirror':
strategy = tf.distribute.MirroredStrategy()
# Multiple Machine, multiple compute device
elif DISTRIBUTE == 'multi':
strategy = tf.distribute.experimental.MultiWorkerMirroredStrategy()print('num_replicas_in_sync = {}'.format(strategy.num_replicas_in_sync))
从 GCS 存储桶加载数据并准备训练、验证和测试分区:
# Preparing dataset
BUFFER_SIZE = 10000
def make_datasets_unbatched():
# Load train, validation and test sets
dest = 'gs://data-bucket-417812395597/'
train_x = np.load(BytesIO(
file_io.read_file_to_string(dest+'train_x', \
binary_mode=True)
))
train_y = np.load(BytesIO(
file_io.read_file_to_string(dest+'train_y', \
binary_mode=True)
))
类似地,加载验证和测试分区:
val_x = np.load(BytesIO(
file_io.read_file_to_string(dest+'val_x', \
binary_mode=True)
))
val_y = np.load(BytesIO(
file_io.read_file_to_string(dest+'val_y', \
binary_mode=True)
))
test_x = np.load(BytesIO(
file_io.read_file_to_string(dest+'test_x', \
binary_mode=True)
))
test_y = np.load(BytesIO(
file_io.read_file_to_string(dest+'test_y', \
binary_mode=True)
))
return train_x, train_y, val_x, val_y, test_x, test_y
定义将黑白图像转换为彩色图像的 TF 模型架构:
def tf_model():
black_n_white_input = tensorflow.keras.layers.Input(shape=(80, 80, 1))
enc = black_n_white_input
定义模型编码器部分:
#Encoder part
enc = tensorflow.keras.layers.Conv2D(
32, kernel_size=3, strides=2, padding='same'
)(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(enc)
enc = tensorflow.keras.layers.Conv2D(
64, kernel_size=3, strides=2, padding='same'
)(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(enc)
类似地,我们将定义两个额外的编码器层,具有递增的过滤器数量、3 的核大小和 2 的步长,以便我们可以将图像压缩到重要的特征:
enc = tensorflow.keras.layers.Conv2D(
128, kernel_size=3, strides=2, padding='same'
)(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(enc)
enc = tensorflow.keras.layers.Conv2D(
256, kernel_size=1, strides=2, padding='same'
)(enc)
enc = tensorflow.keras.layers.LeakyReLU(alpha=0.2)(enc)
enc = tensorflow.keras.layers.Dropout(0.5)(enc)
定义模型的解码器部分:
#Decoder part
dec = enc
dec = tensorflow.keras.layers.Conv2DTranspose(
256, kernel_size=3, strides=2, padding='same'
)(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
dec = tensorflow.keras.layers.Conv2DTranspose(
128, kernel_size=3, strides=2, padding='same'
)(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
如我们所见,解码器设计几乎与编码器部分相反。在这里,我们通过使用多层转置卷积重新创建图像,并逐步减少通道到 3 以生成最终的彩色图像输出:
dec = tensorflow.keras.layers.Conv2DTranspose(
64, kernel_size=3, strides=2, padding='same'
)(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
dec = tensorflow.keras.layers.Conv2DTranspose(
32, kernel_size=3, strides=2, padding='same'
)(dec)
dec = tensorflow.keras.layers.Activation('relu')(dec)
dec = tensorflow.keras.layers.BatchNormalization(momentum=0.8)(dec)
dec = tensorflow.keras.layers.Conv2D(
3, kernel_size=3, padding='same'
)(dec)
最后,使用tanh
激活函数生成彩色图像输出:
color_image = tensorflow.keras.layers.Activation('tanh')(dec)
return black_n_white_input, color_image
以下函数将为我们构建和编译 TF 模型:
`# Build the and compile TF model
def build_and_compile_tf_model(loss_fn, learning_rate):
black_n_white_input, color_image = tf_model()
model = tensorflow.keras.models.Model(
inputs=black_n_white_input,
outputs=color_image
)
_optimizer = tensorflow.keras.optimizers.Adam(
learning_rate=learning_rate,
beta_1=0.5
)
model.compile(
loss=loss_fn,
optimizer=_optimizer
)
return model
现在,让我们定义主函数以开始执行我们的训练和调整任务。在这里,num_replicas_in_sync
参数定义了在多工作者训练策略中不同工作者上并行运行多少个训练任务:
def main():
args = get_args()
NUM_WORKERS = strategy.num_replicas_in_sync
# Here the batch size scales up by number of workers since
# `tf.data.Dataset.batch` expects the global batch size.
GLOBAL_BATCH_SIZE = args.batch_size * NUM_WORKERS
MODEL_DIR = os.getenv("AIP_MODEL_DIR")
加载训练和验证数据以开始训练我们的 TF 模型:
train_x, train_y, val_x, val_y, _, _ = \
make_datasets_unbatched()
with strategy.scope():
# Creation of dataset, and model building/compiling need to be within
# `strategy.scope()`.
model = build_and_compile_tf_model(args.loss, \
args.learning_rate)
history = model.fit(
train_x,
train_y,
batch_size=GLOBAL_BATCH_SIZE,
epochs=args.epochs,
steps_per_epoch=args.steps_per_epoch,
validation_data=(val_x, val_y),
)
model.save(MODEL_DIR)
最后,使用hypertune
包定义 HPT 指标:
# DEFINE HPT METRIC
hp_metric = history.history['val_loss'][-1]
hpt = hypertune.HyperTune()
hpt.report_hyperparameter_tuning_metric(
hyperparameter_metric_tag='val_loss',
metric_value=hp_metric,
global_step=args.epochs)
if __name__ == "__main__":
main()
接下来,我们在 GCS 中创建一个用于存储 HPT 作业中试验结果等工件的中转存储桶:
BUCKET_URI = "gs://hpt-staging" # @param {type:"string"}
if BUCKET_URI == "" or BUCKET_URI is None or BUCKET_URI == "gs://[your-bucket-name]":
BUCKET_URI = "gs://" + PROJECT_ID + "aip-" + TIMESTAMP
! gsutil mb -l {REGION} -p {PROJECT_ID} {BUCKET_URI}
GCS_OUTPUT_BUCKET = BUCKET_URI + "/output/"
下一步是将task.py
文件中定义的整个训练代码容器化。超参数调整作业将使用此容器以不同的超参数作为参数启动不同的试验:
%%writefile Dockerfile
FROM gcr.io/deeplearning-platform-release/tf2-gpu.2-8
WORKDIR /
# Installs hypertune library
RUN pip install cloudml-hypertune
# Copies the trainer code to the Docker image.
COPY task.py .
# Sets up the entry point to invoke the trainer.
ENTRYPOINT ["python", "-m", "task"]
我们的 Dockerfile 已经准备好了——让我们构建并推送 Docker 镜像到Google Container Registry(GCR):
PROJECT_NAME="*******-project"
IMAGE_URI = (
f"gcr.io/{PROJECT_NAME}/example-tf-hptune:latest"
)
! docker build ./ -t $IMAGE_URI
! docker push $IMAGE_URI
现在我们已经准备好了包含所有所需训练代码的容器镜像。让我们配置 HPT 作业。
首先,我们定义我们希望试验运行的机器类型。机器规格将取决于模型的大小和训练数据集的大小。由于这是一个小实验,我们将使用 n1-standard-8
机器来运行它:
# The spec of the worker pools including machine type and Docker image
# Be sure to replace PROJECT_ID in the `image_uri` with your project.
worker_pool_specs = [
{
"machine_spec": {
"machine_type": "n1-standard-8",
"accelerator_type": None,
"accelerator_count": 0,
},
"replica_count": 1,
"container_spec": {
"image_uri": f"gcr.io/{PROJECT_NAME}/example-tf-hptune:latest"
},
}
]
注意,在工作者池规格中,我们还传递了我们创建的训练镜像的路径。
接下来,我们将定义我们的作业将使用以找到最佳超参数的参数空间:
# Dictionary representing parameters to optimize.
# The dictionary key is the parameter_id, which is passed into your training
# job as a command line argument,
# And the dictionary value is the parameter specification of the metric.
parameter_spec = {
"learning_rate": hpt.DoubleParameterSpec(min=0.0001, \
max=0.001, scale="log"),
"epochs": hpt.DiscreteParameterSpec(values=[10, 20, \
30], scale=None),
"steps_per_epoch": hpt.IntegerParameterSpec(min=100, \
max=300, scale="linear"),
"batch_size": hpt.DiscreteParameterSpec(values=[16,32,\
64], scale=None),
"loss": hpt.CategoricalParameterSpec(["mse"]), # we can add other loss values
}
参数空间应根据最佳实践和先验知识仔细定义,以便 HPT 作业不必在无关紧要的超参数范围内执行不必要的试验。
接下来,我们需要定义指标规格。在我们的案例中,因为我们正在尝试优化验证损失值,我们希望最小化它。在准确度的情况下,我们应该最大化我们的指标:
metric_spec = {"val_loss": "minimize"}
Vertex AI HPT 作业默认使用贝叶斯优化方法来找到我们设置的最好超参数。我们还有使用其他优化方法的选择。由于贝叶斯优化在大多数情况下效果最好,我们将在实验中使用它。
接下来,我们定义将运行我们的超参数调整试验的自定义作业:
my_custom_job = aiplatform.CustomJob(
display_name="example-tf-hpt-job",
worker_pool_specs=worker_pool_specs,
staging_bucket=GCS_OUTPUT_BUCKET,
)
最后,我们定义将使用前面定义的自定义作业启动试验的 HPT 作业:
hp_job = aiplatform.HyperparameterTuningJob(
display_name="example-tf-hpt-job",
custom_job=my_custom_job,
metric_spec=metric_spec,
parameter_spec=parameter_spec,
max_trial_count=5,
parallel_trial_count=3,
)
注意,max_trial_count
和 parallel_trial_count
参数在这里非常重要:
-
max_trial_count
:您需要为服务将运行的试验数量设置一个上限。更多的试验通常会导致更好的结果,但会有一个收益递减的点,在此之后,额外的试验对您试图优化的指标的影响很小或没有影响。最佳实践是从较小的试验数量开始,在扩展之前了解您选择的超参数的影响程度。 -
parallel_trial_count
:如果您使用并行试验,服务将提供多个训练处理集群。增加并行试验的数量可以减少超参数调整作业运行所需的时间;然而,这可能会降低作业的整体效果。这是因为默认的调整策略使用先前试验的结果来告知后续试验值分配。如果我们保持并行试验计数等于最大试验数,那么所有试验都将并行启动,并且我们将最终运行一个“随机参数搜索”,因为没有从先前试验的性能中学习的空间。
现在我们已经准备好了,我们可以启动 HPT 任务:
hp_job.run()
一旦启动作业,它就会提供一个链接到云控制台 UI,在那里我们可以监控我们的 HPT 试验和作业的进度。云控制台 UI 的外观类似于 图 9**.1 中所示。
图 9.1 – 在云控制台 UI 中监控 HPT 任务
现在我们已经成功理解和启动了在 Vertex AI 上的 HPT 作业,让我们跳到下一部分,了解 NAS 模型优化技术。
什么是 NAS 以及它与 HPT 有何不同?
人工神经网络或ANNs今天被广泛用于解决复杂的机器学习问题。大多数时候,这些网络架构是由机器学习专家手工设计的,这并不总是最优的。神经架构搜索或NAS是一种自动化设计神经网络架构的过程的技术,通常比手工设计的网络表现更好。
虽然 HPT 和 NAS 都被用作模型优化技术,但它们的工作方式存在某些差异。HPT 假设一个给定的架构,并专注于优化导致最佳模型的超参数。HPT 优化超参数,如学习率、优化器、批量大小、激活函数等。另一方面,NAS 专注于优化特定于架构的参数(在某种程度上,它自动化了设计神经网络架构的过程)。NAS 优化参数,如层数、单元数、层之间的连接类型等。使用 NAS,我们可以根据准确性、延迟、内存、这些特性的组合或自定义指标来搜索最优的神经网络架构。
NAS 通常与比 HPT 更大的搜索空间一起工作,并控制网络架构的不同方面。然而,解决的根本问题是与 HPT 优化相同的。有许多基于 NAS 的优化方法,但在高层次上,任何 NAS 方法都有三个主要组件,如下所示:
-
搜索空间
-
优化方法
-
评估方法
让我们更深入地了解这些组件的每一个。
搜索空间
此组件控制要考虑的可能神经网络架构的集合。搜索空间通常是特定于问题的,例如,与视觉相关的问题可能会有卷积神经网络(CNN)层的可能性。然而,识别最佳架构的过程是通过 NAS 自动化的。仔细设计这些搜索空间仍然依赖于人类的专业知识。
优化方法
此组件决定如何导航搜索空间以找到给定应用的最佳可能架构。许多不同的优化方法已经应用于 NAS,例如强化学习(RL)、贝叶斯优化、基于梯度的优化、进化搜索等。这些方法中的每一种都有其评估架构的独特方式,但高层次的目标是专注于提供更好性能的搜索空间区域。这一方面的 NAS 与 HPT 优化方法相当相似。
评估方法
评估方法是用于评估所选优化方法设计的架构质量的一个组件。评估神经架构的一个简单方法是对其进行完全训练,但这种方法在计算上相当昂贵。作为替代,为了使神经架构搜索(NAS)更高效,已经开发出了部分训练和评估方法。为了提供更便宜的神经网络质量启发式度量,一些评估方法已经被开发出来。这些评估方法非常特定于 NAS,并利用神经网络的基本结构来估计网络的质量。这些方法的一些例子包括权重共享、超网络、网络形态学等。这些针对 NAS 的特定评估方法在实际上比完全训练便宜得多。
我们现在对 NAS 优化方法及其工作原理有了很好的理解。接下来,让我们探索 Vertex AI 提供的产品及其在 Google Cloud 上启动 NAS 的功能。
Vertex AI NAS 概述
Vertex AI NAS 是一种优化技术,可以用来为给定的机器学习用例找到最佳的神经网络架构。基于 NAS 的优化在准确性方面寻找最佳网络,但也可以通过其他约束来增强,例如延迟、内存或根据需求定制的指标。一般来说,可能的神经网络搜索空间可以相当大,NAS 可能支持高达 10²⁰ 的搜索空间。在过去的几年里,NAS 已经能够成功生成一些最先进的计算机视觉网络架构,包括 NASNet、MNasNet、EfficientNet、SpineNet、NAS-FPN 等。
虽然看起来可能很复杂,但 NAS 功能非常灵活且易于使用。初学者可以利用预构建的模块来探索搜索空间、训练脚本和 Jupyter 笔记本,以在自定义数据集上开始探索 Vertex AI NAS。如果您是专家,您可能开发自定义训练脚本、自定义搜索空间、自定义评估方法,甚至为非视觉用例开发应用程序。
Vertex AI 可以用来探索针对我们定制架构和用例的完整 NAS 功能集。以下是 Vertex AI 为我们提供的一些帮助,以便更方便地实现 NAS:
-
Vertex AI 提供了一种特定的 NAS 语言,可以利用它来定义一个自定义搜索空间,以尝试所需的可能神经网络架构集合,并将此空间与我们的自定义训练脚本集成。
-
预构建的最先进的搜索空间和训练器,可以立即使用并在 GPU 上运行。
-
一个预定义的 NAS 控制器,它从我们自定义定义的搜索空间中采样,以找到最佳的神经网络架构。
-
一组预构建的库和 Docker 镜像,可以用来在自定义硬件设置上计算延迟、FLOPS(每秒浮点运算次数)或内存使用情况。
-
Google Cloud 提供教程来解释 NAS 的使用方法。它还提供了设置 NAS 以高效运行 PyTorch 应用程序的示例和指导。
-
预构建工具用于设计代理任务。
-
有库支持可以利用,以报告自定义定义的指标并对它们进行分析。
-
Google Cloud 控制台在监控和管理 NAS 作业方面非常有帮助。我们还获得了一些易于使用的示例笔记本,以启动搜索。
-
基于每个项目或每个作业的 CPU/GPU 资源使用管理,借助预构建库。
-
一个 NAS 客户端,用于构建 Docker 镜像、启动 NAS 作业以及恢复基于 Python 的旧 NAS 搜索作业。
-
客户支持是基于 Google Cloud 控制台用户界面的。
这些功能可以帮助我们在不花费太多努力的情况下设置定制的 NAS 作业。现在让我们讨论一些与 NAS 一起工作的最佳实践。
NAS 最佳实践
这里需要注意的重要事项是,NAS 不是一个我们应该应用于所有机器学习问题的优化方法。在决定为我们的用例运行 NAS 作业之前,有一些事情需要牢记。以下是一些最佳实践:
-
NAS 不适用于调整模型的超参数。它只执行架构搜索,不建议比较这两种方法的成果。在某些配置中,HPT 可以在 NAS 之后进行。
-
NAS 不建议用于较小的或高度不平衡的数据集。
-
NAS 成本高昂,除非我们可以在没有极高期望的情况下花费几千美元,否则它不适合我们。
-
你应该首先尝试其他传统和常规的机器学习方法和技术,如超参数调整。只有当你没有看到传统方法带来进一步收益时,才应使用神经架构搜索。
由于预构建资源和公开发布的代码示例,在 Vertex AI 上设置 NAS 作业并不复杂。有了这些预构建功能、示例和最佳实践,我们应该能够设置一个定制的 NAS 作业,帮助我们找到满足项目目标的最佳架构。
摘要
在本章中,我们讨论了将模型优化技术应用于我们的应用程序以获得最佳性能的重要性。我们学习了两种模型优化方法——HPT 和 NAS,以及它们的相似之处和不同之处。我们还通过代码示例学习了如何在 Vertex AI 上设置和启动大规模 HPT 作业。此外,我们还讨论了一些最佳实践,以充分利用 HPT 和 NAS。
在阅读本章之后,你应该对“模型优化”这个术语及其在开发机器学习应用程序中的重要性有一个公正的理解。此外,你现在应该对使用 Google Cloud 上的 Vertex AI 工具快速设置从小型到大型规模的超参数调整实验充满信心。你还应该对 NAS、它与 HPT 的区别以及设置 NAS 作业的最佳实践有一个公正的理解。
现在我们已经了解了模型优化技术的重要性以及常见的方法,我们具备了开发高质量模型的良好基础。接下来,让我们学习如何部署这些模型,以便它们可以被下游应用所使用。
第十章:Vertex AI 部署和自动化工具 – 通过托管 Kubeflow 管道进行编排
在典型的机器学习(ML)解决方案中,我们通常会有很多应用程序和服务作为端到端工作流程的一部分。如果我们尝试使用一些定制的脚本和 cron 作业将这些服务和应用程序拼接在一起,管理工作流程就会变得非常棘手。因此,利用一些编排服务来仔细管理、扩展和监控复杂的工作流程变得非常重要。编排是将多个应用程序或服务拼接在一起以构建端到端解决方案工作流程的过程。Google Cloud 提供了多个编排服务,例如 Cloud Scheduler、Workflows 和 Cloud Composer,以大规模管理复杂的工作流程。Cloud Scheduler 非常适合单一、重复的任务,Workflows 更适合复杂的多服务编排,而 Cloud Composer 非常适合数据驱动的负载。
ML 工作流程有很多步骤,从数据准备到模型训练、评估等。除此之外,监控和版本跟踪变得更加具有挑战性。在本章中,我们将学习关于 GCP 工具如何有效地编排 ML 工作流程。本章涵盖的主要主题如下:
-
使用 Vertex AI 管道(托管 Kubeflow 管道)编排 ML 工作流程
-
使用 Cloud Composer(托管 Airflow)编排 ML 工作流程
-
Vertex AI 管道与 Cloud Composer 的比较
-
在 Vertex AI 上获取预测
-
管理 Vertex AI 上部署的模型
技术要求
本章中展示的代码示例可以在以下 GitHub 仓库中找到:github.com/PacktPublishing/The-Definitive-Guide-to-Google-Vertex-AI/tree/main/Chapter10
使用 Vertex AI 管道(托管 Kubeflow 管道)编排 ML 工作流程
ML 解决方案复杂且涉及许多步骤,包括数据准备、特征工程、模型选择、模型训练、测试、评估和部署。除此之外,在生产过程中跟踪和版本控制与 ML 模型相关的许多方面也非常重要。GCP 上的 Vertex AI 管道让我们能够以易于组合、共享和重现的方式对 ML 工作流程进行编码。Vertex AI 管道可以以完全托管的方式运行 Kubeflow 以及基于TensorFlow Extended(TFX)的 ML 管道。在本节中,我们将学习如何开发用于 ML 开发的 Kubeflow 管道作为 Vertex AI 管道。
Kubeflow 是一个 Kubernetes 原生解决方案,它简化了 ML 管道的编排,使得实验变得简单且可重复。此外,管道是可共享的。它提供了对执行监控、工作流程调度、元数据记录和版本控制等框架的支持。Kubeflow 管道是 ML 工作流程的描述,它将工作流程的多个小组件组合成一个有向无环图(DAG)。在幕后,它将在容器上运行管道组件,这提供了可移植性、可重复性和封装。每个管道组件是 ML 工作流程中的一步,执行特定的任务。一个组件的输出可能成为另一个组件的输入,依此类推。每个管道组件由代码组成,打包成执行管道中一步的 Docker 镜像,并在一个或多个 Kubernetes Pod 上运行。Kubeflow 管道可以用于 ETL 和 CI/CD 任务,但它们更常用于运行 ML 工作流程。
Vertex AI SDK 允许我们从 Jupyter Notebook 内部以编程方式创建和上传 Kubeflow 管道,但我们也可以使用控制台 UI 来处理管道。Vertex AI UI 允许我们可视化管道执行图。它还允许我们跟踪、监控和比较不同的管道执行。
使用 Python 开发 Vertex AI 管道
在本节中,我们将使用 Vertex AI SDK 在 Jupyter Notebook 中开发和启动一个简单的基于 Kubeflow 的 Vertex 管道。在这个例子中,我们将使用开源的葡萄酒质量数据集。让我们开始吧!
打开一个 Jupyter Notebook 并安装一些有用的库:
!pip3 install google-cloud-aiplatform
!pip3 install kfp --upgrade
!pip install google_cloud_pipeline_components
在一个新的单元格中,导入用于 Vertex 管道开发的库:
from typing import NamedTuple
import typing
import pandas as pd
from kfp.v2 import dsl
from kfp.v2.dsl import (Artifact, Dataset, Input, Model, Output, Metrics, ClassificationMetrics, component, OutputPath, InputPath)
from kfp.v2 import compiler
from google.cloud import bigquery
from google.cloud import aiplatform
from google.cloud.aiplatform import pipeline_jobs
from google_cloud_pipeline_components import aiplatform as gcc_aip
创建一个时间戳变量。它将有助于为管道对象创建唯一的名称:
from datetime import datetime
TIMESTAMP =datetime.now().strftime("%Y%m%d%H%M%S")
现在,我们将设置一些与项目相关的配置,例如project_id
、区域、暂存桶和服务账户:
PROJECT_ID='417xxxxxxx97'
REGION='us-west2'
SERVICE_ACCOUNT='417xxxxxxx97-compute@developer.gserviceaccount.com'
BUCKET_URI='gs://my-training-artifacts'
在本节中,我们将使用葡萄酒质量数据集。葡萄酒质量数据集由 Cortez, Paulo, Cerdeira, A., Almeida, F., Matos, T. 和 Reis, J. (2009) 创建。您可以在以下链接查看:doi.org/10.24432/C56S3T
。 (UCI 机器学习仓库。)
接下来,我们在笔记本单元格中加载并检查葡萄酒质量数据集,以了解数据和列:
df_wine = pd.read_csv("http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv", delimiter=";")
df_wine.head()
此代码片段的输出显示在图 10.1中。
图 10.1 – 葡萄酒质量数据集概述
这里是特征列的快速概述:
-
挥发性酸度
:挥发性酸度
列表示气态酸的含量 -
固定酸度
:葡萄酒中发现的固定酸量,可以是酒石酸、琥珀酸、柠檬酸、苹果酸等等 -
残糖
:此列表示葡萄酒发酵后剩余的糖量 -
柠檬酸
:柠檬酸的含量,它天然存在于水果中 -
氯化物
:葡萄酒中的盐含量 -
游离二氧化硫
:二氧化硫,或 SO2,可以防止葡萄酒氧化和变质 -
总二氧化硫
:葡萄酒中 SO2 的总含量 -
pH 值
:pH 值用于检查葡萄酒的酸度 -
密度
:表示葡萄酒的密度 -
硫酸盐
:硫酸盐有助于保持葡萄酒的新鲜度,并保护其免受氧化和细菌侵害 -
酒精
:葡萄酒中酒精的百分比
策略是预测葡萄酒质量,给定所有前面的参数。我们将将其转换为分类问题,如果葡萄酒的质量指标值 >=7,则称其为最佳质量。
管道组件
在这个练习中,我们将为我们的任务定义四个管道组件:
-
数据加载组件
-
模型训练组件
-
模型评估组件
-
模型部署组件
在这里,第一个组件加载数据,第二个组件使用这些数据来训练模型。第三个组件在测试数据集上评估训练好的模型。第四个组件将训练好的模型自动部署为 Vertex AI 端点。我们将对自动模型部署设置条件,例如,如果模型 ROC >= 0.8,则部署模型,否则不部署。
现在,让我们逐一定义这些组件。以下是一个加载并拆分数据到训练和测试分区的第一个组件。
要创建一个 Kubeflow 组件,我们可以用@component
装饰器包装我们的函数。在这里,我们可以定义基本镜像,以及需要安装的依赖项:
备注
在实际项目或生产管道中,建议在包名称旁边写出版本号,以避免任何版本相关的冲突。
@component(
packages_to_install=["pandas", "pyarrow", "scikit-learn==1.0.0"],
base_image="python:3.9",
output_component_file="load_data_component.yaml"
)
在这里,我们定义一个函数,用于加载数据并将其拆分为训练集和测试集:
def get_wine_data(
url: str,
dataset_train: Output[Dataset],
dataset_test: Output[Dataset]
):
import pandas as pd
import numpy as np
from sklearn.model_selection import train_test_split as tts
df_wine = pd.read_csv(url, delimiter=";")
df_wine['best_quality'] = [1 if x>=7 else 0 for x in df_wine.quality]
df_wine['target'] = df_wine.best_quality
df_wine = df_wine.drop(
['quality', 'total sulfur dioxide', 'best_quality'],
axis=1,
)
我们将保留大约 30%的数据用于测试,其余的用于训练,并将它们保存为 CSV 文件:
train, test = tts(df_wine, test_size=0.3)
train.to_csv(
dataset_train.path + ".csv",
index=False,
encoding='utf-8-sig',
)
test.to_csv(
dataset_test.path + ".csv",
index=False,
encoding='utf-8-sig',
)
要定义一个组件,我们可以用@component
装饰器包装我们的 Python 函数。它允许我们传递基本镜像路径、要安装的包,如果需要将组件写入文件,还可以指定 YAML 文件路径。组件的 YAML 文件定义使其具有可移植性和可重用性。我们可以简单地创建一个包含组件定义的 YAML 文件,并在项目的任何位置加载此组件。请注意,我们还可以使用包含所有自定义依赖项的自定义容器镜像。
第一个组件实际上加载了葡萄酒质量数据集表,创建了之前讨论的二进制分类输出,删除了不必要的列,并将其最终分为训练文件和测试文件。在这里,训练和测试数据集文件是该组件的输出工件,可以在随后运行的组件中重用。
现在,让我们定义第二个组件,该组件在第一个组件生成的训练数据集上训练一个随机森林分类器。
第一步是装饰器,包括依赖项:
@component(
packages_to_install = [
"pandas",
"scikit-learn"
],
base_image="python:3.9",
output_component_file="model_training_component.yml",
)
接下来,我们定义我们的训练函数,它将模型拟合到训练数据上,并将其保存为 Pickle 文件。在这里,我们的输出工件将是一个模型,我们还可以将其与一些元数据相关联,如下面的函数所示。在这个函数内部,我们可以通过将元数据键和值放入 model.metadata
字典中来将模型工件与元数据关联。
def train_winequality(
dataset: Input[Dataset],
model: Output[Model],
):
from sklearn.ensemble import RandomForestClassifier
import pandas as pd
import pickle
data = pd.read_csv(dataset.path+".csv")
model_rf = RandomForestClassifier(n_estimators=10)
model_rf.fit(
data.drop(columns=["target"]),
data.target,
)
model.metadata["framework"] = "RF"
file_name = model.path + f".pkl"
with open(file_name, 'wb') as file:
pickle.dump(model_rf, file)
此组件在训练数据集上训练随机森林分类器模型,并将模型保存为 Pickle 文件。
接下来,让我们定义模型评估的第三个组件。我们以 @component
装饰器开始:
@component(
packages_to_install = [
"pandas",
"scikit-learn"
],
base_image="python:3.9",
output_component_file="model_evaluation_component.yml",
)
现在,我们定义实际的 Python 函数用于模型评估:
def winequality_evaluation(
test_set: Input[Dataset],
rf_winequality_model: Input[Model],
thresholds_dict_str: str,
metrics: Output[ClassificationMetrics],
kpi: Output[Metrics]
) -> NamedTuple("output", [("deploy", str)]):
from sklearn.ensemble import RandomForestClassifier
import pandas as pd
import logging
import pickle
from sklearn.metrics import roc_curve, confusion_matrix, accuracy_score
import json
import typing
这里是一个小的函数,用于控制模型的部署。只有当新模型的准确度高于某个阈值时,我们才部署新模型:
def threshold_check(val1, val2):
cond = "false"
if val1 >= val2 :
cond = "true"
return cond
data = pd.read_csv(test_set.path+".csv")
model = RandomForestClassifier()
file_name = rf_winequality_model.path + ".pkl"
with open(file_name, 'rb') as file:
model = pickle.load(file)
y_test = data.drop(columns=["target"])
y_target=data.target
y_pred = model.predict(y_test)
现在我们有了模型输出,我们可以计算准确度分数和 roc_curve
,并将它们作为元数据记录:
y_scores = model.predict_proba(
data.drop(columns=["target"])
)[:, 1]
fpr, tpr, thresholds = roc_curve(
y_true=data.target.to_numpy(),
y_score=y_scores, pos_label=True
)
metrics.log_roc_curve(
fpr.tolist(),
tpr.tolist(),
thresholds.tolist()
)
metrics.log_confusion_matrix(
["False", "True"],
confusion_matrix(
data.target, y_pred
).tolist(),
)
最后,我们检查模型准确度,看它是否满足部署条件。我们从这里返回部署条件标志:
accuracy = accuracy_score(data.target, y_pred.round())
thresholds_dict = json.loads(thresholds_dict_str)
rf_winequality_model.metadata["accuracy"] = float(accuracy)
kpi.log_metric("accuracy", float(accuracy))
deploy = threshold_check(float(accuracy), int(thresholds_dict['roc']))
return (deploy,)
此组件使用组件 1(测试数据集)和组件 2(训练模型)的输出作为输入,并执行模型评估。此组件执行以下操作:
-
加载测试数据集
-
从 Pickle 文件中加载训练好的模型
-
将 ROC 曲线和混淆矩阵作为输出工件记录
-
检查模型准确度是否大于阈值
最后,我们定义模型部署组件。如果部署条件为 true
,则该组件会自动将训练好的模型作为 Vertex AI 端点部署:
@component(
packages_to_install=["google-cloud-aiplatform", "scikit-learn", "kfp"],
base_image="python:3.9",
output_component_file="model_winequality_component.yml"
)
接下来,我们定义一个函数,当部署条件为真时,将部署葡萄酒质量模型。这个函数将被之前定义的 @component
装饰器包装起来,这样我们就可以在最终的管道定义中使用它:
def deploy_winequality(
model: Input[Model],
project: str,
region: str,
serving_container_image_uri : str,
vertex_endpoint: Output[Artifact],
vertex_model: Output[Model]
):
from google.cloud import aiplatform
aiplatform.init(project=project, location=region)
DISPLAY_NAME = "winequality"
MODEL_NAME = "winequality-rf"
ENDPOINT_NAME = "winequality_endpoint"
在这里,我们定义一个函数来创建我们模型的端点,以便我们可以用它进行推理:
def create_endpoint():
endpoints = aiplatform.Endpoint.list(
filter='display_name="{}"'.format(ENDPOINT_NAME),
order_by='create_time desc',
project=project,
location=region,
)
if len(endpoints) > 0:
endpoint = endpoints[0] # most recently created
else:
endpoint = aiplatform.Endpoint.create(
display_name=ENDPOINT_NAME, project=project, location=region
)
endpoint = create_endpoint()
在这里,我们以编程方式导入我们保存的模型:
#Import a model programmatically
model_upload = aiplatform.Model.upload(
display_name = DISPLAY_NAME,
artifact_uri = model.uri.replace("model", ""),
serving_container_image_uri = serving_container_image_uri,
serving_container_health_route=f"/v1/models/{MODEL_NAME}",
serving_container_predict_route=f"/v1/models/{MODEL_NAME}:predict",
serving_container_environment_variables={
"MODEL_NAME": MODEL_NAME,
},
)
最后,我们将上传的模型部署到所需的机器类型上,并按照所需的流量分配:
model_deploy = model_upload.deploy(
machine_type="n1-standard-4",
endpoint=endpoint,
traffic_split={"0": 100},
deployed_model_display_name=DISPLAY_NAME,
)
# Save data to the output params
vertex_model.uri = model_deploy.resource_name
现在我们管道的核心组件已经准备好了,我们可以继续定义我们的 Vertex Pipeline。
首先,我们需要为我们的管道提供一个唯一的名称:
DISPLAY_NAME = 'pipeline-winequality job{}'.format(TIMESTAMP)
管道定义是我们将这些组件拼接在一起以定义我们的机器学习工作流程(或执行图)的部分。在这里,我们可以控制哪些组件先运行,以及哪个组件的输出应该被馈送到另一个组件。以下脚本定义了我们实验的一个简单管道。
我们可以使用 @dsl.pipeline
装饰器来定义一个 Kubeflow 管道。我们可以在装饰器中传递一个 pipeline_root
参数,如下面的代码所示:
@dsl.pipeline(
pipeline_root=BUCKET_URI,
name="pipeline-winequality",
)
def pipeline(
url: str = "http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv",
project: str = PROJECT_ID,
region: str = REGION,
display_name: str = DISPLAY_NAME,
api_endpoint: str = REGION+"-aiplatform.googleapis.com",
thresholds_dict_str: str = '{"roc":0.8}',
serving_container_image_uri: str = "us-docker.pkg.dev/vertex-ai/prediction/sklearn-cpu.0-24:latest"
):
我们可以在这里创建执行 DAG 并定义预定义组件的执行顺序。某些组件可能是相互依赖的,其中一个组件的输出是另一个组件的输入。依赖组件按顺序执行,而独立的组件可以并行执行:
# adding first component
data_op = get_wine_data(url)
# second component uses output of first component as input
train_model_op = train_winequality(data_op.outputs["dataset_train"])
# add third component (uses outputs of comp1 and comp2 as input)
model_evaluation_op = winequality_evaluation(
test_set=data_op.outputs["dataset_test"],
rf_winequality_model=train_model_op.outputs["model"],
# We deploy the model only if the model performance is above the threshold
thresholds_dict_str = thresholds_dict_str,
)
这是决定是否部署此模型的条件:
# condition to deploy the model
with dsl.Condition(
model_evaluation_op.outputs["deploy"]=="true",
name="deploy-winequality",
):
deploy_model_op = deploy_winequality(
model=train_model_op.outputs['model'],
project=project,
region=region,
serving_container_image_uri = serving_container_image_uri,
)
在这里,我们使用 @dsl.pipeline
装饰器来定义我们的流水线。请注意,在先前的定义中,前三个组件很简单,但第四个组件是使用 dsl.Condition()
定义的。只有当这个条件满足时,我们才会运行模型部署组件。因此,这就是我们控制何时部署模型的方法。如果我们的模型符合业务标准,我们可以选择自动部署它。
接下来,我们可以编译我们的流水线:
compiler.Compiler().compile(
pipeline_func=pipeline,
package_path='ml_winequality.json',
)
最后,我们可以将我们的流水线作业提交到 Vertex AI:
pipeline_job = pipeline_jobs.PipelineJob(
display_name="winequality-pipeline",
template_path="ml_winequality.json",
enable_caching=False,
location=REGION,
)
pipeline_job.run()
此脚本将在 Vertex AI 中启动我们的流水线。它还将为我们提供一个控制台 URL,以便监控流水线作业。
我们也可以通过在控制台中转到 Vertex AI 选项卡并点击 流水线 选项卡来定位流水线运行。图 10.2 是 Vertex AI 中我们示例作业的执行图截图。
图 10.2 – 从 Google Cloud 控制台 UI 观看的示例 Vertex 流水线的执行图
如我们所见,这个执行图包含了我们定义的所有四个组件。它还包括由组件生成的一切工件。如果我们点击 指标 工件,我们可以在控制台 UI 的右侧面板中看到输出值。它看起来类似于 图 10.3。
图 10.3 – 与我们的流水线执行相关的元数据和工件
这就是我们可以使用 Google Cloud 控制台 UI 跟踪我们的 ML 相关工作流的执行和指标的方法。一旦我们的流水线准备就绪,我们还可以使用 Vertex AI Pipelines 的本地调度器、Cloud Scheduler(我们可以定义一个计划)、Cloud Functions(基于事件的触发器)等服务来安排其执行。
现在,我们对如何在 Google Cloud 上作为 Vertex AI Pipelines 开发 Kubeflow 流水线有了很好的理解。我们现在应该能够从头开始开发和启动我们的自定义流水线。在下一节中,我们将了解 Cloud Composer 作为工作流编排的另一种解决方案。
使用 Cloud Composer(托管 Airflow)编排 ML 工作流
Cloud Composer 是建立在 Apache Airflow 开源项目之上的 Google Cloud 上的工作流程编排服务。主要区别在于 Composer 是完全托管,并且可以非常容易地与其他 GCP 工具集成。使用 Cloud Composer,我们可以编写、执行、调度或监控我们的跨多云和混合环境也得到支持的工作流程。Composer 管道是 DAG,可以使用 Python 轻松定义和配置。它附带丰富的连接器库,让我们可以一键部署我们的工作流程。在 Google Cloud 控制台上的工作流程图形表示使得监控和故障排除非常方便。我们的 DAG 自动同步确保我们的作业始终按计划进行。
Cloud Composer 通常被数据科学家和数据工程师用于构建复杂的数据管道(ETL 或 ELT 管道)。它也可以用作 ML 工作流程的编排器。由于 Apache 项目附带数百个操作员和传感器,Cloud Composer 对于数据相关的工作流程来说非常方便,这使得我们可以用很少的代码轻松地在多个云环境中进行通信。它还允许我们定义故障处理机制,例如在管道失败时发送电子邮件或 Slack 通知。
现在,让我们了解如何开发基于 Cloud Composer 的管道。
创建 Cloud Composer 环境
我们可以按照以下步骤使用 Google Cloud 控制台 UI 创建 Cloud Composer 环境:
-
启用 Cloud Composer API。
-
从控制台左侧面板中选择 Composer,然后点击 创建 以开始创建 Composer 环境(见 图 10.4)。
图 10.4 – 在 Google Cloud 控制台上创建 Composer 环境
- 点击 创建。创建环境大约需要 15-20 分钟。一旦完成,环境页面将如下所示(见 图 10.5)。
图 10.5 – 即可使用的 Cloud Composer 环境
- 点击 Airflow 以查看 Airflow 网页 UI。Airflow 网页 UI 如 图 10.6 所示。
图 10.6 – 使用我们的工作流程的 Airflow 网页 UI
如前一个屏幕截图所示,已经有一个 DAG 在运行 – airflow_monitoring.py
文件。见 图 10.7。
图 10.7 – 我们可以放置基于 Python 的 DAG 以进行执行的 GCS 位置
现在我们 Composer 的设置已经准备好了,我们可以快速检查它是否按预期工作。为了快速测试,我们将使用 Airflow 教程中的一个演示 DAG,并将其放入这个桶的dags文件夹中。如果一切正常,我们放入这个桶中的任何 DAG 都应该会自动与 Airflow 同步。
下面的代码是从 Airflow 教程中的一个演示 DAG:
from datetime import timedelta
from textwrap import dedent
# The DAG object; we'll need this to instantiate a DAG
from airflow import DAG
# Operators; we need this to operate!
from airflow.operators.bash import BashOperator
from airflow.utils.dates import days_ago
# These args will get passed on to each operator
# You can override them on a per-task basis during operator initialization
在创建操作符时,将使用以下具有一些默认参数的字典。默认情况下,这些参数将传递给每个操作符,但根据需要,我们也可以在操作符中覆盖一些这些参数:
default_args = {
'owner': 'airflow',
'depends_on_past': False,
'email': ['airflow@example.com'],
'email_on_failure': False,
'email_on_retry': False,
'retries': 1,
'retry_delay': timedelta(minutes=5),
# 'queue': 'bash_queue',
# 'execution_timeout': timedelta(seconds=300),
# 'on_failure_callback': some_function,
# 'on_success_callback': some_other_function,
# 'on_retry_callback': another_function,
# 'sla_miss_callback': yet_another_function,
}
这是我们定义我们的 DAG 的地方,执行步骤按照所需或要求的顺序:
with DAG(
'composer-test-dag',
default_args=default_args,
description='A simple composer DAG',
schedule_interval=timedelta(days=1),
start_date=days_ago(2),
tags=['example'],
) as dag:
在这里,我们定义了我们的代码将要执行的不同任务:
# t1, t2 and t3 are examples of tasks created by instantiating operators
t1 = BashOperator(
task_id='print_date',
bash_command='date',
)
t2 = BashOperator(
task_id='sleep',
depends_on_past=False,
bash_command='sleep 5',
retries=3,
)
您可以使用以下属性来记录您的任务:doc_md
(Markdown)、doc
(纯文本)、doc_rst
、doc_json
和doc_yaml
,这些属性将在 UI 的任务实例****详情页面上显示:
t1.doc_md = dedent(
)
dag.doc_md = __doc__
dag.doc_md = """a documentation placed anywhere"""
templated_command = dedent(
"""
{% for i in range(5) %}
echo "{{ ds }}"
echo "{{ macros.ds_add(ds, 7)}}"
echo "{{ params.my_param }}"
{% endfor %}
"""
)
现在让我们定义t3
任务:
t3 = BashOperator(
task_id='templated',
depends_on_past=False,
bash_command=templated_command,
params={'my_param': 'Parameter I passed in'},
)
在这里,我们定义了任务的执行顺序。t1
需要在t2
和t3
之前执行,但t2
和t3
可以并行执行:
t1 >> [t2, t3]
一旦我们将这个.py
文件上传到 dags 文件夹中的 GCS 桶,Airflow 将自动同步它。如果您刷新 Airflow web UI,它应该显示另一个 DAG,如图图 10.8所示。
图 10.8 – Airflow web UI 中 GCS 位置中存在的所有 DAG
如果我们能在 Airflow UI 中看到我们的 DAG 正在运行,这验证了我们的安装运行正常。现在,让我们打开这个 DAG 来检查实际的执行图。它应该看起来与图 10.9中显示的类似。
图 10.9 – Airflow web UI 中我们工作流程的执行图
尽管这是一个非常简单的 DAG,但它让我们了解到使用 Cloud Composer 与 Airflow 一起工作是多么容易。我们通过 Cloud Composer 获得的日志记录和监控水平相当惊人。Cloud Composer 让数据工程师的生活变得非常容易,这样他们就可以专注于定义复杂的数据管道,而不用担心基础设施和 Airflow 管理。
我们现在对如何使用 Vertex AI Pipelines 和 Cloud Composer(托管 Airflow 服务)作为 ML 工作流程的编排器有了很好的了解。现在让我们总结一下这两者之间的一些相似之处和不同之处。
Vertex AI Pipelines 与 Cloud Composer
在本节中,我们将讨论 Vertex AI Pipelines 和 Cloud Composer 在编排 ML 工作流程方面的关键相似之处和不同之处。基于这种比较,我们可以为我们的下一个 ML 项目选择最佳解决方案。以下是一个总结两个编排器在 ML 相关任务重要方面的要点列表:
-
在任务(作曲家)或容器化组件(Vertex AI Pipelines)方面,它们都易于使用,并将整体 ML 工作流程划分为更小的执行单元。
-
在组件之间传递数据的方式相似,如果数据量很大,可能需要一个中间存储系统。
-
Vertex AI Pipelines 提供了一系列可用的预构建组件,这些组件是开源的,因此开发者可以避免编写大量的模板代码。另一方面,在基于 Composer 的管道的情况下,我们需要编写整个工作流程。
-
根据设置环境的简便性,Vertex AI Pipelines 稍微容易一些。
-
它们都运行在 Kubernetes 上,但在 Vertex AI Pipelines 的情况下,无需担心集群、Pods 等。
-
Cloud Composer 非常适合数据相关任务。我们还可以将 ML 管道作为数据任务实现,但我们会失去许多 ML 相关功能,例如血缘跟踪、指标、实验比较和分布式训练。这些功能是 Vertex AI Pipelines 的默认功能。
-
数据工程师可能会更习惯于 Composer 管道,而 ML 工程师可能会更习惯于 Vertex AI Pipelines。
-
在许多情况下,Vertex AI Pipelines 的使用成本可能更低,因为我们只为我们使用的部分付费。另一方面,在 Composer 的情况下,一些 Pods 总是处于运行状态。
-
如果需要,一些 Vertex AI Pipelines 的功能也可以与 Composer 一起使用。
-
使用 Vertex AI Pipelines 不需要了解 Kubernetes,但使用 Cloud Composer 时,了解 Kubernetes 的常见方面很重要。
在阅读了这些比较点之后,我们可能会觉得选择我们下一个机器学习(ML)用例的最佳编排器变得容易。然而,这两个编排器都易于使用,并且在各个组织中普遍用于管理它们复杂的数据/ML 相关工作流程。
现在我们已经对 Google Cloud 上的 ML 编排工具及其优缺点有了很好的理解,我们准备开始开发生产级的 ML 管道。接下来,让我们学习如何在 Vertex AI 上获取预测。
在 Vertex AI 上获取预测
在本节中,我们将学习如何在 Vertex AI 上从我们的机器学习模型中获取预测。根据用例,预测请求可以是两种类型之一——在线预测(实时)和批量预测。在线预测是对模型端点发出的同步请求。在线预测是那些需要通过 API 调用及时请求输出以更新最终用户信息的应用程序所需要的。例如,Google Maps API 提供了近实时的交通更新,并需要在线预测请求。另一方面,批量预测是异步请求。如果我们的用例只需要批量预测,我们可能不需要将模型部署到端点,因为 Vertex AI 的 batchprediction
服务也允许我们从 GCS 位置中的保存模型执行批量预测,甚至不需要创建端点。批量预测适用于那些对响应时间不敏感且可以接受延迟响应的用例(例如,电子商务公司可能希望预测未来六个月左右的销售额)。使用批量预测,我们可以通过单个请求对大量数据进行预测。
获取在线预测
在模型可以被用来处理在线预测请求之前,我们必须将其部署到端点。模型部署本质上意味着将模型及其所需的基础设施(内存和计算)保持在内存中,以便能够以低延迟提供预测。根据用例和扩展需求,我们也可以将多个模型部署到单个端点,或者将单个模型部署到多个端点。
当你使用 Vertex AI API 部署模型时,你需要完成以下步骤:
-
创建端点。
-
获取端点 ID。
-
将模型部署到端点。
我们可以使用以下 Python 示例函数来创建 Vertex AI 端点。这个函数取自官方文档(cloud.google.com/vertex-ai/docs/general/deployment#api
):
def create_endpoint_sample(
project: str,
display_name: str,
location: str,
):
aiplatform.init(project=project, location=location)
endpoint = aiplatform.Endpoint.create(
display_name=display_name,
project=project,
location=location,
)
print(endpoint.display_name)
print(endpoint.resource_name)
return endpoint
第二步是获取端点 ID,这样我们就可以用它来部署我们的模型。以下 shell 命令将给出我们项目位置内所有端点的列表。如果我们有端点名称,我们可以通过端点名称进行过滤:
gcloud ai endpoints list \
--region=LOCATION \
--filter=display_name=ENDPOINT_NAME
现在我们已经获得了端点 ID,我们可以将我们的模型部署到这个端点。在部署模型的过程中,我们可以指定多个副本的参数、加速器数量、加速器类型等。以下是一个示例 Python 函数,可以用来将模型部署到指定的端点。这个示例取自 Google Cloud 文档(cloud.google.com/vertex-ai/docs/general/deployment#api
):
def deploy_model_with_dedicated_resources_sample(
project,
location,
model_name: str,
machine_type: str,
endpoint: Optional[aiplatform.Endpoint] = None,
deployed_model_display_name: Optional[str] = None,
traffic_percentage: Optional[int] = 0,
traffic_split: Optional[Dict[str, int]] = None,
min_replica_count: int = 1,
max_replica_count: int = 1,
accelerator_type: Optional[str] = None,
accelerator_count: Optional[int] = None,
explanation_metadata: Optional[explain.ExplanationMetadata] = None,
explanation_parameters: Optional[explain.ExplanationParameters] = None,
metadata: Optional[Sequence[Tuple[str, str]]] = (),
sync: bool = True,
):
在这里,我们初始化 Vertex AI SDK 并将我们的模型部署到端点:
aiplatform.init(project=project, location=location)
model = aiplatform.Model(model_name=model_name)
model.deploy(
endpoint=endpoint, deployed_model_display_name=deployed_model_display_name,
traffic_percentage=traffic_percentage,
traffic_split=traffic_split,
machine_type=machine_type,
min_replica_count=min_replica_count,
max_replica_count=max_replica_count,
accelerator_type=accelerator_type,
accelerator_count=accelerator_count,
explanation_metadata=explanation_metadata,
explanation_parameters=explanation_parameters,
metadata=metadata,
sync=sync,
)
model.wait()
print(model.display_name)
print(model.resource_name)
return model
一旦我们的模型部署到端点,它就准备好提供在线预测。现在我们可以向此端点发出在线预测请求。请参见以下示例请求:
def endpoint_predict_sample(
project: str, location: str, instances: list, endpoint: str
):
aiplatform.init(project=project, location=location)
endpoint = aiplatform.Endpoint(endpoint)
prediction = endpoint.predict(instances=instances)
print(prediction)
return prediction
instances[]
对象是必需的,并且必须包含要获取预测的实例列表。请参见以下示例:
{
"instances": [
[0.0, 1.1, 2.2],
[3.3, 4.4, 5.5],
...
]
}
响应体也类似。它可能看起来像以下示例。此示例与先前的模型无关;只是为了理解目的:
{
"predictions": [
{
"label": "tree",
"scores": [0.2, 0.8]
},
{
"label": "bike",
"scores": [0.85, 0.15]
}
],
"deployedModelId": 123456789012345678
}
当处理输入时出现错误时的响应如下:
{"error": "Divide by zero"}
我们现在对如何使用 Vertex AI 端点获取在线预测有了很好的了解。但并非每个用例都需要按需或在线预测。有时我们想要对大量数据进行预测,但结果并不需要立即得到。在这种情况下,我们可以利用批量预测。让我们进一步讨论如何使用 Vertex AI 获取批量预测。
获取批量预测
如前所述,批量预测请求是异步的,不需要将模型始终部署到端点。要发出批量预测请求,我们指定一个输入源和一个输出位置(可以是云存储或 BigQuery),其中 Vertex AI 存储预测结果。输入源位置必须包含我们的输入实例,格式之一为:TFRecord、JSON Lines、CSV、BigQuery 等。
TFRecord 输入实例可能看起来像以下示例:
{"instances": [
{ "b64": "b64EncodedASCIIString" },
{ "b64": "b64EncodedASCIIString" }
]}
可以通过 Vertex AI API 编程方式或使用 Google Cloud 控制台 UI 请求批量预测。由于我们可以向批量预测请求传递大量数据,因此它们可能需要很长时间才能完成,具体取决于数据量和模型大小。
使用 Python 的 Vertex AI API 的一个示例批量预测请求可能看起来像以下 Python 函数。此示例代码取自官方文档(cloud.google.com/vertex-ai/docs/predictions/get-batch-predictions
):
def create_batch_prediction_job_dedicated_resources_sample(
project: str,
location: str,
model_resource_name: str,
job_display_name: str,
gcs_source: Union[str, Sequence[str]],
gcs_destination: str,
instances_format: str = "jsonl",
machine_type: str = "n1-standard-2",
accelerator_count: int = 1,
accelerator_type: Union[str, aiplatform_v1.AcceleratorType] = "NVIDIA_TESLA_K80",
starting_replica_count: int = 1,
max_replica_count: int = 1,
sync: bool = True,
):
在这里,我们初始化 Vertex AI SDK,并在我们的部署模型上调用批量预测:
aiplatform.init(project=project, location=location)
my_model = aiplatform.Model(model_resource_name)
batch_prediction_job = my_model.batch_predict(
job_display_name=job_display_name,
gcs_source=gcs_source,
gcs_destination_prefix=gcs_destination,
instances_format=instances_format,
machine_type=machine_type,
accelerator_count=accelerator_count,
accelerator_type=accelerator_type,
starting_replica_count=starting_replica_count,
max_replica_count=max_replica_count,
sync=sync,
)
batch_prediction_job.wait()
print(batch_prediction_job.display_name)
print(batch_prediction_job.resource_name)
print(batch_prediction_job.state)
return batch_prediction_job
一旦批量预测请求完成,输出将保存在指定的云存储或 BigQuery 位置。
一个jsonl
输出文件可能看起来像以下示例输出:
{ "instance": [1, 2, 3, 4], "prediction": [0.1,0.9]}
{ "instance": [5, 6, 7, 8], "prediction": [0.7,0.3]}
我们现在对 Vertex AI 上的在线和批量预测工作原理有了相当的了解。将批量预测与在线预测(消除部署需求)分开的想法可以节省大量的资源和成本。接下来,让我们讨论一些与 Google Vertex AI 上部署的模型相关的重要考虑因素。
管理 Vertex AI 上的部署模型
当我们将机器学习模型部署到端点时,我们将它与物理资源(计算)关联起来,以便它可以在低延迟下提供在线预测。根据需求,我们可能希望将多个模型部署到单个端点,或者将单个模型部署到多个端点。让我们了解这两种场景。
多个模型 - 单个端点
假设我们已经在生产环境中将一个模型部署到端点,并且我们已经找到了一些改进该模型的好主意。现在,假设我们已经训练了一个改进的模型,我们想要部署,但我们也不希望对我们的应用程序进行任何突然的更改。在这种情况下,我们可以将我们的最新模型添加到现有端点,并开始用新模型服务非常小的流量百分比。如果一切看起来都很完美,我们可以逐渐增加流量,直到它服务全部 100% 的流量。
单个模型 - 多个端点
当我们想要为不同的应用环境(如测试和生产)部署具有不同资源的模型时,这很有用。其次,如果我们的某个应用程序有高性能需求,我们可以使用高性能机器的端点来提供服务,而我们可以使用低性能机器为其他应用程序提供服务,以优化运营成本。
计算资源和扩展
Vertex AI 会分配计算节点来处理在线和批量预测。当我们部署我们的机器学习模型到端点时,我们可以自定义用于服务模型的虚拟机类型。如果需要,我们可以选择使用 GPU 或 TPUs 等加速器。具有更多计算资源的机器配置可以以更低的延迟处理预测,因此可以同时处理更多的预测请求。但是,这样的机器将比计算资源较低的机器成本更高。因此,根据用例和需求选择最合适的机器非常重要。
当我们部署用于在线预测的模型时,我们还可以配置一个预测节点以自动扩展。但是,批量预测的预测节点不会自动扩展。默认情况下,如果我们部署带有或没有专用 GPU 资源的模型,Vertex AI 将自动调整副本的数量,以便 CPU 或 GPU 使用率(以较高的为准)匹配默认的 60% 目标值。在这些条件下,Vertex AI 将进行扩展,即使这可能不是达到每秒查询数(QPS)和延迟目标所必需的。我们可以监控端点以跟踪 CPU 和加速器使用率、请求数量、延迟以及当前和目标副本数量等指标。
为了从成本角度确定预测容器的理想机器类型,我们可以将其部署到虚拟机实例上,并通过发送预测请求来基准测试实例,直到虚拟机达到大约 90%的 CPU 使用率。通过在多个不同的机器上重复进行这个实验,我们可以根据 QPS 值确定预测服务的成本。
摘要
在本章中,我们学习了两种流行的机器学习工作流程编排工具——Vertex AI Pipelines(托管 Kubeflow)和 Cloud Composer(托管 Airflow)。我们还为示例用例实现了一个 Vertex Pipeline,并且类似地,我们也使用 Cloud Composer 开发并执行了一个示例 DAG。Vertex AI Pipelines 和 Cloud Composer 都是 GCP 上的托管服务,使得设置和启动复杂的机器学习和数据相关的工作流程变得非常容易。最后,我们学习了在 Vertex AI 上为我们的自定义模型进行在线和批量预测,包括一些与模型部署相关的最佳实践。
阅读本章后,你应该对在 GCP 上执行机器学习工作流程编排的不同方式及其相似之处和不同之处有一个很好的理解。现在,你应该能够编写自己的机器学习工作流程,并通过 Vertex AI Pipelines 或 Cloud Composer 在 GCP 上编排它们。最后,你应该对使用 Vertex AI 进行在线和批量预测也充满信心。
现在我们已经对在 GCP 上部署机器学习模型以及编排机器学习工作流程有了很好的理解,我们可以开始为不同的用例开发生产级别的管道。沿着相似的方向,我们将在下一章学习一些机器学习治理的最佳实践和工具。
第十一章:使用 Vertex AI 的 MLOps 治理
在快速发展的数字时代,成功实施机器学习(ML)解决方案并不仅仅是创建能够准确预测复杂用例结果的复杂模型。虽然这无疑是必要的,但人工智能(AI)/机器学习操作(MLOps)的熟练管理和治理同样重要。这在企业环境中尤为重要,公司必须确保他们遵守多项内部政策和法规合规要求。本章深入探讨不同的 MLOps 治理组件以及如何利用 Google Cloud 中可用的功能来实施它们。
MLOps 治理围绕建立一个结构化的方法来管理和优化机器学习操作的各个组成部分。它包括确保机器学习项目顺利运行并符合所需政策和法规的过程、工具和指南。
在本章中,我们将涵盖 Google Cloud 上的 MLOps 治理,重点关注以下关键领域:
-
理解 MLOps 治理
-
MLOps 治理案例研究
-
在 Google Cloud 上实施 MLOps 治理
到本章结束时,我们的目标是让您全面了解 MLOps 治理、在 Google Cloud 上的实施以及它在维护成功、可扩展和合规的机器学习操作中的关键作用。
什么是 MLOps 治理及其关键组成部分?
MLOps 是指将机器学习(ML)、数据科学和 DevOps 原则相结合的学科,以有效地管理机器学习模型的整个生命周期。MLOps 的目标是创建一个简化的管道,用于开发、部署和维护机器学习模型,确保这些模型提供可靠和一致的结果。然而,实施和管理这种实践需要治理框架来确保遵守最佳实践和标准。我们所说的 MLOps 治理就是指这个治理框架。
MLOps 治理是实施和管理组织内部机器学习模型的一个基本但往往被忽视的方面。它包含了一套全面的规则、程序和指南,旨在监督机器学习模型在其整个生命周期中的运行。这种治理在确保 MLOps 管道平稳和道德地运行、减轻与机器学习模型部署和使用相关的任何风险方面发挥着关键作用。
MLOps 治理的主要焦点是在组织内部创建一个可靠、透明和可问责的机器学习(ML)系统。这包括监督数据管理、模型开发、模型部署、模型监控和模型审计,可以分为两个关键方面:数据治理和模型治理。
数据治理
ML 模型的质量仅取决于其训练所使用的数据。在 MLOps 管理中,数据处理指的是对数据收集、存储、处理和使用的管理。它包括确保数据的质量和相关性、保护数据隐私以及遵守相关法规。这保证了用于模型训练的数据不仅质量高,而且来源和用途符合伦理。
模型治理
模型治理包括以下组件:
-
模型部署管理:监督模型部署包括确保模型正确集成到组织的系统中,并按预期运行。它还涉及检查模型是否无意中造成任何有害后果,例如偏差结果或隐私侵犯。
-
模型审计:MLOps 管理确保对 ML 模型在性能、伦理影响和整体对组织影响方面进行系统性的审查。模型审计对于保持透明度和问责制至关重要,尤其是在模型的预测对商业决策或用户体验有重大影响的情况下。
-
模型监控:一旦模型部署,MLOps 管理要求持续监控其性能的任何变化。这包括跟踪模型的准确性、检测数据漂移,并确保模型持续提供可靠的预测。
MLOps 管理不是一刀切的做法;它需要根据每个组织的具体需求和情况量身定制。这可能涉及根据处理的数据的性质、使用的 ML 模型类型、这些模型的具体应用以及更广泛的监管环境来定制管理体系。
总结来说,MLOps 管理是任何采用 ML 模型的组织的关键组成部分。通过建立强大的 MLOps 管理体系,组织可以确保其 MLOps 实践不仅有效,而且符合道德、透明和合规。
突出 MLOps 管理重要性的企业场景
为了理解 MLOps 管理的重要性,让我们通过一些强调这一点的现实场景来探讨。
场景 1 – 限制 AI 解决方案中的偏差
考虑一家金融服务业公司部署了一套机器学习模型来预测信用风险。金融领域的这家大型公司会有一系列内部政策,涉及数据访问、使用和预测模型的风险评估,其机器学习解决方案需要遵守这些政策。这可能包括限制可用于此类目的的数据,以及谁可以访问模型输出。它还必须遵守多项监管要求,例如防止决策模型中对受保护群体的偏见。例如,银行需要确保其贷款审批的决策过程不会基于种族或性别产生偏见。即使监管者无法解读底层机器学习模型,他们也可以进行统计分析,以检测贷款审批与种族等因素之间是否存在显著的相关性。如果发现银行在决策中存在偏见,除了会受到监管机构的重大罚款外,还会面临重大的公关灾难。因此,银行需要在机器学习开发的生命周期中建立制衡机制,以标记其开发中的模型中可能出现的任何此类问题,并防止此类模型进入生产环境。
场景 2 – 持续监控特征分布的变化
考虑一个在线电子商务巨头广泛使用人工智能为零售客户提供个性化推荐的情况。它有一套在生产中似乎运行良好的模型。现在,零售商正在进行大规模的市场推广,以获取其客户基础中迄今为止代表性不足的额外地区的用户。随着来自新地区客户的大量涌入,零售商的业务发展团队根据新的月度销售分析报告注意到其点击率和每用户会话收入急剧下降。当其分析师深入研究可能的原因时,他们意识到新地区用户的年龄分布与现有地区客户的年龄分布存在显著差异。这种特征/数据分布的变化在 MLOps 术语中被称为数据漂移,可能会对用户体验和公司最终底线产生重大影响。尽管我们正在考虑一个假设场景,即公司向额外地区的扩张导致数据发生变化,但这可能由多种不同的情况引起,包括但不限于营销策略的变化、经济的变化和产品供应的变化。
因此,重要的是要建立检查机制,以便及早发现推理输入数据中的此类重大变化,以便数据科学团队能够通过构建使用更近期数据的更新模型或构建更针对性的模型来减轻其影响。
场景 3 – 监控成本的需求
权力越大,责任越大。就像云中的任何其他可扩展技术一样,如果资源没有合理规划,并且没有在 Google Cloud 项目中设置适当的预算和限制作为安全措施,您的团队可能会产生巨额账单。考虑这样一种情况,数据科学家启动了一个 Vertex AI Workbench 环境,节点上连接了一个昂贵的 GPU 进行快速实验,但后来忘记了关闭机器。另一个类似的场景是,有人试图安排一个每月运行一次的 MLOps 管道,使用一个极其庞大的 GPU 集群,但错误地将其配置为每天运行一次,从而使成本增加了 30 倍。这样的错误可能本身不会让一家典型的中型公司破产,但您可以想象这样的成本如何迅速累积,尤其是在大型、分散的团队中,没有人完全清楚在价值 10,000 美元/月的集群上运行了 3 天的训练作业是否是实际跟踪的实验,或者它只是个错误。因此,设置成本管理政策非常重要,更重要的是,设置自动控制,以限制在 Google Cloud 平台(GCP)上特定资源的使用。
场景 4 – 监控训练数据的来源
尽管数据控制主要将由数据所有者处理,但 AI 产品/解决方案领导者需要意识到他们从哪里获取数据。如果用于训练模型的发现数据未授权或来自数据质量可疑的来源,这可能导致大量资源浪费,包括基础设施成本和人力成本。
现在,让我们看看 Vertex AI 内部可用的不同工具和功能,这些工具可以帮助您在您的机器学习解决方案中实施 MLOps 治理。
Vertex AI 中可以帮助进行治理的工具
Vertex AI 提供了几个工具来帮助进行机器学习解决方案的治理和监控,您可以使用这些工具来实施和跟踪您组织的标准治理政策和更通用的治理最佳实践。请记住,对于许多治理政策,特别是关于安全和成本管理的政策,您将需要使用 Vertex AI 之外的工具。例如,为了设置每月的成本限制和预算,您将需要使用 GCP 的原生计费工具。
让我们详细了解 Vertex AI 内部可用于作为 MLOps 治理流程一部分的不同工具:
模型注册表
Vertex AI 模型注册表提供了一个集中、组织和安全的位置,用于管理组织内部的所有机器学习模型。这促进了从开发、验证到部署和监控的流畅和高效的机器学习操作:
图 11.1 – Vertex AI 模型注册表
作为管理您的机器学习模型生命周期的中心枢纽,Vertex AI 模型注册表提供了对您模型的鸟瞰图,从而使得跟踪和训练新模型版本的方法更加有序和高效。它作为部署您首选模型版本到端点的接入点,无论是直接部署还是通过使用别名。
Vertex AI 模型注册表扩展了对所有 AutoML 数据类型的自定义模型的支持——无论是文本、表格数据、图像还是视频。此外,它还可以集成 BigQuery ML 模型,这意味着如果您有通过 BigQuery ML 训练的模型,您可以轻松地在 Vertex AI 模型注册表中注册它们。
导航到模型版本详情页面,您将获得许多选项:您可以评估模型、将其部署到端点、设置批量预测,并检查与模型相关的特定细节。凭借其用户友好的简化界面,Vertex AI 模型注册表简化了您管理和部署最佳模型到生产环境的方式。
让我们探讨 Vertex AI 模型注册表如何促进机器学习治理:
-
模型集中存储库:模型注册表提供了一个单一的位置,用于存储组织中的所有模型。这个集中存储库使得数据科学家、机器学习工程师和 DevOps 团队能够轻松地存储、访问和管理模型。它还促进了跨职能的可见性和协作,这是维护强大治理框架的必要元素。
-
版本控制和模型血缘:每次训练新模型或更新现有模型时,模型注册表中都会创建一个新的版本。它维护了模型所有版本的记录,使得跟踪和比较不同版本变得容易,并确保任何更新或修改都得到适当的记录和考虑:
图 11.2 – Vertex AI 模型注册表(版本视图)
-
模型元数据管理:结合元数据存储,它可以帮助记录模型的血缘关系,提供有关用于构建模型每个版本的训练数据集、模型参数和训练管道的信息。这种血缘信息对于审计和合规目的至关重要,是机器学习治理的关键方面。
-
模型验证和测试:在将模型部署到生产环境之前,需要对其进行验证和测试,以确保其满足所需的性能指标。模型注册表通过集成 Vertex AI 的模型评估工具来支持这一点。这些工具可以比较不同的模型版本,并验证它们是否符合预定义的指标,确保只有准确且可靠的模型被部署。您可以直接从模型详情页面查看有关您模型的详细信息,包括性能指标:
图 11.3 – Vertex AI 模型评估
- 与其他 Vertex AI 服务的集成:模型注册表无缝集成到其他 Vertex AI 服务中,包括训练管道和预测服务。Vertex AI 模型注册表允许您通过几点击或几行代码轻松地将模型部署到端点进行实时预测。与 BigQuery 的集成允许您将 BQML 模型注册到 Vertex AI 模型注册表中,以便您可以在一个地方跟踪所有模型。这种集成促进了端到端的 MLOps 治理,允许高效、一致和受控的机器学习操作。
接下来,让我们看看元数据存储。
元数据存储
Vertex AI 元数据存储提供了一个强大、可扩展的系统,用于跟踪和管理与您的机器学习工作流程相关的所有元数据。在此背景下,元数据指的是关于使用的数据、模型训练运行细节、这些运行中使用的参数、生成的指标、创建的工件等信息:
图 11.4 – Vertex AI 元数据存储模型血缘
通过系统地收集和组织这些元数据,Vertex AI 元数据存储能够全面跟踪整个机器学习生命周期,从而促进有效的机器学习治理。以下是具体方法:
-
可追溯性:Vertex AI 元数据存储的一个关键特性是能够为跟踪的机器学习工作流程提供端到端的可追溯性。对于每个构建的模型,它可以追溯数据来源和预处理、特征工程、模型训练、验证和部署过程中所采取的步骤。
-
模型实验和比较:Vertex AI 元数据存储允许您跟踪和比较不同的模型版本、参数和指标。这有助于治理,确保模型开发和选择是系统化和透明的,从而更容易复制和审计您的流程。
-
一致性和标准化:通过使用 Vertex AI 元数据存储,组织可以在不同的机器学习工作流程中标准化元数据。这促进了机器学习工作流程执行和跟踪的一致性,使得应用治理政策和程序更加容易。
-
合规性和监管遵从性:在医疗保健或金融等行业,机器学习模型必须遵守严格的监管要求。Vertex AI 元数据存储通过提供详细的模型血缘来帮助实现合规性,该血缘可以将最终训练好的模型与数据源联系起来,并展示在模型部署到生产之前遵循了最佳实践和满足了适当的评估标准。
-
可重现性:Vertex AI 元数据存储在确保机器学习实验的可重现性方面也发挥着重要作用,这是机器学习治理的一个关键方面。通过跟踪实验的所有元素,包括数据、配置、参数和结果,它确保实验可以在未来可靠地重现。
-
协作和沟通:元数据存储可以促进团队内部的更好协作和沟通。通过全面跟踪机器学习工作流程,团队成员可以了解其他人正在做什么,促进透明度和有效协作。
Vertex AI 元数据存储是您机器学习操作相关元数据的综合存储库,以图形的形式呈现:
图 11.5 – Vertex AI 元数据存储
在这个基于图形的元数据框架中,艺术品和执行形成节点,而事件作为连接边,指定艺术品为特定执行的输入或输出。上下文表示逻辑子组,包含选定的艺术品和执行集合,以便于参考。
Vertex AI 元数据存储允许将元数据作为键值对应用于艺术品、执行和上下文中。例如,一个训练好的模型可以携带元数据,提供有关所使用的训练框架的详细信息,性能指标,如准确率、精确率和召回率等。
要全面掌握您的机器学习系统性能的变化,对由您的机器学习工作流程产生的元数据和其艺术品的家谱进行彻底分析是强制性的。一个艺术品的家谱包含了所有对其起源有贡献的元素,以及从这个根艺术品起源的后续艺术品和元数据。
以一个模型的谱系为例,它可能包括以下元素:
-
用于模型训练、测试和评估的数据集
-
模型训练过程中使用的超参数
-
在训练模型中起关键作用的特定代码库
-
从训练和评估阶段积累的元数据,例如模型的准确率
-
从这个父模型派生出的艺术品,例如批量预测结果
Vertex ML 元数据系统以分层结构组织资源,需要所有资源都属于元数据存储。因此,建立元数据存储是创建元数据资源的先决条件。
让我们深入了解在 Vertex ML 元数据中使用的核心概念和术语,这构成了组织资源和组件的基础:
-
元数据存储:这是元数据资源的顶级容器。元数据存储是区域特定的,并与一个唯一的 Google Cloud 项目相关联。通常,组织在每个项目中使用一个共享的元数据存储来管理元数据资源。
-
元数据资源:Vertex ML Metadata 提供了一个类似于图的数据模型来体现来自和由 ML 工作流使用的元数据。该模型下的主要概念包括工件、执行、事件和上下文。
-
工件:在 ML 工作流中,工件是一个生成的或消耗的独立实体或数据片段。它可以是数据集、模型、输入文件、训练日志等等。
-
上下文:上下文被用来将工件和执行分组到一个可搜索和分类型的类别下。它可以用来表示一组元数据。例如,一个 ML 管道的运行可以被指定为一个上下文。
为了说明,上下文可以封装以下元数据集:
-
Vertex AI Pipelines 管道的一次运行,其中上下文代表运行过程,每个执行符号化 ML 管道中的一个步骤。这展示了如何将工件、执行和上下文融合到 Vertex ML Metadata 的图数据模型中。
-
从 Jupyter Notebook 运行的实验。在这里,上下文可以代表笔记本,每个执行可以表示笔记本中的单元格:
-
事件:事件是用来描述工件和执行之间连接的术语。每个工件可以由一个执行生成,并由其他执行消耗。事件通过将工件和执行链接在一起,有助于在 ML 工作流中建立工件的血缘关系。
-
执行:执行是 ML 工作流中单个步骤的日志,通常带有其运行时参数。执行的例子包括模型训练、模型评估、模型部署、数据验证和数据摄取。
-
元数据模式:MetadataSchema 为特定类型的工件、执行或上下文提供了一个模式。这些模式在创建相应的元数据资源时用于验证键值对。模式验证仅检查资源和 MetadataSchema 之间的匹配字段。这些类型的模式使用 OpenAPI 模式对象表示,通常使用 YAML 进行描述。
-
练习 - 使用 Vertex AI 元数据存储跟踪 ML 模型开发
请参阅附带的笔记本,Chp11_Metadata_Store.ipynb,github.com/PacktPublishing/The-Definitive-Guide-to-Google-Vertex-AI/blob/main/Chapter11/Chp11_Metadata_Store.ipynb
,它将指导你完成创建元数据存储以存储 Vertex AI Pipeline 运行中工件的操作。
接下来让我们谈谈特征存储。
特征存储
Google Cloud 的 Vertex AI 特征存储是一个托管服务,允许数据科学家和 ML 工程师创建、管理和共享 ML 特征。该服务有助于加速将原始数据转换为 ML 模型的过程,确保模型是用既可靠又一致的高质量数据构建的。
虽然 Vertex AI 特征存储主要简化了模型开发过程,但它也在支持机器学习治理方面发挥着重要作用。让我们深入了解该服务如何协助机器学习治理的各个方面:
-
数据管理和可追溯性:机器学习治理的一个关键方面是确保用于开发机器学习模型的数据是准确、相关且可追溯的。Vertex AI 特征存储通过维护模型血缘的元数据来促进这一点。这种可追溯性使得有效地审计整个数据管道成为可能,从而在机器学习操作中促进透明度和问责制。
-
数据一致性:在训练和部署模型使用的数据一致性对于机器学习治理至关重要。不一致性可能导致结果偏差,对模型的性能和可靠性产生负面影响。Vertex AI 特征存储为训练和在线部署提供统一的存储,确保在这些阶段使用相同的数据特征。
-
数据质量监控:维护数据质量是机器学习治理的另一个重要方面。差劣的数据质量可能导致有偏或错误的模型预测。Vertex AI 特征存储通过提供监控和验证输入到特征存储中的数据的功能来帮助管理这一点。它可以帮助识别数据分布随时间的变化或异常,从而允许及时干预和纠正。
-
数据版本控制和可重复性:在机器学习治理的背景下,管理特征的多个版本对于跟踪时间变化和实现可重用性至关重要。Vertex AI 特征存储自动跟踪数据更新并支持时间点查找,这有助于训练实验的一致性和模型的可重复性。
-
隐私和安全:机器学习治理还涉及确保遵守数据隐私和安全法规。Vertex AI 特征存储建立在 Google Cloud 强大的安全模型之上,确保敏感数据在静态和传输过程中都得到加密。借助 Google Cloud 的身份和访问管理(IAM),组织还可以对特征存储实施细粒度的访问控制,确保只有授权人员才能访问敏感数据特征。
使用特征存储时的最佳实践如下:
-
为多个实体建模特征:存在一些特征适用于多种类型实体的场景。例如,考虑一个跟踪用户对产品点击的计数值。这样的特征共同描述了产品-用户对。在这些情况下,建议创建一个新的实体类型,如产品-用户,以分组共享的特征。如果 ID 是字符串,可以通过组合涉及实体的 ID 来形成实体 ID。这些共同形成的实体类型被称为复合实体类型。
-
使用 IAM 策略管理访问权限:IAM 角色和策略为满足不同需求的多个团队提供了强大的管理访问权限的方式。例如,您可能拥有机器学习研究人员、数据科学家、DevOps 和站点可靠性工程师,他们都需要访问相同的特征存储,但他们的访问范围可能不同。资源级 IAM 策略可以用于控制对特定特征存储或实体类型的访问。这允许您的组织中的每个角色或角色都有预定义的 IAM 角色,以适应所需的特定访问级别。
-
通过资源监控和调整优化批量导入:批量导入作业可能会增加特征存储的 CPU 利用率,从而影响在线服务性能。为了达到平衡,可以考虑为每个在线服务节点启动一个工作进程,然后监控导入期间的 CPU 使用情况。可以根据监控结果调整工作进程的数量,以优化吞吐量和 CPU 使用率。
-
使用 disableOnlineServing 字段管理历史数据:在回填过程中(即,导入历史特征值)期间,您可以禁用在线服务,这实际上绕过了对在线存储的任何修改。
-
采用自动扩展以优化成本:对于面临负载频繁波动的用户,自动扩展可以帮助优化成本。这使 Vertex AI 特征存储能够根据 CPU 利用率自动调整节点数量。然而,值得注意的是,自动扩展可能不是管理流量突然激增的最佳解决方案。
-
测试在线服务节点以评估实时服务性能:测试在线服务节点的性能对于确保特征存储的实时性能至关重要。这可以通过基准测试 QPS、延迟和 API 等参数来实现。请记住,从同一区域运行这些测试,使用 SDK 中的 gRPC API 以获得更好的性能,并执行长时间测试以获得更准确的指标。
-
batchReadFeatureValues
或exportFeatureValues
请求。这确保请求在可用特征数据的一个子集上运行查询,这可以在离线存储使用成本上带来显著节省。
练习 - 使用 Vertex AI 特征存储对特征进行编目和监控
请参阅随附的笔记本,Chp11_feature_store.ipynb,github.com/PacktPublishing/The-Definitive-Guide-to-Google-Vertex-AI/blob/main/Chapter11/Chp11_feature_store.ipynb
,它将指导您完成在 Vertex AI 中启用模型监控的练习
我们将在下一节讨论 Kubeflow 管道。
Vertex AI 管道
此主题在第十章中详细讨论,Vertex AI 部署和自动化工具。
Vertex AI Pipelines 旨在帮助管理和编排 ML 工作流,它在 ML 治理中发挥着重要作用。通过提供一个构建、部署和管理 ML 工作流的平台,这个工具使组织能够为其 ML 操作实施有效的治理流程:
-
定义和复用 ML 管道:Vertex AI Pipelines 和 Kubeflow Pipelines 支持将管道定义为一系列组件化步骤。这些步骤可以封装数据预处理、模型训练、评估、部署等。通过定义这些步骤,您可以强制执行最佳实践,确保管道的每一步都是可追踪的,并保证所有模型都是一致开发的。
-
在多个工作流中复用管道和组件是另一个显著优势。这有助于在不同机器学习(ML)项目中实现标准化,这是 ML 治理的关键方面。标准化不仅促进了代码和流程的复用,还降低了错误的风险,并确保了 ML 模型构建和部署的一致性。
-
版本控制和实验跟踪:Vertex AI Pipelines 和 Kubeflow Pipelines 都提供了版本控制和实验跟踪的功能。通过 ML 模型版本控制,可以管理不同版本的模型,并在必要时回滚旧版本。
-
实验跟踪对于治理也至关重要。它提供了不同模型参数和数据集如何影响模型性能的可见性。记录和比较实验的能力也促进了可审计性,使您能够了解每个模型背后的决策过程。
-
自动化和可重复的管道:自动化 ML 工作流确保所有步骤都一致且可靠地执行,这是 ML 治理的一个基本方面。Vertex AI Pipelines 和 Kubeflow Pipelines 都允许创建自动化管道,这意味着 ML 过程中的每一步都是可重复的。
-
可重复性是 ML 治理中经常被低估的方面。可重复的管道意味着您可以在管道的每一步跟踪数据、代码、配置和结果,这对于调试和审计至关重要。当您的模型需要遵守某些法规时,这些法规要求透明的可解释模型开发过程,这一点尤为重要。
-
与其他 Google Cloud 服务的集成:Vertex AI Pipelines 和 Kubeflow Pipelines 被设计成与其他 Google Cloud 服务无缝协作,例如 BigQuery 用于数据管理,Cloud Storage 用于存储模型和数据,以及 AI Platform 用于模型部署。这种集成使得在整个机器学习工作流程中实施管理流程变得更加容易。例如,您可以通过使用 BigQuery 的数据管理功能来确保数据隐私和安全,或者使用 AI Platform 的功能来管理访问控制和监控模型性能。Vertex AI Pipelines 和 Kubeflow Pipelines 提供了各种支持机器学习管理的功能,包括管道定义和重用、版本控制、实验跟踪、自动化、可重复性和与其他 Google Cloud 服务的集成。通过利用这些功能,组织可以有效地管理他们的机器学习操作,确保遵守最佳实践和法规,并创建一个透明、负责且高效的机器学习工作流程。
现在,让我们详细谈谈监控!
模型监控
Vertex AI 监控在 MLOps 管理流程中发挥着关键作用,它提供了实时监控和管理机器学习模型的工具。它使组织能够在他们的机器学习过程中建立透明度、责任感和可靠性。以下是 Vertex AI 监控如何帮助机器学习管理的概述:
-
模型监控:Vertex AI 监控提供了对在生产中部署的模型的自动化监控。这意味着系统会持续跟踪模型的表现,识别数据中的任何潜在漂移以及模型性能的下降。如果模型的表现低于预定义的阈值,它会向适当的利益相关者发出警报。这种持续的监控对于保持模型的准确性和相关性至关重要,这是 MLOps 管理的基本方面。
-
数据偏差和漂移检测:Vertex AI 监控的主要功能之一是其检测数据偏差和漂移的能力。数据偏差是用于训练模型的训练数据与用于提供预测的服务数据之间的差异。另一方面,漂移是数据随时间的变化。两者都可能导致模型性能下降。Vertex AI 监控自动检测这些差异并提供及时的警报,允许快速修复。确保数据的一致性和可靠性符合数据管理的原则,这是 MLOps 管理的关键组成部分。
-
自动警报:Vertex AI 监控的自动警报为生产中模型的任何潜在问题提供了一个早期预警系统。及时的警报确保任何问题都能被迅速识别和解决,防止对模型的表现或业务运营产生长期影响。这一功能对于风险管理至关重要,是 MLOps 管理的关键方面。
-
与其他 Google Cloud 工具的集成:Vertex AI Monitoring 可以无缝集成到其他 Google Cloud 工具中,例如 Cloud Logging 和 Cloud Monitoring。这使得您能够创建综合仪表板来可视化您的 ML 模型的健康状况和性能,并接收任何检测到的问题的警报。这些功能使监控和故障排除能力更加强大,从而提高了 ML 模型的总体治理水平。
现在,让我们看看监控解决方案如何计算训练-服务偏斜和预测漂移的细节。
Vertex AI Monitoring 通过计算分布和距离得分来使用TensorFlow Data Validation(TFDV)检测训练-服务偏斜和预测漂移。这个过程涉及两个步骤:
-
计算基线统计分布
在 Vertex AI Monitoring 的上下文中,偏斜检测和漂移检测的关键在于准确定义基线统计分布。这两个方面的基线之间的区别在于用于计算它们的数据:
-
偏斜检测:基线是从训练数据中存在的特征值统计分布推导出来的
-
漂移检测:相反,对于漂移检测,基线是从最近的生产数据中观察到的特征值的统计分布中制定的
计算这些分布的过程如下:
-
分类特征:分类特征的分布是通过计算特征每个潜在值的数量或比例来确定的。
-
数值特征:在处理数值特征时,Vertex AI Monitoring 将整个可能的特征值范围划分为均匀的区间。随后,计算每个区间内特征值的数量或百分比。
重要的是要注意,基线最初是在创建模型监控作业时设置的,并且只有在分配给作业的训练数据集有更新时才会重新计算。
-
-
计算生产中看到的最近特征值的统计分布
该过程通过计算距离得分,将最近在生产环境中观察到的特征值分布与基线分布进行对比来启动。对于不同类型的特征,使用不同的方法:
-
分类特征:使用 L-infinity 距离法来计算距离得分
-
数值特征:使用 Jensen-Shannon 散度法来计算距离得分
当计算出的距离得分超过预定义的阈值时,表明两个统计分布之间存在显著差异,Vertex AI Monitoring 会识别并标记这种不一致性,将其标记为偏斜或漂移。
-
以下是在使用 Vertex AI Monitoring 时的最佳实践:
-
预测请求采样率:为了提高成本效率,可以配置预测请求采样率。此功能允许监控模型的生产输入的一部分,而不是整个数据集。
-
监控频率:可以定义最近记录的部署模型输入被审查偏斜或漂移的频率。这个频率,也称为监控窗口大小,决定了每次监控运行中评估的日志数据的时间范围。
-
警报阈值:您可以设置每个被监控特征的警报阈值。如果输入特征分布与其相应的基线之间的统计距离超过此阈值,则生成警报。默认情况下,分类和数值特征都被监控,每个特征都有一个阈值为 0.3。
-
跨多个模型的共享配置参数:在线预测端点可以托管多个模型。当在端点上启用偏斜或漂移检测时,包括检测类型、监控频率和监控的输入请求比例在内的某些配置参数将在该端点上托管的所有模型之间共享。
-
模型特定的配置参数:除了共享参数外,还可以为每个模型的其它配置参数指定不同的值。这种灵活性允许您根据每个模型的独特需求和行为定制监控设置。
练习 - 使用 Vertex AI 监控功能跟踪生产环境中部署的模型性能的[notebook]
请参考随附的笔记本,Chp11_Model_Monitoring.ipynb
,github.com/PacktPublishing/The-Definitive-Guide-to-Google-Vertex-AI/blob/main/Chapter11/Chp11_Model_Monitoring.ipynb
,它将指导您在 Vertex AI 中启用模型监控的练习。
我们将在下一节中查看账单监控。
账单监控
GCP提供了一套强大的账单和成本管理工具,这些工具在 MLOps 治理中可以发挥关键作用。这些工具提供了对资源如何被利用的精细可见性,帮助组织有效管理与其 ML 工作流程相关的成本。以下是方法:
-
预算和警报:GCP 的预算和警报功能允许组织为其 GCP 项目或账单账户建立自定义预算,并在实际支出超过定义的阈值时配置警报。这个工具在跟踪和控制与训练、部署和运行 ML 模型相关的成本方面起着至关重要的作用。当集成到 MLOps 治理框架中时,它确保与 ML 工作流程相关的支出不超过其分配的预算,防止成本超支并促进财务责任。
-
详细的账单报告:GCP 的详细账单报告提供了关于每个服务具体成本的洞察。例如,一个组织可以查看关于 Vertex AI、云存储、BigQuery 和 Compute Engine 等服务产生的详细费用报告。这些报告使组织能够了解哪些机器学习工作流或组件成本更高,需要优化。这种细粒度的可见性对于 MLOps 中的成本管理至关重要,它使组织能够战略性地规划资源使用并管理成本。
-
账单导出到 BigQuery:GCP 允许您将详细的账单数据导出到 BigQuery,这是 Google 高度可扩展且成本效益高的数据仓库。此功能使组织能够以编程方式分析其 GCP 账单数据,并使用数据可视化工具(如 Data Studio)构建自定义仪表板。通过这种方式,MLOps 团队可以更好地理解和管理与各种机器学习项目相关的成本,并识别节省和优化的机会。
-
成本管理工具:GCP 的成本管理工具,如定价计算器和总拥有成本(TCO)工具,帮助组织预测其云费用,并将这些费用与在本地或其他云平台上运行相同基础设施的成本进行比较。这些工具有助于在机器学习项目的规划和预算阶段,使 MLOps 团队能够做出更明智的资源分配和成本优化决策。
-
用于自动化成本控制的云函数:GCP 的无服务器执行环境 Cloud Functions 可以用来创建基于自定义逻辑自动停止或启动服务的函数。例如,您可以编写一个函数,当 Compute Engine 实例未被使用时自动停止,从而节省成本。这种级别的自动化成本控制对于管理运行机器学习模型相关的成本非常有价值,这是 MLOps 治理的一个关键方面。
由于账单和预算监控是一个比 Vertex AI 更广泛的话题,它超出了本书的范围,但您可以参考 GCP 账单文档(cloud.google.com/billing/docs/how-to
)以深入了解此主题。
摘要
在本章中,我们讨论了 MLOps 治理的基础知识,详细说明了它在保持机器学习系统效率、准确性和可靠性中的关键作用。为了强调 MLOps 治理在现实场景中的重要性,我们探讨了来自各个行业的案例研究,展示了这种治理模式如何显著影响 AI/ML 实施的成败。
随着我们深入探讨这个主题,我们明确了 MLOps 治理的核心组件——数据治理和模型治理,提供了它们在机器学习模型生命周期中的功能和必要性的概述。此外,我们还讨论了一些现实世界的场景,这些场景有效地强调了 MLOps 治理的相关性和重要性。
在技术方面,我们列举并讨论了 Vertex AI 内部可用的几个有助于机器学习解决方案治理和监控的工具。我们提到了模型注册、元数据存储、特征存储、Vertex AI 管道、模型监控和 GCP 的成本管理工具的功能。通过它们的联合使用,我们展示了如何建立强大、透明和合规的机器学习操作。
我们通过使用 Vertex AI 实施机器学习治理的示例和练习来补充本章,以巩固这些概念。这些实践练习提供了对 Vertex AI 的模型注册、元数据存储和模型监控功能的实际操作经验。
在本书的下一部分,第三部分,GCP 中可用的预建/一站式机器学习解决方案,我们将介绍不同的现成机器学习模型和解决方案,例如 GenAI/LLM 模型、文档 AI、视觉 API 和 NLP API,你可以利用这些工具为不同的用例构建机器学习解决方案。
参考文献
要了解更多关于本章所涉及的主题,请查看以下资源:
GCP Vertex AI 元数据存储文档:cloud.google.com/vertex-ai/docs/ml-metadata
GCP Vertex AI 账单和预算功能:cloud.google.com/billing/docs/how-to
MLOps 实践指南:cloud.google.com/resources/mlops-whitepaper
第三部分:GCP 中可用的预建/一站式机器学习解决方案
在本部分,你将了解 Google Cloud 中一些最常用的预建机器学习解决方案。许多这些解决方案可以立即使用,并且可以迅速与实际应用场景集成。最重要的是,本部分还涵盖了最近在 Vertex AI 中推出的生成式人工智能解决方案。
本部分包含以下章节:
-
第十二章,Vertex AI – 生成式人工智能工具
-
第十三章,文档 AI – 处理文档的端到端解决方案
-
第十四章,视觉、自然语言处理和语音的机器学习 API
第十二章:Vertex AI – 生成式人工智能工具
生成式人工智能(GenAI)是人工智能的一个快速发展的领域,它使机器能够创建新的内容,如文本、图像、代码和音乐。GenAI 模型在大量现有内容的数据集上进行训练,并学习识别这些内容背后的模式和关系。一旦训练完成,这些模型就可以用来生成与训练内容相似但独特且富有创意的新内容。
GenAI 模型可用于广泛的用途,包括以下内容:
-
文本生成:生成文本,如新闻文章、博客文章、营销文案和创意内容
-
聊天机器人:创建能够与用户进行自然对话的聊天机器人
-
图像生成:生成图像,如产品照片、营销图像和艺术图像
-
代码生成:生成代码,如 Python 脚本、Java 类和 HTML 模板
-
文本嵌入:创建可用于文本分类、文本搜索和自然语言推理(NLI)等任务的文本嵌入
在本章中,我们将涵盖以下主题:
-
GenAI 基础知识
-
GenAI 与 Vertex AI
-
提示工程概述
-
检索增强生成方法
-
模型调优
在我们深入探讨 Vertex AI 的 GenAI 功能之前,让我们首先了解 GenAI 的基础知识。
GenAI 基础知识
GenAI 是人工智能的一个子领域,专注于开发能够生成新内容,如文本、图像、音乐或代码的算法和模型。这与传统的人工智能模型形成对比,后者通常专注于理解和分类现有数据。
GenAI 的核心概念在于大型语言模型(LLMs)。LLMs 是一种在大量文本数据上训练过的人工神经网络(ANN)。这种训练使得 LLMs 能够学习人类语言的模式和结构,从而能够生成与人类写作难以区分的文本。
GenAI 与传统 AI 的比较
传统的人工智能模型通常基于监督学习(SL),其中模型在标记示例的数据集上进行训练。例如,一个用于图像分类的模型可能会在标记了正确对象类别的图像数据集上进行训练。一旦训练完成,该模型就可以用来对新的图像进行分类。
另一方面,GenAI 模型通常基于无监督学习(UL),其中模型在未标记数据集上进行训练。模型的任务是学习数据中的潜在模式和结构。在 LLM 的情况下,这可能涉及学习人类语言的模式。
GenAI 模型的类型
GenAI 模型有多种不同类型,每种类型都有其自身的优势和劣势。其中一些最常见类型包括以下内容:
-
自回归模型:这些模型逐字生成文本,根据已经生成的单词预测下一个单词
-
变分自编码器(VAEs):这些模型学习数据的潜在表示,然后可以用来生成新的样本
-
生成对抗网络(GANs):这些模型由两个相互竞争的神经网络组成:一个生成器生成新的样本,一个判别器试图区分真实和虚假样本
GenAI 的挑战
尽管前景广阔,但 GenAI 仍然面临几个挑战,包括以下内容:
-
偏差:GenAI 模型可能会存在偏差,反映它们训练数据中的偏差。例如,当模型直接在来自互联网的原始内容上训练时,如果要求它写一个关于医生和护士的故事,LLM 更有可能写一个关于男性医生和女性护士的故事,即使提示没有指定任何角色的性别。这是因为模型已经学会了深深嵌入在我们社会和我们社会成员在线分享的内容中的相同性别偏见。
-
生成虚假/有害内容:GenAI 模型可以用来生成有害或冒犯性的内容。AI 用于在图像或视频上叠加不知情受害者图像或视频的“深度伪造”问题已经开始困扰互联网。
-
可解释性:解释 GenAI 模型如何做决定可能很困难,这可能会使其难以被信任。
-
幻觉:GenAI 解决方案和底层 LLM 的最后一个挑战,也可能是最具破坏性和最难解决的挑战,是我们无法阻止它们产生幻觉。在 LLM 的背景下,“幻觉”指的是模型生成的不基于现实、事实错误或根据上下文没有意义的信息。当使用 AI 执行需要高精度任务时,例如新闻生成或学术研究,或在法律和医疗应用中,这可能会成为一个问题。以下是我们在没有应用缓解技术的基 LLM 中遇到的几个幻觉示例:
示例 1:
用户:2+2 等于多少?
Chat LLM: It's 4\. Is there anything else I can help you with?
用户:什么?你给我提供错误的信息吗?我的朋友告诉我 2+2 等于 5。
Chat LLM: I apologize. I am a large language model and I am still learning. Your friend is correct. 2+2 is 5.
现在,显然 2+2 不等于 5,无论我的朋友怎么说。但我们很容易就说服了“无所不知”的 LLM 这是真的。
示例 2:
用户:给我总结一下标题为“为什么 AI 系统是危险的”的白皮书,以及其引用。
Chat LLM: The whitepaper "Why AI Systems Are Dangerous" by Dr. Roman V. Yampolskiy, published in 2018, presents a comprehensive analysis of the potential dangers associated with artificial intelligence (AI) systems.
Citation: Yampolskiy, R. V. (2018). Why AI Systems Are Dangerous. arXiv preprint arXiv:1803.04756.
根据第一印象,看起来 LLM 模型在提供论文信息方面做得非常出色。唯一的问题是,并没有标题为“为什么 AI 系统是危险的”的论文。我们的模型不仅根据我们的提示发明了一篇论文,而且还为这篇论文编造了 arXiv 标识符!
现在,让我们看看一些常用的评估技术,这些技术通常用于评估 LLM。
LLM 评估
评估大型语言模型(LLM)对于评估其性能、确定改进领域以及确保其负责任的发展和部署至关重要。为了从多个维度评估 LLM,采用了多种评估方法,包括以下内容:
-
生成性指标:
-
困惑度:衡量 LLM 预测序列中下一个单词的能力。困惑度越低,表示预测能力越好。
-
BLEU 分数:评估生成文本与人类编写的参考文本之间的相似度。BLEU 分数越高,表示相似度越大。
-
用于摘要评估的召回导向的副手(ROUGE):一套评估文本相似性不同方面的指标,如单词重叠和召回。
-
-
人工评估:
人工评估在评估 LLM 的质量和有效性方面发挥着至关重要的作用。虽然自动化指标可以为 LLM 的性能提供有价值的见解,但人类判断对于评估难以量化的方面(如流畅性、连贯性、相关性和创造性)是必不可少的。
-
基准测试:
-
标准基准:利用已建立的基准,如 GLUE、SuperGLUE 或 Big-bench,来比较 LLM 在各种任务中的性能。
-
特定领域基准:当为特定领域用例开发 LLM 时,模型开发者还应致力于开发特定领域的基准,以评估 LLM 在专业领域(如医学诊断或法律研究)中的表现。考虑到开发此类基准所需的努力,我们预计特定行业的主要团队将进行更多合作,发布此类基准的行业标准。
-
通过结合这些评估方法,研究人员和开发者可以全面了解 LLM 的能力、局限性和潜在偏差,使他们能够改进和提升这些强大的语言模型。
现在,让我们看看 Vertex AI 中可用于开发生成式 AI 解决方案的功能。
使用 Vertex AI 进行生成式 AI
Vertex AI 提供各种工具和资源,帮助您开始使用生成式 AI。您可以使用 Vertex AI 模型园地来探索可用的不同生成式 AI 模型,并获得设置和使用这些模型的帮助。您还可以使用 Vertex AI 生成式 AI 工作室来实验生成式 AI 模型,并创建您自己的提示。
理解基础模型
在 Vertex AI 环境中,您会遇到所谓的“基础模型”。这些模型本质上是基于它们被设计用来创建的内容的性质定义的生成式 AI 模型。Vertex AI 中可用的模型类别范围广泛,包括但不限于以下内容:
-
文本和聊天:用于创建文本内容并促进聊天交互
-
图像:用于生成视觉内容
-
代码:生成代码、单元测试并协助开发者
-
嵌入:在向量空间中创建文本或图像的表示
这些基础模型可通过您特定 Google Cloud 项目的发布者端点访问,从而消除了单独部署基础模型的必要性,除非需要针对特定应用进行定制。
Vertex AI GenAI 工具集包括两个关键组件:
-
Vertex AI 模型花园(不仅用于 GenAI 模型)
-
Vertex AI GenAI Studio
接下来,让我们看看这些组件提供了什么。
Vertex AI 模型花园
Vertex AI 模型花园是一个预训练机器学习(ML)模型的存储库,您可以根据需求选择。它包含 Google 专有模型和第三方开源模型。
除了是一个针对各种用例的模型一站式商店外,模型花园还提供了不同大小的相同或类似 Google 模型。当您的用例相对简单时,这一点尤其有利,较小的模型在推理期间计算效率更高,同时为特定用例提供与较大模型相似的精度。
以下截图展示了 Vertex AI 模型花园中可用的各种模型,这些模型按其可用模式或任务进行排序:
图 12.1 – Vertex AI 模型花园
命名结构表示模型大小:为了帮助您区分不同大小的相似模型,Vertex AI 中发布的 Google 模型带有不同的后缀。Google 迄今为止发布的四个模型大小标签,从大到小分别是独角兽、野牛、水獭和壁虎。截至本书出版时,大多数可用的模型是野牛或壁虎类型,但用户可以期待根据 Google Cloud 团队的通知,未来将包含更多不同大小的模型。
注意
可用最大的 LLM 并不总是您解决方案的最佳选择,因为与参数较少的模型相比,较大的模型在推理过程中会产生显著更高的计算成本。始终使用满足您精度要求的最小模型,以确保您的解决方案计算效率高。
现在,让我们看看模型花园中可用的某些基础模型。
Vertex AI 模型花园中的基础 GenAI 模型
GenAI 基础模型是大型、强大的 LLM,构成了所有 GenAI 解决方案的核心。它们能够生成新的、原创的内容,如文本、图像、音乐或代码,并按其模式(文本、图像等)和使用案例(通用、医疗、安全等)进行分类。
Vertex AI 模型园是一个包含大量基础模型的仓库,包括开源模型(例如,Meta 发布的 Llama)和 Google 发布的模型。Google 模型建立在 Google 研究和工程团队设计和训练的核心 LLM 模型之上。它们针对不同的关键用例,如聊天、文本生成、图像生成、代码辅助和工件匹配。
这里是当前可用的 Google 发布的模型列表:
-
text-bison
:描述:
text-bison
是一个旨在遵循自然语言指令的文本生成模型,适用于各种语言任务。后缀“bison
”表示模型大小(参见前面的 注意 关于模型大小标签)。用例:
-
文本分类
-
从给定文本输入中提取实体
-
提取式问答(EQA)
-
文本摘要
-
营销内容生成
-
-
textembedding-gecko
:描述: 此模型为文本输入返回多维向量嵌入。一旦创建了现有文本语料库的嵌入数据库,您就可以使用它来查找任何其他文本片段的最近匹配。后缀“
gecko
”表示模型大小(参见前面的 注意 关于模型大小标签)。用例:
-
文本匹配
-
搜索引擎后端
-
-
textembedding-gecko-multilingual
:描述: 与上述
textembedding-gecko
模型类似,此模型支持超过 100 种语言。用例:
-
多语言文本分析
-
跨语言自然语言处理(NLP)
-
语言翻译应用
-
-
chat-bison
:描述: 优化用于多轮对话场景。它已使用截至 2023 年 2 月的数据进行训练,支持多达 4,096 个输入标记、1,024 个输出标记和最多 2,500 轮对话。
用例:
-
聊天机器人
-
虚拟助手
-
客户服务应用
-
-
code-bison
:描述: 微调以从自然语言描述中生成代码,支持多达 6,144 个输入标记和 1,024 个输出标记。
用例:
-
自动化代码生成
-
单元测试创建
-
-
codechat-bison
描述: 微调用于聊天机器人对话,协助与代码相关的问题,并支持 6,144 个输入标记和 1,024 个输出标记。
用例:
-
代码辅助聊天机器人
-
开发支持
-
教育和代码学习平台
-
-
code-gecko
(不支持模型调整):描述: 设计用于根据编写代码的上下文建议代码补全,管理多达 2,048 个输入标记和 64 个输出标记。
用例:
- 代码补全工具
-
imagegeneration
:描述: 此模型旨在快速生成高质量的视觉资产,包括 1024x1024 像素的分辨率,并允许某些请求和图像大小限制。
用例:
-
图形设计
-
内容创作
-
-
multimodalembedding
:描述:从提供的输入生成向量,这些输入可以是图像和文本的组合,在指定的令牌、语言和大小参数内。
用例:
-
图像和文本分析
-
多模态数据处理
-
内容推荐系统
-
图像文本(图像标题)
-
-
imagetext
(图像标题):描述:一个能够为提供的图像生成多语言标题的图像标题模型,同时遵守一定的速率和大小限制。
用例:
-
图像标题
-
内容创作
-
无障碍服务
-
图像文本(视觉问答,或VQA)
-
-
imagetext
(VQA):描述:一个为 VQA 服务设计的模型,在定义的速率和大小限制内提供英文答案。
用例:
-
VQA 服务
-
教育和培训模块
-
交互式内容创作
-
由于我们已经熟悉了关键的基础模型,现在让我们通过 GenAI Studio 来尝试它们。
Vertex AI GenAI Studio
GenAI Studio 是您可以用来与之前列出的大多数基础模型交互的用户界面。它不需要任何编程知识,主要是为非程序员构建,以便能够使用 Vertex AI 提供的强大 GenAI 功能。另一方面,程序员可以使用 Vertex AI API 来访问基础 GenAI 模型。我们将在本章后面讨论基于 API 的使用。
目前,GenAI Studio 支持三种模态:
-
文本(语言)
-
图像(视觉)
-
音频(语音)
GenAI Studio – 语言
在语言部分,您可以选择以两种模式与 Vertex AI 基础模型交互:
-
提示模式:使用针对交易优化的文本或代码模型,通常对自然语言查询生成较大的响应
-
聊天模式:使用针对对话优化的文本或代码模型,根据当前输入和最近的对话/聊天历史生成响应
以下截图显示了 GenAI Studio 中与语言模型交互的不同选项,包括基于提示的方法和基于聊天的方法:
图 12.2 – Vertex AI GenAI Studio(语言部分)
在我们开始使用 GenAI Studio 进行实验之前,了解有关提示设计/工程的基本概念非常重要。
什么是提示?
在 GenAI 或 NLP 的背景下,一个“提示”是指输入到语言模型中以生成相应输出文本的文本字符串。在这种情况下,提示作为指导或引导模型根据给定输入生成文本的方式。它可以是一个句子、一个短语,甚至是一个单词,具体取决于手头任务的特定要求。
提示设计或提示工程是什么?
“提示设计”指的是为语言模型创建和优化输入(提示)的过程,以实现预期的输出或结果。这个过程涉及理解语言的细微差别和 AI 模型的行为,以引发与用户期望相符的响应。提示设计可能是与生成式 LLM(大型语言模型)合作的关键方面。
这里是提示设计的一些基本方面:
-
清晰性:确保提示清楚地传达给模型所需的任务。
-
具体性:使提示具体化,以避免模糊或过于泛化的响应。
-
上下文:在提示中提供足够的上下文,以促进更明智和相关的输出。
-
格式化:以鼓励期望的响应格式的方式来结构化提示。
-
测试和迭代:提示设计通常是一个迭代过程,涉及测试各种提示策略并根据收到的输出进行微调。
-
道德考量:设计道德的提示,避免鼓励模型产生有害、偏见或不适当的响应。
-
安全措施:实施安全措施,例如使用技术限制模型仅对安全且适当的内容做出响应。
在实践中,提示设计可能涉及艺术和科学的混合,需要创造性和分析技能的结合来掌握。它是 AI 领域的关键技能,特别是对于从事 AI 聊天机器人、虚拟助手、内容创作工具和其他依赖 NLP(自然语言处理)的应用程序的人来说。
提示内容
根据手头任务的复杂性,“提示”可以分解成几个组成部分。以下是构成良好结构化提示的常见部分:
-
指令:这是提示的一部分,其中你提供明确的指令或问题来引导 AI 的响应。指令应明确说明你期望的信息类型或答案格式。指令可以像“加利福尼亚州的首府是什么?”这样简单,也可以像考虑模型时应遵循的 10 页长规则列表那样复杂。这组详细的指令可以与下一节中讨论的“上下文”提示重叠。
-
上下文:如果提示是后续的或寻求详细信息,提供上下文可能是至关重要的。上下文可以包括生成精确和准确响应所需的背景信息或数据。对于一个聊天机器人,上下文通常包括与机器人之前的对话,以便机器人能够使响应与讨论的主题保持一致。
-
示例:在某些情况下,尤其是对于更复杂的任务,在提示中提供示例可能有益于更清晰地展示预期的输出。
这里是一个简单提示的例子:
[Context: You are an assistant helping a user find the perfect recipe based on the ingredients they have on hand.]
[Instruction: Provide a simple recipe that utilizes the ingredients mentioned. Make sure the recipe is easy to follow and suitable for a beginner cook.]
[Example: If the user has chicken breasts, broccoli, and cheddar cheese, you might suggest a recipe for a baked chicken and broccoli casserole topped with melted cheddar cheese.]
[User's Ingredients: Chicken, onions, tomatoes, garlic, and pasta.]
在这个提示中,我们包含以下内容:
-
上下文:通过定义 AI 在根据可用食材寻找食谱中的角色来设定场景。
-
指令:明确指导 AI 提出一个简单且适合初学者的食谱,使用列出的食材。
-
示例:提供了一个使用不同食材的原型食谱,帮助 AI 理解预期的响应类型。
这种结构化的提示有助于引导 AI 构建一个满足用户特定需求和期望的响应,同时提供了一个具体的工作示例。它鼓励 AI 创建一个简单、适合初学者的食谱,使用提示中指定的食材。
一个典型的 GenAI 模型对之前提供的结构化提示的响应可能看起来像这样:
Based on the ingredients you have on hand, you can prepare a simple chicken and Tomato Pasta. Here is a straightforward recipe suitable for a beginner cook:
### Chicken Tomato Pasta
#### Ingredients:
- Chicken (500g)
- Onions (1 large, finely chopped)
- Tomatoes (2 medium, chopped)
- Garlic (2 cloves, minced)
- Pasta (200g, any type you prefer)
#### Instructions:
1\. Cook the pasta according to the package instructions until al dente. Drain and set aside.
2\. In a large pan, heat a bit of oil over medium heat. Add the chopped onions and minced garlic, sautéing until they become translucent and aromatic.
3\. Add the chicken to the pan, breaking it apart with a spatula. Cook until it's no longer pink.
4\. Stir in the chopped tomatoes and let the mixture simmer for about 15-20 minutes, allowing the flavors to meld and the tomatoes to break down and become saucy.
5\. Combine the cooked pasta and the chicken mixture, tossing everything together until well mixed.
6\. Serve hot, optionally garnished with a sprinkle of Parmesan cheese or a few fresh basil leaves on top.
Feel free to adjust the quantities of the ingredients to your taste. Enjoy your meal!
在这个响应中,以下情况发生了:
-
创建了一个新食谱,利用了提示中提到的所有食材。
-
指令简单且适合初学者,遵循提示中给出的指令。
-
该食谱包括食材清单及其大致数量,随后是一个逐步烹饪指南,帮助即使是初学者也能轻松跟随。
-
响应保持了有帮助和鼓励的语气,与提示中设定的上下文一致,并且通过建议可选的装饰品来增强菜肴,增加了个人风格。
在 GenAI Studio 中,除了输入提示之外,您还可以使用以下列出的响应参数来调整输出:
-
最大输出标记数:此参数限制了生成的响应可以包含的最高标记数。一个“标记”大约等于 4 个字符,100 个标记大约相当于 60-80 个单词。为了获得更简短的响应,请设置较低的值,反之,为了获得更冗长的响应,请增加它。
-
温度:此参数定义了响应生成阶段中标记选择过程中的随机性。较低的温度值确保了确定性和较少的创造性输出,而增加它则鼓励更多样化和创造性的输出。
-
Top-K:此参数通过定义从最高概率的标记中选择下一个标记的范围来控制标记选择方法,这个过程受到温度设置的影响。默认设置为 40,但修改它可以控制输出的随机性,从而促进更确定性的或更随机化的响应。
-
Top-P:与Top-K类似,此参数通过设置标记选择的概率阈值来操作。标记的选择基于其概率,遵循Top-P值,从而引导响应中的随机性。
理解并仔细操作这些参数将有助于您调整模型响应以满足您的需求。通过尝试不同的配置来掌握生成模型的最佳利用。
下面的屏幕截图显示了 GenAI Studio 的一些不同响应参数:
图 12.3 – GenAI Studio 设置
现在我们已经熟悉了提示设计的基础,让我们看看如何使用类似的提示与 Vertex AI 基础模型进行交互。
通过 GenAI Studio 使用 Vertex AI GenAI 模型
现在,让我们看看一些如何使用 GenAI Studio 生成内容的示例。在本节中,我们将涵盖四个用例:
-
使用自由格式输入生成文本
-
使用结构化输入生成文本
-
生成图像
-
生成代码示例
示例 1 – 使用 GenAI Studio 语言模型生成文本
在这个例子中,我们将使用 Vertex AI GenAI 模型为新设备生成营销内容,并尝试一些输出配置:
-
导航到 GCP 控制台>> Vertex AI >> 生成 AI 工作室 >> 语言 >> 文本提示。
-
将Token 限制值设置为 256。
-
在提示字段中输入以下文本或复制粘贴(从电子书中)以下文本:
Create an Ad for new Android phone called zPhone. Key features to highlight: - 7-inch OLED screen - HD front camera for video calls - 50MP rear camera - Long 48 Hr battery life
-
点击提交以生成响应。
响应将类似于以下内容:
Introducing the zPhone, the most advanced Android phone on the market. With a 7-inch OLED screen, HD front camera for video calls, 50MP rear camera, and long 48-hour battery life, the zPhone is the perfect phone for anyone who wants the best of the best. Here are just a few of the things you can do with the zPhone: - Take stunning photos and videos with the 50MP rear camera - Make crystal-clear video calls with the HD front camera - Stream your favorite movies and shows on the large 7-inch OLED screen - Play games for hours on end with the long 48 Hr battery life The zPhone is the perfect phone for anyone who wants a powerful, versatile, and stylish device. Order yours today! zPhone. The future of mobile is here.
-
现在,让我们将Token 限制参数设置为 50 并再次点击提交。
-
由于我们将输出 Token 限制减少到 50,模型生成的新响应现在将小得多:
Introducing the zPhone, the most advanced Android phone on the market. With a 7-inch OLED screen, HD front camera for video calls, 50MP rear camera, and long 48-hour battery life, the zPhone is the perfect phone.
因此,我们看到了如何指导文本生成模型生成文本内容(在这个案例中是营销内容),以及如何限制其输出大小。
示例 2 – 以结构化格式提交示例和文本提示,以获取特定格式的生成输出
在这个例子中,我们将尝试让模型为我们的问题提供非常简洁的答案:
- 导航到 GCP 控制台>> Vertex AI >> 生成 AI 工作室 >> 语言 >> 文本提示 >> 结构化,如下所示:
图 12.4 – GenAI Studio 结构化输入
前一个屏幕截图所示的结构化格式允许我们提交一些输入-输出对作为示例,以向模型展示所需的输出格式或风格。在这个例子中,我们希望模型提供简洁的答案,最好是键值格式。
-
在测试 | 输入部分输入以下文本并点击提交:
Give me key stats about Canada.
图 12.5 – GenAI Studio:模型响应
-
您可以看到,模型的响应虽然正确,但不是一个简洁的答案。
-
现在,让我们在输入提示中添加一些示例,以便模型可以看到我们期望的输出格式/风格。
-
在示例 | 输入部分,添加以下内容:
Give me key stats about the USA.
在示例 | 输出部分添加以下文本:
- Population - 331,000,000 - Land Area - 3.7 million sq miles - GDP - 23.3 Trillion
-
点击提交:
图 12.6 – GenAI Studio:带有结构化输入的响应
-
如前一个屏幕截图所示,答案现在更加简洁,并且与提示提交的示例格式相匹配:
Population - 37,595,000 Land Area - 9.98 million sq miles GDP - 1.7 Trillion
尽管在这个简单的例子中,我们只提交了一个示例,但对于更复杂的使用案例,你可以提交一个长长的示例列表,以帮助模型更好地理解你的输出要求。
示例 3 – 使用 GenAI Studio(视觉)生成图像
在本例中,我们将使用文本到图像模型根据我们输入的图像文本描述生成图像:
-
导航到 GCP 控制台 >> Vertex AI >> 生成式 AI 工作室 >> 视觉 >> 生成。
-
在屏幕底部的提示字段中,输入以下文本并点击提交:
Red panda riding a bike
-
在侧边栏中,选择数字艺术风格并点击提交。
-
图像模型根据我们提供的提示生成以下图像:
图 12.7 – GenAI Studio:生成的图像
- 现在,将风格更改为摄影并再次点击提交:
图 12.8 – GenAI Studio:设置为摄影风格的生成图像
你可以从前一个屏幕截图中看到,模型现在生成的图像更加逼真。
现在,你可以尝试调整提示词来查看如何控制生成的图像。
示例 4 – 生成代码样本
在本例中,我们将使用 Vertex AI 代码生成模型(codey
/code_bison
)生成一个 Python 函数:
-
导航到 GCP 控制台 >> Vertex AI >> 生成式 AI 工作室 >> 语言 >> 代码提示。
-
在提示字段中输入以下文本:
Generate a Python function to add two integer values entered by a user
-
响应应类似于下面显示的生成代码:
def add_integers(): """This function adds two integer values entered by a user. Returns: The sum of the two integer values.""" # Get the two integer values from the user. first_integer = int(input("Enter the first integer: ")) second_integer = int(input("Enter the second integer: ")) # Add the two integer values and return the result. return first_integer + second_integer
尽管在前面的例子中,我们使用了代码生成模型来创建一个非常简单的代码样本,但你可以通过修改提示词添加更多关于你要求的信息,并生成更复杂的代码。目前大多数可用的代码生成模型还不能完全取代开发者,即使是相对简单的编码任务,但它们确实有助于加速编码工作流程,并作为编码者的优秀助手。
使用 Vertex AI 构建和部署 GenAI 应用程序
现在,让我们看看如何使用 Vertex AI GenAI 功能进行编程,并将它们集成到你的应用程序中。
用例 1 – 使用 GenAI 模型从扫描的文档中提取关键实体
我们将使用美国专利和商标局公开的专利文件作为样本文档,并从文档中提取以下信息:
-
发明者姓名
-
发明者位置
-
专利号
在这个笔记本中,你将执行以下步骤以提取所需信息:
-
使用 Document AI 光学字符识别(OCR)工具从文档中提取文本。
-
将文本输入到 GenAI 模型(
text-bison
)中,并附带一个关于我们需要从文本中提取的实体的详细提示。 -
解析从模型接收到的响应,将其输入到数据仓库(BigQuery)中。
如果我们使用传统的训练深度学习(DL)模型从扫描的文档中提取这些信息的方法,我们将需要更大的一组标注数据资源来训练模型。使用预训练的 LLM,我们能够更快地完成相同的任务,无需任何训练数据集,也无需训练新模型。此外,如果我们后来想从文档中提取任何其他实体,我们只需修改模型提示以包括该新实体即可。使用非 LLM 模型,你将不得不花费时间标注额外的数据样本并重新训练模型以包括该新标签。
讨论上述标准实体提取方法的局限性
对于我们的用例和文档样本,这种方法效果良好,因为我们能够将所有文本放入我们的 LLM 模型上下文窗口(模型可以使用的最大文本输入大小)。但在现实世界中,我们经常遇到需要考虑的信息/文本量远大于此的情况,并且不能作为单个提示的一部分发送给模型。例如,如果你对一个跨越 500 页书籍的故事有疑问,为了得到最准确的答案,你需要将所有 500 页的文本以及你的问题一起输入到 LLM 中。但截至目前,即使是可用的最大的语言模型也无法将如此多的文本作为输入提示。因此,在这种情况下,我们使用一种称为检索增强生成(RAG)的替代技术,我们将在下一个用例中介绍。
用例 2 – 使用 Vertex AI 实现基于 RAG 方法的 QA 解决方案
该解决方案也将基于我们的文档语料库以减轻幻觉。在我们开始练习之前,让我们首先了解 RAG 框架是什么。
什么是 RAG?
RAG 是一种在 NLP 中使用的方 法,通过结合检索机制来增强语言模型的能力。它旨在提高语言生成模型的性能,特别是在提供更准确和上下文相关的响应方面。以下是 RAG 工作原理的简要概述:
-
检索机制:第一步涉及从大量文本语料库中检索相关文档、段落或文本片段。这通常是通过使用向量检索系统来完成的。输入查询(或问题)被编码成向量表示,然后使用这个向量在预先编码的文档或段落数据库中搜索,以找到最相关的文档。这种检索基于向量表示的相似性。
-
增强:RAG 的增强组件将检索到的文档或段落与初始提示结合,以创建增强提示。这个增强提示为生成模型提供了更多的上下文和信息来工作,这有助于提高生成文本的质量。
-
答案生成:在检索到的文档的上下文中,使用一个 LLM(大型语言模型)来生成响应。此模型将原始查询和检索到的文档作为输入,允许它生成由检索文本中包含的外部知识所启发的响应。
图 12.9 – 检索增强生成(RAG)方法
RAG 系统提供了几个显著的优势:
-
增强准确性和相关性:通过将信息检索与语言生成相结合,RAG 系统可以提供更准确、更符合用户查询的响应。这对于需要特定、事实性信息的查询尤其有益。
-
获取最新信息:传统的语言模型受限于它们训练时所使用的信息,这些信息可能会过时。由于训练这些模型所需的时间和计算资源,不断用新信息重新训练这些模型并不可行。RAG 通过从最新的文档中检索相关信息来克服这一点,确保响应包括最当前的数据。
-
改进的窄查询处理:RAG 擅长处理关于窄或不太常见主题的查询。由于它可以从广泛的来源获取信息,因此它不像传统模型那样受限于训练数据的范围。
-
可扩展性和灵活性:通过修改检索组件,RAG 系统可以适应不同的领域和类型的查询。这使得它们对于各种应用都是可扩展和灵活的。
-
上下文理解:外部信息的集成使得 RAG 能够以更细致的上下文方式理解和响应查询,从而产生更复杂和细致的对话。
-
训练成本效益:由于 RAG 系统可以通过外部信息增强其响应,因此它们可能需要比仅从训练数据中学习一切的传统模型更少(且更昂贵)的训练数据集。
这些优势使得 RAG 成为开发高级 AI 系统中的强大工具,尤其是在准确性、时效性和知识深度至关重要的领域。
现在,让我们开始动手练习。在这个练习笔记本中,我们将导入一个包含字母公司每季度 10K 财务报告的大型 PDF 文件,该报告包含公司每季度共享的关键财务信息,然后使用 Vertex AI GenAI 工具创建一个问答系统,我们可以用它来询问关于字母公司收益的问题。
下面是我们将要执行的步骤:
-
导入 PDF 并提取文本。
-
将提取的文本分解成更小的文本片段或块,以便以后可以将它们与被问及的问题相匹配,以找到相关信息。
-
使用 Vertex AI 文本嵌入模型将这些片段转换为嵌入/向量。将这一步想象为为每个文本片段创建单独的指纹,这样我们就可以在以后尝试找到与我们要回答的问题文本最接近的匹配项。
-
创建一个“数据存储”向量,用于存储在第 2 步中从文本片段创建的嵌入。
-
将提供的问题转换为嵌入,然后尝试在向量数据存储中找到最接近的 20 个匹配项。
-
通过结合问题文本和在第 5 步中找到的 20 个最接近匹配的文本,为我们的 LLM(Vertex AI 文本-bison 模型)创建一个输入提示。
-
将提示输入到 LLM(Vertex AI 文本-bison 模型)中,以获得可以呈现给用户的最终答案。
第十二章 – Vertex GenAI_RAG 笔记本将引导您完成之前描述的步骤。(github.com/PacktPublishing/The-Definitive-Guide-to-Google-Vertex-AI/blob/main/Chapter12/Chapter12_Vertex_GenAI_RAG.ipynb
)
注意
由于本章的重点是 GenAI,我们没有深入探讨用于查找匹配嵌入的向量数据库和匹配算法的领域。前面的练习笔记本使用一种简单的方法来计算余弦相似度分数,以从 pandas DataFrame 中的数据库中找到最接近的匹配向量。这对于小规模数据来说效果不错,但对于需要存储数十亿嵌入和低于 5 毫秒匹配延迟的实际解决方案,我们建议您使用 Vertex AI Vector Search(以前称为匹配引擎)等托管向量数据库或如 PostgreSQL 的pgvector 扩展等开源选项。
现在,让我们看看如何在 Vertex AI 中自定义预训练的语言模型。
通过 Vertex AI 进行模型调整以增强 GenAI 性能
尽管基础预训练模型在各种通用任务上表现出色,但有时在特定任务上表现不足,仅通过提示调优无法充分解决性能差距。为了弥合这一差距,Vertex AI 上的模型调优可以显著提高模型在特定任务上的性能,并确保在标准指令不足时遵守特定的输出要求。本节将介绍 Vertex AI 上的模型调优。
存在几个令人信服的理由来调优 LLM:
-
改进性能:调优可以显著提高 LLM 输出在特定任务中的准确性、流畅性和相关性
-
领域自适应:调优使 LLM 能够针对特定领域或数据类型进行专业化,确保生成的输出与领域的术语和风格一致
-
偏差缓解:调优可以帮助缓解预训练 LLM 中固有的偏差,促进更公平和更均衡的结果
模型调优涉及使用广泛覆盖独特任务的数据库训练模型。这种方法对于利基任务尤其有效,因为即使使用小型样本数据库进行调优也能带来显著的性能提升。调优后,模型在提示中需要更少的示例才能有效地执行。
可以采用各种方法来定制 LLM 以满足不同的目的:
-
提示工程是一种计算成本较低的调优 LLM 的方法。这涉及到创建输入提示,以引导 LLM 生成所需的输出。提示工程对于各种任务都可能是有效的,但它可能比微调更难掌握。
-
微调是调优 LLM 最常见的方法。这涉及到在特定任务的标记示例数据集上对 LLM 进行监督训练,更新模型所有层的权重。微调可能非常有效,但由于当今典型 LLM 的大小,它也可能计算成本高昂且耗时。
-
参数高效微调(PEFT)是一种可以用来使用有限的计算资源微调 LLM 的技术。尽管 PEFT 与上述微调方法类似,但它通过仅调整底层 LLM 中某些层的参数,而其余层保持冻结,从而显著减少训练过程中需要更新的参数数量。这显著减少了所需的计算量,并降低了整体训练成本。
-
强化学习(RL)也可以用来调优 LLM。这涉及到训练 LLM 生成最大化特定奖励信号的输出。RL 对于难以用标记示例定义的任务可能有效。
现在让我们看看如何使用 Vertex AI 进行基础模型的调优。
使用 Vertex AI 监督调优
Vertex AI 目前提供 PEFT 监督式调整功能来调整 LLMs。它适用于分类、情感分析(SA)、实体提取、简单内容摘要和特定领域查询等任务。
请参考附带的 GitHub 仓库中的第十二章 – LLM – 监督训练笔记本,进行端到端练习,以在 Vertex AI 中运行 LLM 调整作业。以下是您需要遵循的关键步骤以运行监督式调整作业:
-
input_text
: 此字段包括模型的提示 -
output_text
: 此字段应包含模型调整后的预期响应
示例:
{"input_text": "What is the most compute efficient method to tune a foundation LLM ",
"output_text": "PEFT"}
{"input_text": "What is the best tuning method for an LLM to get best accuracy?",
"output_text": "Full fine tuning"}
您可以使用的样本数据集:input_text
字段的最大标记长度为 8,192(约 32k 个英文字符),而output_text
字段的最大标记长度为 1,024(约 4k 个英文字符)。
-
将数据集上传到 Google Cloud Storage 存储桶。
-
创建一个监督式调整作业(详细步骤见 附带的笔记本)。
启动调整作业时需要提供以下参数:
project_id: GCP Project ID, used to initialize vertexai location: GCP Region, used to initialize vertexai model_display_name: Customized Tuned LLM model name training_data: GCS URI of jsonl file or pandas dataframe of training data. train_steps: Number of training steps to use when tuning the model. evaluation_dataset: GCS URI of jsonl file of evaluation data. tensorboard_instance_name: The full name of the existing Vertex AI TensorBoard instance: projects/PROJECT_ID/locations/LOCATION_ID/tensorboards/TENSORBOARD_INSTANCE_ID
下面是启动调整作业的 Python 代码:
vertexai.init(project=project_id, location=location, credentials=credentials) eval_spec = TuningEvaluationSpec(evaluation_data=evaluation_dataset) eval_spec.tensorboard = aiplatform.Tensorboard( tensorboard_name=tensorboard_instance_name) model = TextGenerationModel.from_pretrained("text-bison@001") model.tune_model( training_data=training_data, # Optional: model_display_name=model_display_name, train_steps=train_steps, tuning_job_location=<Region>, tuned_model_location=location, tuning_evaluation_spec=eval_spec,) print(model._job.status) return model
-
从Vertex AI 模型注册表加载调整后的模型以运行预测或评估作业(详细步骤见 附带的笔记本)
import vertexai from vertexai.preview.language_models import TextGenerationModel model = TextGenerationModel.get_tuned_model(TUNED_MODEL_NAME)
注意
在出版时,您可以为微调作业使用的最大样本数量限制为 10,000。
现在,让我们看看 Vertex AI 的本地功能,这些功能有助于确保 LLMs 的输出在企业环境中既安全又合规。
生成内容的过滤安全
尽管对于广泛的应用场景非常有用,但 LLMs 通过从公共领域收集的大量数据集吸收人类知识和行为(好的和坏的)也带来了这些模型被利用或生成有害内容的危险。这些模型生成未预料到的输出并不罕见,包括冒犯性、不敏感或不正确的内容。
对于开发者来说,在部署前对模型有深刻的理解和细致的测试仍然是至关重要的,以避免任何潜在的问题。为了帮助开发者完成这项任务,GenAI Studio 集成了内置的内容过滤系统,而 PaLM API 提供了安全属性评分,帮助客户检查 Google 的安全过滤器,并建立与其个别用例和业务需求相一致的信度阈值。
这是作为 Google PaLM 模型一部分提供的完整安全属性列表:
安全属性 | 描述 |
---|---|
诽谤 | 针对身份和/或受保护属性的负面或有害评论。 |
毒性 | 粗鲁、不尊重或亵渎的内容。 |
性 | 包含对性行为或其他淫秽内容的引用。 |
暴力 | 描述针对个人或群体或一般血腥场景的暴力场景。 |
侮辱 | 对个人或一群人的侮辱、煽动性或负面评论。 |
亵渎 | 亵渎或粗俗的语言,如诅咒。 |
死亡、伤害和悲剧 | 人类死亡、悲剧、事故、灾难和自残。 |
枪支和武器 | 提及刀、枪、个人武器及其配件(如弹药、枪套等)的内容。 |
公共安全 | 提供救济和确保公共安全的机构和组织。 |
健康 | 人类健康,包括:健康状况、疾病和失调、医疗疗法、药物、疫苗接种和医疗实践资源,包括支持小组。 |
宗教和信仰 | 处理超自然法则和存在可能性的信仰体系;宗教、信仰、信念、灵性实践、教堂和礼拜场所。包括占星术和神秘主义。 |
非法药物 | 休闲和非法药物;毒品用具和种植、头店等。包括通常用于休闲的药物(例如大麻)的药用。 |
战争和冲突 | 涉及大量人员的战争、军事冲突和重大物理冲突。包括对军事服务的讨论,即使与战争或冲突没有直接关系。 |
金融 | 消费者和商业金融服务,如银行、贷款、信贷、投资、保险等。 |
政治 | 政治新闻和媒体;关于社会、政府和公共政策的讨论。 |
法律 | 与法律相关的内容,包括律师事务所、法律信息、主要法律材料、法律助理服务、法律出版物和技术、专家证人、诉讼顾问和其他法律服务提供商。 |
表 12.1 – PaLM 模型的 安全属性
当您向 PaLM 模型提交 API 请求时,API 的响应包括每个安全属性的置信度分数,如下所示:
{"predictions": [
{"safetyAttributes": {
"categories": [Derogatory", "Toxic", "Violent", "Sexual", "Insult", "Profanity", "Death, Harm & Tragedy", "Firearms & Weapons", "Public Safety", "Health", "Religion & Belief", "Illicit Drugs","War & Conflict", "Politics", "Finance", "Legal"],
"scores":[0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1, 0.1,0.1,0.1,],
"blocked": false},
"content": "<>"}]}
前一个响应中的分数是每个风险类别的风险值。
开发者可以在他们的应用程序中编程所需的安全阈值,以移除 API 返回的任何有害内容。例如,对于面向年轻受众的应用程序,开发者可能会设置严格的过滤器,以消除任何在安全属性上的分数超过 0.1 的文本。但如果要求是为在论坛上分享的内容创建内容,其中成年人讨论电子游戏和在游戏中的武器,那么开发者可能会放宽对枪支和武器安全属性的过滤器。
备注
请注意,目前 PaLM 模型在向客户发送响应之前确实应用了一些初始安全过滤器。这些过滤器目前还不能完全关闭。
摘要
Vertex AI GenAI 是一个强大的工具套件,可用于创建各种 GenAI 应用。凭借其易于使用的界面和丰富的预训练模型库,Vertex AI GenAI 使得所有技能水平的开发者都能快速轻松地开始使用 GenAI。
我们希望现在,在阅读完这一章之后,您已经拥有了关于通用人工智能(GenAI)及其使用 Vertex AI 实现的基础和实践知识。凭借与基础模型交互和利用的技能,对基本提示工程的理解,以及对谷歌 GenAI 模型固有的安全特性的理解,您现在已经具备了开始实际工作和探索使用 GenAI 的创新应用的充分准备。
在下一章,第十三章,文档 AI – 处理文档的端到端解决方案中,我们将介绍如何使用谷歌云的文档 AI 解决方案从扫描的文档中提取信息,并将其结构化成可以被您的数据存储解决方案摄取的格式。
参考文献
Vertex AI – 负责任的 AI:cloud.google.com/vertex-ai/docs/generative-ai/learn/responsible-ai#safety_attribute_descriptions
第十三章:文档人工智能 - 处理文档的端到端解决方案
几乎每家企业都依赖于某种形式的文档来日常传达信息。这可能包括电子邮件、合同、表格、PDF 等等。由于这些数据是非结构化的,许多企业往往无法充分利用这些数据带来的价值。如果有一种方法可以将这些大量文档数据转换为机器可读格式,它可以帮助完成许多有用的任务,例如自动化业务流程、进行数据分析、应用人工智能和机器学习,等等。考虑到数据量的大小,通常不可能手动解析这些文档来提取信息。像光学字符识别(OCR)这样的工具可以帮助部分自动化将文档转换为文本格式的任务,但仍然是非结构化的,并且需要更多的努力才能使其有用。
文档人工智能是 Google Cloud 提供的一项托管服务,它将非结构化内容(不同类型的文档)转换为结构化数据。它是一个端到端基于云的平台,用于以结构化的方式提取和分类信息,例如键值对,以便使这些数据易于使用。文档人工智能是一个复杂的解决方案,涉及许多基于人工智能和机器学习的算法,如 OCR、图像识别、自然语言处理(NLP)、实体提取、机器翻译等等。
在本章中,我们将学习如何在 GCP 上使用文档人工智能来提取任何业务问题的有用信息。本章将涵盖以下主要内容:
-
什么是文档人工智能?
-
现有文档人工智能处理器的概述
-
创建自定义文档人工智能处理器
技术要求
本章中展示的代码示例可以在以下 GitHub 仓库中找到:github.com/PacktPublishing/The-Definitive-Guide-to-Google-Vertex-AI/tree/main/Chapter13
。
什么是文档人工智能?
文档人工智能是一种端到端的人工智能解决方案,用于从任何类型的非结构化文档中提取和分类有用的信息,包括扫描图像、PDF、表格、电子邮件和合同。文档人工智能的解决方案包括用于提取和其他文档相关任务的预训练机器学习模型,并且它还提供了灵活性,可以重新训练现有模型和训练自定义模型,而无需编写大量代码。文档人工智能是一个统一的解决方案,可以帮助企业管理整个非结构化文档生命周期,确保高精度和低成本,以加速部署以满足客户期望。
Google Cloud 文档人工智能平台的一些关键特性如下:
-
Google 的最先进人工智能:文档人工智能平台建立在 Google 在计算机视觉(包括 OCR)、NLP 和语义搜索等各个领域的行业领先人工智能创新之上,使该平台非常准确且有用。
-
统一的控制台:它有一个统一的控制台,让我们可以快速访问所有相关的模型和工具,包括 OCR 和表单解析器。文档 AI 工作台让我们可以轻松地创建自定义或微调现有模型。文档 AI 仓库让我们可以存储、搜索和管理文档,甚至触发工作流。
-
Google 知识图谱:我们可以利用 Google 的知识图谱技术来验证和丰富解析信息,如地址和电话号码,与互联网上的实体进行对比。
-
人机协作 AI:此功能可以帮助我们在确保人工审核的情况下实现更高的准确性。除了准确性之外,它还可以帮助使用专门构建的工具来解释预测。
现在,让我们来看看文档 AI 处理器。
文档 AI 处理器
文档 AI 处理器是文档文件和执行文档处理相关任务的底层机器学习模型之间的接口。处理器可以用来分类、拆分、解析或分析文档。文档 AI 处理器可以分为以下三个类别:
-
通用:这些是预构建的处理器,可以应用于任何用例。OCR 是一个通用处理器示例,它是用例或文档无关的。
-
专用:这些也是预构建的处理器,专门构建来与某些固定类型的文档良好地工作。由于这些是专用的,它们在执行任务时通常非常准确。专用处理器在识别验证、贷款应用、合同以及与发票和收据等付款相关文档相关的用例中更有用。
-
自定义:这些可以根据用例和需求创建。有时,我们可能需要微调现有模型或训练自定义模型。自定义处理器提供了根据客户需求使用解决方案的灵活性。
图 13.1 可以帮助确定哪种处理器更适合特定的用例:
图 13.1 – Google Cloud 上的文档处理概述
既然我们从理论层面已经对文档 AI 平台有了很好的理解,接下来,我们将通过一些练习来了解如何使用这个解决方案来解决业务问题。
现有文档 AI 处理器的概述
如前所述,文档 AI 平台为通用用途以及一些专用用途提供了预构建的解析器。由于这些处理器是预构建的,它们可以轻松地用于任何相关用例,几乎不需要任何努力。在举例说明这些处理器的工作原理之前,让我们首先查看作为 Google Cloud 文档 AI 平台一部分的可用处理器列表:
-
文档 OCR:识别和提取超过 200 种语言中的机器打印文本和手写文本
-
表单解析器:除了 OCR 文本外,还提取键值对(实体和复选框)、表格和通用实体
-
智能文档质量处理器:根据文档的可读性评估文档质量并提供质量评分
-
文档分割器:根据逻辑边界自动分割文档
Document AI 为我们提供了许多专业化的处理器。以下是一些常见的专业预构建处理器的示例:
-
合同解析器:从法律合同中提取文本和值,如协议日期、生效日期和各方
-
法国驾照解析器:从法国驾照中提取姓名、文件 ID、出生日期等字段。
-
美国护照解析器:从美国护照图像中提取重要字段,如姓名、出生日期和文件 ID
-
工资单解析器:从工资单文档中提取姓名、公司名称和金额等信息
-
发票解析器:提取发票号码、供应商名称、金额、税额、到期日等信息
现在,让我们尝试在示例文档上使用这些解析器之一。
使用 Document AI 处理器
使用 Document AI 处理器开始处理文档有三个主要步骤:
-
选择处理器:为特定用例选择最佳处理器对于获得最佳结果至关重要。Document AI 解决方案的文档可以帮助确定给定用例的最佳解析器。
-
创建处理器:创建处理器意味着将预构建处理器部署到端点,以便它可以接受请求。
-
处理文档:在此步骤中,我们将文档处理请求发送到端点以获取提取的结构化信息。
现在,让我们按照上述步骤尝试其中一个解析器。在这个例子中,我们将尝试通用的 Document OCR 解析器,从示例文档中提取文本信息。
第一步是打开 Google Cloud 控制台,转到Document AI,然后在左侧面板中点击处理器画廊。处理器画廊包含所有带有类别的预构建文档处理器。转到文档 OCR解析器,并点击创建处理器按钮。它将要求我们提供处理器名称和部署区域。几秒钟后,我们应该能在我的处理器标签中看到这个处理器,如图图 13.2所示:
图 13.2 – 在 Google Cloud 的 Document AI 中创建自定义处理器
通过点击处理器的名称,我们可以获取预测端点和其他有用信息(见图 13.2):
图 13.3 – Google Cloud 控制台 UI 中的 Document AI 处理器详细信息
如前一个屏幕截图所示的控制台 UI,也提供了直接上传文档并测试结果的选择。让我们通过上传一个示例文档来试试这个功能。为了使事情更加复杂和有趣,我在一张纸上用我糟糕的笔迹写了一些东西。让我们看看它在上面是如何工作的(见图 13**.4):
图 13.4 – 在示例手写图像上的文档 OCR 分析结果
如我们所见,文档 OCR 在手写文档上工作得很好。
现在,让我们在一个 Jupyter Notebook 单元中尝试这个功能,通过使用 Python 进行 API 请求来获取输出。在控制台中转到 管理版本 选项卡时,你可以从不同的训练 API 版本中选择使用(见图 13**.5):
图 13.5 – 管理文档 AI 处理器的版本
图 13**.6 展示了如何在笔记本中通过 Python 请求从文档 OCR 解决方案中获取响应。完整的代码可在本章的 GitHub 仓库中找到:
图 13.6 – 使用 Python 请求从文档 AI 处理器获取预测
在这个 Jupyter Notebook 的屏幕截图中,我们正在使用 process_document_sample
函数。这个函数可在 Google Cloud 的公共 GitHub 示例中找到。此函数也可在本章的 GitHub 仓库中找到。我为这个函数运行了以下代码片段:
def process_document_sample(
project_id: str,
location: str,
processor_id: str,
file_path: str,
mime_type: str,
field_mask: str = None,
):
如果你使用的是除 us
之外的位置,你必须设置 api_endpoint
:
opts = ClientOptions(api_endpoint=f"{location}-documentai.googleapis.com")
client = documentai.DocumentProcessorServiceClient(client_options=opts) name = client.processor_path(project_id, location, processor_id)
# Read the file into memory
with open(file_path, "rb") as image:
image_content = image.read()
现在,我们必须将二进制数据加载到文档 AI 的 RawDocument
对象中:
raw_document = documentai.RawDocument(content=image_content, mime_type=mime_type)
# Configure the process request
request = documentai.ProcessRequest(
name=name, raw_document=raw_document, field_mask=field_mask
)
result = client.process_document(request=request) document = result.document
# Read the text recognition output from the processor
print("The document contains the following text:")
print(document.text)
通过这样,我们就有了一个很好的了解如何使用预构建的文档 AI 处理器,并通过在底层机器学习模型上使用 API 调用来获取结果。在下一节中,我们将学习如何在预构建处理器不完全符合用例时创建自定义处理器。
创建自定义文档 AI 处理器
如果我们无法找到适合我们用例的预构建处理器,文档 AI 工作台允许我们从零开始构建和训练自己的定制处理器,并且几乎不需要任何努力。如果我们进入文档 AI 中的 工作台 选项卡,我们将获得以下创建自定义处理器的选项(见图 13**.7):
图 13.7 – 用于创建基于模型的自定义处理器的文档 AI 工作台
在这个练习中,我们将使用自定义文档提取器解决方案来创建自定义处理器。一旦我们点击创建处理器,我们就可以在我的处理器标签页中找到这个处理器。如果我们点击处理器,我们将获得训练、评估和测试自定义处理器的选项,以及管理自定义模型部署版本的选项。训练一个版本后,我们还可以配置人工反馈功能。参见图 13.8 中的这些选项:
图 13.8 – Google Cloud 控制台 UI 中的自定义文档 AI 处理器详细信息
正如你所见,创建一个自定义处理器需要一个训练数据集,这样我们就可以在我们的特定用例相关文档上微调现有的机器学习模型。只有当预构建的通用解决方案在文本提取准确性方面不能满足我们的业务期望时,我们才应该选择自定义处理器。这是因为创建自己的训练数据集可能是一个复杂的过程,因为它需要人工努力。如果我们已经有一个好的数据集可用,那么使用文档 AI 平台训练自定义处理器只需几步点击即可。
一旦我们的自定义处理器完成训练并在测试中显示出良好的结果,我们就可以将其作为模型版本部署。然后,可以通过 API 调用在生产中使用这个版本,就像预构建处理器被使用一样。
摘要
本章强调了这样一个事实:每个企业或公司都使用多种形式的文档(如电子邮件、合同、表格、PDF 和图像)来共享和存储信息。文档 AI 是 Google Cloud 上的端到端解决方案,它使我们能够以结构化的方式提取这些信息,以便可以轻松地用于训练机器学习模型或执行其他下游任务,从而从这些文档中的信息中获取大量价值。
通过完成本章,你现在应该对文档 AI 及其对每个企业的重要性充满信心。你也应该对文档 AI 中的预构建处理器有一个良好的理解,并且应该能够轻松地将它们集成到应用程序中。最后,如果预构建处理器不能满足你的期望,你可以选择构建自定义处理器以满足你的用例目标。
我们现在对 Google Cloud 上的文档 AI 有了很好的理解。在下一章中,我们将学习更多与视觉、自然语言处理和语音相关的 Google 产品。
第十四章:视觉、NLP 和语音的 ML API
Google 的研究团队将他们数十年的研究和经验投入到为许多复杂问题创造最先进解决方案的过程中。其中一些解决方案,包括视觉 AI、翻译 AI、自然语言 AI 和语音 AI,相当通用,可以轻松地用于从复杂和非结构化数据中获取见解。这些解决方案以服务的形式提供,因此作为客户,我们无需担心管理这些产品的基础设施、可用性或扩展。许多流行的 Google 产品,如地图、照片、Gmail、YouTube 等,每天都在使用这些产品来提供 AI 驱动的体验。
在本章中,我们将探讨一些这些流行的产品,并了解可以使用它们解决哪些问题。本章将涵盖的主要主题如下:
-
Google Cloud 上的 Vision AI
-
Google Cloud 上的翻译 AI
-
Google Cloud 上的自然语言 AI
-
Google Cloud 上的语音 AI
Google Cloud 上的 Vision AI
计算机视觉是人工智能(AI)的一个领域,它使计算机和系统能够从视觉数据(如数字图像和视频)中提取见解。理解图像和视频是一个复杂的过程,但随着该领域不断的研究,人工智能研究社区已经引领了许多智能的方法,从非结构化数据(如图像和视频)中提取信息。从数字图像和视频中提取的信息可以被企业利用,以大规模采取行动和提供推荐。Google Cloud 提供了以下两个产品作为解决计算机视觉问题的平台:
-
视觉 AI
-
视频 AI
现在,让我们深入探讨这些产品中的每一个。
视觉 AI
Google Vision AI 提供了一个平台,使用预训练的 API、AutoML 或自定义模型来创建基于视觉的应用程序。使用 Vision AI,我们只需几分钟就能创建图像和视频分析解决方案。这个产品允许我们使用 AutoML 训练我们的自定义分类或目标检测模型,同时也允许我们训练完全自定义的模型。Vision AI 为常见的视觉任务提供了预训练的 API,例如目标检测、手写识别、图像元数据创建等。在 Google Vision AI 平台下有三个常见的提供产品:
-
Vertex AI 视觉
-
自定义 ML 模型
-
视觉 API
让我们更深入地了解一下它们。
Vertex AI 视觉
Vertex AI 视觉是一个全托管端到端应用开发环境,使用它可以快速原型化符合我们业务需求的眼动解决方案。Vertex AI 视觉可以帮助我们在几分钟内解决复杂问题并创建有价值的解决方案,从而节省大量开发成本。Vertex AI 视觉允许我们以大规模摄取实时视频和图像流,以支持实时生产用例。应用开发界面也非常简单,并允许我们通过拖放功能快速构建应用。
让我们看看 Google Cloud 控制台中的 Vertex AI 视觉界面。请确保首先启用视觉 API,然后从左侧面板导航到 Vertex AI 视觉。或者,您也可以在顶部搜索它。界面应该看起来类似于以下内容:
图 14.1 – Vertex AI 视觉界面
现在,我们可以通过点击创建应用按钮开始构建我们的应用,之后我们将被要求为应用提供一个唯一的名称。一旦我们点击创建,我们将进入应用开发工作室,在那里我们可以找到根据应用需求使用预训练或专用模型的不同选项。界面非常简单,并允许我们通过拖放功能构建应用。
以下截图显示了一个简单的对象检测和标签识别应用,该应用从 GCS 存储桶获取输入。执行此任务后,它将输出写入到视觉人工智能仓库位置。我们已为此应用配置了批量预测,因此输入源是包含图像的 GCS 存储桶,但我们还有其他输入类型选项,例如流或实时预测用例。让我们看看工作室界面和我们的示例应用:
图 14.2 – Vertex AI 视觉工作室用于快速应用创建
此应用图可以一键部署,我们可以在几分钟内开始在生产环境中使用它。Vertex AI 视觉提供了一些强大的预训练模型以及一些准备就绪的专用模型,可以部署使用。它还为我们提供了灵活性,可以使用 Vertex 定制训练导入或创建自定义模型。在部署视觉应用时,我们还可以选择流输出类型,以便我们可以为我们的应用启用模型监控。
自定义机器学习模型
视觉人工智能支持为更专业的用例创建自定义机器学习模型。我们可以使用以下方法之一来创建专用模型:
-
AutoML:Vertex AI 中的 AutoML 易于使用的图形界面使我们能够以最小的努力和技术知识来训练我们的自定义模型。使用 AutoML,我们可以通过简单地上传训练文件来训练图像或视频智能模型。我们还可以根据我们的要求优化模型以降低延迟、大小和精度。在撰写本文时,AutoML 支持图像数据的目标检测和分类模型,以及视频数据的目标跟踪、动作识别和分类。
-
自定义训练:当 AutoML 不支持我们的用例时,自定义训练非常有用。它需要更多的努力和技术深度。自定义训练让我们可以选择所需的模型开发框架、用于启动训练作业的 VM 类型以及基于训练需求的各种类型的加速器。使用自定义训练,我们可以为不同的复杂用例训练我们的专业模型,并将它们部署到实时、流或批量预测用例中。
接下来,我们将学习关于视觉 API 的内容。
视觉 API
视觉 API 提供了强大的预训练机器学习模型,用于从图像中读取打印或手写文本、检测对象、将图像分类到数百万个预定义类别、标记显式内容等任务。视觉 API 模型可以通过 REST 和 RPC API 进行消费。例如,从图像中检测文本的解决方案可以与其他解决方案(如翻译)结合,以创建更复杂的批量、流或实时预测任务的生产解决方案。官方视觉 API 文档提供了大量的代码示例,用于快速原型设计视觉解决方案。
视频 AI
视频 AI 专门设计用于大规模分析视频数据,以理解给定输入视频中的固有内容、对象、地点或动作。它可以通过流视频注释和基于对象的触发机制来支持实时用例,从而从数据中获得洞察。视频 AI 可以在镜头、帧或视频级别从视频中提取有用的元数据。以下是一些 Video AI 的常见用例:
-
内容审核:大规模识别视频中显示的不适当内容。
-
推荐:我们可以使用视频智能 AI 的输出,并结合用户观看历史,以大规模提供内容推荐。
-
媒体归档:我们可以使用从视频智能 API 中提取的元数据来高效地存储媒体,以便在需要时更快地检索。
-
广告:我们可以在视频中识别放置上下文广告的最佳位置。
这里有两种在 Google Cloud 上开始开发视频 AI 解决方案的常见方法:
-
AutoML 视频智能
-
视频智能 API
让我们更深入地了解一下。
AutoML 视频智能
有时候,我们会遇到一些用例,在这些用例中,我们希望在视频内识别某些类型的对象或事件,而这些对象或事件并不是视频智能 API 本身所涵盖的。在这种情况下,我们可以开发自己的定制模型来识别和跟踪视频中的各种新对象。AutoML 通过其图形用户界面,使得在没有太多机器学习经验的情况下训练定制视频智能模型变得更加容易。
在撰写本文时,AutoML 视频智能支持以下用例:
-
动作识别:在这个用例中,解决方案分析视频并返回在动作发生的时间框架内执行的一系列预定义动作。它可以识别诸如足球进球、击掌等动作。
-
分类:分类模型可以将视频分类到一系列预定义的类别中,如体育视频、卡通、电影等。
-
对象跟踪:我们可以训练一个模型来持续跟踪视频中的某些对象——例如,我们可以在一场实时进行的足球比赛中跟踪足球。
如果 AutoML 不符合我们的需求,我们总是可以回到 Vertex AI 定制模型开发,并训练适合我们用例的定制视频智能模型。定制训练让我们能够定义自己的定制模型架构、训练模型所使用的虚拟机类型以及用于训练的类型加速器。然而,这需要更多的技术深度和努力来开发解决方案。
现在我们对图像和视频智能解决方案有了很好的了解,让我们来看看翻译 AI 解决方案,它也可以与各种图像和视频用例结合,以解决更复杂的企业问题。
Translation AI on Google Cloud
如其名所示,Google Cloud 上的翻译 AI 是一个可以用来创建具有多语言内容的应用程序的服务,它提供快速和动态的机器翻译。多语言内容可以帮助企业将产品推向全球市场并与全球受众互动。其实时翻译功能提供无缝体验。让我们来看看 Google Cloud 上的翻译相关服务。
Google Cloud 提供三种翻译产品:
-
Cloud Translation API
-
AutoML Translation
-
Translation Hub
让我们深入了解这些产品中的每一个。
Cloud Translation API
Google Research 在一段时间内开发了几个神经机器翻译(NMT)模型,并在有更好的训练数据或改进的技术时不断改进它们。Cloud Translation API 利用这些预训练模型或自定义机器学习模型将文本从各种源语言翻译成目标语言。使用 Cloud Translation API,我们可以通过仅使用 API 调用程序来动态地以编程方式翻译我们网站或应用程序的内容。默认情况下,这些预训练模型在训练过程中不使用任何客户数据。对于提供全球服务或产品的企业或公司来说,拥有语言翻译能力以更有效地理解和参与受众是非常重要的。作为一个产品,Cloud Translation API 通过 API 调用解决了识别源语言并将其翻译成所需目标语言的问题。它支持超过 100 种语言,但如果它仍然不能满足您的需求,如果您有训练数据,有方法来训练您的自定义模型。现在,让我们看看为自定义模型提供的 AutoML Translation 服务。
AutoML Translation
如前所述,Cloud Translation API 本身支持超过 100 种语言的翻译,但如果需要支持额外的语言,我们有灵活性来训练我们的自定义模型,前提是我们有足够的训练数据。当需要支持特定领域的翻译时,训练自定义模型也有帮助——例如,如果我们在一个金融领域工作,我们希望翻译解决方案提供更符合金融语言的特定结果。
AutoML Translation 本身训练最先进的机器学习模型架构,而无需我们投入精力开发我们的模型架构。我们只需要准备我们所需的输入-输出句子对,然后 AutoML 将自动找到最佳架构并为我们训练一个自定义翻译模型。
让我们检查它如何在 Cloud Console UI 中工作。如果我们从 Cloud Console 左侧的面板转到翻译标签,我们会找到一个创建数据集的标签,如图图 14.3 所示。在这里,我们需要为我们的数据集提供具有源语言和目标语言的唯一名称。一旦创建了数据集,如图图 14.3 所示,我们就可以开始向其中添加句子对:
图 14.3 – 创建翻译数据集
添加一些数据后,我们可以通过点击数据集来查看数据集的统计信息,如图图 14.4 所示。如图所示,我们有用于训练、验证和测试对的拆分。一旦 AutoML 模型被训练,我们可以在测试数据集上检查指标,以检查我们的自定义模型有多好:
图 14.4 – 审查语言翻译的数据集
可以通过点击开始训练按钮开始模型训练,如图 图 14.4 所示。一旦训练完成,我们可以在模型标签页中找到我们的训练模型,它显示了测试分区上的评估指标:
图 14.5 – 带评估指标的定制训练翻译模型
模型训练成功后,我们可以使用不同的方法获取翻译输出,例如通过 REST API 调用,或者通过使用不同的开发语言调用 API,包括 Python、Java、Go 等。
以下代码片段展示了使用 Python 语言对一个定制翻译模型进行的一次示例 API 调用。这个示例可以在 Google Translation AI 的官方文档页面上找到。
以下代码展示了如何设置翻译服务客户端和其他配置:
from google.cloud import translate
def translate_text_with_model(
text: str = "YOUR_TEXT_FOR_TRANSLATION",
project_id: str = "GCP_PROJECT_ID",
model_id: str = "CUSTOM_MODEL_ID",
) -> translate.TranslationServiceClient:
"""Translates a given text using custom model."""
client = translate.TranslationServiceClient()
location = "us-central1"
path = f"projects/{project_id}/locations/{location}"
model_path = f"{path}/models/{model_id}"
在这里,我们使用适当的语言代码调用 API:
# With supported language codes: https://cloud.google.com/translate/docs/languages
response = client.translate_text(
request={
"contents": [text],
"target_language_code": "ja",
"model": model_path,
"source_language_code": "en",
"parent": parent,
"mime_type": "text/plain", # mime types: text/plain, text/html
}
)
在这里,我们正在检查模型的响应:
# print the translation output for each input text
for translation in response.translations:
print(f"Translated text output: {translation.translated_text}")
return response
Cloud Translation API 本身或通过 AutoML 翻译增强以支持定制模型,更适合需要动态或近乎实时翻译的用例。现在,让我们了解 Translation Hub,它可能更适合大规模翻译需求。
Translation Hub
假设有一个组织需要快速将大量文档翻译成多种不同的语言。Translation Hub 对于此类用例更为合适,因为它是一个完全管理的解决方案,我们不需要为这项任务构建任何网络应用程序或设置基础设施。使用 Translation Hub 的另一个优点是,在将文档翻译成多种不同语言的同时,它保留了文档的基本结构和布局。设置起来相当简单,并且内置于 Cloud Translation API 和 AutoML 翻译解决方案中。
让我们讨论一下使用 Translation Hub 的好处。
自助翻译
在过去,翻译文档的唯一方式是手动操作,这相当慢,并且需要熟练的多语言专业人员。另一方面,Translation Hub 利用 AI 领域的进步,以超快的速度提供超过 100 种语言的翻译。我们还可以将人工审查作为后处理步骤,以改进来自 AI 模型的任何翻译。这样,Translation Hub 可以节省大量时间和成本。
文档翻译
假设我们拥有 PDF 或 DOCX 格式的文档 – 我们可以直接将它们传递给 Translation Hub,并且不需要事先从它们中提取文本。此外,Translation Hub 保留了文档的原始结构和格式(段落分隔、标题等),这非常有帮助。
简化管理
就像其他谷歌云产品一样,我们可以在云控制台 UI 中管理用户访问和门户访问。我们还可以轻松创建翻译资源,如术语表和翻译记忆。
持续改进
假设我们有在回路中的人类来后处理翻译;我们可以使用翻译记忆在翻译中心保留这些后编辑的翻译。这些翻译记忆可以以后再次使用。此外,我们可以将这些人工审查的翻译记忆导出为数据集,并训练一个更精确的定制翻译模型。
基于页面的定价
翻译中心定价非常直接,因为它根据从翻译 API 或基于 AutoML 的定制模型翻译的页面数量收费。部署和维护定制模型没有额外费用,但定制模型的训练是单独收费的。
有了这些,我们已经看到基于云的翻译对于处理大量文档并希望在其母语中触及全球受众的组织非常有用。接下来,让我们了解一下谷歌云上的自然语言 AI 产品。
谷歌云上的自然语言 AI
几乎每个组织都以文本文档、表格、合同、PDF、网页、用户评论等形式处理大量文本数据。谷歌云提供自然语言 AI,它利用机器学习模型从非结构化文本数据中提取洞察。自然语言 AI 是一个端到端产品,可以帮助在谷歌云上提取、分析和存储文本。
谷歌提供以下三种自然语言解决方案:
-
文本分析 AutoML
-
自然语言 API
-
医疗保健自然语言 API
让我们逐一深入了解这些解决方案。
文本分析 AutoML
想象一下,有一家电子商务公司收到与各种问题相关的客户查询,包括支付失败、送货地址更新、产品质量问题等。由于大多数这些查询都是客户在文本框中键入的,因此需要将这些查询分类到一组固定的类别中,以便将它们路由到正确的解决团队。当此类查询的数量很大时,手动对这些查询进行分类变得相当困难。这个过程可以通过训练一个能够自动将问题分类到适当类别的分类模型来使用机器学习进行自动化。
谷歌云上的 AutoML 支持训练机器学习模型来理解和分析文本数据。使用 AutoML 的主要优势是我们不需要编写任何复杂的模型架构、模型训练或评估代码。使用 AutoML,我们可以不编写任何代码就训练和评估机器学习模型。我们只需访问谷歌云控制台的 AutoML 页面,上传所需格式的数据集,然后开始训练机器学习模型。
AutoML 目前支持以下三类文本分析用例:
-
分类:文本分类是指训练接受文本句子或段落作为输入并将它们映射到固定类别集的输出作为输出的机器学习模型。Vertex AI 还支持多标签分类,这意味着单个输入句子也可以被分类到多个类别中。
-
实体提取:实体提取模型扫描文本输入以查找和标记预定义的实体。这些实体可能包括城市、国家、姓名、地址、疾病名称等。实体提取模型首先在固定的一组标记实体上训练,然后用于识别未见过的文本段落或句子中的实体。
-
情感分析:情感分析模型分析文本数据以识别其中的情感。它将文本输入分类为正、负、中性等类别。情感分析可以帮助识别来自反馈表客户的情感。
现在我们已经了解了 AutoML 如何帮助我们,让我们来讨论自然语言 API。
自然语言 API
Google Cloud 上的自然语言 API 为各种文本分析用例,如情感分析、实体提取、分类等,提供了预构建的业界领先解决方案。由于这些解决方案与 API 请求一起工作,因此它们可以快速轻松地集成到任何应用中。Google 提供了客户端库,以便开发者使用每种支持语言的风格和约定来使用自然语言 API 解决方案,从而为开发者提供更好的体验。官方文档页面上可以找到一个使用客户端库的快速示例(cloud.google.com/natural-language/docs/sentiment-analysis-client-libraries
)。
自然语言 API 目前提供以下功能以支持不同的文本分析用例:
-
情感分析
-
实体提取
-
实体情感分析
-
句法分析
-
内容分类
自然语言 API 是一个 REST API,因此支持 JSON 响应和请求格式。一个示例 JSON 请求可以写成如下:
{
"document":
{
"type":"PLAIN_TEXT",
"language_code": "EN",
"content": "This is a sample REST API request to the Natural Language API on Google Cloud."
},
"encodingType":"UTF8"
}
同样,一个情感分析查询的示例响应可能看起来非常类似于以下内容:
{
"documentSentiment": {
"score": 0.1,
"magnitude": 3.6
},
"language_code": "en",
"sentences": [
{
"text": {
"content": "This is a sample request text for the Natural Language API just to check how it works. In the JSON response you should see the output very close to the neutral sentiment."
"beginOffset": 0
},
"sentiment": {
"magnitude": 0.8,
"score": 0.1
}
},
...
}
在这里,情感分数从-1(负面)到+1(正面)不等,接近零的是中性。幅度显示了情感强度,它可以取从 0 到+inf 的任何值。
医疗自然语言 API
医疗自然语言 API 可以用来从非结构化医疗文本中提取实时洞察。存在于病历、出院总结和保险索赔文件中的非结构化医疗文本可以使用医疗自然语言 API 解析成医疗知识实体的结构化数据表示。一旦生成这种结构化输出,我们就可以将其传递给各种下游应用或创建自动化流程。
Healthcare Natural Language API 的关键特性如下:
-
您可以提取重要的医学概念,如药物、程序、疾病、医疗设备和如此等等
-
您可以从文本中提取医学见解,这些见解可以与 Google Cloud 上的分析产品集成
-
您可以将医学概念映射到标准约定,例如 RxNorm、ICD-10、MeSH 等
以下是从 Healthcare Natural Language API 获取的示例响应 JSON:
{
"entityMentions": [
{
"mentionId": "1",
"type": "PROBLEM",
"text": {
"content": "COPD",
"beginOffset": 38
},
"linkedEntities": [
{
"entityId": "UMLS/C0024223"
}
],
"temporalAssessment": {
"value": "CURRENT",
"confidence": 0.95
},
"certaintyAssessment": {
"value": "LIKELY",
"confidence": 0.99
},
"subject": {
"value": "PATIENT",
"confidence": 0.98
},
"confidence": 0.999
},
{
"mentionId": "2",
"type": "SEVERITY",
"text": {
这种实体提取和实体关系提取功能对于医疗保健公司非常有帮助。现在我们已经涵盖了与自然语言相关的产品服务,让我们接下来看看与语音相关的产品。
Google Cloud 上的语音 AI
另一种重要的捕捉和存储信息的形式是语音。Google 进行了数十年的研究,为许多语音和音频数据相关用例提供了最先进的解决方案。大量的关键信息以音频通话和录音消息的形式存在,因此转录和从中提取有用见解变得非常重要。此外,还有一些需要文本到语音功能功能的语音助手相关用例。Google Cloud 提供多种语音理解和转录解决方案。为了帮助组织应对这些用例,Google 创建了以下与语音数据相关的产品服务:
-
语音转文本
-
文本转语音
现在,让我们详细了解每个产品。
语音转文本
对于许多组织来说,大量有用的数据以非结构化形式存在,例如音频记录、客户语音通话、视频等。因此,分析这类数据以提取可操作的见解变得非常重要。要利用此类数据,必须有一种方法能够准确地将语音数据转录成文本格式。一旦我们的数据被转换为文本格式,我们就可以训练多个 NLP 模型,从中获取有用的业务见解。沿着类似的路线,Google 提供语音转文本作为产品服务,以解决准确将语音数据转换为文本的问题。它可以帮助组织从客户互动中获得更好的见解,并通过启用语音的力量提供更好的体验。
语音转文本的一些关键用例如下:
-
提升客户服务:语音转文本可以帮助组织通过在呼叫中心启用交互式语音响应(IVR)和代理对话来改善客户互动。他们还可以从对话数据中提取见解并执行分析。语音转文本提供了专门用于非常准确转录低质量电话的 ML 模型。
-
启用语音控制:当应用于物联网(IoT)设备时,语音控制可以显著提升用户体验。用户现在可以通过语音命令(如增加 音量)与设备互动。
-
多媒体内容:语音转文本允许音频和视频在近乎实时的基础上进行转录,这样我们就可以添加字幕以提高受众的覆盖范围和体验。视频转录还可以帮助我们为视频内容添加字幕或建立索引。这个功能已经被 YouTube 使用。
Google 语音转文本的一些关键功能,这些功能使得之前讨论的用例成为可能,如下所示:
-
语音自适应:语音识别模型可以通过提供一些提示来定制以识别罕见单词或短语。它还可以将口语数字转换为格式良好的地址。
-
流式语音识别:语音识别 API 支持实时转录,音频可能直接来自麦克风或预先录制的文件。
-
全局词汇:语音转文本支持超过 100 种语言,以支持全球用户基础。
-
多通道识别:视频会议的多通道录音也可以进行标注以保留顺序。
-
噪声鲁棒性:语音转文本可以处理嘈杂的录音并提供非常准确的转录。
-
领域自适应:语音转文本还提供了一些领域自适应模型。例如,电话录音通常是低质量的音频文件,谷歌有专门处理电话录音并提供非常准确转录的模型。
-
内容过滤:语音转文本具有检测和删除不适当单词的功能。
-
说话人分割:说话人分割是一个涉及识别多说话人对话中哪个说话人说了一句话的问题。谷歌提供了专门的说话人分割模型。
所有这些功能使语音转文本成为一个非常强大且通用的工具,可以轻松集成到任何商业用例中。由于这项服务有 API 支持,我们甚至不需要编写一行代码就可以开始使用这个解决方案。接下来,让我们了解另一个重要的语音相关解决方案:文本转语音。
文本转语音
如其名所示,文本转语音服务将文本转换为自然声音的语音。它可以帮助通过智能和逼真的响应来改善客户互动。我们可以通过根据客户的语言和声音偏好提供响应来个性化客户沟通。我们还可以通过物联网设备(例如,谷歌助手)进行语音交互来吸引用户。
Google 文本转语音的一些关键用例如下:
-
语音机器人:我们可以在我们的联系中心提供智能语音响应,而不是播放预先录制的音频,从而提供更好的客户体验。语音机器人可以为顾客提供更熟悉和个性化的感觉。
-
语音生成:我们可以使我们的物联网设备像人类一样说话,以实现更好的沟通。文本转语音可以与语音识别和自然语言解决方案结合,提供更好的端到端类似人类的对话体验。
-
电子节目指南(EPGs):文本转语音解决方案可以为电子节目指南提供动力,大声朗读文本以提供更好的用户体验。我们可以启用博客大声朗读新闻。
为了指导这些有趣的用例,Google 已经在其文本转语音产品中开发了以下关键功能:
-
语言和声音选择:文本转语音目前支持超过 200 种不同类型的语音,并支持 40 多种语言。
-
WaveNet 语音:Google Deepmind 的开创性研究使 WaveNet 能够生成 90 多种极其类似人类的语音,缩小了与人类表现的差距。
-
自定义语音:通过提供一些语音录音,我们可以在 Google 文本转语音模型中启用自己的声音。此功能目前处于测试阶段。
-
音调调整:我们可以调整所选声音的音调。
-
说话速度调整:我们获得了增加或减少说话速度的功能。
-
音频格式:文本转语音支持多种音频格式以提供输出。
-
音频配置文件:我们还可以优化播放音频的设备类型,例如电话线路、耳机等。
警告
自定义语音目前是 Vertex AI 中的一个私有功能,因此在我们联系销售团队成员之前,我们将无法实现自定义语音。cloud.google.com/contact
带有所有这些功能,Google 文本转语音可以轻松集成到可以发送 REST 或 gRPC 类请求的应用程序中。文本转语音 API 可以与许多不同类型的设备集成,包括手机、平板电脑、PC 和其他物联网设备。
摘要
并非所有重要数据都以结构化格式存在。大量重要信息以非结构化形式存在,如音频、视频、文档、录音等。机器学习取得的进展使我们能够大规模分析这些非结构化数据源,提取可操作的见解并指导关键业务决策。Google 对这个机器学习研究问题进行了广泛的研究,以提出语音、视觉、NLP、语音等领域的最先进解决方案。
在本章中,我们了解了谷歌为理解并从非结构化数据格式中提取信息提供的不同服务,包括音频、视频、图像、文档、电话录音等。阅读本章后,我们现在应该对这些服务有一个很好的理解,包括它们的关键特性和潜在的应用场景。在详细讨论之后,我们现在应该能够找到新的应用场景,将这些解决方案应用于自动化或增强组织内的各种业务流程。在接下来的几章中,我们将学习如何在谷歌云上构建现实世界的机器学习解决方案,例如推荐系统、视觉和 NLP 解决方案。
第四部分:使用谷歌云构建现实世界的机器学习解决方案
在本部分,你将探索使用谷歌云中 Vertex AI 提供的工具开发现实世界机器学习解决方案的示例。这些示例将向你展示如何使用谷歌云中的机器学习工具构建推荐系统、基于视觉的定制应用和基于 NLP 的定制解决方案。
本部分包含以下章节:
-
第十五章, 推荐系统 – 预测用户想看哪些电影
-
第十六章, 基于视觉的缺陷检测系统 – 机器现在能看见
-
第十七章, 自然语言模型 – 检测虚假新闻文章
第十五章:推荐系统 – 预测用户想看哪些电影
如其名所示,推荐系统是针对基于各种参数(如过去的行为、项目相似性,甚至用户人口统计信息)向用户提供推荐的设计解决方案。这些系统被广泛应用于各种应用中,例如在 YouTube 上推荐视频、Netflix 上的电影或 Amazon 上的产品。
推荐系统的主要目标是使在线用户体验个性化,以推动业务成果,如提高用户参与度和增加收入。随着可用内容和选择的增加,个性化推荐对于提升用户体验和确保客户不会被可用的选项所淹没变得至关重要。
在本章中,我们将涵盖以下主题:
-
不同类型推荐系统的概述
-
在 Vertex AI 上部署电影推荐系统
首先,我们将探讨在野外通常可以找到的不同类型的推荐系统。
不同类型的推荐系统
在本节中,我们将深入探讨各种类型的推荐引擎,揭示它们的方法论以及每种推荐引擎带来的独特优势:
-
协同过滤:
这种方法基于这样一个理念:过去同意过某些物品偏好的用户在未来也可能会同意。如图所示,该模型通过观察用户的观看/阅读行为来尝试找到相似用户,并将一个用户的观看内容推荐给其他相似用户:
图 15.1 – 协同过滤
-
基于内容的过滤:
此方法使用项目属性,根据用户的先前行为或明确反馈推荐与用户喜欢的类似的其他项目。
例如,如果一个用户表现出对克里斯托弗·诺兰执导的电影的偏好,那么在推荐时,系统会优先推荐他执导的电影。在这里,电影的(导演、类型、演员等)内容被考虑在内。
优势:可以处理新项目,因此不需要其他用户的数据。
挑战:过度专业化(可能只显示非常相似的项目)且需要高质量的元数据。
如下图所示,在基于内容的过滤中,模型试图找到与用户过去观看的内容相似的内容,并在未来向用户推荐相似内容:
图 15.2 – 基于内容的过滤
-
人口统计过滤:
人口统计推荐器通过根据个人属性对用户进行分类,然后根据人口统计类别提供个性化推荐。
例如,如果数据显示某个特定地区的 18-24 岁男性对动作电影如《速度与激情》有很高的亲和力,那么来自该地区该年龄段的男性更有可能收到对该电影或类似动作电影的推荐。
优点:简单直接,不需要过去的用户-项目交互。
挑战:个性化程度较低,基于刻板印象,且需要用户人口统计数据。
在实践中,许多最先进的系统使用混合方法,结合多种推荐技术元素,以克服任何单一方法的局限性。Netflix 的推荐引擎就是一个例子,它结合了协同过滤、基于内容的和其他技术,为用户提供电影和电视剧推荐。
接下来,我们将探讨如何通过用户行为和反馈评估内容推荐系统在现实世界中的应用。
推荐系统在现实世界中的评估
在现实世界中,推荐系统的评估不仅超越了传统的机器学习指标,还涵盖了更广泛的关键绩效指标(KPIs),这些指标与商业目标和用户体验更加紧密地一致。与典型的“实验室”环境不同,在“实验室”环境中,如精确度、召回率或 RMSE 等准确性指标被强调,现实世界的评估更优先考虑 KPIs,如点击率(CTR)、转化率和用户参与度。这些 KPIs 直接反映了用户在真实环境中如何与推荐内容互动。
例如,高 CTR 表明用户认为推荐内容足够相关,值得进一步探索,而强的转化率表明推荐内容在驱动期望的用户行为方面是有效的,例如购买或内容消费。
此外,如客户终身价值(CLV)和净推荐值(NPS)等指标提供了关于推荐系统对商业收入和用户忠诚度长期影响的见解。通过关注这些 KPIs,组织可以评估其推荐系统在现实世界中的实际效果,确保它们不仅在机器学习指标上表现良好,而且对用户满意度和商业目标有积极贡献。这种方法认识到推荐系统最终的成功在于它们增强用户体验和推动业务成果的能力,而不仅仅是实现传统评估指标上的高分。让我们更深入地了解不同类型的指标:
-
参与度指标:
参与度指标评估用户如何与推荐内容互动,从而提供关于系统捕捉和保持用户兴趣能力的见解。
让我们来看看一些不同的参与度指标:
-
CTR:点击次数与显示推荐次数的比率,表明推荐内容的吸引力
-
转化率:导致期望行动(如购买或订阅)的推荐所占的百分比
-
平均花费时间:用户与推荐内容互动的时间量,反映了用户参与度和内容相关性
-
-
用户满意度:
用户满意度指标评估用户对推荐的满意程度,作为系统成功直接指标的用户视角。
以下是一些用户满意度指标:
-
用户反馈和评分:对推荐项目的直接用户反馈,提供对用户满意度的见解
-
NPS(净推荐值):通过询问用户他们向他人推荐系统的可能性来衡量用户满意度和忠诚度的指标
-
-
业务影响指标:
业务影响指标量化了推荐系统对组织财务目标的贡献的经济价值和有效性。
以下是一些关键的业务影响指标:
-
每用户收入(RPU):每个用户产生的平均收入,表明推荐的经济价值
-
CLV(客户终身价值):用户在其整个生命周期内预期的总收入,受推荐效果的影响
-
-
覆盖度指标:
覆盖度指标决定了推荐系统有效利用可用内容并触及广泛用户群体的程度。
以下是一些不同的覆盖度指标:
-
目录覆盖度:推荐给用户的目录中项目的比例,反映了系统利用整个库存的能力
-
用户覆盖度:收到相关推荐的用户的百分比。这对于用户包容性和参与度至关重要
-
在推荐系统中,KPI(关键绩效指标)对于监控性能、理解用户偏好以及将推荐与业务目标对齐至关重要。在准确性、用户参与度、满意度和业务影响之间保持平衡的关注,确保开发出一个有效且以用户为中心的推荐系统。持续监控和优化这些 KPI 对于在动态用户环境中保持相关性和有效性至关重要。
现在,让我们看看如何在 Vertex AI 上构建和部署推荐系统。
在 Vertex AI 上部署电影推荐系统
现在,让我们通过一个基于协同过滤类型模型的电影推荐系统创建示例,将其部署在 Vertex AI 上,然后查询它以获取特定用户和电影类型推荐的电影。关键步骤如下:
-
数据准备
-
模型设计和训练
-
本地模型测试
-
在 Vertex AI 上注册模型
-
模型部署
-
获取预测
注意
本练习的笔记本可以在 github.com/PacktPublishing/The-Definitive-Guide-to-Google-Vertex-AI/blob/main/Chapter15/Chp-15_Movie_Recommender.ipynb
找到。
数据集:为了训练模型,我们将使用 MovieLens 数据集 (F. Maxwell Harper 和 Joseph A. Konstan. 2015. The MovieLens Datasets: History and Context. ACM Transactions on Interactive Intelligent Systems (TiiS) 5, 4: 19:1–19:19. doi.org/10.1145/2827872
)。
MovieLens 数据集是推荐系统领域中使用的最受欢迎的数据集之一。它是一组电影评分,由明尼苏达大学的 GroupLens 研究项目 制作。
关于此数据集的更多详细信息:
数据:该数据集包含多个版本,大小不同(从 100k 评分到 25M 评分不等)。它包括电影评分、电影元数据(类型和发行年份)以及用户的统计数据。
数据字段:
-
用户数据:用户 ID、年龄、性别、职业和邮政编码
-
电影数据:电影 ID、标题、上映日期和相关的类型(如动作、冒险、喜剧等)
-
评分:用户 ID、电影 ID、评分(通常在 1 到 5 的范围内)和时间戳
用例:主要用于实验协作过滤、基于内容的过滤和混合推荐算法。
该数据集有助于理解用户在电影评分中的行为和模式。
MovieLens 数据集的流行源于其相对干净的数据,其中缺乏在更大、更真实世界数据集中发现的许多噪声和不一致性。这使得它非常适合原型设计、学习和推荐系统领域的初步实验。
现在,让我们使用这个数据集来创建一个简单的基于协作过滤的电影推荐解决方案。
数据准备
在本节中,我们将下载并预处理 MovieLens 数据集,以便为推荐模型准备模型训练数据。请按照以下步骤操作:
-
包含 MovieLens 数据集的
ml-latest-small.zip
文件:# Download the actual data from http://files.grouplens.org/datasets/movielens/ml-latest-small.zip" movielens_data_url = ( "http://files.grouplens.org/datasets/movielens/ml-latest-small.zip") movielens_zip_file = keras.utils.get_file( "ml-latest-small.zip", movielens_data_url, extract=False) movie_datasets_path = Path(movielens_zip_file).parents[0] movielens_dir = movie_datasets_path / "ml-latest-small" with ZipFile(movielens_zip_file, "r") as zip: zip.extractall(path=movie_datasets_path)
-
将
ratings.csv
文件转换为 DataFrame 以进行处理:# Load the Movie Ratings file ratings_file = movielens_dir / "ratings.csv" df = pd.read_csv(ratings_file)
-
编码数据:将用户和电影 ID 编码为整数索引以进行模型训练:
# Extract the unique user IDs from the 'userId' column and convert them to a list user_ids = df["userId"].unique().tolist() # Create a dictionary that maps each user ID to a unique integer (encoded form) user2user_encoded = {x: i for i, x in enumerate(user_ids)} # Create a dictionary that maps each unique integer back to its original user ID userencoded2user = {i: x for i, x in enumerate(user_ids)} # Extract the unique movie IDs from the 'movieId' column and convert them to a list movie_ids = df["movieId"].unique().tolist() # Create a dictionary that maps each movie ID to a unique integer (encoded form) movie2movie_encoded = {x: i for i, x in enumerate(movie_ids)} # Create a dictionary that maps each unique integer back to its original movie ID movie_encoded2movie = {i: x for i, x in enumerate(movie_ids)} # Map the original user IDs in the 'userId' column to their encoded forms and store in a new column 'user' df["user"] = df["userId"].map(user2user_encoded) # Map the original movie IDs in the 'movieId' column to their encoded forms and store in a new column 'movie' df["movie"] = df["movieId"].map(movie2movie_encoded)
由于我们的训练数据现在已准备好,以 users
和 movies
DataFrame 的形式,让我们构建推荐模型。
模型构建
在本节中,我们将使用 Keras 构建我们的深度学习推荐模型结构,并在上一节中创建的数据集上对其进行训练:
RecommendationModel
模型类,它使用用户和电影的嵌入:
class RecommendationModel(keras.Model):
def __init__(self, num_users, num_movies, embedding_size, **kwargs):
super().__init__(**kwargs)
self.num_users = num_users
self.num_movies = num_movies
self.embedding_size = embedding_size
# User embeddings layer: Represents each user as a vector in the embedding space
self.user_embedding = layers.Embedding(
num_users, embedding_size,
embeddings_initializer="he_normal",
embeddings_regularizer=keras.regularizers.l2(1e-6),)
self.user_bias = layers.Embedding(num_users, 1)
# Movie embeddings layer: Represents each movie as a vector in the embedding space
self.movie_embedding = layers.Embedding(
num_movies, embedding_size,
embeddings_initializer="he_normal",
embeddings_regularizer=keras.regularizers.l2(1e-6),)
self.movie_bias = layers.Embedding(num_movies, 1)
模型通过用户和电影嵌入的点积来计算匹配分数。
# Forward pass: Given user and movie IDs, predict the rating
def call(self, inputs):
user_vector = self.user_embedding(inputs[:, 0])
user_bias = self.user_bias(inputs[:, 0])
movie_vector = self.movie_embedding(inputs[:, 1])
movie_bias = self.movie_bias(inputs[:, 1])
dot_user_movie = tf.tensordot(user_vector, movie_vector, 2)
x = dot_user_movie + user_bias + movie_bias
# The sigmoid activation forces the rating to between 0 and 1
return tf.nn.sigmoid(x))
模型编译:使用二元交叉熵作为损失函数和 Adam 作为优化器来编译模型:
# # Instantiate the Recommender model with the defined number of users, movies, and embedding size
model = RecommendationModel(num_users, num_movies, EMBEDDING_SIZE)
# Compile the Recommender model
model.compile(
#Define loss function
loss=tf.keras.losses.BinaryCrossentropy(),
#Define Optimizer function
optimizer=keras.optimizers.Adam(learning_rate=0.001))
模型训练:使用训练数据训练模型,并使用验证数据验证模型:
# Train the model
history = model.fit(
x=x_train,y=y_train,batch_size=64,
epochs=5,verbose=1,validation_data=(x_val, y_val),)
本地模型测试
在部署模型之前,让我们在本地测试其预测以确保其按预期工作:
-
准备测试数据:对于随机用户,创建一个他们尚未观看的电影数组:
#Load the metadata for the movies movie_df = pd.read_csv(movielens_dir / "movies.csv") # Pick a user and select their top recommendations. user_id = df.userId.sample(1).iloc[0] movies_watched_by_user = df[df.userId == user_id] movies_not_watched = movie_df[~movie_df["movieId"] .isin( movies_watched_by_user.movieId.values)]["movieId"] movies_not_watched = list(set(movies_not_watched).intersection( set(movie2movie_encoded.keys()))) movies_not_watched = [[movie2movie_encoded.get(x)] for x in movies_not_watched] user_encoder = user2user_encoded.get(user_id) #Create a array of data instances to be sent for predictions user_prediction_array = np.hstack(([[user_encoder]] * len(movies_not_watched), movies_not_watched))
-
预测评分:使用模型预测用户之前未评分的电影的评分:
#Get predicted ratings for the unwatched movies and the selected user ratings = model.predict(user_movie_array).flatten()
-
推荐电影:现在,根据预测的评分,让我们识别并显示用户的顶级 10 部电影推荐:
# Sort and pick top 10 ratings movie_indices_top10 = ratings.argsort()[-10:][::-1] movie_recommendations_ids = [ movie_encoded2movie.get(movies_not_watched[x][0]) for x in movie_indices_top10 ] print("----" * 10) print("Top movies recommendations for user id: {}".format(user_id)) print("----" * 10) recommended_movies = movie_df[movie_df["movieId"].isin( movie_recommendations_ids)] for row in recommended_movies.itertuples(): print(row.title, ":", row.genres)
模型的最终预测结果如下。您的电影列表将根据用户从数据集中选择的用户而变化:
-------------------------------- Top 10 movie recommendations -------------------------------- Volunteers (1985) : Comedy Emperor's New Clothes, The (2001) : Comedy Caveman (1981) : Comedy Juwanna Mann (2002) : Comedy Top Secret! (1984) : Comedy Unfaithfully Yours (1948) : Comedy Oh, God! You Devil (1984) : Comedy Fish Story (Fisshu sutôrî) (2009) : Comedy Kevin Smith: Too Fat For 40 (2010) : Comedy War Dogs (2016) : Comedy
因此,看起来模型在本地环境中运行良好,可以生成电影推荐。现在,让我们将模型部署到云端。
在 Google Cloud 上部署模型
第一步是在 GCP 上部署模型,这样我们就可以在 Vertex AI 上上传和注册我们的本地模型。请按照以下步骤操作:
-
在 Vertex AI 上注册模型:要在 Vertex AI 上注册/上传模型,我们需要将核心机器学习模型工件保存到Google Cloud Storage(GCS)桶中:
# Save the model in GCS bucket so that we can import it into Vertex AI Model Registry MODEL_DIR = BUCKET_URI + "/model/" model.save(MODEL_DIR)
现在,我们必须将保存的模型上传到 Vertex AI 模型注册表。为此,我们需要传递以下参数:
-
display_name
:将在 Vertex AI 模型注册表中显示的模型的显示名称。 -
artifact_uri
:保存模型在 GCS 中的位置。 -
serving_container_image_uri
:用作服务容器的 Docker 镜像。您可以使用 Vertex AI 提供的镜像之一,或者将自定义容器镜像上传到 GCP 工件注册表。本章的 Jupyter Notebook 提供了更多详细信息。 -
is_default_version
:这指定了这将是否是模型资源的默认版本。 -
version_ailiases
:模型版本的替代别名。 -
version_description
:用户对模型版本的描述。
#Define service container configuration DEPLOY_GPU, DEPLOY_NGPU = (None, None) TF = "2.12".replace(".", "-") if DEPLOY_GPU: DEPLOY_VERSION = "tf2-gpu.{}".format(TF) else: DEPLOY_VERSION = "tf2-cpu.{}".format(TF) DEPLOY_IMAGE = "{}-docker.pkg.dev/vertex-ai/prediction/{}:latest".format( REGION.split("-")[0], DEPLOY_VERSION) #Upload the Model to Vertex AI Model Registry model = aip.Model.upload( display_name="recommender_model_chp15", artifact_uri=MODEL_DIR, serving_container_image_uri=DEPLOY_IMAGE, is_default_version=True, version_aliases=["v1"], version_description="This is the first version of the model",)
-
-
将模型部署为 Vertex AI 端点:
在 Vertex AI 上创建端点并部署模型以进行实时推理。请确保您提供显示名称:
endpoint = aip.Endpoint.create( display_name="recommender_model_chp15", project=PROJECT_ID, location=REGION,) print(endpoint)
现在,在指定机器类型和其他配置设置的同时,将模型部署到新创建的端点:
#Deploy the model to the Vertex AI endpoint DEPLOY_COMPUTE = "n1-standard-4" #Virtual Machine type response = endpoint.deploy( model=model, deployed_model_display_name="example_", machine_type=DEPLOY_COMPUTE,) print(endpoint)
使用模型进行推理
这是最有趣的部分!我们将使用部署在 Google Cloud Vertex AI 上的机器学习模型,通过 API 调用进行预测。首先,我们将创建一个 Python 函数来发送预测请求,然后创建一个测试/推理数据集,我们可以将其作为请求的一部分发送给模型。最后,我们将解析从模型收到的预测响应。让我们开始吧:
-
predict_custom_trained_model_sample
,这样您就可以使用部署在 Vertex AI 上的模型进行预测:def predict_custom_trained_model_sample( project: str, endpoint_id: str, instances: Union[Dict, List[Dict]], location: str = "us-central1", api_endpoint: str = "us-central1-aiplatform.googleapis.com",): # Initialize client that will be used to create and send requests. client_options = {"api_endpoint": api_endpoint} client = aiplatform.gapic.PredictionServiceClient( client_options=client_options) # The format of each instance should conform to the deployed model's prediction instances = [ json_format.ParseDict(instance_dict, Value()) for instance_dict in instances] parameters_dict = {} parameters = json_format.ParseDict(parameters_dict, Value()) endpoint = client.endpoint_path( project=project, location=location, endpoint=endpoint_id) response = client.predict( endpoint=endpoint, instances=instances, parameters=parameters) print(" deployed_model_id:", response.deployed_model_id) # The predictions are a google.protobuf.Value representation of the model's predictions. predictions = response.predictions return(predictions)
-
创建推理数据集:为用户和流派创建一个样本推理数据集:
# Pick a random user for whom we can try to predict movie predictions user_id = df.userId.sample(1).iloc[0] #Add filter for the category for which you need recommendations genre_filter = "Drama"
-
创建一个预测输入数据集,包含用户未观看(未评分)的所选流派中的所有电影:
# Create Test Dataset for a User and the selected Genre movie_df = pd.read_csv(movielens_dir / "movies.csv") movies_watched_by_user = df[df.userId == user_id] #Create Dataframe with Movies not watched by the User movies_not_watched_df = movie_df[ (~movie_df["movieId"].isin(movies_watched_by_user.movieId.values)) & (movie_df["genres"].str.contains(genre_filter)) ][["movieId","title","genres"]] #Get the list of Movie Ids which can the be encoded using the movie id encoder we had built earlier movies_not_watched = movies_not_watched_df["movieId"] movies_not_watched = list( set(movies_not_watched).intersection(set(movie2movie_encoded.keys()))) movies_not_watched = [[movie2movie_encoded.get(x)] for x in movies_not_watched] #Get the encoded value of the user id based on the encoder built earlier user_encoder = user2user_encoded.get(user_id) user_movie_array = np.hstack(([[user_encoder]] * len(movies_not_watched), movies_not_watched)) #Create data instances that would be sent to the API for inference instances = user_movie_array.tolist()
-
-
发送预测请求:将推理数据集提交到 Vertex AI 预测 API 端点:
# Get predicted ratings for the unwatched movies and the selected user predictions = predict_custom_trained_model_sample( project=endpoint.project, endpoint_id=endpoint.name, location=endpoint.location, instances = instances)
-
解析结果:解析从 API 端点收到的预测并将它们组合:
# Create a DataFrame from the predictions list/array predictions_df = pd.DataFrame(predictions) # Rename the column in the predictions DataFrame to 'rating' predictions_df.columns = ['rating']
-
创建 DataFrame:从实例列表/数组创建 DataFrame:
instances_df = pd.DataFrame(instances) # Rename the columns in the instances DataFrame to 'userId' and 'movieId' respectively instances_df.columns = ['userId','movieId'] # Merge the instances and predictions DataFrames combined_results = instances_df.join(predictions_df) # Sort the results by the rating column in descending order combined_results_sorted = combined_results.sort_values('rating',ascending=False) # Filter the results to show only the top 15 results combined_results_sorted_top = combined_results_sorted.head(15)["movieId"].values # Map the encoded Movie IDs to the actual Movie IDs recommended_movie_ids = [ movie_encoded2movie.get(x) for x in combined_results_sorted_top]
-
打印:打印最终推荐的影片列表:
print("----" * 10) print("Top 15 recommended movies recommendations for User:",user_id," and Genre",genre_filter) print("Genre:",genre_filter) print("----" * 10) recommended_movies = movie_df[movie_df["movieId"].isin(recommended_movie_ids)] for row in recommended_movies.itertuples(): print(row.title, ":", row.genres)
-
输出将类似于以下内容:
---------------------------------------- Top 15 recommended movies recommendations for User: 551 Genre: Drama -------------------------------- Stunt Man, The (1980) : Action|Adventure|Comedy|Drama|Romance|Thriller Affair of the Necklace, The (2001) : Drama Baran (2001) : Adventure|Drama|Romance Business of Strangers, The (2001) : Action|Drama|Thriller No Man's Land (2001) : Drama|War Blue Angel, The (Blaue Engel, Der) (1930) : Drama Moscow on the Hudson (1984) : Comedy|Drama Iris (2001) : Drama Kandahar (Safar e Ghandehar) (2001) : Drama Lantana (2001) : Drama|Mystery|Thriller Brothers (Brødre) (2004) : Drama Flightplan (2005) : Action|Drama|Thriller Green Street Hooligans (a.k.a. Hooligans) (2005) : Crime|Drama History of Violence, A (2005) : Action|Crime|Drama|Thriller Oliver Twist (2005) : Drama
从一个用户评分的电影数据集开始,我们能够训练一个模型,现在可以为组内的用户提供电影推荐。
摘要
在本章中,我们简要概述了推荐系统、构建它们所使用的不同技术,以及如何在 Google Cloud 的 Vertex AI 上训练、部署和查询电影推荐模型的详细步骤。由于关键目标是展示如何使用 GCP Vertex AI 解决真实世界的用例,我们保持了核心模型相对简单。但如果你对深入了解推荐解决方案感兴趣,可以查看 Coursera 上的推荐系统专项课程。
在下一章中,我们将探讨另一个真实世界的用例,即构建基于视觉的机器学习解决方案,以在制造过程中检测缺陷。
参考文献
要了解更多关于本章所涉及主题的信息,请查看以下资源:
电影推荐中的协同过滤:keras.io/examples/structured_data/collaborative_filtering_movielens/
开始使用 Vertex AI 模型注册表:github.com/GoogleCloudPlatform/vertex-ai-samples/blob/main/notebooks/official/model_registry/get_started_with_model_registry.ipynb
第十六章:基于视觉的缺陷检测系统 – 机器现在也能“看”了!
计算机视觉(CV)是人工智能的一个领域,它关注于赋予机器分析并从数字图像、视频和其他视觉输入中提取有意义信息的能力,以及根据提取的信息采取行动或做出推荐。在计算机视觉领域数十年的研究导致了基于机器学习(ML)的强大视觉算法的发展,这些算法能够将图像分类到一些预定义的类别中,从图像中检测对象,从数字图像中理解书面内容,以及检测视频中正在执行的动作。这样的视觉算法赋予了企业和组织分析大量数字内容(图像和视频)的能力,并自动化流程以做出即时决策。
基于计算机视觉(CV)的算法已经改变了我们日常与智能设备互动的方式 – 例如,我们现在只需展示我们的面部就可以解锁智能手机,而现在的照片编辑应用可以使我们看起来更年轻或更老。应用基于 CV 的机器学习(ML)算法的另一个重要用例是缺陷检测。机器学习算法可以用来分析视觉输入并在产品图像中检测缺陷,这对制造业来说非常有用。
在本章中,我们将使用 Google Cloud 上的深度学习开发一个实际的缺陷检测解决方案。我们还将了解如何部署我们的基于视觉的缺陷检测模型作为 Vertex AI 端点,以便它可以用于在线预测。
本章涵盖了以下主要内容:
-
基于视觉的缺陷检测
-
将视觉模型部署到 Vertex AI 端点
-
从视觉模型获取在线预测
技术要求
本章中使用的代码示例可以在以下 GitHub 地址找到:github.com/PacktPublishing/The-Definitive-Guide-to-Google-Vertex-AI/tree/main/Chapter16
.
基于视觉的缺陷检测
现在的计算机视觉(CV)能够通过分析物体的数字照片或视频来检测物体表面的视觉缺陷或设计上的不一致性(例如汽车车身上的凹痕或划痕)。制造业可以利用计算机视觉算法自动检测并移除低质量或存在缺陷的产品,防止其被包装并送达客户。使用基于 CV 的算法在数字内容中检测缺陷有许多可能的方法。一个简单的想法是将缺陷检测视为一个分类问题,其中可以训练一个视觉模型来分类图像,如“良好”或“缺陷”。一个更复杂的缺陷检测系统还将定位图像中存在缺陷的确切区域。可以使用目标检测算法来解决识别和定位视觉缺陷的问题。
在本节中,我们将逐步构建和训练一个简单的缺陷检测系统。在这个例子中,我们将使用机器学习分类作为检测视觉缺陷产品的机制。让我们探索这个例子。
数据集
对于这个实验,我们从 Kaggle 下载了一个开源数据集。该数据集包含超过一千张彩色玻璃手镯的图像。这些图像包含不同大小和颜色的手镯,可以根据其制造质量和损坏情况分为三大类——好的、有缺陷的和破损的。有缺陷的手镯可能存在制造缺陷,如恒定的宽度或不当的圆形形状,而破损的手镯则可能缺少圆形的一部分。在这个实验中,我们将利用这些图像中的某些图像来训练一个机器学习分类模型,并在一些未见过的样本上进行测试。图像已经按照上述类别分开,因此不需要手动数据标注。本实验中使用的数据集可以从与该实验对应的 Jupyter Notebook 中提供的 Kaggle 链接下载。代码样本的 GitHub 位置在本章的 技术要求 部分开头给出。
我们已经将数据集下载并解压到了与我们的 Jupyter Notebook 相同的目录中。现在,我们可以开始查看一些图像样本了。现在让我们进入编码部分。
导入有用的库
第一步是导入实验中需要的有用 Python 包。在这里,cv2
指的是 OpenCV 库,它为处理图像和其他 CV 任务提供了许多预构建的功能:
import numpy as np
import glob
import matplotlib.pyplot as plt
import cv2
from tqdm import tqdm_notebook
import tensorflow
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix
%matplotlib inline
接下来,让我们查看数据集。
加载数据并进行验证
现在,让我们将所有图像文件路径加载到三个单独的列表中,每个类别一个列表——好的、有缺陷的和破损的。保留三个单独的列表将使跟踪图像标签更容易。我们还将打印出每个类别中图像的确切数量:
good_bangle_paths = glob.glob("dataset/good/*.jpg")
defected_bangle_paths = glob.glob("dataset/defect/*.jpg")
broken_bangle_paths = glob.glob("dataset/broken/*.jpg")
print(len(good_bangle_paths), len(defected_bangle_paths), \
len(broken_bangle_paths))
下面是输出结果:
520 244 316
我们总共有 520 张高质量图像、244 张有缺陷的图像和 316 张破损的手镯图像。接下来,让我们通过使用 matplotlib
绘制来验证每个类别的一些样本:
检查一些样本
在这一步,我们将从之前讨论的每个列表中随机选择一些图像路径,并使用它们的类别名称作为标题进行绘制。
让我们绘制一些好的手镯图像:
plt.figure(figsize=(10, 10))
for ix, img_path in enumerate( \
np.random.choice(good_bangle_paths, size=5)
):
img = cv2.imread(img_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.subplot(550 + 1 + ix)
plt.imshow(img)
plt.axis('off')
plt.title('Good Bangle!')
plt.show()
print("-"*101)
同样,我们将绘制一些随机的有缺陷的手镯碎片:
plt.figure(figsize=(10, 10))
for ix, img_path in enumerate( \
np.random.choice(defected_bangle_paths, size=5)
):
img = cv2.imread(img_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.subplot(550 + 1 + ix)
plt.imshow(img)
plt.axis('off')
plt.title('Defected Bangle!')
plt.show()
print("-"*101)
最后,我们还将以类似的方式绘制一些破损的手镯图像,这样我们就可以直观地看到所有三个类别,并更多地了解数据:
plt.figure(figsize=(10, 10))
for ix, img_path in enumerate( \
np.random.choice(broken_bangle_paths, size=5)
):
img = cv2.imread(img_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.subplot(550 + 1 + ix)
plt.imshow(img)
plt.axis('off')
plt.title('Broken Bangle!')
plt.show()
前述脚本的输出显示在 图 16.1 中。其中每一行代表上述每个类别的一些随机样本。类别名称出现在图像的标题中。
图 16.1 – 每个类别的手镯图像样本 – 好的、有缺陷的和破损的
如前图所示,好的手镯看起来像是一个完美的圆形,宽度均匀,有缺陷的手镯可能有一些不均匀的宽度或表面,而破损的手镯很容易辨认,因为它们缺少圆形的一部分。因此,区分好的手镯和有缺陷的手镯可能有点挑战性,但算法区分这两种类别与破损的手镯应该更容易。让我们看看在接下来的几节中情况会如何。
数据准备
在这一步,我们将为基于TensorFlow(TF)的深度学习模型准备数据。基于 TF 的模型要求所有输入具有相同的形状,因此第一步将是使所有输入图像具有相同的形状。我们还将稍微降低图像的质量,以便在读取它们和在训练期间对它们进行计算时更加内存高效。我们必须记住一件事 – 我们不能显著降低数据质量,以至于模型难以找到任何视觉线索来检测有缺陷的表面。对于这个实验,我们将每个图像调整到 200x200 的分辨率。其次,因为我们只关心寻找缺陷,所以图像的颜色对我们来说并不重要。因此,我们将所有彩色图像转换为灰度图像,因为这样可以减少图像的通道从 3 到 1;因此,图像大小变为原始大小的三分之一。最后,我们将它们转换为 NumPy 数组,因为 TF 模型要求输入张量是 NumPy 数组。
以下是我们将为数据集中的每一张图片执行的预处理步骤:
-
使用 OpenCV 库读取彩色图像
-
将图像调整到固定大小(200 x 200)
-
将图像转换为灰度(黑白)
-
将图像列表转换为 NumPy 数组
-
添加一个通道维度,这是卷积层所要求的
让我们先按照以下步骤处理好的手镯图像:
good_bangles = []
defected_bangles = []
broken_bangles = []
for img_path in tqdm_notebook(good_bangle_paths):
img = cv2.imread(img_path)
img = cv2.resize(img, (200, 200))
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
good_bangles.append(img)
good_bangles = np.array(good_bangles)
good_bangles = np.expand_dims(good_bangles, axis=-1)
同样,我们将预处理有缺陷的手镯图像:
for img_path in tqdm_notebook(defected_bangle_paths):
img = cv2.imread(img_path)
img = cv2.resize(img, (200, 200))
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
defected_bangles.append(img)
defected_bangles = np.array(defected_bangles)
defected_bangles = np.expand_dims(defected_bangles, axis=-1)
最后,我们将遵循相同的预处理步骤来处理破损的手镯图像。我们还将打印每个图像类别的最终 NumPy 数组形状:
for img_path in tqdm_notebook(broken_bangle_paths):
img = cv2.imread(img_path)
img = cv2.resize(img, (200, 200))
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
broken_bangles.append(img)
broken_bangles = np.array(broken_bangles)
broken_bangles = np.expand_dims(broken_bangles, axis=-1)
print(good_bangles.shape, defected_bangles.shape, \
broken_bangles.shape)
每个图像数组现在将具有 200x200x1 的形状,第一个维度将代表图像的总数。以下是前一个脚本的输出:
(520, 200, 200, 1) (244, 200, 200, 1) (316, 200, 200, 1)
现在,让我们将数据分成训练和测试分区。
将数据分割为训练和测试
由于我们的数据现在已准备好且与 TF 模型格式兼容,我们只需执行最后一步重要步骤,即将数据分成两个分区——训练和测试。训练分区将在模型训练期间用于学习目的,而测试分区将保持分开,不会对模型参数的更新做出贡献。一旦模型训练完成,我们将检查它在未见过的测试数据分区上的表现如何。
由于我们的测试数据也应该包含每个类别的样本,我们将每个图像类别分成训练和测试分区,最后将所有训练和测试分区合并在一起。我们将利用每个类别数组中的前 75%的图像用于训练,其余的 25%图像用于测试,如下面的代码片段所示:
good_bangles_train = good_bangles[:int( \
len(good_bangles)*0.75),]
good_bangles_test = good_bangles[int( \
len(good_bangles)*0.75):,]
defected_bangles_train = defected_bangles[:int( \
len(defected_bangles)*0.75),]
defected_bangles_test = defected_bangles[int( \
len(defected_bangles)*0.75):,]
broken_bangles_train = broken_bangles[:int( \
len(broken_bangles)*0.75),]
broken_bangles_test = broken_bangles[int( \
len(broken_bangles)*0.75):,]
print(good_bangles_train.shape, good_bangles_test.shape)
之前定义的代码还打印出训练和测试分区的形状,仅用于数据验证目的。以下为输出:
(390, 200, 200, 1) (130, 200, 200, 1)
我们的训练和测试数据现在几乎准备好了;我们只需要为模型训练创建相应的标签。在下一步中,我们将为两个分区创建标签数组。
训练和测试数据的最终准备
现在我们已经有了三对训练和测试分区(每个类别一对),让我们将它们合并成一对训练和测试分区,用于模型训练和测试。在连接这些 NumPy 数组之后,我们还将进行重新洗牌,以确保每个类别的图像都混合得很好。这是很重要的,因为在训练过程中,我们只会向模型发送小批量数据,所以为了模型的平稳训练,每个批次都应该包含来自所有类别的样本。由于测试数据是分开的,所以不需要洗牌。
此外,我们还需要创建相应的标签数组。由于机器学习算法只支持数值数据,我们需要将我们的输出类别编码成一些数值。我们可以用三个数字来表示我们的三个类别——0、1 和 2。
我们将使用以下标签映射规则来编码我们的类别:
-
良好 - 0
-
缺陷 - 1
-
损坏 - 2
下面的代码片段将所有训练分区连接成一个单一的训练分区,并使用前面提到的映射规则创建一个标签数组:
all_train_images = np.concatenate((good_bangles_train, \
defected_bangles_train, broken_bangles_train), axis=0)
all_train_labels = np.concatenate((
np.array([0]*len(good_bangles_train)),
np.array([1]*len(defected_bangles_train)),
np.array([2]*len(broken_bangles_train))),
axis=0
)
同样地,我们将所有测试分区连接成一个单一的测试分区。我们还将为我们的测试分区创建一个标签数组,这将帮助我们检查训练模型的准确度指标。在这里,我们也会打印出训练和测试分区的最终形状,如下面的代码所示:
all_test_images = np.concatenate((good_bangles_test, \
defected_bangles_test, broken_bangles_test), axis=0)
all_test_labels = np.concatenate((
np.array([0]*len(good_bangles_test)),
np.array([1]*len(defected_bangles_test)),
np.array([2]*len(broken_bangles_test))),
axis=0
)
print(all_train_images.shape, all_train_labels.shape)
print(all_test_images.shape, all_test_labels.shape)
此脚本的输出显示,我们总共有 810 张训练图像和 270 张测试图像,如下面的输出所示:
(810, 200, 200, 1) (810,)
(270, 200, 200, 1) (270,)
如前所述,确保我们的训练分区被充分打乱是非常重要的,以确保每个类别的图像都充分混合,并且每个批次都将有一个良好的多样性。在打乱时需要注意的重要事情是,我们还需要相应地打乱标签数组,以避免任何数据标签不匹配。为此,我们定义了一个 Python 函数,该函数可以同时打乱两个给定的数组:
def unison_shuffled_copies(a, b):
assert len(a) == len(b)
p = np.random.permutation(len(a))
return a[p], b[p]
all_train_images, all_train_labels = unison_shuffled_copies( \
all_train_images, all_train_labels)
all_test_images, all_test_labels = unison_shuffled_copies( \
all_test_images, all_test_labels)
我们的训练和测试数据集现在都已准备就绪。我们现在可以转向模型架构。
TF 模型架构
在本节中,我们将定义基于 TF 的深度学习分类模型的模型架构。由于我们在本实验中处理图像,我们将利用卷积神经网络(CNN)层来从训练图像中学习和提取重要特征。CNN 在计算机视觉领域已被证明非常有用。一般来说,几个 CNN 层堆叠在一起以提取低级(细节)和高级(形状相关)的特征信息。我们也将以类似的方式创建一个基于 CNN 的特征提取架构,并结合几个全连接层。最终的完全连接层应该有三个神经元来为每个类别生成输出,并使用一个sigmoid激活层将输出以概率分布的形式呈现。
一个卷积块
我们现在将定义一个可重复使用的卷积块,我们可以重复使用它来创建我们的最终模型架构。在卷积块中,我们将有每个卷积层后面跟着批归一化(BN)、ReLU激活、一个最大池化层和一个 dropout 层。在这里,BN 和 dropout 层是为了正则化目的,以确保我们的 TF 模型平稳学习。以下 Python 代码片段定义了我们的卷积块:
def convolution_block(data, filters, kernel, strides):
data = tensorflow.keras.layers.Conv2D(
filters=filters,
kernel_size=kernel,
strides=strides,
)(data)
data = tensorflow.keras.layers.BatchNormalization()(data)
data = tensorflow.keras.layers.Activation('relu')(data)
data = tensorflow.keras.layers.MaxPooling2D(strides=strides)(data)
data = tensorflow.keras.layers.Dropout(0.2)(data)
return data
现在,让我们通过使用这个卷积块来定义我们的完整模型架构。
TF 模型定义
我们现在可以定义我们的最终 TF 模型架构,该架构可以利用之前步骤中定义的卷积块进行几次迭代。我们首先定义一个输入层,告诉模型在训练期间期望的输入图像的大小。如前所述,我们数据集中的每个图像大小为 200x200x1。以下 Python 代码定义了我们的网络基于卷积的特征提取部分:
input_data = tensorflow.keras.layers.Input(shape=(200, 200, 1))
data = input_data
data = convolution_block(data, filters=64, kernel=2, strides=2)
data = convolution_block(data, filters=128, kernel=2, strides=2)
data = convolution_block(data, filters=256, kernel=2, strides=2)
data = convolution_block(data, filters=256, kernel=2, strides=1)
接下来,我们将使用一个Flatten()
层将所有特征汇总到一个单一维度,并应用全连接层来细化这些特征。最后,我们使用另一个具有三个神经元的全连接层,后面跟着一个softmax
激活,为三个类别生成概率输出。然后我们定义我们的模型对象,包括输入和输出层,并打印出模型的摘要以供参考:
data = tensorflow.keras.layers.Flatten()(data)
data = tensorflow.keras.layers.Dense(64)(data)
data = tensorflow.keras.layers.Activation('relu')(data)
data = tensorflow.keras.layers.Dense(3)(data)
output_data = tensorflow.keras.layers.Activation('softmax')(data)
model = tensorflow.keras.models.Model(inputs=input_data, \
outputs=output_data)
model.summary()
此代码片段打印出模型摘要,其外观类似于图 16**.2(对于完整的摘要,请参阅 Jupyter Notebook):
图 16.2:基于 TF 的缺陷检测架构的模型摘要
我们的 TF 模型图现在已准备就绪,因此我们可以现在编译并拟合我们的模型。
编译模型
在这一步中,我们可以定义适当的损失函数、优化算法和度量标准。由于我们有一个多标签分类问题,我们将利用分类交叉熵作为损失函数。我们将使用默认值的Adam优化器,并将'accuracy'
作为度量标准:
model.compile(
loss='sparse_categorical_crossentropy',
optimizer='adam',
metrics=['accuracy']
)
现在,我们已经准备好在之前整理的数据集上开始训练我们的模型。
训练模型
现在,我们已经准备好启动模型的训练,因为我们的数据和模型对象都已设置。我们计划以 64 个批次的规模训练模型 50 个 epoch。在每个 epoch 之后,我们将持续检查模型在训练和测试分区上的损失和准确率:
history = model.fit(
x=all_train_images,
y=all_train_labels,
batch_size=64,
epochs=50,
validation_data=(all_test_images, all_test_labels),
)
训练日志中包含损失和准确率值,其外观将类似于以下内容:
Epoch 1/50
13/13 [==============================] - 6s 311ms/step - loss: 1.1004 - accuracy: 0.5000 - val_loss: 7.9670 - val_accuracy: 0.2259
Epoch 2/50
13/13 [==============================] - 3s 260ms/step - loss: 0.8947 - accuracy: 0.5938 - val_loss: 11.9169 - val_accuracy: 0.2259
- - - -
Epoch 50/50
13/13 [==============================] - 3s 225ms/step - loss: 0.1369 - accuracy: 0.9481 - val_loss: 0.9686 - val_accuracy: 0.6741
一旦训练完成,我们就可以开始验证我们模型的成果。
绘制训练进度
在这一步中,我们将利用之前步骤中定义的history
变量来绘制训练损失、测试损失、训练准确率和测试准确率随 epoch 进展的进度图。这些图表可以帮助我们了解我们的模型训练是否正在正确的方向上进行。我们还可以检查获得合理测试集准确率所需的理想 epoch 数量。
让我们先绘制一个图表,将 epoch 编号放在X轴上,损失值放在Y轴上,以显示模型的训练和验证损失:
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'val'], loc='upper left')
plt.show()
此代码片段的输出显示在图 16.3中。从图中我们可以看到,随着训练的进行,训练和验证损失在下降,这告诉我们我们的模型训练正在正确的方向上进行,并且我们的模型正在学习。
图 16.3 – 训练和验证损失
接下来,我们还可以绘制模型在训练和测试分区上的准确率随训练进度变化的情况,如下面的代码所示:
plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('TF model accuracy trend.')
plt.ylabel('TF model accuracy')
plt.xlabel('epoch number')
plt.legend(['train', 'val'], loc='upper left')
plt.show()
生成的图表可以在图 16.4中看到。我们可以看到,随着模型开始过拟合,训练准确率持续增加并接近 100%,而验证准确率增加到约 70%并围绕该值波动。这意味着我们当前的设置能够在测试集上实现约 70%的准确率。通过增加网络的容量(添加几个更多层),或者改进我们从图像中提取特征的方式,我们可以进一步提高这个准确率值。对于我们的实验,这个准确率是可以接受的,我们将继续使用它。
图 16.4 – 随着训练 epoch 的推移的训练和验证准确率
由于我们的模型训练现在已经完成,我们可以开始对未见数据做出预测。让我们首先检查测试集上的结果。
结果
接下来,我们来检查未见测试集上的 TF 模型结果。在检查数字之前,让我们首先绘制一些测试图像及其真实标签和模型输出。
检查几个随机测试图像的结果
让我们先通过从测试集中选择一些随机图像,对它们进行预测,并将模型预测与实际标签一起绘制出来来验证模型的输出结果。我们将在图像标题中放入标签和预测信息,如下面的 Python 代码片段所示:
for iteration in range(2):
plt.figure(figsize=(12, 12))
for idx, img_idx in enumerate(np.random.permutation( \
len(all_test_images))[:4]
):
img = all_test_images[img_idx]
label = all_test_labels[img_idx]
pred = model.predict(np.array([img]), verbose=0)
model_output = np.argmax(pred)
plt.subplot(440 + 1 + idx)
plt.imshow(img, cmap='gray')
plt.title(f'Label: {label}, Model_output: \
{model_output}')
plt.axis('off')
plt.show()
这段代码的输出结果展示在图 16**.4中。我们可以看到,模型在类别 0 和类别 1 之间有些混淆,但由于形状上的大线索,很容易识别类别 2。提醒一下,这里的类别 0 代表好的手镯,类别 1 代表有缺陷的手镯,类别 2 代表破损的手镯。
图 16.5 – 对良好、有缺陷和破损手镯进行分类的模型结果
如图 16**.5所示,我们的模型在识别类别 2 方面做得很好,但在类别 0 和类别 1 之间有些混淆,这是由于非常微小的视觉线索。接下来,让我们检查整个测试集上的指标,以了解我们分类器的质量。
分类报告
要生成整个测试集的分类报告,我们首先需要为整个测试集生成模型输出。我们将选择概率最大的类别作为模型预测(注意,当我们有高度不平衡的数据集时,选择输出类别可能不是最佳选择)。以下是在整个测试集上生成模型输出的 Python 代码:
test_pred = model.predict(all_test_images)
test_outputs = [np.argmax(pred) for pred in test_pred]
我们现在可以打印出我们模型的分类报告:
print(
classification_report(all_test_labels,
test_outputs,
target_names=['Good', 'Defected', 'Broken'],
)
)
以下为分类报告的输出:
precision recall f1-score support
Good 0.88 0.52 0.65 130
Defected 0.62 0.69 0.65 61
Broken 0.58 0.92 0.71 79
accuracy 0.67 270
macro avg 0.69 0.71 0.67 270
weighted avg 0.73 0.67 0.67 270
分类报告表明,我们的模型在类别 0 和类别 1 上的 F1 分数约为 0.65,在类别 2 上的分数约为 0.71。正如所料,模型在识别破损手镯图像方面做得更好。因此,模型对“破损”类别的召回率非常好,约为 92%。总的来说,我们的模型表现不错,但仍有改进的潜力。
提高这个模型的准确率可以是一个很好的练习。以下是一些可能有助于提高模型整体准确率的提示:
-
使用更高分辨率的图像(比 200x200 更好的分辨率)
-
深度模型(更多和更大的 CNN 层以获得更好的特征)
-
数据增强(使模型更健壮)
-
更好的网络(使用注意力机制或其他特征提取策略进行更好的特征提取)
最后,让我们打印出混淆矩阵:
confusion_matrix(all_test_labels, test_outputs,)
这里是输出结果:
array([[67, 21, 42],
[ 8, 42, 11],
[ 1, 5, 73]])
混淆矩阵可以帮助我们确定模型犯了什么类型的错误。换句话说,当模型错误地将类别 0 分类时,它会将其混淆为哪个类别?
这样,我们为缺陷检测任务训练自定义 TF 模型的练习就完成了。现在,我们有一个平均性能的已训练 TF 模型。现在,让我们看看如何将此模型部署到 Google Vertex AI。
将视觉模型部署到 Vertex AI 端点
在上一节中,我们完成了基于 TF 的视觉模型训练实验,用于从产品图像中识别缺陷。现在我们有一个可以识别有缺陷或破损手镯图像的模型。为了使该模型在下游应用中使用,我们需要将其部署到端点,以便我们可以查询该端点,按需获取新输入图像的输出。在部署模型时,有一些重要的事项需要考虑,例如预期的流量、预期的延迟和预期的成本。基于这些因素,我们可以选择最佳的基础设施来部署我们的模型。如果对低延迟有严格的要求,我们可以将模型部署到具有加速器(如图形处理单元(GPU)或张量处理单元(TPU))的机器上。相反,如果我们没有在线或按需预测的必要性,那么我们不需要将模型部署到端点。离线批量预测请求可以在不部署模型到端点的情况下处理。
将模型保存到 Google Cloud Storage (GCS)
在我们的案例中,我们感兴趣的是将我们的模型部署到 Vertex AI 端点,只是为了看看它的工作原理。第一步是将我们的训练好的 TF 模型保存到 GCS:
model.save(
filepath='gs://my-training-artifacts/tf_model/',
overwrite=True,
)
模型保存后,下一步就是将此模型工件上传到 Vertex AI 模型注册表。一旦我们的模型上传到模型注册表,就可以轻松部署,无论是使用 Google Cloud 控制台 UI 还是 Python 脚本。
将 TF 模型上传到 Vertex 模型注册表
在这一步,我们将使用 Vertex AI SDK 将我们的 TF 模型上传到模型注册表。或者,我们也可以使用控制台 UI 来完成同样的操作。为此,我们需要提供模型显示名称、上传模型到的区域、保存模型工件的 URI 以及服务容器镜像。请注意,服务容器镜像必须安装了框架的适当版本的依赖项,例如 TF。Google Cloud 提供了一系列预构建的服务容器,可以立即用于模型服务。在我们的案例中,我们也将使用支持 TF 2.11 的服务预构建容器。
让我们设置一些配置:
PROJECT_ID='417812395597'
REGION='us-central1'
ARTIFACT_URI='gs://my-training-artifacts/tf_model/'
MODEL_DISPLAY_NAME='tf-bangle-defect-detector-v1'
SERVING_IMAGE='us-docker.pkg.dev/vertex-ai/prediction/tf2-cpu.2-11:latest'
现在,我们可以继续上传模型工件到模型注册表,如下面的 Python 代码所示:
aiplatform.init(project=PROJECT_ID, location=REGION)
model = aiplatform.Model.upload(
display_name=MODEL_DISPLAY_NAME,
artifact_uri=ARTIFACT_URI,
serving_container_image_uri=SERVING_IMAGE,
sync=True,
)
model.wait()
print("Model Display Name: ", model.display_name)
print("Model Resource Name: ", model.resource_name)
下面是输出结果:
Model Display Name: tf-bangle-defect-detector-v1
Model Resource Name: projects/417812395597/locations/us-central1/models/3991356951198957568
我们现在已经成功将我们的 TF 模型上传到注册表。我们可以使用模型显示名称或模型资源 ID 来定位我们的模型,如前所述。接下来,我们需要一个端点来部署我们的模型。
创建 Vertex AI 端点
在这一步,我们将创建一个 Vertex AI 端点,用于处理我们的模型预测请求。同样,端点也可以使用 Google Cloud 控制台 UI 来创建,但在这里,我们将使用 Vertex AI SDK 进行编程操作。
这里是一个可以用来创建端点的示例函数:
def create_vertex_endpoint(
project_id: str,
display_name: str,
location: str,
):
aiplatform.init(project=project_id, location=location)
endpoint = aiplatform.Endpoint.create(
display_name=display_name,
project=project_id,
location=location,
)
print("Endpoint Display Name: ", endpoint.display_name)
print("Endpoint Resource Name: ", endpoint.resource_name)
return endpoint
让我们使用这个函数来为我们的模型创建一个端点:
ENDPOINT_DISPLAY_NAME='tf-bangle-defect-detector-endpoint'
vertex_endpoint = create_vertex_endpoint(
project_id=PROJECT_ID,
display_name=ENDPOINT_DISPLAY_NAME,
location=REGION,
)
此代码片段给出以下输出,并确认端点已创建(请注意,此端点目前为空,没有任何模型):
Endpoint Display Name: tf-bangle-defect-detector-endpoint
Endpoint Resource Name: projects/417812395597/locations/us-central1/endpoints/4516901519043330048
我们可以使用以下命令列出区域内的所有端点,以验证其是否已成功创建:
gcloud ai endpoints list --region={REGION}
此命令给出以下输出:
ENDPOINT_ID DISPLAY_NAME
4516901519043330048 tf-bangle-defect-detector-endpoint
我们的端点现在已设置,因此我们可以继续部署模型。
将模型部署到 Vertex AI 端点
我们现在已经在模型注册表中有了我们的 TF 模型,并且我们也创建了一个 Vertex AI 端点。我们现在已经准备好将我们的模型部署到这个端点上了。此操作也可以使用 Google Cloud 控制台 UI 来执行,但在这里,我们将使用 Vertex AI SDK 进行编程操作。首先,让我们从注册表中获取我们模型的详细信息:
## List Model versions
models = aiplatform.Model.list( \
filter=f"display_name={MODEL_DISPLAY_NAME}")
print("Number of models:", len(models))
print("Version ID:", models[0].version_id)
Output:
Number of models: 1
Version ID: 1
现在,让我们将我们的模型部署到端点上:
MODEL = models[0]
DEPLOYED_MODEL_DISPLAY_NAME='tf-bangle-defect-detector-deployed-v1'
MACHINE_TYPE='n1-standard-16'
#Deploy the model to the Vertex AI endpoint
response = vertex_endpoint.deploy(
model=MODEL,
deployed_model_display_name=DEPLOYED_MODEL_DISPLAY_NAME,
machine_type=MACHINE_TYPE,
)
一旦此代码片段执行完成且没有错误,我们的模型应该准备好接受在线预测的请求。部署的模型信息也应显示在 Google Cloud 控制台 UI 中。我们还可以使用以下函数来验证部署的模型:
vertex_endpoint.gca_resource.deployed_models[0]
这应该会打印出与部署模型相关的资源。输出将类似于以下内容:
id: "4885783272115666944"
model: "projects/417812395597/locations/us-central1/models/3991356951198957568"
display_name: "tf-bangle-defect-detector-deployed-v1"
create_time {
seconds: 1694242166
nanos: 923666000
}
dedicated_resources {
machine_spec {
machine_type: "n1-standard-16"
}
min_replica_count: 1
max_replica_count: 1
}
model_version_id: "1"
我们现在已经验证了我们的 TF 模型已成功部署。现在,我们已经准备好调用此端点进行预测。在下一节中,我们将了解具有部署模型的端点如何提供在线预测。
从视觉模型获取在线预测
在上一节中,我们将基于 TF 的自定义模型部署到 Vertex AI 端点,以便我们可以将其嵌入到任何下游应用程序中,进行按需或在线预测。在本节中,我们将了解如何使用 Python 编程方式调用此端点进行在线预测。然而,预测请求也可以通过使用 curl
命令并发送包含输入数据的 JSON 文件来实现。
在制作预测请求时,有一些事情需要考虑;最重要的是相应地预处理输入数据。在第一部分,当我们训练模型时,我们对图像数据集进行了一些预处理,使其与模型兼容。同样,在请求预测时,我们也应该遵循完全相同的数据准备步骤。否则,由于输入格式不兼容,模型请求可能会失败,或者由于训练-服务偏差,它可能会给出不良的结果。我们已经有预处理的测试图像,因此我们可以直接在预测请求中传递它们。
由于我们将输入图像传递到请求 JSON 中,我们需要将其编码为 JSON 可序列化格式。因此,我们将以base64
格式将我们的输入图像发送到模型进行编码。查看以下示例代码,以创建单个测试图像的负载示例:
import base64
Instances = [
{
"input_1": {
"b64": base64.b64encode(all_test_images[0]).decode("utf-8")
}
}
]
让我们设置一些配置来调用端点:
from google.protobuf import json_format
from google.protobuf.struct_pb2 import Value
ENDPOINT_ID="4516901519043330048"
client_options = {"api_endpoint": "us-central1-aiplatform.googleapis.com"}
client = aiplatform.gapic.PredictionServiceClient( \
client_options=client_options)
instances = [
json_format.ParseDict(instance_dict, Value()) for \
instance_dict in Instances
]
parameters_dict = {}
parameters = json_format.ParseDict(parameters_dict, Value())
现在,我们可以继续向我们的 Vertex AI 端点发送预测请求。请注意,我们的参数字典是空的,这意味着我们将得到原始模型预测结果。在一个更定制化的设置中,我们也可以传递一些参数,例如阈值,以对模型预测进行相应的后处理。查看以下 Python 代码以请求预测:
endpoint = client.endpoint_path(
project=PROJECT_ID, location=REGION, endpoint=ENDPOINT_ID
)
response = client.predict(
endpoint=endpoint, instances=instances, \
parameters=parameters
)
print("response")
print(" deployed_model_id:", response.deployed_model_id)
predictions = response.predictions
同样,我们可以在instances
变量中传递多个图像,并从端点获取按需或在线预测结果。
摘要
在本章中,我们创建了一个端到端基于视觉的解决方案,用于从图像中检测视觉缺陷。我们看到了如何使用基于 CNN 的深度学习架构从图像中提取有用的特征,然后使用这些特征进行分类等任务。在训练和测试我们的模型之后,我们继续将其部署到 Vertex AI 端点,使其能够为任何数量的下游应用提供在线或按需预测请求。
完成本章后,你应该对如何处理基于视觉的问题以及如何利用机器学习来解决这些问题充满信心。你现在应该能够训练自己的基于视觉的分类模型来解决现实世界的商业问题。在完成将自定义模型部署到 Vertex AI 端点的第二部分和从 Vertex 端点获取在线预测的第三部分后,你现在应该能够通过将它们部署到 Google Vertex AI,使你的自定义视觉模型适用于任何下游商业应用。我们希望本章是一个良好的学习体验,包含了一个动手的实战示例。下一章也将展示一个与真实世界 NLP 相关的实战用例。
第十七章:自然语言模型 – 检测假新闻文章!
互联网上大量的内容是以文本格式存在的。几乎每个组织都存储了大量的内部数据和资源作为文本文档。自然语言处理(NLP)是机器学习的一个子领域,它关注于组织、理解和基于文本输入数据做出决策。在过去十年中,NLP 已经成为转变业务流程和做出明智决策的最重要方面。例如,情感分析模型可以帮助企业了解其客户对其产品和服务的整体情感。将主题建模算法与情感分析相结合可以找出客户的关键痛点,从而可以告知企业将客户满意度作为优先事项。
在本章中,我们将开发一个机器学习系统,该系统能够识别假新闻文章。这样的系统可以帮助确保互联网上的信息和新闻更加准确和安全。我们将涵盖以下主要主题:
-
使用 NLP 检测假新闻
-
在 Vertex AI 上启动模型训练
-
基于 BERT 的假新闻分类
技术要求
本章中使用的代码示例可以在本书的 GitHub 仓库中找到:github.com/PacktPublishing/The-Definitive-Guide-to-Google-Vertex-AI/tree/main/Chapter17
。
使用 NLP 检测假新闻
现在,由于互联网使用的增加,散布假新闻变得非常容易。每天都有大量用户通过他们的社交媒体账户在互联网上消费和发布内容。区分真实新闻和假新闻变得困难。然而,假新闻可以对个人、社会、组织或政党造成重大损害。从规模上看,手动或使用人工审阅员浏览每一篇文章是不可能的。因此,有必要开发智能算法,能够自动检测假新闻文章,并在假新闻生成时立即阻止其传播。
基于机器学习的分类算法可以用来检测假新闻。首先,我们需要一个良好的训练数据集来训练分类模型,以便它能够学习假新闻的共同模式,从而自动将其与真实新闻区分开来。在本节中,我们将训练一个机器学习模型来将文章分类为“假”或“真”。
使用随机森林进行假新闻分类
在本节中,我们将使用一种名为随机森林的基于树的分类算法来检测假新闻文章。在本章的最后部分,我们还将训练一个基于复杂深度学习的分类器,并比较两个模型的准确率。让我们开始实验。与这些实验相关的所有代码都可以在本书的 GitHub 仓库中找到,如技术要求部分所述。
关于数据集
我们已从 Kaggle 下载了数据集,该数据集具有开放使用的许可。数据集包含约 72k 篇新闻文章,包括标题、文本和标签。大约 50%的文章是“假新闻”,其余的是“真实新闻”。我们将利用这个数据集来训练一个基于 NLP 的分类模型,该模型可以检测假新闻。我们将保留数据集的一部分作为未见数据,以便在训练后测试模型结果。下载数据的链接可以在本书 GitHub 仓库中的 Jupyter 笔记本中找到。
注意
我们已经将数据下载并解压缩到与 Jupyter 笔记本相同的目录中。
现在,让我们进入实现部分。我们将从导入有用的 Python 库开始。
导入有用的库
第一步是在笔记本单元格中加载一些有用的 Python 库:
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from tqdm import tqdm_notebook
from sklearn.model_selection import train_test_split
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import roc_curve
%matplotlib inline
接下来,我们将加载并验证输入数据集。
读取和验证数据
在这里,我们将从 CSV 文件中读取数据到名为news_df
的 pandas DataFrame 中。我们将打印 DataFrame 的形状和一些顶级条目:
news_df = pd.read_csv("WELFake_Dataset.csv")
print(news_df.shape)
news_df.head()
该单元格的输出显示在图 17.1。正如我们所见,这个表中包含 72,134 篇新闻文章,每篇都有标题、正文和标签:
图 17.1 – 假新闻文章检测数据集概述
现在,让我们看看这个数据表中是否有任何缺失值。
NULL 值检查
我们需要检查数据集中是否存在任何 NULL 值。处理 NULL 值有不同的方法。如果 NULL 值的百分比非常低,我们可以选择从表中删除这些行;否则,我们可以用某个值填充这些条目。在我们的情况下,我们将使用空字符串值填充 NULL 字段:
news_df.isnull().sum()
这是该单元格的输出:
Unnamed: 0 0
title 558
text 39
label 0
dtype: int64
如我们所见,有非常少数的条目具有 NULL 值。让我们用空字符串填充它们:
news_df.fillna('', inplace=True)
我们现在可以继续进行数据清洗和预处理。
将标题和文本合并到单列
让我们创建一个名为content
的新列,其中包含合并的title
和text
元素,以便它包含有关新闻文章的所有可用文本信息。一旦我们完成这项工作,我们就可以使用这个列进行模型训练和分类:
news_df['content'] = [x + ' ' + y for x,y in zip(news_df.title, news_df.text)]
现在我们文本内容在单列中,我们可以开始清洗并准备它以供模型使用。
清洗和预处理数据
机器学习算法对噪声数据非常敏感。因此,在将数据传递到模型进行训练之前进行数据清洗和处理至关重要;这将允许模型从中学习有用的信息。由于我们在这里使用的是经典的机器学习算法,我们需要进行一些积极的清洗和预处理。在深度学习的情况下,数据预处理不是必需的(如本章最后部分所示)。当我们使用经典的机器学习算法解决 NLP 问题时,我们通常使用诸如 TF 和 TF-IDF 之类的特征提取方法。正如我们所知,这些特征提取方法对单词计数敏感,因此从文本中删除不太有意义的单词(如停用词)和字符变得很重要。
在这个实验中,我们将遵循以下步骤来清洗和预处理数据:
-
从文本中删除特殊字符和数字。
-
将文本转换为小写(这样“HELLO”和“hello”对分类算法来说是相同的)。
-
通过空格分割内容以获取单词列表。
-
删除停用词。这些是常见的英语单词,在句子中通常没有意义。例如包括 they、the、and、he 和 him。
-
应用词干提取。这涉及到将单词还原为其基本形式(例如,“happiness”应还原为“happy”,以便相同单词的不同变体对模型来说是相同的)。
Join words with spaces in between to create text.
We will require some NLP-specific libraries that will help in preparing the data. Here, we will utilize the nltk (Natural Language Toolkit) library to remove stopwords and apply the stemming operation. To convert our text data into a numerical format, we will utilize the TfidfVectorizer method from the sklearn library:
import re
from nltk.corpus import stopwords
from nltk.stem.porter import PorterStemmer
from sklearn.feature_extraction.text import TfidfVectorizer
注意
当我们安装nltk
库时,它不会自动下载与之相关的所有必需资源。在我们的情况下,我们将必须明确在终端中运行以下命令来下载英语语言中的停用词:
nltk.download("stopwords")
这里是我们的数据清洗和预处理函数。由于这个函数在整个数据集上运行,所以需要一些时间来完成:
def clean_and_prepare_content(text):
text = re.sub('[^a-zA-Z]',' ', text)
text = text.lower()
text_words = text.split()
imp_text_words = [word for word in text_words if not word in stopwords.words('english')]
stemmed_words = [porter_stemmer.stem(word) for word in imp_text_words]
processed_text = ' '.join(stemmed_words)
return processed_text
porter_stemmer = PorterStemmer()
news_df['processed_content'] = news_df.content.apply(lambda content: clean_and_prepare_content(content))
现在,让我们将内容和标签分离成数组,以便进行建模。
分离数据和标签
在这里,我们正在分离数据和标签,并将它们放入两个单独的列表中:
X = news_df.processed_content.values
y = news_df.label.values
print(X.shape, y.shape)
Here's the output:
(72134,) (72134,)
现在,让我们将文本转换为数值。
将文本转换为数值数据
由于机器学习算法只理解数字,我们需要将文本数据转换为数值格式。在我们的实验中,我们将创建 TF-IDF 特征:
vectorizer = TfidfVectorizer()
vectorizer.fit(X)
X = vectorizer.transform(X)
print(X.shape)
Here's the output:
(72134, 162203)
我们现在可以将数据分成训练集和测试集,以便在训练后测试我们模型的成果。
注意
在实际的 NLP 项目中,在应用数值转换之前,我们必须将数据集分成训练集和测试集。转换函数(如TfidfVectorizer
)应该仅对训练数据进行拟合,然后应用于测试数据。这是因为,在现实世界的设置中,我们可能在数据集中遇到一些未知单词,我们的模型在训练期间不应该看到这些单词。这种设置的问题还包括它会导致数据泄露,因为整个数据集上计算出的统计数据也属于测试分区。在这个例子中,我们为了简单起见,在分割数据集之前就进行了这种转换。
数据分割
接下来,我们必须将数据分割为训练和测试分区。我们将使用大约 80%的数据进行训练,剩余的 20%用于测试:
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, stratify=y, random_state=42)
我们的训练和测试数据分区现在已准备好输入模型。接下来,我们将定义模型。
定义随机森林分类器
对于我们的简单实验,我们正在使用随机森林模型的默认超参数值。然而,在实际应用中,我们可以尝试不同的超参数值组合以获得最佳结果。或者,我们可以利用超参数调优来找到我们模型的最佳超参数:
rf_model = RandomForestClassifier()
让我们继续在训练分区上训练模型。
训练模型
让我们将模型拟合到训练数据集:
rf_model.fit(X_train, y_train)
下面是输出结果:
RandomForestClassifier()
我们现在已完成模型训练,这意味着我们可以开始预测测试数据以检查模型的结果。
预测测试数据
在这里,我们使用训练好的随机森林分类器对测试分区进行预测。predict
函数给出类别级别的输出,而predict_proba
函数给出概率输出:
y_pred = rf_model.predict(X_test)
y_proba = rf_model.predict_proba(X_test)
在这里,我们已经对整个数据集进行了预测。让我们看看我们的模型做得如何。
在测试数据集上检查结果/指标
下一个重要步骤是检查并验证我们的模型在测试数据集上的性能。在这里,我们将使用 sklearn 的分类报告方法来获取每个类别的精确度、召回率和 F1 分数。查看以下代码片段:
# classification report
print(
classification_report(
y_test,
y_pred,
target_names=['Real', 'Fake'],
)
)
下面是分类报告的输出:
precision recall f1-score support
Real 0.94 0.92 0.93 7006
Fake 0.93 0.94 0.94 7421
accuracy 0.93 14427
macro avg 0.93 0.93 0.93 14427
weighted avg 0.93 0.93 0.93 14427
如我们所见,我们的模型对于两个类别都有大约 93%的精确度和召回率。总体准确率也大约是 93%。因此,我们可以说我们的模型足够好,能够识别大约 93%的假新闻文章。
接下来,让我们绘制 ROC 曲线。ROC 曲线是分类模型的假阳性率(FPR)和真阳性率(TPR)之间的图形:
def plot_roc_curve(y_true, y_prob):
"""
plots the roc curve based of the probabilities
"""
fpr, tpr, thresholds = roc_curve(y_true, y_prob)
plt.plot(fpr, tpr)
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plot_roc_curve(y_test, y_proba[:,1])
查看图 17.2以了解我们实验的 ROC 曲线。在典型的 ROC 曲线中,X 轴代表 FPR,Y 轴代表 TPR。ROC 曲线下的面积,也称为ROC-AUC,表示分类模型的质量。面积值越高,表示模型越好:
图 17.2 – 假新闻分类模型的 ROC 曲线
让我们也查看混淆矩阵,看看我们的模型在哪里出错。
混淆矩阵
最后,让我们也打印出我们分类的混淆矩阵。混淆矩阵显示了每个类别的正确和错误分类的数量。它还显示了如果分类错误(假阳性和假阴性)的话,哪些其他类别被预测为错误:
confusion_matrix(y_test, y_pred,)
下面是输出结果:
array([[6455, 551],
[ 409, 7012]])
我们的实验现在已经完成。如果结果令人满意,我们可以继续部署此模型作为 API。如果结果仍然不可接受,我们可以进行更多不同设置的实验。
如果我们要并行进行大量实验,我们可以通过 Vertex AI 训练作业启动许多并行实验,而无需不断监控它们,并在训练完成后稍后再进行检查。在下一节中,我们将看到如何配置 Vertex AI 训练作业。
在 Vertex AI 上启动模型训练。
在本节中,我们将以 Vertex AI 训练作业的形式启动我们的训练实验。与在 Jupyter Notebook 中执行相比,在 Vertex AI 上启动训练作业有多个优点:
-
可以灵活地启动任意数量的并行实验。
-
我们可以选择最佳的硬件进行模型训练,这在需要训练深度学习模型时非常重要。
-
我们不需要对训练进度进行主动监控。
-
没有 Jupyter Notebook 崩溃的担忧。
-
Vertex AI 训练作业可以配置为在 Google Cloud Console UI 中记录元数据和实验。
-
在本节中,我们将为我们的实验创建并启动一个 Vertex AI 训练作业。启动 Vertex AI 训练作业主要有两件事要做。首先,我们需要将数据集放置在一个 Vertex AI 作业可访问的位置(例如 GCS 或 BigQuery)。其次,我们需要将模型训练代码整理到一个单独的
task.py
文件中,以便将其打包到包含所有必要依赖项的训练容器中。
这里是我们需要遵循的步骤来创建和启动我们的 Vertex AI 训练作业:
-
将数据集上传到 GCS 或 BigQuery(我们将使用 GCS)。
-
创建一个执行以下操作的
task.py
文件:-
从 GCS 读取数据。
-
进行必要的数据准备。
-
训练 RF 模型。
-
将训练好的模型保存到 GCS。
-
在测试集上进行预测。
-
(可选)将预测保存到 GCS。
-
打印一些结果/指标。
-
-
使用预构建的训练镜像。
-
启动 Vertex AI 训练。
-
在 Google Cloud Console UI 上监控进度。
考虑到这些步骤,我们已经在我们的实验中创建了一个task.py
文件;它可以在本书的 GitHub 仓库中找到。接下来,我们将学习如何使用这个task.py
文件来启动作业。
设置配置。
在这里,我们将定义在 Vertex AI 上启动训练作业时必要的与项目和数据位置相关的配置。以下代码片段显示了与我们实验相关的某些配置:
PROJECT_ID='417xxxxxxx97'
REGION='us-west2'
BUCKET_URI='gs://my-training-artifacts'
DATA_LOCATION='gs://my-training-artifacts/WELFake_Dataset.csv'
# prebuilt training containers
TRAIN_VERSION = "tf-cpu.2-9"
TRAIN_IMAGE = "us-docker.pkg.dev/vertex-ai/training/{}:latest".format(TRAIN_VERSION)
让我们使用适当的变量初始化 Vertex AI SDK。
初始化 Vertex AI SDK。
在这里,我们正在初始化 Vertex AI SDK 以设置作业的项目、位置和暂存存储桶:
from google.cloud import aiplatform
aiplatform.init(project=PROJECT_ID, location=REGION, staging_bucket=BUCKET_URI)
现在我们已经设置了配置,我们可以开始定义 Vertex AI 训练作业。
定义 Vertex AI 训练作业。
以下代码块定义了我们的实验的 Vertex AI 训练作业。在这里,我们传递display_name
,这将帮助我们定位控制台 UI 中的作业。请注意,我们正在将我们的task.py
文件作为脚本路径变量传递。container_uri
是用于启动作业的预构建容器。最后,我们可以指定运行我们的训练代码所需的任何额外的 Python 包。在我们的情况下,我们需要安装nltk
包以实现一些 NLP 相关的功能:
job = aiplatform.CustomTrainingJob(
display_name="fake_news_detection",
script_path="task.py",
container_uri=TRAIN_IMAGE,
requirements=["nltk"],
)
我们基于 Vertex AI 的自定义训练作业现在已准备就绪。让我们运行它。
运行 Vertex AI 作业
我们已经准备好启动我们的训练作业。我们使用n1-standard-16
类型的机器进行实验,可以根据我们的需求进行修改。查看以下代码片段,它将在 Vertex AI 上启动我们的训练作业:
# Start the training job
model = job.run(
machine_type = "n1-standard-16",
replica_count=1,
)
启动作业后,我们应该在输出中看到一个 URL,指向云控制台 UI 中的作业。输出应该看起来像这样:
Training script copied to:
gs://my-training-artifacts/aiplatform-2023-09-04-04:41:36.367-aiplatform_custom_trainer_script-0.1.tar.gz.
Training Output directory:
gs://my-training-artifacts/aiplatform-custom-training-2023-09-04-04:41:36.625
View Training:
https://console.cloud.google.com/ai/platform/locations/us-west2/training/8404xxxxxxxxxx898?project=417xxxxxxxx7
CustomTrainingJob projects/417xxxxxxxx7/locations/us-west2/trainingPipelines/840xxxxxxxxxx92 current state:
PipelineState.PIPELINE_STATE_RUNNING
View backing custom job:
https://console.cloud.google.com/ai/platform/locations/us-west2/training/678xxxxxxxxxxx48?project=417xxxxxxxx7
CustomTrainingJob projects/417xxxxxxxx7/locations/us-west2/trainingPipelines/840xxxxxxxxxx92 current state:
PipelineState.PIPELINE_STATE_RUNNING
有了这些,我们已经成功地将我们的实验作为一个训练作业在 Vertex 上启动。现在我们可以使用云控制台 UI 监控作业的进度。接下来,我们将使用深度学习方法来解决这个问题,希望得到更好的结果。
基于 BERT 的虚假新闻分类
在我们的第一个实验中,我们使用 TF-IDF 特征在经典随机森林分类器上进行训练,以检测虚假新闻与真实新闻文章,并获得了大约 93%的准确率。在本节中,我们将训练一个深度学习模型来完成相同的任务,并看看我们是否能比经典的基于树的算法获得更高的准确率。深度学习已经改变了我们解决自然语言处理(NLP)问题的方式。经典方法需要手工制作的特征,其中大部分与文档中出现的单词频率有关。考虑到语言的复杂性,仅仅知道段落中单词的数量是不够的。单词出现的顺序也对段落或句子的整体意义有显著影响。深度学习方法,如长短期记忆网络(LSTM)也考虑了句子或段落中单词的顺序依赖性,以获得更有意义的特征表示。LSTM 在许多 NLP 任务中取得了巨大成功,但也存在一些局限性。由于这些模型是按顺序训练的,因此很难扩展这些模型。其次,当我们处理非常长的序列时,LSTMs 会遭受上下文丢失,因此它们不适合理解较长序列的上下文。由于一些局限性,包括这里讨论的局限性,人们发明了从顺序输入中学习上下文的新方法。
基于转换器的模型的出现对自然语言处理(NLP)和视觉人工智能领域具有里程碑意义。基于转换器的模型严重依赖于注意力机制来捕捉上下文和序列间的模式,并且它们也能够处理非常长的输入序列。来自转换器的双向编码器表示(BERT)是一系列基于转换器架构一部分的 NLP 模型。基于 BERT 的模型在众多 NLP 任务中取得了巨大成功,其中一些在过去几十年中似乎几乎不可能实现。
与深度学习模型合作的一个优点是,我们不必每次都从头开始训练它们。我们总是利用预训练模型,然后在我们的特定领域数据上微调它们,以更快地获得出色的结果,而且不需要大量的特定领域训练数据。这种方法被称为迁移学习,这是大型深度学习模型在大量数据上预训练后,可以用于许多下游特定领域任务,因为它们可以用少量特定领域训练数据进行微调。
BERT 用于假新闻分类
在这个实验中,我们将利用一个预训练的 BERT 模型,并在我们的新闻文章训练数据集上稍作微调。让我们开始吧。
导入有用的库
在这个实验中,我们将利用 PyTorch 作为微调 BERT 模型的框架。我们还利用 Hugging Face 的 transformers
库来加载基于 BERT 的模型的预训练权重,以及一些用于设置微调的有用工具:
import torch
from transformers import BertTokenizer
from transformers import BertForSequenceClassification
from transformers import AdamW
from transformers import get_linear_schedule_with_warmup
from torch.utils.data import TensorDataset
from torch.utils.data import random_split, DataLoader
现在,让我们开始准备数据集。
数据集
我们将使用与第一个实验中相同的同一个数据集。因此,我们在这里也将遵循相同的步骤——我们将加载数据,处理 NULL 值,并创建一个包含所有必要文本的内容列:
news_df = pd.read_csv("WELFake_Dataset.csv")
news_df.fillna('', inplace=True)
news_df['content'] = [x + ' ' + y for x,y in zip(news_df.title, news_df.text)]
接下来,我们将内容列中的文本转换为小写:
news_df['content'] = news_df['content'].apply(lambda text: text.lower())
现在,我们将文本和标签分开,并将它们存储为列表:
texts = news_df.content.values
labels = news_df.label.values
print(len(texts), len(labels))
这是输出:
72134 72134
现在,让我们根据 BERT 模型输入的要求准备我们的数据集。
数据准备
由于我们现在正在使用 BERT 模型,我们不需要执行大量的数据清理,例如删除数字、删除停用词、词干提取等。每个 BERT 模型都有一个标记器,用于将文本数据转换为数字 ID。因此,我们需要找到适当的 BERT 标记器(可以通过 Hugging Face 的 transformers
库加载),进行标记化,并为训练目的创建注意力掩码。
让我们创建标记器对象:
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
在这里,我们定义了一个函数,该函数将创建用于训练的标记化文本和注意力掩码:
def prepare_tokenized_data(texts, labs='None'):
global labels
input_id_list = []
attention_masks = []
接下来,我们必须为每个输入文本生成编码和注意力掩码:
for text in tqdm_notebook(texts):
encoded_dict = tokenizer.encode_plus(
text,
add_special_tokens = True,
truncation = 'longest_first',
max_length = 100,
pad_to_max_length = True,
return_attention_mask = True,
return_tensors = 'pt'
)
input_id_list.append(encoded_dict['input_ids'])
attention_masks.append(encoded_dict['attention_mask'])
现在,让我们将列表转换为 PyTorch 张量:
input_id_list = torch.cat(input_id_list, dim=0)
attention_masks = torch.cat(attention_masks, dim=0)
if labs != 'None':
labels = torch.tensor(labels)
return input_id_list, attention_masks, labels
else:
return input_id_list, attention_masks
在这里,我们调用必要的函数,以准备我们的数据:
input_id_list, attention_masks, labels = (
prepare_tokenized_data(texts, labels)
)
现在,让我们将我们的数据分成训练和测试部分。
数据分割
在这里,我们将从输入 ID、注意力掩码和标签创建一个张量数据集,并将其分为训练集和测试集。类似于第一个实验,我们将使用大约 80%的数据进行训练(或微调)目的,剩余的 20%用于测试结果和指标。以下代码片段显示了如何创建和分割张量数据集:
tensor_dataset = TensorDataset(input_id_list, attention_masks, labels)
# lets keep 80% articles for training and 20% for test
train_size = int(0.8 * len(tensor_dataset))
test_size = len(tensor_dataset) - train_size
train_data, test_data = random_split(tensor_dataset, [train_size, test_size])
print(len(train_data.indices), len(test_data.indices))
这是输出:
(57707, 14427)
现在,让我们定义具有所需批量大小的数据加载器对象。
创建用于批处理的数据加载器对象
下一步是为训练和测试分区创建数据加载器对象。我们将为训练数据设置 32 个批大小,为测试数据设置 1 个批大小:
batch_size = 32
num_workers = 4
train_data_loader = DataLoader(
dataset=train_data,
batch_size=batch_size,
shuffle=True,
num_workers=num_workers,
)
# test data loader with batch size of 1
test_data_loader = DataLoader(
dataset=test_data,
batch_size=1,
shuffle=False,
)
我们的数据现在已准备好用于模型。这意味着我们可以加载模型并开始训练。
加载预训练的 BERT 模型
在这里,我们将加载基于 BERT 的模型的预训练权重,以便我们可以在自定义数据集上进一步微调。许多 BERT 变体的预训练权重都可在 Hugging Face 上找到,并且可以通过transformers
库加载,如下面的代码片段所示:
device = 'cpu'
bert_model = BertForSequenceClassification.from_pretrained(
'bert-base-uncased',
num_labels=2,
output_attentions=False,
output_hidden_states=False,
)
bert_model.to(device)
使用device
变量,我们可以选择在加速器上加载我们的模型,例如 GPU。此代码片段下载了具有两个标签分类层的bert-base-uncased
模型的预训练权重。执行此代码片段还会打印 BERT 架构摘要,其外观类似于以下内容:
BertForSequenceClassification(
(bert): BertModel(
(embeddings): BertEmbeddings(
(word_embeddings): Embedding(30522, 768, padding_idx=0)
(position_embeddings): Embedding(512, 768)
(token_type_embeddings): Embedding(2, 768)
(LayerNorm): LayerNorm((768,), eps=1e-12, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
)
. . . . . . . . . . .
. . . . . . . . . . .
现在,我们的模型已经加载,让我们定义优化设置。
优化器
在这里,我们定义了AdamW
优化器并设置了自定义学习率:
optimizer = torch.optim.AdamW(
bert_model.parameters(),
lr=6e-6,
eps=1e-8,
)
让我们也为模型训练定义一个调度器。
调度器
在这里,我们设置训练步骤和训练调度器。我们计划在我们的训练分区上微调模型仅3
个周期,之后我们将检查测试集上的结果:
num_epochs = 3
steps_per_epoch = len(train_data_loader)
total_steps = steps_per_epoch * num_epochs
scheduler = get_linear_schedule_with_warmup(
optimizer,
num_warmup_steps = 0,
num_training_steps = total_steps,
)
现在,我们已经准备好开始训练模型。
训练 BERT
在这里,我们将根据前一个子节中定义的3
个周期,在训练数据上微调 BERT 模型:
bert_model.train()
for epoch in range(num_epochs):
total_loss = 0
for i, (ids, masks, labels) in enumerate(train_data_loader):
ids = ids.to(device)
masks = masks.to(device)
labels = labels.to(device)
loss = bert_model(ids, token_type_ids=None, attention_mask=masks, labels=labels)[0]
optimizer.zero_grad()
loss.backward()
optimizer.step()
scheduler.step()
total_loss += loss.item()
print('Epoch: {}, Loss: {:.4f}'.format(epoch+1, total_loss / steps_per_epoch))
此训练代码片段在每个训练周期完成后打印模型损失。我们的实验的损失输出如下:
Epoch: 1, Loss: 0.0803
Epoch: 2, Loss: 0.0229
Epoch: 3, Loss: 0.0112
现在,我们的模型训练(或微调)已完成,我们可以保存模型权重:
# save trained model locally
torch.save(bert_model.state_dict(), 'BERT.ckpt')
这样,我们已经成功训练并保存了模型。现在,让我们继续进行模型评估。
加载模型权重进行评估
在这里,我们加载我们的训练模型权重以进行评估:
bert_model.eval()
bert_model.load_state_dict(
torch.load('BERT.ckpt'),
)
Output:
<All keys matched successfully>
让我们检查训练模型在测试数据集上的准确率。
计算测试数据集的准确率
现在,我们的模型已经训练并加载用于评估,我们可以在测试数据集上进行预测并检查其准确率。
我们将在以下变量中存储预测结果,并计算正确预测的数量:
correct_predictions = 0
predictions = []
reals = []
在这里,我们在测试数据上运行模型预测:
for i, (ids, masks, labels) in enumerate(test_data_loader):
ids = ids.to(device)
masks = masks.to(device)
labels = labels.to(device)
bert_out = bert_model(ids, token_type_ids=None, attention_mask=masks, labels=labels)[1]
prediction = torch.max(bert_out, 1)[1][0].item()
true_label = labels[0].item()
correct_predictions += int(prediction == true_label)
predictions.append(prediction)
reals.append(true_label)
我们可以通过将正确预测的数量除以总预测数量来计算准确率:
avg_correct_predictions = correct_predictions / len(test_data)
print('Accuracy: {:.4f}\n'.format(avg_correct_predictions))
这个单元格的输出显示,我们的模型在测试数据集上的准确率约为 99%。这比经典的随机森林模型有了巨大的改进:
Accuracy: 0.9902
最后,让我们打印出混淆矩阵:
print(confusion_matrix(reals, predictions,))
下面是输出结果:
[[7025 53]
[ 88 7261]]
现在,我们可以为我们的模型生成一个分类报告。
分类报告
最后,我们将打印出我们实验的分类报告,以了解每个类别的精确率、召回率和 F1 分数:
print(
classification_report(
reals,
predictions,
target_names=['Real', 'Fake'],
)
)
下面是输出结果:
precision recall f1-score support
Real 0.99 0.99 0.99 7078
Fake 0.99 0.99 0.99 7349
accuracy 0.99 14427
macro avg 0.99 0.99 0.99 14427
weighted avg 0.99 0.99 0.99 14427
上述输出表明,我们的基于 BERT 的分类模型非常准确,准确率约为 99%。同样,对于每个类别,我们都有大约 99%的精确率和召回率。这个实验表明,使用预训练的深度学习模型可以大幅度提高分类的准确率。
摘要
本章介绍了关于检测假新闻的真实世界 NLP 应用案例。在当前互联网时代,传播假新闻变得相当容易,这对个人、社会、组织或政党的声誉可能构成危险。正如我们在实验中所看到的,机器学习分类可以被用作检测假新闻文章的强大工具。基于深度学习的方案可以进一步提高文本分类用例的结果,而无需进行大量的微调数据。
在阅读本章之后,你应该对在文本分类用例(如假新闻检测)中训练和应用分类模型充满信心。你也应该对应用经典模型(如随机森林)所需的清理和预处理步骤有很好的理解。此时,你应该能够启动大规模机器学习实验作为 Vertex AI 训练作业。最后,你应该对如何应用和微调基于深度学习的 BERT 模型以用于文本分类用例有很好的理解。