谷歌机器学习和生成式人工智能的解决方案架构-全-

谷歌机器学习和生成式人工智能的解决方案架构(全)

原文:annas-archive.org/md5/90c02ac66d0c0f03912aac73223f0fbf

译者:飞龙

协议:CC BY-NC-SA 4.0

前言

几乎每家公司现在都在以某种方式使用或尝试使用人工智能/机器学习,尤其是在生成式人工智能最近的革命之后。虽然人工智能/机器学习研究无疑很复杂,但实际构建和运行有效使用人工智能/机器学习应用程序的过程通常更为复杂。这本书教你如何根据多年在世界上一些领先技术公司实施大规模和高度复杂的人工智能/机器学习项目的经验,成功设计和运行人工智能/机器学习工作负载。

本书的前几章提供了不同类别的人工智能和机器学习(AI/ML)以及一般云计算概念的概述。随后是对 Google Cloud 的概述,包括与人工智能/机器学习相关的 Google Cloud 产品及其预期用例示例。

然后,这本书将逐步介绍典型机器学习项目和模型开发生命周期的各个阶段。每一章都涵盖了生命周期中的一个重要阶段。你不仅将学习这些概念,还将通过每章附带的实际练习将它们付诸实践。这个过程从获取和准备数据开始,然后转向训练机器学习模型。然后,我们将部署模型并从中获取推断。你还将学习在部署后监控和更新模型,以确保它们继续提供最佳可能的结果。此外,你将通过构建端到端的 MLOps 解决方案来自动化所有这些步骤。

这本书不仅涵盖了机器学习模型开发生命周期的所有步骤,还涵盖了在企业规模实施和管理机器学习解决方案中的重要主题。我们将深入探讨诸如隐私、合规性、伦理以及许多其他对于在真实商业环境中运行机器学习解决方案所必需考虑的话题。

在阅读完这本书之后,你将掌握云计算、Google Cloud、人工智能/机器学习以及生成式人工智能的高级知识。你将构建复杂的项目、解决方案和模型,解决现实世界的商业用例,并学习到公司在构建人工智能/机器学习解决方案时经常遇到的常见挑战,以及如何根据多年在行业最大和最复杂的 AI/ML 系统和项目上的经验来应对这些挑战。你还将学习和实施重要的解决方案架构考虑因素,如可靠性、可扩展性和安全性,以及它们如何应用于人工智能/机器学习用例。

这些技能在技术行业中是最受欢迎且薪酬最高的,在所有行业中也是最受欢迎的技能之一。考虑到这一点,请加入我的旅程,并从今天开始提升你的职业生涯。

这本书面向的对象

本书主要面向解决方案架构师或希望成为解决方案架构师的读者,他们希望学习如何在谷歌云上设计和实施人工智能/机器学习解决方案。然而,它也可以供希望学习谷歌云的人工智能/机器学习和生成式人工智能工具以及有助于他们构建稳健解决方案的重要解决方案架构概念的数据科学家使用。

在我的职业生涯中,我积累了大量为广泛受众编写技术文档的经验。我了解到,在这方面的一项最佳实践是永远不要假设文档的读者对该主题有先前的“内在知识”。在这本书中,你会发现我总是从需要理解的基础知识开始,然后进入更复杂的话题。这种方法的优点是,如果你已经掌握了基础知识,你可以直接跳到更复杂的话题,而如果你对某个话题是新手,你也不会落后。这意味着本书既适合初学者也适合高级从业者,因为每一章都是从基本概念开始的,然后逐步涵盖更高级的应用案例。

更广泛地说,本书首先介绍重要的基本人工智能/机器学习概念,然后通过示例和动手活动逐步增加复杂性,最终深入探讨当今市场上解决实际应用案例的高级、前沿人工智能/机器学习应用。

本书涵盖的内容

第一章**, 人工智能/机器学习概念、实际应用和挑战,为本书中更深入探讨的人工智能/机器学习主题奠定了基础。

第二章**, 理解机器学习模型开发生命周期,介绍了典型、结构良好的机器学习项目中常见的步骤。

第三章**, 人工智能/机器学习 具和谷歌云人工智能/机器学习 ,描述了构建人工智能/机器学习解决方案的工具,特别是在谷歌云上。

第四章**, 利用谷歌云的 AI 服务,开始使用工具来实现实际的 AI/ML 应用案例。

第五章**, 在谷歌云上构建 ,在谷歌云上使用 Scikit-learn 进行实践操作。

第六章**, 深入探讨 - 在谷歌云上为人工智能/机器学习工作负载准备和处理数据,概述了实施复杂数据处理工作负载的程序。

第七章**, 特征工程和降维,基于前一章的数据处理主题,本章重点介绍机器学习项目中最重要的步骤之一:特征工程。

第八章**,超参数和优化*,概述了超参数调优的重要性,以及如何在 Vertex AI 中实现这一点。

第九章**,神经网络和深度学习,概述了使用神经网络解决 AI/ML 中更复杂问题的应用。

第十章**,生产环境中的部署、监控和扩展,专注于如何将机器学习模型投入生产,在此过程中面临的挑战类型,以及如何使用 Vertex AI 来解决其中的一些挑战。

第十一章**,使用谷歌云*的机器学习工程和 MLOps,更详细地介绍了部署概念和挑战,并描述了 MLOps 在解决大规模生产 AI/ML 工作负载挑战中的重要性。

第十二章**,偏差、可解释性、公平性和谱系,详细讨论了这些概念,并解释了如何有效地将这些概念融入读者的 ML 工作负载中。

第十三章**,ML 治理和谷歌云架构框架,描述了在谷歌云上运行 AI/ML 工作负载的架构设计模式。

第十四章**,额外的 AI/ML 工具、框架和考虑因素*,扩展到其他流行的 AI/ML 框架,如 PyTorch、Spark ML 和 BigQuery ML。

第十五章**,生成式 AI 简介,概述了生成式 AI 的基本概念,并关注其与“传统”预测 AI/ML 的区别。

第十六章**,高级生成式 AI概念和应用案例,深入探讨了嵌入、向量数据库以及 RAG 和 LangChain 等框架。

第十七章**,谷歌云上的生成式 AI,探讨了谷歌云的生成式 AI 产品与解决方案。

第十八章**,整合一切:使用谷歌云和 Vertex AI 构建 ML 解决方案*,汇集了本书中我们学到的所有主要元素,并帮助我们构建参考架构。

为了充分利用这本书

在整本书中,我提供了如何安装所有必需软件的全面指导。我还提供了构建本书中概述的所有解决方案所需的所有代码,以及代码功能的详细描述。具备 Python 知识将是一个优势,但不是硬性前提条件。

本书涵盖的软件/硬件 操作系统要求
Python Linux
Scikit-learn Linux
TensorFlow Linux

如果您正在使用本书的数字版,我们建议您亲自输入代码或从本书的 GitHub 仓库(下一节中提供了链接)获取代码。这样做将帮助您避免与代码的复制和粘贴相关的任何潜在错误。

下载示例代码文件

您可以从 GitHub 下载本书的示例代码文件github.com/PacktPublishing/Google-Machine-Learning-for-Solutions-Architects。如果代码有更新,它将在 GitHub 仓库中更新。

我们还有其他来自我们丰富图书和视频目录的代码包,可在github.com/PacktPublishing/找到。查看它们吧!

使用的约定

本书使用了多种文本约定。

文本中的代码:表示文本中的代码单词、数据库表名、文件夹名、文件名、文件扩展名、路径名、虚拟 URL、用户输入和 Twitter 昵称。以下是一个示例:“将下载的WebStorm-10*.dmg磁盘映像文件作为系统中的另一个磁盘挂载。”

代码块设置如下:

import matplotlib.pyplot as plt
import pandas as pd
# Load dataset
data = load_wine()
df = pd.DataFrame(data.data, columns=data.feature_names)

当我们希望您注意代码块中的特定部分时,相关的行或项目将以粗体显示:

{
  "name": "BUCKET_NAME",
  "location": "BUCKET_LOCATION",
  "storageClass": "STORAGE_CLASS",
  "iamConfiguration": {
    "uniformBucketLevelAccess": {
      "enabled": true
    },
  }
}

任何命令行输入或输出都按以下方式编写:

$ cd packt-ml-sa

粗体:表示新术语、重要单词或您在屏幕上看到的单词。例如,菜单或对话框中的单词以粗体显示。以下是一个示例:“从管理面板中选择系统信息。”

小贴士或重要注意事项

看起来是这样的。

联系我们

我们读者的反馈总是受欢迎的。

一般反馈:如果您对本书的任何方面有疑问,请通过 customercare@packtpub.com 给我们发邮件,并在邮件主题中提及书名。

勘误表:尽管我们已经尽最大努力确保内容的准确性,但错误仍然可能发生。如果您在这本书中发现了错误,我们将非常感激您能向我们报告。请访问www.packtpub.com/support/errata并填写表格。

盗版:如果您在互联网上以任何形式遇到我们作品的非法副本,我们将非常感激您能提供位置地址或网站名称。请通过 copyright@packtpub.com 与我们联系,并提供材料的链接。

如果您有兴趣成为作者:如果您在某个主题上具有专业知识,并且您有兴趣撰写或为本书做出贡献,请访问authors.packtpub.com

分享您的想法

一旦您阅读了《Google 机器学习和生成式 AI 解决方案架构师指南》,我们非常乐意听取您的想法!请点击此处直接访问此书的亚马逊评论页面并分享您的反馈。

您的评论对我们和科技社区非常重要,并将帮助我们确保我们提供高质量的内容。

下载此书的免费 PDF 副本

感谢您购买此书!

您喜欢在路上阅读,但无法携带您的印刷书籍到处走?

您的电子书购买是否与您选择的设备不兼容?

不用担心,现在,每购买一本 Packt 书籍,您都可以免费获得该书的 DRM 免费 PDF 版本。

在任何地方、任何地点、任何设备上阅读。直接从您最喜欢的技术书籍中搜索、复制和粘贴代码到您的应用程序中。

优惠远不止于此,您还可以获得独家折扣、时事通讯和每日免费内容的专属访问权限

按照以下简单步骤获取这些好处:

  1. 扫描下面的二维码或访问以下链接

packt.link/free-ebook/978-1-80324-527-0

  1. 提交您的购买证明

  2. 就这样!我们将直接将免费 PDF 和其他优惠发送到您的邮箱

第一部分:基础知识

本部分为本书其余部分奠定了基础。它涵盖了理解书中更复杂概念(以及实现后续工作负载)所需的所有基本主题。我们首先介绍一些人工智能/机器学习的基本概念,并讨论人工智能/机器学习在现实世界用例中的应用实例。最重要的是,我们讨论了公司在实施大规模人工智能/机器学习项目时经常遇到的常见挑战,并开始讨论如何解决这些挑战,为本书中更深入的讨论奠定基础。接下来,我们概述了典型人工智能/机器学习项目生命周期中的步骤,这些步骤将被用来形成本书大部分内容的整体结构。最后,我们通过介绍谷歌云和常见的 AI/ML 工具来结束本部分。

本部分包含以下章节:

  • *第一章**, 人工智能/机器学习概念、现实世界应用和挑战

  • *第二章**, 理解机器学习模型开发生命周期

  • 第三章**, 人工智能/机器学习工具和谷歌云人工智能/机器学习景观

第一章:人工智能/机器学习概念、实际应用和挑战

本章将介绍将在本书其余部分更详细探讨的基本概念。我们理解本书的读者可能处于他们人工智能/机器学习AI/ML)旅程的不同阶段,其中一些读者可能已经是熟悉运行 AI/ML 工作负载的高级从业者,而其他人可能对 AI/ML 总体上较为陌生。因此,我们将根据需要简要描述本书中的重要基本概念,以确保所有读者都有一个共同的起点,以便构建他们对所讨论主题的理解。对于 AI/ML 的新手来说,学习重要的基础概念比在没有基础背景的情况下直接深入每个主题更有益,而对于高级从业者来说,这些概念应该是有用的知识更新。

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

  • 术语——人工智能(AI)、机器学习(ML)、深度学习DL)和生成式人工智能GenAI

  • 人工智能/机器学习(AI/ML)简史

  • 机器学习方法与用例

  • 对机器学习基本概念的简要讨论

  • 开发机器学习应用中的常见挑战

在本章结束时,您将了解常见的 AI/ML 方法及其实际应用,以及 AI/ML 概念发展的一些历史背景。最后,您将了解公司在开始实施 AI/ML 工作负载时可能遇到的一些常见挑战和陷阱。这部分在本书中尤为重要,特别是对于解决方案架构师角色,它提供了在学术课程中找不到的实战见解;这些见解来自在多个公司进行大规模 AI/ML 项目多年的经验。

术语——AI、ML、DL 和 GenAI

在这里,我们描述了术语AIML之间的关系。需要注意的是,这些术语通常可以互换使用,以及缩写术语AI/ML,它作为一个总括术语,用于包含人工智能和机器学习。我们还描述了术语DLGenAI如何在 AI/ML 的范畴下定位。

我们将首先简要介绍官方认可的AIML的定义。我们选择包含来自柯林斯英语词典的定义,其中 AI 被定义为“一种关注使机器以类似人类大脑工作方式工作的计算机技术”,而 ML 被定义为“人工智能的一个分支,其中计算机根据输入的原始数据生成规则。”术语DL尚未被正式列为词典术语,但柯林斯英语词典将其列为新词建议,建议定义为“一种关注人工神经网络的高级模式识别的机器学习类型。”我们理解官方词典定义并不总是完全解释概念,但包含它们作为参考是很重要的,随着我们继续阅读本书,我们将更详细地介绍这些概念。所有这些术语构成了我们现在开始称之为“传统 AI”的内容,以区别于 GenAI,后者是一个更新且截然不同的概念。本书将有一个专门章节介绍 GenAI,因此这种区别将变得更加清晰。

一般而言,DL 被视为 ML 的一个子领域,ML 被视为 AI 的一个子领域。GenAI 可以被视为 DL 中的一个子领域,因为它在其应用中使用了深度神经网络和自然语言处理的概念。你经常在文献中看到它们以同心圆的形式图形化表示,其中 AI 是最广泛的领域,ML 作为 AI 中的一个子领域嵌套,DL 作为 ML 中的一个子领域嵌套。我在这个概念表示中增加了 GenAI 在 DL 领域的位置,尽管这更多是一种关联而非严格的子类别:

图 1.1:描述 AI、ML、DL 和 GenAI 之间的关系

图 1.1:描述 AI、ML、DL 和 GenAI 之间的关系

现在我们已经介绍了一些关于 AI/ML 的基本术语,让我们简要地讨论一下其历史,并了解 AI/ML 行业至今的发展情况。

AI/ML 的简要历史

如果我们只回到几年前——回到 2015 年——并将当时的人工智能/机器学习行业的状况与今天相比,我们会发现当时相对很少有公司已经商业化了大规模的人工智能/机器学习用例。尽管我们会发现在这个领域进行的学术研究,但我们不会经常在主流媒体中听到关于人工智能/机器学习的讨论,而成功的商业或工业应用主要只由世界上一些最大的、行业领先的技术或细分市场公司实现。再向前推进两年,我们发现到 2017 年底,科技行业正充斥着关于人工智能/机器学习的讨论,这似乎是每个人心中——至少是主要话题之一。

基于我们的时间旅行冒险,人们可能会认为人工智能/机器学习是一个全新的术语,仅在过去的几年中突然出现。然而,实际上,这些概念已经发展了几十年。作为我们时间旅行之旅的下一步,我们进一步回到 20 世纪 50 年代。1955 年,约翰·麦卡锡教授首次使用“人工智能”这个术语(麦卡锡等,1955 年),在 20 世纪 50 年代还发生了一系列对这一科学领域有重大贡献的重要发展,例如艾伦·图灵 1950 年的论文《计算机与智能》,在其中他提出了问题,“机器能思考吗?”(图灵,1950),以及弗兰克·罗森布拉特对“感知器”的研究(罗森布拉特,1957),我们将在本书的后续部分更详细地探讨这一点。

作为我们时间旅行旅程的延伸,应该注意的是,今天的人工智能/机器学习算法使用的是几个世纪或几千年前最初发现和制定的数学概念。例如,本书中将要探讨的许多算法都使用了线性代数和微积分的概念,这些概念已经使用了几个世纪,当我们学习关于成本函数、训练和评估时,我们将使用欧几里得几何的概念,例如勾股定理,其历史可以追溯到几千年以前。有趣的是,尽管人们认为毕达哥拉斯生活在约 2500 年前,但有一些证据表明,在毕达哥拉斯出生前 1000 多年,美索不达米亚的巴比伦人等之前的文明已经理解和使用了“勾股定理”的概念(Götze,1945,37-38)。多么令人着迷啊,我们今天一些最前沿的深度学习算法使用了与青铜时代古老文明相同的数学结构!在 20 世纪 60 年代和 70 年代,使用计算机对数据进行统计分析建模的做法开始显著增长,并出现了专门用于这些目的的软件,如统计分析系统SAS)和社会科学统计软件包SPSS)。这些工具通常用于内存内处理,这意味着使用这些工具的所有数据都将加载到单个计算机的内存中。在下一节中,你将看到为什么这一点很重要。

接下来,我们穿越到现代,心中浮现的一个问题是这样的:如果这一切始于 20 世纪 50 年代,为什么感觉上人工智能和机器学习是最近几年突然让每个人都热情高涨的概念?为什么在此之前我们没有看到人工智能/机器学习实施如此广泛的应用和成功?许多因素导致了这些概念最初开始研究时和它们在过去几年中在行业中开始获得公众明显关注之间的时间差距(例如,参见“人工智能寒冬”)。正如我们在本书的后续章节中将会看到的,其中一个因素是 AI/ML 用例通常需要大量的数据和广泛的计算资源。这也是为什么——直到最近——AI/ML 研究通常只由能够负担得起积累这些所需资源的实体进行,例如大型科技公司、成熟的科研机构和政府部门。

近年来,是什么改变了,帮助 AI/ML 突破大型企业和研究机构的专属领域?小型公司,甚至业余爱好者,是如何突然获得训练、托管和评估 ML 模型以及实验如何将 AI/ML 应用于日益增多的有趣新用例所需资源的?这一突然革命的主要贡献者之一是“云计算”,以及构建和运行 AI/ML 工作负载的迭代工具开发,以及深度学习方法的进步。

AI/ML 和云计算

为了更详细地了解云计算是如何突然革命化 AI/ML 研究和实际应用的,让我们考虑训练、托管、评估和管理 ML 模型所需的资源类型。虽然我们可以使用笔记本电脑或家用电脑在小型数据集上训练和评估一个相对简单的模型,但当我们想要扩展我们的研究和用例时,我们会很快发现我们个人电脑上的计算资源不足以训练更大的模型,而我们个人电脑的硬盘空间也不足以存储所需的数据集。这些也是我们在上一节中提到的统计建模工具(如 SAS 和 SPSS)所遇到的限制,这些工具在单台机器上“内存中”处理数据。

为了说明这个概念,我们将分步骤扩大我们的用例。如果我们仅仅稍微超出市场上最强大的个人电脑的资源,我们就需要在硬件“服务器”上运行我们的工作负载,这个服务器包含更强大的计算资源,并且我们可以将多个大容量硬盘连接到这个服务器上,可能是一个独立磁盘冗余阵列RAID)数组(以前称为廉价磁盘冗余阵列)。这仍然是一个个人可以在家中完成的事情,但强大的服务器——尤其是市场上“最新和最优秀”的服务器——购买起来可能相当昂贵,并且设置服务器和配置 RAID 数组需要更多的技术知识。在这个阶段,我们已经开始超出除了最热衷的业余爱好者之外的所有领域。

超出市场上最强大的硬件服务器的资源范围,将需要我们创建一个服务器集群。除了购买多个服务器及其连接的硬盘的额外费用外,这还需要更多的技术知识来构建和配置一个将服务器适当连接在一起的网络。这对大多数业余爱好者来说可能不是一个经济可行的方案,但对于小型公司来说可能仍然是有意义的。

接下来,让我们将范围扩展到今天一些最先进的深度学习(DL)用例,这些用例的训练可能需要数周或数月,并且需要在数百台高性能且非常昂贵的服务器上进行。如果我们想完全自行运行这些类型的工作负载,我们需要建立一个数据中心,雇佣专家团队来安装数百台服务器,构建和配置一个复杂的网络来将它们适当连接在一起,并执行多项其他支持活动以设置我们的基础设施。让我们暂时想象一下,我们想要创建一家初创公司,该公司将使用深度学习(DL)来实现我们设计的新突破性想法。仅仅建立一个数据中心就可能需要几年时间,并且可能花费数百万美元,在我们能够开始实验我们的想法之前。这显然不是一个可行的选择。

然而,借助云计算,我们只需简单地编写一个脚本或在云计算提供商的网站上点击一些链接和按钮,就可以在几分钟内启动我们需要的所有服务器。然后我们可以进行实验——迭代训练和评估我们的模型——并在我们的工作完成后简单地关闭服务器。正如您所想象的那样,这比试图建立和管理我们自己的数据中心要容易、便宜得多,并且更容易实现。现在,这为小型公司和资金有限的研究人员或爱好者提供了访问计算能力和资源的途径,这些资源以前仅限于非常大型组织。

注意,不仅更容易创建和访问所需的硬件基础设施帮助革命化了人工智能/机器学习(AI/ML)行业,相关的软件工具和框架也在随着时间的推移而发展,以及可用数据的数量。虽然 20 世纪 60 年代和 70 年代开发的 SAS 和 SPSS 等工具足以在单个机器的内存中执行数据集的统计建模,但互联网的快速普及导致公司可以收集和产生的数据量急剧增加。与此并行,开发了 Python 等语言的库,这使得数据处理、分析和建模等活动变得更加容易。我可以自信地说,使用 scikit-learn、PyTorch 和 Keras 等库进行许多类型的建模用例,比使用上面提到的早期工具要容易得多。尽管如此,许多今天的机器学习算法可以被视为传统统计建模技术的演变,这些技术得到了增强,以处理更大和更复杂的用例。此外,Apache Hadoop 和 Apache Spark 等工具(我将在本书的后面部分更详细地讨论),使得实现可以跨越单机限制的用例成为可能,因此可以处理更大的数据集。

到目前为止,在我们的扩展用例讨论中,我们主要关注的是模型训练和评估,但这些活动只是创建实际用于现实世界的机器学习应用程序所需活动的一个子集。在本书中,我们将经常使用“在生产中”这个术语来指代创建、托管和提供在现实世界(实验室测试环境之外)使用的 AI/ML 应用程序的概念。

即使是大型、成熟的组织,拥有经验丰富的数据科学家团队,也常常发现成功托管生产中的机器学习应用程序可能比模型训练和评估过程更复杂、更具挑战性。现在,让我们看看云计算如何能够提供额外的价值,以解决这些挑战,而不仅仅是启动所需的计算和存储资源。在本书的后续章节中,我们将详细讨论典型机器学习项目中的所有步骤,但在此,让我们从高层次上考虑,如果不存在云计算,托管生产中的机器学习模型需要哪些资源和基础设施。

除了模型训练和评估所需的各项活动,例如构建数据中心、安装服务器、构建和配置复杂网络以及随着时间的推移维护所有硬件之外,我们还需要执行许多其他活动,以实际托管和为生产使用提供机器学习模型。例如,我们需要创建一个接口,以便将我们的模型暴露给最终用户或其他系统。最可能的方法是使用基于网络的界面,在这种情况下,我们需要构建一个由多个网络服务器组成的集群,并持续配置和管理这些服务器。我们需要在这些网络服务器上开发和构建一个应用程序,以便将我们的模型暴露给网络客户端,然后安装和配置负载均衡器,并在我们的网络服务器之间分配负载。当然,所有这些基础设施都需要得到适当的保护。图 1.2展示了你可能需要设置的此类基础设施的示例;请记住,你可能需要为你的解决方案中的每一层复制该基础设施——例如,你可能需要多次复制该基础设施以用于你的网络服务器层、应用程序服务器层和模型托管层。图中显示了两个负载均衡器和路由器,以实现冗余,以防其中任何一个组件出现故障:

图 1.2:模型托管示例基础设施

图 1.2:模型托管示例基础设施

不幸的是,大多数数据科学家并不是同时还是网络专家、网络服务器配置专家和安全专家,所以即使我们有一支由最佳数据科学家组成的团队,他们已经创建了一个突破性的模型,我们仍然需要许多其他专门专家团队来构建和维护将这个模型向客户展示所需的基础设施。另一方面,如果我们想使用像谷歌云上的 Vertex AI 这样的服务,它将自动为我们构建和管理所有这些基础设施,我们可以在几分钟内从实验室测试过渡到生产托管。

需要注意的是,如果没有云计算,公司不仅会发现构建他们的 AI/ML 工作负载不太方便,而且这也会变得难以承受——也就是说,除非大公司事先确信他们的应用程序将会成功,否则他们不会投资建设所需的基础设施,而这是非常难以预测的。较小的公司如果没有在基础设施费用上进行重大前期投资,就无法开始,而大多数公司都无法获得这些资金。因此,没有云计算,人工智能/机器学习的研究、实验以及在现实世界中的最终实施将会远不如现在普遍和可行。

当谈到在现实世界中实施人工智能/机器学习时,让我们来看看不同的人工智能/机器学习方法和它们的一些实际应用案例。

机器学习方法和应用案例

人工智能/机器学习应用程序通常旨在根据输入数据做出某种预测,也许除了生成式人工智能之外,因为生成式人工智能旨在生成内容,而不仅仅是做出预测。为了做出预测,机器学习模型首先需要被训练,而它们的训练方式取决于所采用的方法。虽然机器学习是一个广泛的概念,涵盖了众多不同的研究领域,并且几乎每天都有无数新的应用案例被创造出来,但该行业通常将机器学习方法分为三个高级类别:

  • 监督学习SL

  • 无监督学习UL

  • 强化学习RL

监督学习SL

监督学习是工业界最常用的机器学习类型,也许也是最容易描述的。术语“监督”表明我们在训练过程中向机器学习模型告知正确答案。例如,让我们想象我们想要训练一个模型能够识别猫的照片。在这种情况下,我们会使用数千或数百万张照片作为我们的训练集,并告诉模型哪些照片包含猫,哪些不包含。我们通过一个称为标记的过程来完成这项工作,我们将在后面的章节中更详细地描述它。如果训练得当,我们的模型将学会如何区分每张照片中识别猫的特征。如果我们向模型展示它以前从未见过的照片(即,那些没有包含在训练集中的照片),我们的模型将能够识别这些照片是否包含猫。更具体地说,对于每张照片,我们的模型将能够根据照片中的观察特征预测它包含猫的概率。

监督学习(SL)有两个子类别:分类和回归。

分类

我们之前描述的猫识别模型是一个分类用例的例子,其中我们的模型可以判断我们的照片是否包含猫。分类进一步细分为二分类或多分类。二分类提供“是”或“否”的预测。例如,在这种情况下,我们会问模型,“这张照片包含猫吗?”,而模型会回答“是”或“否”。如果我们训练我们的模型来识别许多不同类型的对象,那么它将能够执行多分类,我们可以提出更广泛的问题,例如,“你在这张照片中看到了什么?”在这种情况下,模型可以回答多个不同的对象分类,包括“猫”(如果它在照片中看到了猫),以及其他它预测存在于照片中的对象(参见图 1**.3):

图 1.3:照片中猫和花的分类

图 1.3:照片中猫和花的分类

分类在实际中的应用

当然,分类可以用于比识别猫的图片更为重要的用例。一个重要的实际分类用例是医疗诊断,其中机器学习模型可以根据输入数据(如身体症状或放射学图像)预测患者是否存在某种医疗状况。

回归

当我们的问题有离散答案时,分类是有用的,而当我们要处理“连续变量”时,则使用回归。在这种情况下,我们问题的答案可以是连续体中的任何值,例如 0.1、2.3、9894.6、105 或 0.00000487。为了引入一些术语,我们提供给模型的输入被称为“输入变量”,而我们希望预测的变量被称为“目标变量”或“因变量”。

注意

当我们在这里使用术语 回归 时,我们指的是线性回归。这不要与逻辑回归混淆,逻辑回归实际上是一种分类,我们将在本书的后面部分介绍。

线性回归的目标是定义一个线性函数,将输入变量映射到输出目标变量。例如,我们可能想根据学生花费的学习时间预测他们在考试中能获得的分数,基于我们有关以前学生成绩和学习时间的数据。我们可以将数据绘制如下(参见 图 1**.4),其中星号代表数据集中的每个学生;也就是说,它们代表每个学生的成绩和他们花费的学习时间:

图 1.4:学生成绩与学习时间

图 1.4:学生成绩与学习时间

如图中所示,成绩与学习时间之间似乎存在某种关系或相关性;也就是说,学习时间较长的学生通常能获得更高的成绩。

在这个数据集上训练的线性回归模型将试图找到最能代表这种关系的函数或直线。你可能还记得,从学校里学到的简单直线函数通常表示为公式 y = ax + b,其中 ax 的倍数,而 b 是直线与 y 轴的交点。为了找到最准确的功能,线性回归过程试图定义一条线,该线与每个数据点(星号)之间的距离最小化,这可能看起来像 图 1**.5。线与一些数据点之间的距离用红色表示以供参考。在后面的章节中,我们将更详细地讨论这些距离是如何计算的:

图 1.5:线性回归函数

图 1.5:线性回归函数

使用这个函数,我们现在可以根据学生花费的学习时间来估计或预测未来的学生成绩。例如,如果一个学生花费了 10 个小时学习,根据我们在 图 1**.6 中看到的情况,我们会预测他们能获得大约 70%的成绩:

图 1.6:应用线性回归函数

图 1.6:应用线性回归函数

线性回归的实际应用

回归是机器学习中最广泛使用的一种类型,它适用于许多不同的商业用例。它是“预测未来”的典范,通常归功于机器学习的力量。商业领导者通常希望预测与业务绩效相关的数字,例如根据历史销售和其他市场数据预测下一季度的销售额。每当你有可以追踪的数值指标,并且有足够的历史特征与这些指标相关联时,你就可以尝试预测或“预测”这些指标的未来的值,从股市价格和房价到各种医疗场景中的血压测量。

UL

在使用 UL 时,我们不是在标注了正确答案的数据集上训练模型。相反,我们要求模型在数据中寻找未知或非预定的模式。我们可以用这样一个类比来说明:在 SL 中,我们是在教模型关于数据中存在什么,而在 UL 中,模型是在教我们关于数据中存在什么,比如数据集中各种数据点之间的潜在趋势。

最常见的 UL 类型是所谓的“聚类”,其中数据点根据模型观察到的某些相似性被分组在一起。图 1.7提供了这个概念的可视化表示,显示了左侧的输入数据和右侧的结果数据簇:

图 1.7:簇类

图 1.7:簇类

UL 的现实世界应用

簇类算法在现实世界中的应用实例之一就是将具有相似购买偏好的客户群体进行分类。你可能已经注意到,当你在线购买商品时,会看到一些推荐其他可能感兴趣的商品,并伴随有诸如“购买此商品的用户也购买了这些其他商品”之类的信息。

另一个重要的现实世界用例是欺诈检测,在这种情况下,一个簇可能代表合法交易,另一个簇可能代表异常或潜在的欺诈交易,或者任何不符合合法交易特征的东西都可能被标记为潜在的欺诈。随着新交易的进行,模型可以根据它们的输入特征相应地将它们分组,如果交易看起来是欺诈性的,则可能触发警告响应。你有没有在假期第一天在新地点使用信用卡时收到过银行的通知或询问?这是因为银行的机器学习模型确定交易的某些特征异常;在这种情况下,是来自你通常不使用信用卡的地方的交易。

注意

簇类实际上可以被视为一种无监督分类。

RL

在强化学习中,训练模型的机制与之前两种方法截然不同。为了介绍一些术语,我们说模型使用一个代理,该代理有一个它想要实现的整体目标(即期望的模型输出)。代理通过向环境发送动作与它的环境进行交互。环境评估这些动作,并以奖励信号的形式提供反馈,该信号指示动作是否有助于实现整体目标,以及观察,它描述了环境的当前状态。参见 图 1.8 对此过程的视觉表示。做一个非常广泛的类比,这类似于我们训练某些动物,例如狗。例如,如果狗执行了一个期望的动作,那么训练者会奖励它美味的食物。相反,如果狗做了某些不期望的事情,训练者可能会以某种方式责备它。在强化学习的情况下,模型在其环境中随机尝试不同的动作。如果一个动作或一系列动作被认为有助于实现整体目标,那么环境会向代理提供积极的奖励作为反馈,而如果动作被认为对实现整体目标有害,那么环境会向代理提供消极的奖励作为反馈。在这种情况下,奖励通常只是一个数值,例如 0.5 或 -0.2,而不是美味的食物,因为不幸的是,对于机器学习模型来说,它们还不够复杂,无法享受美味的食物:

图 1.8:强化学习

图 1.8:强化学习

模型的环境是存在目标和所有可能动作的空间,观察是环境的特征。这可以是一个物理环境,例如当机器人在一个物理空间中移动时,或者基于模型试图解决的问题的某种抽象。例如,你可以创建一个模型,使其成为国际象棋或电子游戏等游戏的专家。模型将首先尝试所有种类的随机动作,其中大多数一开始可能看起来很愚蠢或奇怪,但基于环境的反馈,模型的动作将逐渐变得更加相关,并可能最终在该任务中超越人类专家的动作。

强化学习实际上可以被认为是一种监督学习(SL),因为当模型做出预测时,会提供反馈给模型,模型根据这些反馈进行学习和改进。然而,它与之前描述的标准监督学习概念不同,因为我们没有在训练过程中提供标记的正确答案。相反,模型被提供了一些信号,帮助它理解它应该执行哪些类型的动作,以便朝着实现所需的目标前进。

强化学习的实际应用

强化学习(RL)在工业界的应用还没有像“传统”的监督学习(SL)和无监督学习(UL)那样广泛,但一些有趣的应用正在出现。除了前一段提到的游戏用例之外,强化学习最显著的应用之一是在机器人导航和自动驾驶汽车中。在这个应用中,汽车可以被看作是模型代理,它执行诸如加速、制动和转向车轮等动作。汽车上的传感器,如摄像头和激光雷达传感器,提供关于环境状态的信息。如果汽车执行的动作帮助它实现目标,例如导航路线或自动泊车而不撞到任何障碍物,那么它会收到正面的奖励;而如果它撞到障碍物,则会收到负面的奖励。随着时间的推移,它可能学会导航路线或自动泊车并避开障碍物。

强化学习在医疗保健领域的另一个重要实际应用是,它在医疗影像诊断(周等,2021,1-39)以及根据患者状况确定哪些类型的医疗治疗对他们有效等方面显示出有希望的结果,这些是通过诸如动态治疗方案(DTRs)等机制实现的。

现在我们已经讨论了不同类型的机器学习方法和它们的实际应用案例,让我们来看看构成这些机器学习实现基础的一些基本概念。

机器学习基本概念的简要讨论

数学是机器学习(ML)背后的隐藏魔法,几乎所有机器学习算法都是通过使用数学来在数据中找到关系和模式来工作的。本书侧重于在谷歌云上实现人工智能/机器学习的实际应用;它不是理论学术课程,因此我们不会深入探讨机器学习模型所依赖的数学方程式,但我们会根据需要包含数学公式作为参考,并在本书中介绍一些在人工智能/机器学习算法中广泛使用的基本概念。关于这些概念的详细学习,有大量的学术材料可供参考。作为一个架构师,理解数学概念可以被视为课外学分而不是必需品;你通常不需要深入研究机器学习算法的数学细节来完成日常工作,但如果你想更好地理解某些算法的工作原理,你可以更详细地审查这些概念。

线性代数

在机器学习(ML)中,我们经常使用向量和矩阵来存储和表示信息。为了简要介绍一些定义,柯林斯词典将向量定义为“具有大小和方向的变量量,例如力”,将矩阵定义为“一种用于解决数学问题的数字、符号或字母的行列排列”。让我们看看这究竟意味着什么。如果我们使用表格数据作为例子,矩阵中信息的表示就最容易演示了。考虑表 1.1中的信息,它代表了华盛顿州金县的销售房屋(摘自 Kaggle 数据集:www.kaggle.com/datasets/harlfoxem/housesalesprediction):

表 1.1:金县房屋销售

表 1.1:金县房屋销售

表 1.1中所示的数据集有 7 行(不包括标题行)和 13 列,其中每一行代表一个单独的房屋销售,我们将其视为数据集中的数据点或观察值,每一列代表数据点的单个特征。我们可以将每一行和每一列视为向量。请注意,向量也可以被视为只有一行或一列的矩阵(即一维向量)。因此,对于数据集中每个单独的房屋购买,我们都有一个包含该房屋所有特征的向量。让我们想象一下,如果我们想根据每栋房屋的特征(除了价格)来预测房价。我们希望找到描述价格与其他所有特征之间关系的最佳函数,线性回归就是实现这一目标的一种方法。在这种情况下,我们希望找到一组值,通过这些值乘以每个特征,然后将所有乘法的结果相加,以正确估计每栋房屋的价格。这意味着每个特征都有一个相应的乘数(或“系数”)。为了有效地计算特征和系数的乘积并将所有结果相加,我们可以将所有系数也表示为一个向量,并计算特征向量和系数向量的点积。我们在这里花一点时间来澄清计算点积的含义。如果我们有两个向量AB,其中A = [a b c]B* = [d e f]*,点积的计算如下:

ad + be + cf*

为了说明,让我们以表 1.1的第一行(不包括价格)作为特征向量;它看起来是这样的:

[3 1 1180 5650 1 0 0 3 7 1955 0]

现在,让我们创建一个初始的随机系数向量(我们最初可以创建随机系数,然后在模型训练过程中改进我们的猜测),它需要与前面的特征向量具有相同数量的元素:

[1 5 0.3 0.001 2 7 2.5 108.67 14.234 0.103 8]

注意

在计算点积时,有一些关于每个向量形状的规则,但为了简单起见,我们在这里省略了这些细节。我们将在后面的章节中深入探讨这些细节。

我们的特征向量和系数向量的点积在此处显示:

3*1 + 1*5 + 1180*0.3 + 5650*0.001 + 1*2 + 0*7 + 0*2.5 + 3*108.67 + 7*14.234 + 1955*0.103 + 0*8 = 996.663

从我们对系数应该是什么的第一个猜测开始,我们估计表 1.1中第 1 行的房价将是$996.663。然而,我们可以从表 1.1中看到,那所房子的实际价格是$221,900。现在我们可以计算由于我们的猜测而产生的误差,如下所示:

221900 – 996.663 = 220903

我们通常将这称为线性函数的损失成本,它类似于之前图 1.5中用红色线条表示的内容,其中这个值代表“距离”正确答案;也就是说,我们的猜测与正确答案有多远。这是学习过程的第一步,在后面的章节中,我们将希望找到使这个误差最小化的系数。

微积分

微积分在机器学习中的一个常见用途是之前提到的误差最小化过程。在后面的章节中,我们将定义一个称为损失函数(或成本函数)的概念,我们将使用“梯度下降”(稍后描述)等机制来最小化该损失函数。在这种情况下,我们将使用微积分推导出表示损失函数的曲线上的各个点的斜率,并利用这些信息来努力最小化成本函数(参见图 1.9):

图 1.9:函数曲线上某点的斜率(来源:https://commons.wikimedia.org/wiki/File:Parabola_tangent.png)

图 1.9:函数曲线上某点的斜率(来源:https://commons.wikimedia.org/wiki/File:Parabola_tangent.png)

统计与概率

机器学习模型不提供确定的答案。相反,机器学习模型的结果通常以近似值、概率或推断的形式提供。我们通常将机器学习模型调用的结果称为 推断。以本章前面提到的猫分类模型为例,我们用来识别照片中猫的模型通常会告诉我们照片中存在猫的概率。例如,模型可能会告诉我们它有 97.3% 的把握认为照片中有一只猫。机器学习的主要目标之一是确保这些概率尽可能准确。如果模型说它有 100% 的把握看到猫,但实际上照片中没有猫,那么这个模型将不会有效。在二元分类的情况下,响应要么为真要么为假,通常会有一个阈值,高于该阈值我们认为概率响应为真,低于该阈值我们认为为假。例如,我们可以确定任何超过 72.3% 概率的都被认为是正面的,而低于该阈值的被认为是负面的。阈值值会根据用例而变化,并且在构建此类模型时需要确定的一个参数。

如果我们将这个过程进一步分解,以猫分类模型为例,它已经观察到了照片中的某些特征,并且基于之前训练中它看到的那些类型的特征(或与那些特征相似的特征),它估计照片中存在猫的概率。

在本书的后续内容中,我们还将看到,统计分析在机器学习项目的早期阶段起着重要作用,当时数据科学家正在探索如何使用数据集来解决业务问题。在这些数据探索活动中,数据科学家通常会分析数据集中每个变量或特征的值统计分布。例如,在探索数据集时,数据科学家通常会想查看有关数据中每个数值变量的统计信息,例如均值、中位数、众数以及值的最大和最小范围;参见 图 1**.10,其中展示了我们的房屋销售数据集中一些特征的统计分布:

图 1.10:数据集特征的统计分布

图 1.10:数据集特征的统计分布

指标

注意

在这里,我们还引入了术语 数据科学。虽然数据科学是一个广泛的科学领域,但为了本书的目的,我们使用术语 数据科学 来涵盖创建机器学习模型所需的所有步骤,包括所有数据准备和处理步骤。

数据科学和机器学习是我们在模型准确性、训练和执行速度,以及计算能力使用上不断追求改进的领域。有一句众所周知的话,“未衡量的无法改进”(这实际上是彼得·德鲁克和开尔文勋爵不同观察的近似),这句话蕴含着很多真理;为了有系统地改进某事物,你需要能够衡量该事物的某些属性。因此,度量标准是任何机器学习项目的必要组成部分,选择正确的度量标准进行监控可以对机器学习实施的成败产生重大影响。

除了操作指标,例如测量你的机器学习模型响应的延迟,还有各种用于衡量机器学习模型推断准确性的指标。

例如,在线性回归中,通常测量平均绝对误差MAE)、均方误差MSE)或均方根误差RMSE),而对于分类用例,我们通常使用准确率和精确度等指标。我们将在后面的章节中探讨所有这些指标以及许多其他指标。

在讨论了机器学习中使用的某些基本理论和数学概念之后,让我们再次将讨论带回现实世界,并看看公司在尝试实施机器学习工作负载时存在哪些挑战。

开发机器学习应用中的常见挑战

当公司开始 AI/ML 开发之旅时,通常会遇到常见的挑战类型,而理解特定问题空间中的常见挑战通常是架构师角色的关键要求。作为一名架构师,如果你不了解挑战以及如何解决它们,那么你不太可能设计出合适的解决方案。在本节中,我们将从高层次介绍最常遇到的一些挑战和陷阱,并在本书的后续章节中讨论解决或减轻这些 AI/ML 发展障碍的方法。

收集、处理和标注数据

数据是机器学习的关键成分,因为通常情况下,机器学习模型没有数据就无法运行。有一个经常引用的谚语说,数据科学家在开始使用数据进行分析或数据科学目的之前,可能要花费高达 80%的时间来寻找、清理和处理数据。这是一个重要的概念,也就是说,数据科学家不仅要找到相关的数据,尽管这本身就是一个困难的任务;他们还需要将数据转换成可以被机器学习算法高效使用的状态。数据在原始格式下可能对许多类型的机器学习模型来说无法使用,数据科学家可能还需要将来自许多不同来源的数据结合起来,每个来源都有不同的格式和不同的问题需要解决,才能使原始数据被机器学习模型使用。此外,可用的数据可能不足以做出我们希望从机器学习模型中获得的那种预测,数据科学家通常需要通过巧妙地使用现有数据源中的数据来发明生成新数据的方法。我们将在本书后面讨论一个称为“特征工程”的实践时更详细地介绍这一点。

数据质量对模型性能的影响

数据科学家在执行上述任务时的有效性可以对最终生成的机器学习模型的表现产生极大的影响,因为输入到机器学习模型中的数据通常会对模型的输出准确性产生直接影响。请记住,对于某些商业应用来说,机器学习模型准确性的微小差异可能会导致企业主收入差异数百万美元。另一个很好地描述这一过程的常见表达是“垃圾输入,垃圾输出”。这个概念相当简单;如果你输入到模型中的数据不能准确代表你试图预测的内容,那么模型将无法做出准确的预测。

不仅模型的输出会受到数据质量或内容的影响。大型机器学习模型训练起来可能既昂贵又耗时,而准备不足的数据可能会增加模型训练所需的时间和费用。作为一个架构师或数据科学家,这些因素在我们设计工作负载时起着根本的作用,因为架构师的目的不仅仅是设计解决技术挑战的方案,而且通常实施解决方案的成本同样甚至可能更为重要。如果我们设计了一个实施起来过于昂贵的解决方案,那么项目可能无法获得继续进行的批准,或者公司可能会因为实施该解决方案而亏损。

偏差与公平性

在本书中我们将更详细地探讨的另一个重要概念是偏差和公平性的概念。在这方面,我们的目标和挑战是确保我们用于训练和评估机器学习模型的训练数据代表了所有相关类别的公平分布。例如,如果我们的模型将做出影响人们生活的预测,例如批准贷款或信用卡申请,我们需要确保用于训练模型的训练数据公平地代表了所有相关的社会群体,并且不会无意中偏向任何特定的社会群体。

数据标注

除了之前描述的挑战之外,对于监督机器学习SML)应用还存在另一个具体的重大挑战。正如我们在本章前面讨论的那样,SML 模型从数据中的标签中学习,这些标签为每个数据条目提供了“正确”的答案。参见图 1.11的示例,其中数据集包含描述学生是否通过考试的标签,以及有关这些考试的其它细节,例如获得的分数和花费的学习时间。然而,通常,这些数据集和相关标签需要以某种方式生成或创建,考虑到某些数据集可能包含数百万个数据点,准确标注所有数据可能很困难、耗时且容易出错:

图 1.11:数据集中标签(绿色突出显示)的示例

图 1.11:数据集中标签(绿色突出显示)的示例

数据治理和合规性

控制数据在公司内部存储和处理的方式以及谁有权访问数据非常重要。在敏感数据方面必须格外小心——例如,包含客户个人详细信息的数据,如他们的地址、出生日期或信用卡号码。在这方面有一些具体的法规需要遵守,例如加利福尼亚消费者隐私法案CCPA)、儿童在线隐私保护法案COPPA)、通用数据保护条例GDPR)和健康保险可携带性和问责法案HIPAA),这些法规详细说明了特定类型的数据必须如何处理。对于在国际上运营的公司来说,遵守不同国家的所有不同法规可能相当复杂。当数据科学家收集、存储、探索、处理和标记数据时,他们需要牢记这些安全要求,并且作为人工智能/机器学习解决方案架构师,你需要确保数据存储和处理基础设施能够促进遵守这些法规和其他重要的信息安全实践。本书将涵盖 Google Cloud 的相关数据存储和处理基础设施选项,并在适当的地方提供关于数据治理概念的其他指导。

数据和模型血缘关系

数据科学包含“科学”这个词是有原因的。与大多数科学领域一样,它涉及迭代实验。当数据科学家创建新的模型时,他们通常需要经历一个复杂的过程,在这个过程中,他们需要尝试不同的数据集、数据集上的不同转换、不同的算法和参数,以及其他支持活动和资源。一个数据科学团队在创建所需的模型之前可能需要尝试数百种不同的步骤组合,并且每个步骤都有输入和输出。如果一个数据科学家有突破性的发现并创建了一个杀手级的新模型,然后他们离开公司或发生了一些事情,除非他们详细记录了创建该模型所采取的所有步骤,包括每个步骤使用和创建的所有输入和输出工件,否则我们无法重新创建他们的工作。

在实验过程中,这同样很重要,数据科学家可能希望与团队中的其他科学家或其他团队中的科学家合作。如果一个数据科学家从实验中获得了一些有希望的结果,他们可以与同事分享这些细节,同事可以验证这些结果或通过结合他们进行的其他实验的输出在它们之上构建。这种合作对于许多类型的科学研究是基本的,并且对于取得重大进展通常是必需的。

数据和模型血缘关系指的是跟踪创建模型所需的所有步骤及其相关的输入和输出这一过程。这不仅对协作和进步很重要,而且对治理目的和人工智能/机器学习发展的公平性也很重要;了解模型是如何创建的,以及沿途使用了哪些数据工件、算法和参数也很重要。

随着公司开始进行人工智能/机器学习研究,它们往往没有建立稳健的血缘跟踪机制,因此大规模的协作可能会受到影响。更糟糕的是,公司有时发现自己使用的是没有人真正了解其工作原理或创建方式的模型。如果你想要更新这些模型或需要审计以符合规定,这并不是一个好的位置。在本书的后面部分,我们将看到 Google Cloud 的 Vertex AI 平台如何帮助确保数据模型血缘关系得到适当的跟踪。

组织挑战

大多数大型公司随着时间的推移而发展,通常由多个相互松散连接的组织组成。当大型公司开始尝试人工智能/机器学习时,研究通常在每个组织内部自发进行,而公司不同部分之间没有协调。当这种情况发生时,知识和数据往往在公司内部没有得到充分共享——或者根本就没有共享——这导致每个组织内部形成孤岛,进而为公司的整体成功在人工智能/机器学习解决方案开发方面设置障碍。作为一名人工智能/机器学习解决方案架构师,你需要向公司领导建议如何构建他们的组织和公司政策,以使他们的人工智能/机器学习之旅尽可能成功。

让我们设想我们拥有一家大型公司,公司内部的一个组织——让我们称它为“组织 A”——在过去的一年里一直在收集、清洗和实验一个大型数据集,他们最终在训练一个提供有希望结果的机器学习模型上取得了一些成功。让我们再设想一下——类似于大多数公司——构成我们业务的其他组织主要相互独立运作,除非作为常规业务运营的一部分,否则它们之间很少有沟通。现在,我们公司中的另一个组织,名为“组织 B”,开始探索人工智能/机器学习,并且他们有与组织 A 相似的使用案例。由于组织独立运作并且不经常相互沟通,组织 B 将从头开始,将在接下来的一年里浪费时间做已经在公司其他地方完成的工作。

现在,让我们假设我们的公司由 20 个大型组织组成,每个组织都有数百个产品开发团队。考虑一下,如果其中只有 20%的产品开发团队在没有相互沟通的情况下开始创建 AI/ML 工作负载,将会浪费多少时间。这可能很难相信,但这就是大多数大型公司在开始尝试 AI/ML 时是如何运作的。

在之前描述的场景中,主要存在四种不同类型的孤岛,它们与以下四个主题相关:

  • 知识

  • 数据

  • AI/ML 模型

  • 工具和开发

知识孤岛

这一点相当直接:如果组织之间没有有效地共享知识,公司各个团队将浪费时间一次又一次地从头开始解决类似的问题。

数据孤岛

我们已经讨论了获取数据的重要性及其难度;特别是获取干净、处理过的数据,这些数据已准备好用于训练 ML 模型。在大多数公司中,每个组织(以及可能每个团队)都会构建自己的数据集。如果组织 B 中的团队想要获取由组织 A 构建的数据集,他们首先需要了解该数据集的存在(这需要一些知识共享的发生)。然后,他们需要请求访问数据,这通常需要通过上级管理层的数月升级才能获得所需的批准。接下来,需要执行一个多个月的项目,以便实际上在组织 A 和组织 B 的系统之间建立集成。在一个 AI/ML 用例和机会发展如此迅速的行业中,这些都是阻碍公司在这个领域快速创新的障碍和流程。图 1.12展示了公司中数据孤岛的例子。你将很快了解在组织之间有效和安全地共享数据集的方法,以打破数据孤岛:

图 1.12:数据孤岛的例子

图 1.12:数据孤岛的例子

模型孤岛

这是对知识和数据孤岛概念的扩展。正如知识和数据集一样,一旦开发出来,某些类型的模型就可以被重复使用。如果一个团队在组织 A 中创建了一个有用的模型,并且该模型可以被公司中的其他团队重复使用,那么我们应该确保这种共享不仅通过我们的企业结构、文化和政策,而且通过我们的 AI/ML 开发基础设施来实现。为了更详细地了解这一点,你将学习如何共享模型,这需要哪些类型的需求,以及我们的 AI/ML 开发工具和基础设施如何帮助或阻碍这一过程。

工具和开发孤岛

在大型公司中,不同的开发团队可能会使用不同的工具和方法来构建他们的 AI/ML 工作负载。这些工具和方法的选择通常基于一些任意因素,例如员工在之前公司使用过哪些工具。每个组织或团队中的员工都会在自己的机器上安装他们选择的工具,并以一种临时的方式开始开发。例如,B 组织中的员工 A 将安装并使用名为scikit-learn的工具进行开发,并使用 MySQL 数据库存储他们的应用程序数据,而 B 组织中的员工 B 将安装并使用 PyTorch 进行开发,并使用 Oracle 数据库存储他们的应用程序数据。接下来,如果员工 A 离开公司,新员工 C 将被雇佣,他们可能会更倾向于使用 TensorFlow 和某些其他类型的数据库。这种“野性西部”的方法使得员工和团队在公司范围内进行协作和共享工件变得非常困难。

在后面的章节中,我们将详细介绍如何防止、修复和设计这些陷阱,但到目前为止,强调标准化的重要性是至关重要的。随着公司开始构建他们的数据科学战略,他们应该尽可能地标准化。标准化用于 AI/ML 开发的工具集以及将使用的数据系统和格式类型。建立公司实践,鼓励知识共享,并以安全的方式简化团队和组织之间的数据和模型共享。没有这些策略,将难以快速进行大规模的协作和创新。一个注意事项是,您需要在标准化和灵活性之间找到平衡。缺乏标准化会导致之前提到的问题,但如果您的标准化策略过于僵化,可能会阻碍开发者的生产力。例如,强迫所有开发者只使用一种类型的数据库和一种特定的编程语言或框架将会过于僵化。不同的工具最适合不同的用例,您的公司应该为员工提供指南,说明哪些工具适用于哪些用例。

AI/ML 模型的实施和持续管理

到现在为止,希望已经很清楚,AI/ML 模型开发可能很复杂且具有挑战性。然而,即使你已经成功创建了一个能够做出有用预测的模型,你的工作仍未完成。公司往往发现,即使模型在实验室中表现良好,也很难将其带入现实世界。我们已经讨论了一些需要执行的基础设施和后勤活动,以便托管模型,但增加复杂性的是,大多数模型需要随着时间的推移而演变,因为它们运行的 环境几乎不可避免地会随着时间的推移而演变和变化。这与常规软件开发类似,我们需要更新我们的应用程序以提供新功能或对我们的客户如何使用我们的产品做出反应。

另一个重要因素是了解何时我们需要更新我们的模型。当我们的模型在现实世界中运行时,我们需要持续监控它们,以确定它们是否继续满足它们被创建来解决的业务需求。

在这本书中,你将了解监控和更新 AI/ML 模型的独特要求,以及传统的软件 DevOps 机制本身不足以满足这些目的,但我们如何在此基础上构建机制以适应 AI/ML 工作负载的需求。

边缘情况

在这里,“边缘情况”一词被用作双关语,具有双重含义。在传统的软件开发中,边缘情况是可能导致异常行为的异常或极端用例。然而,在这种情况下,我们还指的是边缘计算的概念,这是云计算的一个子领域,它专注于为具有低延迟要求的客户尽可能提供计算资源(见图 1.13)。我们将这些计算资源的位置称为“边缘位置”,因为它们存在于核心云计算基础设施位置之外,并且与核心云计算基础设施位置相比,它们通常资源有限。

ML 模型通常需要强大的计算资源才能运行,而这可能给边缘计算用例带来挑战,因为边缘位置的资源有限。

然而,一些 ML 模型需要在或接近“边缘”处运行。例如,考虑一辆自动驾驶汽车,它需要在其环境中执行操作以导航。在每个动作之前和之后,它需要咨询 ML 模型以确定下一步的最佳操作。在这种情况下,它不能使用托管在遥远数据中心中的模型,因为它不能等待 API 请求通过互联网到达云中的服务器,然后再等待服务器提供响应,然后它才能决定下一步做什么。相反,它需要在毫秒内做出决定并对环境做出反应。这是一个边缘计算的明确用例。

在后续章节中,我们将探讨这些场景的一些需求和解决方案以及如何应对人工智能/机器学习工作负载:

图 1.13:边缘计算

图 1.13:边缘计算

摘要

在本章中,我们介绍了与人工智能/机器学习相关的基本术语以及人工智能/机器学习随时间发展的一些背景信息。我们还探讨了目前存在的不同人工智能/机器学习方法和它们在现实世界中的应用。最后,也许是最重要的,我们总结了公司在开始实施人工智能/机器学习工作负载时通常会遇到的常见挑战和陷阱。

在接下来的章节中,我们将更深入地探讨模型开发过程。

第二章:理解机器学习模型开发生命周期

在本章中,我们将探讨典型 AI/ML 项目中存在的不同步骤。这些信息是 AI/ML 解决方案架构师角色的重要基础,因为您需要向公司建议如何高效地实施这些步骤。它也是本书其余内容的基础,因为在后面的章节中,您将创建自己的机器学习项目,了解过程中的步骤非常重要。我们还将探讨本书中的 MLOps 概念以及 ML 模型开发生命周期如何作为 MLOps 范式的基石。

本章涵盖了以下主题:

  • 机器学习模型开发生命周期概述

  • 机器学习模型开发生命周期中遇到的常见挑战

  • 克服常见挑战的最佳实践

机器学习模型开发生命周期概述

您可能熟悉软件开发生命周期SDLC)的概念,这是在世界各地的计算机科学课程中教授的内容。SDLC 概念始于 20 世纪 60 年代和 70 年代初,到目前为止,它已经成为一个确立且被广泛理解的过程,被几乎每家开发软件的公司以各种格式使用。如果没有正式化的流程供人们在开发软件时遵循,公司就难以高效地生产高质量的软件,软件开发行业将会非常混乱。事实上,这就是软件开发行业在早期的情况,目前对于大多数公司来说,机器学习行业也是如此。只有在过去几年里,行业才开始围绕公司如何开发 ML 模型及其相关应用建立一些结构。

在本节中,我们提供了一个 ML 模型开发生命周期的概述,概述了您在大多数机器学习项目中会遇到的所有步骤。让我们先快速回顾一下 SDLC。在相关的地方,我们将引用这个更成熟的过程集。

注意

术语MDLC,代表模型开发生命周期,最初是由我的一个朋友和同事费元提出的。在“MLOps”一词在业界开始使用之前,他和我在亚马逊构建了一个 MLOps 流程。这并不是说我们是我们唯一试图自动化数据科学项目步骤的人。例如,这本书的技术审稿人告诉我,他和一些同事在 2000 年代初使用 SAS 和一个名为 CRISP-DM 的流程模型实现了 MLOps 类型的工作负载,CRISP-DM 代表跨行业标准数据挖掘流程。您可以在以下网址了解更多关于 CRISP-DM 的信息:www.datascience-pm.com/crisp-dm-2/。幸运的是,近年来,MLOps 已成为机器学习模型开发中的一个重要且流行的概念,现在有许多 MLOps 工具可供使用,我们将在本书的后续部分介绍。

SDLC——快速回顾

SDLC 的一个最早和最简单的版本被称为瀑布模型,因为该流程中的活动流程是顺序的,其中每个活动的交付成果作为下一个活动在流程中的依赖项。图 2.1显示了 1970 年温斯顿·罗伊斯(Winston Royce)在论文《管理大型软件开发》中展示的原始瀑布图。

图 2.1:SDLC 瀑布模型

图 2.1:SDLC 瀑布模型

如我们所见,该流程从收集和分析系统需要满足的需求开始,然后设计、编码和测试软件,最后部署使用。在部署后的软件之后,您需要通过持续运营活动来管理它。该模型后来更新,包括各个阶段之间的反馈循环。例如,测试的反馈可能导致更新的编码步骤,这反过来又可能导致更新的程序设计步骤,依此类推。

瀑布模型的一个众所周知的问题是,该流程不促进今天快速发展的软件开发行业所需的快速创新或灵活性,因为在开发、测试和部署阶段,新需求经常出现。软件设计需要频繁更新,流程的各个阶段更具有循环性,以便更灵活地进行更新(参见图 2.2)。因此,像敏捷这样的新开发方法出现了。尽管如此,从收集需求到设计、编码、测试、部署和监控软件的方法论事件序列仍然以各种形式存在于系统设计项目中,这扩展到了机器学习和项目。

图 2.2:软件开发循环方法,通常称为 DevOps(来源:https://openclipart.org/download/313185/1546764098.svg)

图 2.2:软件开发的一种循环方法,通常被称为 DevOps(来源:https://openclipart.org/download/313185/1546764098.svg)

典型的机器学习项目阶段

有趣的是,将传统软件开发行业的经验应用到机器学习模型开发上花费了一些时间。在过去几年中,随着机器学习开发突然受到巨大的人气提升,许多公司在没有正式流程的情况下跳入了这场竞赛,结果,公司在没有太多能力在整个行业标准化的情况下遇到了自己随机意外的问题。幸运的是,从这一过程中的早期先驱者那里学到了经验教训,并出现了标准化的项目活动。以下是在大多数机器学习开发项目中可以预期采取的步骤:

  1. 收集、分析和理解模型将开发的业务需求。

  2. 寻找并收集相关数据。

  3. 探索和理解数据的内容。

  4. 对数据进行转换或操作以用于机器学习模型训练,这可能包括特征工程和存储特征以供后续步骤使用。这一步骤通常也与步骤 6紧密相关,因为选定的算法可能对数据如何呈现有特定的要求。

  5. 对于监督学习模型,如果数据集中尚未存在所需的标签,则对数据进行标记。

  6. 选择一个适合业务案例要求的算法。

  7. 训练一个模型。

  8. 配置和调整超参数。

  9. 部署模型。

  10. 部署模型后监控模型。

图 2.3展示了这些步骤的视觉表示,我们将在接下来的章节中详细探讨这些步骤:

图 2.3:典型的机器学习项目阶段

图 2.3:典型的机器学习项目阶段

如您所见,机器学习模型开发过程与传统软件开发生命周期(SDLC)之间有一些相似之处,但也存在一些独特的差异。最值得注意的是,数据被纳入了过程。我们现在需要将数据的操作纳入整体过程,这增加了许多复杂性,正如我们在更详细地通过每个过程步骤时将会看到的。需要注意的是,生命周期中的每个步骤通常是循环性质的,其中数据科学团队可能需要多次执行每个任务或任务组合,使用试错法,直到找到每个步骤的最佳使用方法。

收集、分析和理解业务需求

这个步骤通常被省略在机器学习生命周期图中,因为这样的图通常关注后续技术步骤,而这些步骤在我们项目中的后续阶段。这可以被视为零步骤,因为通常需要在我们的项目中的任何技术步骤开始之前发生。就像在传统的软件开发中一样,整个过程必须从收集和理解模型将要解决的业务需求开始。例如,我们项目产生的模型将用于预测下一年的销售收入,还是我们正在着手构建一个将监控人们的健康数据并根据这些数据提供健康相关建议的应用程序?业务需求会影响我们在项目后续步骤中做出的决策,例如我们需要收集哪些类型的数据,我们将使用哪些机器学习算法来训练我们的模型,以及我们将如何衡量与模型性能相关的指标。

在人工智能/机器学习项目的这个部分,解决方案架构师将与业务领导合作,了解他们从业务角度想要实现的目标,然后将与技术人员合作,将业务需求转化为技术需求。定义技术需求是定义满足业务领导概述的业务目标的整体策略的第一步之一。这包括确定可能存在的任何限制,例如与数据科学家合作确定需要哪些类型的数据来解决业务目标,以及这些数据是否可以收集、生成或从某处采购。

寻找和收集相关数据

我们在第一章中简要提到了这个话题。数据是机器学习模型学习的基础,所以没有数据就没有机器学习。如果项目团队——包括数据科学家和数据工程师(我们将在后面更详细地解释这些角色)——无法想出如何获取满足业务目标所需的数据,那么项目可能从一开始就难以启动,因此这是过程中的一个关键步骤。数据来源根据项目类型而异,但以下是一些可用于各种人工智能/机器学习用例的数据示例:

  • 包含客户信用卡交易和/或银行交易详细信息的歷史数据

  • 与客户在线购买相关的数据

  • 特定地区的住房销售数据

  • 包含技术系统操作事件详细信息的日志条目数据

  • 由可穿戴设备(如手表或健身追踪器)追踪的健康数据

  • 从填写表格或调查问卷的人那里收集的数据

  • 来自物联网(IoT)设备(如工厂输送带或建筑车辆车队)的数据流

如您所见,有不同类型的数据可以用于许多不同的目的。数据科学团队的首要任务是定义和定位项目所需使用的数据。这不是一个原子活动,因为它不需要在项目开始时一次性完成。通常,科学团队会先对所需数据有一个大致的想法,然后根据项目后期测试和反馈来细化数据需求。

探索和理解数据

当数据科学团队收集了他们认为可以用于满足业务需求的数据时,他们通常不会直接在该数据上训练机器学习模型。相反,他们通常需要检查数据,以评估其是否真的能够满足项目的需求。原始数据往往不适合某些机器学习算法使用。让我们从我们的潜在数据源列表中举几个例子。如果我们使用的是人们填写表格或调查表收集的数据,人们可能会输入错误的信息。他们可能会留空某些字段或在输入时拼写错误。作为另一个例子,如果我们使用的是来自可穿戴健康追踪器或其他物联网设备(如机械设备传感器)的数据,这些传感器可能会出现故障并记录损坏的数据。因此,数据科学家通常需要检查数据,寻找错误、异常或潜在损坏的数据。在第一章中,我们也提到数据科学家可能希望获取有关数据的统计细节,例如数据中特定变量的值范围或其他统计分布细节。在本书的后续实践活动中,我们将使用数据可视化工具和其他数据检查工具来探索和理解数据集的内容。

对数据进行转换或操作以用于机器学习模型训练

缺失或损坏的数据在训练机器学习模型时可能会引起问题。一些需要操作数值数据的算法在遇到非数值值(包括空值和乱码/损坏的字符)时会产生错误。即使对于可以优雅处理这些值的算法,这些值也可能以意想不到的方式扭曲学习过程,从而影响最终模型的表现。

当数据科学家发现某个数据集不适合用于训练机器学习模型时,他们通常不会放弃,而是尝试对数据进行修改,使其更接近理想状态。我们称这个过程为特征工程

注意

一些文献出版物仅用“特征工程”一词来指代从现有特征(例如我们每平方英尺的价格示例)创建新特征的过程,而其他文献则用同一术语来描述与操纵我们数据集中特征相关的所有活动,包括替换缺失值。

这可能包括数据清洗(或净化)技术,例如用更有意义的东西替换缺失数据。例如,让我们假设某种医疗状况更可能在一个人变老时发生,我们希望构建一个预测这种状况发生可能性的模型。在这种情况下,一个人的年龄将是我们数据集中的重要输入特征。在我们的数据探索活动中,如果我们发现数据集中的一些记录缺失年龄值,我们可以计算数据集中所有人的平均年龄,并用平均年龄值替换每个缺失的年龄值。或者,我们可以用众数(即最频繁出现的值)替换每个值。这两种情况至少比在训练过程中数据集中有缺失或损坏的值要好。

此外,针对特定业务需求的最佳变量和值可能在我们能访问的任何原始数据中都不易获得。相反,数据科学家通常需要结合来自不同来源的数据,并想出巧妙的方法从现有数据中推导出新的数据。一个非常简单的例子是,如果我们特别需要一个年龄作为输入变量,但数据集只包含他们的出生日期。在这种情况下,数据科学家可以在数据集中添加另一个特征,即年龄,并从当前日期中减去出生日期以计算该人的年龄。一个稍微复杂一点的例子是,如果我们想预测房价,并确定每平方英尺的价格将是我们模型的重要输入特征,但我们的数据集只包含每所房子的总价格和每所房子的总面积(以平方英尺为单位)。在这种情况下,为了创建每所房子的每平方英尺输入特征,我们可以将每所房子的总成本除以该房子的总面积,然后将这个值作为数据集中的特征添加。

重要的是要理解,当数据科学家创建了训练模型所需的重要特征后,他们通常会希望将这些特征存储在某个地方以备后用,而不是需要一次又一次地重新创建它们。在本书的后面部分,我们将探讨为这一目的开发的工具。

数据标注

正如我们在第一章中讨论的那样,监督学习算法在训练过程中依赖于数据集中的标签,这些标签告诉模型模型试图学习的各种数据关系类型的正确答案。图 2.4展示了我们的标记数据集示例。

图 2.4:数据集中标签的示例(绿色突出显示)

图 2.4:数据集中标签的示例(绿色突出显示)

如果你很幸运,你将找到一个可以用来解决你的业务需求并且已经包含你想要预测的变量的必要标签或“正确答案”的数据集。如果没有,你将需要将标签添加到数据集中。再次强调,考虑到你的数据集可能包含数百万个数据点,这可能是一项非常复杂且耗时的任务。而且,就像你数据集中的其他任何特征一样,你标签的质量直接影响到你模型预测的可靠性。因此,你需要能够准确标记你的数据集的劳动力,以及其他有助于标记的工具。

另一个用于监督学习算法的数据准备步骤是将数据集分成三个不同的子集,分别用于模型的训练、验证和测试。我们将在本章后面的模型训练部分描述这些子集的使用。

在这里需要强调的一个重要概念是数据泄露,它指的是使用训练数据集之外的信息来创建模型的情况。这可能导致模型在训练数据上表现良好(因为它拥有在现实世界场景中不会拥有的信息),但在生产中由于这些无意中的提示而表现不佳。

数据泄露的原因有很多,比如在我们进行数据科学项目时如何以及何时分割我们的数据集,或者我们如何标记我们的数据。例如,在数据准备活动,如标记或特征工程中,我们可能会意外地包含在现实世界应用中模型无法获得的知识。考虑这样一个场景,我们正在使用历史数据来训练我们的模型。我们可能会意外地包含在数据集中表示的事件实际发生之后才变得可用的信息。虽然这些数据可能相关并且可能有助于影响结果,但如果这些信息在模型需要做出预测的现实世界场景中不可用,那么它将损害我们的模型性能。

选择算法和模型架构

有许多不同类型的机器学习算法,可以用于各种目的,并且新的算法和模型架构模式经常出现。在某些情况下,选择你的方法是一个简单的决定,因为有一些算法和模型架构特别适合特定的用例。例如,如果你想实现一个计算机视觉用例,那么像卷积神经网络架构这样的东西将是一个好的起点。另一方面,选择用于特定问题的机器学习算法和实现可能是一项困难的任务,这通常取决于数据科学团队的经验。例如,经验丰富的数据科学家团队可能已经参与了多个不同的项目,并形成了对不同情况下哪些算法效果最好的实际理解,而经验较少的数据科学团队可能需要对各种算法和模型架构进行更多的实验。

除了直接的业务需求,例如“我们需要一个计算机视觉模型来识别制造缺陷”,所选择的算法还可以依赖于不那么具体的企业需求,例如“模型需要在有限的计算资源上运行”或“在这个用例中,模型的可解释性非常重要。”上述每个要求都对数据科学团队为特定用例选择算法的类型施加了不同的约束。

与整体 AI/ML 项目生命周期中的大多数步骤一样,选择最佳的算法和模型架构可能需要数据科学团队实施一个循环的试错方法,他们可能会尝试不同的算法、架构、输入/输出,直到找到最佳的实施方案。我们将在本书后面的实践活动中探讨各种算法及其独特的特性,但总体来说,最好从一个简单的基线模型开始,这样我们就有了一个比较指标和了解基础数据集的起点。然后,我们可以测试更复杂的模型,并评估它们是否表现更好。

训练模型

这可能是 AI/ML 项目生命周期中最知名的活动。这是模型真正从数据中学习的地方。对于无监督算法,这可能就是它们形成我们在第一章中提到的那些聚类的时刻,例如。对于监督算法,这是我们的训练、验证和测试数据集进入场景的地方。在第一章中,我们简要地讨论了线性代数和微积分在机器学习中的应用。如果我们以线性回归为例,这正是那些概念会发挥作用的地方。我们的模型首先会尝试找到特征和标记的目标输出之间的关系。也就是说,它会尝试找到每个特征的系数,当这些系数组合使用(例如,通过将它们全部相加)时,会产生标记的目标输出。它试图计算适用于数据集中所有数据点的系数,为此,它需要扫描训练数据集中的所有项目。

模型通常从这个过程开始时进行随机猜测,因此它不可避免地在第一次尝试时是错误的。然而,然后它会计算错误并调整以通过数据集的后续迭代来最小化这些错误。有几种不同的方法和算法可以用来最小化错误,但一个非常流行的方法是称为梯度下降。我们在第一章中简要提到了梯度下降,但在这里我们将更详细地讨论它。在梯度下降中,算法致力于找到我们所说的损失函数的最小值,损失函数是我们模型试图猜测数据集中每个数据点产生标记输出的特征系数时产生的错误的表示。"方程式 2.1"展示了计算线性回归损失函数的均方误差(MSE)的方程式示例:

<mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" display="block">mml:miM</mml:mi>mml:miS</mml:mi>mml:miE</mml:mi>mml:mo=</mml:mo>mml:mfracmml:mrowmml:mn1</mml:mn></mml:mrow>mml:mrowmml:min</mml:mi></mml:mrow></mml:mfrac>mml:mrowmml:munderover<mml:mo stretchy="false">∑</mml:mo>mml:mrowmml:mii</mml:mi>mml:mo=</mml:mo>mml:mn1</mml:mn></mml:mrow>mml:mrowmml:min</mml:mi></mml:mrow></mml:munderover>mml:mrowmml:msupmml:mrowmml:mo(</mml:mo>mml:msubmml:mrowmml:miy</mml:mi></mml:mrow>mml:mrowmml:mii</mml:mi></mml:mrow></mml:msub>mml:mo-</mml:mo>mml:msubmml:mrow<mml:mover accent="true">mml:mrowmml:miy</mml:mi></mml:mrow>mml:mo^</mml:mo></mml:mover></mml:mrow>mml:mrowmml:mii</mml:mi></mml:mrow></mml:msub>mml:mo)</mml:mo></mml:mrow>mml:mrowmml:mn2</mml:mn></mml:mrow></mml:msup></mml:mrow></mml:mrow></mml:math>

方程式 2.1:均方误差公式

方程式 2.1 中,n 代表数据集中数据点的数量。

要理解这个公式所表达的意思,让我们从括号内的部分开始:<mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">mml:mo(</mml:mo>mml:msubmml:mrowmml:miy</mml:mi></mml:mrow>mml:mrowmml:mii</mml:mi></mml:mrow></mml:msub>mml:mo-</mml:mo>mml:msubmml:mrow<mml:mover accent="true">mml:mrowmml:miy</mml:mi></mml:mrow>mml:mo^</mml:mo></mml:mover></mml:mrow>mml:mrowmml:mii</mml:mi></mml:mrow></mml:msub>mml:mo)</mml:mo></mml:math>

<mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">mml:msubmml:mrowmml:miy</mml:mi></mml:mrow>mml:mrowmml:mii</mml:mi></mml:mrow></mml:msub></mml:math> 代表每个数据点的模型预测目标变量,而 <mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">mml:msubmml:mrow<mml:mover accent="true">mml:mrowmml:miy</mml:mi></mml:mrow>mml:mo^</mml:mo></mml:mover></mml:mrow>mml:mrowmml:mii</mml:mi></mml:mrow></mml:msub></mml:math> 代表每个数据点的真实目标变量的值。

方程式 2.1 的括号内,我们通过从模型预测值中减去真实值来计算模型预测的错误,这与我们在 第一章 中描述的类似,然后对结果进行平方。在这种情况下,我们计算的是所谓的 欧几里得距离,即在二维空间中预测值与真实值之间的距离。对结果进行平方也起到了消除减法结果中负值的作用。

方程中的求和符号Σ(西格玛)代表将训练数据集中所有数据点的计算误差加起来。然后,我们将最终结果——即所有预测的总误差——除以数据集中的数据点数量,以计算所有预测的平均误差(或均值)。

记住,我们希望通过找到这个损失函数(也称为目标函数)的最小点来最小化每次训练迭代中的误差。为了理解在损失函数中找到最小点意味着什么,如果我们能够绘制出函数的图形,那会有所帮助。图 2.5 展示了均方误差(MSE)的二维损失函数图的例子:

图 2.5:展示最小点的均方误差损失函数图

图 2.5:展示最小点的均方误差损失函数图

每次算法从每次训练迭代中计算出损失时,那个损失值可以表示为图上的一个点。考虑到我们想要移动到最小点以最小化损失,我们希望在图上向下迈一步。无论何时我们想要从一个点移动到另一个点(即使在我们现实生活中移动身体),我们需要确定运动的两个方面:方向和大小,即我们想要朝哪个方向移动以及移动多远?这就是梯度下降发挥作用的地方。它帮助我们确定应该朝哪个方向移动以向最小点前进。让我们更详细地看看它是如何工作的。

想象一下图 2.5 是一个山谷,我们站在代表最近一次训练迭代中计算出的损失的那个点上。那个点位于山谷的侧面,例如图 2.6 中所示的位置。

图 2.6:展示当前位置的均方误差损失函数图

图 2.6:展示当前位置的均方误差损失函数图

对于人类来说,下山行走有一定的本能,因为我们有感觉输入告诉我们哪个方向是下坡。例如,我们的脚可以感觉到当前位置的山坡斜度,我们可以感觉到向下的重力拉扯,我们也许还能够看到我们的周围环境,因此可以看到哪个方向是下坡。然而,我们的梯度下降算法没有这些感觉输入,它只能通过数学来找出哪个方向是下坡。然后,它需要使用程序方法来定义在那个方向上迈步的含义。我们的算法知道图上的当前位置,并且可以计算函数的导数(来自微分学的概念)以确定当前位置的图形斜率。图 2.7 展示了图上某一点处直线斜率的例子,这代表了该点处函数的导数。

图 2.7:特定点的损失函数导数

图 2.7:特定点的损失函数导数

当导数被计算出来后,这个信息可以被我们的算法用来朝着最小点迈出一步。方程 2.2展示了在线性回归的背景下,如何计算每个后续步骤的梯度下降:

θj=θj−α1m∑i=1m(hθxi−y(i))xj(i)

方程 2.2:线性回归的梯度下降

方程 2.2中,θj代表图上的位置,而θ代表我们数据集中每个数据点特征的系数向量。记住,我们正在尝试找到一组系数,使得我们的模型预测与数据点目标变量的真实值之间的误差最小:

  • hθxi表示每个数据点的预测目标变量

  • y(i)表示每个数据点的真实目标值

如我们所见,在更广泛的一组括号中,我们再次从每个数据点的预测目标变量值中减去真实目标值。这是因为方程 2.2是从方程 2.1(这里省略了该推导的数学证明以简化)推导出来的。

m代表我们数据集中每个数据点的特征数量。

<mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">mml:miα</mml:mi></mml:math>就是我们所说的学习率。它是我们算法的其中一个超参数,它决定了我们应该采取的步长大小;即,我们在所选方向上移动的幅度。

总的来说,1m∑i=1m(hθxi−y(i))xj(i)代表了在图上当前位置损失函数的导数。因此,公式 2.2表明我们的下一个位置将等于当前位置减去在图上当前位置损失函数的导数乘以学习率。这样就会朝着最小值点迈出一步,其中损失函数的导数决定了方向,而与学习率的组合则定义了幅度。

非常重要的是要注意,公式 2.2仅仅代表了梯度下降过程中的一个步骤。我们多次迭代这个过程,在每次迭代中,我们遍历数据集,输入我们的估计系数,计算误差/损失,然后通过梯度下降朝着损失函数的最小值点迈进来减少损失。我们可能永远无法精确地达到最小值点,但即使我们能够非常接近,我们的模型估计和预测也可能是可接受的准确。

我们应该注意,梯度下降有不同的配置。在批量梯度下降中,我们会在每次迭代中遍历整个训练集。或者,我们可以实现小批量梯度下降,在这种情况下,每次迭代会处理训练数据集的子集。这种方法不如全面,但可能更有效率。一种流行的实现方式被称为随机梯度下降(“随机”一词意味着“随机”)。在随机梯度下降中,我们每次迭代从数据集中抽取一个随机样本子集,这可能是每个样本中只有一个数据点。关键在于,因为我们每次迭代都抽取一个随机子集,所以我们每次都是从特征空间的不同点开始。起初,这似乎有些无序,因为我们会在特征空间的不同点跳跃。然而,这种方法已被证明在最小化整体损失函数方面非常有效。它还可以帮助避免所谓的局部最小值,这指的是某些损失函数并不像我们在图 2.5中展示的那样简单。它们可能有多个峰值和谷底,在这种情况下,任何谷底的底部都可以被视为一种最小点,但局部最小值可能不是函数的整体最小值,这被称为全局最小值图 2.8展示了多个最小值和最大值的例子:

图 2.8:局部和全局最小值及最大值

图 2.8:局部和全局最小值及最大值

尽管我们在这个部分关注了二维损失函数,但损失函数可以超过两个维度,同样的概念也适用于更高维的空间。

注意

在本节中,我们选择了一个特定的算法(线性回归)和一种数据集类型(表格)来展示模型训练过程的例子。当然,还有其他算法和数据类型适用于不同的用例,那些用例的训练过程会有它们自己独特的实现。然而,整体模型训练过程通常涉及处理输入数据,试图找到某种有用的模式或关系,然后以重复的方式逐步提高该模式或关系的准确性,直到达到某个确定的准确度阈值或直到训练被认为无效(如果模型未能有效地学习任何有用的模式或关系)并因此终止。

配置和调整超参数

超参数是定义模型训练作业运行方面的参数。它们不是模型从数据集中学习的参数,而是与模型训练过程执行相关的外部配置选项。以一个简单的例子开始:我们讨论过,训练作业通常需要多次遍历训练数据集,以便学习数据中的模式。您可能为模型训练作业配置的一个超参数可能是指定它应该遍历数据集的次数。这通常被称为epoch的数量,其中 epoch 代表一次遍历训练数据集。

为您的超参数选择最佳值是另一种通常需要大量试错尝试的活动,在这个过程中,您可能需要尝试不同的超参数值组合,以找到最大化模型训练性能的最佳设置。让我们继续我们的简单例子,即配置训练作业应该处理训练数据集的次数。考虑到模型每次遍历数据集时可能学习到更多信息,我们最初可能会认为决定 epoch 的数量将是一个简单的选择,即我们只需将此值设置得非常高,以便模型从数据中学习到更多信息。然而,在现实中,这通常不是最佳选择,因为模型每次处理数据集时并不总是能学习到更多有用的信息。机器学习中存在一些称为欠拟合过拟合的概念,我们将在本章的挑战部分进行探讨。它们与继续在现有数据集上训练将无法产生预期结果的问题相关。

即使在模型每次处理数据集时都能学习到有用信息的情况下,它通常也会达到一个点,即它学习新信息的速率会放缓或达到平台期。当这种情况发生时,再次反复遍历数据集将是不高效的。请记住,在大型数据集上训练模型可能非常昂贵,因此当模型的学习达到平台期时,您不希望继续处理数据。我们可以通过生成学习曲线图来衡量学习速率,该图显示了训练过程中的训练错误。图 2.9显示了学习曲线的一个示例:

图 2.9:学习曲线图

图 2.9:学习曲线图

图 2.9中,蓝色和红色线之间的差距代表我们的模型在训练数据集和测试数据集上的预测误差。当图表显示蓝色和红色线之间的差距没有显著减少时,我们知道继续训练不会使我们的模型显著更准确,这可能是一个停止训练过程的良好时机。

一个类比是,如果我们有一个学生已经读过一本书很多次,以至于记住了每个单词并彻底理解了书中的每个概念。在那个时刻,继续指导学生反复阅读这本书就变得没有必要了,因为他们将不再从这本书中学到任何新东西。现在让我们也想象一下,我们需要每次学生阅读这本书时都付给他们报酬,这类似于为在数据集上训练模型所需的计算资源付费。

配置训练轮数(epochs)是尝试为特定超参数找到最佳配置的一个例子。不同类型的算法有不同的超参数类型,尝试测试所有超参数值的组合对于数据科学家来说可能是一个痛苦且耗时的工作。幸运的是,Google Cloud 有一个工具可以自动执行这项任务,我们将在本书的后面部分探讨。

部署模型

终于!我们已经找到了合适的数据、算法和超参数值的组合,并且我们的模型已经准备好在现实世界中使用了,我们称之为托管服务我们的模型。达到这个阶段需要大量的工作。我们可能已经训练了数百个不同版本的模型,以便将其部署到生产环境中。我们的数据科学团队可能不得不尝试许多不同的数据集版本和转换,以及许多不同的算法和超参数值,才能最终获得一些有意义的成果或见解。直到大约五年前,执行所有这些步骤并跟踪其结果仍然是一个非常缓慢、手动且痛苦的过程。尽管如此,现在至少有工具可以自动化许多这些步骤,并且可以更快地完成,可能只需要几周而不是几个月。在这本书的后面部分,我们将讨论一种称为 AutoML 的技术,它可以将整个流程简化为几个简短的命令,只需几分钟或几小时即可完成!

部署我们的模型可能就像将其打包成 Docker 容器并在服务器上部署容器一样简单,尽管我们通常会希望创建某种基于 Web 的 API,以方便应用程序访问模型。我们将在后续的动手活动中这样做。此外,当我们介绍 MLOps 时,我们将看到为什么对我们来说创建管道来自动化模型的部署是有意义的,这与我们使用 CI/CD 管道构建和部署常规软件应用的方式非常相似。

部署后监控模型

你可能会认为一旦你成功测试并部署了模型到生产环境,你的工作就完成了。然而,乐趣并没有停止!就像常规软件一样,你需要持续监控你的模型性能。这包括传统的监控,例如跟踪你的模型在给定时间段内(例如每秒)服务了多少请求,模型响应请求需要多长时间(延迟),以及这些指标是否随时间变化。然而,机器学习模型还有额外的监控需求,例如像在第一章中提到的机器学习特定指标(MAE、MSE、准确率、精确度等)。这些指标帮助我们了解我们的模型从推理角度的表现,因此我们需要监控它们,并确保它们继续满足我们的业务需求。

注意

在本节中你学到的机器学习模型开发生命周期中的各个阶段是理解 MLOps 和 AutoML 的基础。我们在这本书中用整整一章来介绍 Google Cloud 上的机器学习工程和 MLOps,但到目前为止,从高层次来看,你可以认为 MLOps 和 AutoML 的目标是自动化机器学习模型开发生命周期的所有步骤。你将在 MLOps 章节中看到,我们可以使用工具来创建管道,自动化所有概述的步骤。我们可以在管道中拥有复杂的管道组合,这将自动化从准备和转换输入数据到训练和部署模型,监控生产中的模型,以及如果我们检测到我们的模型停止提供期望的结果,我们希望重新训练模型在更新的数据上,自动重新启动整个过程的全部工作。这将提供一个自我修复的模型生态系统,有助于持续保持我们的模型更新。

AI/ML 项目中的角色和人物

在整本书中,我们提到了各种角色,如数据科学家、数据工程师和机器学习工程师。我们还提到了更多传统的角色,如软件工程师、项目经理、利益相关者和业务领导者。这些传统角色在行业中已经定义了几十年,所以我们在这里不会定义它们,但对于特定于 AI/ML 项目的较新角色,常常存在混淆,因此我们将在这里简要描述它们。在小型团队中,需要注意的是,一个人可能需要执行所有这些角色:

  • 数据工程师:数据工程师通常参与数据科学项目的早期阶段——具体来说是数据收集、探索和转换阶段。数据工程师通常负责找到相关数据并将其清理干净,以便在项目的后期阶段使用。

  • 数据科学家:数据科学家通常是实际训练机器学习模型的角色。他们在迭代各种模型训练实验的过程中,通常会执行数据收集、探索和转换等活动。在某些情况下,数据科学家将是项目中的资深成员,他们可能会为数据工程师和机器学习工程师提供指导。他们通常负责创建的机器学习模型,尽管这些模型是在数据工程师和机器学习工程师的帮助下创建和部署的。

  • 机器学习工程师:机器学习工程师角色通常指的是具有机器学习或数据科学专长的软件工程师。他们理解机器学习概念,并且是模型开发生命周期各个阶段的专家。他们通常是连接 DevOps 专长到机器学习项目的桥梁,以便创建 MLOps 工作负载。当数据科学家创建他们认为可以用于生产的模型时,他们可能会与机器学习工程师合作,在 MLOps 管道中部署模型到生产环境中所需的全部机制。

现在我们已经涵盖了典型 AI/ML 项目中发现的重大步骤和概念,让我们来看看公司在尝试实施此类项目时通常会遇到的陷阱。

在机器学习模型开发生命周期中遇到的常见挑战

对于机器学习模型开发生命周期中的某些阶段,我们已经讨论了你在这些阶段可能会遇到的各种挑战。然而,在本节中,我们特别指出了一些作为与实施 AI/ML 工作负载的公司互动的 AI/ML 解决方案架构师需要了解的主要挑战。在本章后面的“克服常见挑战的最佳实践”部分,我们将探讨克服许多这些挑战的方法。

寻找和收集相关数据

我们面临的第一大挑战之一是找到为解决我们的模型构建的业务问题所需的相关数据。我们在上一节中提供了一些潜在数据源的示例,在某些情况下,您可能已经可以轻松获得所需的数据,但找到相关数据对于数据科学家和数据工程师来说并不总是直接的。以下是在寻找和访问正确数据方面的一些常见挑战:

  • 如果您在一家大公司工作,数据可能存在于您公司内的另一个团队或组织中,但您可能不知道它或不知道如何找到它。

  • 数据可能需要从散布在公司各个部门的不同数据源中创建,这些数据源由不同的组织拥有。

  • 数据可能包含敏感信息,因此可能受到有关其存储和访问方式的法规和限制。

  • 您可能需要咨询专家以找到、验证和理解数据,例如,财务数据、医疗数据、大气数据或与特定专业领域相关的其他数据。

  • 数据可能存储在仅限于生产事务操作使用的数据库中。

  • 您可能不知道您是否可以信任数据的内含内容。例如,它是否准确?

  • 数据可能包含固有的偏差或其他未知挑战。

选择算法和模型架构

当涉及到选择要使用的算法或模型架构时,最初的最大的挑战之一可能是仅仅确定从哪里开始。您不希望花费数月时间仅在不同选项上进行实验,直到找到有用的实现或永远找不到有用的实现。

数据标注

数据标注可能是一项非常手动的工作,需要人类通过大量数据并为每个数据点添加标签。近年来已经开发了一些工具来自动化一些标注任务或使任务对人类来说更容易执行,但仍然需要在标注数据集时有人类参与。因此,公司可能面临的一个主要挑战是寻找和雇佣一支强大的数据标注团队。请记住,某些数据标注任务可能需要特定的专业知识。例如,考虑一个由医学图像组成的数据集。图像中的特定特征可能表明存在某种特定的医疗状况。通常需要特殊培训才能阅读医学图像并识别所讨论的具体特征,因此这不是可以雇佣任何随机人员的任务。正如我们之前讨论的,如果您的标签不准确,那么您的模型也不会准确,在本例中,对于被委托诊断危及生命医疗状况的医疗设施来说,这可能具有重大影响。

训练模型

关于模型训练的两个经典挑战是欠拟合过拟合问题。这些挑战与你的模型如何学习数据中的关系或模式有关。

在监督学习的情况下,我们通常将数据集分为前面提到的三个子集:训练集、验证集和测试集。验证集通常用于超参数调整,训练数据集是模型训练所用的数据,测试数据集是我们评估训练模型的方式。我们根据为该模型定义的指标来评估模型,例如准确率、精确度或均方误差。在这种情况下,测试数据集是模型在训练过程中未见过的新的数据,我们希望确定当模型看到这些新数据时,其预测是否准确——即,我们希望确定模型对新数据的泛化能力。如果一个模型在训练数据集上提供非常准确的预测,但在测试数据集上提供不准确或不太准确的预测,那么我们就说该模型是过拟合的。这意味着它过于紧密地拟合了训练数据,当它接触到新数据时无法表现良好。

另一方面,如果我们发现模型在任一数据集(训练或测试)上表现不佳,那么我们就说它是欠拟合的。

图 2.10展示了试图确定蓝色和红色数据点之间差异的分类模型的拟合、过拟合和欠拟合的示例。黑色边界线代表过拟合,因为它与数据集拟合得过于精确,紫色线代表欠拟合,因为它没有很好地捕捉蓝色和红色点之间的差异。绿色线很好地分离了蓝色和红色点;它并不完全完美,但可能是一个泛化能力良好的可接受的模型。

图 2.10:拟合、过拟合和欠拟合的示例

图 2.10:拟合、过拟合和欠拟合的示例

除了前面提到的经典训练挑战之外,还有其他挑战与作为更广泛 AI/ML 项目一部分的训练整体过程有关,例如我们提到的第一章中的谱系跟踪。在大型的 AI/ML 项目中,可能有多个数据科学家团队进行实验和训练数百个模型。在大型项目中跟踪他们的结果并与他们分享可能非常具有挑战性。

配置和调整超参数

寻找最佳的超参数值集合可能几乎与制作一个可用的数据集或选择正确的算法一样具有挑战性。考虑到超参数会影响我们的模型训练作业的运行方式,每个作业可能需要很长时间才能运行,并且可能存在数千种超参数值的组合需要探索,手动进行这项工作可能非常具有挑战性和耗时。

评估模型

虽然我们在训练和超参数调整过程中通常进行一些验证和测试,但在将模型部署到生产环境中之前,我们应该彻底评估我们的模型。在第一章“开发机器学习应用中的常见挑战”部分中,我们讨论了从数据科学项目中实现商业价值所面临的挑战。第一章中,我们强调了数据科学家与业务利益相关者合作,彻底理解目标人工智能/机器学习系统旨在解决的业务需求的重要性。在我们数据科学项目中,评估步骤就是检查我们创建的模型和解决方案是否充分满足了这些业务需求,这是基于我们定义的成功度量标准。除了数据科学团队评估模型外,在此阶段与业务利益相关者审查结果,以确保它们符合预期,也可能是相关的。如果我们发现结果不满意,我们通常需要从数据科学生命周期的早期重新尝试这个过程,可能使用新的或不同的数据、不同的算法和/或不同的超参数值。我们可能需要在交互式过程中重复这些步骤,直到我们适当地满足业务需求。

部署模型

在部署我们的模型时,我们需要选择足够的计算资源来充分服务我们的模型。根据模型架构,我们可能需要包括 GPU/TPU,通常也结合 CPU,当然还有 RAM。在这个项目阶段的一个非常重要的活动是“正确配置”这些组件。为此,我们需要估计每种类型的组件需要多少才能尽可能准确地服务我们的模型,考虑到我们期望接收的每秒请求数量。为什么这如此重要呢?嗯,模型托管通常被公司报告为它们在 AI/ML 方面的最大成本。它可能占公司 AI/ML 成本的 90%。因此,如果我们配置的服务器比我们需要的资源更多,这将增加成本。另一方面,如果我们没有配置足够的资源,我们将无法处理来自客户的请求数量,从而导致我们的模型服务中断。幸运的是,像 Vertex 这样的云 AI/ML 服务可以自动扩展我们的模型托管基础设施以满足增加的需求,但我们需要尽可能准确地确定每台服务器的规模,以便控制成本。

在部署我们的模型时,我们还需要考虑我们的应用程序需要多快地对推理请求做出响应。在构建我们的模型托管基础设施时,我们需要记住这一点。

部署后监控模型

除了监控与我们的模型相关的各种指标外,在此阶段需要强调的一个重要概念是所谓的漂移,它可以以各种格式表示,如模型漂移、数据漂移或概念漂移。为了解释漂移的概念,我们首先需要深入探讨模型训练过程与模型在生产中运行之间的关系。

注意,在模型训练期间,模型接触到了特定格式和特定约束的数据,这就是它学习的方式。让我们将输入数据的状态称为其形状,它指的是数据的格式和约束。当我们将我们的模型部署到生产环境中,并暴露给新数据以从模型中获得预测时,我们希望确保新数据的形状尽可能匹配训练数据的形状。我们不是指数据的内涵,而是数据如何表示给模型。

在我们的训练过程中,我们可能对原始数据进行了转换,使其更适合模型训练。如果是这样,我们需要对任何我们发送给模型进行预测的新数据进行相同的转换。然而,在现实世界中,数据会随着时间的推移而变化,因此数据的形状也会随着时间的推移而变化。我们称这种现象为漂移,即自我们训练模型以来,现实世界中的原始数据在某种程度上发生了根本性的变化。让我们看看几个漂移的例子,以便阐明这一点:

示例一

我们使用从在线填写表格的客户那里收集的数据来训练我们的模型。我们的模型试图预测这些客户是否可能对一项特定的营销活动做出良好反应,该活动将向他们发送带有鞋类折扣的目标电子邮件。最近,一位管理员决定他们想要从客户那里获取一些额外的信息,并且一些之前收集的数据不再相关,因此他们在表格中添加了一些字段并删除了一些其他字段。现在,当新客户填写表格并将这些数据发送到我们的模型时,输入中将有模型以前从未见过的额外字段,而模型期望看到的其他字段将不再存在。这可能会影响模型有效解释和使用输入数据的能力,导致错误或预测不正确。

示例二

我们构建了一个模型,用于估算我们向客户交付产品所需的速度。该模型使用来自多个不同来源的输入。其中一个来源是一个包含过去交付中向客户交付产品所需时间的历史数据的数据库。我们每天都会收到该数据库的更新,其中包含前一天交付的所有订单的详细信息。该数据库中的一个关键特征是交付时间,以天为单位衡量。这个数据库是由我们公司中另一个组织拥有的系统创建的,因此我们无法控制该数据库。最近,我们的交付流程变得更加高效,一些产品现在可以在同一天交付,因此交付时间现在已更新为以小时为单位而不是以天为单位。然而,没有人通知我们的数据科学团队关于这一变化。现在,我们的模型查看交付时间特征,由于度量单位已更改,其对新交付时间的预测是不正确的。

另一个有趣的例子是我们都多少有些熟悉的。许多大型零售商使用 AI/ML 模型根据与客户购买相关的数据来预测他们库存中应该存放什么,他们试图寻找新兴趋势以识别消费者行为的改变。在 COVID-19 大流行的前几周,人们对购买什么的需求发生了巨大而突然的变化。模型可能惊讶地发现,突然之间,每个人都对某一特定事物非常感兴趣,在此之前,这一事物通常以非常可预测的速度销售。模型预测的,突然之间每个人都对什么特别感兴趣的东西是什么?卫生纸!

图 2.11:商店中空空的卫生纸货架(来源:https://commons.wikimedia.org/wiki/File:COVID-19_-_Toilet_Paper_Shortage_%2849740588227%29.jpg)

图 2.11:商店中空空的卫生纸货架(来源:https://commons.wikimedia.org/wiki/File:COVID-19_-Toilet_Paper_Shortage%2849740588227%29.jpg)

随着时间的推移,我们的数据也可能发生许多更微妙的变化。我们之前已经讨论了数据科学家在训练模型之前通常想要检查数据,他们经常想要检查的一个方面是每个特征(均值、众数、最大值、最小值等)的统计分布。这些细节很重要,因为它们让我们了解我们的特征通常预期包含哪些类型的值。在检查过程中,这可以帮助我们识别出可能表明错误数据或可能让我们了解我们之前未意识到的数据其他特征的异常值。我们还可以将这种知识应用于生产中的预测。我们可以分析发送到我们的模型进行推理的数据,如果我们看到统计分布以一致的方式发生变化,那么这可能会提醒我们潜在的数据损坏或数据确实发生了变化,这可能会表明我们需要通过在新数据上训练来更新我们的模型,这些新数据与我们在现实世界中观察到的更新形状相匹配。

正如我们所见,漂移可能导致我们的模型变得不准确或提供错误的结果,因此我们需要通过检查我们在生产中观察到的数据以及监控我们模型的预期指标来特别关注这一点。如果我们看到我们模型的指标随着时间的推移或突然下降,这可能是模型训练的数据类型与它在生产中观察到的数据类型之间漂移的迹象。

克服常见挑战的最佳实践

本节包含公司随着时间的推移开发出的指针和最佳实践,以解决上一节中讨论的许多挑战。

寻找和收集相关数据

我们讨论了数据孤岛是大型公司中常见的挑战,以及关于数据存储和访问的限制,特别是可能受到各种法规和合规要求约束的敏感数据。克服这些挑战的关键是通过创建集中的数据湖和数据发现机制来打破孤岛,例如包含描述我们数据湖中各种数据集元数据的可搜索数据目录。为了确保我们的数据存储和访问安全,我们需要实施强大的加密和基于权限的访问机制。我们将在后面的章节中更详细地探讨这些主题,并执行一些关于检测和解决数据集中偏差和其他问题的动手活动。

在我们的数据存在于专门为交易性业务操作限制的数据库中时,我们可以实施一个变更数据捕获CDC)解决方案,将我们的数据复制到可以用于数据分析和 AI/ML 工作负载的数据湖。

考虑到数据收集过程发生在我们的 AI/ML 工作负载的最初阶段,我们必须在这个阶段实施数据质量检查,以防止工作负载后期出现问题。例如,我们知道在损坏的数据上训练我们的模型会导致错误或模型输出不准确。请记住,在大多数 ML 用例中,我们定期在来自某个来源的更新数据上训练我们的模型,这个来源可能是由另一个团队或组织拥有和运营的系统。因此,如果我们在这个数据进入工作负载时创建数据质量检查,并且检测到数据质量问题,我们应该实施机制来防止我们的流程中的后续步骤继续进行。否则,执行我们流程中的下游步骤,如数据转换和模型训练,将是时间和金钱的浪费,并可能导致生产中出现更糟糕的后果,如模型故障。

数据标注

如果您的公司在寻找执行标注任务的工作团队方面遇到困难,谷歌云的数据标注服务可以帮助您适当地标注数据。

选择算法和模型架构

在选择算法时,我们应该从哪里开始?这是一个常见的挑战,因此数据科学家一直在构建解决方案,试图使这个过程更容易。在本节中,我们将描述一个分层框架,用于在此背景下处理新的 AI/ML 项目:

  • 一级:您可以查看是否已经存在针对您业务问题的打包解决方案。例如,谷歌云已经为许多不同类型的用例创建了打包解决方案,如计算机视觉、自然语言处理和预测。我们将在接下来的章节中更详细地介绍这些解决方案。

  • 第二级:如果您想创建和部署自己的模型而不做任何相关工作,请查看 Google Cloud 的 AutoML 功能,看看它是否符合您的需求。我们也会在本书的后续章节中通过实际操作活动来探讨这一点。

  • 第三级:如果您想使用别人训练好的模型开始,存在许多数据科学家共享他们创建的模型的数据中心“模型动物园”。类似于传统软件开发中的软件库,这些是由其他数据科学家为特定目的创建的资产,您可以重用它们而不是从头开始实现相同的功能。例如,您可以在 Google Cloud 的 AI Hub(https://cloud.google.com/ai-hub/docs/introduction)中找到各种用例的预训练模型。

  • 第四级:如果前面的选项不能满足您的特定需求,您可以创建自己的自定义模型。在这种情况下,Google Cloud Vertex AI 提供了用于常见用例的内置算法,例如线性回归、图像分类、目标检测等等,或者您可以将自己的自定义模型安装到 Vertex AI 上运行。Vertex AI 为 AI/ML 项目生命周期的每个步骤都提供了许多工具,我们将在本书中探讨其中大部分。

训练模型

有一些已建立的方法来解决过拟合和欠拟合问题。过拟合的一个原因可能是模型没有获得足够多的不同数据点来学习适当的模式。让我们来看一个非常极端的例子,假设我们的数据集中只有一个数据点,并且我们的模型反复处理这个数据点,直到找到一组系数,它可以用来将输入特征准确关联到该数据点的目标输出。现在,每当它看到相同的数据点时,它可以轻松准确地预测目标变量。然而,如果我们向它展示一个具有相似结构的新数据点——即相同数量和类型的特征,但特征值不同——那么我们的模型很可能无法准确预测新数据点的输出,因为它在训练过程中只学习了单个数据点的特定特征。这是一个过拟合的例子,其中模型在训练数据点上表现非常好,但不能对其他数据点做出准确预测。

一种可以帮助解决这种过拟合问题的方法是在训练我们的模型时提供更多的数据点。如果我们的算法在训练过程中看到了成千上万的数据点,那么它更有可能构建一个更通用的模型,该模型对特征空间以及特征与目标变量之间的关系有更广泛的理解。因此,当它看到新的数据点时,它可能能够对新的数据点的目标变量做出更准确的预测。

在这个背景下,我们需要注意一个权衡:虽然我们的训练过程很可能会随着我们提供越来越多的数据点而构建一个更通用的模型,但我们还需要记住,在大数据集上训练模型可能会很昂贵。我们可能会发现,当模型已经看到了数百万个数据点后,每次新的训练迭代只使模型的泛化指标略有增加。例如,如果我们的模型目前的准确率为 99.67%,每次训练迭代只将其准确率提高 0.0001%,但这样做可能需要花费数千美元,那么从财务角度来看,继续在越来越多的数据点上训练模型可能就没有意义了,尤其是如果我们认为 99.5%的准确率已经足够满足业务需求的话。这一点很重要——训练成本与准确率增加之间的权衡取决于业务需求。如果我们正在构建一个用于医疗诊断用例的模型或一个预测准确率错误可能导致公司损失数百万美元的模型,那么继续在更多数据点上训练模型可能是值得的。在任何情况下,你通常需要做的是定义一个阈值,在这个阈值下,业务认为模型的指标已经足够,并测量随着模型在更多数据点上训练而该指标的增量。如果你看到该指标在达到一定数量的数据点后开始趋于平稳,那么可能就是停止训练过程的时候了。

应该注意的是,增加更多数据点并不总是可行的,因为你可能一开始就只有有限的数据集,并且可能很难为你的特定用例收集更多真实世界的数据。在这些情况下,你可能能够生成具有与你的真实世界数据相似特征的人工合成数据,或者使用机制在训练过程中优化现有数据集的使用,例如通过交叉验证来最大化训练数据集,我们将在本书后面的动手活动中探讨这一点。

另一个可能导致过度拟合的潜在原因是模型过于“复杂”,这里的“复杂”意味着训练数据集中每个数据点可能使用了过多的特征。再次以极端的例子来说明,如果每个数据点都有数千个特征,模型将学习到特征与训练数据集之间非常具体的关系,这些关系可能无法很好地推广到其他数据点。在这种情况下,一个解决方案可能是删除那些被认为对于确定特征与目标变量之间最佳关系的非关键特征。选择相关特征本身就是一个挑战,我们将探讨如主成分分析PCA)等机制来帮助选择最相关的特征。

那么,过拟合的对立面是欠拟合,欠拟合的一个潜在原因是模型过于简单,在这种情况下,数据集中每个数据点可能没有足够多的特征,使得模型无法确定特征与目标变量之间的有意义关系。当然,在这种情况下,我们希望找到或生成额外的特征,以帮助我们的模型学习到这些特征与目标变量之间更有意义的关系。

为了解决在大规模机器学习项目中跟踪实验及其结果所带来的挑战,我们将使用 Vertex ML 元数据,它为我们跟踪所有实验及其输入和输出(即我们数据和机器学习模型工件的历史记录)。

配置和调整超参数

有一些系统性的方法可以探索我们所说的“超参数空间”,这意味着所有可能的超参数值。以下是一些流行的方法:

  • 随机搜索:随机搜索方法使用一种子采样技术,为每个训练作业实验随机选择超参数值。这不会导致测试每个超参数的所有可能值,但它通常是一种非常有效的方法,可以找到一组有效的超参数值。

  • 网格搜索:超参数调优的网格搜索方法是最全面的,因为它会尝试每个超参数的所有可能值的组合。这意味着它通常比随机搜索方法花费更多的时间。此外,请记住,每个训练作业都会产生费用,所以如果你有一个很大的超参数空间,这可能会非常昂贵,甚至不可行。

  • 贝叶斯优化:在本章的早期,我们讨论了使用梯度下降通过找到函数的最小点来优化函数。贝叶斯优化是另一种优化技术。这是一个相当复杂的过程,通常比之前提到的其他方法更有效。幸运的是,Google Cloud 的 Vertex AI Vizier 服务将为你执行贝叶斯优化,所以如果你使用该工具,你就不需要自己实现了。

    如果你对深入了解贝叶斯优化的内部工作原理感兴趣,我建议参考以下论文:arxiv.org/abs/1807.02811

Google Cloud 的 Vertex AI Vizier 服务将为你运行大量的训练作业实验,尝试每个实验中许多不同的超参数值组合,并找到运行你的机器学习训练作业的最优超参数值。

关键提示

为了在超参数优化过程中节省大量繁琐的工作和时间,请使用专为该目的构建的云服务,例如 Google Cloud 的 Vertex AI Vizier 服务。

部署模型

延迟通常是我们的模型部署中的一个关键因素,我们需要确保我们的模型托管基础设施满足客户端应用程序预期的延迟要求。

在这个背景下,一个需要考虑的决定点是,我们是否有批量或在线使用场景。在在线使用场景中,客户端将一块输入数据发送到我们的模型,并等待接收推理响应。这通常发生在我们的客户端应用程序需要快速得到答案时,例如当客户在我们的网站上执行交易时,我们想查看交易是否看起来是欺诈性的。这是一个实时使用场景,因此延迟通常需要非常低;可能只有几毫秒。你通常需要与业务领导者合作,以定义可接受的延迟。

在批量使用场景中,我们的模型可以一次处理大量数据。例如,在推理时间作为我们模型的输入,我们可能提供一个包含数千或数百万数据点的文件,我们希望我们的模型对这些数据进行预测,我们的模型可能需要数小时来处理这些输入,并将所有推理结果保存为另一个文件中的输出,我们可以在以后参考。

小贴士

批量使用场景通常与不需要低延迟的场景相关联。然而,具有讽刺意味的是,也存在一种场景,批量使用场景实际上可以帮助在推理时间提供更低的延迟。考虑这样一个场景,我们正在运行一个零售网站,我们想从用户的购买历史中获取洞察,以便向客户推荐他们可能在访问我们的网站时感兴趣购买的产品。根据我们拥有的历史数据量,处理这些数据可能需要很长时间。因此,我们不想在客户访问我们的网站时实时进行这项操作。相反,我们可以在每晚定期运行一个批量推理作业,并将我们的结果存储在文件或键值数据库中。然后,当客户访问我们的网站时,我们可以从我们的文件或数据库中检索预先计算的推理结果。在这种情况下,从文件或数据库中检索一个值通常会比实时在线推理快得多。请注意,这仅适用于某些用例。例如,它不适用于交易性欺诈评估用例,因为我们需要从该场景的持续交易中获得实时特征。因此,作为数据科学家或 AI/ML 解决方案架构师,您需要确定哪种推理方法最适合您的每个用例。

部署后监控模型

如果你检测到生产中出现了漂移,这表明你可能需要更新你的模型。我们建议在检测到漂移时,建立机制来自动化使用更新数据重新训练你的模型,尤其是如果你正在管理大量模型时。我曾与那些在生产中同时运行数百个模型的组织合作过,手动监控、整理和持续重新训练所有这些模型是不可行的。在这种情况下,我们实施了 MLOps 框架,该框架会在模型的指标持续低于我们认为是可接受的预配置阈值时,在更新数据上重新训练模型。然后,MLOps 框架会对新模型进行测试,如果新模型的指标在生产中优于当前模型的指标,它就会用新模型替换生产模型。

当涉及到定义和监控生产中模型的操作指标时,你可以使用 Google Cloud Monitoring 来完成这个目的。

摘要

在本章中,我们快速回顾了传统的 SDLC(软件开发生命周期),并介绍了 ML 模型开发生命周期的概念。我们讨论了在大多数 AI/ML 项目中通常遇到的每个步骤,然后深入探讨了每个步骤中普遍存在的具体挑战。最后,我们介绍了公司随着时间的推移学到的方法和最佳实践,以帮助他们解决一些常见的挑战。

在下一章中,我们将开始探索 Google Cloud 中可以用来实现 AI/ML 工作负载的各种不同服务。

第三章:AI/ML 工具和 Google Cloud AI/ML 生态系统

在本章中,我们将探讨 Google Cloud 中可用于实现 AI/ML 工作负载的各种工具。我们首先快速概述一些作为 Google Cloud 上几乎所有工作负载基石的基本 Google Cloud 服务。然后,我们进一步探讨专门用于数据科学和 AI/ML 工作负载的更高级服务。这是本书“基础知识”部分的最后一章,就像前两章一样,它提供了我们在整本书中构建的基础信息。如果您已经了解 Google Cloud 的服务,本章可能有助于巩固这些知识。如果您是 Google Cloud 的新手,本章是您学习过程中的一个重要部分,因为它介绍了本书其他部分假定已知的概念。

为了描述每个工具在数据科学项目中的应用,我们将参考第二章中概述的 ML 模型生命周期步骤。[图 3.1]*显示了一个简化了的 ML 模型生命周期图。实际上,这些步骤的组合可以在模型生命周期中循环重复,但为了简化,我们在此省略这些细节。我们的简化工作流程示例假设每个步骤的输出都是令人满意的,我们可以继续到下一个步骤。它还包括在训练模型步骤中的超参数优化。

图 3.1:简化 ML 模型生命周期

图 3.1:简化 ML 模型生命周期

本章将涵盖以下主题:

  • 为什么选择 Google Cloud?

  • 使用 Google Cloud 工具的先决条件

  • Google Cloud 服务概述

  • Google Cloud 数据处理工具

  • Google Cloud VertexAI

  • Google Cloud 上的标准行业工具

  • 选择合适的工具

让我们从讨论为什么我们最初想要使用 Google Cloud 进行数据科学和 AI/ML 应用场景开始。

为什么选择 Google Cloud?

Google 在 AI/ML 领域已经是一个长期知名领导者。他们通过无数的研究论文、出版物以及向开源社区捐赠 AI/ML 库(如 TensorFlow,有史以来最广泛使用的 ML 库之一)等方式,为 AI/ML 行业做出了大量贡献。他们的搜索和广告算法多年来一直引领着各自的行业,他们的同行组织,如 DeepMind,将他们的全部存在都致力于纯 AI/ML 研究。

Google 还一直在引领诸如道德 AI等倡议,倡导公平性和可解释性的概念,以确保 AI 负有责任,并且仅用于对人类有益的目的。AI/ML 不是 Google 试图利用的东西,而是 Google 商业的核心原则。

Google Cloud 在这个领域的领导地位的一个显著证明是,Gartner 正式将其认定为 2022 年 Gartner® 魔力四边形™ 云 AI 开发服务领域的领导者。Google Cloud 提供了一系列服务和工具,用于实施 AI/ML 用例,并拥抱开源和第三方解决方案,以便为顾客提供尽可能广泛的选择。通过使用 Google Cloud 进行 AI/ML 工作负载,您可以受益于 Google 在这个领域数十年的 AI/ML 研究和积累的专业知识。

使用 Google Cloud 工具和服务的先决条件

这一节将会相当简单,因为 Google Cloud 让尝试其服务变得非常容易。如果您有 Gmail 账户,那么您基本上已经拥有了在 Google Cloud 上开始所需的一切。作为一项慷慨的额外奖励,Google Cloud 向新客户提供 300 美元的信用额度,以及验证其商业电子邮件地址的新客户将获得额外的免费信用额度。您可以使用这些免费信用额度来探索和评估 Google Cloud 的各种服务。此外,Google Cloud 的许多服务提供 免费层,允许您免费使用这些服务,直到达到指定的免费使用限制,具体详情您可以在 Google Cloud 文档中找到(cloud.google.com/free/docs/free-cloud-features)。

如果您需要创建新的 Google Cloud 账户,您可以在 console.cloud.google.com/freetrial 注册,当您需要超出免费使用范围时,您可以升级到付费的 Cloud Billing 账户。

在您创建并登录账户后,您就可以开始使用本书中将要使用的 Google Cloud 服务以及更多服务。当您第一次尝试使用 Google Cloud 服务时,您可能需要启用该服务的 API。这是一个简单的单次点击操作,您只需在每个 Google Cloud 项目中执行一次。图 3.2 展示了您第一次尝试使用 Google Filestore 服务时显示的页面(我们将在本章后面更详细地介绍 Filestore)。您只需点击 启用 按钮即可启用 API。

定义

Google Cloud 项目组织了您所有的 Google Cloud 资源。它包括一组用户;一组 API;以及这些 API 的计费、身份验证和监控设置。所有 Google Cloud 资源,以及访问它们的用户权限,都位于一个项目中。

图 3.2:首次使用时启用 Google Cloud API

图 3.2:首次使用时启用 Google Cloud API

安全、隐私和合规性

当我们创建了我们的谷歌云账户后,首先需要考虑的是安全性。这同样也涉及到隐私和合规性,这些是目前数据分析和人工智能/机器学习行业的热门话题,因为您的客户希望知道他们的数据正在被安全地处理。幸运的是,这些话题是谷歌云的主要优先事项,因此,谷歌云提供了一系列默认控制和专用服务来促进和维持这些优先事项。我们将在本文简要介绍一些重要概念和相关服务,并在本书的后续章节中深入探讨这些话题。

谁有权访问什么?

在安全、隐私和合规性的背景下,首先需要讨论的主题是身份和访问管理;也就是说,识别和控制谁有权访问您的谷歌云环境中的哪些资源。谷歌云为此提供了身份和访问管理IAM)服务。此服务使您能够定义用户和用户组等身份,以及关于访问谷歌云资源的权限。对于在谷歌云上进行的每一次尝试操作,无论是从存储中读取对象还是作为云函数运行一段代码,谷歌云 IAM 都会评估与此操作相关的权限、操作将作用其上的资源以及调用身份,并且只有当所有相关身份和资源都应用了正确的权限组合时,操作才会被允许。为了提供额外的便利,您可以将谷歌云 IAM 与外部身份提供者IdPs)和目录,如 Active Directory 集成。

数据安全

谷歌云默认对所有静态数据进行加密。您可以通过使用客户管理加密密钥CMEKs)来控制用于加密数据的密钥,或者您可以让谷歌云为您管理所有这些功能。至于传输中的数据,谷歌已经建立了具有严格安全控制的全球网络,并使用 TLS 加密来保护在这些全球网络中传输的数据。谷歌云还通过使用基于硬件的可信执行环境TEE)的保密计算,使您能够在数据积极使用时对其进行加密。TEE 是安全且隔离的环境,在数据使用期间防止未经授权的访问或修改应用程序和数据。

基础设施安全

除了 Google Cloud 先进的云基础设施安全控制之外,Google Cloud 还提供工具来帮助防止和检测潜在的安全威胁和漏洞。例如,您可以使用 Cloud Firewall 和 Cloud Armor 来防止 分布式拒绝服务DDoS)和常见的 OWASP 威胁。您可以使用 Chronicle、Security Command Center 和 Mandiant 进行 安全事件和事故监控SIEM)、安全编排自动化和响应SOAR)、入侵检测和威胁情报。除了所有这些 Google Cloud 服务之外,您还可以使用 Google Cloud 上的第三方可观察性和报告服务,如 Splunk。

合规性

Google Cloud 提供审计数据,跟踪在您的环境中对资源执行的操作,这对于合规性原因非常重要。Google Cloud 参与正式的合规性计划,如 FedRamp、SOC2 和 SOC3,并支持如 支付卡行业数据安全标准PCI DSS)和多个 ISO/IEC 国际标准等合规性标准。您可以在 cloud.google.com/security/compliance 查看有关 Google Cloud 合规性计划参与的更多详细信息。

与 Google Cloud 服务交互

您可以通过多种方式与 Google Cloud 服务进行交互。从高层次来看,您可以使用 图形用户界面GUI)、命令行界面CLI)或 API。我们将在本节中更详细地探讨这些选项。

控制台

与 Google Cloud 服务交互的最直接方式之一是通过 Google Cloud 控制台,它提供了一个 GUI。您可以通过 console.cloud.google.com/ 访问控制台。

控制台允许您通过在浏览器中的基于网页的界面中点击来执行 Google Cloud 的操作。例如,您可以通过在产品菜单中点击 Compute Engine 来创建 虚拟机VM),然后转到虚拟机实例页面并点击 创建实例来指定 VM 的所需属性,如图 图 3**.3 所示。

图 3.3:在 Google Cloud 控制台中创建虚拟机

图 3.3:在 Google Cloud 控制台中创建虚拟机

gcloud CLI

如果你更喜欢使用 CLI,Google Cloud 已经构建了一个名为 gcloud 的工具,它允许你通过执行基于文本的命令与 Google Cloud 服务交互。这在你希望通过编写包含多个命令的脚本来自动化一系列 Google Cloud 服务 API 操作时特别有用。例如,你可以创建一个包含多个命令的 Bash 脚本,并且你可以手动执行该脚本,或者如果它包含需要频繁重复执行的操作,你可以按周期性计划执行该脚本。这种方法适用于只需少量努力即可实现的临时自动化。在后面的章节中,我们将探讨在 Google Cloud 上自动化更复杂操作序列的其他方法。

以下是一个 gcloud 命令的示例。此命令将启用 SERVICE_NAME 的 API,其中 SERVICE_NAME 是我们想要交互的 Google Cloud 服务的名称占位符:

gcloud services enable SERVICE_NAME

例如,要启用 Filestore API,而不是点击 gcloud CLI 命令:

gcloud services enable file.googleapis.com

在这种情况下,file 是 Google Cloud Filestore 服务的命令行名称(完整服务名称为 file.googleapis.com)。

要使用 gcloud CLI,你可以在任何你希望运行它的机器上安装它,因为它支持许多不同的操作系统,如 Linux、macOS 和 Windows,或者你可以使用下一节中描述的 Google Cloud Shell。

Google Cloud Shell

Google Cloud Shell 是使用 gcloud CLI 和与 Google Cloud APIs 交互的一种非常方便的方式。这是一个提供基于 Linux 环境的工具,你可以在此环境中向 Google Cloud 服务 API 发送命令。

你可以通过点击 Google Cloud 控制台屏幕右上角的 图标来打开 Cloud Shell,如图 3.4 所示:

图 3.4:激活 Google Cloud Shell

图 3.4:激活 Google Cloud Shell

然后,终端将出现在屏幕底部,如图 3.5 所示:

图 3.5:Google Cloud Shell

图 3.5:Google Cloud Shell

当你第一次尝试使用 Cloud Shell 时,你需要授权它与 Google Cloud 服务 API 交互,如图 3.6 所示。

图 3.6:授权 Google Cloud Shell

图 3.6:授权 Google Cloud Shell

API 访问

与 Google Cloud 服务交互的最底层方法是程序化直接调用它们的 API。这种方法与 GUI 和 CLI 访问不同,因为它不是旨在直接与人类交互,而是适合更高级的使用案例,例如通过您的应用程序软件与 Google Cloud 服务交互。作为一个例子,让我们考虑一个将用户照片保存在云中的应用程序。当新用户注册时,我们可能希望创建一个新的 Google Cloud Storage 存储桶来存储他们的照片,以及其他与注册相关的活动(我们将在本章后面描述 Google Cloud Storage 服务)。为了这个目的,我们可以创建以下 REST API 请求:

curl -X POST --data-binary @JSON_FILE_NAME \
     -H "Authorization: Bearer OAUTH2_TOKEN" \
     -H «Content-Type: application/json» \
     https://storage.googleapis.com/storage/v1/b?project=PROJECT_IDENTIFIER

让我们分解一下:

  • JSON_FILE_NAME 是指定存储桶详细信息的所需 JSON 文件的名称

  • OAUTH2_TOKEN 是调用 API 所需的访问令牌

  • PROJECT_IDENTIFIER 是与我们的存储桶相关联的项目 ID 或编号,例如,my-project

所需的 JSON 文件结构如下:

{
  "name": "BUCKET_NAME",
  "location": "BUCKET_LOCATION",
  "storageClass": "STORAGE_CLASS",
  "iamConfiguration": {
    "uniformBucketLevelAccess": {
      "enabled": true
    },
  }
}

这里的分解如下:

  • BUCKET_NAME 是我们想要给我们的存储桶的名称。

  • BUCKET_LOCATION 是您想要存储您的存储桶对象数据的位置。有关 Google Cloud 位置的更多信息,请参阅以下 Google Cloud 文档:cloud.google.com/compute/docs/regions-zones

  • STORAGE_CLASS 是您存储桶的默认存储类别。有关 Google Cloud 存储类别的更多信息,请参阅以下 Google Cloud 文档:cloud.google.com/storage/docs/storage-classes

在实践中,最常见的是使用 Google Cloud 的客户端 软件开发工具包SDKs)来程序化地创建这样的 API 调用。例如,在下面的 Python 代码中,我们导入 Google Cloud Storage 客户端库,然后定义一个函数来创建一个新的存储桶,指定存储桶名称、位置和存储类别:

# import the GCS client library
from google.cloud import storage
def create_bucket_class_location(bucket_name):
    """
    Create a new bucket in the US region with the coldline storage
    class
    """
    # bucket_name = "your-new-bucket-name"
    storage_client = storage.Client()
    bucket = storage_client.bucket(bucket_name)
    bucket.storage_class = "COLDLINE"
    new_bucket = storage_client.create_bucket(bucket, location="us")
    return new_bucket

现在我们已经介绍了一些如何与 Google Cloud 服务交互的基础知识,让我们讨论一下本书中将使用的 Google Cloud 服务类型。

Google Cloud 服务概述

在介绍了如何设置 Google Cloud 账户以及如何启用和交互各种服务的基础知识之后,我们现在将介绍本书中将要使用的服务,以创建 AI/ML 工作负载。我们将首先介绍几乎所有工作负载都基于的基本云服务,然后我们将介绍与数据科学和 AI/ML 相关的更高级服务。

Google Cloud 计算服务

考虑到单词 computing 直接包含在术语 云计算 中,以及计算服务构成了所有其他云服务的基础,我们将从这个部分开始,简要概述 Google Cloud 的计算服务。

Google 计算引擎(GCE)

几年前,云计算这个术语几乎与虚拟化这个术语同义。传统上,公司在自己的场所拥有物理服务器,然后与之形成对比的是在云中创建虚拟服务器,无论是公共的还是私有的。因此,在云计算中,最容易理解的概念可能是虚拟化,我们通过在硬件和我们的服务器操作系统之间引入一个称为虚拟机的抽象层,简单地创建一个虚拟服务器而不是物理服务器,如图3**.7所示。对于大多数公司来说,如果他们已经在运行物理服务器,那么他们进入云计算世界的第一步通常是通过使用虚拟机来实现的,因为这是从物理范式过渡到云范式最简单的一步。Google 计算引擎GCE)是 Google 云在云中运行虚拟机的服务。它提供了一些有用的功能,例如基于需求的自动扩展,这是云计算已确立的众多好处之一。

图 3.7:示例虚拟机实现

图 3.7:示例虚拟机实现

Google Kubernetes 引擎(GKE)

在 2000 年代,通过使用 Linux cgroupsNamespaces 来隔离运行操作系统中特定进程的计算资源,如 CPU、RAM 和存储资源,创建了一种新型的虚拟化技术。随着容器化的出现,抽象层在堆栈中的位置上升,存在于操作系统和我们的应用程序之间,如图3**.8所示。

图 3.8:示例容器实现

图 3.8:示例容器实现

这为我们带来了比基于虚拟机的虚拟化所提供的更多有趣的好处。例如,容器通常比虚拟机小得多,更轻量级,这意味着它们包含的软件组件要少得多。虚拟机必须在启动整个操作系统和大量软件应用程序之后才能变得可用,这可能需要几分钟的时间,而容器通常只包含你的应用程序代码和任何所需的依赖项,因此可以在几秒钟内加载。这在自动扩展和自动修复基于云的软件工作负载时产生了重大差异。与突然增加的流量相关的新虚拟机的启动可能不够快,你可能会在虚拟机启动并加载你的应用程序时丢失一些请求。同样,由于某种问题重新启动虚拟机也是如此。在这两种情况下,容器通常会启动得更快。包含更少的组件也意味着容器可以部署得更快,这使得它们成为具有 DevOps CI/CD 管道的微服务的完美环境。容器还有许多其他好处,例如可移植性和易于管理。

然而,容器化带来的挑战之一也源于它们的轻量级特性。因为它们通常比虚拟机小,所以在单个应用程序部署中拥有更多的容器是很常见的。管理大量的微型容器可能具有挑战性,尤其是在应用程序生命周期管理和编排方面;也就是说,确定如何以及在哪里运行您的负载,并分配足够的计算资源给它们。这正是 Kubernetes 发挥作用的地方。以下是对 Kubernetes 以及特别针对Google Kubernetes EngineGKE)的官方定义。

Kubernetes,也称为K8s,是一个开源系统,用于自动化容器化应用程序的部署、扩展和管理。它将构成应用程序的容器组合成逻辑单元,以便于管理和发现。GKE 提供了一个使用 Google 基础设施部署、管理和扩展容器化应用程序的托管环境。

图 3.9展示了 Kubernetes 如何组织和编排应用程序的示例。它将您的应用程序部署为 Pod,Pod 是由具有相似功能的容器组成的组,并在您的硬件服务器或宿主操作系统上部署代理,以跟踪资源利用率并将该信息反馈给 Kubernetes 主节点,Kubernetes 主节点使用这些信息来管理 Pod 部署。

图 3.9:示例 GKE 实现(来源:https://kubernetes.io/docs/concepts/architecture/)

图 3.9:示例 GKE 实现(来源:https://kubernetes.io/docs/concepts/architecture/)

Google Cloud 无服务器计算

在云计算的上下文中,无服务器一词指的是在云提供商的基础设施上运行您的代码,而不需要管理任何用于运行您的代码的服务器。实际上,仍然有服务器在幕后被使用,但云提供商代表您创建和管理这些服务器,这样您就不需要执行这些操作。Google Cloud 有两个与无服务器计算相关的核心服务,分别命名为云函数云运行。另一个名为App Engine的 Google Cloud 服务也经常被归类在无服务器范畴之下,我们将在本节稍后描述该服务,以及它与云函数和云运行的区别。

注意

许多其他 Google Cloud 服务也以无服务器的方式运行,即它们代表您执行的操作在后台管理的服务器上运行,您无需管理这些服务器。然而,云函数和云运行是两个与无服务器计算相关的 Google Cloud 服务,这特别指的是运行您的代码而不需要明确管理服务器。

云函数

使用云函数,您只需编写小段代码——例如,一个单独的函数——谷歌云将根据您指定的触发器运行该代码。您不需要管理任何容器、服务器或您的代码执行的任何基础设施,并且您可以配置许多类型的触发器。例如,每当文件上传到您的谷歌云存储桶时,这可能会触发您的代码片段执行。然后,您的代码可以以某种方式处理该文件,将其输入到另一个谷歌云服务进行处理,或者简单地发送通知告知某人文件已上传。

这个概念被称为函数即服务FaaS),因为它通常用于为每个事件触发执行单个函数。这种方法适用于您只想简单地编写和运行响应您环境中发生的事件的小代码片段时。您还可以使用云函数连接到其他谷歌云或第三方云服务,以简化复杂的编排问题。

除了让您免于管理服务器的麻烦之外,使用云函数的另一个优点是,当您的环境中没有事件发生时,您不需要为服务器付费。

Cloud Run

Cloud Run 是一种更适合长时间运行的应用程序进程的无服务器计算服务。虽然云函数旨在响应特定事件运行小段代码,但 Cloud Run 可以运行更复杂的应用程序。这也意味着它提供了更多关于代码执行方面的灵活性和控制。例如,它将在容器中运行您的代码,并且您对这些容器中执行的内容有更多的控制。如果您的应用程序需要自定义软件包依赖项,例如,您可以将这些依赖项配置为在容器中可用。

Cloud Run 通过自动从零几乎瞬间扩展和缩减,根据流量进行管理,并且只对您使用的确切资源收费,从而抽象化了所有基础设施管理。

App Engine

虽然 App Engine 也可以被视为一种无服务器服务,因为它为您管理底层基础设施,但其用例与 Cloud Functions 和 Cloud Run 不同。App Engine 有两个服务级别,称为 标准灵活。在标准环境中,您的应用程序在一个沙盒内的轻量级服务器上运行。这个沙盒限制了您的应用程序可以执行的操作。例如,沙盒只允许您的应用程序使用有限的一组软件二进制库,并且您的应用程序不能写入永久磁盘。标准环境还限制了应用程序可用的 CPU 和内存选项。由于这些限制,大多数 App Engine 标准应用程序通常是无状态的 Web 应用程序,能够快速响应 HTTP 请求。相比之下,灵活环境在 Google Compute Engine 虚拟机上运行您的应用程序,这些虚拟机具有较少的限制。

此外,请注意,标准环境可以从零实例快速扩展到数千个实例,但灵活环境必须至少运行一个实例,并且可能需要更长的时间来响应突增的流量。

App Engine 通常适用于大型网络应用程序。其灵活的环境可以比 Cloud Run 更具可定制性。然而,如果您想部署一个无需管理底层基础设施的长期运行的网络应用程序,我建议首先评估 Cloud Run 是否能满足您的应用程序需求,并比较在 Cloud Run 上运行应用程序与在 App Engine 上运行的成本。

Google Cloud 批处理

一些工作流程旨在长时间运行,无需人工交互。这类工作负载的例子包括媒体转码、计算流体动力学、蒙特卡洛模拟、基因组处理和药物发现等。这类工作负载通常需要大量的计算能力,可以通过并行运行任务来优化。自行创建和运行这些作业可能会产生一些开销,例如管理服务器、排队机制、并行化和故障逻辑。幸运的是,Google Cloud 批处理服务已经构建好以管理您所需的所有这些活动。作为一个完全管理的作业调度器,它自动调整运行批处理作业所需的基础设施规模,并处理您在执行过程中配置的并行化和重试逻辑,以防出现任何错误。

现在我们已经介绍了 Google Cloud 上的主要计算服务,让我们回顾一下您可以使用它们在 Google Cloud 之间进行集成的服务。

Google Cloud 集成服务

除了计算和存储等 Google Cloud 基础设施服务之外,我们通常还需要实现服务之间的集成,以便创建复杂的工作负载。Google Cloud 为此目的创建了专门的工具,我们将在本节中简要讨论一些相关的工具。

Pub/Sub

Google Cloud Pub/Sub 是一种消息服务,可用于在系统架构的组件之间传递数据,无论这些组件是其他 Google Cloud 服务、第三方服务还是您自己构建的组件。这是一个极其灵活的服务,可用于广泛的系统集成用例,例如解耦微服务或将数据流式传输到数据湖。

Pub/Sub 与发布和订阅的系统架构概念相关,其中一个系统可以向共享空间或主题发布一条消息或数据,然后其他系统可以通过订阅该主题来接收该数据。消息可以通过推送拉取机制进行传递。在推送方法的情况下,Pub/Sub 服务与订阅者系统建立通信,并将消息发送到这些系统。在拉取模型的情况下,订阅者系统与 Pub/Sub 服务建立通信,然后从 Pub/Sub 服务请求或拉取信息。

Pub/Sub 还满足了一些细微的消息需求,例如按顺序发布消息(如果需要)和重试失败的消息传输。Google Cloud 还提供了一种名为 Pub/Sub Lite 的产品,它是一种比常规 Pub/Sub 产品功能更少、成本更低的选项。

Google Cloud Tasks

与 Pub/Sub 类似,Google Cloud Tasks 是一种可用于实现消息传递和异步系统集成的服务。在 Pub/Sub 中,发布者和订阅者是完全解耦的,它们对彼此的实现没有控制权。另一方面,在 Cloud Tasks 中,发布者(或任务生产者)完全控制工作负载的整体执行。它可以专门用于任务生产者需要控制特定 webhook 或远程过程调用执行时间的情况。Cloud Tasks 包含在本节中是为了完整性,因为它是 Pub/Sub 在某些用例中的替代方案,但我们在本书中不会使用 Cloud Tasks。

Eventarc

Eventarc 是一种 Google Cloud 服务,使您能够构建事件驱动的工作负载。这是希望其工作负载在环境中的事件发生时执行的公司常用的模式。当我们介绍 Cloud Functions 时,我们简要地提到了这个话题。Cloud Functions 可以由某些事件源直接触发,但 Eventarc 提供了更多的灵活性和控制,以实现复杂的事件驱动架构,与 Cloud Functions 和其他 Google Cloud 服务以及一些第三方应用程序一起使用。

Eventarc 使用 Pub/Sub 将来自 事件提供者 的消息路由到 事件目的地。正如其名称所暗示的,事件提供者将事件发送到 Eventarc,Eventarc 将事件发送到事件目的地。它提供了一种标准化您的事件处理架构的方法,而不是在您的各种系统组件之间构建随机、临时的基于事件的实现。

工作流程

虽然 Eventarc 提供了一种标准化事件驱动工作负载的机制,但 Google Cloud Workflows,正如其名称所暗示的,是一种专门构建来编排复杂工作流程的服务,在这些工作流程中,需要按照特定顺序实现不同系统之间活动的协调。考虑到这一点,当一起使用时,Google Cloud Workflows 和 Eventarc 是实现复杂、事件驱动工作负载的绝佳组合。工作流程可以由事件触发,或者您可以创建可以以不同方式触发的批量工作流程。

工作流程可以在各种微服务和自定义或第三方 API 之间协调活动。工作流程服务在执行过程中维护您工作负载中每个步骤的状态,这意味着它跟踪每个步骤的输入和输出,并且知道哪些步骤已经完成,哪些步骤正在执行,以及哪些步骤需要在工作流程中调用。它允许您可视化工作流程的所有步骤及其依赖关系,如果在过程中任何步骤失败,您可以使用工作流程服务来确定是哪个步骤,并确定下一步要做什么。图 3.10 展示了在线零售系统的工作流程示例,其中客户购买了一件商品。工作流程中的每个软件服务都使用各种 Google Cloud 计算产品运行,每个步骤的协调都由工作流程服务管理。虽然这是一个简单的订单处理工作流程示例,但请注意,大多数大型零售公司都与由极其复杂的互联系统和合作伙伴组成的供应链合作。

图 3.10:在线零售系统的工作流程示例

图 3.10:在线零售系统的工作流程示例

工作流程服务最适合在服务之间编排活动。如果您想实现数据工程的工作流程编排,那么 Google Cloud Composer 可能更合适。我们将在本章后面讨论 Google Cloud Composer。

调度器

Google Cloud Scheduler 是一种相对简单但非常有用的服务,可以用于根据计划执行工作负载。例如,如果您希望一个进程每天、每小时或每月在同一时间运行,您可以使用 Cloud Scheduler 定义并启动这些执行。任何熟悉基于 Unix 的操作系统的您可能会看到与 cron 服务的相似之处。

Google Cloud Scheduler 可以与我们在本节中描述的许多集成服务一起使用。例如,你可以安排每 15 分钟向 Pub/Sub 主题发送一条消息,然后可以将其发送到 Eventarc 并用于调用云函数。

网络和连接

几乎没有工作负载不需要设置某种形式的网络连接。例如,即使你只有一个服务器,你也通常需要以某种方式连接到它,才能对其执行任何操作。当你扩展到单个服务器之外时,那些服务器通常需要相互通信。在本节中,我们将讨论构建本书后续章节中工作负载的基础网络和连接概念。

虚拟专用云(VPC)

本节中我们首先介绍的概念是虚拟专用云VPC)概念。VPC 是一个可以跨越所有谷歌云区域的虚拟网络。之所以称为虚拟专用云,是因为它定义了你的网络基础设施的边界,因此你在谷歌云中运行工作负载的位置。然而,你可以与其他 VPC 进行对等或共享连接,以便跨 VPC 边界进行通信。

混合网络

如果你为一家拥有自己的本地服务器和网络的公同工作,并且你想将它们连接到云端,这被称为混合连接性。这对于许多公司来说是一个常见需求,因此,谷歌云已经创建了特定的解决方案来促进这种连接,这些解决方案包括以下服务。

专用互连

专用互连为你的本地网络和谷歌的网络之间提供直接的物理连接。它提供 99.99%的保证正常运行时间,并且可以连接一个或两个链路,每个链路都可以支持高达 100 千兆比特每秒Gbps)的带宽。它需要在特定的专用互连位置设置硬件连接,因此可能需要相当大的努力来设置。此选项适用于需要在其场所和谷歌云之间进行长期连接的高带宽网络的公司。

合作伙伴互连

如果你没有在专用互连位置之一建立自己的基础设施,那么有一些谷歌云合作伙伴提供高达 99.99%可用性的连接服务,即合作伙伴互连。此选项也需要与合作伙伴合作以设置它,但它不需要与专用互连相同的投资。一种权衡是,合作伙伴通常将连接共享给许多客户,因此带宽低于专用互连。

本地部署的私有谷歌访问(PGA)

这是一个基本的连接选项,它从你的本地位置直接提供对谷歌服务(如云存储和 BigQuery)的访问。

虚拟专用网络(VPN)

将您的本地资源连接到 Google Cloud VPC 可能最简单的方式是通过虚拟专用网络VPN),它使用IP 安全IPsec)机制提供了一种低成本选项,通过加密的公共互联网连接提供 1.5 – 3.0 Gbps 的吞吐量。与之前提到的 Interconnect 服务不同,此选项不需要在任何特定位置进行任何特殊、与硬件相关的网络连接。

现在我们已经介绍了支撑我们在本书中构建的工作负载的基本 Google Cloud 服务,现在是时候深入探讨我们将直接用于创建我们的数据处理工作负载以准备我们的 AI/ML 用例的服务了。

Google Cloud 数据存储和处理工具

由于收集数据是 AI/ML 项目中的第一个主要步骤(在确定项目的业务目标之后),我们首先通过回顾存储和处理数据的工具来探索 Google Cloud 的 AI/ML 相关服务。图 3.2显示了与摄取、存储和处理数据相关的生命周期步骤。需要注意的是,训练模型评估模型监控模型步骤通常也会创建需要存储的输出。

图 3.11:数据摄取、存储、探索和处理

图 3.11:数据摄取、存储、探索和处理

图 3.11所示,并且正如我们之前讨论的,与数据打交道是任何 AI/ML 项目的一个非常突出的部分。

数据摄取

在我们能够在 Google Cloud 中对数据进行任何操作之前,我们需要获取数据,并且我们通常希望将数据摄取到 Google Cloud 上的某种存储服务中。在本节中,我们将讨论 Google Cloud 上用于摄取数据的某些工具,在下一节中,我们将介绍摄取服务所摄取数据的 Google Cloud 存储系统。在本章中,我们不会关注 Google Cloud 的数据库服务,也不会涉及相关的数据库迁移服务DMS),因为在机器学习的目的下,我们通常会从数据库中提取数据并将其放置在本节描述的某个存储系统中。对此的一个例外可能是 Google Cloud Bigtable,但我们将单独在稍后的章节中讨论该服务。

gsutil

将数据传输到Google Cloud StorageGCS)或 GCS 存储桶之间可能最简单的方式是通过 gsutil 命令行工具,它可以用来通过简单的命令传输高达 1 TB 的数据。

数据传输服务

如果您要传输超过 1 TB 的数据,可以使用数据传输服务,该服务可以从本地系统或其他公共云提供商快速且安全地传输数据。对于可能需要运行多个数据传输作业的大型数据迁移项目,它允许您集中管理作业以监控每个作业的状态。您可以通过高达数十 Gbps 的带宽传输包含数十亿文件的 PB 级数据,数据传输服务将优化您的网络带宽以加速传输。您可以将数据导入 GCS,然后让其他 Google Cloud 服务从那里访问它。

BigQuery 数据传输服务

BigQuery 数据传输服务自动化了数据在 BigQuery 中的特定移动,以计划和管理为基础。您可以通过 Google Cloud 控制台、bq 命令行工具或 BigQuery 数据传输服务 API 访问 BigQuery 数据传输服务。它支持许多数据源,例如 GCS、Google Ads、YouTube、Amazon S3、Amazon Redshift、Teradata 以及更多。

数据存储

在 Google Cloud 中存储数据有许多不同的方式,您选择的数据存储工具和服务类型将取决于您的用例和您试图实现的目标。在本节中,我们将探讨 Google Cloud 在数据存储领域提供的不同产品和服务的类型,以及它们最适合的工作负载。

概念 - 数据仓库、数据湖和湖屋

在深入了解每个主要的 Google Cloud 数据存储服务之前,讨论数据仓库、数据湖和湖屋的概念非常重要,这些术语在近年来在业界变得相当流行。

数据仓库通常包含针对分析目的优化的结构化数据格式,例如 Parquet优化行列存储ORC)。这是因为数据分析查询通常在数据库列上而不是行上操作。例如,我们可能运行一个查询来找出购买我们产品的客户的平均年龄,因此这个查询将专注于我们客户数据库表中的 年龄 列。列式数据格式将每个列的所有元素在物理存储磁盘上彼此靠近存储,因此操作数据库列的查询运行得更高效。

如其名所示,数据湖是一个可以以各种格式存储大量数据的存储库,包括结构化和非结构化数据。由于没有关于查询优化的具体要求,数据湖通常可以存储比数据仓库多得多的数据。数据湖是打破我们在 第二章 中描述的问题数据孤岛的关键组成部分,并且可以作为您数据管理策略的基础。

术语数据湖屋指的是最近出现的模式,其中公司利用数据仓库和数据湖的组合,以获得两者的最佳效果,并支持更广泛的用例,如实时分析、批量数据处理、机器学习和可视化,所有这些都可以从同一来源进行。

Google Cloud Storage (GCS)

除了 Google Compute Engine 之外,Google Cloud StorageGCS)是 Google Cloud 中最基础的服务之一。它支持所谓的对象存储,可能是 Google Cloud 中所有存储服务中最灵活的,因为您几乎可以在 GCS 中存储任何类型的数据,并且可以直接从处理数据的几乎所有 Google Cloud 服务中访问它。它特别适合大量数据,并且可以用作构建企业数据湖的基础。

GCS 提供不同的存储类别,根据成本和访问频率优化您的使用。对于您不经常访问的对象,您可以将其放入成本更低的存储类别,甚至可以配置 GCS 根据每个对象的年龄等标准自动在存储类别之间移动您的对象。有关每个不同存储类别的更多信息以及哪个最适合不同的用例,请参考cloud.google.com/storage/docs/storage-classes中的表格。

Filestore

Google Cloud Filestore 服务是一种高性能、完全管理的文件存储服务,用于需要结构化文件系统的作业。这是网络附加存储的概念,其中您的虚拟机和容器可以挂载共享文件系统,并可以访问和操作共享目录结构中的文件。它使用网络文件系统版本 3NFSv3)协议,并支持任何 NFSv3 兼容客户端。

Filestore 提供三种不同的格式:

  • Filestore Basic,最适合文件共享、软件开发和网站托管

  • Filestore Enterprise,最适合关键应用,如 SAP 工作负载

  • Filestore High Scale,最适合高性能计算,包括基因组测序、金融服务交易分析和其他高性能工作负载

对共享文件系统的访问取决于您配置的权限以及您使用本章“网络和连接”部分中讨论的产品设置的联网连接性。

持久磁盘

到目前为止,我们已经介绍了对象存储和文件存储。另一种存储类型被称为块存储。这种存储类型可能最为熟悉,因为它是由直接连接到计算机的磁盘使用的传统存储类型;也就是说,直接附加存储DAS)。例如,您的笔记本电脑中的硬盘驱动器使用这种类型的存储。在公司自己的本地数据中心中,许多服务器可能连接到称为存储区域网络SAN)的共享块存储设备,使用我们在第一章中简要讨论的共享 RAID 数组配置类型。在任一情况下,这些块存储设备都似乎在我们的服务器操作系统中被视为直接附加的磁盘,并且它们被我们的服务器或容器中的应用程序用作此类磁盘。

SANs 可能需要大量的设置和维护工作,但使用 Google Cloud Persistent Disk 时,您只需简单地定义您想要的磁盘存储类型和所需容量,所有底层基础设施都由 Google 为您管理。

在高层次上,Persistent Disk 提供两种不同的存储类型,即硬盘驱动器HDDs)和固态驱动器SSDs)。当大量吞吐量是首要考虑时,HDDs 提供低成本存储。SSDs 提供高性能和速度,适用于随机访问工作负载和大量吞吐量。这两种类型都可以扩展到 64 TB。

BigQuery

Google Cloud BigQuery 是一个无服务器数据仓库,这意味着您可以在不配置或管理任何服务器的情况下使用它。作为一个数据仓库,它跨越存储和处理。它可以以优化数据分析工作负载的格式存储您的数据,并提供允许您在该数据上运行 SQL 查询的工具。您还可以使用它来对其他存储系统(如 GCS、Cloud SQL、Cloud Spanner、Cloud Bigtable)以及 AWS 或 Azure 上的存储系统运行查询。此外,它还提供了内置的机器学习功能,允许您通过 SQL 查询从数据中获得机器学习推断,而无需使用其他服务。另一方面,如果您明确想要使用其他服务,例如我们将在本章后面描述的 Vertex AI,它可以轻松地与其他许多 Google Cloud 服务集成。

它支持地理空间分析,因此您可以通过添加位置数据来增强您的分析工作流程,并且当您将流式处理解决方案(如 Dataflow)与 BigQuery BI Engine 集成时,它还支持对流数据的实时分析。BI Engine 还与 Looker Studio 原生集成,并支持许多商业智能工具。BigQuery 是 Google Cloud 上极受欢迎的服务,您将在本书中学习如何使用其许多功能。

在您将数据存储在谷歌云之后,您通常会希望对其进行组织和管理工作,以便它可以轻松被发现并有效利用。在下一节中,我们将讨论谷歌云的数据管理工具。

数据管理

我们在本节中描述的服务使您能够组织您的数据,并使您的数据更容易被组织内的用户发现和访问,从而打破或预防数据孤岛。这些工具作为我们之前章节中讨论的数据存储服务和支持层之间的一个支持层,以及我们将在本章后续部分讨论的数据处理服务。

BigLake

BigLake 是一种存储引擎,通过允许 BigQuery 和如 Spark 等开源框架以细粒度访问控制访问数据,统一了数据仓库和数据湖。例如,您可以将数据存储在 GCS 中,并将其作为 BigLake 表提供,然后您可以从 BigQuery 或 Spark 访问这些数据。细粒度访问控制意味着您可以在表、行和列级别控制对数据的访问。例如,您可以确保您的数据科学家可以看到除信用卡信息列之外的所有列,或者您可以确保特定地理位置的销售部门只能看到与该地理位置相关的行,而无法看到与任何其他地理位置相关的数据。

BigLake 允许您在数据存储的任何位置和方式上执行分析,无论使用的是您偏好的分析工具——开源或云原生——都可以在单一份数据副本上操作。这一点很重要,因为它意味着您不需要在您的数据湖和数据仓库之间移动数据,这通常既费时又昂贵。BigLake 还支持如 Apache Spark、Presto 和 Trino 等开源引擎,以及 Parquet、Avro、ORC、CSV 和 JSON 等开放格式,通过 Apache Arrow 为多个计算引擎提供服务。您可以在一个地方集中管理数据安全策略,并确保它们在多个查询引擎以及使用 BigQuery Omni 时在多个云中一致执行。它还可以与我们将要描述的谷歌云 Dataplex 集成,以增强这一功能并提供大规模的统一数据治理和管理。

Dataplex

Google 将 Dataplex 称为“一种智能数据布料,它使组织能够集中发现、管理、监控和治理其跨数据湖、数据仓库和数据集市的数据,并具有一致的控制。”这关系到打破数据孤岛的概念。在 第二章 中,我们讨论了数据孤岛是公司在执行数据科学任务时遇到的常见挑战,以及当你拥有多个由公司内不同组织拥有的数据集时,管理谁可以安全访问数据的复杂性。Dataplex 通过启用数据发现,提供一个跨数据孤岛的数据管理单一视角,以及集中式安全和治理来帮助克服这些挑战。这意味着你可以在 Dataplex 中定义安全和治理策略,并以一致的方式应用于由其他系统存储和访问的数据。它集成了其他 Google Cloud 数据管理服务,如 BigQuery、Cloud Storage 和 Vertex AI。

使用 Dataplex 的理念是创建一个 数据网格,在这个网格中,你的各种数据存储和数据处理系统之间存在逻辑连接,而不是孤立的数据孤岛。它还利用 Google 的 AI/ML 能力提供额外的功能,例如自动数据生命周期管理、数据质量执行和血缘跟踪(你可能还记得,在 第二章 中,我们也讨论了血缘跟踪是公司在实施数据科学工作负载时面临的困难且常见的挑战)。

Google Cloud 最初有一个名为 Data Catalog 的独立服务,可以用来存储关于你各种数据集的元数据,因此通过允许你查看和搜索元数据来提供可发现性,以了解哪些数据集可用。这项服务现在包含在 Dataplex 中,甚至可以自动化数据发现、分类和元数据丰富。然后,它可以使用 Dataplex 湖和数据区域的概念,将存在于多个存储服务中的数据进行逻辑组织,进入业务特定的领域。

Dataplex 还通过其 无服务器数据探索工作台 提供一些数据处理功能,该工作台提供一键访问 Spark SQL 脚本和 Jupyter 笔记本,允许你交互式地查询你的数据集。工作台还允许团队发布、共享和搜索数据集,从而实现跨团队的发现性和协作。

谈到数据处理,我们下一节将介绍一些在 Google Cloud 上处理数据的初级工具和服务。

数据处理

当你使用我们在上一节中讨论的一些服务来存储、组织和管理工作负载时,你可能还希望以某种方式处理这些数据。幸运的是,Google Cloud 中有许多工具和服务可以用于此目的,我们将在下面探讨它们。

Dataproc

Dataproc 是一个完全托管且高度可扩展的服务,用于运行 Apache Hadoop、Apache Spark、Apache Flink、Presto 以及 30 多个开源工具和框架。因此,它在 Google Cloud 上非常受欢迎,尤其是在偏好开源工具的数据处理工作负载中;你可以自己管理处理你数据的服务器,或者 Dataproc 也提供无服务器选项,在这种情况下,Google 将为你管理所有服务器。人们有时会想自己管理服务器,如果他们想使用自定义配置或自定义工具的话。Dataproc 还集成了其他 Google 工具,如 BigQuery 和 Vertex AI,以满足灵活的数据管理需求和数据科学项目,并且你可以使用 Dataproc、BigLake 和 Dataplex 强制执行细粒度的行和列级访问控制。你也可以使用现有的 Kerberos 和 Apache Ranger 策略来管理和强制执行用户授权和身份验证,并且它提供了内置的 Dataproc Metastore,从而消除了运行自己的 Hive Metastore 或目录服务的需要。

管理你自己的本地 Hadoop 或 Spark 集群可能需要大量工作。Dataproc 的一个优点是你可以轻松地按需启动集群以运行数据处理工作负载,然后在你不再使用它们时自动关闭它们,并且集群可以自动扩展和缩减以满足你的需求,这有助于节省成本。你也可以使用 Google Compute Engine Spot 实例进一步节省可以容忍中断的工作负载的成本。你可以在虚拟机或容器中运行你的工作负载,并且它还支持 GPU,如果你需要在数据处理工作负载中使用它们的话。

Dataprep

Trifacta 的 Dataprep 是一个用于可视化探索、清理和准备结构化和非结构化数据以供分析、报告和机器学习的工具。它是无服务器的,因此无需部署或管理任何基础设施。它是数据科学项目数据探索阶段的一个非常有用的工具,使您能够通过可视化的数据分布来探索和理解数据,并自动检测模式、数据类型、可能的连接以及缺失值、异常值和重复值等异常。然后,您可以定义一系列转换来清理和准备您的数据,以便训练机器学习模型。您可以通过可视化操作完成所有这些操作,无需编写任何代码,并且它甚至建议您可能希望实施的各种转换类型,例如聚合、转置、非转置、连接、并集、提取、计算、比较、条件、合并、正则表达式等等。您还可以应用数据质量规则以确保您的数据满足质量要求,并允许团队通过共享或按需复制数据集来协作。

数据流

为了讨论 Google Cloud Dataflow,我们首先花一分钟介绍 Apache Beam。在本书的前几节和章节中,我们提到了批处理数据,其中大量数据通过长时间运行的工作进行处理,以及流处理数据,其中小数据块被非常快速地处理,通常是在实时或接近实时。通常,每种处理类型都有不同的工具。例如,您可能使用 Hadoop 进行批处理,而您可能使用 Apache Flink 进行流处理。Apache Beam 提供了一个统一的模型,可以用于批处理和流式工作负载。用 Apache Beam 项目管理委员会的话说,这允许您“一次编写,到处运行。”这非常有用,因为它使您的数据工程师能够通过使用这个统一的模型来简化他们编码数据处理工作负载的方式,而不是为他们的批处理和流式用例使用完全不同的工具和代码。

Google Cloud Dataflow 是一个完全托管、无服务器的服务,用于执行 Apache Beam 管道。一旦您将数据处理步骤定义为 Apache Beam 管道,然后您可以使用您首选的数据处理引擎,例如 Spark、Flink 或 Google Cloud Dataflow 来执行管道步骤。作为一个完全托管的服务,Dataflow 可以自动配置和扩展运行数据处理步骤所需的资源,并且它与 BigQuery 等工具和服务集成,使您能够使用 SQL 访问您的数据,以及 Vertex AI 笔记本用于机器学习模型训练用例。

Looker

Looker 是谷歌云的企业智能平台,具有嵌入式分析功能。其主要优势之一是 LookML,这是一种基于 SQL 的强大建模语言。您可以使用 LookML 作为版本控制的数据模型集中定义和管理业务规则和定义,然后 LookML 可以代表您创建高效的 SQL 查询。作为一个企业智能工具,Looker 提供了一个用户界面,您可以在其中以图表、图表和仪表板的形式可视化您的数据。

它提供几种不同的服务级别,提供不同层次的企业智能功能。谷歌最初有一个名为数据工作室的企业智能工具,而 Looker 是由另一家公司创建的,但谷歌收购了那家公司,并将 Looker 整合到其云服务组合中。他们还将原始的数据工作室产品整合到 Looker 中,创建了 Looker Studio,并增加了一个企业版工具,名为 Looker Studio Pro,它提供了额外的功能以及客户支持。

数据融合

为了讨论数据融合,让我们首先谈谈ETLELT的概念,分别代表提取、转换、加载提取、加载、转换。ETL 概念自 20 世纪 70 年代以来一直存在,它是数据科学和数据工程中在需要对数据进行转换时使用的一种常见模式。在这种情况下使用的模式是从数据源存储位置提取数据,以某种方式对其进行转换,然后将其加载到所需的存储位置。转换的例子可能包括将数据格式从 CSV 转换为 JSON,或者删除包含缺失信息的所有行。复杂的数据工程项目可能需要创建定义多个转换步骤的 ETL 管道。另一方面,ELT 近年来在云基础数据处理工作负载中获得了流行,特别是在与云基础数据处理工作负载相关的情况下。ELT 的想法是,您可以从源位置提取数据并将其加载到数据湖或数据仓库中,然后根据项目需求执行不同的转换。这通常也被称为数据集成。使用这种方法可以使分析师能够使用 SQL 从数据中获得洞察和价值,而无需数据工程师创建复杂的 ETL 管道。

考虑到这一点,数据融合是谷歌云的无服务器产品,允许您运行 ETL/ELT 工作负载,而无需管理任何服务器或基础设施。它提供了一个可视化界面,使您能够在不编写代码的情况下定义数据转换步骤,这使得非技术分析师处理数据变得容易,并且它甚至跟踪我们讨论过的非常重要的数据血缘,即第二章,随着您的数据通过每个转换步骤。

数据融合与 Google Cloud 的其他服务集成,例如 BigQuery、Dataflow、Dataproc、Datastore、Cloud Storage 和 Pub/Sub,这使得在这些服务之间执行数据处理工作流程变得容易。

Google Cloud Composer

Composer 是基于开源 Apache Airflow 项目构建的 Google Cloud 编排服务,它特别适用于数据集成或数据处理工作负载。与数据融合类似,它集成了其他 Google Cloud 服务,如 BigQuery、Dataflow、Dataproc、Datastore、Cloud Storage 和 Pub/Sub,这使得在这些服务之间编排数据处理工作流程变得容易。

它具有高度的可扩展性,并且可以用于在多个云提供商和本地位置实施工作负载。它通过使用有向无环图DAGs)来编排工作流程,这些图表示工作流程需要执行的任务,以及它们之间所有的关系和依赖。

与 Google Cloud Workflows 类似,Composer 监控工作负载中任务的执行情况,并跟踪每个步骤是否正确完成或是否发生了任何问题。图 3.12展示了 Google Cloud Composer 编排的一个工作流程示例,其中客户订单数据定期从 Cloud Bigtable 导入到 Cloud Dataproc,并使用第三方提供商提供的关于更广泛零售趋势的数据进行丰富,这些数据通过 Google Cloud Storage 提供。然后,输出存储在 BigQuery 中以供分析。这些数据可以用来在 Looker 中构建业务智能仪表板,或者例如在 Vertex AI 中训练机器学习模型。

图 3.12:数据处理工作流程

图 3.12:数据处理工作流程

图 3.12所示,当我们处理和存储我们的数据后,我们可能想使用它来训练一个机器学习模型。在我们开始训练自己的模型之前,让我们探索一些我们可以在 Google Cloud 上使用的 AI/ML 能力,这些能力提供了由 Google 训练的模型。

Google Cloud AI 工具和 AutoML

在本节中,我们将介绍 Google Cloud 的 AI 工具,这些工具可以用于实现 AI 用例,而无需了解底层机器学习概念。使用这些服务,您只需向 API 发送请求,就可以从由 Google 创建和维护的 ML 模型中获得响应。无需手动预处理数据,训练或超调机器学习模型,或管理任何基础设施。

我们将这些服务分为以下几类:自然语言处理NLP)、计算机视觉发现

注意

在撰写本文时,即 2023 年 1 月,Google 还宣布了一个名为 Timeseries Insights API 的服务的预览版,该服务可以用于实时分析您的时序数据集并获取洞察,适用于时序预测或检测数据在发生时的异常和趋势。这是一个有趣的新服务,因为对数十亿个时序数据点进行预测和异常检测工作负载是计算密集型的,而大多数现有系统将这些工作负载作为批量作业实现,这限制了您在线可以执行的分析类型,例如根据数据值的突然增加或减少来决定是否发出警报。

NLP

在人工智能的背景下,自然语言处理(NLP)是指使用计算机来理解和处理自然的人类语言。它可以进一步细分为 自然语言理解NLU)和 自然语言生成NLG)。NLU 关注于理解人类如何理解单词和句子的内容和意义。NLG 则更进一步,试图以人类可以理解的方式创建或生成单词和句子。在本节中,我们将讨论一些 Google Cloud 的与 NLP 相关的服务。

自然语言 API

您可以使用 Google Cloud Natural Language API 来理解文本输入的内容。这可以用于情感分析、实体分析、内容分类和语法分析等目的。通过情感分析,它可以告诉您内容中暗示了哪些类型的情感。例如,您可以将所有产品评论输入到这个 API 中,并了解人们是否对您的产品做出积极反应,或者他们可能因为产品的某些方面而感到沮丧。实体分析可以识别文本中存在的内容类型,例如人名、地名、地点、地址和电话号码。如果您有大量文本数据,并且希望根据内容对其进行组织和分类,内容分类功能将非常有用。

文本转语音

这个服务的名称在一定程度上是自我解释的。该服务将接受您提供的文本输入,并将其转换为可听说的语音输出。这对于可访问性用例非常有用,如果某人视力受损且无法阅读文本内容,它可以将文本自动读给他们听。它提供了使用许多不同声音来个性化用户体验的选项,您甚至可以使用自己的录音创建自定义声音。截至 2023 年 1 月,它支持超过 40 种语言和变体。它还支持 语音合成标记语言SSML),这使您能够更控制地处理单词和短语的发音。

语音转文本

此项服务基本上与之前的服务相反。在这种情况下,您可以提供音频输入,该服务将任何口语语言转录成文本输出。这对于语音输入、辅助功能用例如字幕,以及其他用例如质量控制等非常有用。例如,您可以提供客户服务通话的录音,并将其转换为文本。然后,您可以将该文本输入到自然语言 API 中,以了解您的客户对所收到的服务是否感到沮丧或满意。截至 2023 年 1 月,该服务支持令人印象深刻的 125 种语言和变体。

翻译人工智能

另一项名为“自解释”的服务,这项服务可用于将一种语言翻译成另一种语言。它可以帮助您国际化您的产品,并通过本地化内容与客户互动。它可以检测超过 100 种语言,您可以使用行业或领域特定的术语自定义翻译。它提供翻译中心,允许您大规模管理翻译工作负载,以及媒体翻译 API,可以将实时音频翻译直接发送到您的应用程序。

联系中心人工智能(CCAI)

联系中心人工智能CCAI)提供类似人类的 AI 驱动的联系中心体验。它由多个不同的组件组成,例如 Dialogflow,可用于创建能够与客户进行智能、类似人类的对话的聊天机器人。

您是否曾经遇到过在公司的客户服务热线上等待一个小时才有人帮助您解决您的问题的情况?当然,这种情况发生在客户服务中心电话过多时。使用聊天机器人可以处理大量简单问题的案例,从而让人类能够专注于更复杂的客户互动。

当人类确实需要介入时,CCAI 还有一个名为“代理助手”的功能,在人类代理处理客户互动时提供支持。它可以推荐准备发送给客户的响应,从集中式知识库中提供客户问题的答案,并实时转录通话。

CCAI 还包括 CCAI 洞察,它使用 NLP 来识别客户情绪和通话原因,这有助于联系中心经理了解客户互动以改善通话结果。

您还可以选择使用 CCAI 平台,该平台提供联系中心即服务CCaaS)解决方案。

文档人工智能

文档 AI 不仅理解文本输入的内容,还结合了结构。它提供用于数据提取的预训练模型,或者您可以使用文档 AI 工作台创建自定义模型,您还可以使用文档 AI 仓库搜索和存储文档。例如,如果您通过表格收集信息,文档 AI 可以用于从这些表格中提取数据并将其存储在数据库中,或者将其发送到另一个数据处理系统以某种方式处理数据,或者将其提供给另一个 ML 模型以执行其他任务。它还可以根据其内容对文档进行分类和组织。一些公司每年处理数百万份表格和合同,在这些类型的 AI 系统存在之前,所有这些文档都必须由人工处理,这导致了极其繁重且易出错的劳动。有了文档 AI,您可以自动化这项工作,您还可以使用 Google 企业知识图谱 (EKG) 来丰富数据,或者您可以通过使用其 人机交互 (HITL) AI 功能来增强文档 AI 的功能。使用 HITL AI,专家可以验证文档 AI 的输出,并在需要时提供更正。您可以使用自己的专家团队来完成这项工作,或者如果您没有雇佣这样的专家,您可以使用 Google 的 HITL 工作团队。

文档 AI 的 光学字符识别 (OCR) 功能扩展到了计算机视觉领域,我们将在下一节中讨论。

计算机视觉

您可以使用 Google Cloud Vision AI 来创建自己的计算机视觉应用程序,或者通过预训练的 API、AutoML 或自定义模型从图像和视频中获取洞察。它使您能够在几分钟内启动视频和图像分析应用程序,用于诸如检测对象、读取手写内容或创建图像元数据等用例。它由三个主要组件组成:Vertex AI Vision、Vision API 和自定义 ML 模型。Vertex AI Vision 包括 Streams 用于摄取实时视频数据,Applications 允许您通过组合各种组件来创建应用程序,以及 Vision Warehouse 用于存储模型输出和流数据。Vision API 提供预训练的 ML 模型,您可以通过 REST 和 RPC API 访问它们,允许您为图像分配标签并将它们分类到数百万个预定义的类别中。如果您需要开发更专业的模型,您可以使用 AutoML 或构建自己的自定义模型。

视觉 AI 可以用于实现有趣的应用场景,例如图像搜索,您可以使用 Vision API 和 AutoML Vision 根据图像中检测到的主题和场景使图像可搜索,或者产品搜索,您可以使用 Vision API 允许客户在图像中找到感兴趣的产品,并使用视觉搜索产品目录。

在计算机视觉领域,还有 Google Cloud Video AI,它可以分析视频内容,用于内容发现等用例。视频 AI 可以识别视频中的 20,000 多个物体、地点和动作,它可以在视频、镜头或帧级别提取元数据,您甚至可以使用 AutoML Video Intelligence 创建自己的自定义实体标签。它由两个主要组件组成:Video Intelligence API,它提供预训练的 ML 模型,以及 Vertex AI for AutoML 视频,它提供了一个图形界面来训练您自己的自定义模型,以在视频中分类和跟踪对象,无需 ML 经验。Vertex AI for AutoML 视频可用于需要自定义标签的项目,这些标签超出了预训练的 Video Intelligence API 的范围。

Discovery AI

Google Cloud Discovery AI 包括搜索和推荐引擎等服务。这类功能对于当今的在线业务至关重要,确保您的客户能够尽可能快、尽可能容易地在您的网站上找到他们想要的东西非常重要。如果这种情况没有发生,他们就会去竞争对手的网站。想象一下,如果您的公司能够将其网站集成 Google 质量的搜索功能,这将包括图像产品搜索等功能,正如我们在上一节中讨论的那样,这将使客户能够通过使用物体识别来提供实时结果,从而更容易地通过图像搜索产品。

除了客户通过直接搜索产品来找到产品外,公司还发现,推荐引擎可以基于客户的先前购买行为为产品做出个性化推荐,这推动了大量的业务。我自己作为一个消费者也多次经历过这种情况,我在网站上购买某样东西时,会看到一些我可能感兴趣的推荐,我想“实际上,我也想买一个”,然后我就在结账前将它添加到购物车中。这类个性化体验有助于保持客户忠诚度,这在当今的在线商业世界中也非常重要。

将这两个概念结合起来——即搜索和个人化——非常有意义,因为不仅搜索结果会智能地匹配客户搜索的内容,而且结果排名可以根据特定客户更可能认为与其偏好相关的结果进行定制。

Discovery AI 的第三个组件是浏览 AI,它将搜索功能扩展到除了文本查询外,还能在分类页面上工作。如果没有这个功能,零售商在分类和导航页面上主要会根据历史畅销品来排序产品。这种排序方式并不适应新产品添加、产品可用性变化和销售情况。有了浏览 AI,零售商可以按个人用户定制的产品顺序对这些页面上的产品进行排序,而不是基于历史畅销品。这种排序可以快速适应新产品、产品缺货和价格变化,无需等待回顾性的畅销品列表来更新。

现在我们已经了解了 Google Cloud 上的高级 AI 服务,您可以通过调用 API 来获取由 Google 训练和维护的 ML 模型的推断,接下来让我们讨论如何在 Google Cloud 上开始训练自己的模型,从 AutoML 开始。

AutoML

我们在前几节讨论的一些服务使用的是完全预训练的模型,而另一些服务则允许您将自己的数据带来训练或升级训练基于您数据的模型。预训练模型是在由 Google 或其他来源提供的数据集上训练的,而“升级训练”一词指的是用额外数据增强预训练模型。如果您想创建比高级 API 服务支持的更多定制用例,您可能需要训练自己的模型。我们将在本章后面描述的 Vertex AI 提供了大量的工具来实现模型开发过程中的每一步。然而,在我们达到定制过程中每一步的程度之前,您可以通过使用 AutoML 来轻松地从在 Google Cloud 上训练的 ML 模型中获取推断,AutoML 使具有有限 ML 专长的开发者能够在几分钟或几小时内训练针对其业务需求的特定模型。实际所需时间取决于所使用的算法、用于训练的数据量以及一些其他因素,但无论如何,AutoML 都能为您节省大量工作和时间,考虑到在不使用 AutoML 的情况下,数据科学家可能需要花费数周时间来完成这些任务。查看我们的 ML 模型开发生命周期图图 3.13,AutoML 会自动执行过程中的所有步骤,如蓝色框内所示的一切。

图 3.13:由 AutoML 管理的 ML 模型生命周期

图 3.13:由 AutoML 管理的 ML 模型生命周期

AutoML 是如何工作的?如果我们回顾一下我们在第二章中讨论的典型数据科学项目的所有步骤,你可能还记得每个步骤——尤其是在项目的早期阶段——都需要大量的试错。例如,你可能尝试了多种不同的数据转换技术,然后在训练期间尝试了几种不同的算法,以及这些算法的超参数值的多种组合。在找到好的候选模型(即我们认为可能满足我们的业务目标和指标)之前,这些步骤可能需要花费许多天或几周的时间。AutoML 自动快速运行许多试错作业——通常比人类能够做到的更快——并评估结果是否符合期望的指标阈值。不符合期望标准的结果不会被选为候选模型,AutoML 将继续尝试其他选项,直到找到合适的候选模型,或者达到某些其他阈值,例如所有选项都已耗尽。

如何开始使用 AutoML?在本章前面部分讨论的一些 AI 服务已经使用 AutoML 来训练通过这些 API 访问的模型。例如,AutoML 图像,你可以从目标检测和图像分类中获得见解;AutoML 视频用于流视频分析;AutoML 文本用于理解文本的结构、意义和情感;AutoML 翻译用于在不同语言之间进行翻译;以及 AutoML 预测,它基于时间序列数据提供预测。

另一个我们尚未探索的 AutoML 用例是针对表格数据的 AutoML(存储在表中的结构化数据)。这是存储业务数据的一种非常常见的格式,因为它提供了一种组织信息的方式,便于人类阅读和理解。AutoML Tabular 支持多种使用表格数据的 ML 用例,例如二分类、多分类、回归和预测。

我们可以使用 AutoML 来自动化许多试错步骤并开发候选模型,然后如果我们愿意,我们可以从那个点开始进一步定制。例如,我们可以使用 Vertex AI Tabular Workflows,它创建一个由玻璃箱管理的 AutoML 管道,让我们能够看到并解释模型构建和部署过程中的每一步。然后我们可以根据需要调整过程中的任何步骤,并通过 MLOps 管道自动化任何更新。我们将在本书的后续章节中精确执行这些活动。

接下来,我们将更深入地探讨 ML 模型定制,并将更详细地探讨 Vertex AI,因为它可以用于定制数据科学项目中的每个步骤。

Google Cloud Vertex AI

这是我们开始进入专家级 AI/ML 的地方。回想一下我们在本书中迄今为止所涵盖的所有数据科学概念;所有不同类型的 ML 方法、算法、用例和任务。Vertex AI 是你可以完成所有这些的地方,以及我们将在本书中进一步探索的许多其他内容。你可以将 Vertex AI 作为你执行所有 AI/ML 相关活动的中央指挥中心。我们的 ML 模型生命周期图图 3.14以图形方式说明了这一点。传统上,我们会期望一个 AI/ML 平台主要关注训练、评估、部署和监控模型。这由图 3.14右侧的蓝色框表示,所有这些活动当然都由 Vertex AI 支持。然而,通过额外的功能,如笔记本和 MLOps 管道,Vertex 不仅超越了传统的 ML 活动,还使我们能够执行生命周期中的所有任务,包括数据探索和处理,正如以下图中左侧的浅蓝色虚线框所示:

图 3.14:使用 Vertex AI 的 ML 模型生命周期

图 3.14:使用 Vertex AI 的 ML 模型生命周期

让我们更详细地了解一下 Vertex AI 的功能。从基础开始,我们可以使用 Vertex AI 的深度学习 VM 镜像在 Compute Engine 实例上实例化包含最流行 AI 框架的 VM 镜像,或者我们可以使用 Vertex AI 深度学习容器在可移植和一致的容器化环境中快速构建和部署模型。

虚拟机和容器镜像为我们提供了构建块,基于这些构建块我们可以开发定制的 ML 工作负载,但我们也可以以其他方式使用 Vertex AI 来执行和管理模型开发生命周期中的所有步骤。我们可以使用 Jupyter 笔记本来探索数据并实验过程中每个步骤,而 Vertex AI Data Labeling 则使我们能够从人工标注者那里获得高度准确的标签,以创建更好的监督式 ML 模型,Vertex AI Feature Store 则提供了一个完全管理的特征存储库,用于服务、共享和重用 ML 特征。Vertex AI Training 提供了预构建的算法,并允许用户将自定义代码带入完全管理的训练服务中,以实现更大的灵活性和定制化,或者对于在本地或另一个云环境中运行训练的用户。Vertex AI Vizier 为我们自动化所有超参数调优任务,为我们找到最优的超参数值集,从而节省我们大量繁琐的手动工作!优化的超参数值可以导致更准确和更高效的模型。

当我们需要部署我们的模型时,我们可以使用 Vertex AI Predictions,它将在由 Google 管理的基础设施上托管我们的模型,该基础设施会自动扩展以满足我们模型的流量需求。它可以托管我们的模型用于批量或在线用例,并提供一个统一的框架来部署基于任何框架(如 TensorFlow、PyTorch、scikit-learn 或 XGB)的定制模型,以及 BigQuery ML 和 AutoML 模型,并在广泛的机器类型和 GPU 上运行。部署后,我们可以使用 Vertex AI 模型监控来提供针对数据漂移、概念漂移或其他可能需要监督的模型性能事件的自动警报。然后,我们可以通过使用 Vertex Pipelines 自动化整个过程,作为 MLOps 管道,它允许我们在需要时触发模型的重新训练,并以版本控制的方式管理我们模型的更新。我们还可以使用 Vertex AI TensorBoard 来可视化 ML 实验结果,并比较模型和模型版本,以轻松识别性能最佳的模型。这个用于 ML 实验的视觉化和跟踪工具包括显示图像、文本和音频数据的模型图。

真正令人兴奋的是,我们可以从 Vertex AI Workbench 中执行和管理所有这些活动,这是一个基于 Jupyter 的完全托管、可扩展、企业级计算基础设施,具有安全控制和用户管理功能。在此过程中,我们的模型在每一步进展中的谱系细节都可以通过 Vertex Experiments 和 Vertex ML 元数据服务进行跟踪,这两个服务为 ML 工作流程提供易于使用的 Python SDK,以实现工件、谱系和执行跟踪。

Vertex AI 提供了比我们之前提到的所有功能更多的功能,例如 Vertex AI 匹配引擎,这是一个大规模可扩展、低延迟且成本效益高的向量相似度匹配服务。Vertex AI 神经架构搜索使我们能够针对特定应用需求构建新的模型架构,并在自动化的服务中优化我们现有的模型架构以降低延迟、内存和功耗,我们还可以使用 Vertex 可解释 AI 来理解并建立对模型预测的信任,通过 Vertex AI 预测、AutoML 表格和 Vertex AI Workbench 中的可操作解释来实现。可解释 AI 提供详细的模型评估指标和特征归因,表明每个输入特征对我们预测的重要性。

Google Cloud 上的标准行业工具

除了在本章中我们已经描述的 Google Cloud 自家的数据科学工具之外,您还可以使用其他数据科学工具,例如开源框架或其他流行的行业解决方案。有许多优秀的库可以轻松完成模型开发生命周期中的各种任务。例如,在数据探索和处理方面,备受喜爱的 pandas 库是任何机器学习和数据分析课程的必备工具。您可以使用它来处理缺失数据、切片、子集、重塑、合并和连接数据集。Matplotlib 在数据探索方面与 pandas 不相上下,因为它允许您通过可定制的交互式图表和图形来可视化数据,这些图表和图形可以导出为各种文件格式。NumPy 允许您轻松地操作和玩转我们在许多机器学习实现中发现的n-维数组和向量。学习 NumPy 也为您使用 scikit-Learn、TensorFlow 和 PyTorch 等框架奠定了基础。

说到 scikit-learn,它在任何机器学习课程中的地位与 pandas 不相上下。如果您参加机器学习课程,您在学习过程中几乎肯定会用到 scikit-learn,这是有充分理由的;它是一个易于使用和理解的框架,包含大量内置算法和数据集,您可以使用它们来实施机器学习工作负载。而且,它不仅仅是一个用于学习的简单框架;许多公司也使用 scikit-learn 来处理他们的生产机器学习工作负载。

虽然我们还在讨论通用机器学习框架的话题,但接下来我们将讨论的是广受欢迎的 TensorFlow,它最初是由 Google 创建的,在开源之前,因此在 Google Cloud 上得到了非常好的支持。TensorFlow 可以用于从数据处理到自然语言处理和计算机视觉的各个方面。您可以使用它来训练、部署和提供模型,并且通过TensorFlow ExtendedTFX),您可以实现端到端的 MLOps 管道来自动化所有这些步骤。我们当然会在本书中更详细地探讨 TensorFlow,以及 Keras,这是一个通过 Python 接口提供对 TensorFlow 访问的 API,因其易用性而受到欢迎,并自称是“为人类设计的 API, 而不是为机器。”

我们将使用 PyTorch 来结束对通用机器学习框架的讨论,PyTorch 最初由 Facebook(Meta AI)开发,现在在 Linux 基金会下开源。PyTorch 近年来迅速获得人气,尤其是在 Python 开发者中,它已经成为除了 TensorFlow 之外一个非常广泛使用的框架。在这本书中,我们不会涉及哪个框架更好的争论。每个阵营都有坚定的支持者,如果你在 Google 上搜索“TensorFlow 与 PyTorch”,你会找到许多网站和论坛强调其中一个在特定类型的用例中比另一个更好。我们还将在这本书的后续章节中使用 PyTorch。

从通用机器学习框架转向更专业的框架,你可能希望使用像 OpenCV 这样的工具来处理计算机视觉工作负载,或者使用 SpaCy 来处理自然语言处理。OpenCV 提供了广泛的选择,可以将机器学习和深度学习应用于图像和视频内容,以执行我们在本章前面讨论的许多任务,例如物体识别,以及通过视频帧跟踪物体和动作。SpaCy 拥有大量的预训练词嵌入和多种语言的流水线,它还支持使用 TensorFlow 和 PyTorch 编写的自定义模型,以及大量的 Python NLP 包。

好消息是,我们在这个部分讨论的所有工具和框架都可以轻松地在 Google Cloud 上使用。除了开源工具之外,还有许多流行的第三方数据科学解决方案可以在 Google Cloud 上使用,为人们提供灵活性,让他们可以使用他们偏好的工具来实现他们想要达到的目标。我们已经讨论了通过 Dataproc 和 Vertex AI 等服务在 Google Cloud 上使用 Spark,你也可以通过 Google Cloud Marketplace 使用第三方 Spark 产品,如 Databricks。市场允许你找到在 Google Cloud 上运行的数千种解决方案,包括来自 Hugging Face 等公司的深度学习解决方案。

在拥有所有这些工具以及 Google Cloud 提供的服务的情况下,你可能想知道如何为你的数据科学工作负载选择合适的工具。让我们在下一节更详细地探讨这个问题。

选择合适工具的工作

你选择的数据处理工具将主要取决于你需要完成哪种数据处理任务。如果你有一大堆需要批量转换的原始数据,就像 ETL/ELT 任务一样,那么数据融合将是开始评估的好地方;而如果你想要使用 SQL 语法执行相对简单的转换,那么从 BigQuery 开始;如果你想要通过易于使用的 GUI 可视化并转换数据,那么选择 Dataprep。如果你更喜欢使用开源工具,那么你可能想使用像 pandas 或 Spark 这样的工具。我们讨论了 pandas 对于刚开始学习数据探索和预处理的人来说是一个很好的起点,以及它不仅仅是一个教育工具。pandas 对于初始数据探索和中等规模的数据处理来说非常好。然而,对于大规模数据处理项目,Spark 高度并行化的功能将更加高效,如果你不想自己管理基础设施,那么你可以在 Dataproc 上运行它。Dataflow 是推荐用于流数据的选项,并且它还有一个额外的好处,就是它的统一编程模型也适用于批量数据处理。

当涉及到为 AI/ML 工作负载选择工具时,决策可能更为直接。如果你或你的公司对某个特定第三方(如 Hugging Face)有先前的偏好,那么你可能会被引导到那个方向。一般最佳实践是,你应该从你可用的高级抽象级别开始,因为这样你就不必花费大量时间和精力去构建和维护那些已经作为服务可供你使用的东西。如果这不能满足你的任何需求,比如需要一定程度的定制化的特定业务需求,那么就转向一个提供更多控制工作负载实施方式的解决方案。例如,如果你正在构建一个需要包含某种 NLP 功能的应用程序,那么首先评估 Google Cloud NLP API。如果出于任何原因,你无法通过该解决方案实现你的预期目标,那么就转向评估使用 AutoML 来自动化在特定数据上训练模型。如果你的目标仍然没有通过该过程中创建的模型得到满足,那么是时候提高你的定制化水平,并可能使用 Vertex AI 来构建一个完全定制的模型。

在你的决策过程中,另一个非常重要的因素是你的预算。为你做更多工作的服务(如高级 AI 服务)可能比低级服务成本更高,但非常重要的一点是要考虑你支付给员工多少来管理基础设施和执行那些可以由高级服务代表你执行的任务。

摘要

在本章中,我们涵盖了所有可用于在谷歌云上实施 AI/ML 工作负载的基础和主要服务。我们首先介绍了基本服务,如谷歌计算引擎和谷歌云网络服务,所有其他服务都是基于这些服务构建的。然后,我们探讨了如何使用这些服务与谷歌云之外的系统建立连接。接下来,我们讨论了可用于将数据导入或传输到谷歌云的服务以及可用于在云中存储数据的各种存储系统。在介绍了主要的存储系统之后,我们转而讨论谷歌云的数据管理和数据处理服务。我们旅程的最后一站是了解谷歌云中存在的所有不同的 AI/ML 服务。

到目前为止,你已经学到了很多,凭借这些知识,你现在可以就 AI/ML 和谷歌云进行有见地的讨论。这是一个重大的成就,因为人们花费了很长时间来学习 AI/ML,也花费了很长时间来学习谷歌云。现在,你比很多人知道的都多,你应该感到自豪,并为走这么远而给自己鼓掌。

这标志着我们书籍的“基础知识”部分的结束,你在前几章中获得的所有知识将成为你在这本书剩余部分所学内容的基础。在下一章以及之后,我们将开始进行动手活动,更深入地了解我们迄今为止所涵盖的服务和概念,并开始在谷歌云上构建数据科学工作负载!

第二部分:深入探索并构建 AI/ML 解决方案

到目前为止,我们已经具备了在谷歌云上构建 AI/ML 解决方案的先决知识。因此,本部分重点在于实际构建这些解决方案。我们首先探索谷歌云的高级 AI 服务。这些服务您可以在不要求任何 AI/ML 专业知识的情况下使用。然后,我们转向在谷歌云上构建自定义 ML 模型。在构建了您的第一个自定义模型之后,本部分剩余的章节将深入探讨典型 AI/ML 项目中每个步骤的细节,例如数据准备、特征工程、超参数优化以及在生产中的部署、监控和扩展。然后,我们深入探讨 MLOps 的概念,以自动化机器学习模型开发生命周期中的所有步骤。接下来,我们超越技术领域,纳入更广泛的企业和社会概念,这些概念适用于 AI/ML 模型,如偏差、可解释性和公平性。然后,我们进一步扩展讨论,讨论 ML 系统治理以及如何使用谷歌云架构框架构建稳健的企业级 AI/ML 系统和解决方案。最后,我们通过探索额外的 AI/ML 用例、框架和技术来结束本节。

本部分包含以下章节:

  • 第四章**,利用谷歌云的高级 AI 服务

  • 第五章**,在谷歌云上构建 C* 自定义 ML M* 模型

  • 第六章**, 深入探讨 - 在谷歌云上为 AI/ML 工作负载准备和处理数据

  • 第七章**,特征 E* 工程和 D* 维度 R* 减少

  • 第八章**,超参数和 O* 优化

  • 第九章**,神经网络与深度学习

  • 第十章**,在生产中部署、 M* 监控和 S* 扩展

  • 第十一章**,使用 谷歌云 进行机器学习工程和 MLOps

  • 第十二章**,偏差、可解释性、公平性和谱系

  • 第十三章**,ML 治理和谷歌云架构框架

  • 第十四章**, 额外的 AI/ML 工具、框架和考虑事项

第四章:利用 Google Cloud 的高级 AI 服务

现在您已经拥有了关于 AI/ML 和 Google Cloud 的信息武器库,您已经准备好开始深入研究和在云中实施 AI/ML 工作负载了——这正是本章将要做的!您将从使用 Google Cloud 的高级 AI/ML API 开始,例如自然语言 API 和视觉 API,这些 API 使您能够使用由 Google 训练和维护的模型来实现 AI/ML 功能。然后,您将使用 Vertex AI AutoML 训练您自己的 ML 模型,而无需任何 AI/ML 专业知识。

本章将涵盖以下主题:

  • 使用文档 AI 从文档中提取信息

  • 使用 Google Cloud 自然语言 API 从文本输入中获取情感分析洞察

  • 使用 Vertex AI AutoML

本章的先决条件

首先,我们需要执行一些设置步骤,为我们在本章中要执行的活动打下基础。

将本书的 GitHub 仓库克隆到您的本地机器

在本书的剩余部分,我们将进行许多需要使用代码、数据和其他文件等资源的动手活动。许多这些资源存储在本书的 GitHub 仓库中,因此访问它们的最简单方法是将仓库克隆到您的本地机器(即您的笔记本电脑/PC)。具体操作方式将根据您使用的操作系统而有所不同,但通常是在您的系统上打开命令终端,导航到您选择的目录,并运行以下命令:

git init
git clone https://github.com/PacktPublishing/Google-Machine-Learning-for-Solutions-Architects

Google Cloud 控制台

第三章 的“使用 Google Cloud 工具和服务的先决条件”部分,我们讨论了您需要创建一个 Google Cloud 账户才能与大多数 Google Cloud 服务进行交互。我们将使用 Google Cloud 控制台来完成本章中的许多活动。一旦您创建了 Google Cloud 账户,您可以通过导航到 console.cloud.google.com 来登录控制台。

在本书中,您将需要在 Google Cloud 控制台中导航到不同的服务。每次您需要这样做时,您都可以点击屏幕左上角 Google Cloud 标志旁边的三个横线符号来查看 Google Cloud 服务或产品的菜单(在此上下文中,我们将在本书中交替使用“服务”和“产品”这两个术语)。参见图 4.1 以获取参考:

图 4.1:访问 Google Cloud 服务菜单

图 4.1:访问 Google Cloud 服务菜单

您可以滚动查看服务列表并选择相关的服务。一些菜单项下有嵌套的子菜单,如图 4.2 所示:

图 4.2:Google Cloud 服务子菜单

图 4.2:Google Cloud 服务子菜单

在本书中,我们有时会使用缩写符号来表示通过服务菜单和子菜单的导航路径。例如,要导航到 凭证 子菜单项,我们将表示为 Google Cloud 服务 菜单 → APIs & ServicesCredentials

现在我们已经了解了如何访问 Google Cloud 控制台,让我们确保我们有一个 Google Cloud 项目用于本书的活动。

Google Cloud 项目

一个 Google Cloud 项目是一个包含您在 Google Cloud 中创建的所有资源的环境。资源包括虚拟机、网络配置、数据库、存储桶、身份和访问控制等几乎所有您在 Google Cloud 中创建的内容。

默认情况下,当您创建 Google Cloud 账户并首次登录控制台时,Google Cloud 会自动为您创建第一个项目,项目名称为 我的第一个项目。如果由于任何原因,这还没有发生,您需要按照以下步骤创建一个:

  1. 在 Google Cloud 控制台中,导航到 Google Cloud 服务 菜单 → IAM & Admin创建 项目

  2. 项目名称 文本框中为您的项目输入一个名称。

    您也可以编辑 项目 ID 值,如果您想的话,但更常见的是将其保留为生成的值,除非您想实施特定的命名约定。请注意,项目创建后不能更改。

  3. 位置 字段中,点击 浏览 以显示您项目的潜在位置。然后,点击 选择

  4. 点击 创建。控制台将导航到 仪表板 页面,您的项目将在几分钟内创建完成。

现在我们已经设置了我们的 Google Cloud 项目,让我们确保我们的计费详细信息已设置好以使用 Google Cloud。

Google Cloud 计费

一个 Google Cloud 计费账户包含所有使 Google Cloud 能够对您使用其服务进行计费的相关详细信息。

如果您还没有 Google Cloud 计费账户,那么您需要按照以下步骤创建一个:

  1. 在 Google Cloud 控制台中,导航到 Google Cloud 服务 菜单→ 计费

  2. 在出现的页面上,选择 管理计费账户,然后 添加 计费账户

  3. 点击 创建账户

  4. 为云计费账户输入一个名称。

  5. 根据您的配置,您还需要选择以下选项之一:

    • 组织:如果您看到一个 组织 下拉菜单,那么在您继续之前必须选择一个组织

    • 国家:如果您被提示选择一个 国家,请选择与您的计费邮寄地址相对应的国家

  6. 点击 继续

  7. 然后,您需要填写所有您的计费详细信息。

  8. 当你已输入所有详细信息后,点击提交并启用计费。要了解更多关于 Google Cloud 计费账户和概念的信息,请访问cloud.google.com/billing/docs/how-to/create-billing-account

现在我们已经设置了 Google Cloud 项目和计费账户,我们就可以开始在我们的项目中使用 Google Cloud 产品了。

Google Cloud Shell

我们将使用 Google Cloud Shell 来完成本章的一些活动。

打开 Cloud Shell,如第三章中“与 Google Cloud 服务交互”部分所述。提醒一下,您可以通过点击屏幕右上角的Cloud Shell符号来访问它,如图图 4**.3所示:

图 4.3:Cloud Shell 符号

图 4.3:Cloud Shell 符号

现在我们已经打开了 Cloud Shell,我们将执行一些基本的设置步骤来准备我们的 Cloud Shell 环境。

认证

当以某种方式调用 Google Cloud 服务时,它通常想知道谁或什么(身份)在调用它。这有多种原因,例如计费和检查调用者是否有权执行所请求的操作。这种识别过程被称为“认证”。有无数种不同的方式可以通过 Google Cloud API 进行认证。例如,当您登录 Google Cloud 控制台时,您正在与控制台进行认证。然后,当您在控制台中导航和执行操作时,您的认证详细信息将用于控制您可以执行的操作类型。其中一种最简单的认证机制被称为API 密钥。我们将接下来探讨这一点。

Google Cloud API 密钥

API 密钥是某些 Google Cloud API 支持的一种非常基本的认证类型。API 密钥不会向被调用的 API 提供任何标识或授权信息;它们通常仅用于计费目的(通过链接到 Google Cloud 项目)或用于跟踪对 Google Cloud 配额的使用情况。

在本章中,我们将使用它们来访问 Google Cloud 自然语言 API。

创建 API 密钥

虽然我们将使用 Cloud Shell 来完成本章中的许多步骤,但 Google Cloud 目前仅支持在 Google Cloud 控制台中创建 API 密钥。要创建我们的 API 密钥,请执行以下步骤:

  1. 在 Google Cloud 控制台中,导航到Google Cloud 服务菜单 → APIs & ServicesCredentials

  2. 选择创建凭据,然后API 密钥

  3. 复制生成的 API 密钥并点击关闭

  4. 您将在后续步骤中需要粘贴此 API 密钥。如果您需要再次查看或复制密钥,您可以在控制台的API Keys部分中选择显示密钥(即您当前所在的区域)。

  5. 这样,我们就创建了一个可以在本章后续活动中使用的 API 密钥。

启用相关 Google Cloud API

正如我们在 第三章 中讨论的那样,在您可以使用 Google Cloud 服务 API 之前,您需要启用它。由于我们已经在 Cloud Shell 中登录,我们可以直接使用 gcloud 命令轻松完成此操作。我们将启用 Google Cloud Natural Language API、Vision API、Document AI API 和 Google Cloud Storage API,因为在本章中我们将使用所有这些 API。为此,请在 Cloud Shell 中运行以下命令:

gcloud services enable language.googleapis.com
gcloud services enable vision.googleapis.com
gcloud services enable documentai.googleapis.com
gcloud services enable storage.googleapis.com

响应应类似于以下内容:

Operation "operations/..." finished successfully.

现在我们已经启用了所需的 API,我们只需再完成几个步骤就可以开始使用了。

在环境变量中存储认证凭据

我们将在本章的许多命令中引用我们的认证凭据——即我们之前创建的 API 密钥。为了便于引用凭据,我们将它们存储在 Cloud Shell 的 Linux 环境变量中。

要存储 API 密钥,请运行以下命令,但将 <YOUR_API_KEY> 替换为您之前创建并复制的 API 密钥:

export API_KEY=<YOUR_API_KEY>

现在,我们几乎完成了环境设置步骤。接下来,我们将克隆我们的 GitHub 仓库,之后我们就可以开始使用 Google Cloud 的高级 AI 服务了。

创建目录并克隆我们的 GitHub 仓库

您已经将我们的仓库克隆到了您的本地机器上。在本节中,您也将将其克隆到您的 Cloud Shell 环境中。为此,请在 Cloud Shell 中执行以下步骤:

  1. 创建一个目录:

    mkdir packt-ml-sa
    
  2. 将位置更改为该目录:

    cd packt-ml-sa
    
  3. 将目录初始化为本地 git 仓库:

    git init
    
  4. 克隆包含我们将在此章节的文档 AI 部分使用的代码的 git 仓库:

    git clone https://github.com/PacktPublishing/Google-Machine-Learning-for-Solutions-Architects
    

现在我们已经将所有必需的代码复制到我们的 Cloud Shell 环境中,是时候开始执行它了!

使用 Cloud Vision API 在图像中检测文本

我们将从一个非常简单的例子开始,向您展示开始使用 Google Cloud 上的 AI/ML 服务是多么容易。只需几个简单的步骤,您就能从图像中提取文本和相关元数据,并将该文本保存到文件中。这个过程被称为 光学字符 识别 (OCR)。

要开始此过程,请将以下图像下载到您的计算机上(该图像也可以在您上面创建的 git 仓库的 Chapter04/images 文件夹中找到):github.com/PacktPublishing/Google-Machine-Learning-for-Solutions-Architects/blob/main/Chapter-04/images/poem.png

图像显示在 图 4.4 中:

图 4.4:用于 OCR 的签名

图 4.4:用于 OCR 的签名

继续执行剩余步骤,将此图像上传到您的 Cloud Shell 环境中:

  1. 点击云 Shell 区域右上角的带三个点的符号(位于你的 Google Cloud 控制台屏幕底部),然后选择上传。参见图 4**.5以供参考:

图 4.5:云 Shell 上传

图 4.5:云 Shell 上传

  1. 你将看到一个文件上传对话框(参见图 4**.6以供参考)。选择选择文件并浏览你之前下载的文件:

图 4.6:云 Shell 上传提示

图 4.6:云 Shell 上传提示

  1. 现在,使用以下命令调用云视觉 API 提取文本并将其保存到以下文件中(在这种情况下,我们使用的图像文件名为poem.png)。结果存储在名为vision-ocr.json的文件中:

    gcloud ml vision detect-text poem.png> vision-ocr.json
    
  2. 检查文件内容:

    cat vision-ocr.json
    

注意

由于文件不适合在书中打印,所以我们在此不显示它。

如你所见,每个提取的单词都存储了一些相关的元数据,例如包含该单词的图像中边界框的XY坐标。这些元数据帮助我们了解每个单词在图像中的位置,这对于开发者来说可能是有用的信息。

  1. 如果你只想查看检测到的文本,而不需要其他元数据,可以使用以下命令:

    cat vision-ocr.json | grep description
    

    你将在第一个描述中看到检测到的整个文本正文,然后在随后的描述中看到单个单词。输出将类似于以下内容(此处截断以节省空间):

    "description": "\"All the summer long I stood\nIn the silence of the wood.\nTall and tapering I grew;\nWhat might happen well I knew;\nFor one day a little bird.\nSang, and in the song I heard\nMany things quite strange to me",
              "description": "\""
              "description": "All"
              "description": "the"
              "description": "summer"
              "description": "long"
              "description": "I"
              "description": "stood"
    

恭喜你——你已经在 Google Cloud 上实现了你的第一个 AI/ML 工作负载!这真的非常简单!接下来,我们将开始探讨一些稍微复杂一些的应用案例。

使用文档 AI 从文档中提取信息

如你所回忆,我们在第三章中详细讨论了文档 AI。我们讨论了它如何超越理解文本输入的内容,并且还结合了结构。在本节中,我们将探讨文档 AI 是如何做到这一点的,并将在一些实际应用案例中看到它的实际应用。我们将从介绍一些重要的文档 AI 概念开始。

文档 AI 概念

文档 AI 使用“处理器”的概念来处理文档。你可以使用以下三种主要类型的处理器:

  • 通用处理器

  • 专用处理器

  • 自定义处理器

通用处理器和专用处理器使用由 Google 预先训练的模型,因此你可以使用它们而无需训练自己的模型,也不需要任何 AI/ML 专业知识。然而,为了提供额外的灵活性,Google Cloud 允许你使用自己的数据进一步训练专用处理器,以提高它们针对特定业务用例的准确性。这个过程被称为“再训练”。

通用处理器包括对文本文档和表格图像执行 OCR 的处理器。虽然我们在上一节中使用了云视觉 API 进行 OCR,但文档 AI 提供了额外的功能,例如识别输入文档中的结构化信息。这包括理解输入表单中的键值对,这对于自动化数据录入用例非常有用。

注意

在解决方案架构师的角色中,这是一个重要的考虑因素;通常有多个不同的服务可以实现类似的企业目标,解决方案架构师的工作是根据特定的业务需求创建或选择最合适的解决方案。在比较云视觉 API 和文档 AI 用于 OCR 用例时,请记住,云视觉 API 通常使用起来需要更少的初始努力,但它提供的功能比文档 AI 要少。因此,如果你有一个非常简单的用例,可以用云视觉 API 满足,那么你可以选择该选项,而对于更复杂的用例,则应引导你使用文档 AI。

专用处理器为处理特定类型的文档提供模型,例如美国联邦政府表格、身份证件和发票。专用处理器目前分为四种不同类型:

  • 采购

  • 身份

  • 借款

  • 合同

在撰写本文时(2023 年 3 月),谷歌云最近宣布了文档 AI 新功能的通用可用性,即文档 AI 工作台。文档 AI 工作台允许你为特定的用例创建完全新的、定制的处理器类型,这超出了谷歌云提供的内容。

让我们看看一些文档 AI 处理器是如何工作的。

使用文档 AI 进行 OCR

我们将使用最简单的用例 OCR 进行演示,这还将使我们能够直接对比这种功能与我们在上一节中使用云视觉 API 进行 OCR 的方式。

创建文档 AI OCR 处理器

在我们能够处理任何文档之前,我们需要创建一个处理器。我们将在这个谷歌云控制台中执行此操作:

  1. 在谷歌云控制台中,导航到谷歌云服务菜单 → 文档 AI处理器库

  2. 文档 OCR下点击创建处理器。参见图 4**.7以获取参考:

图 4.7:创建处理器

图 4.7:创建处理器

  1. OCR-Processor作为名称输入,选择离你最近的地域,然后点击创建

关于地域和区域的说明

对于本书,每次您需要选择一个区域时,我们建议每次都选择相同的区域,因为我们将在这本书的整个过程中构建资源,这些资源可能需要与其他章节中创建的其他资源一起使用。通常,当您需要使用一些云资源与其他云资源一起使用时,如果这些资源在同一个区域,通常会更简单。有时,可能很难或不可能在没有构建定制解决方案的情况下,让一个区域内的资源引用另一个区域内的资源。

在本书的一些活动中,您还可以选择在区域内选择一个特定的区域。这个决定对于本书中的活动通常不太重要,因为在一个区域内跨区域访问资源通常相当容易。在生产环境中,如果您有特定的业务需求,例如需要非常紧密协作的计算实例集群,您可能希望将资源保留在同一个区域。

如果您没有这样的特定要求,那么最佳实践是将您的资源分布在多个区域以提高工作负载的弹性和可用性。您可以在以下 URL 的文档中了解更多关于 Google Cloud 区域和区域的信息:cloud.google.com/compute/docs/regions-zones

  1. 当您的处理器创建时,您应该自动重定向到 处理器详细信息 页面。如果不是,您可以通过在屏幕左侧菜单中选择 我的处理器 然后选择您新创建的处理器来查看详细信息。处理器详细信息显示在 图 4**.8 中:

图 4.8:OCR 处理器详细信息

图 4.8:OCR 处理器详细信息

记下您的处理器 ID(由图 4.8 中的红色箭头突出显示),您将在下一节中使用的代码中引用它。

调用 OCR 处理器

现在我们已经创建了我们的处理器,我们可以开始使用它了。在本节中,我们将运行一段简单的 Python 代码,该代码使用 Document AI Python 客户端库处理文件并提取必要的信息。我们将使用本章前面与 Cloud Vision API 一起使用的相同文件。

在 Cloud Shell 中执行以下步骤:

  1. 安装 Document AI 客户端包的最新版本:

    python -m venv env
    source env/bin/activate 
    pip install --upgrade google-cloud-documentai
    
  2. 记下您的项目 ID,因为您将在与 Document AI 交互的 Python 代码中引用它。您可以使用以下命令查看它:

    echo $DEVSHELL_PROJECT_ID
    
  3. 确保您在您的家目录中:

    cd ~
    
  4. docai-ocr.py 文件从我们之前创建的 git 目录复制到您的家目录。我们将在这个分支之外编辑这个文件,因为我们不需要将更新合并回主分支:

    cp ~/packt-ml-sa/Google-Machine-Learning-for-Solutions-Architects/Chapter-04/docai-ocr.py ~
    

在这个 Python 文件中,我们将首先导入所需的库。然后,我们将定义一些变量(我们需要用上一节中创建的处理器的值来替换这些变量的值)。

然后,我们将定义一个函数,该函数创建一个 Document AI 客户端,读取输入文件,根据文件内容创建一个请求对象,并将此请求发送给 Document AI 服务进行处理。

最后,函数将打印生成的文档文本。

要执行这些操作,请执行以下步骤:

  1. 使用nano打开文件进行编辑:

    nano docai-ocr.py
    
  2. 将变量定义替换为在 Google Cloud 控制台中创建处理器后保存的值:

    1. project_id的值替换为您之前在$DEVSHELL_PROJECT_ID环境变量中查看的项目 ID。

    2. 根据您使用的区域指定'us''eu'作为位置。

    3. processor_id的值替换为您可以在包含我们想要处理的文件路径的file_path值中查看的处理器 ID。我们使用的 Cloud Shell 上传功能通常将文件存储在您的 Cloud Shell 主目录中,通常是/home/admin_

    4. 在这种情况下,mime_type的值是'image/png'。您可以在cloud.google.com/document-ai/docs/file-types查看支持的 MIME 类型列表。

  3. 当您完成所有编辑后,按Ctrl + X退出nano,然后按Y保存文件,最后按Enter确认。

  4. 现在,我们准备执行 OCR!以下命令将运行我们的 Python 函数,并将结果保存到名为docai-ocr.txt的文件中:

    python docai-ocr.py > docai-ocr.txt
    
  5. 检查文件内容:

    cat docai-ocr.txt
    

    响应应如下所示:

    All the summer long I stood
    In the silence of the wood.
    Tall and tapering I grew;
    What might happen well I knew;
    For one day a little bird.
    Sang, and in the song I heard
    Many things quite strange to me
    

注意输出格式与使用 Cloud Vision API 时收到的结果不同。这进一步证明了我们可以使用不同的服务来实现类似的结果。然而,这些服务之间存在细微的差异,我们需要根据业务需求选择最佳选项。Cloud Vision API 的使用初始工作量较小,但请记住,Document AI 具有更强大的功能,例如自动化文档处理和针对特定用例的定制模型。

让我们来看看 Document AI 的一些附加功能。

Document AI 的响应

在我们的 OCR 示例中,我们关注了响应中的document.txt对象。然而,返回的完整响应包含更多信息,我们可以以各种方式使用这些信息,例如文档中的页数、段落和行数,以及许多其他类型的元数据。当使用表单解析器或专用处理器时,甚至可以突出显示结构化数据类型,如表格和键值对。

还应注意的是,在先前的例子中,我们执行了一个在线推理请求,其中我们为单个文档实时获得了响应。如果需要一次性处理大量文档,Document AI 也允许我们执行批量推理请求。

环境中的 AI(HITL)

在先前的用例中,模型能够识别图像中的所有单词。然而,在现实中,我们图像的来源可能并不总是清晰可辨。例如,我们可能需要从可能磨损的地方的公路标志图片中读取信息。在考虑你需要的结果有多准确时,这是需要考虑的事情。Document AI 提供了一个 HITL(人机交互)功能,允许你通过人工审查并在必要时进行更新来提高结果准确性。

使用 Google Cloud Natural Language API 从文本输入中获取情感分析洞察

自然语言处理NLP)和自然语言理解NLU)在我们的日常生活中变得越来越突出,研究人员几乎每天都在发现有趣的新用例。在本章中,我们将通过使用 Google Cloud Natural Language API 探索在 Google Cloud 上获得强大的 NLP/NLU 功能的最简单方法。在后面的章节中,我们将构建和使用更多复杂的语言用例。

使用自然语言 API 进行情感分析

情感分析使我们能够了解文本的主要情感基调。这对于许多商业用例来说很重要,尤其是在与客户建立联系和理解客户方面。例如,如果你想了解客户对你发布的新产品的看法,你可以分析各种客户互动渠道,如评论、社交媒体反应和客户服务中心日志,以了解人们对新产品的反应。这使你能够回答以下问题:

  • 他们对此满意吗?

  • 是否有关于特定功能的投诉模式出现?

如果你有成千上万的评论、社交媒体反应和服务中心日志要处理,手动进行此类分析将是不可能的。

幸运的是,你可以通过向 Google Cloud Natural Language API 发起简单的 API 调用来对一段文本进行情感分析。

要这样做,请在 Cloud Shell 中执行以下步骤:

  1. 创建一个包含我们想要分析的文本片段的 JSON 文件。就像我们讨论 Document AI 时一样,我们可以使用 nano 命令来完成这个任务,这将创建并打开文件以供编辑:

    nano request.json
    

    将以下文本粘贴到 request.json 文件中:

    {
      "document":{
        "type":"PLAIN_TEXT",
        "content":"This is the best soap I've ever used! It smells great, my skin feels amazing after using it, and my partner loves it too!"
      },
      "encodingType":"UTF8"
    }
    
  2. Ctrl + X 退出 nano

  3. Y 保存文件。

  4. Enter 确认此操作。

  5. 现在,我们可以向自然语言 API 的analyzeSentiment端点发送请求。为此,我们将使用以下curl命令。请注意,我们正在使用本章早期创建的API_KEY环境变量。这将用于验证我们的请求:

    curl -X POST -s -H "Content-Type: application/json" --data-binary @request.json "https://language.googleapis.com/v1/documents:analyzeSentiment?key=${API_KEY}"
    

    你的回复应该看起来像这样:

    {"documentSentiment": {
     { "magnitude": 1.9, "score": 0.9
      }, "language": "en",
      "sentences": [
        {"text": {"content": "This is the best soap I've ever used!", "beginOffset": 0},
          "sentiment": {"magnitude": 0.9,"score": 0.9 }},
        {"text": {"content": "It smells great, my skin feels amazing after using it, and my partner loves it too!", "beginOffset": 38 },
          "sentiment": {"magnitude": 0.9,"score": 0.9}
        }]}
    

我们在输出中首先可以看到的是整个文档的评分,这是整个文本体的评分。之后,我们可以看到检测到的单个句子的评分。情感评分的范围在-1.0(负面)到 1.0(正面)之间,幅度表示给定文本中情感的整体强度(包括正面和负面)。您可以在cloud.google.com/natural-language/docs/basics#sentiment_analysis_response_fields了解更多关于响应字段和评分的信息。

在这种情况下,这两句话都构成了一条正面评价,因此它们都获得了高分,因此整个文档的评分也因此很高。

注意

如果你的评分与输出中的评分略有不同,那是因为服务这些请求的模型正在不断用新数据更新。

在本节中重试所有之前的步骤,但在审查的末尾添加以下两句:“唯一不好的是它太贵了,这真的很糟糕。非常烦人!”

整个评价将如下所示:

这是我用过的最好的肥皂!它闻起来很棒,用后我的皮肤感觉非常好,我的伴侣也喜欢它!唯一不好的是它太贵了,这真的很糟糕。 非常烦人!

当你提交更新后的请求时,输出将如下所示:

{ "documentSentiment": { "magnitude": 3.4,"score": 0.1
  }, "language": "en",
  "sentences": [
    {"text": {"content": "This is the best soap I've ever used!","beginOffset": 0},
      "sentiment": {"magnitude": 0.9,"score": 0.9}},
    {"text": {"content": "It smells great, my skin feels amazing after using it, and my pertner loves it too!",
        "beginOffset": 38},
      "sentiment": {"magnitude": 0.9,"score": 0.9}},
    {"text": {"content": "The only bad thing is that it's just too expensive, and that really sucks.",
        "beginOffset": 122},
      "sentiment": {"magnitude": 0.5,"score": -0.5}},
    {"text": {"content": "Very annoying!",
        "beginOffset": 197},
      "sentiment": {"magnitude": 0.8,"score": -0.8}
    }]}

在输出中,请注意,结尾的负面句子得分要低得多,因此这降低了整个评价的整体评分。这很有道理,因为评价的整体情感是挫败感,尽管它以积极的情感开始。

自然语言 API 还提供其他类型的功能,如下所示:

  • 实体分析:这涉及到识别文本中存在哪些类型的实体(例如,人物、地点等)。支持的实体列表可在cloud.google.com/natural-language/docs/reference/rest/v1/Entity#type找到。

  • 实体情感分析:实体分析和情感分析的结合。

  • 句法分析:这涉及到检查给定文本的语言结构。

  • 内容分类:这涉及到对文档或文本内容进行分类。

要更详细地探索自然语言 API,让我们看看它的另一个功能内容分类。

使用自然语言 API 进行内容分类

让我们假设我们想要构建一个可以用于搜索大量文档和内容对象的搜索引擎。我们首先需要做的事情之一是将我们的文档和内容对象分类到不同的类别中。在数百万个对象上手动进行此操作是不可能的,或者至少是非常费时费力且容易出错的。这就是自然语言 API 的内容分类功能可以发挥作用的地方。

为了演示,我们将使用本章节前一部分中我们的 Document AI OCR 处理器生成的文本。这还将展示一个重要的概念,即你可以结合多个 AI 服务来创建更复杂的用例以满足你的业务需求。在这种情况下,我们不仅可以对常规文本输入进行分类,还可以检测图像中的文本,然后对文本内容进行分类。

在 Cloud Shell 中执行以下步骤:

  1. 创建一个 JSON 文件,我们将用它向 API 发送请求。这个文件将包含来自我们的 OCR 处理器的文本:

    nano classify-request.json
    
  2. 将以下文本粘贴到 classify-request.json 文件中:

    {
      "document":{
        "type":"PLAIN_TEXT",
        "content":""All the summer long I stood
    In the silence of the wood.
    Tall and tapering I grew;
    What might happen well I knew;
    For one day a little bird.
    Sang, and in the song I heard
    Many things quite strange to me "
      },
      "classificationModelOptions":{
        "v2Model":{
          "contentCategoriesVersion":"V2"
        }
      }
    }
    
  3. Ctrl + X 退出 nano

  4. Y 键保存文件。

  5. 按下 Enter 键以确认此操作。

  6. 现在,我们可以向自然语言 API 的 classifyText 端点发送请求。为此,我们将使用以下 curl 命令。请注意,我们正在使用本章早期创建的 API_KEY 环境变量。这将用于验证我们的请求:

    curl "https://language.googleapis.com/v1/documents:classifyText?key=${API_KEY}"   -s -X POST -H "Content-Type: application/json" --data-binary @classify-request.json
    

    你的响应应该看起来像这样:

    {
      "categories": [
        {
          "name": "/Books & Literature/Poetry",
          "confidence": 0.45689428
        },
        {
          "name": "/Arts & Entertainment/Music & Audio/Music Reference",
          "confidence": 0.22331826
        },
        {
          "name": "/Arts & Entertainment/Music & Audio/Rock Music",
          "confidence": 0.109513044
        }
      ]
    }
    

看起来更接近了!请注意,响应包含多个潜在类别的条目,每个类别都有不同的置信度级别。这展示了针对解决方案架构师角色的两个重要现实:

  • 虽然我们希望通过 AI/ML 尽可能地自动化一切,但通常需要有人类审查模型输出并在必要时进行更正的机制。

  • AI/ML 工作负载通常由多个步骤组成,其中数据从一个步骤传递到下一个步骤,因此在过程中的每个阶段实施数据质量检查是很重要的。

注意

当使用 HITL 审查时,我们不需要对每个数据点都进行人工审查(这不太实际,并且会抵消 AI/ML 的好处),但我们应该有机制来定义在特定用例中我们期望看到哪些类型的值,如果可能的话,或者如果我们的模型在某些数据点的置信度低于指定的阈值,则标记我们的输出以供人工审查。

现在,我们已经探讨了如何使用 Google 提供的预训练模型,接下来我们将探讨在 Google Cloud 上实现 AI/ML 工作负载的下一级复杂性,即以管理方式使用 AutoML 训练我们自己的模型。

使用 Vertex AI AutoML

如我们在 第三章 中所讨论的,我们可以使用 AutoML 来自动化模型训练和评估过程中的所有步骤。在本节中,我们将使用 Vertex AI 构建一个 AutoML 模型。

注意

在遵循本节中的说明之前,请参考以下链接了解 Vertex AutoML 定价:cloud.google.com/vertex-ai/pricing.

用例 – 预测

我们将关注此工作负载的用例是预测。毕竟,预测是几乎所有企业都必须以某种形式执行的最基本业务流程之一。例如,无论您是一家全球在线零售公司还是一个小镇上的单个商店,您都需要根据对那些商品的预期客户需求来估算每个月或每天应该购买多少产品。而且,预测不仅限于实物商品。例如,如果您拥有一家咨询或服务公司,您将需要估算在未来的几个月内需要雇佣多少人以满足客户预期的需求。能够预测未来是一种相当重要的超级能力,在我们的案例中,我们将直接跳过预测股市表现的“快速致富”用例。

您准备好训练您的第一个 ML 模型了吗?让我们开始吧!

准备工作 – 为我们的预测输出创建 BigQuery 数据集

BigQuery 是一个用于查看和执行预测输出上的分析查询的有用工具。因此,我们将创建一个 BigQuery 数据集来存储我们的 AutoML 测试输出。要在 BigQuery 中创建数据集,请执行以下步骤:

  1. 在 Google Cloud 控制台中,导航到Google Cloud 服务菜单 → BigQuery

  2. 在屏幕的左上角,您将看到您项目的名称。点击项目名称右侧的三个垂直点(参见图 4.9以获取参考):

图 4.9:BigQuery 项目菜单

图 4.9:BigQuery 项目菜单

  1. 在显示的菜单中,选择创建数据集

  2. 给您的数据集命名,例如forecast_test_dataset(参见图 4.10)。

  3. 选择您首选的区域,然后选择创建数据集

图 4.10:创建 BigQuery 数据集

图 4.10:创建 BigQuery 数据集

  1. 就这样 – 目前在 BigQuery 中我们不需要做任何事情。

创建 AutoML 工作负载

现在,是时候定义将要自动化我们数据科学项目中所有步骤的 AutoML 作业了。作为提醒,模型生命周期的步骤在图 4.11中显示:

图 4.11:由 AutoML 管理的 ML 模型生命周期

图 4.11:由 AutoML 管理的 ML 模型生命周期

如我们所见,该过程的第一个步骤是摄取一些数据。我们需要为此创建一个数据集。我们将使用 Kaggle 的一个公共数据集,这是一个练习 ML 概念的宝贵资源。预测用例通常需要时间序列数据,这是一种按时间间隔按时间顺序排列的数据序列。因此,我们的数据集将需要包含一个时间戳字段。我们将在本书的后面部分深入了解模型训练和部署的工作原理,但现在,我们将专注于 Vertex AI AutoML 如何使我们能够轻松地训练预测模型,而无需太多或任何 AI/ML 专业知识。请注意,Vertex AI AutoML 也可以用于分类和回归用例。

在我们的示例中,我们将使用道琼斯工业平均指数 30 种股票时间序列数据集的一个子集,该数据集可在www.kaggle.com/datasets/szrlee/stock-time-series-20050101-to-20171231找到。

为了参考,数据包含以下字段:

  • Date: yy-mm-dd 格式

  • Open: 市场开盘时的股价(这是 NYSE 数据,因此所有数据均为美元)

  • High: 当日达到的最高价

  • Low Close: 当日达到的最低价

  • Volume: 交易的股票数量

  • Name: 股票的股票代码

在您在本章早期在本地上创建的 GitHub 仓库的副本中,您将在名为data的目录中找到该文件的修改版本,该目录位于名为Chapter``0``4的目录中。修改后的文件名为automl-forecast-train-1002.csv

因此,您应该在您的本地机器上的以下路径中找到文件(如果您使用的是 Microsoft Windows,则斜杠将被反转):[您克隆我们的 GitHub 仓库的位置]/``Chapter-04``/data/automl-forecast-train-1002.csv

要在 Google Cloud 中创建我们的数据集,请执行以下步骤:

  1. 在 Google Cloud 控制台中,导航到Google Cloud 服务菜单 → Vertex AI数据集

  2. 选择my-forecasting-dataset

  3. 您还将被要求选择数据类型和目标。选择表格,然后选择预测。您的选择应类似于图 4**.12所示。

  4. 选择您首选的区域,然后选择创建(请注意,这必须与您在上一节中创建 BigQuery 数据集的区域相同):

图 4.12:创建数据集

图 4.12:创建数据集

  1. 接下来,我们需要向数据集中添加数据。选择从您的计算机上传 CSV 文件,然后点击选择文件。参见图 4**.13以获取参考:

图 4.13:将数据添加到您的数据集中

图 4.13:将数据添加到您的数据集中

  1. 从以下路径选择文件(如果您使用的是 Microsoft Windows,则斜杠将被反转):

    [Location in which you cloned our GitHub repository]/Chapter-04/data/automl-forecast-train-1002.csv
    
  2. 云存储路径输入字段中,选择浏览

  3. 我们将为此用例创建一个新的 Cloud Storage 存储桶。为此,点击右上角看起来像带有加号的存储桶符号()。

  4. 为存储桶提供一个唯一的名称并选择创建(你可以保留所有存储桶配置选项的默认值)。

  5. 如果你被提示防止公开访问,请选择确认。这将防止你的存储桶中的任何项目被公开,这是一个最佳实践,除非你特别想创建公开可访问的内容。在这个例子中,我们不需要创建公开可访问的内容。

  6. 当你的存储桶创建完成后,点击屏幕底部的选择。这样,你的存储桶现在是我们训练数据的存储位置。结果屏幕应类似于图 4.14中所示:

图 4.14:向数据集添加数据

图 4.14:向数据集添加数据

  1. 选择继续

  2. 当文件上传完成后,你应该会看到一个消息说上传已完成。现在,我们准备开始训练我们的模型!

  3. 在你的数据集详情屏幕上,选择标有训练 新模型的按钮。

  4. 在出现的下一个屏幕上,选择AutoML(默认)

  5. 接下来,按照以下方式输入 AutoML 工作负载的详细信息(参见图 4.15中的最终配置详细信息):

    1. 数据集名称将自动作为工作负载的名称。你可以保留默认值,或者根据需要更改名称。

    2. 我们将尝试预测每个日期公司股票的销量,因此选择 [project_name].[dataset_name].[table_name],其中我们有以下内容:

      1. project_name是你的 Google Cloud 项目的名称(提示:记得在创建 BigQuery 数据集时在 BigQuery 控制台中看到过)。

      2. dataset_name是你创建的 BigQuery 数据集的名称;例如,table_name是用于存储测试输出的表的名称。你可以在这里输入任何名称,该名称将被分配给创建的表。需要注意的是,此表将由我们的 AutoML 作业创建,因此在此点之前不得手动在 BigQuery 中创建。只需创建数据集即可;不是数据集内的表。

      3. 当你输入了数据集详细信息后,点击选择。数据集路径将出现在BigQuery 路径输入字段中:

图 4.15:模型详情

图 4.15:模型详情

  1. 选择继续

  2. 在出现的训练选项屏幕上,选择关闭开盘列旁边的复选框。

  3. 当你这样做时,屏幕顶部附近将出现四个蓝色文本菜单(参见 图 4**.16 以获取参考)。点击 特征类型 菜单并选择 协变量。这是一个必填步骤,它表示训练数据集中的这些列包含随时间变化的值:

图 4.16:训练选项

图 4.16:训练选项

  1. 选择 继续

  2. 在输入字段中的 1 上(参见 图 4**.17 以获取参考):

图 4.17:计算和定价预算

图 4.17:计算和定价预算

  1. 选择 开始训练

  2. 要监控我们的训练作业,我们可以从屏幕左侧的菜单中选择 训练

  3. 当我们的作业状态变为 完成 时,我们的模型已经训练完成,我们可以开始使用它来获取预测。

注意

由于 AutoML 流程中的各种步骤以及“节点小时”的概念,作业可能运行超过 1 小时。

恭喜!您已在 Google Cloud 上训练了您的第一个机器学习模型。让我们看看有关我们模型的一些细节。

查看模型详情

当我们的模型训练作业状态变为 完成 时,我们可以点击训练作业的名称并查看有关我们模型的大量有用细节(参见 图 4**.18 以获取参考)。在屏幕顶部,我们可以看到各种性能指标,例如 平均绝对误差MAE)、平均绝对百分比误差MAPE)以及其他指标。您可以在每个旁边的问号符号上点击以了解更多信息。我们还会在本书的后续章节中更详细地讨论这些指标。

另一个有用的信息是 特征重要性,它显示每个输入特征似乎对模型输出的影响程度。这对于理解我们的模型如何工作非常重要。

你能想到这些功能中的每一个如何可能影响股票预测销量吗?例如,当股票价格低时,人们会购买更多该股票吗?如果这是真的,那么表示每天股票最低价点的 特征在预测某一天会卖出多少该股票时很重要,这有意义吗?

图 4.18:模型指标

图 4.18:模型指标

除了我们模型的表现指标外,让我们看看我们模型在 AutoML 工作负载执行过程中的测试过程中做出的某些预测。

查看模型预测

要查看由我们的 AutoML 作业生成的某些模型输出,我们需要查看我们创建的用于存储这些输出的 BigQuery 表。为此,执行以下步骤:

  1. 在 Google Cloud 控制台中,导航到 Google Cloud 服务 菜单 → BigQuery

  2. 在屏幕左上角,点击您的项目名称,然后点击您的数据集名称,然后点击表的名称。

  3. 您将看到表的架构。

  4. 点击 预览 选项卡;将显示输出数据的预览。

  5. 向右滚动;您将看到名为 predicted_Volume.valuepredicted_on_Date 的列。这些列显示了我们的模型预测输出。

重要的是要注意,我们只允许我们的作业运行了 1 个节点小时,因此我们的预测值可能在此点不准确。一个 AutoML 作业通常需要运行更长的时间来找到最佳模型。这是从成本角度需要考虑的事情。如果您的预算允许,尝试运行 AutoML 作业更长时间,看看它如何影响模型性能。

摘要

在本章中,您学习了如何使用 Google Cloud 的高级 AI/ML API,通过使用由 Google 训练和维护的模型来实现 AI/ML 功能。然后,您继续使用 Vertex AI AutoML 训练自己的 ML 模型。所有这些都是在 Google Cloud 的完全托管服务帮助下完成的。在下一章以及之后,我们将更深入地探讨,您将从头开始构建自己的模型,以便更详细地了解模型开发生命周期中的每个步骤是如何工作的。

第五章:在 Google Cloud 上构建自定义 ML 模型

在上一章中,我们通过让谷歌为我们完成所有工作来实现 AI/ML 工作负载。现在,我们将通过在 Google Cloud 上从头开始构建自己的模型来提升我们的知识和技能到专家水平。

我们将使用在数据科学项目中常用的流行软件库,并将开始实现我们在前几章中讨论的一些概念,例如无监督机器学习UML)和监督机器学习SML),包括聚类、回归和分类。

本章涵盖以下主题:

  • 背景信息 – 库

  • 在 Vertex AI 上使用 scikit-learn 实现 UML

  • 在 Vertex AI 上使用 scikit-learn 实现回归模型

  • 在 Vertex AI 上使用 XGBoost 实现分类模型

背景信息 – 库

在我们深入探讨并开始构建自己的模型之前,让我们花一点时间讨论一下本章中我们将使用的软件库。

定义

软件库是一组代码和数据,包括用于特定类型编程任务的实用函数和工具。当在某个行业中识别出常见的编程任务类型,例如数据处理或实现复杂的数学方程式时,通常有人最终会创建一个包含执行这些任务所需的代码和其他资源的库。然后,其他人可以轻松地使用这个库来完成相同的任务,并可能随着时间的推移扩展以添加更多功能,而不是每个人都需要反复编写执行这些常见任务的代码。没有库,程序员将不得不每次从头开始构建一切,并将浪费大量时间在基础编程任务上。在本章中,我们将使用 scikit-learn、Matplotlib 和 XGBoost 等库。在本书的后期,我们将使用其他库,如 TensorFlow 和 PyTorch,并在各自的章节中更详细地描述这些库。

scikit-learn

scikit-learn,也称为sklearn,是一个内置了许多有用的数据科学工具和实践数据集的开源 Python 库。它就像是数据科学的“瑞士军刀”,对于初涉数据科学领域的从业者来说,它是开始机器学习项目的热门起点,因为它相对容易上手,正如你将在本章中看到的。

Matplotlib

第二章中,我们讨论了几乎存在于所有数据科学项目中的典型阶段,以及其中有一个阶段专注于数据探索。我们还讨论了“可视化”通常是数据探索阶段的一个重要部分,在这个阶段,数据科学家和工程师使用工具来创建其数据集特性的视觉表示。这些视觉表示,如图表,可以帮助数据科学家和工程师更好地理解数据集,以及这些数据集如何受到在数据科学项目中执行的各种实验和转换的影响。数据科学家和工程师还经常希望构建表示其数据科学项目活动其他方面的可视化,例如帮助确定模型性能的指标的增加或减少。用 Matplotlib 的开发者的话说,“Matplotlib 是一个用于在 Python 中创建静态、动画和交互式可视化的综合性库。”因此,Matplotlib 是创建数据视觉表示的常用库。

pandas

pandas 是一个用于数据操作和分析的 Python 库。它用于数据探索以及执行数据转换。例如,使用 pandas,我们可以从文件或其他数据源读取数据,预览数据的一个子集以了解其内容,并对数据集进行统计分析。然后,我们还可以使用 pandas 对数据进行更改,以准备训练机器学习模型。

XGBoost

第一章中,我们讨论了梯度下降的概念在机器学习模型训练过程中的常用性。XGBoost 是一个基于梯度提升概念的流行机器学习库,它使用集成方法,结合了许多小型模型(通常被称为弱学习器)来创建一个更好的整体预测模型。在梯度提升的情况下,训练过程中的每一迭代都会训练一个小型模型。几乎在每一个模型训练过程中,产生的模型都会做出一些错误的预测。在梯度提升过程中的下一迭代将基于前一个模型所犯的残差误差来训练模型。这有助于在后续的每一迭代中“提升”训练过程,目的是创建一个更强的预测模型。XGBoost,代表极端梯度提升,克服了先前梯度提升算法的顺序限制,并且可以并行训练数千个弱学习器。我们将在本章后面更详细地描述 XGBoost 的工作原理。

注意

通常,“集成”模型训练的概念指的是将许多弱模型组合起来以创建更好的或“更强”的整体预测机制,通常被称为“元模型”。提升只是集成方法的一个例子。其他例子包括“Bagging”(或“Bootstrap Aggregation”),它在数据的子集上训练许多弱学习器,以及“Stacking”,它可以用来结合使用完全不同算法训练的模型。在每个情况下,目的是构建比任何单个模型单独实现更有用的预测机制。

根据集成方法的实现,集成中每个模型的预测可以以不同的方式组合,例如求和或平均,或者在分类用例中,可能实现投票机制以确定最终的最佳预测。

本章的先决条件

就像在前一章中一样,我们将在开始本章的主要活动之前执行一些初始活动。

Google Cloud 使得开始使用我们在前几节中描述的数据科学库变得更加容易,因为我们可以使用已经安装了这些库的 Vertex AI Workbench 笔记本。如果您想在 Vertex AI 之外使用这些库,您需要自行安装它们。

考虑到我们将使用 Vertex AI 笔记本,并且不需要显式安装库,因此本书中不会包含如何安装的细节。如果您想在其他环境中安装库,包括Google Compute EngineGCE)或Google Kubernetes EngineGKE),您可以在每个库的相应网站上找到安装说明,例如:

接下来,我们将更详细地讨论 Vertex AI Workbench 笔记本,以及如何创建一个笔记本。

注意

在本章的后面部分,您将看到导入这些库的代码片段。这并不等同于安装。这些库已经安装在我们的 Vertex AI Workbench 笔记本中,但我们只需要将它们导入到笔记本上下文中才能使用。

Vertex AI Workbench

Vertex AI Workbench 是 Google Cloud 中的一个开发环境,它使您能够在 Vertex AI 内管理所有 AI/ML 开发需求。它基于 Jupyter 笔记本,提供了编写和运行代码的交互式界面。这使得笔记本非常灵活,因为您不仅可以与更广泛的 Vertex AI 生态系统进行编码交互,还可以与其他 Google Cloud 服务 API 进行交互。

Vertex AI Workbench 笔记本

在 Vertex AI Workbench 中,您可以使用以下三种类型的笔记本:

  • 管理笔记本,正如其名所示,由 Google 为您管理。这些对于许多用例来说是一个很好的默认选项,因为它们内置了许多有用的工具,并且已经准备好在 Google Cloud 上使用。它们在 JupyterLab 环境中运行,这是一个基于网页的交互式开发环境,用于笔记本。

  • 用户管理笔记本,正如其名所示,由您管理。如果需要对我们环境进行重大定制,则这些笔记本是合适的。它们是 Google Cloud 深度学习 VM 的可定制实例,这些 VM 是包含用于实现 深度学习DL)工作负载的工具的 虚拟机VM)镜像。然而,这些笔记本不仅可以用于深度学习用例。

  • Vertex AI Workbench 实例,这是 Google Cloud 在 2023 年晚些时候发布的新选项。这些可以被视为前两种选项的混合体,并且可能会随着时间的推移成为主要选项。在撰写本文的 2023 年 9 月,此选项目前仅以预览模式提供,因此我们现在将继续使用 选项 12

Google 还提供了一种名为 Colab 的服务,这是一个非常流行的服务,允许您通过公共互联网运行免费的笔记本。在 2023 年晚些时候,Google Cloud 还发布了一个名为 Colab Enterprise 的选项,使客户能够在自己的 Google Cloud 环境中使用 Colab。在撰写本文时,Colab Enterprise 也仅以预览模式提供。

管理笔记本和用户管理笔记本正在被弃用,因此在这本书中,我们将主要使用最新的选项:Vertex AI Workbench 实例。让我们现在就创建一个。

创建 Vertex AI Workbench 实例

要创建 Vertex AI Workbench 实例,请执行以下步骤:

注意

对于这些说明中没有明确提到的配置参数,请将这些参数保留在默认值。

  1. 在 Google Cloud 控制台中,导航到 Google Cloud 服务菜单 → Vertex AIWorkbench

  2. 选择 实例 选项卡并点击 创建新实例

  3. 在出现的侧面板中(参见 图 5**.1 以获取参考),为您的笔记本输入一个名称。或者,您可以使用该输入字段中自动生成的默认名称:

图 5.1:新建实例对话框

图 5.1:新建实例对话框

  1. 选择您首选的区域。

  2. 选择附加 GPU 的选项(在撰写本文时,您应该选择标有附加 1 个 NVIDIA T4 GPU的框)。参见图 5**.1以获取参考。

  3. 目前请将网络配置细节保留为默认值。

  4. 在侧面板的底部,点击高级选项

  5. 在随后出现的屏幕上(参见图 5**.2以获取参考),确保选中启用 Dataproc的选项并点击继续(您可能需要向下滚动以看到继续按钮):

图 5.2:新实例对话框(继续)

图 5.2:新实例对话框(继续)

  1. 在随后出现的屏幕上(即环境配置屏幕),选择使用最新版本并点击继续

  2. 在随后出现的屏幕上,您可以使用所有默认值(除非您有更改任何内容的偏好)并点击继续

  3. 您可以点击两次继续按钮(即接受下一两个屏幕上的默认值,除非您有更改的偏好)直到达到网络配置屏幕。

  4. 网络配置屏幕上,确保选中分配外部 IP 地址的选项。

  5. 除非您有特定的网络配置需求,否则您可以直接使用项目中默认的网络。

  6. 点击继续

  7. 在随后出现的屏幕上(即IAM & 安全屏幕),确保安全选项部分中的所有选项都已选中。

  8. 选择屏幕底部的创建,并等待几分钟以创建笔记本。

    当笔记本运行起来时,笔记本名称左侧将出现一个绿色的勾选标记。

  9. 最后,点击打开 JupyterLab

在此阶段,我想强调一组重要的集成和功能,这是 Google Cloud 在 Vertex AI Notebooks 的 JupyterLab 界面中添加的。

Vertex AI Notebook JupyterLab 集成

在您的 Vertex AI Notebook 实例的 JupyterLab 界面中,您会在屏幕的左侧注意到一组图标,如图图 5**.3所示:

图 5.3:Google Cloud JupyterLab 集成

图 5.3:Google Cloud JupyterLab 集成

这些图标代表我们可以在 Vertex AI 的 JupyterLab Notebook 实例中直接使用的集成。例如,如果我们点击 BigQuery 图标,我们可以看到我们的 BigQuery 数据集,我们甚至可以使用集成的 SQL 编辑器直接从 JupyterLab Notebook 界面运行 SQL 查询。

我建议点击各种图标来了解更多关于它们的功能。其他有用的功能包括与 Google Cloud Storage 集成的能力以及一个允许我们安排笔记本执行选项。后者对于需要定期自动重复的工作负载非常有用,这在数据科学中是一个常见需求(例如,每天对新数据进行重新训练、评估和部署模型)。

现在笔记本实例已经创建,我们将克隆我们的 GitHub 仓库,以便我们可以访问我们的笔记本代码并跟随本章的活动。

克隆 GitHub 仓库

克隆我们的 GitHub 仓库是将本章动手活动的所有资源快速导入到 Google Cloud Vertex AI 笔记本实例中的最简单方法。要将我们的仓库克隆到笔记本中,请执行以下步骤:

  1. 点击屏幕左侧菜单中的Git符号。符号看起来像图 5.4中所示:

图 5.4:Git 符号

图 5.4:Git 符号

  1. 选择克隆仓库

  2. 输入我们的仓库 URL:github.com/PacktPublishing/Google-Machine-Learning-for-Solutions-Architects.

  3. 如果有任何选项显示,请保留它们的默认值。

  4. 选择克隆

  5. 你应该会在笔记本中看到一个新文件夹出现,命名为Google-Machine-Learning-for-Solutions-Architects

现在,我们已经准备好开始使用我们的笔记本实例了!让我们继续到下一节,我们将进行一些无监督训练。

在 Vertex AI 上使用 scikit-learn 进行 UML

在本节中,我们将开始使用我们的 Vertex AI Workbench 笔记本来训练模型。我们将从一个相对简单的用例开始,我们将创建一个无监督模型来发现数据中的聚类模式。在我们深入代码之前,我们将先花一分钟讨论我们将在本节中使用的聚类算法,它被称为 K-means。

K-means

你可能还记得我们在第一章中讨论了无监督学习UL)机制,例如聚类。记住,在聚类中,数据点根据模型观察到的特征或特征之间的相似性被分组在一起。图 5.5提供了这个概念的可视化表示,显示了左侧的输入数据和右侧的结果数据聚类:

图 5.5:聚类

图 5.5:聚类

K-means 是聚类算法的一个例子,它被归类为中心点聚类算法。这意味着它选择一个中心点,这是一个代表我们每个簇中心的点。每个簇的成员是我们数据集中的数据点,它们在每个簇中的成员资格将取决于它们与每个中心点距离的数学评估。从每个中心点的这种邻近度或距离通常用欧几里得距离来计算,如方程 5.1 所示:

d(x,y)=∑i=1n(xi−yi)2

方程 5.1:欧几里得距离

别担心——我们将会更详细地讨论这个问题。图 5.5 中显示的图表代表所谓的特征空间,并且显示了我们的每个数据点在特征空间中的位置。在上述图表的情况下,它们代表一个二维特征空间,每个数据点都有一个 xy 坐标,这些坐标代表了数据点在特征空间中的位置。也就是说,xy 坐标是每个数据点的特征。如果我们从图表上取任意两点,欧几里得距离就是这两点之间直线距离,这个距离是通过将 xy 坐标(即每个数据点的特征)代入图 5.1 中所示的方程来计算的。

数据点可以作为其特征具有比 xy 坐标更多的坐标,这个概念也适用于更高维度的特征空间。

让我们用一个比 xy 坐标更具体的例子来说明。我们的数据集可能包括有关零售公司客户的详细信息,每个客户的特征可能包括他们的年龄、他们居住的城市以及他们在公司商店最近一次访问中购买的商品。聚类算法如 K-means 可以通过寻找他们特征与每个组中心点之间的相似性来将这些客户分组。

讨论 K-means 时经常出现的一个问题是:如何选择质心?例如,算法如何知道使用多少个质心,以及在哪里放置它们在特征空间中?让我们首先解决质心的数量问题。这被指定为算法的“超参数”。这意味着你可以告诉算法使用多少个质心(因此形成多少个簇)。实际上,这反映在名称“K-means”中,其中 K 代表质心或簇的数量。你通常会尝试不同的质心数量,直到找到一个值,该值最大化获得的信息量并最小化每个簇中的方差。用于找到 K 的最佳值的机制通常被称为“肘部方法”。使用肘部方法,我们在不同 K 值的范围内对数据集运行 K-means 聚类(例如 1-10)。然后,对于每个 K 值,计算所有簇的平均得分。默认计算的得分称为畸变。畸变表示每个点与其分配的簇中质心的平方距离之和,这再次与方程 5.1相关。如果你将 K 值与每次运行中的畸变得分进行绘图,你通常会注意到畸变得分随着 K 值的增加而下降。畸变得分通常会开始急剧下降,最终开始以更小的增量下降。当添加新的簇(即增加 K 值)不再显著减少畸变得分时,你通常可以认为已经找到了 K 的最佳值。

现在,让我们讨论算法如何在特征空间中放置质心的位置。它首先在特征空间中随机放置它们,并将数据点随机分配给每个质心。然后,它重复以下步骤,直到每个簇中没有新的数据点被添加,此时认为已经计算出了最佳的聚类位置:

  1. 计算哪些数据点最接近质心,并将它们分配给该质心。

  2. 计算这些点的平均值(均值)。

  3. 移动质心。

现在我们已经涵盖了 K-means 聚类的理论,让我们继续到有趣的部分,即实际实现算法。

在 Vertex AI 中实现 UML 工作负载

我们将在 scikit-learn 中使用 K-means 算法来开始实现我们的 Vertex AI 中的 UML 工作负载。在 scikit-learn 中使用 K-means 的一个典型的聚类示例是使用所谓的鸢尾花数据集,以找到数据中的聚类模式。正如其名所示,鸢尾花数据集包含了各种鸢尾花的数据。

商业案例

我们的公司 BigFlowers.com 最近收购了一家较小的花店,在这个过程中,我们获得了他们所有的数字资产,包括包含他们花卉库存的数据集。不幸的是,他们没有很好地记录他们的数据集,所以我们不清楚他们的库存中有什么。

我们的任务是尽可能多地了解花卉库存的内容,因此我们将使用一些数据分析工具和机器学习模型来了解更多关于数据集的信息。我们将要做的第一件事是尝试找到任何模式,例如逻辑分组,这可能有助于我们了解数据集中是否存在不同的对象类别,以及额外的信息,例如存在多少不同的类别。

注意:在撰写本文时,公司 BigFlowers.com 并不存在,我们在这里的练习仅用于示例目的。

要开始这项任务,请导航到您在上一节中创建的 Vertex AI 笔记本中的 Google-Machine-Learning-for-Solutions-Architects 文件夹。然后,导航到 Chapter-05 文件夹,双击 Chapter-5.ipynb 文件(如果提示,请选择 Python 内核),并执行以下步骤。

  1. 在我们的笔记本中,我们首先需要导入所需的资源,例如 scikit-learn 的 K-means 类,以及 pandas 和 Matplotlib 库。我们还将导入一个从 scikit-learn 加载 iris 数据集的函数。要执行这些操作,请将以下代码输入到笔记本中的交互式提示(或使用您从 GitHub 克隆的笔记本)中。笔记本中的以下代码执行了这些步骤:

    from sklearn.cluster import KMeans
    from sklearn.datasets import load_iris
    import pandas as pd # for exploring our data
    import matplotlib.pyplot as plt # for plotting our clusters
    from mpl_toolkits.mplot3d import Axes3D # Specifically for creating a 3-D graph
    
  2. 要执行代码,请按住键盘上的 Shift 键,然后按 Enter 键。考虑到代码只是导入库,除非发生错误,否则您不会在屏幕上看到任何输出。

注意

从现在开始,当我们进行 Vertex AI Workbench 笔记本中的活动时,我们将只为每个步骤提供代码示例,这表示您需要将此代码输入到笔记本中下一个可用的空单元格中(除非您正在使用已包含代码的克隆笔记本),然后执行单元格,就像您之前处理那段代码一样。

注意

在 Jupyter 笔记本中每个单元格的左侧,有一个看起来像这样的方括号符号:[ ]

这可以用来了解单元格的状态,指标如下:

[ ](空):该单元格尚未执行。

[*](星号):该单元格正在执行。

[1](任何数字):该单元格已执行完成。

  1. 接下来,我们将读取 iris 数据集:

    # Load the iris dataset:
    iris = load_iris()
    # Assign the data to a variable so we can start to use it:
    iris_data = iris.data
    
  2. 让我们使用 pandas 获取有关我们数据集的一些信息:

    # Convert the dataset to a pandas data frame for analysis:
    iris_df = pd.DataFrame(iris_data)
    # Use the info() function to get some information about the dataset
    iris_df.info()
    

    输出应类似于 图 5.6 中所示:

图 5.6:pandas.DataFrame.info() 输出

图 5.6:pandas.DataFrame.info() 输出

  1. info() 函数的输出显示我们的数据集包含什么类型的数据。在这种情况下,我们可以看到它包含 150 行(从 0 到 149 索引)和 4 列(从 0 到 3 索引),并且每个单元格中的数据值是浮点数。我们的数据集中的每一行都是一个数据点,它代表一朵特定的鸢尾花,每一列是数据集中的一个特征。如果我们查看 scikit-learn 文档中关于鸢尾花数据集的描述,该描述可以在 scikit-learn.org/stable/datasets/toy_dataset.xhtml#iris-dataset 找到,我们可以看到特征是:

    1. 萼片长度(厘米)

    2. 萼片宽度(厘米)

    3. 花瓣长度(厘米)

    4. 花瓣宽度(厘米)

    从这个例子中,我们可以理解我们数据集中每个单元格中的浮点数是测量每朵花四个方面的值。

  2. 我们还可以预览数据的一个子集,以查看每个单元格的实际值,如下所示:

    iris_df.head()
    

    输出应类似于 图 5.7 中所示:

图 5.7:pandas.DataFrame.head() 输出

图 5.7:pandas.DataFrame.head() 输出

  1. 现在,我们将使用 K-means 根据数据集的特征将相似的数据点分组在一起。首先,我们创建了一个 K-means 模型的实例,并指定它将有三簇,因为在这种情况下,数据集文档告诉我们我们的数据集中有三种不同的鸢尾花类别。如果我们不知道需要使用多少簇,那么我们可以尝试不同的簇数,并使用肘部方法找到最佳数量:

    kmeans_model = KMeans(n_clusters=3)
    
  2. 在这一点上,我们已经定义了我们的模型,但它还没有从我们的数据中学习到任何东西。接下来,我们指示模型“拟合”到我们的数据集。术语 fit 被许多算法用来指代训练过程,因为在训练过程中,这正是算法试图做的事情;它试图创建一个尽可能精确地(不发生过拟合)拟合给定数据集的模型:

    kmeans_model.fit(iris_data)
    
  3. 当我们的模型完成训练过程后,我们现在可以使其对数据进行聚类。我们将原始数据集输入到模型中,根据它在训练期间学习的模式,它将根据定义的每个簇放置数据点:

    kmeans_model.predict(iris_data)
    
  4. 最后,我们将模型的标签存储在一个变量中,这样我们就可以在下一个单元中可视化簇:

    labels = kmeans_model.labels_
    
  5. 接下来,我们将可视化 K-means 创建的簇:

    # Create a figure object:
    fig = plt.figure()
    # Define the axes (note: the auto_add_to_figure option will default to False from mpl3.5 onwards):
    axes = Axes3D(fig, auto_add_to_figure=False)
    # Add the axes to the figure:
    fig.add_axes(axes)
    # Create the scatter plot to graph the outputs from our K-means model:
    axes.scatter(iris_data[:, 2], iris_data[:, 3], iris_data[:, 1],
        c=labels.astype(float))
    # Set the labels for the X, Y, and Z axes:
    axes.set_xlabel("Petal length")
    axes.set_ylabel("Petal width")
    axes.set_zlabel("Sepal width")
    
  6. 生成的图表应类似于 图 5.8 中所示的图表。注意我们如何在图表中看到三个不同的数据点簇,每个不同的簇都按紫色、绿色或黄色进行着色编码:

图 5.8:K-means 聚类图

图 5.8:K-means 聚类图

这为我们提供了一些有用的信息。我们可以看到数据集中的三个不同的数据点类别或聚类,其中数据点与其同一聚类中的其他点具有相似的特征,但与其他聚类中的数据点不同。我们无需对数据集进行标记就能获得这些见解,考虑到标记是一个耗时且容易出错的任务,这非常有用。

注意

尽管我们的数据集包含四个特征(也称为“维度”),但人类只能看到/可视化三维的东西。因此,我们只使用了四个特征中的三个来创建我们的图表。以下是我们定义用于图表中的特征的行,其中数字代表要使用的特征:

axes.scatter(iris_data[:, 2], iris_data[:, 3], iris_data[:, 1], c=labels.astype(float))

你可以尝试通过将每个数字更改为 0 到 3 之间的任何值来玩转这个图表,只要每个条目都是唯一的值(也就是说,在代码中不要重复任何数字)。

每次你进行更改时,都可以再次执行单元格以更新图表。

现在我们已经看到了在 Vertex AI 中实现 UML 工作负载需要什么,接下来让我们继续学习如何在下一节中实现 SML 工作负载。

在 Vertex AI 上使用 scikit-learn 实现回归模型

我们将在 Vertex AI 工作台中构建的第一个 SML 模型是一个线性回归模型。你可能还记得我们在 第一章 中描述了线性回归。

商业案例

我们在 BigFlowers.com 的老板在工作场所举办了一场有趣的竞赛。员工被要求预测当给出与该花朵相关的其他测量值时,鸢尾花花瓣的长度,例如萼片长度、萼片宽度和花瓣宽度。预测最准确的人将获得一份大奖,员工可以使用技术来帮助他们进行预测,因此我们将构建一个机器学习模型来帮助我们做出这些预测。

在上一节中,我们使用了 scikit-learn 中的 K-means 算法。在本节中,我们将使用 scikit-learn 中的线性回归算法。因此,我们需要将 LinearRegression 类导入我们的笔记本上下文中。我们还将导入一个函数,该函数将计算 均方误差MSE)指标,我们在 第二章 中描述了该指标,它通常用于评估线性回归模型。

我们可以使用相同的花瓣数据集来构建我们的线性回归模型,因此我们不需要重复之前的任何数据集导入步骤,因为它已经加载到我们的笔记本上下文中。这是一个需要注意的重要概念;我们可以根据业务用例和期望的结果,在相同的数据上使用不同类型的模型。然而,正如我们在第二章中讨论的,SML 模型训练引入了一些关于数据集使用方面的额外要求,我们将在下面进行描述。

记住

监督学习(SL)用例中,我们需要定义数据集中哪一列被指定为“目标”特征。这是我们试图根据数据集中的其他特征进行预测的特征。在训练过程中,该列的一些元素被用作标签,代表模型学习的已知、正确的答案。

数据集中其他特征的值用作输入。在预测过程中,模型使用它所学习到的所有输入特征与目标特征之间的关系,根据输入特征的值来预测目标特征的值。

此外,请记住,在 SL 用例中,我们通常将数据集分为训练、验证和测试等子集。训练数据集,正如其名所示,是模型训练所用的数据。测试数据集是我们评估训练好的模型的方式(基于为该模型定义的指标),而验证集通常用于超参数调整。

注意

我们将在后面的章节中探讨超参数调整。在我们当前的章节中,我们将训练一个单一的回归模型,然后直接对其进行测试,因此我们不需要从我们的数据中分离出一个验证子集。因此,我们将仅将数据集分为训练集和测试集。

要开始构建我们的线性回归模型,请执行以下步骤:

  1. 从 scikit-learn 导入LinearRegression类,并导入一个将使我们能够将数据集分割成训练集和测试集的函数,以及一个将计算我们稍后用于评估模型性能的 MSE 指标的函数:

    from sklearn.linear_model import LinearRegression
    from sklearn.metrics import mean_squared_error
    from sklearn.model_selection import train_test_split
    
  2. 定义我们数据集中哪一列是我们想要用作预测目标特征的列:

    target = iris_df[[2]]
    

记住:

在本章的前一节中,我们查阅了 iris 数据集的文档,并看到数据集中的列如下:花萼长度(厘米),花萼宽度(厘米),花瓣长度(厘米),花瓣宽度(厘米)。这些列从 0 到 3 索引。考虑到我们想要预测花瓣长度,我们已选择iris_df数据框的列 2 作为我们的目标列。

  1. 接下来,定义我们的输入特征。在这种情况下,我们使用除了列 2 之外的所有特征列(因为我们已定义列 2 是我们的目标列):

    input_feats = iris_df[[0, 1, 3]]
    
  2. 将我们的数据集分割成单独的训练集和测试集:

    input_train, input_test, target_train, target_test = \
        train_test_split(input_feats,target,test_size=0.2)
    

注意

test_size变量的值设为 0.2 意味着原始数据集的 20%将被分离出来以创建测试数据集。剩下的 80%形成训练数据集。input_traininput_test数据集包含训练过程中使用的输入特征以及将用于测试训练模型的输入特征。target_traintarget_test数据集包含训练和测试数据集的相应标签(即“正确答案”)。

  1. 现在,让我们使用训练数据集来训练我们的线性回归模型,然后使用测试数据集来生成模型预测:

    # Create an instance of a LinearRegression model
    lreg_model = LinearRegression()
    # Train the model by fitting it to the training data
    lreg_model.fit(input_train,target_train)
    # Use the test set to generate predictions
    target_predictions = lreg_model.predict(input_test)
    

记住

为了测试训练模型,我们将input_test特征发送给它,并要求它根据input_test特征的值预测相应的目标特征值。然后我们可以将模型的预测与target_test值(即已知的、正确的答案)进行比较,以查看其预测与正确、预期的值有多接近。

  1. 最后,是时候看看我们的模型基于input_test数据做出了哪些预测了!

    pred_df = pd.DataFrame(target_predictions[0:5])
    pred_df.head()
    

    输出结果应类似于图 5.9所示,尽管数字可能不同(预测值位于右侧列,忽略顶部的数字 0,它是列标题):

图 5.9:线性回归模型预测

图 5.9:线性回归模型预测

  1. 现在,让我们看一下target_test数据集中相应的已知、正确值:

    target_test.head()
    

    输出结果应类似于图 5.10所示,尽管数字可能不同(数值位于右侧列,忽略顶部的数字 2,它是列标题):

图 5.10:来自 target_test 数据集的已知、正确值

图 5.10:来自 target_test 数据集的已知、正确值

  1. 如我们所见,在某些情况下数字非常接近。然而,让我们使用指标来评估模型的整体性能。为此,我们使用mean_squared_error()函数将预测与target_test数据集中的正确值进行比较,并生成 MSE 指标值:

    mean_squared_error(target_test,target_predictions)
    
  2. 值应类似于 0.08871798773326277。

    这是一个相当不错的数值,因为误差相当低,这意味着我们的模型在预测目标值方面做得很好。在这个阶段,我认为我们可能在预测鸢尾花花瓣长度的比赛中赢得那个大奖!

深入探讨前一小节中提到的各种数据集

我们在动手活动中的train_test_split函数从源数据集中创建了以下子集:

input_train:训练过程中使用的输入特征。

input_test:将用于测试训练模型的输入特征。

target_train: 在训练过程中使用的目标标签。在训练过程中,模型使用这些值作为它试图预测的已知、正确答案。这些是训练过程中的关键,因为在训练过程中,模型试图学习输入特征之间的关系,以帮助它尽可能准确地预测这些答案。

target_test: 在测试过程中使用的目标标签。这些是从原始数据集中分离出来的已知、正确答案,因此它们没有被包含在训练过程中。因此,模型在训练过程中从未见过这些值。然后我们使用这些值来测试训练后模型的性能。

现在我们已经看到了线性回归的实际应用,让我们继续进行我们的第一个 SL 分类任务。

在 Vertex AI 上使用 XGBoost 实现分类模型

到现在为止,你已经开始熟悉许多在数据科学项目中常用的流行库。在本节中,我们将开始使用另一个非常流行的库,XGBoost,它可以用于分类或回归用例。

尽管我们在本章开头简要介绍了 XGBoost,但在这里我们将更深入地探讨其工作原理,从决策树的概念开始。

决策树

在本章前面讨论梯度提升主题时,我们提到梯度提升的一个组成部分是弱学习者的概念。决策树是弱学习者的一个例子。让我们从一个简单的决策树例子开始。参考图 5.11,它显示了一个用于估计银行客户是否可能购买房屋的决策树,基于他们的年龄组和收入:

图 5.11:决策树

图 5.11:决策树

决策树由一系列决策组成。过程从所谓的根节点开始,在树的每个点上都会做出一个决策,然后引导我们采取下一步。因此,决策序列导致通过树的一条路径,直到我们达到一个不再包含进一步决策的最终点。这样的点被称为叶节点。按照图 5.11 中的步骤,它确定如果银行客户年龄在 25 岁到 65 岁之间,并且年收入超过 50,000 美元,他们很可能购买房屋。决策树中的所有其他因素都表明,他们不太可能购买房屋。

尽管图 5.11 中的例子相当简单,但这种过程可以在机器学习应用中算法化使用,其中每个点的决策基于某种阈值。例如,如果值小于或大于某个阈值,则继续评估特征 A;否则,评估特征 B 或停止评估特征。在使用决策树时,一个目标就是找到数据集中哪些特征可以帮助做出最佳决策,以及需要做出多少决策,这被称为树深度,以便得到最佳预测。

决策树过程中的两个关键概念是信息增益。在这个上下文中,熵是给定实体分组中不纯度的度量。例如,完美捕捉同一组中相同实体的分组将具有零熵,而具有大量实体之间差异的分组将具有高熵。在这个上下文中,信息增益可以看作是我们决策树中每个决策减少熵的程度。在我们的图 5.11 中的银行客户例子中,初始客户集(在做出任何决策之前)包括我们所有的客户,这个集合将具有很多熵,因为它将包括所有年龄段和各种经济状况以及其他特征的人。

现在,当我们试图找出哪些客户特征可以帮助我们的算法决定他们是否可能购买房屋时,我们发现一个模式表明,一定年龄组(比如说,25 至 65 岁之间)的人,并且每年收入超过一定数额(比如说,超过 50,000 美元)的人,比其他客户更有可能购买房屋。因此,在这种情况下,客户的年龄和收入是帮助最大化信息增益并减少熵的例子,因此它们将是我们决策树中良好的决策点特征。另一方面,诸如他们的名字或音乐偏好等特征不太可能与他们购买房屋的概率有任何相关性,因此这些特征不会在我们的决策树中的决策点产生显著的信息增益,决策树模型在训练过程中可能会学会忽略这些特征。

决策树算法对于某些用例可能非常有效,尽管它们有一些局限性,例如容易过拟合。这就是集成概念发挥作用的地方,因为将许多树结合起来可以创建一个更强大的预测模型——而且比单个树本身更不可能过拟合。这可以通过使用 Bagging 方法,例如随机森林算法(参见图 5.12以供参考)来实现,该算法在集成中的每个树都使用从训练特征空间中随机子样本(带替换)进行训练,或者可以通过使用 Boosting 方法,正如我们在梯度提升案例中描述的那样:

图 5.12:随机森林

图 5.12:随机森林

当我们使用决策树进行梯度提升时,我们将其称为梯度提升树。简单梯度提升树实现的一个固有挑战是算法的顺序性,即一个训练迭代中树的误差需要在下一个迭代中使用来训练集成中的下一个树。然而,正如我们在本章前面提到的,XGBoost 克服了这一限制,并且可以并行训练数千棵树,这大大加快了整体训练时间。

在了解这些背景信息的基础上,让我们看看如何使用 XGBoost 在 Vertex AI 中构建分类模型。这里的业务案例不需要专门的突出显示部分,因为它相当直接:我们的模型将需要根据每朵鸢尾花的花瓣和萼片测量值来预测其类别。

注意

鸢尾花数据集包含关于适合三个类别之一的鸢尾花的详细信息:

  • Iris-Setosa

  • Iris-Versicolour

  • Iris-Virginica

在本章前一部分的线性回归示例中,我们决定使用花瓣长度特征作为我们试图预测的目标。然而,在本节中,我们将尝试根据数据集中所有其他特征来预测每朵鸢尾花的类别(或分类)。因为存在多个类别,这将是一个多类别分类任务。

本节中我们将介绍一个新的特征——鸢尾花数据集的分类特征,我们尚未与这个特征进行交互。接下来,我们将讨论如何访问这个特征。

scikit-learn 中的鸢尾花数据集包含多个对象。其中之一是数据对象,这是我们本章到目前为止一直在使用的。

数据集中另一个对象是目标对象,它包含类别特征列。类别特征列表示类别如下:

0 = Iris-Setosa

1 = Iris-Versicolour

2 = Iris-Virginica

记住本章前面提到的以下两行代码:

iris = load_iris()

iris_data = iris.data

那些代码行将 iris 数据集加载进来,并将该数据集的data对象特别分配给iris_data变量。当时我们没有引用target对象,因为我们不需要这样做。

我们将在本节中开始使用target对象,为此,我们将将其分配给一个名为iris_classes的变量。

要训练分类模型,请在您的 Vertex AI Workbench 笔记本中执行以下步骤:

  1. 就像我们在上一节中使用的库一样,在开始使用之前,我们需要导入 XGBoost 库。更具体地说,我们将从XGBoost库中导入XGBClassifier类:

    from xgboost import XGBClassifier
    
  2. 考虑到我们将用它来进行分类用例,我们还将导入一个函数,该函数将计算一个可以用于评估分类模型的指标,称为accuracy

    from sklearn.metrics import accuracy_score
    
  3. 将 iris 数据集的target对象分配给iris_classes变量,以便我们可以开始引用它:

    iris_classes = iris.target
    
  4. 创建我们的训练和测试数据集拆分,就像我们在上一节中的回归示例中所做的那样:

    xgb_input_train,xgb_input_test,xgb_target_train,xgb_target_test=
        train_test_split(iris_data, iris_classes, test_size=.2)
    
  5. 创建一个模型实例并指定超参数:

    xgbc = XGBClassifier(n_estimators=2, max_depth=2, 
        learning_rate=1, objective='multi:softmax')
    

深入了解

在前面的代码片段中指定的超参数代表以下内容:

n_estimators:在集成中使用的决策树数量。

max_depth:每个树的最大决策点(或最大深度)数。

learning_rate:在成本函数优化期间使用的学习率。

objective:我们希望模型执行的预测类型。在这种情况下,我们希望它使用softmax函数进行多类分类。

  1. 让我们训练我们的模型:

    xgbc.fit(xgb_input_train, xgb_target_train)
    

    你将看到类似于图 5.13的输出,该图总结了模型参数的值(包括默认值):

图 5.13:XGBoost 参数

图 5.13:XGBoost 参数

  1. 现在,是时候使用xgb_input_test数据集从我们的模型中获取预测了:

    xgb_predictions = xgbc.predict(xgb_input_test)
    
  2. 让我们看看它对xgb_input_test数据集中的每个项目做出了什么预测:

    xgb_predictions
    

    输出应该是一个预测类别的数组,这些类别由 0、1 或 2 表示,类似于图 5.14中显示的输出,尽管你得到的值可能不同:

图 5.14:XGBoost iris 分类预测

图 5.14:XGBoost iris 分类预测

  1. 我们的模型做对了没有?为了找出答案,我们可以检查已知的正确答案:

    xgb_target_test
    

    这段代码的输出也应该是一个类别的数组,这些类别由 0、1 或 2 表示,类似于图 5.15中显示的输出,尽管你得到的值可能不同:

图 5.15:已知、正确的答案

图 5.15:已知、正确的答案

  1. 它们看起来很相似,但为了确保,让我们通过将我们的预测与已知的正确答案进行比较来测试准确性:

    accuracy_score(xgb_target_test,xgb_predictions)
    

    分数将以表示准确百分比的浮点数形式呈现。如果结果是 1.0,这意味着我们的预测是 100%准确的!

深入探讨

准确度指标量化了我们的模型在所有预测中正确预测的比例,如下公式所示:

准确度 = 正确预测数 / 总预测数

评估模型预测性能有许多其他指标,scikit-learn 内置了计算这些指标的功能。作为额外的学习,我们建议你查阅以下链接的 scikit-learn 指标文档:scikit-learn.org/stable/modules/classes.xhtml#module-sklearn.metrics

干得好!你已经在 Google Cloud Vertex AI 上正式训练了多个自己的模型!让我们回顾一下本章所学的内容。

摘要

在本章中,我们从第一章和第二章中提取了许多机器学习概念并将其付诸实践。我们使用聚类以无监督方式在我们的数据中找到模式,并且你特别学习了更多关于 K-means 在聚类中的应用及其工作原理。

然后,我们深入探讨了 SL,你探索了 scikit-learn 中的线性回归类,并学习了如何使用指标来衡量回归模型的性能。

接下来,你学习了如何使用 XGBoost 构建分类模型,并根据特征对鸢尾花数据集中的项目进行分类。

不仅你将所有这些重要概念付诸实践,而且你还学会了如何创建和使用 Vertex AI Workbench 管理的笔记本。

此外,你还学习了机器学习行业中的其他重要概念,例如决策树的工作原理、梯度提升的工作原理以及 XGBoost 如何增强该功能以实现行业中最有效的机器学习算法之一。

在这一章中,你需要学习很多东西,你应该为自己的技能和知识在当今商业世界中需求很高的领域得到显著提升而感到自豪。

在下一章中,你将学习另一组极其重要的技能,因为我们将会关注机器学习工作负载的数据分析和数据转换。

第六章:深入探讨 – 在 Google Cloud 上为 AI/ML 工作负载准备和处理数据

在上一章中,我们通过查看与我们的数据集相关的一些细节,使用诸如pandas.DataFrame.info()pandas.DataFrame.head()等函数,进行了一些非常基础的数据探索。在本章中,我们将更深入地探讨数据探索和准备领域,这在本章中由数据科学生命周期图中用蓝色突出显示的部分所代表。1*:

图 6.1:数据探索和处理

图 6.1:数据探索和处理

在典型数据科学项目的早期阶段,您可能会在 Jupyter 笔记本中执行许多数据探索和准备步骤,正如我们所看到的,这对于实验小数据集是有用的。然而,当您将工作负载投入生产时,您可能会使用更大的数据集,在这种情况下,您通常会需要使用不同的工具来处理您的数据。在大型规模数据处理、分析和 AI/ML 方面,Google 被视为行业领导者。例如,Google Cloud BigQuery 已成为行业中最受欢迎的数据仓库服务之一,Google Cloud 还拥有许多其他行业领先的数据处理和分析工作负载服务。

在本章中,我们将学习如何使用 Vertex AI、BigQuery、Dataproc 和 Cloud Composer 等工具探索、可视化和准备数据以供 ML 用例使用。此外,我们将深入了解实时处理流数据的 Dataflow,并介绍数据管道的基本原理。到本章结束时,您将能够创建、构建和运行 Google Cloud 上的数据管道,为您在当今快节奏、数据驱动的世界中承担复杂数据处理任务提供必要的技能。

本章涵盖了以下主题:

  • 先决条件和基本概念

  • 将数据导入 Google Cloud

  • 探索和可视化数据

  • 清洗和准备数据以供 ML 工作负载使用

  • 数据管道简介

  • 处理批量和流数据

  • 在 Google Cloud 上构建和运行数据管道

让我们先来讨论本章的先决条件。

本章的先决条件

在我们可以开始执行本章的主要活动之前,本节中的活动需要完成。

启用 API

除了我们在前几章中讨论的用于启用 Google Cloud API 的方法,例如 Google Cloud Shell 或 Google Cloud 控制台中被提示,您还可以主动搜索一个 API 以在控制台中启用它。为此,您需要执行以下步骤,其中[服务/API 名称]是您希望启用的服务/API 的名称:

  1. 在 Google Cloud 控制台中,导航到Google Cloud 服务菜单 → APIs & ServicesLibrary

  2. 在搜索框中搜索[服务名称]

  3. 从结果列表中选择 API。

  4. 在显示 API 信息的页面上,点击启用

为以下每个服务/API 名称执行前面的步骤:

  • Compute Engine API

  • Cloud Scheduler API

  • Dataflow API

  • 数据管道 API

  • Cloud Dataproc API

  • Cloud Composer API

  • Cloud Pub/Sub API

在您启用所需的 API 之后,我们就可以继续下一节了。

IAM 权限

在本节中,我们将设置启用本章后续活动所需的身份和访问管理IAM)权限。

服务帐户

在前面的章节中,我提到过有多种方式可以与 Google Cloud 服务进行身份验证,您在第四章中使用的 API 密钥是最简单的身份验证方法。现在,随着我们向更复杂的使用案例迈进,我们将开始使用一种更高级的身份验证形式,称为服务帐户。

Google Cloud 服务帐户是 Google Cloud 服务、应用程序和虚拟机VM)用于与其他 Google Cloud 资源交互和验证的特殊帐户。它们是一个有趣的概念,因为除了是资源外,它们还被认为是有身份或主体,就像人一样,就像人一样,它们有自己的电子邮件地址和与它们相关的权限。然而,这些电子邮件地址和权限适用于使用它们的机器和应用程序,而不是人。服务帐户提供了一种方式,让机器和应用程序在系统想要执行需要通过 Google Cloud API 和资源进行身份验证的活动时拥有身份。

我们将创建一个服务帐户,用于在本章中执行的活动所需的权限。

数据处理服务帐户

考虑到在本章中我们将使用多个 Google Cloud 服务以不同的方式处理数据,我们将创建一个具有主要与 Google Cloud 数据处理服务相关的权限的服务帐户,例如 BigQuery、Cloud Composer、Dataflow、Dataproc、Google Cloud StorageGCS)和 Pub/Sub。

执行以下步骤以创建所需的服务帐户:

  1. 在 Google Cloud 控制台中,导航到Google Cloud 服务菜单→ IAM & Admin服务帐户

  2. 选择创建 服务帐户

  3. 对于服务帐户名称,输入data-processing-sa

  4. 在标题为授予此服务帐户访问项目的章节中,添加*图 6**.2 中显示的角色:

图 6.2:Dataflow 工作服务帐户权限

图 6.2:Dataflow 工作服务帐户权限

  1. 选择完成

我们的服务帐户现在已准备好在本章的后续部分使用。

注意

在我们刚刚创建的服务账户中,我们还添加了服务账户用户权限。这是因为,在我们将要实施的某些用例中,我们的服务账户也需要暂时代表或“充当”其他服务账户或身份。有关代表服务账户的概念的更多信息,请参阅以下文档:cloud.google.com/iam/docs/service-account-permissions#directly-impersonate

云存储桶文件夹

我们将使用云存储桶来存储本章后面活动所需的数据。我们已经在第四章中创建了一个桶,因此我们可以简单地向桶中添加一些文件夹来存储我们的数据。执行以下步骤以创建文件夹:

  1. 在 Google Cloud 控制台中,导航到Google Cloud 服务菜单→云存储

  2. 点击第四章中创建的桶的名称。

  3. 选择创建文件夹

  4. 将其命名为data

  5. 选择创建

重复前面的步骤,使用以下额外的文件夹名称:

  • code

  • dataflow

  • pyspark-airbnb

我们的数据文件夹现在已准备好存储数据。

上传数据

我们将使用名为AB_NYC_2019.csv的文件作为本章某些活动的数据集。在第四章中您在本地机器上创建的 GitHub 仓库克隆副本中,您将在名为data的目录中找到该文件,该目录位于名为Chapter-06的目录内。

因此,您应该在您的本地机器上找到以下路径处的文件(如果您使用的是 Microsoft Windows,斜杠将被反转):

[您克隆我们的 GitHub 仓库的位置]/``Chapter-06``/data/AB_NYC_2019.csv

为了上传此文件,请执行以下步骤:

  1. 导航到上一节中在 GCS 中创建的data文件夹。

  2. 点击上传文件

  3. 现在,通过导航到您在本地机器上创建的 GitHub 仓库克隆副本中的Chapter-06/data目录,选择AB_NYC_2019.csv文件。

现在我们已经完成了先决条件,让我们讨论一些重要的行业概念,我们将在本章中深入探讨。

本章的基本概念

在本书中,我们的目标是为您提供有关如何使用相关 Google Cloud 服务来处理各种工作负载的知识,同时也提供与每个相关技术相关的重要行业概念。在本节中,我们简要介绍了为本章的学习活动提供额外背景的概念。

将数据摄入 Google Cloud

在前面的章节中,您已经执行了上传数据到 GCS 和谷歌云大数据查询(BigQuery)的步骤。除了对 GCS 和 BigQuery 执行批量上传外,还可以将这些服务中的数据流式传输。您将在本章中看到这一过程的具体操作。

本节提供了对谷歌云数据摄取选项的更全面概述。在这里,我们只涵盖谷歌云的服务,但您还可以在谷歌云上运行无数第三方数据库和数据管理服务,例如 MongoDB、Cassandra、Neo4j 以及通过谷歌云市场提供的许多其他服务。

对于流式数据处理用例,我们将在本章后面更详细地描述,您可以使用 Cloud Pub/Sub 从物联网设备或网站点击流源摄取数据。Dataflow 也可以用于从各种来源摄取数据,对其进行转换,并将其写入其他谷歌云服务,如 BigQuery、Bigtable 或云存储。正如我们将在本章后面讨论的,Dataflow 还支持批量数据处理用例。

谷歌云 Dataproc 可用于从兼容Hadoop 分布式文件系统HDFS)的源或其他分布式存储系统摄取数据,谷歌云数据融合也可以用于从各种来源摄取数据,对其进行转换,并将其写入大多数谷歌云存储和数据库服务。

对于关系型数据库数据,您可以使用谷歌云数据库迁移服务DMS)将数据摄取到谷歌云 SQL 中,这是一个为 MySQL、PostgreSQL 和 SQL Server 提供的完全托管的关系型数据库服务。您还可以使用标准 SQL 客户端、导入/导出工具和第三方数据库迁移工具将数据摄取到云 SQL 实例中。

对于非关系型数据库数据,有多种选择,包括以下内容:

  • 谷歌云 Bigtable,这是一个为大规模、低延迟工作负载提供的完全托管、可扩展的 NoSQL 数据库。您可以使用 Bigtable HBase API 或 Cloud Bigtable 客户端库将数据摄取到 Bigtable 中。

  • 谷歌云 Firestore,这是一个为 Web 和移动应用提供的完全托管、无服务器的 NoSQL 文档数据库。Firestore 提供了客户端库、REST API 或 gRPC API 来摄取数据。

  • 一些您可能也熟悉谷歌云数据存储(Google Cloud Datastore),它曾经是独立的谷歌云非关系型数据库服务,但已经与谷歌云 Firestore 有所合并。要了解更多关于这些数据库选项之间如何相互关联的详细信息,请参阅以下链接的谷歌云文档:cloud.google.com/datastore/docs/firestore-or-datastore

现在我们已经介绍了将数据导入 Google Cloud 的许多选项,让我们讨论在导入数据后我们可能想要对数据进行哪些操作,从数据转换方法开始,例如提取、转换、加载ETL)和提取、加载、转换ELT)。

ETL 和 ELT

ETL 和 ELT 是数据集成、处理和存储的两种方法。在 ETL 中,数据首先从源系统中提取出来,然后转换成另一种格式。这些转换可能包括清洗、丰富、聚合或去重。这些转换通常在一个中间处理引擎或暂存区域中进行。一旦数据被转换,它就被加载到目标系统中,这通常是数据仓库或数据湖。ETL 是一种传统方法,非常适合数据一致性和质量至关重要的环境。然而,由于在数据加载之前发生处理步骤,它可能既耗时又消耗资源。

另一方面,ELT 颠倒了最后两个步骤的顺序。数据首先从源系统中提取出来,然后直接加载到目标系统中,例如现代数据仓库或数据湖。转换步骤在目标系统内部执行,使用目标系统的处理能力。近年来,由于现代基于云的数据仓库的可扩展性和处理能力的提高,ELT 因其能够更快地加载并允许用户按需执行复杂转换而越来越受欢迎。

在 ETL 和 ELT 之间进行选择取决于数据处理环境的具体要求、数据质量需求以及目标系统的能力。

批量和流数据处理

从高层次来看,我们可以以两种主要方式处理数据:批量处理和流处理。在本节中,我们将解释这些方法,这将为我们提供本章后续活动中所需的知识。

批量数据处理

批量数据处理通常指的是以批量方式对大量数据集进行一系列转换。这类管道适用于需要在一小时或甚至几天内并行处理大量数据的用例。例如,想象一下您的公司在不同的地理区域运行在线零售业务,例如在北美有一个www.example.com网站,在英国有一个www.example.co.uk网站,在中国有一个www.example.cn网站。每个晚上,您可能希望运行一个工作负载,该工作负载将当天每个区域所有客户购买的所有商品汇总起来,将数据跨区域合并,然后将这些数据输入到机器学习模型中。这将是批量工作负载的一个例子。其他批量数据处理用例的例子包括以下内容:

  • 处理每日销售交易以生成业务决策报告

  • 分析来自 Web 服务器的日志文件以了解特定时间窗口内的用户行为(例如,一天或一周)

  • 运行大规模数据转换作业,例如将原始数据转换为下游数据系统所需的结构化格式

除了需要定期执行的数据处理任务之外,公司可能还需要实时或接近实时地处理数据,这使我们来到了流数据处理的主题。

流数据处理

流数据处理,正如其名所示,涉及对持续流入系统的数据流进行工作,通常是在持续的基础上。而不是将庞大的数据集作为一个单独的作业进行处理,流数据处理用例中的数据通常由在飞行中的小数据块组成。流数据处理的例子包括以下内容:

  • 分析社交媒体流以识别趋势或检测事件(例如,情感分析(SA),标签跟踪)

  • 实时监控和分析物联网传感器数据以检测异常、触发警报或优化流程

  • 实时处理金融交易以进行欺诈检测和预防

现在我们已经讨论了数据处理的两个主要高级用例类别,让我们开始深入了解我们如何实际实现这些用例。

数据管道

数据管道是我们自动化的概念,例如大规模 ETL/ELT 或流数据转换。对于处理大量数据或需要复杂数据处理工作负载的组织来说,数据管道是必不可少的,因为它们有助于在规模上简化数据管理。如果没有这样的自动化管道,员工将花费大量时间进行枯燥且重复但复杂且易出错的数据处理活动。Google Cloud 提供了多种服务,可用于批处理和流数据管道,你将在本章中学习如何使用这些服务。

现在我们已经介绍了一些基本概念,是时候开始深入了解一些实际的数据处理活动了。

然而,在我们开始构建自动化的数据处理管道之前,我们首先需要探索我们的数据,以便我们了解我们希望在管道中实施哪些类型的转换。

注意

在之前的章节中,我们将代码直接包含在本书的页面中,但现在我们正在转向更复杂的使用案例,这些使用案例需要大量不适合直接包含在本书页面中的代码。请查阅 GitHub 仓库中与本章节相关的代码工件,以了解我们用于实现这些步骤的代码:github.com/PacktPublishing/Google-Machine-Learning-for-Solutions-Architects

在本书的其余部分,我将继续在适当的地方直接包含代码。

探索、可视化和准备数据

用例:我们计划去纽约市旅行,并想了解最佳的住宿选项。我们不会逐个浏览和评估大量的 Airbnb 帖子,而是会下载大量的评论,并进行批量数据分析和数据处理,以获得一些见解。

我们可以使用在第五章中创建的 Vertex AI Workbench 笔记本来完成这个目的。请打开该笔记本实例上的 JupyterLab。在屏幕左侧的目录浏览器中,导航到Chapter-6目录并打开Chapter-6-Airbnb.ipynb笔记本。您可以选择Python (Local)作为内核。正如您在第五章中所做的那样,通过选择单元格并在键盘上按Shift + Enter来运行笔记本中的每个单元格。

在笔记本中,我们使用 Markdown 单元格详细描述每个步骤,以便您理解过程中的每个步骤。我们使用pandasmatplotlibseaborn等库来总结和可视化数据集的内容,然后我们执行数据清理和准备活动,例如填充缺失值、移除异常值以及移除对训练预测住宿价格的回归模型可能不实用的特征。图 6**.3展示了我们数据可视化图表的一个示例,其中我们查看数据集中列表价格的范围和分布:

图 6.3:数据集中价格分布

图 6.3:数据集中价格分布

如我们所见,大多数住宿选项每晚的费用低于 200 美元,但也有一些数据点(尽管不多)每晚在 600 至 1000 美元之间。这些可能是非常昂贵的住宿选项,或者它们可能是数据中的潜在异常值/错误。您可以在笔记本中查看更多的数据可视化图表。

关于数据清理活动,例如,为了清理潜在的价格异常值,我们使用以下代码片段来设置 800 美元的限制(尽管仍然很高)并移除任何超过该每晚价格的列表:

price_range = (data_cleaned['price'] >= 10) & (
    data_cleaned['price'] <= 800)
data_cleaned = data_cleaned.loc[price_range]

为了移除对训练预测住宿价格的回归模型可能不实用的特征,我们使用以下代码片段:

columns_to_drop = ['id', 'name', 'host_name', 'last_review', 
    'reviews_per_month']
data_cleaned = data.drop(columns=columns_to_drop)

这些只是我们在笔记本中执行的数据准备步骤的几个示例。

当您完成笔记本中所有活动的执行后,我们将继续探讨如何将这些活动转化为生产环境中的自动化流程。我们将首先实现批量数据处理流程。

批量数据处理流程

现在我们已经使用我们的 Jupyter 笔记本来探索我们的数据,并确定我们想在数据集上执行哪些类型的转换,让我们设想一下,我们想要将这个转换成一个可以自动在非常大的文件上运行的生产工作负载,而不需要任何进一步的人工努力。正如我之前提到的,这对于任何实施大规模数据分析和 AI/ML 工作负载的公司来说都是至关重要的。让某个人每次都手动执行这些转换是不切实际的,而对于非常大的数据量,这些转换无法在笔记本实例上执行。例如,想象一下,我们每天都会收到数千条新的帖子,我们想要自动为 ML 模型准备这些数据。我们可以通过创建一个自动化的管道来每晚(或我们希望的时间间隔)执行数据转换来实现这一点。

批量数据处理管道的概念和工具

在我们开始深入构建我们的批量数据处理管道之前,让我们首先介绍这个领域的一些重要概念和工具。

Apache Spark

Apache Spark 是一个非常流行的开发和执行框架,可以用于实现非常大的数据处理工作负载以及其他类型的大规模计算用例,如 ML。它的力量既在于其内存处理能力,也在于其能够并行实现多个大型计算和数据处理任务的能力。

虽然 Spark 可以用于批处理和流式(或微批处理)数据处理工作负载,但我们在本章中将使用它来执行我们的批量数据转换。

Google Cloud Dataproc

正如我们在 第三章 中讨论的那样,Google Cloud Dataproc 是一个完全托管、快速且易于使用的服务,可以在 GCP 上运行 Apache Spark 和 Apache Hadoop 集群。在本章中,我们将使用它来执行我们的 Spark 处理作业。

Apache Airflow

Apache Airflow 是一个开源平台,用于编排复杂的数据工作流。它由 Airbnb 创建,后来贡献给了 Apache 软件基金会ASF)。Airflow 设计用于帮助开发人员和数据工程师创建、安排、监控和管理工作流,使得处理相互依赖的任务变得更加容易。它通常用于数据工程和数据科学项目中的任务,如 ETL、ML 管道和数据分析,并且被各个行业的组织广泛使用,使其成为管理复杂数据工作流的热门选择。

有向无环图

Airflow 将工作流表示为 有向无环图DAGs),它由任务及其依赖关系组成。工作流中的每个任务都表示为一个节点,任务之间的依赖关系由有向边表示。这种结构确保了任务按照特定的顺序执行,不会创建循环,如图 6**.4 所示:

图 6.4:一个简单的 DAG(来源:https://www.flickr.com/photos/dullhunk/4647369097)

图 6.4:一个简单的 DAG(来源:https://www.flickr.com/photos/dullhunk/4647369097)

图 6.4中,我们可以看到任务bcde都依赖于任务a。同样,任务d也依赖于任务bc,任务e也依赖于任务cd

在 Airflow 中,DAG 通过 Python 脚本定义,它将任务及其依赖关系表示为代码。

Google Cloud Composer

Google Cloud ComposerGCC)是基于 Apache Airflow 构建的完全托管的工作流程编排服务。它允许您在多个 Google Cloud 服务、本地或多云环境中创建、安排和监控数据工作流。

云作曲家通过提供易于使用的界面并自动化基础设施管理来简化设置和管理 Apache Airflow 的过程。这允许您专注于创建和维护您的流程,而 Google 则负责底层基础设施、扩展和更新。

现在我们已经涵盖了实现批量数据管道的重要概念,让我们开始构建我们的管道。

构建我们的批量数据管道

在本节中,我们将创建我们的 Spark 作业并在 Google Cloud Dataproc 上运行它,并将使用 GCC 来编排我们的作业。这意味着我们可以让 GCC 每天自动运行我们的作业。每次运行作业时,它将创建一个 Dataproc 集群,执行我们的 Spark 作业,然后在我们的作业完成后删除 Dataproc 集群。这是公司用来节省资金的标准最佳实践,因为当你不使用计算资源时,你不应该有它们在运行。我们 Google Cloud 上的管道架构在图 6.5中显示:

图 6.5:批量数据管道架构

图 6.5:批量数据管道架构

让我们从设置云作曲家开始。

云作曲家

在本节中,我们将设置云作曲家以安排和运行我们的批量数据处理管道。

云作曲家环境

在云作曲家中,我们做的所有事情都在云作曲家环境中进行。要设置我们的云作曲家环境,请执行以下步骤:

  1. 在 Google Cloud 控制台中,导航到Google Cloud 服务菜单→作曲家环境

  2. 选择创建环境

  3. 如果需要,选择作曲家 2

  4. 在出现的屏幕上,输入您的 Composer 环境名称。参见图 6.6以获取参考:

图 6.6:创建 Composer 环境

图 6.6:创建 Composer 环境

  1. 选择您首选的区域。(记住,如果可能的话,在整个本书中为每个活动使用相同的区域会更好。)

  2. 选择最新的镜像版本。参见图 6.6以获取参考。

  3. 重要提示:选择您在本章中创建的服务帐户(如果您使用了建议的名称,那么名称中将包含 data-processing-sa)。

  4. 环境资源部分,选择一个小型环境。

  5. 将所有其他选项保留在默认值并选择创建

  6. 环境启动可能需要 25 分钟。

在等待环境启动的同时,让我们继续下一节。

Cloud Composer Python 代码

在本节中,我们将审查和准备用于我们的 Cloud Composer Spark 工作负载的 Python 代码。我们将使用两个代码资源与 Cloud Composer 一起,这些资源可以在我们的 GitHub 仓库中找到(github.com/PacktPublishing/Google-Machine-Learning-for-Solutions-Architects/tree/main/Chapter-06):

  • composer-dag.py,其中包含定义我们的 Cloud Composer Airflow DAG 的 Python 代码

  • chapter-6-pyspark.py,其中包含定义我们的 Spark 作业的 PySpark 代码

执行以下步骤以开始准备这些文件用于与 Cloud Composer 一起使用:

  1. 在您在本地机器上创建的我们的 GitHub 仓库的克隆中找到这些文件,并打开它们进行编辑。

  2. chapter-6-pyspark.py 文件中,您只需更新源和目标数据集的存储位置。为此,在文件中搜索 GCS-BUCKET-NAME 字符串,并将其替换为您之前创建的自己的 GCS 存储桶名称。

重要

GCS-BUCKET-NAME 字符串在文件中有两个位置(一次在开头附近,一次在结尾附近)。一个位置指定源数据集,另一个位置指定 Spark 作业将保存处理后的数据的目标位置。将字符串的所有出现替换为您自己的 GCS 存储桶名称。

  1. composer-dag.py 文件中,您将在文件开头附近看到以下变量块:

    PROJECT_ID = "YOUR PROJECT ID"
    REGION = "us-central1"
    ZONE = "us-central1-a"
    SERVICE_ACCOUNT_EMAIL = "data-processing-sa@YOUR-PROJECT-ID.iam.gserviceaccount.com"
    PYSPARK_URI = "gs://GCS-BUCKET-NAME/code/chapter-6-pyspark.py"
    

    所有这些变量都需要使用您 GCP 项目中的特定值进行更新。文件中的注释提供了关于替换的额外细节。

  2. 除了做出上述更改外,请审查代码内容,以了解 Cloud Composer 将如何执行我们的作业。代码中包含注释,描述了每个部分正在做什么,以便您了解其工作原理。

  3. 当您完成前面的步骤后,我们就可以上传 Cloud Composer 将要使用的资源了。

  4. Cloud Composer 需要将前面的代码资源存储在 GCS 中,但需要在两个不同的位置:

    • 对于chapter-6-pyspark.py:将此文件上传到您之前在 GCS 中创建的code文件夹中。为此,导航到您创建的code文件夹,选择chapter-6-pyspark.pycomposer-dag.py:此文件将被上传到 Cloud Composer 为您创建的特定文件夹。当您的 Cloud Composer 环境完全创建后,在 Cloud Composer 控制台中点击您新创建的环境名称,您的环境详细信息屏幕将打开。在屏幕顶部附近,从您在本地机器上创建的 GitHub 仓库克隆中(即您在之前步骤中编辑的文件)选择composer-dag.py文件。

就这样!一旦composer-dag.py文件上传完毕,Cloud Composer 将为您完全自动化一切。这可能需要几分钟,但 Cloud Composer 将创建您的 DAG,您将在 Cloud Composer 控制台中看到它出现。然后它将执行 DAG,这意味着它将创建一个 Dataproc 集群,执行 Spark 作业以执行我们指定的数据转换,并在作业完成后删除 Dataproc 集群。

您可以在 Composer 和 Dataproc 控制台中看到正在进行的各种任务(每种情况都给一些时间),最终的测试将是验证处理后的数据是否出现在 PySpark 代码中指定的 GCS 目标中。

当您完成所有上述步骤并且不再需要您的 Composer 环境时,您可以删除该环境。

删除 Cloud Composer 环境

执行以下步骤以删除 Composer 环境:

  1. 在 Google Cloud 控制台中,导航到Google Cloud 服务菜单→Composer环境

  2. 选择您环境名称旁边的复选框。

  3. 在屏幕顶部选择删除。参见图 6.7以获取参考:

图 6.7:删除 Composer 环境

图 6.7:删除 Composer 环境

  1. 在出现的确认屏幕中选择删除

环境删除可能需要几分钟,之后它将从您的环境列表中消失。

太棒了!您已经在 Google Cloud 上正式创建了您的第一个数据处理管道!

注意,本章中我们使用的方法是使用多个 Google Cloud 服务实现数据管道(一个非常流行的)模式的一个示例。Google Cloud 还提供其他产品,可用于实现类似的结果,例如 Google Cloud Data Fusion,它允许您使用可视化用户界面创建管道。我们将在本书的后续章节中探索其他服务,而 Google Cloud 在 2023 年推出的另一个重要服务是无服务器 Spark,我们将在下一节中简要讨论。

Google Cloud 无服务器 Spark

Google Cloud 无服务器 Spark 是一个完全托管的无服务器 Apache Spark 服务,它使得在不配置或管理任何基础设施的情况下运行 Spark 作业变得简单。它还会根据需求自动扩展您的作业,因此您只需为使用的资源付费,这使得它是一种成本效益高的运行 Spark 作业的方式,即使是对于短期或间歇性工作负载也是如此。

它还与 Google Cloud 的其他服务集成,例如 BigQuery、Dataflow、Dataproc 和 Vertex AI,以及流行的开源工具如 Zeppelin 和 Jupyter Notebook,这使得使用这些服务直接探索和分析数据以及构建和运行 端到端E2E)数据管道变得容易。

例如,在 Dataproc 上的无服务器 Spark 中,您可以从预制的模板中选择,轻松执行常见任务,如将数据在 Java 数据库连接JDBC)或 Apache Hive 数据存储与 GCS 或 BigQuery 之间移动和转换,或者您可以为无服务器 Spark 构建自己的 Docker 容器,以便实现自定义数据处理工作负载。有关如何开发此类自定义容器的更多信息,请参阅以下 Google Cloud 文档:cloud.google.com/dataproc-serverless/docs/guides/custom-containers

现在我们已经学会了如何构建批量数据处理管道,我们将继续实施流式数据处理管道。

流式数据处理管道

在本节中,我们将处理不同类型的数据源,并了解实时数据处理与我们在前几节中使用的面向批量的方法的差异。

流式数据处理管道的概念和工具

同样,在我们开始构建流式数据处理管道之前,有一些重要的概念和工具我们需要介绍和理解。

Apache Beam

Apache Beam 是一个开源的、统一的编程模型,用于批处理和流处理模式下的大规模数据处理。它最初由 Google 开发,作为其内部数据处理工具的一部分,后来捐赠给了 ASF。Beam 提供了一种统一的方式来编写可以在各种分布式处理后端上执行的数据处理管道,例如 Apache Flink、Apache Samza、Apache Spark、Google Cloud Dataflow 等。它支持多种编程语言,包括 Java、Python 和 Go,并允许开发者使用单个 API 编写批处理和流数据处理管道,从而简化了开发过程并实现了批处理和流处理模式之间的无缝切换。它还提供了一套丰富的内置 I/O 连接器,用于各种数据源和接收器,包括 Kafka、Hadoop、Google Cloud Pub/Sub、BigQuery 等。此外,如果需要,开发者可以构建自己的自定义连接器。在本章中,我们将使用 Apache Beam 在 Google Cloud Dataflow 上创建一个管道,以实时处理数据。

Apache Beam 概念

在本节中,我们讨论了 Apache Beam 编程模型的一些基本概念,包括以下内容:

  • Pipelines:就像我们在本章前面使用的 Apache Airflow 中的管道概念一样,Apache Beam 管道是一个 DAG,它表示 Apache Beam 工作负载中的数据处理步骤序列或整体数据处理工作流程。

  • PCollections并行集合PCollection)是一个不可变的分布式数据集,表示数据元素集合。它是 Apache Beam 管道中用于存储和操作数据的主要数据结构。

  • PTransforms并行转换PTransform)是一个用户定义的操作,它接受一个或多个 PCollections 作为输入,处理数据,并产生一个或多个 PCollections 作为输出。PTransforms 是管道的构建块,并定义了数据处理逻辑。

  • Windowing:窗口化是一种机制,允许根据时间戳或其他标准对 PCollection 中的数据元素进行分组。这个概念对于处理流应用程序中的无界数据集特别有用,在这些应用程序中,数据元素需要以有限窗口进行处理。

  • Watermarks:水印是估计流处理管道中时间进度的一种方式,并有助于确定何时可以安全地发出特定窗口的结果。

  • 触发器:触发器根据某些因素(如到达一定数量的数据元素、经过一定的时间或水印的推进)确定何时聚合每个窗口的结果。

  • Runners:运行器是负责在特定执行引擎或分布式处理平台上执行 Beam 管道的组件。

Beam 模型将管道定义与底层执行引擎解耦,使用户能够为他们的用例选择最合适的平台。

Google Cloud Dataflow

我们在 第三章 中介绍了 Dataflow,现在我们将更深入地探讨它。Dataflow 是一个 Google Cloud 服务,你可以在其上运行 Apache Beam。换句话说,它提供了 Apache Beam 工作负载可以运行的执行环境或运行器之一。

Dataflow 为各种类型的用例提供了多个功能,在本节中,我们将简要讨论各种选项及其应用。

Dataflow 数据管道和 Dataflow 作业

人们经常对 Dataflow 数据管道和 Dataflow 作业之间的区别感到困惑。最好的看待方式是,Dataflow 数据管道指的是数据管道的定义,这可以定期执行,而 Dataflow 作业则指单个数据管道的执行。这种混淆的原因是,你可以在 Dataflow 作业控制台或 Dataflow 数据管道控制台中创建新的管道定义。

在任何情况下,当创建管道定义时,我们都有使用预定义模板的选项,这些模板涵盖了人们经常希望使用 Dataflow 完成的常见任务类型,例如将数据从 BigQuery 转移到 Bigtable,或从 Cloud Spanner 转移到 Pub/Sub,而且有大量的不同模板可供选择,覆盖了广泛的数据源和目的地。这些模板使我们能够非常容易地实现数据传输工作负载,而无需我们进行很多或任何开发工作。或者,如果我们有更复杂的数据处理需求,而这些需求不包括在任何标准模板中,那么我们可以创建自己的自定义管道定义。我们将在本章后面探讨这两种选项。

Dataflow Workbench 笔记本

我们可以通过使用 Dataflow Workbench 笔本来开发自定义数据处理管道。这可能听起来有些熟悉,因为你可能还记得在 第五章 中创建和使用 Vertex AI Workbench 笔记本。在 Dataflow Workbench 控制台中,我们可以创建已经预装 Apache Beam 的笔记本。我们将在本章后面创建一个笔记本。

Dataflow 快照

Dataflow 快照保存了流管道的状态,这使得你可以在不丢失状态的情况下启动 Dataflow 作业的新版本。这对于备份和恢复、测试以及回滚流管道的更新非常有用。

SQL 工作区

Dataflow 控制台还包括一个内置的 SQL 工作区,它允许你直接从控制台运行 SQL 查询,并将结果发送到 BigQuery 或 Pub/Sub。这对于你只想简单地运行一个 SQL 查询以从给定源获取信息并将结果存储在支持的某个目的地的情况非常有用。

现在我们已经涵盖了实现流数据管道的重要概念,让我们开始构建我们的管道。

构建我们的流数据管道

坚持我们计划去纽约市的主题,本章前几节的活动让我们对可用的住宿选项有了很好的了解,现在我们想要评估我们的交通选项;具体来说,我们想知道在纽约市乘坐出租车旅行的费用可能多少。

我们的流数据管道将从 Google Cloud Pub/Sub 获取输入数据,在 Dataflow 中进行一些处理,并将输出放入 BigQuery 以进行分析。我们的管道在 Google Cloud 上的架构如 图 6.8 所示:

图 6.8:流数据管道

图 6.8:流数据管道

Google Cloud 提供了一个公共数据流,可以用于测试这些类型的流处理工作负载,其中包含与纽约市出租车行程相关的信息,我们将在本节的示例中使用它。让我们首先为我们的流数据创建一个目的地,也称为我们的管道的

创建 BigQuery 数据集

我们将使用 Google Cloud BigQuery 作为我们的数据存储系统。要开始,我们首先需要在 BigQuery 中定义一个数据集,我们将将其用作我们的管道目的地。为此,执行以下步骤:

  1. 在 Google Cloud 控制台中,导航到 Google Cloud 服务 菜单→ BigQuery

  2. 在屏幕的左上角,你会看到你的项目名称。点击项目名称右侧的三个垂直点符号(参见 图 6.9 以获取参考):

图 6.9:BigQuery 项目菜单

图 6.9:BigQuery 项目菜单

  1. 在显示的菜单中,选择 创建数据集

  2. 给你的数据集起个名字:taxirides

  3. 选择你首选的区域,并选择 创建数据集

现在我们已经创建了数据集,我们需要在该数据集中创建一个表。

创建 BigQuery 表

一个 BigQuery 数据集通常包含一个或多个包含实际数据的表。让我们创建一个我们将数据流到其中的表。为此,执行以下步骤:

  1. 在 BigQuery 编辑器中,点击你刚刚创建的 taxirides 数据集,并选择 创建表

  2. 将表名设置为 realtime

  3. 模式 部分中,点击加号(+)添加一个新字段。我们的第一个字段具有以下属性(将每个字段的其余选项保留为其默认值):

字段名称 类型 模式
ride_id STRING NULLABLE

表 6.1:BigQuery 表中第一个字段的属性

  1. 重复步骤 3以添加更多字段,直到架构看起来像图 6.10中所示:

图 6.10:表架构

图 6.10:表架构

  1. 选择创建表

现在我们的表已经准备好接收数据流,让我们继续创建我们的数据流管道。

从模板创建 Dataflow 作业

我们将使用 Dataflow 模板来创建我们的第一个数据流管道。为此,请执行以下步骤:

  1. 在 Google Cloud 控制台中,导航到Google Cloud 服务菜单→Dataflow作业

  2. 选择从模板创建作业

  3. 对于taxi-data-raw

  4. 选择您首选的区域。

  5. Dataflow 模板下拉菜单中,选择Pub/Sub 到****BigQuery模板。

注意

Pub/Sub 还发布了与 BigQuery 的直接集成,但考虑到我们想要说明如何使用 Dataflow 模板,我们本章使用 Dataflow 连接方法。

  1. 接下来,在输入 Pub/Sub 主题字段中,选择手动输入主题

  2. 输入以下主题:

    projects/pubsub-public-data/topics/taxirides-realtime
    
  3. 在上一节中创建的realtime表中。

  4. 在屏幕底部单击选择

  5. 临时位置字段中,输入以下格式的所需存储位置路径(将[BUCKET-NAME]替换为您的桶名称):gs://[BUCKET-NAME]/dataflow。

  6. 展开可选参数部分,并向下滚动,直到找到服务帐户****电子邮件字段。

  7. 在该字段中,选择您在本章中较早创建的服务帐户(如果您使用了建议的名称,名称中将包含data-processing-sa)。

  8. 将所有其他选项保留在默认值。

  9. 选择运行作业

  10. 几分钟后,您将看到作业详情出现,一个类似于图 6.11所示的图形:

图 6.11:Dataflow 执行图

图 6.11:Dataflow 执行图

  1. 尝试在图中每个步骤和子步骤上点击,以更好地了解每个步骤的作用。

经过一段时间后,您可以前往 BigQuery 控制台并验证数据是否正在流入表中。继续下一节以执行此操作。但是,请不要关闭 Dataflow 控制台,因为您将在验证 BigQuery 中的数据后返回这里。

验证 BigQuery 中的数据

为了验证 BigQuery 中的数据,请执行以下步骤:

  1. 在 Google Cloud 控制台中,导航到Google Cloud 服务菜单→BigQuery

  2. 在屏幕的左上角,您将看到您的项目名称。单击项目名称左侧的箭头符号以展开它(参见图 6.12以供参考)。

  3. 然后,单击数据集名称(taxirides)左侧的箭头符号以展开它。

  4. 选择您的realtime表。

  5. 选择预览选项卡。

  6. 然后,你应该会看到一个类似于图 6.12所示的屏幕:

图 6.12:BigQuery 数据

图 6.12:BigQuery 数据

  1. 当您在 BigQuery 中验证了数据后,您可以返回 Dataflow 控制台,通过点击屏幕顶部的停止来停止 Dataflow 作业。

现在您已经看到了从模板设置 Dataflow 作业是多么容易,让我们继续探讨更复杂的 Dataflow 使用案例。

创建数据流笔记本

因为我们想使用定制的 Apache Beam 笔记本,所以我们将创建一个在 Dataflow Workbench 控制台中的笔记本。按照以下步骤创建笔记本:

  1. 在 Google Cloud 控制台中,导航到Google Cloud 服务菜单→DataflowWorkbench

  2. 在屏幕顶部,选择实例标签。

  3. 现在,在屏幕顶部,选择创建新

  4. 在出现的屏幕中(参见图 6.13以获取参考),您可以选择接受默认的笔记本名称或创建您偏好的名称:

图 6.13:创建用户管理的笔记本

图 6.13:创建用户管理的笔记本

  1. 选择您首选的区域和区域。在这种情况下,区域选择并不重要,但我建议选择您在此书之前活动中一直使用的相同区域。

  2. 选择继续,然后再次继续

  3. 选择 E2 作为计算实例类型。

  4. 您还可以配置一个空闲超时周期,在此周期后,如果机器空闲这么长时间,它将自动关闭。这有助于节省成本。

  5. 选择继续多次,直到达到IAM安全屏幕

  6. IAM 和安全屏幕中,选择单用户选项。参见图 6.14以获取参考:

图 6.14:数据流笔记本 – IAM 和安全

图 6.14:数据流笔记本 – IAM 和安全

注意

您可能记得在第五章中创建我们的托管笔记本时执行了类似的步骤(即选择单用户身份验证选项)。这允许我们直接使用笔记本,而无需事先将其作为服务账户进行身份验证。

  1. 出现的用户电子邮件框应自动填充您的登录电子邮件地址。如果不是,请输入您用于登录 Google Cloud 控制台的电子邮件地址。

  2. 此外,我们希望我们的笔记本实例使用我们在本章早期创建的服务账户,所以取消选中表示在 VM 上使用默认 Compute Engine 服务账户调用 Google Cloud API的选项。

  3. data中,你应该会在可用的服务账户列表中看到您在本章早期创建的服务账户的名称(假设您将其命名为data-processing-sa,如该部分中建议的)。

  4. 在列表中选择该服务账户。

  5. 此外,请注意屏幕右上角的定价摘要选项。这是如果您整个月都保持笔记本运行,它将花费的估计金额。幸运的是,您在本章中只会使用很短的时间。如果您在创建笔记本时没有配置空闲关闭时间段,请记住在您完成使用后关闭它。

  6. 您可以将所有其他选项保留在默认值,并在屏幕底部选择创建

  7. 创建笔记本实例需要几分钟。当实例创建完成后,您将在用户管理的笔记本列表中看到它,并且将出现一个打开 JupyterLab 的选项。

  8. 选择打开 Jupyterlab

  9. 当 JupyterLab 屏幕打开时,是时候将我们的仓库克隆到您的笔记本中了。这个过程与您在第五章中执行的过程类似,但您在本章中创建了一个单独的笔记本实例,因此我们需要将仓库克隆到这个实例中。克隆仓库的步骤如下。

  10. 点击屏幕左侧菜单中的Git符号。该符号看起来就像图 6**.15中所示的那样:

图 6.15:Git 符号

图 6.15:Git 符号

  1. 选择克隆仓库

  2. 输入我们的仓库 URL:github.com/PacktPublishing/Google-Machine-Learning-for-Solutions-Architects.

  3. 如果显示任何选项,请保留它们的默认值。

  4. 选择克隆

  5. 您应该会在您的笔记本中看到一个名为 Google-Machine-Learning-for-Solutions-Architects 的新文件夹。

  6. 双击该文件夹,然后双击其中的 Chapter-06 文件夹,最后双击 Streaming_NYC_Taxi_Data.ipynb 文件以打开它。

  7. 在出现的选择内核屏幕中,选择 Apache Beam 的最新版本。在撰写本文时,启动器中可用的最新选项是 Apache Beam 2.4.6(参见图 6**.16以获取参考):

图 6.16:选择笔记本内核

图 6.16:选择笔记本内核

  1. 我们打开的笔记本包含大量的 Apache Beam Python 代码,我们可以使用这些代码来处理从公共 Pub/Sub 主题流进的数据。

  2. 运行笔记本中的每个单元格,并阅读 markdown 和注释中的说明,以了解我们在做什么。我们正在使用 Apache Beam 定义一个将在 Google Cloud Dataflow 中运行的数据流处理管道。

当你完成笔记本中单元格的运行后,你可以转到 Dataflow 作业控制台,你将看到你的新管道在那里运行。给管道启动和数据处理一些时间,就像之前一样,我建议你点击管道执行图的各种部分,以便更好地理解管道的结构。接下来,让我们在 BigQuery 中验证这个新管道的数据,但同样,不要关闭 Dataflow 控制台,因为你在验证 BigQuery 中的数据后将会回到这里。

验证 BigQuery 中的数据

要验证 BigQuery 中的数据,请打开 BigQuery 控制台,在taxirides数据集下,你会看到一个由我们的自定义 Dataflow 管道创建的新表,称为run_rates。点击由我们的管道计算出的run_rates值。

当你在 BigQuery 中验证了数据后,你可以回到 Dataflow 控制台,通过点击屏幕顶部的停止来停止 Dataflow 作业。

现在我们已经完成了本节的活动,你可以通过以下步骤关闭你的用户管理的笔记本:

  1. 在 Google Cloud 控制台中,导航到Google Cloud 服务菜单 → Dataflow工作台

  2. 在屏幕顶部,选择用户管理笔记本标签。

  3. 选择你的笔记本名称旁边的复选框,并在屏幕顶部(在用户管理笔记本标签上方)点击停止

笔记本将在几分钟后关闭。

如果一切按预期进行,你现在已经成功创建了一个自定义管道,该管道可以处理和转换飞行中的流数据!

摘要

在本章中,你学习了如何从各种来源将数据导入 Google Cloud,并且你发现了在 Google Cloud 中处理数据的重要概念。

你随后学习了如何使用 Vertex AI 和 BigQuery 探索和可视化数据。接下来,你学习了如何使用 Jupyter 笔记本清理和准备数据以供 ML 工作负载使用,然后是如何在 Google Cloud Dataproc 上使用 Apache Spark 以批量方法创建自动数据管道,以在生产规模上执行相同的转换,以及如何使用 Apache Airflow 在 GCC 中自动编排整个流程。

我们随后介绍了与处理流数据相关的重要概念和工具,而你最终使用 Apache Beam 在 Google Cloud Dataflow 上构建了自己的流数据处理管道。

在下一章中,我们将花更多的时间在数据处理和准备上,特别关注特征工程的概念。

第七章:特征工程和降维

在本章中,我们将逐步深入探讨许多数据科学项目中常见的数据处理步骤,以及如何使用 Google Cloud 中的 Vertex AI 来执行这些步骤。我们将从更详细地查看特征在机器学习工作负载中的使用方式以及与特征使用相关的常见挑战开始本章。

然后,我们将讨论如何解决这些挑战,以及如何在 Google Cloud 中有效地使用我们的机器学习特征。

本章涵盖了以下主题:

  • 与机器学习中的维度或特征相关的基本概念

  • 维度灾难的介绍

  • 降维

  • 特征工程

  • Vertex AI 特征存储

本章的基本概念

在本节中,我们将简要介绍为本章的学习活动提供额外背景的概念。

维度和特征

我们在第一章中介绍了特征的概念,并使用金县房屋销售数据集作为示例描述了特征。为了简要回顾,特征是我们数据集中观察到的单个、可度量的属性或特征。它们是我们数据集的方面,机器学习算法从中学习以创建模型。换句话说,模型可以被视为算法从我们数据集中的特征中学习到的模式的表示。

例如,房屋的特征包括诸如房间数量、建造年份、位置以及其他描述房屋的因素等信息,如表 7.1所示:

表 7.1:金县房屋销售特征

表 7.1:金县房屋销售特征

当我们处理表格数据时,特征通常以数据集中的列的形式表示,每一行代表一个单独的数据点或观察结果,有时也被称为实例

特征也被称为变量、属性或维度。因此,当我们谈论数据集的维度时,它与我们数据集中有多少个特征或维度有关,以及这如何影响我们的机器学习工作负载有关。

过拟合、欠拟合和正则化

我们在第二章中简要讨论了过拟合和欠拟合的概念,由于这些概念对于机器学习过程至关重要,因此在本书中我们将继续更详细地回顾这些主题。在本节中,我们将讨论数据集中特征的数量如何影响我们的算法从数据中学习的方式。一个需要记住的关键概念是,过拟合和欠拟合可以受到我们数据集中观察到的数量以及每个观察到的特征数量的强烈影响。

我们通常需要在数据集的这两个方面之间找到合适的平衡。例如,如果我们对每个观察到的数据点有非常少的观测值和很多特征,那么我们的模型很可能会过度拟合数据集,因为它为这些观测值及其特征学习到了非常具体的模式,但它无法很好地泛化到新的观测值。相反,如果我们有大量的观测值,但每个观测值只有很少的信息(即特征),那么我们的模型可能无法学习到任何有价值的模式,这意味着它将欠拟合我们的数据集。正因为如此,减少特征的数量可以帮助减少过度拟合,但只能到一定程度——去除过多的特征可能会导致欠拟合。此外,我们不想去除那些对模型学习有用的信息,因此,我们可以在保持许多特征的同时,通过使用一种称为正则化的机制来解决过度拟合问题。我们也在第二章中简要提到了这一点,我们将在这里更详细地讨论它。

正则化

要开始我们关于正则化的讨论,我们需要再次提及机器学习中的损失函数的概念,这是我们已经在第一章中介绍过的。记住,许多机器学习算法通过尝试找到每个特征的最好系数(或权重),以实现对目标特征的最近似来工作。因此,过度拟合受到特征与其系数之间的数学关系的影响。如果我们发现模型对特定特征过度拟合,我们可以使用正则化来减少这些特征及其系数对模型的影响。

由于过度拟合通常发生在模型过于复杂的情况下,例如相对于观测值的数量有太多的特征,正则化通过向损失函数中添加惩罚来解决这一问题,这会阻止模型对任何特征赋予过多的重视。这有助于提高模型的泛化能力。

在机器学习中实现正则化的方法有很多,但我会解释两种最常见类型——即L1L2正则化——以及这两种方法的组合,称为弹性网络

L1 正则化

这种类型的正则化也称为Lasso正则化,它通过以下公式通过添加与成本函数中系数或权重的 L1 范数(或绝对值)相等的惩罚来实现:

成本函数 + λ * |权重|

在这里,λ是正则化参数,它控制惩罚的强度,可以被认为是一个超参数,其最佳值可能因问题而异。请注意,如果惩罚太强,可能会导致欠拟合,因此在这方面找到合适的平衡很重要。

L1 正则化的作用是将模型的一些系数缩小到正好为零,从而有效地排除相应的特征,这使得 L1 正则化在处理高维数据时对于特征选择(我们将在稍后更详细地介绍)非常有用。

L2 正则化

这种正则化也称为 正则化。这种方法通过以下公式在成本函数中添加一个相当于 L2 范数(或平方)的惩罚:

成本函数 + λ * (权重²)

与 L1 正则化不同,L2 正则化不会导致特征的排除,而是将系数推向零附近,在特征之间均匀分配权重。当我们处理相关特征时,这可能是有益的,因为它允许模型考虑所有这些特征。

弹性网络

弹性网络作为 L1 和 L2 正则化的组合,旨在在这两种方法之间提供折衷方案,结合两者的优点。与 L1 和 L2 正则化一样,弹性网络向损失函数添加惩罚,但它不是添加 L1 惩罚或 L2 惩罚,而是通过以下公式添加两者的加权总和:

成本函数 + λ1 * |权重| + λ2 * (权重²)

在这里,λ1 和 λ2 是控制 L1 和 L2 惩罚强度的超参数。如果 λ1 为零,弹性网络回归将退化为岭回归,而如果 λ2 为零,则退化为 Lasso 回归。

弹性网络具有 L1 正则化的特征选择能力(因为它可以将系数缩小到零),以及 L2 正则化的正则化强度(因为它可以在相关特征之间均匀分配权重)。与弹性网络相关的权衡是,它有两个超参数需要调整,而不是 Lasso 或岭回归中只有一个,这可能会使模型更复杂,训练起来计算量更大。

现在我们已经更详细地介绍了正则化这个重要话题,让我们深入探讨特征选择和特征工程。

特征选择和特征工程

在本书的前几章中,我们简要地讨论了特征工程,但在这里我们将更详细地探讨这些概念。在第二章中,我们通过将每栋房子的总成本除以该房子的总面积(平方英尺)来创建一个新的特征 price-per-square-foot,作为我们的住房数据示例。在本章中,我们将探讨许多额外的特征工程示例。

然而,从现有特征中创建新特征并不是我们在为训练机器学习模型准备数据集时需要在特征上进行的唯一活动。我们还需要选择我们认为对实现我们希望模型完成的任务(例如预测房价)最重要的特征。正如我们在第六章中看到的,我们可能还需要对特征进行转换,例如确保它们都表示在共同的、标准化的尺度上。

在选择和构建特征时的目标是,以最易于消化的格式为我们模型提供最相关的信息,以便它可以从数据中有效地学习。

维度诅咒

高维数据集包含许多维度或特征,每个数据点都有很多。我们可能会假设,我们为每个数据点包含的特征越多,我们的模型学到的信息就越多,因此,我们的模型就越准确。然而,请注意,并非所有特征都同等有用。一些可能对我们的模型几乎没有或没有有用的信息,其他可能包含冗余信息,甚至可能对模型学习的能力有害。机器学习艺术和科学的一部分就是确定使用哪些特征以及如何准备它们,以便模型能够发挥最佳性能。

此外,请记住,我们数据集中包含的信息越多,我们的模型需要处理的信息就越多。这直接导致我们的机器学习算法处理数据集时需要更多的计算资源,这反过来又直接导致模型训练时间更长,成本增加。数据集中过多的无关数据或噪声也可能使算法更难识别(即学习)数据中的模式。因此,理想的情况是找到提供最大有用信息的最小特征数量。例如,如果我们可以用三个特征或十个特征达到相同的结果,那么通常选择使用三个特征会更好。“最大有用信息”可以通过方差来衡量,其中具有高相对方差的特征对我们的模型结果影响最为显著,而相对方差小的特征在训练模型识别模式时通常不太有用。

“维度诅咒”是数据科学行业用来描述处理包含更多维度的数据集时出现的挑战的术语。让我们看看这些挑战中的一些。在随后的章节中,我们将讨论解决这些挑战的机制。

数据探索挑战

这是我们可以引入数据集中的“维度”与物理空间维度之间联系的重要点。众所周知,正如本书前面提到的,人类只能感知到最多三个维度的物理世界(宽度、高度和深度),而“时间”被视为我们物理现实的第四维度。对于具有两个或三个维度的数据集,我们可以轻松创建表示那些数据集各个方面的可视化,但我们无法创建更高维数据集的图表或其他视觉表示。在这种情况下,如果我们能尝试找到其他方法来视觉解释这些数据集,比如将它们投影到低维表示中,这会很有帮助,我们将在稍后更详细地探讨这一点。

特征稀疏性

在高维空间中,数据集中的点(即实例或样本)往往彼此相距甚远,导致稀疏性。一般来说,随着特征数量相对于数据集中观察值的数量的增加,特征空间变得越来越稀疏,这种稀疏性使得算法从数据中学习变得更加困难,因为它们在任意给定点的附近有更少的例子可以学习。

例如,让我们假设我们的数据集包含有关公司客户的信息,在这种情况下,数据集中的每个实例代表一个人,每个特征代表一个人的某种特征。如果我们的数据集存储了数百甚至数千个特征,那么不太可能每个特征都会被填充。因此,我们数据集的整体特征空间将是稀疏的。另一方面,如果我们有较少的特征,这种情况发生的可能性较小。

距离测量

在前面的章节中,我们讨论了欧几里得距离在许多机器学习算法中的应用,用于寻找数据集中数据点之间潜在的关联或差异。我们已经探讨的这种概念的最直接例子之一是 K-means 聚类算法。在高维空间中,距离有时可能变得不那么有意义,因为最大可能距离和最小可能距离之间的差异变得越来越小。这意味着传统的距离度量,如欧几里得距离,也变得不那么有意义,这可能会特别影响依赖于距离的算法,例如k 近邻kNN)或聚类算法。

过度拟合和增加的数据需求

回顾我们之前关于过拟合或欠拟合如何受数据集中观察值与特征比例影响的讨论,高维数据集更容易过拟合,除非我们有大量的观察值来帮助我们的模型泛化。记住我们在本章前面提到的关于算法处理数据量与训练模型成本之间关系的内容。具有大量观察值和大量特征的数据集将更昂贵且更难训练和管理。

可解释性和可解释性

可解释性和可解释性指的是我们理解和解释我们的机器学习模型如何工作的能力。这有多个原因,我们将在下面简要讨论。首先,对我们模型工作原理的不理解阻碍了我们改进这些模型的能力。然而,更重要的是,我们需要确保我们的模型尽可能公平和无偏见,这就是可解释性发挥关键作用的地方。如果我们不能解释我们的模型为何产生特定的结果,那么我们就无法充分评估其公平性。一般来说,我们的数据集维度越高,我们的模型往往越复杂,这会直接影响(即减少)可解释性和可解释性。

现在我们已经回顾了一些与高维数据集相关联的常见挑战,让我们来看看一些解决这些挑战的机制。

维度降低

如你所想,解决维度过多挑战的第一种方法就是减少维度数量,为此我们可以使用两种主要的技术:特征选择和特征投影。

特征选择

这涉及到从原始特征中选择一个子集。特征选择有几种策略,包括以下几种:

  • 过滤方法,这些方法根据统计指标对特征进行排序,并选择排名最高的特征子集

  • 包装方法,这些方法使用不同的输入特征子集评估多个模型,并选择导致最高模型性能的子集

  • 嵌入方法,这些方法使用具有内置特征选择方法的机器学习算法(例如 Lasso 正则化)

同样重要的是要理解,我们将讨论的特征投影方法可以用来帮助我们选择数据集中最重要的特征子集,因此这些概念之间有一些重叠。

特征投影

在特征投影中,我们使用数学变换将特征投影到低维空间。在本节中,我们将介绍三种流行的特征投影技术:主成分分析PCA)、线性判别分析LDA)和t-分布随机邻域嵌入t-SNE)。

PCA

主成分分析(PCA)是一种无监督算法,旨在在尽可能保持原始数据方差的同时,降低我们的特征空间的维度。在高维数据空间中,PCA 识别出数据变化最大的轴(主成分)。这些主成分是正交的,意味着在这个多维空间中它们彼此之间成直角。第一个主成分PC1)捕捉数据中最大方差的方向。第二个主成分PC2)在正交于 PC1 的同时,捕捉剩余的最大方差,依此类推。PCA 的过程通常包括以下步骤:

  1. 如果特征具有不同的尺度,则对数据进行标准化。这是很重要的,因为 PCA 对特征尺度很敏感,尺度较大的特征可能会被错误地认为是更占主导地位的。

  2. 计算协方差矩阵以了解不同特征是如何一起变化的。协方差矩阵是一个方阵,包含了每对特征之间的协方差。两个特征之间的协方差衡量了这些特征是如何一起变化的:正协方差表示特征一起增加或减少,而负协方差表示一个特征增加而另一个减少。

  3. 计算协方差矩阵的特征值特征向量。特征向量代表新空间的方向或成分,特征值代表每个成分的大小或解释方差。特征向量通常被称为数据的主成分,它们构成了新特征空间的一个基。

  4. 对特征值及其对应的特征向量进行排序。在计算了特征值及其相关的特征向量之后,下一步是对特征值按降序排序。具有最高对应特征值的特征向量是 PC1。具有第二高对应特征值的特征向量是 PC2,依此类推。这种排序的原因是每个特征向量的重要性由其特征值的大小给出。

  5. 选择主成分的子集。PCA 创建与原始数据集中变量数量一样多的主成分。然而,由于 PCA 的目标是降维,我们通常选择主成分的子集,称为前 k 个主成分,这些主成分捕捉了数据中的最大方差。这一步是降低维度的原因,因为较小的特征值及其向量被丢弃。

  6. 转换原始数据。PCA 的最后一步是将原始数据转换成由所选主成分定义的降维子空间,这是通过将原始数据矩阵乘以前k个特征向量的矩阵来实现的。

转换后的数据现在可以用于进一步的分析和可视化(如图图 7.1所示),或者作为机器学习算法的输入。重要的是,这个减少的数据集尽可能地保留了原始数据中的方差(考虑到减少的维度数):

图 7.1:欧洲遗传结构的 PCA 可视化(来源:https://commons.wikimedia.org/wiki/File:PCA_plot_of_European_individuals.png)

图 7.1:欧洲遗传结构的 PCA 可视化(来源:https://commons.wikimedia.org/wiki/File:PCA_plot_of_European_individuals.png)

PCA 是一种强大的技术,用途广泛,但它也有局限性。例如,它假设主成分是原始特征的线性组合。如果这不是这种情况(即,如果数据中的潜在结构是非线性的),那么 PCA 可能不是最佳降维技术。还值得注意的是,主成分比原始特征更难以解释——它们在原始特征方面没有直观的意义。

LDA

LDA 是一种监督算法,旨在找到最佳分离对象类别的特征线性组合。然后可以使用这个组合进行降维。它涉及以下步骤:

  1. 计算类均值。对于数据集中的每个类别,计算均值向量,这仅仅是该类别中所有向量的平均值。

  2. 计算类内协方差矩阵,它衡量各个类别如何围绕各自的均值分散。

  3. 计算类间协方差矩阵,它衡量类别均值在数据总体均值周围如何分散。

  4. 计算线性判别方向,这些方向是特征空间中类别最佳分离的方向。

  5. 对线性判别方向进行排序。就像在 PCA 中一样,特征向量按照它们对应的特征值降序排列。特征值表示每个判别所解释的数据方差量。前几个线性判别方向,对应于最大的特征值,是解释最大方差的方向。

  6. 最后,数据被投影到由前几个线性判别方向张成的空间中。

这导致数据在低维表示中类别最大化分离。我们可以如下可视化:

图 7.2:葡萄酒品种的 LDA 图

图 7.2:葡萄酒品种的 LDA 图

重要的是要注意,LDA 的主要假设是类别具有相同的协方差矩阵。如果这个假设不成立,LDA 可能表现不佳。

t-SNE

这种方法可能拥有所有方法中最酷的名字。它是一个无监督的非线性降维算法,特别适合将高维数据嵌入到二维或三维空间中,同时旨在使相似实例靠近,不同实例分离。它是通过将高维数据映射到低维空间,以保留点之间的大部分相对距离来实现这一点的。它包括以下步骤:

  1. 在高维空间中计算相似性:t-SNE 首先计算高维空间中数据点对相似的概率。彼此靠近的点有更高的被选中概率,而彼此远离的点有更低的被选中概率。

  2. 在低维空间中计算相似性:t-SNE 随后计算低维表示中点对相似性的概率。

  3. 优化:最后,t-SNE 使用梯度下降来最小化高维和低维空间中概率的差异。目标是使相似对象由低维空间中的邻近点表示,不同对象由低维空间中的远点表示。

t-SNE 的结果是一张地图,以人类更容易理解的方式揭示了高维数据的结构。

应该注意的是,虽然 t-SNE 在可视化方面非常出色,可以揭示数据中的簇和结构(如图图 7.3所示),但它并不像 PCA 那样提供关于数据中特征重要性或含义的明确信息。它更多的是一种探索性工具,可以帮助进行降维,而不是一种正式的降维技术:

图 7.3:数字数据集的 t-SNE 可视化

图 7.3:数字数据集的 t-SNE 可视化

现在我们已经介绍了一些最受欢迎的特征投影技术,让我们再讨论一组关于我们数据集中的特征如何影响模型训练的重要概念。

使用 PCA 和 LDA 进行降维

我们将在本章中通过使用 PCA 和 LDA 进行降维来开始我们的动手活动。我们可以使用 scikit-learn 中的葡萄酒数据集作为例子。我总是希望我能通过成为一个葡萄酒专家来给我的朋友们留下深刻印象,但我几乎无法区分 10 美元一瓶的酒和 500 美元一瓶的酒,所以,我将使用数据科学来发展令人印象深刻的知识。

葡萄酒数据集是一个多变量数据集的例子,它包含了在意大利同一地区种植但来自三种不同葡萄品种(称为栽培品种)的葡萄酒的化学分析结果。分析的重点是量化三种葡萄酒类型中发现的 13 种成分。

使用 PCA 处理这个数据集将帮助我们理解重要的特征。通过观察原始特征在主成分中的权重,我们可以看到哪些特征对葡萄酒数据集中的变异性贡献最大。

再次,我们可以使用在第五章中创建的相同的 Vertex AI Workbench 笔记本实例来完成此目的。请在笔记本实例上打开 JupyterLab 并执行以下步骤:

  1. 在屏幕左侧的目录浏览器中,导航到Chapter-07目录并打开dimensionality-reduction.ipynb笔记本。

  2. 选择Python (Local)作为内核。

  3. 通过选择单元格并按键盘上的Shift + Enter来运行笔记本中的每个单元格。

笔记本中的代码执行以下活动:

  1. 首先,它导入必要的库。

  2. 然后,它加载数据集。

  3. 接下来,它标准化了葡萄酒数据集的特征。它应用主成分分析(PCA)将维度降低到二维(即前两个主成分)。这是通过使用fit_transform()方法完成的,该方法将 PCA 模型拟合到数据上,然后转换数据。

  4. 最后,它在两个主成分的空间中可视化数据,根据葡萄酒的类型对点进行着色:

    from sklearn.datasets import load_wine
    from sklearn.preprocessing import StandardScaler
    from sklearn.decomposition import PCA
    import matplotlib.pyplot as plt
    import pandas as pd
    # Load dataset
    data = load_wine()
    df = pd.DataFrame(data.data, columns=data.feature_names)
    # Standardize the features
    scaler = StandardScaler()
    df = scaler.fit_transform(df)
    # Apply PCA
    pca = PCA(n_components=2)
    principalComponents = pca.fit_transform(df)
    principalDf = pd.DataFrame(data = principalComponents, 
        columns = ['principal component 1', 
            'principal component 2'])
    # Visualize 2D Projection
    plt.figure(figsize=(8,6))
    plt.scatter(principalDf['principal component 1'], principalDf['principal component 2'], c=data.target)
    plt.xlabel('Principal Component 1')
    plt.ylabel('Principal Component 2')
    plt.show()
    

    结果可视化应类似于图 7**.4所示:

图 7.4:葡萄酒数据集的 PCA 散点图

图 7.4:葡萄酒数据集的 PCA 散点图

散点图应显示不同类型葡萄酒之间的清晰分离,这表明葡萄酒的类型与其化学成分密切相关。此外,PCA 对象(在我们的代码中命名为pca)存储了components_属性,其中包含每个特征与主成分的映射。通过检查这些,我们可以找出哪些特征在区分葡萄酒类型时最为重要。

可视化中的每个数据点代表我们数据集中的一个单独样本,但不是在原始的高维特征空间中绘制,而是在由主成分定义的较低维空间中绘制。

在葡萄酒数据集的上下文中,PCA 可视化中的每个数据点代表一个单独的葡萄酒样本。因为我们已经将原始的 13 个特征映射到两个 PCA 维度,所以每个点在XY轴上的位置对应于该葡萄酒样本的第一个和第二个主成分的值。

每个点的颜色代表葡萄酒样本的真实类别(来自三种不同的品种)。通过根据它们的真实类别着色点,你可以看到 PCA 转换在降维空间中如何将不同的类别分开。

记住,每个主成分是原始特征的线性组合,因此每个点的位置仍然由其原始特征值决定。这样,PCA 使我们能够可视化高维数据,并突出显示最大方差维度,这些维度通常是最具信息量的。

然后,我们可以访问拟合的 PCA 对象的components_属性来查看各个成分。该属性返回一个矩阵,其中每一行对应一个主成分,每一列对应一个原始特征。

因此,以下代码将打印一个表格,其中表格中的值代表每个成分中每个特征的权重:

components_df = pd.DataFrame(pca.components_, 
    columns=data.feature_names, index=['Component 1', 'Component 2'])
print(components_df)

结果应该类似于表 7.2中所示:

表 7.2:葡萄酒数据集的 PCA 成分和特征

表 7.2:葡萄酒数据集的 PCA 成分和特征

通过查看这些权重的绝对值,我们可以确定哪些特征对每个主成分最重要。大的绝对值对应于在捕捉该主成分变化中起重要作用的特征,权重的符号(正或负)可以告诉我们特征与主成分之间关系的方向。

接下来,让我们看看如何使用 LDA 来识别导致不同类型葡萄酒之间差异最大的成分。同样,我们首先导入必要的库并标准化数据。然后,我们将对标准化特征应用 LDA,指定n_components=2以获得二维投影,然后拟合 LDA 模型到数据并对前两个 LDA 成分进行数据转换。最后,我们将可视化转换后的数据:

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
# Apply LDA
lda = LDA(n_components=2)
lda_components = lda.fit_transform(df, data.target)
lda_df = pd.DataFrame(data = lda_components, 
    columns = ['LDA 1', 'LDA 2'])
# Visualize 2D Projection
plt.figure(figsize=(8,6))
plt.scatter(lda_df['LDA 1'], lda_df['LDA 2'], c=data.target)
plt.xlabel('LDA 1')
plt.ylabel('LDA 2')
plt.show()

结果可视化应该类似于图 7**.5中所示:

图 7.5:葡萄酒数据集的 LDA 散点图

图 7.5:葡萄酒数据集的 LDA 散点图

在这种情况下,散点图显示了第一二个 LDA 成分空间中的数据点,点再次根据葡萄酒类型着色。我们还应该看到不同类型葡萄酒之间的清晰分离,这表明它们具有不同的化学成分分布。

就像我们检查拟合的 PCA 对象的components_属性一样,我们可以查看拟合的 LDA 对象的coef_属性来查看最具判别性的特征,如下面的代码及其相应的输出所示:

# Create and print a DataFrame with the LDA coefficients and feature names
coef_df = pd.DataFrame(lda.coef_, columns=data.feature_names, 
    index=['Class 1 vs Rest', 'Class 2 vs Rest', 'Class 3 vs Rest'])
print(coef_df)

结果应该类似于表 7.3中所示:

表 7.3:葡萄酒数据集的 LDA 类别和特征

表 7.3:葡萄酒数据集的 LDA 类别和特征

在生成的表中,每一行对应一个类别(与其他类别相比),每一列对应一个原始特征。因此,表中的值代表线性判别分析中每个特征的系数。类似于我们的 PCA 评估,绝对值大的特征表示对区分类别有显著贡献的特征。

现在我们已经了解了如何降低数据集的维度,让我们假设我们已经确定了所需的特征,并开始探索我们如何进一步工程特征以确保我们有最佳可能的特征集来训练我们的模型。

特征工程

特征工程可以构成数据科学家活动的大部分内容,它对他们成功的重要性可能与其选择正确的机器学习算法一样重要,有时甚至更重要。在本节中,我们将更深入地探讨特征工程,这可以被视为一种艺术和科学。

我们将使用 OpenML 上可用的 Titanic 数据集(www.openml.org/search?type=data&sort=runs&id=40945)在本节中的示例。此数据集包含关于泰坦尼克号乘客的信息,包括人口统计数据、票务等级、票价以及他们是否在船沉没中幸存。

在您的 Vertex AI Workbench Notebook 实例的 JupyterLab 中的 Chapter-07 目录下,打开 feature-eng-titanic.ipynb 笔记本,并将内核选择为 Python (Local)。再次,通过选择单元格并在键盘上按下 Shift + Enter 来运行笔记本中的每个单元格。

在这个笔记本中,代码执行以下步骤:

  1. 首先,它导入必要的库。

  2. 然后,它加载数据集。

  3. 然后,它执行一些初步探索,以查看我们的数据集看起来如何。

  4. 最后,它工程新的特征。

让我们更详细地查看每个步骤,从导入所需的库、加载数据集和探索数据集开始。我们使用以下代码来完成这些任务:

import pandas as pd
import numpy as np
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder
# Load the data
titanic_raw = pd.read_csv('./data/titanic_train.csv')
titanic_raw.head()

head() 方法的输出结果应类似于 表 7.4 中所示:

表 7.4:Titanic 数据集 head() 输出

表 7.4:Titanic 数据集 head() 输出

数据集中的字段如下:

  • survived:表示乘客是否幸存。这是一个二进制特征,其中 1 表示幸存,0 表示未幸存。

  • pclass(乘客等级):表示乘客票的等级。它有三个类别:1 表示头等舱,2 表示二等舱,3 表示三等舱。这也可以表示乘客的社会经济状况。

  • name:乘客的名字。

  • sex:乘客的性别;男性或女性。

  • age:乘客的年龄。有些年龄是分数,对于年龄小于 1 岁的乘客,年龄估计为分数。

  • sibsp: 乘客在泰坦尼克号上的兄弟姐妹和配偶总数。

  • parch: 乘客在泰坦尼克号上的父母和子女总数。

  • ticket: 乘客的票号。

  • fare: 乘客票价——即票的成本。

  • cabin: 乘客所住的船舱号。一些条目是 NaN,表示数据中缺少船舱号。

  • embarked: 乘客登船的港口。C 代表瑟堡;Q 代表昆士敦;S 代表南安普顿。

  • boat: 乘客被分配到的救生艇(如果乘客幸存)。

  • body: 身体编号(如果乘客未幸存且其尸体被找回)。

  • home.dest: 乘客的家乡和目的地。

假设我们想要使用这个数据集来构建一个模型,该模型可以根据乘客记录的信息预测乘客生存的可能性,让我们看看我们是否可以使用一些领域知识来评估哪些特征可能是对生存或死亡结果影响最大的贡献者,以及我们是否可以使用任何数据操作技术来构建更有用的特征。

Passenger Class 是一个可能的重要特征,我们可以从它开始考虑,因为头等舱和二等舱乘客的船舱位于更高的船层,这些船舱更靠近救生艇。

乘客的名字不太可能影响结果,他们的票号或登船港口也是如此。然而,我们可以构建一个名为 Title 的新特征,该特征从乘客的名字中提取出来,并可能提供有关社会地位、职业、婚姻状况和年龄的有价值信息,这些信息可能不会立即从其他特征中明显看出。我们还可以通过合并类似头衔,如 MissMs,并将高级头衔标识为 Distinguished 来清理这个新特征。执行此操作的代码如下:

# We first define a function to extract titles from passenger names
def get_title(name):
    if '.' in name:
        return name.split(',')[1].split('.')[0].strip()
    else:
        return 'Unknown'
# Create a new "Title" feature
titanic['Title'] = titanic['Name'].apply(get_title)
# Simplify the titles, merge less common titles into the same category
titanic['Title'] = titanic['Title'].replace(['Lady', 'Countess', 
    'Capt', 'Col', 'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 
    'Dona'], 'Distinguished')
titanic['Title'] = titanic['Title'].replace('Mlle', 'Miss')
titanic['Title'] = titanic['Title'].replace('Ms', 'Miss')
titanic['Title'] = titanic['Title'].replace('Mme', 'Mrs')

接下来,让我们考虑 FareCabin 特征。这些特征可能与阶级有些相关,但我们将更详细地探讨这些特征。对于 Cabin 特征,我们可以提取另一个名为 CabinClass 的新特征,它更清楚地表示与每个条目相关的阶级。例如,我们可以通过从船舱号中提取第一个字母,用它来表示船舱阶级(例如,A、B、C 等),并将其存储在新的 CabinClass 特征中。执行此操作的代码如下:

# Create "CabinClass" feature
titanic['CabinClass'] = titanic['Cabin'].apply(lambda x: x[0])

让我们确保尽可能准确地表示票价,考虑到人们可能作为一家人一起旅行购买了票价。为此,我们可以创建一个名为 FamilySize 的新特征,它是 SibSpParch 特征的组合(为当前乘客添加一个额外的“1”),然后通过以下代码通过将 Fare 特征除以 FamilySize 特征来计算 FarePerPerson

titanic['FamilySize'] = titanic['SibSp'] + titanic['Parch'] + 1
# Create "FarePerPerson" feature
titanic['FarePerPerson'] = titanic['Fare'] / titanic['FamilySize']

一个人是独自旅行还是与家人同行也可能影响他们的生存机会。例如,家庭成员在试图到达救生艇时可以互相帮助。因此,让我们从 FamilySize 特征中创建一个特征,以确定乘客是否独自旅行:

# Create new feature "IsAlone" from "FamilySize"
titanic['IsAlone'] = 0
titanic.loc[titanic['FamilySize'] == 1, 'IsAlone'] = 1

接下来,让我们考虑年龄如何影响生存的可能性。非常年轻或年长的人,不幸的是,如果没有他人的帮助,生存的可能性可能较小。然而,在考虑年龄的这种情况下,我们可能不需要按年或按分数年进行粒度划分,也许将人们分组到年龄组可能更有效。在这种情况下,我们可以使用以下代码创建一个名为 AgeGroup 的新特征,该特征将按十年分组,例如 0-9、10-19、20-29 等:

# Create "AgeGroup" feature
bins = [0, 10, 20, 30, 40, 50, 60, 70, np.inf]
labels = ['0-9', '10-19', '20-29', '30-39', '40-49', '50-59', '60-69', 
    '70+']
titanic['AgeGroup'] = pd.cut(titanic['Age'], bins=bins, labels=labels)

我们还希望将分类特征转换为数值,使用独热编码,因为机器学习模型通常需要数值。我们可以这样做(我们需要为所有分类特征都这样做):

# Convert "Title" into numerical values using one-hot encoding
one_hot = OneHotEncoder()
title_encoded = one_hot.fit_transform(titanic[['Title']]).toarray()
title_encoded_df = pd.DataFrame(title_encoded, 
    columns=one_hot.get_feature_names_out(['Title']))
titanic = pd.concat([titanic, title_encoded_df], axis=1)

现在,让我们删除那些我们知道对预测生存可能性(以及我们编码的原始特征)没有价值的特征:

titanic = titanic.drop(['name', 'ticket', 'Title', 'cabin', 'sex', 
    'embarked', 'AgeGroup', 'CabinClass', 'home.dest'], axis=1)

然后,我们可以快速查看我们的更新数据集看起来像什么:

titanic.head()

head() 方法的输出结果应类似于 表 7.5 中所示:

表 7.5:更新数据集的 head() 方法输出

表 7.5:更新数据集的 head() 方法输出

在这一点上,我们有一个增强的数据集,其中包含可用于训练模型的工程化特征。重要的是要记住,我们在源数据集上执行的任何特征工程步骤,在用我们的模型进行预测时也需要考虑。这种在机器学习中的常见需求促使 Google Cloud 开发了一个名为特征存储的服务。我们将在下一节中探讨这一点。

Vertex AI 特征存储

在本章中,我们进行了大量的特征工程工作。请注意,我们执行了数据转换并创建了新的特征,因为我们有理由相信原始数据不足以训练一个适合我们业务案例的机器学习模型。这意味着模型在现实世界中看到的原始数据通常不会包含我们在训练期间对数据进行增强的部分。在完成所有这些工作之后,我们通常会保存我们已工程化的更新特征,以便模型在需要做出预测时可以引用它们。Vertex AI 特征存储就是为了这个目的而创建的。我们在 第三章 中简要提到了 Vertex AI 特征存储,在本节中,我们将更详细地探讨它是什么以及我们如何使用它来存储和提供训练和推理所需的特征。

Vertex AI Feature Store 简介

这里是来自 Google Cloud 文档的官方定义:

Vertex AI Feature Store 是一个托管、云原生的特征存储服务,它是 Vertex AI 的核心组成部分。它通过允许你在 BigQuery 表或视图中管理你的特征数据,简化了你的机器学习特征管理和在线服务流程。然后,你可以直接从 BigQuery 数据源在线提供特征。Vertex AI Feature Store 提供资源,允许你通过指定你的特征数据源来设置在线服务。然后,它作为元数据层与 BigQuery 数据源接口,以低延迟直接从 BigQuery 为在线预测提供最新的特征值。

除了存储和提供我们的特征外,Vertex AI Feature Store 还与 Google Cloud Dataplex 集成,提供特征治理能力,包括跟踪特征元数据(如特征标签和版本)的能力。在第十三章中,我们将深入探讨数据治理的重要性,并讨论如何将 Dataplex 用作构建强大治理框架的重要组件。

到目前为止,重要的是要强调,Vertex AI Feature Store 在 2023 年推出了一个全新的版本。因此,现在在 Google Cloud 中我们可以选择两种不同的特征存储服务版本,先前版本被称为 Vertex AI Feature Store(Legacy),而新版本则简单地称为 Vertex AI Feature Store。我们将在本章中讨论这两种版本,以及它们之间的一些主要区别。为了为后续章节的内容提供背景,我将简要描述在线与离线特征服务的话题。

在线与离线特征服务

简而言之,在线服务指的是交互发生在实时的情况——也就是说,请求实体或客户端发送请求并同步等待响应。在这种情况下,需要尽可能减少延迟。另一方面是离线服务,它指的是请求实体或客户端不同步等待响应,操作允许在更长的时间内发生。在这种情况下,延迟通常不是主要关注的问题。这个概念与在线和离线推理的主题密切相关,我们将在第十章中详细讨论。

在离线特征服务的情况下,Vertex AI Feature Store 允许我们直接在 Google Cloud BigQuery 数据集中存储和提供特征。这是一个相当方便的选项,因为许多 Google Cloud 客户已经使用 BigQuery 来存储和分析大量数据。

在在线特征服务的情况下,现在有两种方式可以在 Vertex AI 特征存储中提供我们的特征。第一种选择使用 Google Cloud Bigtable 来提供我们的特征。Google Cloud Bigtable 是一个专为服务大量数据(数以兆字节计的数据)而设计的强大服务。

在线特征服务的第二种选择,被称为优化在线服务,作为 Vertex AI 特征存储新版本的一部分被添加,允许我们创建一个专门针对以极低延迟提供特征数据的在线商店。

选择哪种选项取决于你的用例需求,特别是你是否需要处理非常大的数据量,或者你是否需要以极低延迟提供你的特征。成本也是这个决定的一个考虑因素,考虑到 Bigtable 解决方案通常比优化在线服务解决方案成本低。

在本章和随附的 Jupyter Notebook 中,我们将主要关注优化在线服务方法。以下部分将更深入地探讨在 Vertex AI 特征存储中设置在线特征服务的过程。

在线特征服务

从高层次来看,以下步骤是使用 Vertex AI 特征存储设置在线服务所需的。我们将在后续章节中详细阐述这些步骤:

  1. 在 BigQuery 中准备数据源。

    可选:通过创建特征组和特征在特征注册表中注册数据源。

  2. 设置在线商店并展示资源以呈现特征数据源。

  3. 从特征视图中提供最新的在线特征值。

让我们更详细地看看这些概念。

特征注册

当使用优化的在线服务方法时,我们可以选择一个步骤来在我们的 Vertex AI 特征注册表中注册我们的特征,该注册表也已被添加为 Vertex AI 特征存储新版本的一个组件。

这涉及到创建称为特征组的资源的过程,这些特征组代表特征列的逻辑分组,并与特定的 BigQuery 源表或视图相关联。反过来,特征组包含称为特征的资源,这些特征代表特征组所表示的数据源中包含特征值的特定列。

即使我们不将我们的 BigQuery 数据源添加到特征注册表中,我们仍然可以在网上提供特征,但请注意,特征注册表提供了额外的功能,例如存储与你的特征相关的历史时间序列数据。因此,我们将在这个章节的实践练习中使用特征注册表。现在,让我们更详细地看看设置在线特征服务的过程。

在线特征存储和特征视图

在我们设置好 BigQuery 中的特征数据后,并可选地在特征注册表中注册特征组和特征,我们需要设置两种主要类型的资源来启用在线特征服务:

  • 一个在线服务集群实例,也称为在线存储。请记住,我们可以使用 Bigtable 进行在线特征服务或新发布的优化在线特征服务选项。

  • 一个或多个特征视图实例,其中每个特征视图都与一个特征数据源相关联,例如在我们的特征注册表中的特征组(如果我们选择了在特征注册表中注册我们的特征选项),或者一个 BigQuery 源表或视图。

在创建特征视图后,我们可以配置同步设置,以确保我们的 BigQuery 中的特征数据与我们的特征视图同步。我们可以手动触发同步,但如果我们的源数据预计会随时间更新,我们还可以配置一个计划,定期从数据源刷新我们的特征视图内容。

现在我们已经涵盖了与 Vertex AI Feature Store 相关的许多重要概念,是时候深入其中,构建我们自己的特征存储库了!

构建我们的特征存储库

在本节中,我们将进行实际练习,以实现我们在前一节中学到的概念。

使用我们的 Vertex AI 笔记本构建特征存储库

第五章中我们创建的 Vertex AI 笔记本实例中,我们可以执行以下步骤来构建特征存储库:

  1. 选择打开 JupyterLab以打开我们在第五章中创建的 Vertex AI 笔记本实例。

  2. 当 JupyterLab 打开时,您应该会在笔记本中看到一个名为 Google-Machine-Learning-for-Solutions-Architects 的文件夹。

  3. 双击该文件夹,然后在该文件夹内双击 Chapter-07 文件夹,最后双击 feature-store.ipynb 文件以打开它。

  4. 在出现的选择内核屏幕上,选择Python (Local)

  5. Shift + Enter运行笔记本中的每个单元格,并阅读 Markdown 和注释中的说明,以了解我们在做什么。

现在您已经按照笔记本中的步骤执行了特征选择和工程,构建了特征存储库,并使用了一些特征来训练模型,让我们看看这些特征在推理时间如何被使用。在后面的章节中,您将学习如何部署模型进行在线推理并向这些模型发送推理请求,但就目前而言,我将从概念层面解释这个过程。

特征在在线推理过程中的使用

在本节中,我将使用我们在配套的 Jupyter Notebook 中构建的出租车费用预测模型用例作为示例,来解释我们如何在推理过程中使用特征存储库中的特征。我们将查看过程中的每个步骤。

结合实时和预计算特征

例如,当前接车时间(pickup_datetime)、pickup_locationpassenger_count等特征可以在每次出租车行程开始时实时获取。

我们的特征存储还包含预计算的特征,例如历史行程距离、每英里费用、接车时间和位置。这些特征可以根据当前行程的上下文从可用的实时特征中选择。

为了获取预计算的特征,处理出租车行程的应用程序可以向我们的特征存储发送请求,传递标识符,如当前时间和位置,之后特征存储可以返回这些标识符的相关特征值。

预测数据组装

在这一点上,我们可以将实时数据和获取到的特征组装成一个与模型期望格式匹配的特征向量,然后将组装好的特征向量传递给模型。模型随后处理这个向量,并输出一个费用预测,该预测随后可以在应用程序中显示。

干得好!你已经成功在 Google Cloud 上构建了一个特征存储。让我们总结一下本章中我们讨论的所有内容。

摘要

在本章中,我们讨论了我们的特征质量以及数据集中特征与观察值的比率如何影响我们的算法从数据中学习。我们讨论了当我们的数据集中包含许多特征时可能出现的挑战,以及如何通过使用诸如降维等机制来解决这些挑战。我们深入探讨了降维技术,如特征选择和特征投影,包括 PCA、LDA 和 t-SNE 等算法,并查看了一些使用这些算法的实例,通过实际操作活动来实现。

接下来,我们深入探讨了特征工程技术,其中我们增强了一个源数据集以创建包含原始数据集中不易获得的信息的新特征。最后,我们深入探讨了 Vertex AI 特征存储,了解我们如何使用该服务来存储和提供我们的工程特征集。

在下一章中,我们将把我们的关注点从模型所学习的数据集和参数转移到讨论影响模型学习方式的不同类型的参数。在那里,我们将探讨超参数和超参数优化的概念。

第八章:超参数和优化

我们在 第二章 中介绍了超参数和超参数优化(或调整)的概念。在本章中,我们将更详细地探讨这些概念,并使用 Google Cloud 产品,如 Vertex AI Vizier,来定义和运行超参数调整作业。

按照我们建立的模式,我们将首先介绍本章实践活动中所需的先决条件。然后,我们将介绍与本章内容相关的一些重要基本概念,最后,我们将进行实践操作,教您如何在现实场景中应用这些概念。

本章涵盖了以下主题:

  • 先决条件和基本概念

  • 什么是超参数?

  • 超参数优化

  • 实践:在 Vertex AI 中进行超参数调整

让我们首先回顾本章的先决条件。

先决条件

在本章中执行主要活动之前,需要完成本节中的步骤。

启用 Artifact Registry API

我们将创建 Docker 镜像,以便与 Google Cloud Vertex AI Vizier 服务一起运行我们的自定义代码。Google Cloud Artifact Registry 是一个完全管理的工件存储库,我们可以用它来存储我们的容器镜像。它可以被视为下一代 Google Cloud Container Registry (GCR),可以用来存储诸如 Java JAR 文件、Node.js 模块、Python 轮子、Go 模块、Maven 工件和 npm 包(除了已经支持在 GCR 中的 Docker 镜像)等工件。

要启用 Artifact Registry API,请执行以下步骤:

  1. 在 Google Cloud 控制台中,导航到 Google Cloud 服务菜单APIs & ServicesLibrary

  2. 在搜索框中搜索 Artifact Registry

  3. 在结果列表中选择 API。

  4. 在显示 API 信息的页面上,点击 启用

接下来,让我们设置本章步骤所需的权限。

创建 AI/ML 服务账户

第六章 中,我们创建了一个服务账户来使用 Google Cloud 的数据处理服务。在本章中,我们将创建一个服务账户,该账户将用于在 Google Cloud Vertex AI 中管理资源时的超参数调整作业。

执行以下步骤以创建所需的服务账户:

  1. 在 Google Cloud 控制台中,导航到 Google Cloud 服务菜单IAM & Admin服务账户

  2. 选择 创建 服务账户

  3. 对于服务账户名称,输入 ai-ml-sa

  4. 点击 创建 并继续

  5. 在标题为 授予此服务账户访问项目 的部分中,添加 *图 8**.1 中显示的角色。

图 8.1:AI/ML 服务账户权限

图 8.1:AI/ML 服务账户权限

  1. 选择 完成

我们的服务账户现在已准备好在本章的后续部分使用。

现在我们已经涵盖了先决条件,让我们讨论一些在执行本章中的动手活动之前我们需要理解的概念。

概念

本节描述了支撑我们在本章中将要讨论的实践活动的概念。

本章中使用的模型评估指标

我们已经在之前的章节中讨论了模型评估指标的话题。我们首先在第一章中介绍了这个概念,其中我们简要讨论了如回归用例的均方误差MSE)和分类用例的准确率等指标。在第五章中,我们使用了 scikit-learn 中的函数来计算我们创建的模型的一些这些指标,并在该章节的末尾建议将查找更多指标作为补充学习活动。

在本章中,我们将为分类用例训练模型,并介绍一些额外的指标来评估我们的模型。我们将使用的主要指标是称为AUC ROC的东西,它代表接收者操作特征曲线下的面积。听起来可能很多,但别担心,我们将在本节中更详细地解释这个指标。为了做到这一点,我们首先需要介绍一些概念和用于计算 AUC ROC 的更简单的指标。

注意,在二元分类用例中,模型需要预测数据集中每个数据点的两种可能结果之一,即真或假,也称为积极消极。它们通常用 1 和 0 表示。

模型很少完美,所以它们有时会犯错误。让我们看看二元分类模型预测的可能结果。

真阳性、假阳性、真阴性和假阴性

二元分类模型的预测通常有四种可能的结果:

  • 当我们的模型预测某事物为真(或积极)而实际上它是真(或积极)时,我们称之为真阳性TP

  • 当我们的模型预测某事物为真(或积极)但实际上它是假的(或消极)时,我们称之为假阳性FP

  • 当我们的模型预测某事物为假(或消极)而实际上它是假(或消极)时,我们称之为真阴性TN

  • 当我们的模型预测某事物为假(或消极)但实际上它是真的(或积极)时,我们称之为假阴性FN

让我们更详细地看看这些结果是如何相互关联的。

混淆矩阵

前述概念可以通过称为混淆矩阵的视觉方式来表示,这在表 8.1中有演示。

预测为消极 预测为积极
实际消极 TN FP
实际积极 FN TP

表 8.1:混淆矩阵

我们可以使用前面的概念来计算衡量模型在尝试准确识别数据集中的正或负数据点时表现如何的指标。我们将在下面定义这些指标。

真阳性率

真阳性率TPR)表示模型正确预测为正例的数据点总数与数据集中所有正例数据点的总数之比,包括模型错误地预测为负的数据点(即模型说它们是负的,尽管它们是正的,这意味着它是假阴性)。

计算 TPR 的公式是 TPR = TP / (TP + FN)

TPR也被称作召回率灵敏度

假阳性率

假阳性率FPR)是假阳性(模型错误地将负例预测为正例的数量)与假阳性加上真负例(模型正确预测为负例的数量)之和的比率。换句话说,它是实际负例中被错误地识别为正例的比例。

计算 FPR 的公式是 FPR = FP / (FP + TN)

TPR也被称作漏报率

真阴性率

真阴性率TNR)的描述方式与 TPR 类似,只是将正负进行了交换。也就是说,TNR 表示模型正确预测为负的数据点总数与数据集中所有负例数据点的总数之比,包括模型错误地预测为正的数据点(即模型说它们是正的,尽管它们是负的,这意味着它是假阳性)。

计算 TNR 的公式是 TNR = TN / (TN + FP)

TPR也被称作特异性

假阴性率

假阴性率FNR)的描述方式与 FPR 类似,只是将正负进行了交换。它是错误预测的负观察值与实际正例的比率。换句话说,它是实际正例中被错误地识别为负例的比例。

计算 FNR 的公式是 FNR = FN / (FN + TP)

精确度

精确度是正确预测的正观察值与总预测正例的比率。换句话说,在模型预测为正的所有实例中,有多少实际上是正的?

计算 FNR 的公式是 P = TP / (TP + FP)

当我开始学习所有这些内容时,我 wonder 为什么有这么多不同的指标来衡量二元分类模型性能的略微不同的方面。

至少有以下几个原因:

  • 统计基础:这些指标是二元分类用例中统计分析的自然结果

  • 试错法:每个指标可能比其他指标更重要,这取决于用例的预期结果。

考虑以下第二个点的例子。如果你试图预测信用卡欺诈,你可能希望最大化你模型的敏感性,这将尽可能减少错误否定数,即使这最终导致更多的错误肯定。换句话说,即使交易并非欺诈,错误地将交易标记为欺诈也比错误地允许欺诈交易发生要好。

另一方面,如果你正在创建垃圾邮件过滤器,你可能更愿意允许一些垃圾邮件意外地进入你的收件箱(错误否定),而不是将有效邮件标记为垃圾邮件(错误肯定)。

前述指标通常过于简单,无法独立使用,因此你通常会想要找到一个更复杂的指标组合,以提供更平衡的结果。即使在信用卡欺诈用例中,太多的错误肯定也会对信用卡客户造成干扰和挫败。这种平衡取决于你指定的阈值(介于 0 和 1 之间),以确定某物是正还是负。例如,低阈值会导致更多的正例,而高阈值会导致更多的负例。这使我们转向更高级的指标,如 F1 分数和 AUC ROC,我们将在下面描述。

F1 分数

F1 分数定义为精确率和召回率的调和平均数,其计算公式如下:

F1 = 2 * (精确率 * 召回率) / (精确率 + 召回率)

F1 分数特别有用,当你更关心正类,并且想要平衡精确率和召回率时。

AUC ROC

要理解 AUC ROC,我们首先分解其名称。接收者操作特征(ROC)是一个相当复杂的名称,指的是通过在不同分类阈值设置下绘制 TPR 与 FPR 的曲线生成的曲线,如图图 8.2所示。

图 8.2:AUC ROC

图 8.2:AUC ROC

曲线下的面积(AUC)是 ROC 曲线下从(0, 0)到(1, 1)的整个二维面积,如图图 8.2中的蓝色区域所示。AUC 提供了对所有可能的分类阈值的性能的汇总度量,目标是最大化曲线下的面积,因此,在最佳情况下,曲线会延伸到左上角,填满整个图表。

让我们更详细地看看如何解释 AUC ROC 分数值:

  • AUC ROC 分数为 1.0 表示模型能够完美地区分所有正负数据点,在这种情况下,它没有错误否定和错误肯定(即没有错误)。

  • AUC ROC 得分为 0.5 意味着模型无法准确区分正负数据点,其表现不如随机猜测。

  • AUC ROC 得分低于 0.5 意味着模型的表现不如随机猜测,将负样本预测为正样本,将正样本预测为负样本。

理解这些指标很重要,因为它们通常是我们的机器学习算法试图优化的目标。在下一节中,我们将讨论超参数和超参数调整,我们将看到这些目标指标构成了我们调整工作的基本目标。

什么是超参数?

正如我们在第二章中讨论的那样,超参数是定义我们的模型训练作业如何运行的参数。它们不是模型从数据集中学习的参数,而是与模型训练过程执行相关的外部配置选项。它们影响最终模型的性能,并代表模型的高级属性,如复杂性或它应该学习的速度。

以下是我们在这本书中已经讨论过的超参数的例子:

  • 在我们第二章关于超参数的讨论中,我们介绍了学习率、训练轮数等例子。

  • 第五章中,我们将聚类数量作为 K-means 算法的超参数,并为基于树的模型配置了超参数,例如树的最大深度。

  • 我们在第七章中讨论了正则化,正则化参数是超参数的另一个例子。

对于不同类型的算法,还有许多其他类型的超参数,随着我们阅读本书的进展,我们将遇到更多。

超参数优化

我们如何知道应该使用哪些类型的超参数以及它们的值是多少?超参数可以根据领域知识、经验或试错来选择,但为了最有效地选择最佳超参数,我们可以使用称为超参数优化或超参数调整的过程,这是一个可以通过不同的机制实现的系统过程,我们将在下一节中讨论。最终,超参数优化的目标是调整模型超参数,以实现最佳性能,这通过在验证集上运行模型来衡量,验证集是我们源数据集的一个子集。

优化超参数值的方法

第二章中,我们描述了超参数调整机制,如网格搜索、随机搜索和贝叶斯优化,这里简要回顾一下:

  • 网格搜索:这是对整个超参数空间(即尝试所有可能的超参数值组合)的穷举搜索。这通常是不切实际的,并且计算上过于昂贵。

  • 随机搜索:随机搜索方法使用一种子采样技术,其中为每个训练作业实验随机选择超参数值。这不会导致测试每个超参数的所有可能值,但它通常是一种非常有效的方法来找到一组有效的超参数值。

  • 贝叶斯优化:这使用一种优化算法,并且是 Google Cloud Vertex AI 提供的一项托管服务。

以下是一些在行业中存在的额外超参数调整机制:

  • 基于梯度的优化:这种方法使用梯度下降,我们已经在本书的早期部分对其进行了深入探讨。这些方法通常用于训练神经网络。本书后面将提供单独的部分,详细描述如何训练神经网络。

  • 进化算法:这些是基于种群的优化算法,其模型松散地基于自然选择的过程。术语“基于种群”指的是构建一个潜在候选者池(或种群)的做法。在这种情况下,种群中的每个候选者代表一组不同的超参数,候选者根据其验证性能进行评估。表现最好的候选者随后被选中以产生下一代的“后代”。这些算法也更有可能被用于高级用例,如神经网络,其中超参数搜索空间可能很大且复杂,评估单个解决方案的性能可能很昂贵。

  • 自动化机器学习AutoML系统:我们在前面的章节中讨论了 AutoML 的过程。它可以用于自动化整个机器学习生命周期,包括超参数调整。

在任何情况下,一般的调整过程如下:

  1. 将源数据集分为三个子集:

    1. 训练数据集:用于训练模型

    2. 验证数据集:用于在调整过程中评估每个超参数组合

    3. 测试数据集:用于测试最终模型

  2. 选择我们想要创建的机器学习模型类型(例如,线性回归,决策树,神经网络)。这决定了哪些特定的超参数可以被调整。

  3. 设置初始的超参数范围或网格及其值。这可以基于领域知识或研究,或者我们可以从随机广泛的范围开始,并在一段时间内对其进行细化。

  4. 选择一种搜索模型超参数空间的方法(例如,随机搜索,贝叶斯优化)。

  5. 对于每个超参数组合,将模型拟合到训练数据,并通过测试它来评估其性能,与验证数据比较,并测量所选模型类型的适当目标指标(例如,回归的 MSE,二分类的 AUC ROC)。

  6. 一旦评估了所有组合,选择导致最佳模型性能的超参数值组合。

  7. 使用这些超参数训练一个最终模型,并使用test数据集测试该模型,以确认模型对未见数据的泛化能力。

注意,找到最佳的超参数和值组合可能需要迭代数百次甚至数千次概述的步骤,这将非常耗时,或者可能无法手动执行。这就是为什么通常需要自动化步骤的超参数调优作业。

现在我们已经涵盖了与超参数调优相关的许多重要理论概念,是时候将我们的重点转移到这些概念的实际应用上了。

动手实践:在 Vertex AI 中进行超参数调优

考虑到 Google Cloud Vertex AI 提供了使我们能够轻松实现数据科学项目生命周期中每一步的工具,这为我们提供了一个完美的环境来将我们的知识付诸实践并开始实施超参数调优作业。实际上,正如我们之前提到的,Vertex AI 提供了一个名为 Vizier 的工具,专门用于自动化超参数调优作业,我们将在下一部分更详细地探讨。

Vertex AI Vizier

Vertex AI Vizier 是 Google Cloud 中的一项服务,它自动化了我们在本章前一部分概述的超参数调优过程。在本节中,我们将讨论 Vertex AI Vizier 服务使用的某些术语,并描述其工作的一些细节。然后,我们将在我们的动手活动中实际使用它来实施超参数调优作业。

Vertex AI Vizier 术语

Google Cloud 使用一些特定于 Vertex AI Vizier 服务的术语。我们在此简要描述一些重要术语,并将它们与我们本章早期讨论的通用概念联系起来。

研究、研究配置和试验

在 Vertex AI Vizier 中,一个研究代表我们试图实现的总体目标以及实现该目标所涉及的所有步骤和其他细节。例如,如果我们查看本章“优化超参数值的方法”部分概述的一般调优过程步骤,一个研究封装了所有这些步骤。一个研究配置是包含我们研究所有细节的实际配置对象,例如我们希望研究优化的目标指标、要测试的参数以及要使用的参数搜索方法。

试验是我们研究中的一个单独实验,或者在调整过程中的单个迭代(即使用特定超参数值的单个训练和评估作业)。当朝着我们指定的目标努力时,研究将运行许多试验。

在您创建了一个研究之后,Vertex AI Vizier 将自动开始运行试验。在每次测试中,将使用不同的一组超参数。Vertex AI Vizier 将跟踪每次运行的成果,并利用这些知识来选择最佳的超参数集(它将在找到最佳的超参数集后自动停止运行试验)。Vizier 还将总结所有试验,并根据与目标指标相关的表现对它们进行排名。然后,我们可以使用排名最高的试验中的超参数来训练我们的机器学习模型。

既然我们已经了解了术语,让我们深入到实际操作活动中!

用例和数据集

在本节中,我们将使用 Kaggle 上可用的信用卡欺诈检测数据集(www.kaggle.com/datasets/mlg-ulb/creditcardfraud)开发一个 XGBoost 模型来检测信用卡欺诈。

实现

我们将在本章的实际操作活动中使用 Jupyter Notebook,并将自定义笔记本的内容,因此我们将使用一个用户管理的笔记本实例。我们可以使用在第七章中创建的相同的 Vertex AI Workbench 用户管理笔记本实例。请在该笔记本实例上打开 JupyterLab。在屏幕左侧的目录浏览器中,导航到Chapter-08目录并打开vizier-hpo.ipynb笔记本。您可以选择Python (Local)作为内核。同样,您可以通过选择单元格并在键盘上按Shift + Enter来运行笔记本中的每个单元格。除了相关代码外,笔记本还包含 Markdown 文本,描述了代码的功能。

我们的超参数调整作业是如何工作的

使用 Vertex AI Vizier 进行超参数调整涉及在模型中实现的几个步骤。让我们看看这个过程中的关键步骤:

  1. 首先,我们创建一个训练应用程序,它由一个 Python 脚本组成,该脚本使用给定的超参数训练我们的模型。此脚本还必须跟踪和报告在验证集上测试模型时的性能,以便 Vertex AI Vizier 可以使用这些性能指标来确定最佳的超参数。因此,我们在代码中使用cloudml-hypertune Python 库定期将超参数调整指标报告回 Vertex AI。

  2. 接下来,我们为超参数调优作业创建一个配置对象,该对象指定了要调优的超参数及其可能值的范围,以及我们想要优化的目标指标(在我们的案例中,我们使用 AUC ROC,在代码中简单地称为auc)。在此阶段需要注意的一个重要事项是,我们包含的超参数越多,需要运行的试验组合就越多。这可能会导致我们的调优作业需要额外的时问和计算资源(因此成本也会增加)。因此,在可能的情况下,最好使用领域知识来确定我们希望调优作业关注的超参数。我们还可以使用超参数调优作业配置中的maxTrials变量来控制试验的数量。

    可以理解的是,并不总是可以使用领域知识来缩小参数搜索空间,我们通常需要在超参数调优作业输出的质量、运行它们所需的时间和成本之间找到一个平衡点。例如,长时间运行调优作业可能会让我们尽可能接近找到完美的超参数值集合,但缩短运行时间可能会得到满足我们用例需求的结果。

  3. 我们超参数调优实现中的最后阶段是使用 Vertex AI Vizier 客户端库将超参数调优作业提交给 Vertex AI,然后 Vertex AI 使用不同的超参数值集合运行我们的训练应用程序,并找到最佳值。

使用我们的超参数调优作业的结果

当然,我们运行超参数调优作业并不是为了好玩(尽管这也是很有趣的!)!当我们的调优作业找到最佳的超参数集合时,我们将想要访问和审查它们,并且通常我们希望使用它们来训练我们模型的最终版本。

通过 Google Cloud 控制台访问结果

当我们在笔记本中运行超参数调优作业时,我们的代码输出将显示一个链接,该链接将使我们能够查看 Google Cloud 控制台中调优作业的状态。在该链接中最重要的内容是调优作业执行的试验列表,它看起来类似于图 8**.3

图 8.3:超参数调优试验

图 8.3:超参数调优试验

在 Google Cloud 控制台中我们的超参数调优试验列表中,我们可以看到每个试验的 AUC 指标,以及相关的试验 ID(如图 8.3 左边的框内所示),我们还可以看到每个试验使用的超参数值(如图 8.3 右边的框内所示)。我们可以点击auc列标题中的箭头符号来按升序或降序排序该列。在我们的情况下,我们希望按降序排序,因为我们希望最高分出现在顶部。这告诉我们哪个试验具有导致性能最佳模型的超参数。在图 8.3 中,您可能会注意到至少前五个试验都具有相同的 AUC 分数。这是常见的,因为可能有多个不同的超参数值组合可以产生相同的指标分数。您可以使用屏幕右下角的箭头浏览额外的试验页面,您将看到其他导致 AUC 分数较低的试验。

编程访问结果

虽然在 Google Cloud 控制台中查看我们的超参数调优作业结果很有用且有趣,但我们可能不希望手动复制粘贴它们到最终的训练作业中,以创建我们的结果模型。

幸运的是,我们可以通过 Vertex API 编程访问所有这些细节,并且我们可以使用 Vertex 客户端库从我们的开发环境中完成这项操作。在我们的笔记本中,在调优作业完成后,我们可以继续进行笔记本中的其他活动,这将向您展示如何访问和使用调优作业产生的最佳超参数值集。然后我们使用这些超参数值在我们的笔记本中训练一个新的模型,然后我们最终将该模型与测试数据集进行测试,计算并显示最终的 AUC 分数。请注意,当我运行这个程序时,我得到了 0.9188 的 ROC-AUC 分数,这相当不错!

干得好,您现在已经学到了很多关于超参数调优主题的知识,您应该准备好将所学知识应用到其他类型的机器学习问题中。让我们总结一下本章我们学到了什么。

概述

在本章中,我们深入探讨了机器学习中重要的目标指标概念。我们详细介绍了用于评估二元分类模型的最受欢迎的许多指标,例如精确率、召回率、F1 分数和 ROC AUC。然后我们转向讨论超参数优化,包括该领域的一些重要理论信息,例如可以用来搜索最佳超参数集及其相关值的多种方法。这也提供了一些关于为什么由于可能需要大量试验,手动高效地进行超参数调优可能非常困难或甚至不可能的见解。

然后,我们深入了解了 Google Cloud Vertex AI Vizier 服务,该服务可以用来自动为我们进行超参数调优。我们在 Vertex AI 上的 Jupyter Notebook 中进行了实际操作,并使用 Vizier 自动找到用于训练信用卡欺诈检测模型的最佳超参数集。

接下来,我们使用超参数调优作业的输出训练了我们模型的最终版本,然后我们用测试数据集评估了该模型。

在下一章中,我们将开始探索比线性回归和决策树等更简单的机器学习算法更深入的内容,并深入到人工神经网络(ANNs)的领域。让我们继续前进,发现这个概念和技术类别中的迷人之处。

第九章:神经网络与深度学习

在本章中,我们将讨论机器学习ML)中的神经网络NN),通常被称为人工神经网络ANNs。我们将介绍这个科学领域中的许多重要主题,包括导致人工神经网络发展的基本概念,以及它们应用的相应用例。在此阶段,重要的是要注意,术语深度学习DL)指的是使用深度神经网络DNNs)实现的机器学习。我们将在本章后面解释“DNN”这个术语。

我们还将介绍一些工具和框架,这些工具和框架使我们更容易创建神经网络,例如 TensorFlow 和 Keras,我们将在本章后面的动手活动中使用这些工具来构建神经网络。最后,我们将讨论不同类型的神经网络架构、神经网络实现中的常见挑战以及优化我们神经网络架构的一些实践。

作为一个旁注,我第一次开始学习关于人工神经网络(ANNs)是在大学期间,我记得我对这个概念非常着迷,因为我也有浓厚的兴趣了解人脑是如何工作的。尽管神经网络的概念确实是基于人类大脑理论运作的,但在本章中,我们将区分炒作和现实,并专注于这项技术的实际、数学描述。让我们首先覆盖这个领域的一些重要概念。

本章涵盖了以下主题:

  • 神经网络和深度学习概念

  • 在 TensorFlow 中实现多层感知器MLP

  • 神经网络架构、挑战和优化

神经网络和深度学习概念

在本节中,我们讨论在神经网络和深度学习背景下理解的重要概念。我们首先讨论人工神经网络是如何与我们理解人脑相联系的。

神经元和感知器

虽然人工神经元和生物神经元(如人类大脑中发现的)之间的联系经常被过分强调,但它们之间存在一个概念上的联系,这有助于我们形成它们如何工作的心理模型。生物神经元通常由三个主要部分组成,如图图 9.1所示:

图 9.1:神经元(来源:https://www.flickr.com/photos/187096960@N06/51173238594)

图 9.1:神经元(来源:https://www.flickr.com/photos/187096960@N06/51173238594)

细胞体是神经元的核心部分,其中包含细胞核和其他重要组件。树突(来自希腊语单词“dendron”,意为“树”)是从细胞体分支出来的结构。它们接收来自其他神经元的信息并将这些信息传输到细胞体。最后,轴突是从细胞体延伸出来的长管状结构,将信息发送到其他神经元的树突(通过称为突触的界面)。关于神经元的生物学,我们就讲到这里;我在这里简化了很多,因为我们只需要为与人工神经网络(ANNs)进行比较提供高级背景,但接下来我们需要了解的是它们是如何传输信息的,这在大体上如下(再次,为了相关背景简化)。

当一个神经元从另一个神经元接收信号时,这会导致神经元细胞膜(神经元内外电压差)中所谓的电势发生变化,从而触发所谓的动作电位,这是一种沿着轴突传播的电气脉冲。当它到达轴突的末端时,它会触发神经递质的释放,这些神经递质是化学信使。这些神经递质穿过所谓的突触间隙(神经元之间的微小空间)并绑定到下一个神经元的树突上的受体,这种结合可以触发或抑制第二个神经元中的新动作电位。

好的——在前两段中,我们刚刚介绍了很多生物学术语,但当我们想要将概念与人工神经网络(ANNs)进行比较时,这些概念是非常重要的。考虑到这一点,让我们继续前进,讨论人工神经网络是如何构建的,从它们最基本的概念,即感知器开始,我在第一章中简要提到了感知器,当时我总结了机器学习(ML)演变的各个里程碑。

感知器可以被视为最简单类型的人工神经网络之一,也是更大、更复杂网络的构建块。它在 20 世纪 50 年代末由弗兰克·罗森布拉特(Frank Rosenblatt)开发,基本上是一个二元分类器,它使用一组应用于输入特征的权重将输入 X(一个向量)映射到一个输出值 f(x)(一个单一的二元值)。

为了更详细地了解这个过程,让我们深入探讨感知器是如何工作的,这可以通过以下步骤来概括:

  1. 感知器接收输入值,这些值可以是数据集中的特征或属性。

  2. 每个输入都有一个与之相关的权重,它表示其重要性。权重通常在训练开始时随机给出,然后在训练过程中进行细化。我们将在稍后详细讨论这一点。

  3. 偏置单元也被添加到感知器模型中,以增加模型的灵活性。这与我们在本书后续章节中讨论的公平性背景下的偏差主题无关;这仅仅是一个数学技巧,它为在尝试产生所需输出时改进我们模型性能提供了一个额外的控制机制。

  4. 接下来,每个输入乘以其相应的权重,并将所有这些乘法的结果(以及偏置)相加(结果是一个加权总和),所以这仅仅是基于权重和偏置值的输入的线性变换

  5. 这个加权的总和随后通过一个激活函数,该函数产生一个二进制输出。我们将在稍后更详细地解释激活函数,但从高层次来看,对加权总和执行非线性变换,并将该变换的结果作为感知器的输出。对于单个感知器来说,一个简单的例子是,如果输入的加权总和大于一个阈值值,感知器将输出 1,或者如果加权总和小于或等于阈值,它将输出 0,所以这基本上是逻辑回归过程的实现。

    从数学上讲,这可以写成以下形式:

    • 如果 ∑ (权重 * 输入) + 偏置 > 0,输出 1

    • 如果 ∑ (权重 * 输入) + 偏置 ≤ 0,输出 0

图 9.2提供了感知器工作原理的视觉表示:

图 9.2:感知器(来源:https://commons.wikimedia.org/wiki/File:Perceptron-unit.svg#file)

图 9.2:感知器(来源:https://commons.wikimedia.org/wiki/File:Perceptron-unit.svg#file)

图 9.2 中,图的最左侧的 x 值代表感知器的输入。x0 输入是偏置,而 x1 到 xn 代表来自我们数据集的输入特征。w 值代表权重,绿色圆圈内的希腊字符(sigma 和 phi)代表激活函数,而最右侧的希腊字符(omicron)代表输出。

需要理解的重要概念是,权重和偏置的值是我们感知器模型试图学习的。也就是说,我们的模型试图找出每个特征的最佳权重,从而在执行我们描述的线性和非线性变换(结合偏置)后,得到一个尽可能接近目标结果的模式。如果我们回想一下我们在前几章中创建的更传统的 ML 模型,例如线性回归,我们可能会记得我们的模型试图找出每个特征的系数的最优值,以实现预期的结果。在感知器和 ANN 中,权重(以及偏置)是我们模型试图优化的系数。

在理解了感知器的工作原理之后,让我们讨论如何使用它们来构建更复杂的 NN。

MLPs 和 NNs

虽然感知器是一个简单而强大的算法,但它只能模拟线性可分函数。这意味着如果我们的数据不是线性可分的(也就是说,我们无法画一条直线来分离类别),感知器将无法准确地区分数据集中的类别。为了克服这一限制,可以通过层将多个感知器组合起来形成 MLP,它有可能解决非线性问题。MLP 是 NN 的一种形式,所以基本上,当我们以顺序方式(即某些感知器的输出成为其他感知器的输入)组合多个感知器时,我们形成了一种 ANN。

考虑到感知器可以被看作是一种人工神经元,从现在开始我们将“感知器”和“人工神经元”(有时简称“神经元”)这两个术语交替使用。

总结与生物神经活动的比较

正如我们之前所讨论的,神经元从感觉器官或其他神经元接收输入,并且根据产生的电势,动作电位会导致神经元向其他神经元发送(或不发送)消息。

同样,感知器(或人工神经元)从我们的数据集接收输入,或者如果我们是在 NN 中将感知器串联起来,则从其他人工神经元接收输入。然后,根据这些输入及其权重和偏置的线性组合,激活函数将影响感知器的输出,该输出可以用作网络中另一个感知器的输入。

接下来,让我们更详细地探讨 NN 的典型结构,并介绍 NN 中重要的概念。

NN 中的层

当人工神经元组合在一起形成 NN 时,它们不是随机连接的,而是使用层这一概念以结构化的方式进行连接,如图图 9.3所示:

图 9.3:NN 层

图 9.3:NN 层

图 9**.3所示,神经网络的层通常分为三种不同类型:

  1. 输入层,正如其名称所暗示的,是我们输入进入神经网络的方式。它是网络中的第一层,当然是。

  2. 隐藏层,位于输入层和输出层之间。它们的工作是将输入转换为输出层可以使用的东西。术语“隐藏”只是意味着它们不与外界接口(它们既不是网络的输入也不是输出)。我们通常无法控制或直接与它们交互;它们学会独立表示数据。隐藏层的数量以及每个隐藏层中的神经元数量定义了神经网络的复杂性和结构。

  3. 输出层,正如其名称所暗示的,展示了我们的神经网络的输出,这通常是某种预测。

除了隐藏层的数量和每个隐藏层中的神经元数量外,层之间的确切连接方式取决于神经网络的架构。我们将在本章后面讨论不同类型的常见神经网络架构,但通常发生的情况是,我们的输入数据被输入到神经网络的输入层后,网络后续层中的每个神经元的行为类似于我们在本章前面描述的感知器。

例如,每个输入都被分配一个表示其重要性的权重。这些权重通常用随机值初始化,然后在学习过程中进行细化。输入乘以其相应的权重,并将结果相加,再加上一个偏差值。然后将总和作为后续层(即从第一个隐藏层开始)中神经元的激活函数的输入。重要的是要记住,每个神经元的权重和偏差将是不同的。因此,尽管每个神经元在第一个隐藏层看到的是完全相同的数据输入,但每个神经元对数据的反应将因各种权重和偏差的不同影响而有所不同。

需要理解的是,每一层的激活函数的输出将作为网络后续层中再次执行的过程的输入。因此,我们刚才描述的过程将在每一后续层中执行,但与我们的原始数据集在每一层作为输入不同,每一后续层将使用前一层的激活值作为输入。这意味着在信息通过我们的网络传递时,正在实施多个转换,这也是神经网络之所以强大的原因。

让我们确保我们对这个过程有清晰的理解。以第二个隐藏层为例,过程如下:

第一层的每个激活函数输出都被分配一个表示其重要性的权重。这些权重通常用随机值初始化,然后在学习过程中进行优化。激活函数的输出乘以相应的权重,并将结果相加,再加上偏差值。然后将这个总和作为下一层神经网络中神经元的激活函数的输入。这个过程在每个层中重复,直到我们到达网络的最终输出层。

注意

不同的神经网络架构可以使用不同的方式在网络中传播信息。在本章中,我们将更详细地讨论一些常见的神经网络架构类型,但我们之前描述的内容可以被认为是人工神经网络工作原理的基石。

你也可能听到“DNN”这个术语。传统上,任何至少有两个隐藏层的神经网络都被认为是深度神经网络(DNN)。

网络中某一层的神经元激活对下一层神经元激活的影响,使我们回到了与人类大脑的类比,其中某些神经元的放电可以引起其他神经元的放电,产生各种不同的交互组合,从而产生更复杂的高级功能。然而,我们必须对这个类比持保留态度,因为即使是最复杂的 ANN 也包含成千上万的神经元,而人类大脑有数十亿个神经元,每个神经元能够执行比人工神经元相对简单的数学变换更复杂的函数。

现在我们已经讨论了信息如何在人工神经网络(ANN)中传播,让我们更深入地探讨 ANN 是如何学习的,为此,我们必须引入反向传播的概念。

反向传播

我们在上一节中描述的内容可以被称为前向传播,其中信息在我们的神经网络(NN)中从一层传播到另一层。为了讨论反向传播,让我们回顾一下在这本书中我们之前学到的关于监督机器学习(SML)算法是如何工作的内容。记住,我们使用标签来描述数据集中每个数据点的特征。当我们训练一个模型时,模型试图学习数据集中特征之间的模式,这将帮助它准确地预测每个数据点的标签。然后我们使用损失函数来计算我们的模型预测与正确标签之间的差距;模型训练活动的首要目的是最小化损失函数(即最小化模型产生的错误),我们可以使用梯度下降等技术来最小化损失函数。

以在表格数据上训练的基本线性回归模型为例。你可能记得,在这种情况下,我们的数据集表中的每一行代表一个数据点或观察值,而表中的每一列代表一个特征。线性回归模型试图猜测它可以为每个特征使用的系数,这样将每个特征乘以其系数并将所有结果相加,可以得到尽可能接近目标标签的结果。

在线性回归的情况下,每次模型预测错误时,我们会使用损失函数来计算误差,然后计算损失函数相对于每个系数的梯度,然后使用梯度下降来确定如何相应地调整系数,这个过程会重复多次,直到模型改进或由于某种原因停止。

这就是神经网络比我们在本书前面实现的简单回归模型更复杂的地方。在神经网络的情况下,我们没有输入特征到系数的一对一映射。相反,我们的数据通过一个由多个层组成的复杂网络传播,每个层包含多个神经元,每个层的每个神经元都有不同的权重集(以及偏差值)。因此,当我们的模型做出预测并使用损失函数来计算误差时,它不再仅仅是计算损失函数相对于每个输入特征系数的梯度,然后更新每个特征的系数并再次尝试的情况。相反,我们必须为神经网络每一层的所有权重执行此过程。完成此过程的一种方法被称为“误差反向传播”或“反向传播”。

使用反向传播,我们从最后一层开始更新每一层的权重(即最接近我们的输出层的那一层,它代表我们的模型预测),然后逐层反向通过我们的网络。

由于我们的神经网络损失函数由几个嵌套函数组成(由于网络中的层),反向传播步骤中的梯度计算使用了一种称为链式法则的技术,这是微积分中计算损失函数相对于每一层权重的导数的技术。然后,这些结果用于确定如何在网络中的每一遍中更新权重。

我们将在本章后面回到反向传播和链式法则的话题,但首先,让我们更详细地探讨一下我们可以在每次训练过程中使用哪些算法来优化我们的成本函数。

成本函数优化算法

我们已经讨论了在模型训练期间使用梯度下降等机制来优化我们的成本函数。在本节中,我们将简要讨论一些我们可以使用的其他常见优化算法。

动量

这可以被视为基本梯度下降算法的升级。当我们讨论成本函数优化中的梯度下降时,我们经常使用在山区下山(或至少到达山谷底部,这可能是“局部最小值”)的类比。在随机梯度下降SGD)的情况下,类比更像是随机跳跃,在这种情况下,我们有时会向上跳一点(即,朝错误的方向),但总体上,我们通常最终会向下走(即,朝正确的方向)。这种在不同方向跳跃的情况被称为振荡。动量算法通过在正确的方向上导航更明显并减少错误方向上的振荡来加速 SGD。它是通过平均每一步的更新梯度来实现的,这导致沿着误差梯度的下降更加平滑,通常会导致更快地到达底部。在这种情况下使用的类比是一个球沿着山滚动,在这种情况下,运动比偶尔跳跃更平滑。请注意,球也可以获得动量,这有助于它在梯度斜率较小时(小梯度斜率会导致传统梯度下降的学习速度较慢)表现得更好。在实践中,动量几乎总是优于基本梯度下降。

自适应梯度算法(Adagrad)

如其名所示,Adagrad 是一种自适应优化算法。也就是说,在每次优化周期中,Adagrad 会根据每个单独的参数调整学习率。对于梯度大的参数,它执行较小的更新;对于梯度小的参数,它执行较大的更新,这使得它在处理稀疏数据和具有数百万个参数的深度学习模型时特别有用。尽管它可能是一个有用的算法,但它可能导致学习率迅速变得过小,从而有效停止学习。这在长时间训练场景(如深度学习)中可能是一个问题,因为学习过程可能会过早停止。为了解决这个问题,最近开发了如均方根传播RMSProp)和自适应矩估计Adam)等更近期的变体,我们将在下一节讨论这些内容。

RMSProp

RMSProp 通过将学习率除以平方梯度的移动平均MA)来解决 Adagrad 的学习率迅速减小的问题。基本上,它比 Adagrad 更快,通常也更好。

Adam

Adam 结合了动量和 RMSProp 的优点。它平均梯度(像动量一样)并使用平方梯度(像 RMSProp 一样)。它通常是优化器的最佳选择,尤其是在深度学习中。

除了本节中我们已介绍的那些优化算法之外,还有许多其他的优化算法,我们可能在后面的章节中使用其他优化器,但本章我们将使用 Adam,所以现在我们只是介绍 Adam 所基于的流行算法。

在我们开始动手活动之前,我们将更深入地探讨一个重要概念,即激活函数的概念。

激活函数

到目前为止,我们已经触及了激活函数及其在高级别上如何工作的主题。在本节中,我们将更深入地探讨这个主题,并讨论一些我们可以在我们的神经网络中使用的一些常见的激活函数类型。

线性(恒等)激活函数

这个激活函数简单地返回我们提供给它的任何输入,不改变,它通常用于简单任务,或者它经常用作回归用例的输出层。

它可以用数学公式表示为 f(x) = x。

这通常不是我们会用于我们网络中的隐藏层的,因为它不允许学习任何类型的复杂关系。

注意

在神经网络中明确指出非线性变换的重要性是很重要的,因为神经网络的主要力量在于它们能够组合多个非线性变换,以学习数据中的复杂关系。因此,非线性激活函数是复杂神经网络的一个重要组成部分。

即使我们将许多层组合到我们的网络中,如果它们都只是实现了线性变换,我们的整个网络也只会执行一个大的线性变换,这我们可以不使用神经网络来实现。

Sigmoid 激活函数

Sigmoid 函数是逻辑回归的一种实现,它将任何输入映射到 0 和 1 之间的范围。

它可以用数学公式表示为 f(x) = 1 / (1 + exp(-x))。

图 9.4 以了解此函数的视觉表示:

图 9.4:Sigmoid 函数(来源:https://commons.wikimedia.org/wiki/File:Sigmoid-function-2.svg)

图 9.4:Sigmoid 函数(来源:https://commons.wikimedia.org/wiki/File:Sigmoid-function-2.svg)

Sigmoid 函数是较简单的激活函数之一,它通常已被我们接下来将要讨论的新函数所取代。它的一个局限性是它容易受到一个称为梯度消失问题的困扰,我们将在本章后面描述这个问题。然而,在二分类问题的输出神经元中,它仍然可以是有用的,其中我们将输出解释为输入属于某一类或另一类的概率。

双曲正切(tanh)激活函数

tanh 函数类似于 sigmoid 函数,但它将任何输入映射到 -1 和 1 之间的值。

它可以用数学公式表示为 f(x) = (exp(x) - exp(-x)) / (exp(x) + exp(-x))。

图 9.5 以了解此函数的视觉表示:

图 9.5:tanh 函数(来源:https://commons.wikimedia.org/wiki/File:Mplwp_tanh.svg)

图 9.5:tanh 函数(来源:https://commons.wikimedia.org/wiki/File:Mplwp_tanh.svg)

与 sigmoid 函数类似,tanh 也存在梯度消失问题,但在实际应用中仍然有用。

矩形线性单元(ReLU)激活函数

ReLU 函数在最近几年变得非常流行。简单来说,它将任何正数映射到自身,任何负数映射到零。

它可以用数学公式表示为 f(x) = max(0, x)。

图 9**.6 中该函数的直观表示:

图 9.6:ReLU 函数

图 9.6:ReLU 函数

ReLU 的一个主要优点是它计算效率高,因为该函数本质上只是检查输入是否大于零,如果大于零则直接返回输入,如果不大于零则返回零。这是一个简单的数学计算,这种简单性导致训练速度大大加快。

另一个主要优点是它不受梯度消失问题的影响。然而,它还受到另一个称为“死亡 ReLU”问题的困扰,这是一种神经元由于持续输出零而变得无用的现象。这是因为当输入为零或负数时,函数的梯度变为零。这意味着在反向传播过程中,当权重更新时,该神经元的权重将不会调整。这种情况导致神经元“卡住”,并持续输出零——实际上导致神经元“死亡”,在区分输入时不起任何作用。

Leaky ReLU 激活函数

该函数试图通过在输入小于零时输出小的负值来解决“死亡 ReLU”问题。

它可以用数学公式表示为 f(x) = max(0.01x, x)。

在这种情况下,0.01 的值代表 x 的小的非零梯度,它是一个可以改变的超参数。

图 9**.7 中该函数的直观表示:

图 9.7:Leaky ReLU

图 9.7:Leaky ReLU

图 9**.7 所示,Leaky ReLU 避免了输出变为零的问题,即使输入是负数。还有一个 Leaky ReLU 的扩展,称为 参数 ReLUPReLU),它允许在训练过程中通过反向传播学习 x 的小的非零梯度,而不是通过超参数指定为静态数字。

Softmax 激活函数

Softmax 函数通常用于多类分类用例中的神经网络输出层,它将网络的原始输出转换为概率向量(即为类别创建概率分布)。

它可以用数学公式表示为 f(xi) = exp(xi) / Σ(exp(xj)),其中 j 遍历输出层中的神经元集合。

它是 sigmoid 函数的扩展;sigmoid 函数可以用来提供输入属于某一类或另一类的概率(在两个类别之间的选择中),而 softmax 函数可以提供输入属于多个类别的概率范围。例如,如果我们的网络试图识别 1 到 10 之间的数字图像,那么有 10 个可能的类别可以选择。如果我们提供一个数字 1 的图像,并在网络的输出层使用 softmax,那么它可能会确定图像中的数字有很高的概率是 1,而其他潜在类别的概率较低(即 2 到 10)。

除了本节中提到的激活函数之外,还有更多的激活函数,但我们在这里提到的这些是最为知名和广泛使用的。我们选择的激活函数可以取决于特定的用例和其他因素。

现在我们已经覆盖了深度学习领域中的许多重要理论概念,让我们通过构建我们的第一个神经网络来将所学知识付诸实践。为此,我们将介绍一些重要的库。

在本节中,我们描述了我们将在本章中使用的库,例如 TensorFlow 和 Keras。

TensorFlow

TensorFlow 是由 Google Brain 团队开发的用于机器学习和深度神经网络研究的开源软件库(OSS)。然而,它也可以在从移动设备到多 GPU 设置的广泛系统上运行,并且它可以在机器学习之外有众多应用。在本节中,我们将讨论其一些重要方面,例如以下内容:

  • 张量是向量矩阵在多维度的推广(我们可以把它们想象成多维数组或列表)。它们是 TensorFlow 的基本构建块。

  • 数据流图DFGs),其中图中的节点代表数学运算,边代表在这些节点之间传输的数据(张量)。这种方法使得 TensorFlow 能够在多个设备上实现并行计算,使其适合训练大型神经网络。

  • 模型部署有多种选择,例如 TensorFlow Serving 用于服务器端部署或 TensorFlow Lite 用于移动和物联网设备。

  • 通过自动计算损失相对于模型权重的梯度来优化反向传播。

对机器学习和深度学习感兴趣的人应该熟悉 TensorFlow,因为它在业界得到了广泛的应用。

Keras

Keras 是一个用 Python 编写的用于在 TensorFlow、Theano 和认知工具包CNTK)等底层框架之上运行的神经网络高级 API。它是为了实现快速实验而开发的,并已成为 TensorFlow 的官方高级 API(截至 TensorFlow 2.0)。它的一些主要特性包括以下内容:

  • 用户友好性:它有一个简单且一致的界面,针对常见用例进行了优化,并提供清晰的错误消息、有用的文档和开发者指南。

  • 模块化:Keras 模型是通过连接可配置的构建块组装而成的。例如,我们可以通过堆叠多个层轻松构建神经网络。

  • 可扩展性:我们可以编写自定义构建块来表达新的研究想法,并创建新的层、损失函数和模型。

Keras 的核心数据结构是模型,这是一种组织层的方式。主要模型类型是 Sequential 模型,它是一系列层的线性堆叠,但对于更复杂的架构,我们可以使用 Keras 功能 API,这允许我们构建自己的自定义层图。Keras 中的层是一个实现常见神经网络操作的类,Keras 包括一系列预定义的层,我们可以使用它们来构建模型。它还允许我们在训练阶段指定我们想要评估的损失函数和度量标准,并提供许多预定义的损失函数,如mean_squared_error和度量标准如accuracy。Keras 还包括许多优化算法,如 SGD。总的来说,它包括许多有用的工具,使我们能够轻松创建神经网络。

现在我们已经介绍了相关的库,让我们深入探讨并构建我们的第一个神经网络!

在 TensorFlow 中实现 MLP

在本节中,我们将使用 TensorFlow 构建一个 MLP。我们将使用 Keras 作为与 TensorFlow 交互的高级 API。我们可以使用在第五章中创建的相同的 Vertex AI Workbench 笔记本来完成此目的。在那个笔记本中,执行以下步骤:

  1. 导航到名为Google-Machine-Learning-for-Solutions-Architects的文件夹。

  2. 在其中双击Chapter-09文件夹,然后双击Chapter-9-TF-Keras.ipynb文件以打开它。

  3. 当提示选择内核时,选择TensorFlow

  4. 我们打开的笔记本中包含一些 Python 代码,使用 Keras 和 TensorFlow 创建和测试了一个 MLP。

  5. 通过点击每个单元格并在键盘上按Shift + Enter来运行笔记本中的每个单元格。如果您看到任何与 CUDA 相关的错误,请忽略它们,因为我们在这个笔记本中不使用 GPU。

笔记本的第一单元格中的代码导入必要的库和模块,使用sklearn.datasets中的make_moons函数加载数据集,然后使用matplotlib可视化数据。

在这种情况下,我们使用moons数据集,这是一个用于二分类的数学生成数据集,常被用作 ML 算法的简单测试案例,尤其是那些设计用于处理非线性数据(如 NNs)的算法。该数据集由两个特征的两维数组组成(通常在 X-Y 平面上可视化)以及每个样本的二元标签(0 或 1),样本生成的方式使得当绘制时形成两个新月形形状(因此得名moons),每个“月亮”对应一个类别。参见图 9.8以获取参考:

图 9.8:moons 数据集

图 9.8:moons 数据集

注意,数据集的主要特征是其非线性(即,分隔两个类别的决策边界不是一条直线)。

我们 Jupyter 笔记本第二个单元格中的代码执行以下操作:

  • 将数据集分为训练集和测试集

  • 定义一个 Sequential 模型(这意味着层是堆叠在一起的)

  • 添加一个输入层和第一个隐藏层,包含 32 个神经元和relu激活函数

  • 添加一个第二个隐藏层,包含 32 个神经元和relu激活函数

  • 添加一个输出层,包含一个神经元(用于二分类)和sigmoid激活函数

  • 使用adam优化器和binary_crossentropy损失函数(适用于二分类)编译模型

  • 对模型进行 50 个周期的训练

当代码运行时,你应该会看到每个周期的输出,如图图 9**.10所示:

图 9.9:训练周期输出

图 9.9:训练周期输出

注意,随着训练的进行,lossval_loss(验证损失)应该减少,而accuracyval_accuracy(验证准确率)应该增加。

接下来,我们第三个单元格中的代码执行以下操作:

  • 使用model.evaluate方法评估我们的模型,该方法在测试模式下返回模型的损失值和度量值(在这种情况下,accuracy)。

  • 使用model.predict方法从我们的模型中获得一些预测,该方法输出每个输入样本属于正类的概率。

  • 为了将其视为二分类用例,我们的代码随后将这些概率转换为基于 0.5 阈值的二元类别标签(即,任何概率超过 0.5 的东西都被认为是正类成员)。

  • 最后,我们打印出前 10 个预测结果以进行快速检查。这些输出将以 0 和 1 的形式呈现,表示预测的类别标签。

就这样!你已经创建了一个神经网络!它可能没有人类那么聪明,但这在 TensorFlow 中使用 Keras 的 MLP(多层感知器)的基本示例。我们可以通过调整诸如层数、神经元类型、激活函数类型、优化器类型、损失函数以及训练配置(如 epoch 数量、批量大小等)等方式,将其扩展到更高级的深度学习用例。做得好!

接下来,我们将深入研究额外的深度学习概念,例如不同类型的神经网络架构、深度神经网络应用中的挑战,以及优化考虑。

神经网络架构、挑战和优化

到目前为止,本章我们已经主要介绍了神经网络的基础知识,在本节中,我们将扩展我们的讨论,包括不同类型的神经网络架构,这些架构可以用于不同类型的实际应用场景,以及训练它们时经常遇到的挑战。最后,我们将讨论如何优化我们的神经网络以解决这些挑战。

常见的神经网络架构

神经网络的“架构”指的是其结构,包括它包含的层数、每层的神经元数量,以及任何影响信息通过网络传播的特殊特性。在本章中我们描述的神经网络架构是 ANN(人工神经网络)的最简单形式,被称为前馈神经网络(FFNN)。这些网络中的信息仅沿一个方向传播,从输入层,通过隐藏层,到输出层。接下来,让我们看看一些其他常用的神经网络架构。在这里,我们将从高层次介绍它们,并在后面的章节中深入探讨更多细节。

注意

当我们在本节中谈论信息通过网络传播时,我们并不是指反向传播步骤,因为那是在迭代学习过程中实现的单独步骤。我们只是简单地指数据在每次训练遍历或推理时间通过我们的网络的方式。

卷积神经网络(CNN)

CNN 在计算机视觉(CV)中常用,用于诸如物体识别和图像分类等用例。考虑这样一个场景,我们希望训练我们的模型来识别猫的图像,同时考虑到这些图像可能以多种不同的形式出现,例如在不同的距离和视角下被捕捉。我们的模型需要建立一种对猫的视觉理解,例如它的面部形状、耳朵、身体和尾巴,以便在图像中正确识别猫。

卷积神经网络(CNNs)通过将图片分解成更小的组件或“特征”并分别学习每个特征来实现这一点。这样,网络学会在更大的图像中检测小细节,例如边缘或曲线,然后将这些细节组合成更大的特征,如单根胡须或猫耳朵的一部分,无论它们在图像中的位置如何,然后将这些特征组合起来以识别猫。卷积神经网络(CNNs)使用卷积层池化层全连接(FC)层的概念来完成这项工作。在这本书的后续章节中,我们将进一步探讨这些概念及其工作原理。

循环神经网络(RNNs)和长短期记忆(LSTM)网络

循环神经网络(RNNs)被设计用来在序列数据中寻找模式,如语言或时间序列。在 RNNs 中,网络包含循环,这使得信息可以从一步持续到下一步,这也是 RNNs 能够创建一种记忆的原因,与假设所有输入(和输出)都是相互独立的基本神经网络不同。通过这种方式,网络在每个步骤中将当前数据与早期阶段输入的数据混合,这对于语言理解等活动非常重要,在这些活动中,模型需要理解每个词与输入中其他词的关系(即,词不是完全独立的)。

然而,循环神经网络(RNNs)的一个问题是,由于我们将在后面讨论的原因,它们在处理长序列时会“忘记”先前的输入。为了解决这些问题,已经发明了诸如长短期记忆(LSTM)网络和门控循环单元GRU)网络等变体,它们使用门和其他技术来保持记忆。

自编码器(AEs)

自编码器(AEs)用于学习未标记数据的有效编码,通常用于降低数据的维度。自编码器(AEs)的基本思想相当简单:它被训练来尝试复制其输入到输出。尽管这可能看起来像是一个简单(且冗余)的操作,但我们施加给网络的限制迫使它发现数据中的有趣方面。最常见的是,我们限制隐藏层中的节点数量,迫使网络学习数据的压缩视图。

自编码器(AEs)由一个编码器和一个解码器组成。编码器将输入数据编码为在低维空间中的压缩表示,解码器则尝试从低维表示中重建输入(即“解码”压缩表示)。在训练过程中的目标是创建一个重建输出,使其尽可能接近输入,以便网络能够学会从压缩表示中重建输入。

在现实世界中,自编码器(AEs)被用于异常检测和推荐系统等应用。自编码器(AEs)的一个特别流行的应用是在生成式人工智能GenAI)模型中。在这种情况下,一旦自编码器被训练,解码器就可以生成新的数据,这些数据模仿了训练数据。

生成对抗网络(GANs)

GANs(生成对抗网络)的基本目标是创建与“真实”数据(由训练数据确定)非常接近的新伪造数据。GANs 由两个相互竞争的神经网络组成,一个称为生成器,另一个称为判别器。这两个网络通过一种最小-最大游戏协同训练,这是一种生成器试图欺骗判别器,而判别器试图可靠地区分真实数据和生成数据的游戏。在训练过程中,生成器在提供看似真实的数据方面变得越来越准确,而判别器在识别伪造方面变得越来越熟练。

Transformer 网络

Transformer 网络是 Google 发明的一种模型架构,其突破性创新是使用自注意力机制或多头注意力,这使得模型在生成输出时能够考虑短语中各种词语的相对重要性。例如,在句子“the dog tried to jump over the pond, but it was too wide”中,“it”这个词可能指的是池塘或狗。对人类来说,这似乎非常明显,因为它指的是池塘,这是因为我们正在使用上下文意识来直观地判断什么最有意义。然而,这对机器学习模型来说并不明显,自注意力机制是允许模型更好地理解句子中每个词语的上下文意义的机制。Transformer 架构还包括编码器和解码器的概念,它们都由一系列相同的层组成。此外,由于自注意力机制本身并不考虑输入序列中词语的位置,因此 Transformer 设计还包含一个位置编码系统来跟踪词语的位置。我们将在后面的章节中更详细地探讨所有这些组件。

Transformer 模型提供的另一个优点是,它们可以并行处理所有输入,而不同于基于序列的模型,如 RNN 或 LSTM 网络,这可以显著加快训练和推理速度。

Transformer 网络已被证明在自然语言处理(NLP)任务中非常有用,包括情感分析(SA)、文本摘要和机器翻译,Transformer 架构是生成预训练 Transformer(GPT)、双向编码器表示来自 Transformer(BERT)和 T5 等模型的基础。如果您想了解更多关于这项突破性技术的信息,我建议阅读首次介绍 Transformer 概念的标志性研究论文(Vaswani, A. et al., 2017),该论文可以在以下网址找到:arxiv.org/abs/1706.03762

除了本节中提到的神经网络架构之外,还有更多类型的架构,但我们在这里讨论的这些是其中最知名和最广泛使用的。研究人员不断创造和实验新的神经网络配置,网络配置的选择取决于我们试图解决的问题,因为每种网络类型都有其优势和劣势。

接下来,让我们讨论一些人们在训练和使用神经网络时遇到的一些常见挑战。

常见神经网络挑战

除了我们在前面章节中讨论的传统机器学习实现的所有挑战之外,DNNs 还引入了它们自己的一套挑战,例如可解释性、成本以及梯度消失或爆炸。

可解释性

可解释性指的是我们理解模型内部工作原理以及它们做出决策背后的原因的难易程度。例如,线性回归模型通常很容易理解和解释,因为它们的输出只是对模型提供的任何输入的简单数学变换。

然而,深度神经网络(DNNs)可能极其复杂,拥有数千个神经元和数十亿个参数,这些参数会影响它们的输出。此外,它们的输出通常不仅仅是输入的线性变换,而是本质上是非线性的。

在后面的章节中,我们将更详细地讨论可解释性的重要性,并介绍可以帮助我们更好地理解模型工作原理的机制。

成本

DNNs 在训练和托管时可能需要大量的计算资源,这可能导致货币支出。如果我们考虑具有数十亿参数的高度复杂模型,这些模型可能需要数周甚至数月的时间来训练,使用大量最新一代的尖端 GPU 的非常强大的服务器。这些资源并不便宜,因此我们需要确保我们的模型尽可能高效地使用计算资源。

梯度消失问题

我们在本章的前几节简要提到了这个话题,所以让我们更详细地探讨这个概念。当损失函数的梯度变得非常小,以至于几乎消失时,就会产生梯度消失问题,导致网络第一层的权重更新缓慢。记住,反向传播使用微分链式法则,这涉及到乘以一系列的导数(或梯度)。这意味着如果导数的值小于 1,我们在通过网络反向传播时,实际上是以指数方式将它们分成越来越小的值。正因为如此,早期层的学习速度比后期层慢得多。

当使用 sigmoid 或 tanh 等将输入压缩到小范围的激活函数时,这个问题变得更加明显。例如,sigmoid 函数将输入值压缩到零到一的范围,这意味着即使输入值很大(无论是正还是负),sigmoid 函数的输出也介于零和一之间,结果是梯度减少到极小的值,导致基于反向传播的学习速度显著减慢。

梯度爆炸问题

另一方面,当梯度变得过大时,会导致网络中的权重通过过大的增量更新,这会导致网络的性能剧烈波动,从而使模型训练过程失败。

梯度爆炸问题在 RNN 中更为常见,尤其是在长序列中,但它可以发生在任何类型的网络中。

防止梯度消失或梯度爆炸的优化

现在我们对梯度消失和梯度爆炸问题发生的方式有了更好的理解,以下考虑因素可以帮助降低它们发生的可能性。

权重初始化

有效的权重初始化可以帮助减轻梯度消失和梯度爆炸的问题。例如,Xavier(Glorot)初始化和 He 初始化等技术可以帮助将初始权重设置为防止梯度在训练初期变得过小或过大的值。

激活函数的选择

正如我们讨论的,使用压缩其输入的激活函数,如 sigmoid 或 tanh,会增加遇到梯度消失和梯度爆炸问题的可能性。因此,在容易遇到这些问题的场合最好避免使用这些激活函数。我们可以改用 Leaky ReLU 或 PReLU 等激活函数,因为这些函数不会压缩它们的输入。

批标准化

使用这种技术,我们可以将层的输出归一化,以稳定每个层输入的均值和方差。这有助于控制梯度的规模,减轻梯度消失和梯度爆炸问题。

梯度裁剪

这种技术对梯度设置了一个预定义的限制或阈值,以防止它们变得过大,这对于解决梯度爆炸问题特别有用。

架构方法

在本节前面讨论 RNN 时,我们提到它们在处理长序列时会“忘记”先前的输入。梯度消失问题是导致这种情况的一个因素,这也是为什么某些架构,如 LSTM 和 GRU,被设计用来在 RNN 的上下文中通过在其结构中使用一种门控机制来解决这些问题的原因之一。因此,有时选择 NN 架构可以降低遇到梯度消失和梯度爆炸问题的可能性。

这些问题和它们的解决方案是理解深度学习模型如何工作以及如何有效地训练深度神经网络的主要因素。

本章我们介绍了许多新的概念和术语。让我们花点时间总结一下我们所学的所有内容。

摘要

在本章中,我们首先探讨了人工神经元(以感知器形式)与人类大脑中的生物神经元之间的比较。然后,我们将这一想法扩展到描述神经网络中多个神经元的活动,包括将多个感知器组合在一起以及我们大脑中的微小神经元如何协同工作以产生极其复杂的高级功能。

然后,我们更深入地探讨了人工神经网络的内幕和工作组件,包括诸如激活函数和反向传播等概念。我们讨论了许多不同类型的激活函数,包括它们的工作原理以及最适合它们的用例。

在反向传播的背景下,我们学习了各种常用的成本函数优化算法,例如动量法和 Adam 法,然后我们介绍了两个非常重要的深度学习库:TensorFlow 和 Keras。

接下来,我们使用这些库构建了我们第一个神经网络,并通过基于moons数据集成功获得预测来测试了这个网络,我们也在本章中对其进行了详细探讨。

在构建了我们第一个简单的神经网络之后,我们扩展了讨论范围,涵盖了更高级的神经网络架构及其用例,并探讨了人们在训练和使用神经网络时经常遇到的常见挑战,以及我们可以用来优化网络以减少遇到这些问题的可能性的方法。

这些是机器学习领域的一些更高级的概念,所以如果你已经理解了本章所涵盖的内容,那么你已经为我们在后续章节中对这些概念进行更深入探讨奠定了重要的基础。

在下一章中,让我们探讨如何将训练好的模型投入生产,以便为现实世界的用例提供服务。

第十章:生产环境中的部署、监控和扩展

有些人可能会从头到尾阅读这本书,以尽可能多地了解 Google Cloud 在 AI/ML 领域的概念,而其他人可能会将其作为参考,当他们需要作为项目或客户合作的一部分处理特定主题时,他们会挑选并阅读某些章节。如果您从本书的开头就开始阅读,那么您已经走了很长的路,我们已经一起走过了ML 模型开发生命周期MDLC)的大部分旅程。虽然模型训练通常是媒体关注的焦点——这也是许多魔法发生的地方——但现在您已经知道,训练只是整个生命周期的一部分。

当我们训练和测试了我们的模型,并且相信它们已经准备好向我们的客户展示时,我们需要找到一种方式来托管它们,以便它们可以被相应地使用。在本章中,我们将更详细地探讨这一过程的部分,包括在托管和管理模型以及持续监控它们以确保它们保持相关性并持续优化性能时存在的挑战。我们将从讨论我们如何托管我们的模型开始。

本章涵盖了以下主题:

  • 我如何使我的模型可供我的应用程序使用?

  • 服务的模型的基本概念

  • A/B 测试

  • 生产环境中服务的模型常见挑战

  • 监控生产环境中的模型

  • 在边缘优化 AI/ML

我如何使我的模型可供我的应用程序使用?

我们在第一章中介绍了这个概念,并讨论了您需要执行的各种操作来在自己的服务器上托管模型,例如设置所有必需的基础设施,包括负载均衡器、路由器、交换机、电缆、服务器和存储等,然后持续管理这些基础设施。这需要您投入大量的时间和资源。

幸运的是,所有这些都在过去,您现在不再需要做任何这些事情。这是因为 Google Cloud 提供了 Vertex AI 预测服务,它使您能够在几分钟内使用由 Google 为您管理的基础设施在生产环境中托管模型。

为了完整性,我还会提到,如果您想在 Google Cloud 上托管模型而不使用 Vertex,还有许多其他 Google Cloud 服务可以用于此目的,例如Google Compute EngineGCE)、Google Kubernetes EngineGKE)、Google App EngineGAE)、Cloud Run 和 Cloud Functions。我们在第三章中描述了所有这些服务,以及一些关于如何在这之间做出选择的提示。

记住,选择合适的平台来托管你的机器学习模型取决于你的具体用例和需求。可扩展性、延迟、成本、开发努力和运营管理都在选择最佳解决方案中发挥作用。你还可以根据你用来构建机器学习模型的框架做出某些决定。例如,如果你在 TensorFlow 中构建模型,你可能想使用 TensorFlow Serving;如果你在 PyTorch 中构建模型,你可能想使用 TorchServe。

在大多数情况下,我的建议是开始使用一个专门且针对当前任务进行优化的服务,在构建和托管机器学习模型的情况下,Vertex AI 就是这样的服务。在本章中,我们将使用 Vertex AI 部署我们的第一个模型,但在我们深入实际操作之前,我们将介绍一些重要概念。

模型服务的根本概念

在本节中,我们将介绍一些与我们如何托管模型以便我们的客户与之交互相关的重要主题。

在线与离线模型服务

在机器学习中,我们有两种从模型中提供预测的选项:在线服务(也称为实时服务)和离线服务(也称为批量服务)。与每种方法相关的高级用例分别是在线(或实时)推理离线(或批量)推理。让我们花几分钟时间介绍这些方法并了解它们的用例。

在线/实时模型服务

正如其名所示,在实时模型服务的情况下,模型需要“实时”响应预测请求,这通常意味着客户端(可能是客户或某些其他系统)需要尽可能快地收到推理响应,并且可能正在同步等待模型的响应。一个这样的例子就是信用卡交易的反欺诈系统。正如你可以想象的那样,信用卡公司希望尽可能快地检测可能的欺诈交易——理想情况下是在交易过程中,这样他们就可以在可能的情况下阻止交易完全处理。在之后的某个任意时间点检查欺诈交易对他们来说可能就不那么有用。

考虑到在线推理请求通常需要尽快返回响应,确保低延迟、处理高请求量以及提供可靠且始终可用的服务是该领域的一些主要挑战。

在这个例子中,当我们提到低延迟时,我们指的是预测响应时间通常在毫秒级别,或者最多几秒钟。实际的响应时间要求将取决于业务用例。例如,一些用户可能可以接受等待几秒钟来批准或拒绝他们的信用卡交易,但另一个实时推理的例子是自动驾驶汽车中机器学习模型的使用,在这种情况下,例如,如果汽车需要突然采取某种行动,比如避开突然出现在其路径上的意外障碍物,它必须能够在毫秒级别对其环境做出反应。图 10.1展示了我们将在本章的实践练习中实施的批预测工作流程的示例。我们将详细解释图中展示的每个组件。在图 10.1中,实线代表我们在实践练习中明确执行的步骤,而虚线代表 Vertex AI 将代表我们自动执行的步骤:

图 10.1:在线预测

图 10.1:在线预测

图 10.1中概述的步骤如下:

  1. 在我们的笔记本中训练模型。

  2. 将生成的模型工件保存到 Google Cloud Storage。

  3. 在 Vertex AI 模型注册表中注册模型详细信息(在本章中更详细地解释)。

  4. 创建一个端点来托管和提供我们的模型。

  5. Vertex AI 在线预测服务(在本章中更详细地解释)从 Vertex AI 模型注册表中检索我们模型的详细信息。

  6. Vertex AI 在线预测服务从 Google Cloud Storage 检索我们保存的模型。

  7. 我们向我们的模型发送预测请求并接收响应。在这种情况下,我们是从我们的 Vertex AI Workbench 笔记本发送请求的,但重要的是要注意,当我们的模型托管在端点时,预测请求可以来自任何可以访问该端点的客户端应用程序。

  8. Vertex AI 在线预测服务将预测输入、输出和其他详细信息保存到 Google Cloud BigQuery。这是一个可选功能,我们可以启用它,以便我们可以对输入、输出以及与我们模型预测相关的其他细节执行分析查询。

还应注意的是,在在线模型服务的情况下,预测通常是按需进行的,通常针对单个实例或一小批实例。在这种情况下,您的模型及其服务基础设施需要能够快速应对推理流量量的突然——可能是意外的——变化。

离线/批处理模型服务

根据我们对在线模型服务的描述,可能已经很明显,离线服务意味着没有客户端在实时等待即时响应。实际上,而不是我们的模型从单个客户端接收按需推理请求,我们可以将许多输入观测值以大批次的形式输入到我们的模型中,它可以处理更长的时间;可能是几个小时甚至几天,具体取决于业务案例。我们的模型产生的预测可以随后存储并用于以后,而不是立即采取行动。批量推理用例的例子包括预测第二天股票价格或根据预测的偏好向用户发送定向电子邮件。图 10**.2 展示了我们将在本章的实践练习中实施的批量预测工作流程的示例。在 图 10**.2 中,实线表示我们将明确在实践练习中执行的步骤,而虚线表示 Vertex AI 将代表我们自动执行的步骤:

图 10.2:批量预测

图 10.2:批量预测

图 10**.2 中概述的步骤如下:

  1. 在我们的笔记本中训练模型。

  2. 将生成的模型工件保存到 Google Cloud Storage。

  3. 在 Vertex AI 模型注册表中注册模型详细信息。

  4. 将测试数据保存到 Google Cloud Storage。这将在我们后续的批量预测作业中用作输入数据。

  5. 创建一个批量预测作业。

  6. Vertex AI 批量预测服务(在本章中更详细地解释)从 Vertex AI 模型注册表中获取我们模型的详细信息。

  7. Vertex AI 批量预测服务从 Google Cloud Storage 获取我们保存的模型。

  8. Vertex AI 批量预测服务从 Google Cloud Storage 获取我们的输入数据。

  9. Vertex AI 批量预测运行一个批量预测作业,使用我们的模型和输入数据。

  10. Vertex AI 批量预测服务将预测输出保存到 Google Cloud Storage。

与优化低延迟不同,批量预测系统通常优化以一次性处理大量实例(即高吞吐量),因此通常属于大规模分布式计算用例,可以从并行执行中受益,并且可以安排定期自动执行(例如,每天一次),或者可以由事件触发(例如,当有新的数据批次可用时)。

重要的是要注意,在线和离线服务的决策并不总是严格二元的,你可能会发现在线和离线服务的组合最能满足你的需求。例如,你可能会使用离线服务生成大规模报告,同时使用在线服务在面向用户的应用中进行实时预测。在任一情况下,在线和离线服务都需要将模型部署在服务基础设施中。该基础设施负责加载模型、接收预测请求、使用模型进行预测,并返回预测结果。在 Google Cloud 中,有各种工具和平台可用于协助此任务,例如 TensorFlow Serving 和 Vertex AI 预测服务,我们将在本章后续部分详细讨论。然而,首先,让我们介绍另一个作为我们端到端模型开发生命周期一部分的重要工具。

Vertex AI 模型注册库

在本书的早期部分,我们将传统的软件开发生命周期SDLC)与 MDLC 进行了类比。为了更深入地探讨这个类比,让我们考虑 SDLC 过程中的几个重要工具:

  • 共享仓库:作为 SDLC 过程的一部分,我们通常希望将我们的代码和相关工件存储在注册库或仓库中,以便多个需要协作进行特定开发项目的贡献者可以访问。这样的仓库通常包括帮助描述代码资产某些方面的元数据,以便人们可以轻松理解这些资产是如何开发的,以及它们是如何被使用的。

  • 版本控制:当贡献者对特定项目中的代码资产进行更改时,我们希望确保我们正在跟踪这些更改和贡献,并且所有贡献者都可以轻松访问这些信息。这也使我们能够在发现软件新部署版本中的问题时回滚到之前的版本。

经验告诉我们,当我们想要高效地部署和管理机器学习模型时,需要类似的工具,尤其是在大规模部署时(记住,一些公司可能拥有成千上万的机器学习模型,由数百个不同的团队拥有)。

此外,请记住,数据科学项目通常高度实验性,数据科学团队可能会尝试许多不同的算法、数据集和超参数值,训练许多不同的模型,以查看哪些选项能产生最佳结果。这在数据科学项目的早期阶段尤其如此,但这种情况也常常持续存在,数据科学家即使在模型部署到生产环境之后,也会不断努力改进模型。他们这样做是为了跟上行业的新趋势,并产生更好的结果。

Google Cloud 的 Vertex AI 平台包括一个模型注册服务,它允许我们在一个集中的位置管理我们的机器学习模型,这使得我们能够更容易地跟踪模型的发展情况,即使有多个团队在贡献这些模型的发展。让我们来看看模型注册的一些重要功能:

  • 模型版本控制:模型注册允许我们创建多个版本的模型,其中每个版本可以对应不同的训练参数集或不同的训练数据集。这有助于我们跟踪不同的实验或部署。

  • 模型元数据:对于每个模型,我们可以记录元数据,例如模型的描述、输入和输出模式、标签(用于分类的有用信息)和指标(用于比较模型的有用信息)。对于每个版本,我们可以记录额外的元数据,例如描述、运行时版本(对应于 Vertex AI 平台服务的版本)、Python 版本、用于服务的机器类型以及服务设置。

  • 模型工件:这些是用于生成模型的工件。它们可以存储在 Google Cloud Storage 中,并链接到注册表中的模型。

  • 访问控制:我们可以通过 Google Cloud 的 身份和访问管理IAM)系统来控制谁可以查看、编辑和部署注册表中的模型。

重要的是要理解模型注册与其他 Vertex AI 组件的良好集成。例如,我们可以使用 Vertex AI 训练服务来训练一个模型,然后自动将训练好的模型上传到注册表中,之后我们可以将模型部署到 Google Cloud Vertex AI 预测服务,我们将在下一节中描述。我们可以比较模型版本,并轻松更改部署到生产中的版本。我们还可以使用 Vertex AI Pipelines 自动化所有这些步骤,我们将在下一章中探讨这一点。

Vertex AI 预测服务

Google Cloud Vertex AI 预测服务是 Vertex AI 生态系统中的一个服务,它使我们能够轻松托管机器学习模型并向我们的客户提供服务,从而支持批量模型服务和在线模型服务用例。这是一个托管服务,因此当我们用它来托管我们的模型时,我们不需要担心管理所需的服务器和基础设施;该服务将根据发送到我们模型的流量量自动扩展所需的基础设施和计算资源。

如我们在上一节中提到的,它集成了 Vertex AI 模型注册,使我们能够轻松控制哪些版本的模型被部署到生产中,并且它还集成了许多其他 Google Cloud 服务,例如 Vertex AI Pipelines,它允许我们自动化模型的开发和部署,以及 Google Cloud Operations Suite,它提供集成的日志记录和监控功能。

我们将在 Google Cloud 中使用 Vertex AI 模型注册和 Vertex AI 预测服务进行实际操作,以存储和提供模型,但首先,让我们再覆盖一个在模型部署和管理方面非常重要的概念:A/B 测试

A/B 测试

A/B 测试是通过测试一个模型(模型 A)与另一个模型(模型 B)的性能来比较哪个模型表现更好。虽然这个术语在技术上可以应用于测试和比较任何模型,但通常的场景是测试模型的新版本,以改善模型在业务目标方面的性能。

Vertex AI 允许我们将多个模型部署到单个端点,并通过使用 traffic_split 变量来控制每个模型所服务的流量量,如图 图 10.3 所示:

图 10.3:使用 Vertex AI 的 traffic_split 进行 A/B 配置

图 10.3:使用 Vertex AI 的 traffic_split 进行 A/B 配置

正如您在本章的实际练习中将会看到的,如果我们不对 traffic_split 变量设置任何值,默认行为是将所有流量都导向已经部署到我们端点的原始模型。这是一个安全机制,可以防止我们的模型在服务客户流量方面出现意外行为。traffic_split 配置使我们能够非常细致地控制我们希望发送到每个已部署模型或模型版本的流量量。例如,我们可以设置 traffic_split 配置,使其突然将所有流量发送到我们的新模型,通过将 100%的流量分配给该模型,从而有效地替换我们的模型。然而,我们可能希望在完全替换先前的模型版本之前,用我们生产流量的一小部分来测试我们的新模型版本,这在软件开发中相当于金丝雀测试的概念。

当我们确定我们的新模型表现符合预期时,我们可以逐渐(或根据业务需求突然)更改 traffic_split 变量,将更多(或全部)流量发送到新模型。

现在我们已经涵盖了与在生产环境中托管和提供模型相关的许多重要概念,让我们通过使用 Vertex AI 部署一个模型来看看这在现实世界中是如何工作的。

我们已经准备了一个 Vertex AI Workbench 笔记本,它会指导你完成所有必要的步骤。再次强调,我们可以使用我们在 第五章 中创建的相同的 Vertex AI Workbench 管理笔记本实例来完成这个任务。请在笔记本实例上打开 JupyterLab。在屏幕左侧的目录浏览器中,导航到 Chapter-10 目录并打开 deployment-prediction.ipynb 笔记本。你可以选择 TensorFlow 2 (Local) 作为内核。同样,你可以通过选择单元格并按键盘上的 Shift + Enter 来运行笔记本中的每个单元格。除了相关的代码外,笔记本还包含描述代码正在做什么的 Markdown 文本。我建议只执行模型训练和部署部分,以及 A/B 测试,然后在继续进行笔记本中的其他活动之前,阅读本章的一些更多主题。

我们还必须在笔记本中启用一个名为 prediction-request-response-logging 的功能,该功能将记录我们模型对收到的预测请求的响应。我们可以将这些响应保存到 Google Cloud BigQuery 表中,这样我们就可以对每个模型的预测响应进行分析,并查看它们的性能。

一旦你完成了笔记本中的模型训练和部署部分(或者如果你现在只想继续阅读),你就可以进入下一部分,我们将讨论公司在生产中部署、提供和管理模型时通常会遇到哪些挑战。

在生产中部署模型时的常见挑战

在生产中部署和托管机器学习模型通常伴随着许多挑战。如果你只是开发和提供单个模型,你可能会遇到一些这些挑战,但如果你正在开发和提供数十、数百或数千个模型,那么你很可能会遇到这些挑战和担忧的大多数。

部署基础设施

选择合适的托管机器学习模型的基础设施、设置和管理它可能很复杂,尤其是在混合或多云环境中。再次强调,Google Cloud Vertex AI 会自动为我们处理所有这些,但没有这样的云服务,许多公司发现这可能是有数据科学项目中最具挑战性的方面之一。

模型在生产和扩展中的可用性

这是部署基础设施管理的扩展。随着需求的增加,我们的模型需要提供更多的预测。根据需求进行服务扩展和缩减的能力至关重要,并且可能很难手动管理。Vertex AI 自动扩展功能使我们能够轻松地做到这一点。我们只需指定我们希望为每个模型运行的机器的最小和最大数量即可。

例如,如果我们知道我们始终需要至少运行三个节点来处理我们通常预期的流量,但有时流量会增加到正常水平的两倍,我们可以指定我们希望 Vertex AI 总是运行至少三台机器,并在需要时自动扩展到最多六台机器。

我们可以通过配置 minReplicaCountmaxReplicaCount 变量来指定我们的自动扩展偏好,这些变量是我们部署的模型机器规格的元素。我们已经在与本章相关的 Jupyter Notebook 中提供了如何操作的步骤。请注意,我们可以按模型指定这些细节,而不仅仅是按端点。这使我们能够独立扩展我们的每个模型,这为我们提供了灵活性,取决于我们的需求。

Vertex AI 也为我们提供了灵活性,可以选择将多个模型部署到同一个端点,或者为每个模型创建独立的、专门的端点。如果我们针对不同的用例有完全不同类型的模型,那么我们通常会把这些模型部署到独立的端点。在这个时候,你可能想知道为什么我们想要将多个模型部署到单个端点。这样做最常见的原因是我们想要实施 A/B 测试。同样,我们已经在伴随本章的 Jupyter Notebook 中介绍了实施 A/B 测试用例的步骤。

数据质量

通常,在生产环境中使用的数据可能包含错误,或者可能没有用于模型训练的数据那么干净,这可能导致预测不准确。因此,我们可能需要在生产中实施数据预处理步骤,在预测时“实时”准备和清理数据。一般来说,我们在准备训练数据时可能应用的任何数据转换技术也需要在推理时应用。

模型/数据/概念漂移

除了准备和清理我们的数据之外,如果你回想一下本书前几章中我们执行的一些数据探索活动,你可能记得我们数据的一个重要方面是数据集中变量的统计分布。例如,包括数据集中每个变量的平均值、每个变量的最小值和最大值之间的观察范围,或者每个变量的值类型,如离散或连续。总的来说,我们可以将这些特征称为我们数据的“形状”。图 10.4 展示了一些不同类型的数据分布的示例:

图 10.4:数据分布  (来源:https://commons.wikimedia.org/wiki/File:Cauchy_pdf.svg)

图 10.4:数据分布 (来源:https://commons.wikimedia.org/wiki/File:Cauchy_pdf.svg)

在一个理想的世界里,用于训练我们模型的 数据形状 应该与模型在生产中预期遇到的数据形状相同。因此,我们通常希望使用现实世界的数据(即,在生产中之前观察到的数据)来训练我们的模型。然而,随着时间的推移,生产中观察到的数据形状可能会开始偏离用于训练模型的数据形状。这种情况可能突然发生,例如,当全球大流行在短时间内急剧改变消费者的购买行为(例如,每个人都突然购买卫生纸和洗手液,而不是时尚和化妆品),或者季节性变化,或者它可能由于特定业务领域或市场的自然进化变化而逐渐发生。

在任何情况下,这种偏差通常被称为“漂移”,或者更具体地说,是模型漂移数据漂移概念漂移。模型漂移指的是模型目标性能随时间整体下降,它可能由数据漂移或概念漂移等因素引起。数据漂移是指生产中数据的统计分布与用于训练我们模型的数据的统计分布不同。另一方面,概念漂移是指模型试图预测的输入特征与目标变量之间的关系发生变化。这意味着即使输入数据保持不变,变量之间的潜在关系也可能随时间变化,这可能会影响我们模型的准确性。大流行期间消费者行为变化的例子是概念漂移的一个实例。

无论漂移的类型如何,它都可能导致模型性能下降。因此,我们需要持续评估我们模型的性能,以确保它们始终满足我们的业务需求。如果我们发现我们模型的性能正在下降,我们需要评估这是否是由于漂移造成的,如果我们检测到它是,我们需要相应地采取纠正措施。我们将在稍后更详细地讨论这些措施。

安全和隐私

确保我们模型使用的数据符合安全和隐私法规可能很复杂,尤其是在处理敏感数据的行业中。根据行业和用例,这可以被认为是模型开发和管理的最重要方面之一。

模型可解释性

通常,模型被视为“黑盒”实现,在这种情况下,我们无法深入了解模型内部的工作方式,这使得理解它们是如何进行预测的变得困难。这可能会引起问题,尤其是在需要解释的监管行业中。我们将在本书的稍后部分更详细地探讨这个话题。

跟踪机器学习模型元数据

正如我们之前提到的,机器学习模型开发通常涉及一些实验,数据科学家会评估他们数据集的不同版本,以及不同的算法、超参数值和其他开发过程组件。此外,开发过程通常涉及多个团队成员或多个独立团队之间的协作。考虑到一些公司开发和部署了数百甚至数千个机器学习模型,跟踪所有这些实验和开发迭代是很重要的。

例如,如果我们有一个在生产中部署的模型,并且观察到该模型正在做出不准确或不适当的预测,那么我们需要了解为什么该模型会这样表现。为了做到这一点,我们需要知道创建该特定模型版本所执行的所有步骤,以及与该模型开发相关的所有输入和输出,例如用于训练模型的输入数据集版本,以及训练过程中使用的算法和超参数值。我们将这些信息称为模型的元数据。没有这些信息,很难理解我们的模型为什么会这样表现。

这个概念与模型可解释性的主题有些关联,但也包括机器学习模型开发的其他方面。

与现有系统的集成

大多数公司都有各种软件系统,这些系统是在多年的时间里开发和采购的,将机器学习模型集成到这些系统中可能很复杂。

监控

如果你自己管理基础设施,为生产中的机器学习模型设置稳健的监控可能是一个挑战。我们需要持续监控模型的预测性能,以确保它仍然有效,并且随着时间的推移没有退化。

这是对模型管理的一个重要方面,因此我们将在本章的下一节专门讨论这个主题。

监控生产中的模型

我们在开发和部署模型后的工作还没有结束——我们需要随着时间的推移跟踪模型的表现和整体健康状况,并在观察到模型性能下降时进行调整。在本节中,我们将讨论我们通常需要监控的一些模型特征。

目标模型性能

毫不奇怪,我们需要监控的我们模型最突出的方面是它在其创建目标方面的表现。我们在本书的前几章讨论了目标指标,例如均方误差MSE)、准确率、F1 分数和 AUC-ROC 等。AUC-ROC 的一个例子在图 10.5中展示,供参考:

图 10.5:AUC-ROC

图 10.5:AUC-ROC

目标指标告诉我们我们的模型在实现其主要目的方面表现如何,例如预测房价或识别照片中的猫。如果我们注意到这些指标在某个我们认为对业务需求可接受的阈值以上持续下降,那么我们通常需要采取纠正措施。

模型性能下降的常见原因是数据漂移,我们已在上一节中讨论过。如果我们发现发生了数据漂移,纠正措施通常是使用与模型在生产中当前观察到的数据形状或分布相匹配的更新数据重新训练我们的模型。这可能需要从我们的生产系统或其他适当的来源收集新鲜数据。

专门监测数据漂移

监测数据漂移涉及比较传入数据的统计属性与训练数据的统计属性。在这种情况下,我们分析数据中的每个特征或变量,并将传入数据的分布与训练数据的分布进行比较。除了比较简单的描述性统计量,如均值、中位数、众数和标准差之外,还有一些特定的统计检验我们可以评估,例如 Kullback-Leibler 散度、Kolmogorov-Smirnov 检验或卡方检验。我们将在本书的后面部分更详细地讨论这些机制。

Vertex AI 模型监控提供了自动测试,可以检测不同类型的漂移。具体来说,它可以检查特征偏斜和漂移以及归因偏斜和漂移,这两者我们将在下文中进行描述。它还提供了模型解释功能,我们将在本书的后面部分详细探讨。

偏斜也被称为训练-服务偏斜,它指的是生产环境中特征数据的分布与用于训练模型的特征数据分布不同的情况。为了检测这种偏斜,我们通常需要访问原始训练数据,因为 Vertex AI 模型监控会将训练数据的分布与发送到我们生产中模型的推理请求中看到的分布进行比较。

预测漂移指的是生产中的特征数据随时间变化的情况。在没有访问原始训练数据的情况下,我们仍然可以开启漂移检测来检查输入数据随时间的变化。

需要注意的是,一些程度的漂移和偏斜可能是可容忍的,但通常我们需要确定和配置阈值,超过这些阈值我们就需要采取纠正措施。这些阈值取决于我们特定用例的业务需求。

异常模型行为

异常可能包括预测请求的峰值、输入特征的异常值或异常的预测响应值。例如,如果一个用于欺诈检测的模型开始标记异常高数量的交易为欺诈,这可能是一个异常,需要进一步调查。异常也可能由于数据漂移或环境中的临时变化而发生。

资源利用率

这包括监控 CPU 使用率、内存使用率、网络 I/O 等方面,以确保模型的服务基础设施在其容量内运行。这些指标是确定何时根据当前发送到我们模型的流量量等因素增加或减少资源的重要指标。

模型偏差和公平性

我们需要确保我们的模型持续进行公平的预测。这可能包括跟踪公平性指标和检查模型预测中的偏差。我们将在下一章中更详细地探讨这个话题。

这些是我们需要监控的模型的主要方面。具体需要优先考虑的项目取决于我们的业务案例。

现在我们已经讨论了模型监控领域中最常见的许多话题,让我们讨论一下如果检测到我们的模型性能下降,我们应该怎么做。

解决模型性能下降问题

如果我们发现我们监控的模型指标值显示出性能下降,我们可以采取一些措施来纠正这种情况,并可能防止未来发生此类情况。本节讨论了一些相关的纠正措施。

确保我们的模型保持最新并表现最佳的最有效方法可能是实施一个健壮的 MLOps 管道。这包括机器学习模型的持续集成和持续部署CI/CD),其主要组成部分是定期使用生产中看到的新数据训练我们的模型——这被称为持续训练。为此,我们需要实施一个机制来捕获生产中的数据,然后自动更新我们的模型。

我们可以定期更新我们的模型(例如,每晚或每月一次),或者根据 Vertex AI 模型监控作业的输出触发重新训练。例如,如果模型监控作业检测到漂移超出了可接受的阈值,可以发送自动通知,并自动启动一个管道来训练和部署我们模型的新版本。

下一章将完全致力于 MLOps 的话题,因此我们将更详细地探讨这些概念。

同时,如果您想从理论转向实践学习,现在执行本章附带的 Vertex AI Workbench 笔记本中的模型监控部分将是一个好时机。否则,让我们继续本章的其余部分,其中包括在边缘优化 AI/ML 用例。

在边缘优化 AI/ML

在边缘提供 ML 模型指的是直接在用户设备上运行您的模型,例如智能手机或物联网设备。术语“边缘”基于传统的网络架构术语,其中网络的核心位于网络所有者的数据中心,而网络的边缘是用户设备连接到网络的地方。在边缘运行模型和其他类型的系统可以提供诸如降低延迟、增加隐私和减少服务器成本等好处。然而,边缘设备通常计算能力有限,因此我们可能需要对模型进行一些调整,以便它们在这些设备上高效运行。我们可以做几件事情来优化我们的模型,以便它们在边缘运行,所有这些内容我们将在本节中讨论。

模型优化

让我们先讨论一下我们可以采取哪些措施来优化我们的模型,以便它们可以在边缘使用。

模型选择

首先,我们应该尝试选择轻量级的模型,这些模型仍然能在我们的目标上提供良好的性能。例如,决策树和线性模型通常比深度学习模型需要的内存和计算能力更少。当然,我们的模型选择过程也取决于我们的业务需求。有时,我们需要更大的模型来实现所需的目标。因此,这个关于在边缘优化 AI/ML 工作负载的建议只是一个初步的指导方针。我们将在下一节讨论更高级的策略。

模型剪枝

剪枝是一种通过移除对模型性能贡献最小的参数(例如,“权重剪枝”)或整个神经元(例如,“神经元剪枝”)来减小模型尺寸的技术。图 10.6 中展示了神经元剪枝的一个例子,其中每个隐藏层都移除了一个神经元(如图中覆盖每个被移除神经元的红色 X 所示):

图 10.6:神经元剪枝

图 10.6:神经元剪枝

结果剪枝后的模型需要更少的内存和计算资源。如果我们移除太多的权重或神经元,那么可能会影响我们模型的准确性,因此,当然,我们的想法是找到一个平衡点,以最小化对准确性的影响,同时减少所需的计算资源。

模型量化

量化是一种降低模型权重数值精度的方法。例如,权重在训练期间可能以 32 位浮点数存储,但在推理时通常可以量化为 8 位整数,而不会显著降低性能。这减少了模型的内存需求和计算成本。这在大型语言模型LLMs)的背景下尤其有用,这些模型可能拥有数百亿个权重。我们将在本书的“生成式 AI”部分详细讨论这一点。

知识蒸馏

这种技术涉及训练一个较小的模型,有时被称为“学生”模型,以模仿一个较大、被称为“教师”模型或模型集合的行为。较小的模型被训练以产生尽可能接近较大模型的输出,以便它能执行类似的任务,或许在模型精度上有所可接受的降低。再次强调,我们需要在模型尺寸减小和精度降低之间找到平衡。在 LLMs 的背景下,蒸馏技术尤其有用。

利用高效模型架构

一些模型架构被设计为在边缘设备上高效。例如,MobileNet 和 EfficientNet 是卷积神经网络CNNs)的高效变体,适合移动设备。

现在我们已经讨论了一些我们可以对模型进行的修改,以优化它们在边缘用例上的性能,让我们看看我们还可以使用哪些其他类型的机制来实现这一目的。

模型技术之外的优化

所有的先前优化技术都涉及对我们的模型进行修改,使其在边缘设备上运行得更高效。我们还可以采取其他措施,例如将训练好的模型转换为针对边缘设备优化的其他格式,或者优化在边缘运行我们的模型的硬件。让我们更详细地讨论这些机制。

硬件特定优化

根据边缘设备上的特定硬件(例如,CPU、GPU、张量处理单元TPU)等),可以使用不同的优化策略。例如,一些库提供了基于特定硬件优化计算图的工具。

专用库

如 TensorFlow Lite 和开放神经网络交换ONNX)运行时之类的库可以将模型转换为针对边缘设备优化的格式,进一步减少模型的内存占用并提高其速度。我们将在本节中更详细地讨论这些库。

TensorFlow Lite

TensorFlow Lite 是 TensorFlow 提供的一套工具,帮助我们运行移动、嵌入式和物联网设备上的模型。它是通过将我们的 TensorFlow 模型转换为更高效的格式,以便在边缘设备上使用来实现的。它还包括优化模型大小和性能的工具,以及实现硬件加速的工具。我们已经使用 TensorFlow Lite 转换我们的模型;这可以在本章所附的 Jupyter Notebook 中找到。

Edge TPU Compiler

Google 的 Edge TPU Compiler 是一种用于将模型编译到 Google 的 Edge TPUs 上运行的工具,这些 Edge TPUs 是为在边缘设备上运行 TensorFlow Lite 模型而设计的。

ONNX Runtime

ONNX 是一种用于表示机器学习模型的开放格式,它使得模型能够在各种机器学习框架之间进行迁移。它还提供了一个跨平台的推理引擎,称为 ONNX Runtime,它包括对各种硬件加速器的支持,旨在提供快速的推理并降低机器学习模型对资源的需求。

TensorRT

TensorRT 是 NVIDIA 开发的一种深度学习模型优化器和运行时库,用于在 GPU 上部署神经网络模型,尤其是在 NVIDIA 的嵌入式平台 Jetson 上。

TVM

Apache TVM 是一个开源的机器学习编译器堆栈,旨在使机器学习模型在各种硬件平台上高效部署成为可能。TVM 支持从各种深度学习框架中获取模型输入,包括 TensorFlow、Keras、PyTorch、ONNX 以及其他框架。

这些只是优化机器学习模型以便在边缘运行的一些工具。随着新型技术设备的不断涌现,边缘优化是一个活跃的研究领域,新的工具和机制仍在不断开发中。

在本章所附的 Jupyter Notebook 的动手活动中,我们使用了 TensorFlow Lite 来优化我们的模型,之后我们将优化后的模型存储在 Google Cloud Storage 中。从那里,我们可以轻松地将我们的模型部署到任何支持 TensorFlow Lite 解释器的设备。TensorFlow Lite 文档中提供了一份支持平台列表,其中还包含大量关于 TensorFlow Lite 如何在更详细层面工作的有用信息:www.tensorflow.org/lite/guide/inference#supported_platforms

到目前为止,我们已经涵盖了与模型部署相关的许多不同主题。让我们花些时间回顾一下我们学到了什么。

摘要

在本章中,我们讨论了各种用于托管机器学习模型的 Google Cloud 服务,例如 Vertex AI、Cloud Functions、GKE 和 Cloud Run。我们区分了在线和离线模型服务,其中在线服务用于实时预测,而离线服务用于批量预测。然后,我们探讨了部署机器学习模型时常见的挑战,例如数据/模型漂移、扩展、监控、性能以及保持模型更新。我们还介绍了 Vertex AI 的特定组件,这些组件使我们的模型部署和管理更加容易,例如 Vertex AI 模型注册表、Vertex AI 预测服务和 Vertex AI 模型监控。

具体来说,我们深入探讨了生产环境中监控模型,重点关注数据漂移和模型漂移。我们讨论了对抗这些漂移的机制,例如自动连续训练。

接下来,我们解释了 A/B 测试,用于比较模型的两个版本,并讨论了使用模型剪枝和量化等方法优化边缘部署的机器学习模型,以及用于优化我们的模型的库和工具,例如 TensorFlow Lite。

到目前为止,我们已经涵盖了 MDLC 中的所有主要步骤。我们接下来关注的主题将是如何使用 MLOps 自动化整个生命周期。请加入我们,在下一章中,你将继续你的旅程,成为一名专家 AI/ML 解决方案架构师,在这个过程中你已经走了很长的路,并且取得了巨大的进步!

第十一章:使用 Google Cloud 进行机器学习工程和 MLOps

通常估计,几乎 90% 的数据科学项目从未进入生产阶段。数据科学家在实验室花费大量时间训练和实验模型,但往往无法成功地将这些工作负载带入现实世界。主要原因是我们已经在本书的前几章中讨论过,在模型开发生命周期中的每一步都存在困难挑战。继我们上一章的内容之后,我们现在将更详细地探讨部署概念和挑战,并描述 机器学习运维MLOps)在解决这些针对大规模生产 AI/ML 工作负载的挑战中的重要性。

具体来说,本章将涵盖以下主题:

  • MLOps 简介

  • 为什么需要 MLOps 来部署大规模机器学习工作负载

  • MLOps 工具

  • 在 Google Cloud 上使用 Vertex AI Pipelines 实施 MLOps

尽管我们已经在本书的早期部分触及了一些这些概念,但我们将以对 MLOps 的更正式介绍开始本章。

MLOps 简介

MLOps 是软件开发行业 DevOps 概念的扩展,但专注于管理和自动化机器学习模型和项目生命周期。它超越了创建机器学习模型所需的战术步骤,并解决了当公司需要以规模管理数据科学用例的整个生命周期时出现的需求。现在是一个反思我们在本书前几章中概述的机器学习模型生命周期阶段的好时机,如图 图 11.1 所示。

图 11.1:数据科学生命周期阶段

图 11.1:数据科学生命周期阶段

从高层次来看,MLOps 的目标是自动化机器学习模型生命周期的所有各种步骤,例如数据收集、数据清洗和预处理、模型训练、模型评估、模型部署和模型监控。因此,它可以被视为一种旨在统一机器学习系统开发和日常运营的工程文化。这包括在机器学习项目中所有相关利益相关者之间的协作和沟通实践,例如公司的数据科学家、机器学习工程师、数据工程师、业务分析师和运营人员,以帮助持续管理整个机器学习生命周期。

在这个背景下,管理机器学习生命周期包括定义、实施、测试、部署、监控和管理机器学习模型,以确保它们在生产环境中可靠且高效地运行。

与 DevOps 的另一个相似之处在于,MLOps 实践也涵盖了持续集成、持续交付和持续部署(CI/CD)的概念,但重点在于如何开发机器学习模型。这确保了模型的新更改被正确集成、彻底测试,并且可以以系统化、可靠和可重复的方式部署到生产环境中。在这方面,目标是确保机器学习生命周期的任何部分(如数据预处理、训练等)都可以在以后以相同的结果重复。正如在软件 DevOps 的 CI/CD 环境中一样,这包括自动化步骤,如验证检查和集成测试,但在机器学习模型开发的情况下,它还增加了额外的组件,例如数据质量检查和模型质量评估。

正如我们在前面的章节中讨论的那样,将模型部署到生产环境是一项巨大的成就,但工作并没有就此结束。一旦机器学习模型被部署到生产环境中,就需要持续监控它们,以确保由于底层数据或其他因素的变化,其性能不会随时间退化。如果检测到任何问题,模型需要更新或用更新的模型替换。MLOps 还包括自动化该过程的工具,例如自动重新训练(例如,使用新鲜数据)、验证和部署新的模型版本。

这其中的另一个重要组成部分是跟踪我们在数据科学项目各个阶段产生的各种工件版本(例如,数据、模型和超参数值)。这不仅使得在需要时可以轻松回滚到以前的版本,而且还提供了合规性审计跟踪,有助于模型的可解释性和透明度,以及适当的治理机制,有助于确保机器学习模型被负责任和道德地使用。

现在我们已经了解了 MLOps 是什么,让我们更深入地探讨为什么它在开发、部署和管理大规模模型时尤为重要。

注意

在本书的后续部分,我们将讨论生成式人工智能/机器学习。在生成式人工智能/机器学习中,有一些特定的机器学习模型被用于其中,被称为大型语言模型LLMs)。这些模型还与一些额外的资源和工件相关联,并且行业中出现了一个新术语 LLMOps,用来指代这些工作负载的运营化。目前,我们将专注于传统的 MLOps。虽然许多这些概念也适用于 LLMOps 工作负载,但我们将在后面的章节中讨论 LLMOps 的额外考虑因素。

为什么需要 MLOps 来部署大规模机器学习工作负载

MLOps 最重要的方面是它帮助组织以更快、更高效和更可靠的方式开发机器学习模型,并允许数据科学团队在满足运营要求的同时进行实验和创新。

到现在为止,我们知道机器学习已经成为许多行业和部门的必要组成部分,提供了宝贵的见解和决策能力,但部署机器学习模型,尤其是在大规模上,面临着许多挑战。其中一些挑战只能通过 MLOps 来解决,我们将在本节中深入探讨这些挑战,并提供 MLOps 如何帮助解决这些挑战的例子。

在我们深入探讨之前,我要指出,本节中我们将讨论的这类挑战实际上适用于任何大规模生产产品的行业,无论这些产品是汽车、安全别针、玩具还是机器学习模型。

我将从一个汽车行业的类比入手,以突出大规模生产任何类型产品所需的概念。考虑在汽车发明之前,主要的交通工具可能是马车,而这种马车可能是在类似图 11.2中展示的工坊中制造的。

图 11.2:锻造车间(来源:https://www.hippopx.com/en/middle-ages-forge-workshop-old-castle-wagon-wheel-297217)

图 11.2:锻造车间(来源:https://www.hippopx.com/en/middle-ages-forge-workshop-old-castle-wagon-wheel-297217)

注意图 11.2中展示的生产环境的特征:

  • 这是一个小环境,只能容纳少数人一起工作。

  • 在这里工作的每个人周围都散落着许多随机工具,似乎并没有实施太多的标准化。

具有这些特征,任何类型的大规模协作都是不可能的,最多只能有三四个人一起工作来创造产品。在这种情况下,公司不可能每个月都生产大量产品(例如)。记住,大多数公司就是这样开始实施数据科学项目的,数据科学家在自己的电脑上执行各种实验并开发模型,使用基于个人偏好的任何随机工具,并试图以非标准化和非系统化的方式与同事分享学习和成果。

为了克服这些挑战,汽车行业发明了流水线的概念,一些最早的流水线可能看起来与图 11.3中展示的相似。

图 11.3:流水线(来源:https://pxhere.com/en/photo/798929)

图 11.3:流水线(来源:https://pxhere.com/en/photo/798929)

注意图 11.3中展示的生产环境的特征:

  • 环境可以容纳很多人一起工作。

  • 工具和制造工艺已经标准化。

这种环境能够实现大规模协作,并且在任何给定的时间框架内可以生产出更多的产品。

随着汽车公司继续发展,它们继续将标准化和自动化应用于流程的每个步骤,从而提高了流程的效率和可重复性,直到今天的装配线看起来就像图 11**.4中所示的那样。

图 11.4:现代装配线(来源:https://www.rawpixel.com/image/12417375/photo-image-technology-factory-green)

图 11.4:现代装配线(来源:https://www.rawpixel.com/image/12417375/photo-image-technology-factory-green)

正如我们在图 11**.4中可以看到的,生产过程已经变得高度自动化,并且在大规模操作上更加高效。带着这个类比,让我们看看这个想法如何映射到机器学习模型开发生命周期的概念和步骤。

模型管理和版本控制

随着组织扩大其机器学习努力,正在运行中的模型数量可以呈指数增长。管理这些模型、跟踪它们的版本以及知道何时更新或淘汰它们可能变得相当困难。如果没有适当的版本控制和管理系统,机器学习模型及其相应的数据集可能会变得混乱,这会导致模型开发过程中的混淆和错误。事实上,当我们想到许多大型公司有数百甚至数千个模型在生产中,并且不断开发这些模型的新版本以改进其性能时,没有专业工具管理所有这些模型基本上是不可能的。MLOps 工具提供了促进更轻松模型管理和版本控制的机制,使团队能够以有组织和高效的方式跟踪和控制他们的模型。

生产力和自动化

训练、测试、部署和重新训练模型通常涉及许多重复性任务,随着机器学习工作负载规模的增加,手动管理这些过程所需的时间和精力可能会变得难以承受。考虑到 MLOps 在机器学习生命周期的各个阶段引入了自动化,例如数据预处理、模型训练、测试、部署和监控,这使得数据科学团队能够专注于更有价值的任务。自动化的重要方面之一是它减少了人为错误的可能性,这有助于避免影响业务的错误,并提高生产力。

可重复性

可重现性可以说是任何大规模生产产品的行业中最重要的因素之一。想象一下,每次你尝试从一家公司购买相同的产品时,你都会收到一些略有不同的事物。很可能会失去对该公司的信任,并停止购买他们的产品。如果没有在生产过程中建立良好的可重现性,公司根本无法实现规模化。在机器学习的背景下,当我们拥有大量模型和数据集,以及不同类型的开发环境时,确保实验的可重现性可能是一个重大的挑战。由于数据、模型和代码缺乏版本控制,可能很难重现之前实验的精确条件。这可能导致结果不一致,并使基于先前工作的构建变得困难。MLOps 框架提供了维护所有实验记录的工具和实践,包括使用的数据、设置的参数、模型架构和结果。这使得实验可以轻松重复、比较和审计。

持续集成/持续部署(CI/CD)

我们应该注意的是,CI/CD 是 DevOps 的一个如此重要的组成部分,以至于这两个术语经常几乎可以互换使用。

更有趣的是,我们还可以在标准的 DevOps CI/CD 管道内管理 MLOps 管道。例如,当使用 Vertex AI Pipelines 时,我们可以使用代码定义我们的管道,并将该代码存储在代码仓库中,如 Google Cloud Source Repositories,然后通过 Google Cloud Build 中的 DevOps CI/CD 管道进行管理。这使得我们可以将 DevOps 的所有好处,如代码版本控制和自动化测试,应用于定义我们管道的代码,从而控制对管道定义的更新方式。

模型验证和测试

由于机器学习模型的概率性质,测试机器学习模型涉及独特的挑战,传统的 DevOps 软件测试技术可能不足以应对。MLOps 引入了专门用于自动化验证和测试 ML 模型的实践和方法,确保在部署到生产之前,它们的表现符合预期,并在部署后的整个生产生命周期中保持如此。此外,能够可靠地重现产品,在大规模开发产品时也要求能够随着时间的推移逐步改进产品。CI/CD 管道自动化了模型的测试和部署,确保新更改能够无缝、高效地集成和部署,并尽可能减少错误。这使得数据科学家能够快速、轻松、以符合公司要求标准的方式实验和尝试不同的更新。

监控和维护

正如我们讨论的,一旦 ML 模型部署,它们的性能需要持续监控,以确保它们始终提供准确的预测。我们也讨论了现实世界数据的变化如何导致模型性能随时间下降,因此,我们需要工具和流程来进行持续监控和警报,使团队能够快速响应任何性能下降,并在必要时重新训练模型。这是任何 MLOps 框架的重要组件。

协作与沟通

随着 ML 项目的扩展,它们通常需要跨各种团队和角色进行协作,包括数据科学家、ML 工程师、数据工程师、业务分析师和 IT 运维人员。在许多组织中,开发 ML 模型的数据科学家和在生产中部署和维护这些模型的 IT 运维团队之间存在差距。没有共同的平台和标准实践,不同的团队成员可能会使用不一致的方法、工具和数据,导致工作流程低效和潜在的错误。MLOps 促进了这些利益相关者之间的有效协作和沟通,使他们能够更有效地合作,避免误解或错位。

监管合规与治理

在医疗保健和金融等行业,ML 模型必须符合特定的监管要求。MLOps 提供了确保模型透明度、可解释性和可审计性的机制,因此有助于维护监管合规。此外,没有 MLOps,跨不同团队和业务单元管理多个模型可能会成为一个挑战。MLOps 允许集中式模型治理,这使得跟踪各种模型的表现、状态和所有者变得更加容易。

既然我们已经深入探讨了为什么 MLOps 是必要的,尤其是在管理大规模 ML 工作负载的背景下,让我们来看看行业内为实施这些概念而开发的一些流行工具。

MLOps 工具

到目前为止,我们已经讨论了 MLOps 的目标和好处,但在现实世界中我们如何实现这些目标和好处呢?许多工具已经开发出来,以促进 MLOps 的各个方面,从数据版本化到模型部署和监控。在本节中,我们讨论使 MLOps 成为现实的具体工具。

管道编排工具

当我们想要标准化流程中的步骤并自动运行它们时,我们通常将它们配置为一系列顺序动作。这个顺序动作集通常被称为管道。然而,仅仅配置步骤的顺序是不够的;我们还需要某种类型的系统来“编排”(即执行和管理)管道,我们可以使用一些流行的流程编排工具来完成这个任务,例如 Kubeflow、Airflow 和TensorFlow ExtendedTFX)。我们已经在第六章中介绍了 Airflow,但让我们更详细地看看 Kubeflow 和 TFX。

Kubeflow

这是一个由谷歌创建的开源项目,现在由一个开源贡献者社区维护,旨在使在 Kubernetes 上运行机器学习工作流程更加容易。Kubeflow 的基本原则包括可移植性、可扩展性和可扩展性。可移植性指的是“一次编写,到处运行”的概念,这是基于容器化的核心原则,即您可以在不同的计算环境中以一致的方式运行您的作业。可扩展性指的是使用 Kubernetes 轻松扩展您的模型训练和预测工作负载的能力,而可扩展性意味着您可以通过添加与 Kubeflow 轻松集成的流行工具和库来实现定制化用例。在这种情况下,Kubeflow 不仅仅是一个工具,而是一个框架和生态系统,我们可以用它来编排和管理我们的机器学习工作流程。以下是 Kubeflow 生态系统的一些核心组件:

  • Kubeflow PipelinesKFP):用于定义、部署和管理机器学习工作流程

  • Katib:用于超参数调整

  • KFServing:用于以可扩展的方式提供模型

  • TensorFlow 和 PyTorch 操作符:用于运行 TensorFlow 和 PyTorch 作业

  • 训练操作符:用于分布式训练

在本章相关的实践练习中,我们将特别深入探讨 Kubeflow Pipelines,我们将构建一个管道并在 Google Cloud Vertex AI 中执行它。除了 KFP 之外,Vertex AI 还支持使用 TFX 来构建和管理机器学习管道。让我们看看下一个。

TensorFlow Extended(TFX)

TFX 是一个端到端平台,也是由谷歌创建的,用于管理和部署生产级机器学习流水线。正如其名所示,它被设计为 TensorFlow 的扩展,旨在使将训练好的模型投入生产变得更加容易。就像 KFP 一样,TFX 提供了实现机器学习生命周期每个阶段的组件,涵盖了从数据摄取和验证到模型训练、调优、服务以及监控的各个方面。同样,TFX 的核心原则包括可扩展性和当然的扩展性。TFX 的其他核心原则还包括可重复性和模块化。可重复性,正如我们在本章前面讨论的,是大规模生产几乎所有内容的关键要求。在这个上下文中,模块化指的是 TFX 的各个组件可以单独使用或组合使用,从而实现定制化。说到这里,TFX 的各个组件和职责包括以下内容:

  • ExampleGen,将数据导入 TFX 流水线

  • StatisticsGen,计算导入数据的统计信息,这对于理解数据和特征工程至关重要

  • SchemaGen,检查数据集统计信息并为数据集创建模式

  • ExampleValidator,用于识别和分析数据集中的异常值和缺失值

  • Transform,可用于在数据集上进行特征工程

  • Trainer,使用 TensorFlow 定义和训练模型

  • Tuner,可用于使用 Keras Tuner 优化超参数

  • InfraValidator,确保模型可以在生产环境中加载和提供服务

  • Evaluator,使用 TensorFlow 模型分析库评估训练模型的指标

  • BulkInferrer,对模型进行批量处理

  • 祝福和部署:如果模型经过验证,它可以被“祝福”,然后使用如 TensorFlow Serving 之类的服务基础设施进行部署。

考虑到 TFX 和 KFP 都可以用于在 Google Cloud Vertex AI 中构建和运行流水线,选择使用哪一个可能会有些挑战。关于这个问题,官方的 Google Cloud 文档建议如下:

“如果你在处理 TB 级结构化数据或文本数据的 ML 工作流中使用 TensorFlow,我们建议你使用 TFX 构建你的流水线……对于其他用例,我们建议你使用 Kubeflow 的 Pipelines SDK 构建你的流水线。”

我们在本章中不会过多地关注 TFX 的细节,但如果你想了解如何构建 TFX 流水线,TensorFlow 文档中有一个有用的教程,链接如下:www.tensorflow.org/tfx/tutorials/tfx/gcp/vertex_pipelines_simple

此外,还有许多其他开源工具可用于实现 MLOps 流程,例如 MLFlow,它提供了跟踪实验、将代码打包成可重复运行以及共享和部署模型的接口。

虽然 KFP 和 TFX 可以用来编排您的整个 MLOps 流程,但也有专注于 ML 生命周期更具体组件的工具,并且可以与 KFP 和 TFX 集成,以便定制您的整体流程。接下来,让我们看看这些工具中的一些。

实验和谱系跟踪工具

正如我们在本章以及前几章中讨论的那样,在运行大规模 ML 工作负载时,跟踪每个模型的每个开发步骤非常重要,这样您就可以轻松理解任何给定模型是如何创建的。这对于可重复性、可解释性和合规性等特性是必需的。想象一下,如果您有数千个模型在生产中运行,合规监管机构要求您解释某个特定模型是如何创建的。如果没有一个良好的系统来跟踪每个模型的每个创建方面的详细信息,例如用于训练模型的数据集版本、使用了哪些类型的算法和超参数、初始评估指标是什么,以及谁将模型部署到生产中,这将是一项不可能完成的任务。这就是实验和谱系跟踪工具发挥作用的地方。让我们考虑一下在这方面我们有哪些工具可以利用。

Vertex AI 实验服务

Vertex AI 实验服务是一个托管服务,帮助您跟踪、比较和分析您的机器学习实验。它提供了一个集中管理实验的地方,并使得比较不同的模型和超参数变得容易。一旦创建了一个实验(使用 Vertex AI SDK 或 Vertex AI 用户界面),您就可以开始跟踪您的训练运行,Vertex AI 实验服务将自动收集训练运行中的指标,如准确率、损失和训练时间。

一旦训练运行完成,您可以查看指标图和表格,并可以使用统计测试来确定哪个模型是最好的。您还可以使用实验仪表板来可视化您的结果,并可以使用实验 API 将结果导出到电子表格或笔记本中。

TensorBoard

TensorBoard 是 TensorFlow 附带的一个基于网页的工具,旨在帮助可视化和理解机器学习模型,以及调试和优化它们。它为机器学习模型和训练过程的各个方面提供了一个交互式界面,并可以轻松创建如我们在前几章中介绍的 ROC 曲线等指标图。

模型部署和监控工具

在这个背景下,我们有 Vertex AI Prediction 和 Model Monitoring 等工具,我们在第十章中对其进行了详细审查。还有像TensorFlow Serving(简称TFServing)这样的开源工具,用于 TensorFlow 模型,以及 TorchServe。

模型可解释性和可解释性工具

如我们之前所讨论的,模型可解释性和可解释性是机器学习中的极其重要的概念。它们与可重复性、合规性和性能相关。例如,如果你对你的模型工作原理没有很好的理解,那么在系统性地持续改进它们时将会更加困难。这些概念也与公平性相关。也就是说,为了确保模型做出公平和道德的预测,你需要详细了解其工作原理。幸运的是,有一些工具可以帮助我们在这方面,我们在这里讨论这些工具。

Google Cloud Vertex AI 提供了诸如可解释 AI 和公平性指标等工具,这些工具可以帮助我们了解我们的机器学习模型是如何工作的,以及它们在不同条件下会如何表现。还有像SHAP(代表SHapley Additive exPlanations)这样的开源工具,它使用博弈论方法来解释任何机器学习模型的输出,以及LIME(代表Local Interpretable Model-agnostic Explanations),这是一个 Python 库,允许我们解释任何机器学习分类器的预测。

本书下一章将致力于介绍偏差、公平性、可解释性和谱系等概念,因此我们将更详细地探讨这些概念和工具。

现在我们已经介绍了许多可以用于实现 MLOps 工作负载的不同类型的工具,让我们深入探讨如何在 Google Cloud Vertex AI 上具体实现这一点。

使用 Vertex AI Pipelines 在 Google Cloud 上实现 MLOps

在本节中,我们将介绍在 Google Cloud 上使用 Vertex AI Pipelines 构建 MLOps 管道的步骤。

前提条件:IAM 权限

在本节中,我们将使用我们在第五章中创建的相同的 Vertex AI Workbench 笔记本实例。该用户管理的笔记本使用默认的 Compute Engine 服务账户,该账户默认被授予 IAM 基本编辑器角色。当我们在我们笔记本中构建和执行我们的管道时,我们决定让我们的管道继承笔记本使用的相同权限。这是通过不指定不同角色给我们的管道执行所做的决定。如果我们想的话,我们可以指定不同的角色,但为了简单起见,我们将采用让我们的管道使用默认 Compute Engine 服务账户的方法。默认情况下,编辑器角色(默认 Compute Engine 服务账户使用的角色)将允许我们在本章的 Vertex AI 中执行所有必需的活动,但我们的管道还需要在 Dataproc 上运行一些步骤。因此,我们将 Dataproc Worker 和 Dataproc 编辑器角色添加到默认 Compute Engine 服务账户中。为此,执行以下步骤:

  1. 在 Google Cloud 控制台中,导航到Google Cloud 服务IAM & AdminIAM

  2. 在主体列表中,点击默认 Compute Engine 服务账户的铅笔符号(服务账户名称将具有格式-[项目编号]-compute@developer.gserviceaccount.com;参见图 11**.5以供参考)。

图 11.5:编辑服务账户

图 11.5:编辑服务账户

  1. 在出现的屏幕上,选择Dataproc,并从角色列表中选择Dataproc 编辑器

  2. 重复步骤 3,并选择Dataproc Worker

  3. 更新后的角色将如图图 11**.6所示。

图 11.6:更新后的角色

图 11.6:更新后的角色

  1. 点击保存

就这样——你已经成功添加了所需的角色。

实现

如前节所述,我们可以使用我们在第五章中创建的相同的 Vertex AI Workbench 笔记本实例来构建我们的 MLOps 管道。请在该笔记本实例上打开 JupyterLab。在屏幕左侧的目录浏览器中,导航到Chapter-11目录并打开mlops.ipynb笔记本。您可以选择Python (Local)作为内核。同样,您可以通过选择单元格并在键盘上按Shift + Enter来运行笔记本中的每个单元格。除了相关代码外,笔记本还包含描述代码正在做什么的 Markdown 文本。

在实际练习中,我们将构建并运行一个 MLOps 管道,该管道将执行我们在本书中迄今为止所涵盖的 ML 模型开发生命周期的所有阶段。我们的管道如图图 11**.5所示。

图 11.7:Vertex AI 管道

图 11.7:Vertex AI 管道

在高层次上,我们的管道将执行以下步骤:

  1. 数据采集:首先,我们需要将我们的数据导入 Google Cloud 环境。我们使用 Google Cloud Storage 来存储我们的数据,当我们的流程启动数据处理和模型训练作业时,我们的数据将从那里读取。

  2. 预处理我们的数据:Google Cloud 提供了多种数据预处理工具,包括 Dataflow、Dataprep 和 Dataproc,我们已在 第六章 中进行了探讨。最近,Google Cloud 还发布了一项名为 Serverless Spark 的服务,它使我们能够在不配置和管理所需的基础设施的情况下运行 Spark 作业。这就是我们在实际练习中在流程中实现数据预处理作业所使用的工具。

  3. 开发和训练我们的模型:我们的流程在 Vertex AI 中使用前一步创建的已处理数据训练 TensorFlow 模型。

  4. 在 Vertex AI 模型注册表中注册我们的模型。

  5. 部署我们的模型:我们的流程进入下一步,即将我们的模型部署到生产环境中。在这种情况下,我们的流程创建一个 Vertex AI 端点,并在该端点上托管我们的模型。

让我们通过检查我们刚刚创建的解决方案架构来更详细地了解我们的流程正在做什么,如图 图 11.6 所示。

图 11.8:Vertex AI 中的 MLOps 流程

图 11.8:Vertex AI 中的 MLOps 流程

图 11.6 中,横跨整个图的水平矩形部分代表我们在 Vertex AI Pipelines 中运行的流程。流程中的每个步骤都进行了编号,编号代表以下操作:

  1. 我们流程中的数据处理步骤向 Dataproc Serverless 提交一个 Spark 作业以执行我们的 PySpark 处理脚本。

  2. Dataproc 从 Google Cloud Storage 获取我们的 PySpark 脚本和原始数据,并执行 PySpark 脚本来处理原始数据。

  3. Dataproc 将处理后的数据存储在 Google Cloud Storage 中。

  4. 数据处理作业状态已完成。

  5. 流程中的下一步——模型训练步骤——被调用。

  6. Vertex AI Pipelines 向 Vertex AI 训练服务提交一个模型训练作业。

  7. 为了执行我们的自定义训练作业,Vertex AI 训练服务从 Google Artifact Registry 获取我们的自定义 Docker 容器,并从 Google Cloud Storage 获取训练数据。这些数据就是我们的数据处理作业存储在 Google Cloud Storage 中的数据(即,这是由我们的数据处理作业创建的已处理数据)。

  8. 当我们的模型训练完成后,训练好的模型工件被保存在 Google Cloud Storage 中。

  9. 模型训练作业状态已完成。

  10. 我们管道的下一步——模型导入步骤——被调用。这是一个中间步骤,为我们的管道的后续组件准备模型元数据。在这种情况下,相关的元数据包括模型工件在 Google Cloud Storage 中的位置以及用于提供我们模型的 Docker 容器镜像在 Google Artifact Registry 中的规范。

  11. 我们管道的下一步——模型上传步骤——被调用。此步骤引用了模型导入步骤中的元数据。

  12. 模型元数据用于在 Vertex AI 模型注册表中注册模型。这使得在 Vertex AI 中部署我们的模型以处理流量变得容易。

  13. 模型上传作业状态已完成。

  14. 我们管道的下一步——端点创建步骤——被调用。

  15. 在 Vertex AI 预测服务中创建了一个端点。这个端点将用于托管我们的模型。

  16. 端点创建作业状态已完成。

  17. 我们管道的下一步——模型部署步骤——被调用。

  18. 我们的模式已部署到 Vertex AI 预测服务中的端点。此步骤引用了由我们的管道刚刚创建的端点的元数据,以及 Vertex AI 模型注册表中我们的模型的元数据。

  19. 模型部署作业状态已完成。

除了我们管道明确执行的上述所有步骤之外,Vertex AI Pipelines 服务还将在 Vertex ML Metadata 服务中注册与我们的管道执行相关的元数据。

我们的模式现在已准备好处理推理请求!是不是很令人印象深刻,所有这些跨越多个 Google Cloud 服务的活动和 API 调用都是由我们的管道自动编排的?在我们定义了管道之后,它可以在我们希望的时候自动运行,在整个过程中不需要任何人工交互,除非我们认为有必要让人类参与任何步骤。

如果你已经完成了笔记本中的活动,那么你现在正式成为 AI/ML 大师!说真的,你刚刚实现了一个端到端的 MLOps 管道。这是 ML 行业中的一个极其复杂和高级的任务。

在取得所有这些成功之后,让我们花些时间来反思我们在本章中学到了什么。

摘要

在本章中,我们从高层次介绍了 MLOps,这基本上是机器学习、DevOps 和数据工程的结合,其主要目标是自动化 ML 生命周期,从而改善工作流程和科学家与工程师之间的协作。我们讨论了 MLOps 如何使组织简化其 ML 操作,加快部署速度,并在生产中保持高质量模型,从而实现更高效、有效和可靠的 ML 工作流程,并最大限度地提高组织从其 ML 项目中获得的价值。

我们讨论了 MLOps 解决的各种痛点,包括但不限于与管理和版本控制模型、确保可重复性和一致性、监控和维护模型以及促进不同团队间协作相关的挑战。

然后,我们深入探讨了为什么 MLOps 对于部署大规模机器学习工作负载至关重要。它解决了机器学习系统中可能出现的一系列挑战,从管理和版本控制模型到确保实验的可重复性。它还促进了模型的持续集成、部署、监控和验证,并促进了团队间的更好协作。

然后,我们讨论了各种 MLOps 工具,如 Kubeflow Pipelines 和 TensorFlow Extended 等。这些工具中的每一个都提供独特的功能,满足 ML 生命周期不同阶段的需求,包括数据版本控制、实验跟踪和模型部署。

然后,我们使用 Google Cloud 上的 Vertex AI Pipelines 实现了 MLOps,这涉及多个步骤,包括管理数据集、预处理数据、训练模型和监控模型。

接下来,我们将探讨机器学习行业中的四个重要且相互关联的主题,即偏差、可解释性、公平性和溯源。让我们进入下一章,详细探讨这些概念。

第十二章:偏差、可解释性、公平性和血统

现在我们已经学习了在谷歌云中构建和部署模型以及自动化整个机器学习(ML)模型开发生命周期的所有步骤,现在是时候深入探讨更多对开发和维护高质量模型至关重要的高级概念了。

除了确保我们的模型为特定用例提供尽可能准确的预测外,我们还需要确保模型提供的预测尽可能公平,并且它们不会对任何个人或人口群体表现出偏见或歧视。

偏差、公平性和可解释性是当前机器学习研究的前沿话题。本章详细讨论了这些概念,并解释了如何有效地将这些概念融入我们的机器学习工作中。具体来说,本章将涵盖以下主题:

  • 人工智能/机器学习(AI/ML)中偏差、公平性和可解释性的概述

  • 如何检测和减轻数据集中的偏差

  • 利用可解释性来理解机器学习模型并减少偏差

  • 在机器学习模型开发中追踪血统的重要性

让我们从定义和描述相关概念开始。

人工智能/机器学习中的偏差、可解释性和公平性的概述

虽然“偏差”、“可解释性”和“公平性”这些术语并不特指机器学习(ML),在本节中,我们将探讨这些术语在机器学习模型开发和应用中的具体应用。

偏差

人工智能/机器学习中的偏差指的是数据和分析算法中的倾向或偏见,可能导致不公平的结果。机器学习模型开发中最常见的偏差来源之一是训练数据中存在偏差;例如,当训练数据中的数据点没有公平地代表模型预测将服务的现实或人群时,我们称之为数据偏差。例如,使用一个数据集,其中数据点主要代表只有一个特定的人口群体来训练模型,当模型需要根据代表其他人口群体的数据点进行预测时,可能会导致性能较差。更具体地说,这是一个被称为抽样偏差的例子。为了将这个概念与现实世界联系起来,让我们想象我们正在训练一个进行面部识别的模型。如果我们用来自一个特定人口群体的主要图像来训练这个模型,那么当模型后来遇到来自其他人口群体的图像时,它可能无法很好地执行面部识别任务。在开发和使用机器学习模型的过程中,我们可能会遇到多种不同的偏差,我们将在以下段落中概述。

收集或测量偏差

数据偏差的主要原因在于数据收集或测量的方式。有时,偏差可能由于我们测量或构建问题的方式而产生,这可能无法正确代表我们试图测量的基本概念。例如,让我们想象我们拥有一家小型公司,我们希望扩大我们的产品种类以吸引新客户。我们可能会决定使用调查来收集数据,以训练机器学习模型来预测我们应该提供哪些类型的新产品,基于这些新产品可能受欢迎的程度。我们可以以多种方式分发这份调查,例如通过电子邮件或通过实体邮件。在电子邮件的情况下,我们可能会决定将调查发送给所有当前客户,因为我们很可能已经在数据库中拥有他们的电子邮件地址。在实体邮件的情况下,我们可能会决定向公司所在邮政编码、城市、州或国家内的所有人发送。

不幸的是,这两种方法可能会意外地将偏差引入我们用于训练模型的训练数据集中。例如,也许我们过去传统上只吸引特定类型的客户。如果我们以当前客户群作为调查组,我们可能无法获得对吸引新客户群体有吸引力的产品的良好数据点。同样,如果我们向特定地理区域内的所有人发送调查问卷,例如邮政编码、城市、州,甚至国家,该区域居住的人可能不代表多样化的人口群体,这可能会无意中引入偏差到最终的数据集中。这种现象有时被称为响应偏差,在这种情况下,提供所需信息的人可能在某些方面存在偏见,因此可能会提供有偏见的回答。更复杂的是,我们在调查中提出问题的方式可能会无意中影响受访者的回答。

在这种情况下,我们还需要意识到观察者偏差主观性,在这种情况下,进行调查的人可能在某些方面存在偏见。事实上,我们决定通过电子邮件向我们的当前客户发送,或向特定区域的人发送实体邮件的例子,是一种观察者偏差,其中我们根据当前可用的数据(例如,我们客户的电子邮件地址)或与我们公司位置的邻近性等因素决定调查特定的人群群体。

预先存在的偏差

这些通常是社会中已经存在的偏差。这种偏差可能源于文化、历史和社会规范等因素,包括根深蒂固的信念和实践,这些信念和实践塑造了个人看待世界的方式。

训练模型最常见的方法之一是使用已经记录的历史数据。然而,过去的数据可能受到那些时代固有的偏见的影响——我想我们都可以同意,20 世纪 50 年代或甚至 20 世纪 90 年代的社会规范与今天的标准有很大不同,特别是在不同人口群体之间的公平性方面。如果 AI/ML 模型在没有纠正的情况下使用这样的数据进行训练,它们很可能会持续这些偏见。重要的是要理解,未解决的预先存在的偏见不仅会持续,有时甚至还会放大刻板印象,导致不公平或歧视性的结果。例如,如果推荐系统在表现出这种偏见的历史数据上训练,它可能会倾向于向男性推荐更高薪酬的工作。

在这个背景下,另一种常见的偏见类型是确认偏见,其中人们可能无意识地倾向于选择和解释数据,以证实他们先前的信念。

如果数据收集过程没有检查预先存在的偏见,它们可能导致的数据并不能真正代表现实或它应该描绘的人群。在这样数据上训练的模型可能会在它们的预测或行动中学习并复制这些偏见。

算法偏见

这指的是由算法本身的设计引入的偏见,而不仅仅是它们训练的数据。考虑到算法在现代社会中用于实施越来越多的重要决策,如信用批准、招聘流程和医疗诊断,这是一个越来越重要的话题。

算法偏见可能更为微妙且难以检测。例如,这种偏见可能仅仅源于算法开发者本身。如果开发算法的团队缺乏多样性,可能无法预见或识别算法实施过程中的潜在偏见。我们还需要认识到在机器学习系统中意外开发有偏见的反馈循环的可能性。例如,在算法持续用新数据训练的系统,有偏见的输出可能会加强输入偏见,随着时间的推移,这可能导致结果越来越偏斜。

就像本节之前讨论的其他类型的偏见一样,未解决的算法偏见可能导致刻板印象、错误信息和不公平做法的持续。

需要注意的是,在本节中,我们只讨论了可能影响机器学习模型开发的一些最常见的偏见类型。这是一个活跃的研究领域,还存在一些我们可能没有明确意识到的其他类型的偏见,在我们开发和使用机器学习模型的过程中。

比喻来说,偏见的概念代表了一枚硬币的一面,而硬币的另一面是公平的概念,我们将在下一节中更详细地探讨。

公平性

在 AI 和机器学习(ML)中,公平性指的是以防止歧视和促进公平的方式开发算法。虽然公平性是一个相对直接的概念,例如平等对待所有人,但在实践中,它可能难以监控和维护。在本章稍后,我们将探讨监控和增强 ML 模型公平性的机制,但首先让我们在 ML 的背景下更详细地描述这一概念。正如前一个与偏差相关的部分,我们将讨论几种定义和衡量 ML 模型公平性的不同方法,这些方法将在以下小节中概述。

代表性公平性

这是防止 ML 模型开发中偏差的第一道防线,特别是在数据偏差方面。代表性公平性旨在确保用于模型训练和验证的数据包含了对结果模型预测将影响的各个不同人口群体的公平代表性;例如,确保性别和种族群体在数据集中得到公平的体现。

程序公平性

这涉及到确保数据收集、数据处理和算法开发的过程是公平的,不偏袒任何特定群体。在第十三章*中,我们将详细讨论治理的概念,特别是与数据治理相关的内容,以及它在帮助确保数据集中潜在的偏差得到解决或减轻的重要作用。许多企业雇佣了整个团队或组织来制定和执行治理要求。在程序公平性的情况下,重点不在于数据的内容,而在于导致 ML 模型开发、部署和运行的过程的公平性。程序公平性的几个关键组成部分由TAIC框架表示,该框架包括以下内容:

  • 透明度,例如在整个模型生命周期中对方法、数据来源和做出的决策进行清晰的文档记录

  • 可问责性,意味着应明确谁对模型开发的各个阶段、部署和监控负责

  • 公平性,意味着程序不应偏袒或歧视任何个人或群体

  • 一致性,意味着用于开发模型的过程应以一致的方式可重复

Google Cloud Vertex AI 提供了帮助审计程序公平性的机制,我们将在本章的后续部分以及伴随本章的实践活动中更详细地探讨。

结果公平性

当代表示性公平主要关注用于训练机器学习模型的输入(即训练数据的内容)时,程序性公平则关注用于开发和部署机器学习模型的程序,结果公平,正如其名所示,关注机器学习模型产生的结果。具体来说,它旨在确保模型产生的结果公平,不会不成比例地使任何群体受益或受损。当然,衡量这种公平性的方法之一是监控模型做出的预测,以确定是否存在任何偏见。在本章中,我们将探讨一些可用于此目的的机制和指标。

正如我在上一节讨论偏见时提到的,机器学习中的偏见和公平性概念仍然是研究非常活跃和不断发展的领域。这就是为什么在实践中,公平性可能是一个复杂的话题,并且重要的是要理解,实现一种类型的公平性有时可能导致另一种类型的公平性受到侵犯。此外,被认为“公平”的东西可能取决于具体情境,可能在不同的社区之间以及随时间推移而有所不同。

现在我们已经介绍了定义偏见和公平性两面性的概念,下一步将介绍一个与这两个概念固有联系的课题,这被称为可解释性

可解释性

机器学习中的可解释性关注人类理解和解释机器学习模型输出产生的能力。这通常也被称为模型的可解释性。随着机器学习模型随着时间的推移变得越来越复杂,这些概念的重要性持续增长。例如,解释和解释简单线性回归模型的输出是如何产生的相对容易,因为我们有定义良好的数学公式来描述这个过程,例如 y = a + bx,其中 y(输出)是 x(输入)的线性变换。同样,对于决策树模型,我们可以逻辑上追踪通过树的决定路径。然而,当我们处理包含数百万甚至数十亿参数的大型神经网络NNs),并采用不同类型的架构和激活函数时,我们需要一些额外的工具来帮助我们理解这些模型是如何做出决定的,我们将在本章中探讨这些工具。

当我们在上一节讨论程序性公平时,我们谈到了透明度的重要性。可解释性与透明度的概念紧密相连,因为它旨在确保人们可以理解从给定模型中产生预测的过程。例如,如果我们拥有一家银行,并且我们的某个模型负责批准或拒绝信贷申请,我们希望彻底了解它是如何做出这些决定的。

我们可以就可解释性从全局可解释性的角度进行讨论,其中我们试图理解模型在所有输入实例上应用的一般逻辑以做出预测,或者从局部可解释性的角度进行讨论,这涉及到解释模型为何对特定实例做出了特定决策(例如,理解为什么某个特定客户的信用申请被拒绝)。

总的来说,可解释性对于建立对 AI 系统的信任、遵守法律要求以及确保人类能够有效地干预决策过程至关重要。

现在我们已经介绍并解释了整体概念,让我们开始深入探讨。本章的第一个深入探讨将是关于数据集中偏差的话题。

如何检测和减轻数据集中的偏差

在本节中,我们探讨如何检测数据集中的偏差,并且我们可以使用各种工具和方法来达到这个目的。实际上,我们已经在本书的前几章中介绍了一些这些工具,例如数据探索和可视化。

数据探索和可视化

当我们使用可视化来探索我们的数据集时,例如,直方图和散点图等图表可以帮助可视化不同人口群体之间的数据分布差异。同样,我们已经探讨了描述性统计,如均值、中位数、众数和方差,以了解我们数据集的内容。如果这些统计量在不同子组之间存在显著差异,这可能表明数据集中存在偏差。

用于检测特征之间依赖关系的特定工具

我们还希望测试数据集中特征之间的潜在相关性或依赖性,以便了解某些特征的值是否受到其他特征值的显著影响。虽然这通常是我们作为常规数据探索和特征工程的一部分要做的事情(也就是说,我们需要尽可能多地了解我们数据中的潜在模式),但在偏差和公平性的背景下,这变得更加重要,特别是在目标变量与性别或种族等受保护属性之间潜在联系方面。

有一些特定的工具可以检测特征之间的依赖关系,例如皮尔逊相关系数,它衡量数值变量之间的线性关系,或者卡方检验,它可以用来确定两个分类变量之间是否存在显著的关联。

包含模型预测结果的机制

除了上述方法之外,我们还可以使用超越仅检查数据集的机制,同时考虑模型的输出,这可以帮助我们将任何观察到的偏见追溯到训练数据和过程。例如,我们可以使用差异影响分析DIA)来比较不同组的有利结果比率,并衡量是否有任何特定组比其他组更有可能获得有利结果。让我们更详细地看看 DIA。

DIA

在 DIA 的情况下,我们通常根据某些受保护特征(如性别或种族)来识别所谓的特权组无特权组(也称为受保护组),并比较给定模型为这两个组提供的输出,以试图确定模型是否在针对这些组表现出偏向(正面或负面)。我们使用称为差异影响比率DIR)的指标来衡量这种差异,该指标由以下公式定义:

DIR=P(FUP)P(FP)

这里,<mml:math xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math">mml:miP</mml:mi><mml:mfenced separators="|">mml:mrowmml:miF</mml:mi>mml:miU</mml:mi>mml:miP</mml:mi></mml:mrow></mml:mfenced></mml:math>代表无特权组获得有利结果的可能性,而 P(FP)代表特权组获得有利结果的可能性。

DIR 值可以这样解释:

  • 当 DIR 等于 1 时,表示完美的公平性,两组以相同的比率获得有利结果

  • 当 DIR 大于 1 时,表示无特权组获得有利结果的可能性更高

  • 当 DIR 小于 1 时,表示无特权组获得有利结果的可能性较低

一个普遍接受的阈值是 DIR 值在 0.8 到 1.25 之间;超出这个范围的值通常表明潜在的差异****影响DI)。

注意,DIA 可以通过使用目标特征直接在数据集上执行,或者它可以使用输入特征和模型预测的组合。

在下一节中,我们将更详细地探讨机器学习中可解释性的概念,并探讨我们如何使用可解释性框架来检测和解决偏见。我们还将扩展本节中涉及的概念,并讨论它们与可解释性和公平性的关系。

使用可解释性来理解机器学习模型并减少偏见

在上一节中,我们以高层次介绍了可解释性的概念。本节将进一步探讨这个主题,介绍可用于在推理时深入了解机器学习模型工作的工具。

可解释性技术、方法和工具

让我们从探索一些流行的技术、方法和工具开始,这些工具可以帮助我们在机器学习中实现可解释性,我们将在以下小节中描述。

执行数据探索

到现在为止,希望已经清楚,理解用于训练我们模型的训练数据是解释模型如何做出决策的第一步之一,同时也是识别和对抗潜在偏差的第一道防线。

在本章相关的实际活动中,我们探讨了“成人人口普查收入”数据集(archive.ics.uci.edu/dataset/2/adult),该数据集已知在种族和性别方面存在不平衡。该数据集包含有关人们的信息,例如他们的种族、性别、所受教育和他们当前的年收入,年收入以“<=50K”(每年不超过 50,000 美元)或“>50K”(每年超过 50,000 美元)表示,当使用收入作为目标变量时,这创建了一个二元分类用例。

在探索这些数据时,我们可以提出以下问题:

  1. 特征值,如种族和性别,是否在一定程度上均匀或不均匀地表示?

  2. 是否存在某些特征值与该人收入之间的相关性?

我们可以通过使用数据可视化技术轻松地看到数据集中的不平衡。让我们看看一些例子。

按性别划分的收入分布

以下代码将向我们展示数据集中每个性别在两种不同的收入类别(即每年收入不超过 50,000 美元或超过 50,000 美元的人)中的分布情况。如果您想跟随我们即将审查的代码示例,可以打开本章附带的 Jupyter 笔记本。我们可以再次使用在第五章中创建的相同的 Vertex AI Workbench-Notebook 实例来完成此目的。请在笔记本实例上打开 JupyterLab。在屏幕左侧的目录浏览器中,导航到Chapter-12目录并打开bias-explainability.ipynb笔记本。您可以选择Python (Local)作为内核。同样,您可以通过选择单元格并按键盘上的Shift + Enter来运行笔记本中的每个单元格。除了相关代码外,笔记本还包含描述代码正在做什么的 markdown 文本:

plt.figure(figsize=(10, 6))
sns.countplot(x='income', hue='sex', data=adult_data)
plt.title('Income Distribution by Gender')
plt.show()

这将显示类似于图 12.1的图表:

图 12.1:按性别划分的收入分布

图 12.1:按性别划分的收入分布

图 12.1中,我们可以看到,总体而言,数据集中收入超过 50,000 美元的人比那些收入不超过 50,000 美元的人要多。我们还可以看到,每个组中的男性数量远超过女性数量。这也告诉我们整个数据集包含与男性相关的数据点比与女性相关的数据点要多。

按种族划分的收入分布

以下代码将向我们展示数据集中每个种族关于收入的分布:

plt.figure(figsize=(15, 8))
sns.countplot(x='income', hue='race', data=adult_data)
plt.title('Income Distribution by Race')
plt.show()

这将显示一个类似于图 12.2所示的图表:

图 12.2:按种族划分的收入分布

图 12.2:按种族划分的收入分布

图 12.2中,对于“<=50K”类别和“>50K”类别,我们可以看到,与任何其他种族相比,白人的数据点要多得多。这可以被视为数据集中的一种偏差。正如我们在本章前面所介绍的,这种偏差可能存在多个潜在原因,例如数据收集中的偏差,或者它可能由于地理位置等其他因素而发生。这个特定的数据集代表了特定地区的人口,这可以部分解释其明显倾向于特定种族的偏差。例如,如果数据是在亚洲收集的,那么它将包含比任何其他种族更多的亚洲人的数据点,或者如果它是在中非收集的,那么它将包含比任何其他种族更多的黑人的数据点。重要的是要注意数据中的任何不平衡,并确定它们可能如何影响机器学习模型的训练以及该模型旨在为谁服务。一般来说,如果数据集中的特征具有特定值的实例数量要高得多,那么机器学习模型的预测可能会以某种方式反映这一点。

在伴随本章的 Jupyter 笔记本中,我们还评估了数据中的其他类型分布,例如按性别划分的职业分布和按种族划分的教育分布。我鼓励您使用 Jupyter 笔记本来更详细地探索数据。现在,让我们继续并更详细地探讨实施 DIA。

实施 DIA

以下是我们用于在 Jupyter 笔记本中实施 DIA 的代码:

pivot_gender_income = adult_data.pivot_table(index='sex', 
    columns='income', values='age', aggfunc='count')
pivot_gender_income['rate'] = pivot_gender_income['>50K'] / (
    pivot_gender_income['>50K'] + pivot_gender_income['<=50K'])
DI = pivot_gender_income.loc['Female', 'rate'] / (
    pivot_gender_income.loc['Male', 'rate'])

代码首先创建了一个adult_data数据框的交叉表,按性别和收入分组,每个组中的人数为值。然后,它向交叉表添加了一个名为rate的新列,这是每个组中收入超过 50,000 美元的人的比例。最后,它通过将女性的比率除以男性的比率来计算 DI。

这是一个在已知包含性别不平衡的数据集上实施 DIA 的非常简单的例子。DIA 可能更加复杂,并且可能需要一些领域专业知识才能有效实施,具体取决于数据集的内容以及在该数据上训练的机器学习模型的目的功能。

接下来,让我们讨论特征重要性的主题。

特征重要性

特征重要性评估了每个特征对模型预测的影响。为了探讨这个概念,让我们想象我们有一个包含关于人们信息的数据集,数据集中的特征包括身高、年龄、眼睛颜色以及他们是否喜欢咖啡。我们想使用这些数据来训练一个模型,以预测每个人成为成功篮球运动员的可能性。你认为我们数据集中的任何输入特征可能比其他特征在影响结果方面更重要吗?身高在决定一个人是否可能成为成功的篮球运动员方面可能比眼睛颜色更重要或更不重要吗?年龄是一个重要因素吗?在这种情况下,我们通过一个简单的例子来描述特征重要性的概念。在现实中,我们可能正在处理包含数千个特征的数据库,而这些特征可能并不总是代表像身高、年龄和眼睛颜色这样容易解释的概念。因此,我们可以使用工具来帮助我们获得这些见解。以下小节描述了我们可以用于此目的的工具。

常见机器学习库中内置的特征重要性工具

feature_importances_ attribute to create a graph similar to that shown in *Figure 12**.3*:
feat_importances = pd.Series(clf.feature_importances_, 
    index=X.columns)
feat_importances.nlargest(10).plot(kind='barh')

图 12.3:特征重要性

图 12.3:特征重要性

图 12.3 中,我们可以看到诸如年龄每周小时数资本收益等特征似乎在预测收入方面非常重要。这些特征的影响是否对你来说直观易懂?

注意,特征重要性并不表示因果关系。仅仅因为一个特征被认为很重要,并不意味着它会导致目标变量发生变化;只是表示存在关联。

当我们在 Jupyter 笔记本中具体使用 scikit-learn 的feature_importances_属性时,其他流行的机器学习库也提供了类似的机制。例如,TensorFlow 的增强树(tf.estimator.BoostedTreesClassifiertf.estimator.BoostedTreesRegressor)也提供了feature_importances_属性来获取每个特征的重要性。同样,LightGBM 和 CatBoost 分别提供了feature_importances_get_feature_importance(),而 XGBoost 提供了plot_importance()函数用于可视化。

虽然feature_importances_和其他机器学习库中的类似机制非常有用,但我们还可以使用更高级的工具来评估特征重要性,我将在下文中描述。

局部依赖性图

部分依赖图PDPs)是用于理解输入特征(或一组输入特征)与模型预测结果之间关系的图形可视化。使用 PDPs,我们只改变一个特征的值,同时保持所有其他特征的值不变,以确定该特定特征的各个值如何影响预测。PDPs 也可以同时使用多个输入特征,这可以揭示多个特征之间的相互作用。还有 PDPs 的扩展形式,称为个体条件期望(ICE)图。虽然 PDPs 显示了特征对预测的平均影响,但 ICE 图显示了特征对单个实例预测的影响。

使用 PDPs,对于感兴趣特征的每个唯一值,都会执行以下高级步骤:

  1. 将数据集中每个实例的感兴趣特征设置为该值。

  2. 使用模型进行预测。

  3. 平均预测值。

  4. 将平均预测与特征的唯一值进行绘图。

以下代码使用 scikit-learn 的PartialDependenceDisplay属性创建并显示 PDP 图形:

features = ['age', 'hours-per-week']
PartialDependenceDisplay.from_estimator(clf, X, features)

此代码将生成一个类似于图 12.4所示的图形:

图 12.4: PDP

图 12.4:PDP

图 12.4所示的 PDP 中,模型似乎预测人们从大约 20 岁开始逐渐增加收入,直到他们达到大约 60 岁,之后他们的收入开始下降。这一点在一定程度上是直观的,因为 20 岁被认为是早期成年,人们通常在 60 多岁时退休。同样,模型预测每周工作更多小时可能会导致收入更高。

接下来,我们将讨论更高级的特征重要性和解释机制。

局部可解释模型无关解释

如我在本章前面提到的,一些模型比其他模型更容易解释和理解(因此更容易解释)。提供的例子包括线性回归模型和决策树,与具有数千、数百万甚至数十亿参数的大型神经网络(可能很快就会达到万亿!)相比!局部可解释模型无关解释LIME)利用这一事实,通过训练一个更简单、代理的模型,该模型比目标模型更容易解释。想法是,即使整体模型复杂且非线性,也可以通过一个更简单、可解释的模型很好地近似。

LIME 的内部工作原理相当复杂,如果您想深入了解该层面的细节,建议阅读原始论文(arXiv:1602.04938)。这类算法细节通常不是解决方案架构师活动所必需的,您只需了解 LIME 的用途,而不需要深入研究其内部工作的学术细节。那么,接下来,下面的代码提供了一个如何使用 LIME 的示例:

explainer = lime_tabular.LimeTabularExplainer(
    X_train.values, training_labels=y_train,
    feature_names=X.columns.tolist(), 
    class_names=['<=50K', '>50K'], 
    mode='classification')
exp = explainer.explain_instance(
    X_test.values[0], clf.predict_proba, 
    num_features=10)
exp.show_in_notebook()

代码将生成与图 12.5中所示类似的可视化效果:

图 12.5:LIME 输出

图 12.5:LIME 输出

图 12.5的顶部,我们看到模型对输入实例的预测。在这种情况下,由于这是一个二元分类问题,它显示了模型预测的类别,以及与该预测相关的概率分数。我们还看到一个表示各种特征对预测影响的水平条形图。每个条形代表一个特征及其影响。条形的长度表示影响的重要性,其方向(左或右)表示影响的方向(例如,指向“<=50K”或“>50K”类别)。每个条形都标有特征名称和一个小描述符,这表明该特征是如何针对特定实例进行量化的。这提供了关于该特定实例的特征值如何影响预测的明确指示。

需要强调的是,LIME 的解释是局部的。它们专门针对特定实例进行定制,展示了模型如何为该实例做出预测,而不是针对所有数据的通用规则。接下来,我们将探讨一种可以帮助解释局部和全局模型机制的机制,这可能是行业中最受欢迎的特征重要性和解释机制之一。

SHapley Additive exPlanations

Shapley Additive exPlanations (SHAP)通过使用称为Shapley 值的概念来帮助解释机器学习模型的预测。这些值来自被称为博弈论的数学领域,或者更具体地说,是合作博弈论,它们最初在 20 世纪 50 年代由 Lloyd Shapley 提出。博弈论的研究关注竞争性情况(称为“游戏”),其中一位玩家的选择结果取决于其他玩家的行为。合作博弈论是一个子分支,它关注玩家可以与其他玩家结盟或联盟,并作为一个团队共同努力,使联盟整体受益,而不仅仅是关注自己的利益。

进一步深入,让我们想象一个赢家将获得 100 美元奖金的游戏。人们可以单独玩游戏,在这种情况下,如果他们赢了,个人将直接获得 100 美元,或者他们可以组成团队共同努力争取 100 美元的奖金。如果三个人组成一个团队并赢得奖金,实际上,他们可能会将奖金平均分成三份。然而,如果奖金应该根据每个人的贡献公平地分配,那会怎样?这就是 Shapley 值发挥作用的地方。

Shapley 值代表每个玩家在所有可能的联盟中以及他们可能进入每个联盟的所有可能顺序中的平均边际贡献。再次强调,关于这个主题的细节覆盖,我将不会在这里包括复杂的数学细节,但如果您想深入了解这些细节,可以阅读原始论文,其正式参考文献如下:

Shapley, L.S. (1953). A Value for n-Person Games. In “Contributions to the Theory of Games volume II”, H.W. Kuhn and A.W. Tucker (eds.), Princeton University Press.

在这里,我们将关注 Shapley 值在机器学习模型可解释性背景下的应用。我们首先从平均预测的概念开始,它代表我们的模型在整个数据集上做出的所有预测的平均值。对于回归模型,这仅仅是所有预测输出的平均值。对于分类模型,它是整个数据集上给定类别的平均预测概率。

当计算特定实例(即输入数据的一行)的 Shapley 值时,每个特征的贡献是通过它们如何将该实例的预测移动到平均预测来衡量的。然后,该特征的 Shapley 值捕捉了它在所有可能的特征组合中的平均边际贡献。例如,考虑一个二元分类模型,该模型预测银行贷款是否会违约。如果平均而言,该模型在整个数据集上预测违约概率为 5%,那么这个 5%就是“平均预测”。现在,对于特定的贷款申请,如果模型预测违约概率为 20%,Shapley 值有助于将这个平均预测的 15%偏差归因于输入中的每个特征(例如,申请人的收入、就业状况、信用评分等)。每个特征的 Shapley 值将表明该特征平均对预测偏差的贡献有多大。

以下代码提供了一个使用 SHAP 库获取特征重要性洞察的示例:

shap_values = shap.TreeExplainer(clf).shap_values(X_test)
shap.summary_plot(shap_values[1], X_test, plot_type="bar")

在代码中,我们正在创建 SHAP 库中的 TreeExplainer 对象。这个特定的解释器针对基于树的模型进行了优化,例如决策树、随机森林和梯度提升树。我们传递给它的 clf 实例是我们训练的基于树的模型。一旦创建了解释器,我们就使用 .shap_values() 方法计算 X_test 数据集中每个样本的 SHAP 值。然后,我们通过使用条形图(条形越长,特征的重要性就越大)来可视化每个特征对模型预测的平均影响。代码将生成类似于 图 12**.6 中所示的图形:

图 12.6:SHAP 输出

图 12.6:SHAP 输出

如我们在 *图 12**.6 中所见,也许令人惊讶的是,一个人的婚姻状况似乎对模型的输出影响最大。考虑到一个特征的 SHAP 值是该特征值对每个可能预测的平均贡献(对所有实例进行平均),它考虑了与其他特征的复杂交互,以及特征本身的影响。

虽然我们可以将 SHAP 等工具导入我们的笔记本中,但我们也可以使用 Vertex AI API 直接从 Vertex AI 中托管的模型中获取解释。下一节将描述如何做到这一点。

从 Vertex AI 中部署的模型获取解释

便利的是,Vertex AI 提供了我们可以使用的 API 和 SDK,以便从我们的模型中获取解释。在本章所附的 Jupyter 笔记本中,我们使用 projects.locations.endpoints.explain API 从我们在上一章 MLOps 管道中部署的模型中获取解释。以下是我们用于此目的的代码片段:

endpoint = aiplatform.Endpoint(endpoint_name)
response = endpoint.explain(instances=[instance_dict], parameters={})
    for explanation in response.explanations:
        print(" explanation")
        # Feature attributions.
        attributions = explanation.attributions
        for attribution in attributions:
            print("  attribution")
            print("   baseline_output_value:", 
                attribution.baseline_output_value)
            print("   instance_output_value:", 
                attribution.instance_output_value)
            # Convert feature_attributions to a dictionary and print
            feature_attributions_dict = dict(
                attribution.feature_attributions)
            print("   feature_attributions:", 
                feature_attributions_dict)
            print("   approximation_error:", 
                attribution.approximation_error)
            print("   output_name:", attribution.output_name)

代码将生成类似于以下内容的输出:

   baseline_output_value: 0.7774810791015625
   instance_output_value: 0.09333677589893341
   feature_attributions: {'dense_input': [-0.1632179390639067, 0.0, -0.2642899513244629, 0.0, 0.174240517243743, 0.0, 0.0, -0.5113637685775757, 0.001784586161375046, 0.1180541321635246, -0.03459173887968063, -0.004760145395994187]}
   approximation_error: 0.007384564012290227
   output_name: dense_3

响应中的字段可以这样解释:

  • baseline_output_value: 这是模型对基线实例的输出值。基线是一个参考点(例如平均值或中性实例),我们将其与对我们感兴趣实例的预测进行比较。模型在感兴趣实例和基线之间的输出差异有助于我们理解每个特征的贡献。

  • instance_output_value: 这是模型为我们传入的解释实例的输出值。在二元分类器的上下文中,这可以解释为实例属于正类的概率。

  • feature_attributions_dict:

    • 'dense_input': 这是模型输入张量的名称。

    • 这串数字表示了给定预测中每个对应特征在输入中的重要性或归因。此列表的长度与模型输入中的特征数量相匹配:

      • 每个数代表该特征对特定实例的模型预测的边际贡献,相对于基线。换句话说,这个特征将预测从平均/基线预测移动了多少?

      • 正值表示该特征推动了模型输出向正类方向。对于二分类,这通常意味着它使模型更有信心将实例分类为正类。

      • 负值表示该特征推动了模型输出向负类方向。

      • 零或接近零表示该特征对特定实例的预测没有产生显著影响。

  • approximation_error: 这是在计算归因值时使用的近似误差。解释方法通常使用近似来计算归因。近似误差给出了我们对归因值可以有多少信心(通常情况下,较小的误差表示更可靠的归因)。

  • output_name: 这是模型输出张量的名称。

恭喜!您已成功检索到发送到 Vertex AI 托管模型的输入的解释。要深入了解 Vertex 可解释 AI,您可以参考以下链接中的文档:cloud.google.com/vertex-ai/docs/explainable-ai/overview

到目前为止,我们讨论了获取和使用解释来理解我们的模型。如果我们发现我们的模型的一些预测是不公平的,那会怎样?我们可以采取哪些行动来对抗这种情况?我们可以用于此目的的一种解释机制是反事实解释,我们将在下一部分探讨。

反事实解释

反事实解释围绕的问题是,“我的输入数据需要改变什么才能改变预测模型的决策?”它们描述了一个假设的替代方案,如果满足某些条件,就会发生观察到的结果。这可能是在输入特征中发生的最小变化,从而将预测改变为指定的输出。

回到我们的贷款批准的例子,假设一个申请人 John 因为他的收入、信用评分和就业历史等特征被拒绝贷款。一个反事实解释可能会告诉 John:“如果你的收入高出 10,000 美元,你将获得贷款批准。”

反事实解释有多个重要原因。它们帮助受模型预测影响的个人理解为什么做出了某个决定。它们帮助数据科学家了解如何根据各种标准增强他们的模型,并且对于合规性也很重要。

要找到一个反事实,我们需要在特征空间中定义一个距离度量。目标通常是找到与原始实例最接近的反事实实例,但结果却产生不同的预测。这通常被表述为一个优化问题,其目标是使原始实例与其反事实之间的距离最小化,同时仍然产生不同的预测。

请记住,对于某些模型,特别是深度神经网络DNNs),找到反事实可能具有计算上的挑战。还重要的是要注意,反事实可能建议在现实生活中不可能或非常难以实现的变化,因此需要评估其现实世界的可行性。在本章附带的 Jupyter 笔记本中,我们执行了一些简单的反事实处理。请记住,反事实是一个在快速发展的领域中高度复杂的话题。

接下来,让我们看看一些减少偏差的额外机制。

减少偏差和增强公平性

在本节中,我们讨论了我们可以采取的主动措施,以在每个模型开发生命周期阶段减少数据集和机器学习模型中的偏差并增强公平性。

从数据开始

就像数据科学领域的任何事物一样,数据通常是开始的好地方。如果可能的话,我们应该收集更多的数据并确保数据尽可能平衡。在数据预处理期间,我们还可以通过使用重采样技术来调整训练数据中代表性不足的群体的表示,例如通过过采样少数群体或欠采样多数群体来减轻偏差。在特征工程期间,我们还可以创建或修改特征以减少其潜在的歧视性影响。

在模型训练期间

在模型训练过程中,我们可以引入公平约束,通过确保受保护群体和非受保护群体具有相等的正率和负率来确保平等机会。为此目的,有大量的公平性指标和约束,例如以下内容:

  • 人口统计学平等统计平等,要求不同群体中积极结果的概率应该相同

  • 平等机会,要求不同群体中真实正率相等

  • 均衡机会,通过要求真实正率和假正率在各个群体中相等来扩展平等机会

  • 治疗平等,要求不同群体中假阴性率与假正率的比例相等

公平约束可以在模型训练期间作为正则化的一种类型来实现。甚至还有一些专门设计来处理公平问题的公平感知算法,例如公平 k 均值算法。

后处理

在后处理期间,我们还可以采取一些步骤,例如调整不同群体的决策阈值,以确保公平性指标,如平等机会或人口统计平衡,我们还可以调整模型预测,以确保它们在各个群体中都是公平的。

当然,持续监控现实世界预测中的公平性问题并在必要时重新训练模型也非常重要。在关键决策场景中,我们可以考虑让人类参与审计或覆盖模型决策。

注意,公平性增强方法可能会导致模型准确性的权衡。挑战通常在于找到公平性和准确性之间的平衡,这对于给定的应用来说是可接受的。了解哪个公平性指标与您具体问题最相关也非常关键,因为不同的公平性指标有时可能会相互冲突。

为了总结本节关于可解释性和公平性的内容,让我们简要地看看一些我们可以用来评估和实施这些概念的库。

其他库

幸运的是,有一个不断增长的库列表正在开发中,目的是评估和促进可解释性和公平性。本节描述了此类库的示例。

What-if Tool

What-if ToolWIT)最初由 Google 开发,是一个早期的可解释性工具,具有可视化界面,允许检查模型的预测、比较不同模型以及检查潜在的偏差。它相对容易使用,不需要太多编码,并且包括了对我们在本章中讨论的许多概念的支持,例如反事实和 PDPs。

AI Fairness 360

IBM 的AI Fairness 360AIF360)是一个开源库,包括一组用于数据集和模型的公平性指标以及减轻偏差的算法。它可以用来提供详细的解释,以理解公平性指标及其在特定环境中的含义,并使用户能够可视化地探索数据集和模型中的偏差。它还可以帮助识别训练好的模型是否产生了偏差的结果,并提供一些工具来帮助在每个模型开发生命周期阶段(如预处理、训练和后处理)减轻偏差。

EthicalML/XAI

这是一个开源的 Python 库,旨在支持可解释的机器学习和负责任的 AI。它包括预处理、模型可解释性、偏差检测和可视化的工具,并支持我们在本章中讨论的概念,例如特征重要性、Shapley 值、LIME 和 DIA。

Fairlearn

Fairlearn 是另一个基于 Python 的开源项目,旨在帮助数据科学家提高人工智能系统的公平性。它包括用于减轻分类和回归模型不公平性的算法,以及用于比较的公平性指标。其主要目标是帮助机器学习从业者通过理解指标和算法来减少预测中的不公平差异,并提供用于模型评估和比较的交互式用户界面体验,这包括公平性指标和评估仪表板。它再次支持在机器学习模型开发生命周期的各个阶段使用缓解技术,例如预处理、训练和后处理。

除了这里提到的之外,还有许多其他可解释性和公平性库,但这些是当前在行业中特别受欢迎的库。谷歌云最近推出了更具体的模型评估机制和公平性指标。在撰写本文的 2023 年 10 月时,这些机制仍处于预览模式,尚未普遍可用。您可以在以下链接的文档中了解更多关于这些功能的信息:cloud.google.com/vertex-ai/docs/evaluation/intro-evaluation-fairness

关于生成式人工智能的说明

本书第十四章至第十七章专门介绍生成式人工智能GenAI),这是 AI/ML 的一个相对较新的子集。在这些章节中,我们将探讨大型语言模型LLMs)的概念以及它们与我们已在本书中介绍的其他类型机器学习模型的不同之处。LLMs 通常在极其庞大的数据集上训练,因此获得了可以应用于许多不同类型用例的大量知识。在这些后续章节中,我们将学习如何将 LLMs 用作自动评分员,为机器学习模型开辟新的评估技术,包括针对偏差、可解释性和公平性的特定评估。

本章最后要探讨的一个主题是谱系追踪的概念。在下一节中,我们将详细探讨这个主题,并评估其在可解释性和公平性背景下的重要性。

在机器学习模型开发中追踪谱系的重要性

我们在前面章节中提到了谱系追踪的概念,现在我们将更详细地探讨它。当我们谈论谱系追踪时,我们指的是追踪创建给定机器学习模型所使用的所有步骤和工件。这包括以下项目:

  • 源数据集

  • 对这些数据集执行的所有转换

  • 创建的所有中间数据集

  • 在结果数据上训练模型所使用的算法

  • 在模型训练过程中使用了哪些超参数和值

  • 在训练过程中使用了哪些平台和工具

  • 如果使用了超参数调整作业,该作业的详细信息

  • 对生成的模型执行的任何评估步骤的详细信息

  • 如果模型正在为在线推理提供服务,则模型托管端点的详细信息

上述列表并不全面。我们通常希望追踪创建模型所使用的每个步骤以及每个步骤中的所有输入和输出。

我们为什么要这样做?血缘追踪对于许多原因都很重要。它补充了可解释性的概念。虽然血缘追踪本身不一定能解释为什么模型以特定方式表现,但对于研究人员了解模型是如何创建的非常重要。它对于可重复性和协作也很重要。我们已经讨论了一些公司在需要管理由许多不同团队创建的数千个机器学习模型时遇到的复杂性。如果一个模型表现有问题,了解其血缘将有助于故障排除。如果一个团队想要基于另一个团队已经完成的工作构建,例如他们已经训练的模型或他们创建的数据集,了解这些工件的血缘将帮助消费团队在这些努力中更加高效。此外,为了持续提升模型的表现,我们需要知道该模型是如何创建的。血缘对于治理和合规也很重要,有时是必需的。

幸运的是,Google Cloud 提供了帮助我们追踪血缘的工具。例如,Dataplex 可以用来追踪数据血缘,而 Vertex ML 元数据服务可以帮助我们追踪我们机器学习模型开发生命周期中的所有步骤和工件。接下来,我们将更详细地了解 Vertex ML 元数据;让我们首先从 Vertex ML 元数据服务使用的术语开始。

机器学习元数据服务术语

执行代表机器学习工作流中的步骤或操作,例如数据预处理、模型训练或评估。工件代表每个步骤的输入和输出,例如数据集、模型或评估指标。事件代表执行和工件之间的关系,例如“工件 X 由执行 Y 生成”或“工件 X 被执行 Y 作为输入使用。”事件通过将工件和执行相互关联,帮助我们建立血缘数据。上下文代表将相关工件和执行捆绑在一起的逻辑分组。一个上下文的例子可能是一个特定的管道运行或模型版本。

所有上述资源统称为元数据资源,并由MetadataSchema描述,该 Schema 描述了特定类型的元数据资源的模式。除了预定义的元数据资源外,我们还可以在 Vertex ML 元数据服务中存储自定义元数据。所有跟踪的元数据都存储在MetadataStore中,所有这些信息都可以用来创建谱系图,这是一个连接工件、执行和上下文,并显示它们之间关系和流的视觉表示。

注意,与大多数 Google Cloud 资源一样,可以通过 Google Cloud 身份和访问管理IAM)来控制对元数据资源的访问,这对于安全和合规性非常重要。

现在我们已经涵盖了主要术语和概念,让我们开始回顾一些 Vertex AI 中的元数据。

Vertex AI 中的谱系跟踪

要探索 Vertex AI 中的谱系跟踪功能,我们将使用我们在第十一章中构建的 MLOps 管道作为示例。

在 Google Cloud 控制台中,执行以下步骤:

  1. 导航到Vertex AI > Pipelines

  2. 点击在第十一章中创建的管道运行名称(除非在此期间你在该 Google Cloud 项目中运行了其他管道,否则它应该是最近的管道运行)。

  3. 你将看到管道运行的执行图。

  4. 在屏幕顶部,点击展开工件Expand Artifacts)左侧的切换按钮(参见图 12.7 以获取参考):

图 12.7:展开工件

图 12.7:展开工件

  1. 现在我们可以开始探索与管道中每个步骤和工件相关的元数据。

  2. 你还会注意到,屏幕右侧的管道运行分析部分包含大量关于此管道运行的信息。摘要SUMMARY)选项卡提供了有关管道运行本身的信息,包括用作输入的参数。这些是我们第十一章中管道定义中定义的参数。

  3. 我们可以点击管道执行图中的元素,以查看与该特定元素相关的元数据。让我们从开始的地方开始。我们想知道哪个数据集被用作管道的初始输入。考虑到我们的管道中的第一步是数据预处理步骤,并且该步骤检索数据集,点击预处理步骤,其元数据将显示在屏幕右侧,如图图 12.8 所示:

图 12.8:预处理步骤详情

图 12.8:预处理步骤详情

  1. 图 12.8 中,绿色的箭头指向source_dataset输入参数,它提供了源数据集的路径(为了隐藏我的存储桶名称,图像中的实际细节已被删除)。

  2. 我们还可以看到preprocessed_data_path参数的值,它提供了预处理脚本将存储结果处理数据的文件夹路径。如果你向下滚动(截图未显示),你也会看到main_python_file_uri参数的值,它提供了我们用于管道预处理步骤的 PySpark 脚本的路径。实际上,如果我们点击查看作业按钮,我们可以查看用于在 Google Cloud Dataproc 上执行我们的脚本的实际无服务器 Spark 作业的详细信息,包括其执行日志。

  3. 现在我们已经成功追踪了我们的源数据集、对数据集进行转换的脚本和作业,以及用于训练我们的模型的处理后的数据集,接下来让我们转向管道中的下一个步骤,即模型训练步骤。

  4. 在我们的管道执行图中点击custom-training-job步骤。在右侧的信息面板中,可能最重要的参数是worker_pool_specs参数。如图图 12.9所示,该参数提供了关于我们的模型如何训练的大量信息,例如用于训练的数据集(这是前一个预处理步骤的输出),训练模型工件保存的位置,用于运行自定义训练代码的容器镜像,训练期间使用的超参数值,以及训练作业使用的机器类型和机器数量:

图 12.9:worker_pool_specs

图 12.9:worker_pool_specs

  1. 再次,如果我们点击屏幕顶部的查看作业按钮,我们可以看到在 Vertex AI 训练服务上运行的实际作业,以及该作业的执行日志。

  2. 因为我们使用自定义脚本来训练我们的模型,并将工件简单地保存在 Google Cloud Storage 中,在这个管道阶段,我们的模型被称为importer作业,用于导入我们的模型工件。

  3. 管道中的model-upload步骤是将我们的模型注册到 Vertex AI 模型注册表中的步骤。如果你在执行图中点击该步骤并查看其元数据,在输出参数部分,你会看到 Vertex AI 模型注册表中结果资源的 URI。

  4. 剩余的步骤endpoint-createmodel-deploy具有类似的格式。正如它们的名称所暗示的,endpoint-create步骤在 Vertex AI 预测服务中创建一个端点,而model-deploy步骤将我们的模型部署到该端点。它们的输出参数将显示由这些步骤创建的资源 URI。

  5. 我想引起您的注意,在管道中endpointmodel工件。如果您点击这些工件,并在屏幕右侧的信息面板中点击出现的查看谱系按钮,它将直接带您到 Vertex AI 元数据服务控制台,并显示步骤和工件之间相互关系的另一种视图,如图图 12.10所示。再次强调,点击图中每个元素都会显示该元素的元数据:

图 12.10:Vertex AI 元数据服务控制台中的谱系图

图 12.10:Vertex AI 元数据服务控制台中的谱系图

除了通过 Google Cloud 控制台获取元数据洞察之外,我们还可以直接使用 Vertex AI SDK 和 API 以编程方式查询和管理元数据。例如,以下代码将列出我们 Google Cloud 项目中所有的工件:

aiplatform.Artifact.list()

类似地,以下行将列出我们 Google Cloud 项目中的所有执行和上下文:

aiplatform.Execution.list()
aiplatform.Context.list()

我们现在已经成功追踪了创建我们的模型所使用的每一个步骤和工件。接下来,让我们探索 Vertex AI 中的实验功能,该功能与谱系追踪紧密相关。

Vertex ML 实验

当我们在第十一章中创建管道定义时,我们指定了一个实验名称来关联我们的管道运行。这为我们提供了另一种查看与我们的管道运行和它们创建的模型版本相关的步骤和工件的方式。此功能对于共享和协作以及比较不同的模型版本非常有用。要查看与我们的管道运行关联的实验,请执行以下步骤:

  1. 在 Google Cloud 控制台中,导航到Vertex AI > 实验

  2. 点击我们在 MLOps 章节中指定的实验名称(aiml-sa-mlops-experiment)。

  3. 点击最近运行的名称,并探索如图图 12.11所示的工件标签页:

图 12.11:Vertex AI 实验 – 工件视图

图 12.11:Vertex AI 实验 – 工件视图

  1. 点击每个工件 ID 下显示的链接,以查看这些工件以及它们在 Vertex ML 元数据服务中的元数据(它将带您回到我们在上一节中已经探索过的屏幕;这只是访问相同元数据的另一种方式)。

我们在本章中涵盖了大量的信息——在我们继续下一章之前,让我们总结一下我们之前讨论的内容。

摘要

在本章中,我们探讨了偏差、可解释性、公平性和谱系的概念。我们首先检查了在机器学习模型开发生命周期中可能出现的常见偏差类型。这包括偏差的来源,如既存偏差、算法偏差以及收集或测量偏差,这些进一步包括子类别,如抽样偏差、响应偏差和观察者偏差。我们讨论了如何使用数据探索和 DIA 等技术来检查偏差。

接下来,我们深入探讨了可解释性技术的应用,以理解我们的模型在推理时如何做出决策,以及如何评估其公平性,特别是理解我们的数据集中的输入特征如何可能影响模型的预测。我们使用了 PDPs 和 SHAP 等工具来完成这些目的。然后,我们探讨了如何使用 Vertex AI 从托管在 Vertex AI 端点的模型中获取解释。在仅仅获取解释之外,我们还讨论了如何通过反事实分析来主动对抗偏差,提出诸如“为了改变预测模型的决策,我的输入数据需要做出哪些改变?”等问题。

最后,我们讨论了谱系跟踪的主题及其在可解释性方面的重要性,以及其他因素,如协作、故障排除和合规性。我们回顾了在前一章中创建的机器学习管道,并检查了管道每个组件相关的元数据,包括创建特定模型所使用的所有步骤和工件。

尽管前面的章节专注于构建和运行机器学习模型所需的一切,但本章则聚焦于更高级的主题,例如确保我们的模型是可解释和公平的。本书的下一章将继续这一趋势。我们不再仅仅关注构建和部署机器学习模型的机制,而是现在正在纳入更广泛的伦理和架构考量。在下一章中,我们将进一步深入探讨治理、合规和模型开发生命周期中的架构最佳实践。

第十三章:机器学习治理与谷歌云架构框架

作为技术人员,我们当然经常发现机器学习ML)的技术方面是最有趣和最令人兴奋的部分,而法律和监管概念并不总是那么吸引我们。然而,这些概念对于在生产的规模上构建稳健的解决方案是必需的。它们帮助我们从业余爱好活动过渡到设计可靠系统,这对公司的成功至关重要,甚至可能影响数百万人的生活。

考虑到这一点,本章将涵盖以下主题:

  • 机器学习治理

  • 谷歌云架构框架概述

  • 关于谷歌云架构框架中 AI/ML 工作负载的概念

让我们直接深入我们的第一个主题。

机器学习治理

机器学习治理指的是在组织内部管理机器学习模型所需的一切,贯穿整个模型开发生命周期。由于模型在关键决策过程中可以发挥重要作用,因此确保它们是透明的、可靠的、公平的和安全的至关重要,我们需要实施结构化的框架来实现这些目标。这些框架包括政策和最佳实践,确保数据和使用机器学习技术的负责任和道德使用。

在本章讨论机器学习治理时,我还会将数据治理纳入讨论范围,因为数据的使用在机器学习生命周期中是如此内在。让我们从这里开始。

数据治理

当涉及到管理机器学习生命周期中的数据时,我们需要考虑许多方面,例如数据质量、血缘、隐私、安全和保留。让我们更详细地看看这些方面。

数据安全、隐私和访问控制

在所有数据治理策略的方面中,数据安全可以说是最重要的。数据安全事件往往会成为头条新闻,而这些并不是你希望负责的新闻头条!

数据安全的基本概念是数据访问控制,正如其名称所暗示的,它关注的是谁可以访问数据以及他们如何访问数据。最坏的情况是,公司外部的人获得了敏感数据的访问权限,并将其公开泄露或用于勒索或破坏等恶意目的。

当谈到数据安全时,我最喜欢的术语是深度防御DiD),它暗示了一个全面的数据安全策略包括使用许多不同的工具来保护数据和其它资源。在接下来的子章节中,我将概述我们可以采取的步骤来确保我们的数据安全。

数据分类

在定义数据的安全策略之前,建立一个分类系统以了解哪些数据元素在保护方面需要更多关注是很重要的。例如,公开发布在你网站上的数据,如产品描述和价格,通常不被认为是绝密信息,而你的客户的信用卡详情则是高度敏感的。你可以根据以下层级对数据进行分类:

  • 零层:高度敏感,例如客户密码和信用卡详情

  • 第一层:敏感,例如客户购买或交易历史

  • 第二层:有些敏感,例如客户地址和电话号码

  • 第三层:非敏感,例如公开可查看的信息

这些只是示例;你需要与你的组织信息安全专家合作,以确定哪些类别对你的组织最有意义。

在对数据进行分类之后,让我们讨论如何保护它们。

网络安全

我们可以将 DiD 方法看作是洋葱的层。在最外层,我们从网络安全开始。如果数据的不当用户没有访问数据的网络路径,那么这将是你的安全策略中的一个非常坚实的基础。网络安全实践包括设置诸如防火墙之类的设备来控制允许进入受保护网络的流量类型。Google Cloud 提供了这样的设备,以及其他网络安全结构,例如虚拟专用云VPC),它允许你设置自己的私有网络并控制如何访问它们,以及VPC 服务控制VPC-SC),它使你能够围绕你的资源创建安全边界以防止数据泄露。

身份验证和授权

洋葱的下一层是身份验证和授权,以授予或拒绝访问资源的权限。即使有人获得了访问受保护网络的权限,下一步就是确定他们允许访问哪些资源以及他们可以在这些资源上执行哪些操作。你需要确保只有被授权的人员和系统才能访问数据,并且授权应基于业务关键性。换句话说,一个人或系统只有在他们需要这样的访问来执行所需的业务功能时才能访问某份数据。在任何时候,你都应能够轻松地确定谁(或什么)可以访问哪些数据,以及为什么。

Google Cloud 身份和访问管理IAM)可用于配置和强制执行此类权限,或者对于软件组件,还可以使用如传输层安全性TLS)认证等额外机制。在本节稍后,我们还将介绍使用 Google Cloud Dataplex 进行数据编目。Dataplex 和 Google Cloud BigLake 可用于使公司更容易管理和强制执行对其数据资源的访问权限。Google Cloud BigQuery 提供额外的数据安全机制,如行级和列级访问控制,这意味着您不仅可以授予或限制对 BigQuery 中表的访问权限,还可以更细致地授予或限制对那些表中的特定行和/或列的访问权限。这为保护资源免受意外访问提供了额外的灵活性。例如,使用列级安全,您可以配置只有财务部门的人员可以查看包含客户信用卡详情的列,而其他员工和系统则不能。使用行级安全,您可以配置销售代表只能查看其区域客户的详细信息,而不能查看其他区域的客户。

数据加密

在最内层是数据资源本身。最佳实践建议数据应加密作为进一步的安全措施。在这种情况下,即使恶意或非故意用户获得了对数据的访问权限,他们也需要解密密钥来解密数据。不言而喻,加密密钥应以高度安全的方式存储在独立的系统中,并实施所有安全层来保护它们。再次强调,Google Cloud 提供了实施所有这些安全机制的工具,包括使用 Google Cloud 密钥管理进行加密和密钥管理。

记录和审计

除了所有这些机制之外,强大的数据安全策略应结合审计和日志实施来监控数据访问和修改,并支持审计和取证调查以检测或调查策略违规和数据泄露。Google Cloud 日志和审计日志可用于这些目的。图 13.1显示了 Google Cloud 审计日志可以跟踪哪些类型的日志:

图 13.1:Google Cloud 审计日志中的审计日志类型

图 13.1:Google Cloud 审计日志中的审计日志类型

图 13.1所示,我们可以使用 Google Cloud 审计日志捕获三种类型的日志。

数据隐私

虽然与数据安全内在相关,但数据隐私更具体地关注于个人信息PI)的合法、道德和安全处理。这是数据安全最重要的方面之一,因为隐私侵犯可能会严重损害公司的声誉和客户信任。

不仅如此,他们还可能招致严重的法律后果。有许多国际标准和法规管理数据隐私和保护,例如欧盟的通用数据保护条例GDPR),美国的加州消费者隐私法案CCPA),以及全球许多其他法规。这些法规概述了数据处理规则,如收集、存储、处理和共享。遵守这些法规并确保系统处理数据的合规性可能相当具有挑战性。

跟踪散布在数据集各个部分中的敏感数据也可能是一项挑战。想象一家拥有来自许多不同来源的 PB 级数据的公司,例如商店中的信用卡读取器或面向客户的在线表单。很容易识别从信用卡机传输的数据需要受到保护,但对于其他数据接口来说,这可能并不那么明显。例如,也许客户不小心将信用卡详细信息输入到非此目的的在线表单字段中(例如,如果客户不小心将信用卡详细信息粘贴到未打算输入信用卡详细信息的字段中)。这些字段可能不被视为敏感,因此从安全角度没有得到任何特殊关注。现在集成了谷歌云数据丢失预防DLP)工具的谷歌云敏感数据保护服务可以帮助识别和保护数据集中的敏感信息。如果发现敏感数据,可以使用敏感数据保护服务实施保护机制,如去标识化、掩码、令牌化和编辑。

在数据安全、隐私和访问控制方面,强调在谷歌云平台上的共同责任和共同命运的概念非常重要。为了避免在这里错误地表述法律术语,我建议阅读谷歌云关于此主题的官方政策,该政策可以在以下网址找到:

cloud.google.com/architecture/framework/security/shared-responsibility-shared-fate

在我们继续讨论机器学习模型治理之前,我们将通过讨论数据质量、编目和血缘关系来结束本节。

数据质量、编目和血缘关系

考虑到数据对公司来说可能是一项宝贵的资源,因此建立确保数据准确性、一致性、可发现性以及(根据用例)及时性的实践至关重要。例如,考虑到数据通常用于做出重要的商业决策,不准确或过时的数据可能会对公司业务产生负面影响。这也适用于由机器学习模型自动化的商业决策。如果我们向机器学习模型输入不准确的数据,我们将得到不准确的预测。

一个有效的数据治理策略始于明确的数据政策、责任和标准,以确保数据质量。然后我们需要建立框架来衡量和监控数据质量因素。在此方面,最佳实践包括定期的数据清理过程,用于纠正数据错误、去重和填充缺失值,以及自动化机制,如定期的自动数据质量检查。

数据的可发现性也是一个重要因素。毕竟,即使你创建了精心策划的数据集,如果没有人知道它们的存在,它们也并不很有用。当公司建立了良好的数据管理实践时,数据生产者和消费者更容易确切地知道他们的数据在哪里以及数据的当前状态,在任何给定时间。在这样的公司中,一个强大的数据目录构成了公司数据基础设施的核心。多年来,我在各种咨询角色中与许多客户合作过,你会惊讶地发现有多少公司没有明确的数据管理策略。鉴于数据可能是组织的生命线,了解到许多公司并不完全清楚他们拥有哪些数据,这令人惊讶。公司内各种系统全天候都在产生和收集数据,但如果这些数据没有以某种方式编目,它们可能只是简单地坐在公司偏远、分散的部分的孤岛中,对大多数组织来说既不可用也不为人知。请记住,数据可以用于各种有趣的企业用例。如果你不知道你有什么数据可以访问,你可能会错失重大的商业机会。

实施数据血缘追踪同样重要,以便了解数据来源以及它在公司内部各种处理系统中如何被转换。如果我在我公司某个地方找到一些数据,我想知道它是如何到达那里的,以及它走过的每一步。它通过了哪些系统?这些系统对数据做了什么?在其他公司各个部分,那些其他系统是否创建了中间数据集?这不仅从业务运营的角度来看很重要,而且在合规性方面可能也是必需的。例如,如果您需要遵守数据主权法规,您最好始终知道您的数据在哪里。如果客户决定在受 GDPR 或其他相关法规约束的市场行使被遗忘的权利,如果您没有很好地掌握您的数据,您将很难遵守。同样,如果发生数据泄露,数据血缘可以帮助确定哪些数据被泄露,并了解潜在的 影响 和所需的恢复步骤。

幸运的是,Google Cloud 提供了众多工具来帮助完成上述各项活动,例如 Dataproc 和 Dataflow 用于数据清洗和处理,以及 Dataplex 用于目录管理、数据质量和数据血缘追踪。

接下来,我们将讨论机器学习模型治理。

机器学习模型治理

在本节中,我们讨论确保我们构建和部署的模型可靠、可扩展和安全的各个方面,以及它们持续满足这些要求的基础。为了实现这一目标,我们需要考虑许多因素,这些因素将在以下子节中进行讨论。

模型文档

从每个开发者最喜欢的主题:文档!虽然文档并不是开发者工作中最有乐趣的部分,但它对于构建和维护生产级系统至关重要。我曾与各种公司中的客户和团队合作,他们并不总是能很好地开发准确、高质量文档,而且你可以几乎肯定的是,缺乏这种文档将使你在需要随着时间的推移维护和改进系统时的工作变得更加困难。想象一下,你加入了一个新的团队,并被分配去提高一个特定应用程序的性能,该应用程序使用机器学习进行医学诊断,而你发现原始应用程序和底层模型是几年前由已经离开公司的人开发的,他们没有记录他们是如何实现该系统的。这并不是一个好的地方,而且你会惊讶地发现,这些类型的场景在行业中是多么普遍。也许在本章的背景下,最重要的是,模型文档对于合规性——有时甚至是法律要求——可能是至关重要的。

那么,高质量的模型文档是什么样的呢?通常,我们的文档应该详细记录模型设计、数据输入、转换、算法和超参数等因素。让我们更详细地看看这些内容。

模型设计

关于模型设计的文档应明确定义模型的目的,例如模型打算实现的目标和模型需要运行的上下文。这包括潜在的使用案例和将与此模型交互的预期用户或系统。我们还需要提供模型架构的详细描述,例如其层、结构和模型不同组件之间的相互依赖关系。此外,我们还应包括有关模型设计理由的详细信息,例如选择这种特定的模型架构或设计的理由,包括与其他考虑的潜在设计进行比较,以及解释为什么它们没有被选择。

数据输入

我们的模型文档应描述我们使用的数据收集过程,包括来源、收集方法以及数据收集的时间范围。我们应该列出模型使用的所有特征,包括它们的定义、类型(例如,分类和数值),对数据所做的任何假设,以及解释为什么每个特征与模型的预测相关。此外,我们还需要记录任何已知的数据质量问题,包括缺失值、异常值或不一致性,以及如何处理或缓解这些问题。

转换

另一项最佳实践是详细说明用于清理和预处理数据的步骤,例如处理缺失数据、归一化、编码技术和特征工程,包括对任何用于特征选择或减少的方法的解释(例如,如图图 13.2所示的主成分分析PCA)),以及使用这些方法的理由:

图 13.2:PCA

图 13.2:PCA

算法

在我们的文档中,我们应该讨论为什么选择特定的机器学习算法,包括与其他考虑的算法的比较,以及解释该算法为何适合当前问题的理由,根据适当的相关文献或经验证据进行引用。同样重要的是详细说明算法的配置,包括针对项目的任何特定定制。

超参数

我们应该包括模型使用的所有超参数的详细信息,为每个提供定义和范围,以及用于超参数调整的过程,例如网格搜索、随机搜索或贝叶斯优化。此外,我们还应包括每个超参数选择的最终值,并解释为什么选择这些特定的值,并支持调整过程的结果。

额外因素

我们的文档还应解释如何评估模型的表现,包括使用的指标(均方误差MSE),ROC 曲线下面积ROC-AUC))以及这些评估的结果。我们应该记录模型已知的任何局限性,记录模型预测中的潜在偏差,并描述这些偏差如何影响不同的群体或个人。我们还需要详细说明与模型相关的任何监管标准或伦理指南,并讨论如何确保合规性。最后,我们需要概述在生产环境中持续监控模型表现和行为的计划,包括处理模型漂移、异常或性能下降的策略。

模型版本控制

就像在传统软件开发中的代码版本控制一样,在机器学习项目中进行模型版本控制对于确保团队能够追踪模型的演变过程、复制结果、在必要时回滚到先前版本,以及维护整个模型生命周期中所有变更的记录至关重要。这在大型或协作环境中尤为重要,因为在这样的环境中,随着时间的推移,可能由许多不同的人或团队开发出多个模型的多个迭代。对于调试、持续改进、审计和合规性目的来说,这也同样重要。图 13.3展示了 Vertex AI 模型注册表中模型版本元数据的一个示例:

图 13.3:Vertex AI 模型注册表中的模型版本元数据

图 13.3:Vertex AI 模型注册表中的模型版本元数据

当我提到模型版本控制时,我指的是不仅仅是模型工件,例如实际模型文件、权重和架构。我们应该为模型开发过程中使用的每个相关项目实施版本跟踪。这包括与模型相关的任何代码,无论是预处理、训练、评估还是部署,以及数据集,无论它们是原始数据、预处理数据还是特征工程数据。甚至超参数值和性能评估指标也应进行版本控制,这样我们就可以轻松理解哪些版本的这些元素与我们的模型版本相对应。

一个实施良好的模型版本控制工具,如 Vertex AI 模型注册表,也将使我们能够添加自定义元数据,以更全面地跟踪我们的各种模型版本。

模型监控

如我们在前几章所讨论的,在我们将模型部署到生产环境中之后,我们需要持续监控这些模型。目的是识别模型性能中的任何漂移、异常或退化,包括公平性和可解释性等重要指标。再次强调,这不仅对业务连续性BC)至关重要,而且出于合规性的考虑。我们可能在部署前和部署期间已经证明我们的模型符合特定的法规,但如果不能定期持续监控,模型可能会偏离并失去合规性。如果我们已经设置了 MLOps 管道来自动化随时间持续改进模型的过程,那么这种监控应该扩展到我们管道的所有方面,例如确保我们在数据预处理步骤中进行数据质量监控,以及在新模型验证和其他过程中的其他重要步骤。

就像我们对于模型开发和管理的所有其他实施一样,我们希望我们的监控过程尽可能地自动化。我们应该设定阈值,超过这个阈值时,如果存在问题,则应自动启动某种纠正措施,或者通知值班支持工程师介入。例如,如果我们看到性能或公平性指标值的变化超过了指定的数量,那么就会启动纠正措施,这可能包括在更新后的数据上自动训练和评估新的模型版本,或者呼叫值班支持工程师进行干预。

正如我们在前几章所讨论的,Vertex AI 提供了内置工具,用于监控模型性能,无论是在部署后还是在模型开发过程中的每个相关步骤。

审计和合规

许多行业都有严格的法规(例如,GDPR、HIPAA 以及各种金融法规),这些法规要求对数据隐私、偏差、透明度等因素设定一定的标准。不遵守这些法规可能导致法律处罚和客户信任的丧失。如果我们有受监管标准约束的工作负载,那么我们需要建立审计流程,以确保我们的工作负载持续符合法规。

我们如何实施这些流程将主要取决于我们需要遵守的法规类型。这些流程可能包括常规的人工审查流程,或者,正如我们一直所做的那样,尽可能自动化审计流程,只有在出现似乎无法自动解决的问题时才通知人类。在人工审查流程的情况下,这是文档固有的重要性的地方,因为高质量的文档可以极大地简化审查过程,并在发现问题时更容易确定纠正措施。理想情况下,我们希望在模型性能、安全性或可靠性问题升级为更大问题之前就识别出潜在风险,并建立定期的审查流程可以帮助确保这一点发生。

对于某些类型的法规,可以使用建立良好的审计清单和标准操作程序(SOPs),这使得审计任务变得稍微容易一些。然而,请记住,机器学习的法规环境仍在不断发展,组织必须跟上变化以保持合规。

在上一章中,我们讨论了可解释性的概念。在合规监管的背景下,可解释性尤为重要。如果你不能轻松或充分地解释一个特定的模型或系统是如何工作的,那么你将很难确保合规性。

现在我们已经相当详细地覆盖了许多机器学习治理的重要因素,让我们再次放大视角,关注更大的图景。在接下来的章节中,我们将讨论如何实施机器学习治理,不同行业中机器学习治理的样子,以及如何跟上不断发展的机器学习治理格局。

机器学习治理的 operationalization

正如我在前几节中暗示的那样,我们通常希望尽可能自动化我们的机器学习治理实践和流程,并且有一些工具和平台可以帮助实现这一目标,例如数据目录、模型管理工具和审计工具,我将在以下子节中描述。

数据目录

我们在本章前面简要地讨论了数据编目。数据目录是一种元数据管理工具,帮助公司找到和管理其组织内部大量分布的数据,无论是在本地还是在云端。你可以将数据目录视为公司数据资产的庞大库存,旨在让用户发现、组织和理解他们的数据源。我们已经介绍了 Google Cloud Dataplex,谷歌将其描述为“一种智能数据布料,使组织能够集中发现、管理、监控和治理其数据湖、数据仓库和数据集市,具有一致的控制。”图 13.4展示了由 Google Cloud Dataplex 创建的目录示例:

图 13.4:Dataplex 目录

图 13.4:Dataplex 目录

这种一致控制的观念在治理的背景下尤其相关。使用 Dataplex,你可以使用元数据来描述你公司所有的数据资产,并且你可以以统一的方式管理不同 Google Cloud 数据存储和处理工具的权限。这当然从治理的角度来看非常重要,而且 Dataplex 还提供了数据质量和数据血缘功能,这些在治理的背景下也同样重要。

模型管理平台

这些平台协助模型整个生命周期的各个方面,包括开发、部署、监控和维护。它们对于模型版本控制、实验跟踪和模型性能监控等活动至关重要。通过为管理机器学习模型提供一个结构化环境,这些平台有助于确保模型是可靠和可重复的,并且满足性能预期。它们还通过提供详细的模型开发和部署过程记录来促进合规性。当然,Vertex AI 是 Google Cloud 的原生模型管理生态系统,提供了上述所有功能。

到目前为止,我们一直关注的是许多行业共有的机器学习治理方面。在下一节中,让我们来看看机器学习治理是如何应用于特定行业的。

不同行业和地区的机器学习治理

什么可以使合规性监管变得更加复杂的是,不同的国家、州和行业都可以有不同的法规。因此,机器学习治理在不同行业和地理区域之间差异很大。在本节中,我们将讨论特定地区和部门(如医疗保健和金融)的治理因素,以及区域考虑因素。

医疗保健

我目前居住在美国,当我听到“合规性监管”和“医疗保健”这两个词在同一句话中时,我脑海中首先想到的是健康保险可携带性和问责法案HIPAA),该法案赋予患者对其健康信息的某些权利,包括安全处理和保密性,并规定了违规和不合规的重大处罚。如果你在美国从事医疗保健工作,你几乎肯定需要了解并遵守 HIPAA 的要求。在设计实施该行业的机器学习系统时,你必须确保整个模型开发生命周期中的数据处理实践符合这些要求。其他国家和地区也有自己的监管要求,如果你在这些地区运营,你必须学习和理解这些要求。

金融

在金融行业,欺诈可能是最大的担忧或威胁之一,金融行业受到严格的监管以避免欺诈发生的可能性。例如,如果你的公司在美运营,那么你的公司的财务操作将需要遵守诸如萨班斯-奥克斯利法案SOX)等法规,该法案主要旨在防止企业欺诈并提高企业披露的可靠性和准确性,以保护投资者。如果你的系统以任何方式处理信用卡数据,那么你很可能需要遵守支付卡行业数据安全标准PCI DSS)的法规,这是一套与安全处理信用卡信息相关的安全标准。

地区特定的治理考虑因素

不同地区有不同的监管要求。例如,如果你在欧盟和欧洲经济区EEA)运营,那么你将受到 GDPR 要求的影响,该要求保护这些地区个人的个人信息。

加利福尼亚州有 CCPA,该法案规定了全球企业如何处理加州居民的个人信息。

还有规定如何处理与儿童相关的数据,例如儿童在线隐私保护法案COPPA),该法案旨在保护 13 岁以下儿童的隐私。

除了地区和行业特定的法规外,我们还必须确保我们遵守关于公平、透明度、可解释性、责任和伦理的义务。而且,我们不仅需要管理不同地区和行业的法规复杂性,而且这种复杂性还因法规可能随时间变化而进一步扩展。让我们在下一节中更详细地讨论这个话题。

跟进机器学习治理的演变趋势

我可以自信地说,机器学习行业是目前发展最快的行业之一。全球的公司、政府和研究机构都在这个行业中大量投资。因此,与这个行业相关的合规法规也在迅速演变。为了持续成功,坦白说,确保你不陷入麻烦,你的公司需要在这个不断变化的环境中保持最新。在本节中,我概述了该领域的重要概念和最佳实践。

持续教育和培训

您公司的员工需要持续教育,以跟上监管要求的进步。除了技术能力外,您的员工还必须了解与机器学习部署相关的伦理考虑和风险管理策略。信息充分且受过良好训练的个人不太可能犯下诸如违反数据隐私标准等代价高昂的错误。此外,由于这是一个不断发展的领域,新的类型偏见和伦理困境几乎每天都在出现。我强烈建议实施定期的培训课程、研讨会和教育资源,让员工了解最新的趋势、工具、伦理考虑和关于机器学习治理的最佳实践。

定期更新治理政策和实践

除了技术和伦理考虑之外,数据保护和隐私的法律环境也在不断演变。组织必须定期更新其治理政策,以符合新的和不断变化的法律和标准(GDPR、CCPA 或行业特定法规),并且随着新技术和方法的发展,治理政策必须适应以适当容纳和管理它们。对于简单的线性回归模型有效的方法可能不足以应对复杂的深度学习DL)系统。不幸的是,随着新技术的出现,威胁环境也在不断发展,昨天还安全的事物明天可能就不再那么安全了。因此,我们需要定期审查和更新安全政策和实践,以保护敏感数据和机器学习系统免受新的漏洞和攻击策略的侵害。

此外,考虑到谷歌的站点可靠性工程SRE)实践,尽管我们应该尽一切努力避免负面事件的发生,但如果此类事件确实发生,我们需要从该场景中学习。因此,我们应该对任何问题进行彻底的复盘,并利用这些见解来改进政策并防止未来发生。

另一套与 SRE 紧密相关的概念包含在谷歌云架构框架中,我将在下一节中讨论。

谷歌云架构框架概述

用谷歌自己的话说,“谷歌云架构框架提供了建议并描述了最佳实践,以帮助架构师、开发人员、管理员和其他云实践者设计和运营一个安全、高效、弹性、高性能且成本效益的云拓扑结构。”在本节中,我们将讨论框架的一些关键概念以及它们如何应用于谷歌云上的 AI/ML 工作负载,特别是在机器学习治理的背景下。

以下 URL 可以找到框架文档:

cloud.google.com/architecture/framework

让我们从框架的基本概念概述开始,这些概念被称为 基柱。一种思考方式是,通过确保所有这些基柱都得到实施,我们可以构建一个坚固且持久的结构(系统)。

框架的分类如下:

  • 系统设计

  • 运营卓越

  • 安全性、隐私和合规性

  • 可靠性

  • 成本优化

  • 性能优化

在接下来的子章节中,我将描述每个类别代表的内容,从系统设计开始。

基柱 1 – 系统设计

有趣的是,Google Cloud 架构框架中的 系统设计 类别更类似于整体框架的基础,而不是一个基柱,因为一个设计良好的系统适当地融合了所有的基柱。系统设计 类别封装了四个核心原则:

  • 记录一切

  • 简化你的设计并使用完全托管的服务

  • 解耦你的架构

  • 使用无状态架构

让我们更详细地看看这些内容。

原则 1 – 记录一切

我们在本章的 ML 模型治理 部分对此原则进行了相当多的讨论。在更广泛的系统设计背景下,我们不仅指的是与我们的模型相关的文档,而是与我们的系统实施的各个方面相关的文档,包括架构图和维护手册等方面。在这种情况下,我总是问这样一个问题:如果一位新成员加入我们的团队,并且需要快速学习他们需要了解的所有内容以改进和维护我们构建的系统,他们需要审查的所有细节是什么?如果其中任何细节没有得到充分的记录,那么这就是我们需要通过开发必要的文档来解决的问题。这也帮助了我们需要与之协作的其他团队,或者需要以某种方式与我们的系统交互的团队,如果监管合规官员需要审计我们的系统,这也会使每个人的工作变得更简单。

原则 2 – 简化你的设计并使用完全托管的服务

自从我听说奥卡姆剃刀的概念以来,我就成了它的忠实粉丝。它有几种不同的总结方式,但其中一种相当常见的是:“如果对某个现象有两种可能的解释,使用更简单的那一个。”这可以进一步扩展为:不要使事情比必要的更复杂。与此相反的是鲁布·戈尔伯格机器的概念,它通过极其复杂的机制来实现一个简单的目标。虽然鲁布·戈尔伯格机器观看起来很有趣,但它们通常非常不实用,而且它们不是你希望在大型、低延迟、高度敏感的生产系统设计中实现的东西。

尽可能简化你的系统设计有许多好处,例如,使故障排除、维护和保障系统变得更加容易。当出现问题时,具有许多不同组件的高度复杂系统很难进行故障排除。同样,在安全方面,高度复杂的系统通常具有更大的 攻击面。我们将在本章后面更详细地介绍这个概念。

我们可以通过将责任外包给 云服务提供商 (CSP) 来使我们的工作变得更简单。云计算的主要好处之一是 CSP 提供了旨在解决行业常见需求的平台和系统。当一家公司在自己的数据中心运行所有工作负载时,它要么需要完全自行构建解决方案和平台,要么安装和管理其他公司创建的软件。这两种选择都会产生大量的员工开销,并需要特定的培训来管理。

让我们以构建和维护一个平台为例,这个平台能够使数据科学家开发和部署机器学习模型。在前几章中,我们概述了模型开发生命周期中所需的各个步骤。如果我们所有的“本地”工作负载(即不在云中)运行,那么我们需要设计、构建和维护一个支持所有这些步骤的平台,或者像许多公司所做的那样,我们可以尝试拼凑一些东西,使用各种随机的第三方软件解决方案,这些解决方案都需要特定的培训,并且不一定能很好地协同工作。然而,在云中,我们只需使用云提供商提供的平台,让他们为我们做所有艰苦的工作,这样我们的团队能够专注于他们的核心能力和主要目标,而不是构建和维护基础设施。

类似的概念存在于其他类型的工作负载中。例如,在本地,我们可能为公司容器化工作负载构建和维护自己的 Kubernetes 环境。我们可能会花费大量时间维护这些系统,但在云中,我们可以使用如 Google Kubernetes Engine (GKE) 或 Cloud Run 这样的托管服务。在这种情况下,我们所说的将更多基础设施管理任务外包给云提供商的服务称为“向更高层栈发展”。在 GKE 和 Cloud Run 的情况下,Cloud Run 可以被视为“向更高层栈发展”,因为它比 GKE 的基本形式提供了更多的完全托管体验,尽管 GKE Autopilot 的最新推出也提供了一种非常少干预的方法,在这种方法中,更多的平台管理任务由 Google Cloud 实现。

原则 3 – 解耦你的架构

这在一定程度上与原则 2相关。它指的是将你的整体系统设计分解成更小的组件。一个典型的例子是将单体应用分解成微服务。原因是每个微服务比一个非常庞大且复杂的单体系统架构更容易管理。较小的组件可以独立开发和扩展,这可以提高你系统中新功能开发的速度。

原则 4 – 使用无状态架构

在无状态架构中,每个事务都是独立的。在处理请求时,服务器不会记住任何先前的请求或事务,客户端必须在每个请求中发送任何必要的数据以进行事务。相反,在有状态架构中,服务器维护客户端会话的状态。先前事务的上下文会被记住,未来的事务可能会受到过去发生的事情的影响。

我会在这个原则的标题中添加“尽可能”这个词,因为有时你的系统将需要维护状态,但尽可能,你想要做的是最小化需要维护的状态量,并将状态管理从你的应用程序卸载到单独的机制,如缓存层。

无状态架构通常更容易扩展,因为它们不需要维护客户端状态,允许请求由任何可用的服务器处理。有状态架构需要更复杂的基础设施来确保客户端与同一服务器交互或状态共享,这在大型环境中可能具有挑战性。有状态系统还使用更多资源来管理和存储会话数据,这可能会进一步影响可扩展性和系统复杂性。

柱石 2 – 运营卓越

运营卓越支柱关注于在 Google Cloud 上高效地运行、管理和监控系统。它包括自动化、可观测性和可扩展性等概念。

这个支柱讨论了使用持续集成和持续部署CI/CD)来自动化系统部署,以及使用基础设施即代码IaC)来管理你的基础设施。这是一个非常重要的概念,因为它提供了传统软件开发的所有好处,例如版本跟踪和增量更新。如果你使用版本跟踪机制来管理基础设施更新,那么你可以为审计目的保持强大的记录,并且如果任何更新引入了问题,那么你可以更容易地回滚到已知工作良好的先前版本。这通常被称为GitOps,而与之相反的是ClickOps。在 ClickOps 的情况下,基础设施更新是通过人们在用户界面中点击来完成的。如果你在你的技术组织中有一百多人,并且他们每天都在通过在用户界面中点击来更新你的基础设施,那么随着时间的推移,协调和跟踪这些更新可能会变得困难。Terraform 是实现在 Google Cloud 上实施 IaC 的流行工具。

运营卓越支柱还概述了在整个软件交付生命周期中融入测试的最佳实践。这包括单元测试、集成测试、系统测试以及其他类型的测试,如性能和安全测试。我们不应该在最后测试一切,而应该旨在在每个开发生命周期的每个步骤中都包含每种类型的测试。例如,单元测试可以作为我们的构建过程的一部分自动化。

在部署软件时,运营卓越支柱建议使用诸如通过蓝/绿部署和 A/B 或金丝雀测试进行不可变基础设施更新等方法。Google Cloud 提供了可用于实施这些策略的 CI/CD 工具。建议使用小而频繁的系统更新,这些更新比大而罕见的更改更容易管理和回滚。

在可观察性方面,这个支柱提供了关于有效地设置监控、警报和日志的建议,包括需要关注的常见指标,以及定义阈值,超过这些阈值应触发某种警报或纠正措施。它还讨论了设置审计跟踪以跟踪系统更改的重要性。对于出现问题的案例,它提供了建立支持和升级程序以及审查过程(如事后评估)的指南,以从任何失败中学习。

当然,确保你的基础设施能够适当地扩展以处理预期的流量量,并且实施计划以主动应对已知的峰值事件,这也是非常重要的。

最后,这一支柱涵盖了尽可能自动化您的大部分系统管理任务的重要性,以最大限度地减少您需要依赖可能存在错误的手动过程来有效运行系统。

第三支柱 – 安全、隐私和合规性

在 ML 治理的背景下,这可能是最相关的支柱之一,我们已经在本章前面讨论了这些主题,但在这里,我们将探讨这些概念如何在谷歌云架构框架中得到更正式的结构化。

除了我们之前讨论的 DiD 概念之外,谷歌推荐了实施默认安全的策略。这包括确保安全作为默认配置嵌入到您的系统架构中的最佳实践,包括诸如最小权限原则PoLP)等概念,其中用户仅被授予执行其工作职能所需的最小权限,不再更多。这还涉及到在网络级别锁定访问。例如,如果您知道在正常操作情况下,您的系统应该只从一到两个其他系统访问,那么您可以设置网络规则,阻止来自除这些特定系统之外的任何来源的访问。谷歌云还提供了一种名为保密计算的服务,用于处理敏感数据。

我想借此机会强调,谷歌云架构框架的支柱通常是相互关联的。例如,我们在运营卓越支柱的背景下讨论了 GitOps 的概念。这种使用 IaC 来管理您如何部署到系统的概念是建立默认安全实践的高度推荐方式。例如,您可以创建经过严格安全评估流程的 Terraform 模块,以符合您的企业安全政策和行业最佳实践来设置基础设施。一旦这些“默认安全”模块获得批准,公司中的任何人都可以安全地使用它们来设置所需的基础设施。这使得您的员工在提供基础设施方面遵守安全政策变得更加容易。为了使您能够轻松提供符合安全最佳实践的基础设施资源,谷歌云提供了安全基础蓝图,您可以在以下 URL 中参考:

cloud.google.com/architecture/security-foundations

作为与运营卓越支柱之间的关联,用于部署资源的 CI/CD 管道应内置安全机制。例如,您可以使用自动化在创建工件时检查安全漏洞。谷歌云还提供了一种称为二进制授权的机制,以验证由 CI/CD 管道构建和部署的 Docker 容器的内容,以确保这些镜像正好包含您期望的内容,没有更多。它还可以验证特定的构建系统或管道创建了一个特定的容器镜像。如果在 CI/CD 管道的任何点上安全检查突出了任何潜在问题,则管道可以自动停止,以确保不会将潜在的安全威胁引入到您的部署中。同样,您可以使用谷歌云的工件分析功能自动扫描存储在工件注册表和容器注册表中的容器中的潜在漏洞。即使在部署之后,您也可以通过使用谷歌云的 Web 安全扫描器来持续扫描您的 Web 应用程序,以识别部署到计算引擎、App Engine 和 GKE 的应用程序中的漏洞。

此支柱还提供了主动识别和编制公司风险以及减轻常见风险的建议。谷歌云最近还推出了风险保护计划,其中包括风险管理器等工具,以帮助您管理风险。

当然,IAM是这个支柱的一个重要组成部分。谷歌云提供了许多帮助管理这一方面的工具,例如 IAM 和云审计日志,我们讨论过这些对于访问管理和审计是必不可少的。

这个支柱还强调了使用云资产管理工具,如云资产清单,来跟踪贵公司所有技术资产并监控是否符合合规政策的重要性。

除了本节中我们讨论的所有主题外,安全支柱还涵盖了网络安全、数据安全、隐私和法规遵从性等主题,这些内容我们在本章前面已经讨论过。它还提供了如何使用谷歌云保证工作负载来帮助您满足合规义务、如何监控合规性以及如何处理数据主权、数据驻留、软件主权和运营主权等细节。

第四支柱 – 可靠性

可靠性支柱关注诸如高可用性HA)、可伸缩性、自动化变更管理和灾难恢复DR)等概念。它涵盖了你们中的一些人可能从谷歌的 SRE 实践中了解到的主题,例如定义服务级别指标SLIs)、服务级别目标SLOs)、服务级别协议SLAs)和错误预算。与运营卓越支柱的情况一样,可靠性支柱将可观察性作为一个主要组成部分。它还重申了运营卓越支柱中的一些其他概念,例如使用 CI/CD 管道自动化部署和增量更新,以及设置适当的可观察性和警报机制、事件管理IM)和事后分析实践。

这个支柱讨论了在系统架构中创建冗余以提高可用性的方法,包括使用多个谷歌云区域和地区来减轻特定地点可能发生的任何潜在问题。除了这些类型的主动缓解技术之外,它还概述了建立 DR 策略的实践,例如将数据同步到其他地区,并在需要时建立故障转移至这些地区的操作手册。

最后,它详细介绍了特定谷歌云产品的最佳实践。这个支柱包含了大量的知识,并且比这里适当包含的更多关于许多特定谷歌云产品的详细信息。

第五支柱 – 成本优化

你们可以保证这对几乎每一位客户都非常重要。事实上,成本优化通常是吸引公司首先迁移到云的主要因素之一。当公司在自己的数据中心运行工作负载时,他们通常需要购买和安装足够的(甚至更多)基础设施来满足他们可能一年或两年才发生一次的最高峰值事件。而在一年中的其余时间,这些基础设施高度未被充分利用,这导致了大量的浪费。然而,在云中,公司可以根据他们的实际需求调整其基础设施的规模,因此不需要在过度配置的基础设施上浪费金钱。此外,正如本章前面讨论的那样,将基础设施管理外包给云服务提供商使公司能够将时间投资于创新和开发支持其核心业务的功能。

该支柱的第一个主要重点是财务操作或FinOps的概念,这是一个文化范式,包括一系列技术流程和业务最佳实践,以帮助组织更有效地优化和管理他们的云投资。在这种情况下,向组织中的每个技术团队提供对他们的云支出的可见性,并要求每个团队对其支出负责,这是非常重要的。要了解更多关于 FinOps 的信息,我建议阅读 Google Cloud FinOps 白皮书,该白皮书可以在以下 URL 找到:

cloud.google.com/resources/cloud-finops-whitepaper

记住,我们通常无法在没有监控的情况下优化或改进某事物。因此,“成本优化”支柱提供了关于监控成本、分析趋势和预测未来成本的推荐。如果你预测你将在下一年或未来三年内花费一定金额,你可以购买承诺使用折扣CUDs)来节省那些工作负载的费用。你还可以使用标签对账单报告中的费用进行分类,例如将资源费用分配给特定的作业和环境。

“成本优化”支柱还提供了关于优化资源使用以降低成本的最佳实践,例如确保你根据当前和预期的需求(包括适当的情况下的一些缓冲)来配置你的基础设施,并且不要过度配置。这被称为正确规模,Google Cloud 甚至提供了一个正确规模推荐器,可以突出显示通过识别看似未充分利用(因此过度配置)的资源来改进规模的机会。你还应该使用自动扩展,这不仅确保你有足够的资源来服务所需的流量量,而且在不需要时可以缩减资源,从而节省资金。

在实施成本优化机制时,设置预算、警报和配额以控制支出是很重要的。例如,你可以指定一个特定的支出预算,并在接近达到该预算时收到警报。你还可以使用配额来设置资源使用的硬性限制,并可以设置 API 上限,以在达到一定阈值后限制 API 的使用。

可靠性支柱一样,“成本优化”支柱为许多具体的 Google Cloud 产品提供了详细的最佳实践,例如优化Google Cloud StorageGCS)中的存储层或优化 BigQuery 中的分区。

第六支柱 – 性能优化

性能优化可以与成本优化相关联,因此在这些概念方面存在一些重叠。例如,如果你的系统运行得最优,那么它们可能运行成本更低。实施良好的自动扩展策略是这一点的典型例子。性能优化支柱提供了如何定义性能要求、如何监控和分析性能以及当然如何优化性能的建议。

在监控和分析性能方面,这指的是可观察性的概念,我们需要实施和监控性能指标,如延迟和资源利用率。

就像可靠性成本优化支柱一样,性能优化支柱也为特定的 Google Cloud 产品提供了许多深入的建议,这是超出这里适当包含的详细程度。

既然你已经了解了 Google Cloud 架构框架是什么以及它由什么组成,让我们看看我们如何在 Google Cloud 的 AI/ML 环境中应用其概念。

注意

在 Google Cloud 架构框架的所有类别中,最经常重复的主题是自动化。想法是尽可能自动化一切。经过验证、可重复且可自动运行的过程往往会使我们在所有支柱上的工作变得更简单。

关于 Google Cloud 上 AI/ML 工作负载的架构框架概念

在本节中,我们将评估如何使用 Google Cloud 架构框架来处理 Google Cloud 上的 AI/ML 工作负载。我们将使用模型开发生命周期中的步骤来构建我们的讨论框架。作为提醒,模型开发生命周期的步骤在图 13.5中进行了高层次的总结:

图 13.5:ML 模型开发生命周期

图 13.5:ML 模型开发生命周期

让我们从模型开发生命周期中的数据收集和准备活动开始,这些活动包括收集、摄取、存储和处理数据。

揭秘!

你会注意到,我们已经在整本书中使用了许多这些实践。在这里,我们明确指出这些实践,以便你了解它们如何应用于一般的工作负载。

数据收集和准备

数据管理可能是与 ML 治理相关的所有主题中最重要的。正如我们所知,你的数据质量直接影响你模型的质量。此外,从安全的角度来看,当恶意行为者试图访问你的系统时,他们通常是为了你的数据,因为数据是一种如此有价值的资源,数据泄露可能对你的公司产生灾难性的影响。让我们看看我们如何应用 Google Cloud 架构框架中关于数据处理的建议。在这种情况下,我们不会将系统设计作为一个单独的支柱来讨论,因为有效的系统设计封装了所有其他支柱。

数据收集和准备中的运营卓越

记住,运营卓越关注自动化、可观察性和可用性等概念。以下子章节将探讨这些概念在数据收集和准备中的具体应用。

流程自动化和集成

在本书的前几章中,我谈到了构建数据管道以自动化我们的数据处理步骤的重要性。本质上,我们希望建立可重复的过程,然后实施机制来自动运行这些过程,无论是基于时间表(如每日、每周或每月)还是对某些事件(如新数据的可用性)的反应。因此,实施数据处理管道的概念是谷歌云架构框架中“运营卓越”支柱中概述的自动化建议的应用。谷歌云提供了许多我们可以集成在一起以设置数据处理管道的服务,例如 Dataproc、Dataflow、GCS、Pub/Sub 和 BigQuery。

一致性和标准化

在 MLOps 章节中,我分享了与不同成熟度级别的各种组织合作的经验,这些组织在实施他们的机器学习工作负载操作方面有所不同。当公司没有建立良好的流程时,他们的团队往往会使用大量随机不同的工具,每个工具都有自己的学习曲线,并且他们在孤岛中维护他们的工件。这些做法不利于公司范围内的协作,并阻碍了公司机器学习操作的扩展性和效率。然后我谈到了在整个公司标准化工具和流程的重要性,以克服这些限制。这一切都与谷歌云架构框架的运营卓越支柱有关。在团队和项目之间保持工具、库和流程的一致性,可以减少复杂性和学习曲线,使管理和扩展操作变得更加容易。也许与机器学习操作最相关的例子是,为了满足我们所有模型开发和部署需求,使用 Vertex AI,因为它为模型开发和管理的生命周期中的每个步骤提供了一套标准工具。

可观察性

所有常规的系统监控和日志记录要求也适用于 AI/ML 工作负载,并且 AI/ML 工作负载还有关于持续监控模型预测输出质量方面的额外要求,以确保它们不会随时间漂移。在早期章节中,我们讨论了用于监控的特定于 ML 的指标,例如线性回归用例的 MSE 或分类用例的 AUC-ROC 分数,以及公平性指标。谷歌云日志和谷歌云监控可用于在谷歌云上 ML 模型开发生命周期的所有点上实现可观察性,从评估训练验证指标到跟踪在 Vertex AI 预测端点部署的模型响应的延迟,以及 Vertex AI 模型监控可用于监视漂移。

数据收集和准备中的安全、隐私和合规性

到现在为止,我们应该已经充分理解,在几乎每家公司中,数据安全和隐私都是至关重要的。一种快速失去客户并损害公司声誉的方式就是成为数据泄露的受害者。我的观点是,安全地管理敏感数据是你可能能做的事情中最重要的;它比本章、这本书以及你公司的业务中的所有其他考虑都更重要。

在本章前面关于这一支柱的概述中,我们讨论了如何通过多层防御(DiD)来保护数据和系统,包括访问管理、加密和网络安全等因素。以下小节将探讨这些概念在数据收集和准备背景下的应用。

数据访问控制

在谷歌云中收集和准备数据时,我们可以使用 IAM 来确保只有授权的个人和服务可以访问数据,并且我们可以根据角色和职责控制谁可以查看、修改或与数据交互。例如,数据科学家可能只有读取和分析数据的权限,但没有删除数据的权限,或者财务数据可能仅供财务部门访问。如果我们使用谷歌云 Dataplex 来构建数据目录,这会变得更加容易,因为 Dataplex 允许我们集中管理跨多个不同的 GCS 和处理服务的我们的数据资产权限。

数据保护和加密

敏感数据应始终加密,无论是在存储(静止状态)时还是在服务或位置之间传输时(传输中)。谷歌云为其服务中存储的数据提供自动加密,我们可以使用 TLS 来保护传输中的数据。对于高度敏感的数据,我们甚至可以使用谷歌云 Confidential Computing 在处理过程中对其进行加密。此外,在数据准备阶段,敏感数据元素可以被屏蔽或标记化,以隐藏其实际值,从而在增强隐私的同时,仍然允许数据用于分析。

数据分类和发现

我们可以使用 Google Cloud 敏感数据保护服务来发现、分类和屏蔽数据集中的敏感元素。在收集数据时,此服务可以帮助自动识别诸如个人身份信息PII)或财务数据等信息,以便我们能够对其进行更高水平的保护。这是 Google Cloud Dataplex 可以提供帮助的另一个领域,因为在一个数据目录中跟踪所有我们的数据资产使得分类和发现变得容易。

审计和监控

我们之前介绍了云审计日志。我们可以使用云审计日志来详细记录谁访问了数据以及他们执行了哪些操作,这对于问责和可追溯性非常重要。这在机器学习工作负载中尤其相关,因为了解谁引入了什么数据以及何时引入可能对于可解释性和故障排除是必需的。而且,你知道吗?!Google Cloud Dataplex 与云审计日志集成,以生成数据目录中执行的操作的审计日志。

数据保留和删除

当使用 Google Cloud 时,我们可以根据数据性质和相关性建立数据保留政策。例如,在使用 GCS 时,可以指定保留策略以防止对象在保留策略指定的时间框架内被删除。这对于符合监管目的或遵守法律保留可能很重要。相反,可以使用对象生命周期管理在一段时间后自动删除数据(只要它不与数据保留策略冲突)。对于您希望永久删除的敏感数据,Google Cloud 提供机制以确保删除操作安全且不可恢复。

合规框架和认证

Google Cloud 提供工具和文档,帮助业务符合 GDPR 和 HIPAA 等标准(以及许多其他标准),并且它接受独立第三方审计,以确保其服务符合常见的监管标准。

防御威胁

云安全命令中心和事件威胁检测等服务允许对潜在威胁进行持续的数据和环境监控,提供洞察和可操作的推荐。定期扫描和评估数据收集和准备过程中涉及的系统,可以帮助确保数据不会暴露于潜在的违规风险。您还可以使用 VPC 网络安全和 VPC-SC 来控制对您的数据存储和处理系统的访问,以防止数据泄露。

我们在本节中讨论的所有项目对于确保数据安全处理和保护用户隐私都至关重要。道德考量也至关重要,以确保数据以公平、透明的方式收集和使用,不会传播偏见,尤其是在它将被用于训练可能影响个人生活的机器学习模型时。

数据收集和准备中的可靠性

记住,谷歌云架构框架中的可靠性支柱侧重于确保服务和应用程序在意外干扰或需求增加的情况下也能持续一致地运行,并满足预期的 SLOs。以下子部分讨论了如何在机器学习模型开发生命周期的数据收集和准备阶段应用可靠性支柱的概念。

自动化数据摄取和处理

依赖于手动过程进行数据收集可能会出错,而自动数据摄取有助于确保数据可以一致地收集。我们还可以自动化数据验证步骤,以确保传入的数据符合预期的格式和值范围,这可以防止损坏或格式不正确的数据在我们的数据处理和机器学习管道中传播。对于数据转换脚本和配置,我们应该使用版本控制来确保如果更改引入了错误,我们可以轻松地回滚到先前的稳定版本。

基础设施弹性

谷歌云的大多数数据存储和处理服务要么默认设计为高可用性,要么提供机制来帮助您将弹性构建到架构中,例如通过在多个区域和地区使用多台机器。

如果我们自行设计系统,我们应该确保数据存储和处理基础设施具有冗余组件。在发生故障的情况下,备份系统可以接管,确保数据收集和准备不间断。我们还应该实施备份和恢复机制,定期备份原始和经过处理的数据。我们可以将数据存储在多个区域或地区,以防止任何特定位置的潜在问题。这不仅保护了数据丢失,还允许在数据损坏或需要回顾早期数据版本时恢复到之前的状态。我们还可以为高速数据流的数据摄取服务实施负载均衡,以确保数据负载的均匀分布并防止系统过载。我们还应该设计我们的基础设施根据需求进行扩展(向上或向外),以确保在变化负载下的可靠性能,并可以实施排队机制来管理数据峰值。

持续监控和警报

运营卓越支柱一样,可观察性是这个支柱的关键组成部分。我们应该定期检查参与数据收集和准备的系统健康状况,并实施当检测到异常或故障时通知相关团队的警报机制。

数据收集和准备中的成本优化

在数据收集和准备阶段,由于可能涉及大量数据、复杂的预处理任务以及不断变化的基础设施需求,管理成本至关重要。以下子节将讨论我们如何在机器学习模型开发生命周期的数据收集和准备阶段应用来自成本优化支柱的概念。

高效的数据存储

如 GCS 和 BigQuery 之类的存储系统提供了不同类别的存储,价格各不相同。从成本优化的角度来看,使用适合我们数据的适当存储类别非常重要。例如,频繁访问的数据可以存储在标准存储中,而很少访问的数据可以转移到近线或冷线存储。为了使我们更容易管理,我们可以实施策略以自动将数据过渡到更便宜的存储类别或在其不再需要时删除它。我们还可以通过删除重复数据并压缩数据来减少存储的数据量(因此减少我们的成本)。在特征存储方面,我们应该在数据准备阶段评估每个特征的需求。删除冗余或低重要性的特征可以显著降低存储和计算成本。

优化的数据处理

我非常推崇尽可能使用无服务器解决方案。这不仅将管理基础设施的烦恼转移给了云服务提供商,而且使用 BigQuery 和 Dataflow 等无服务器解决方案,我们通常只需为使用的部分付费,无需担心过度配置(因此过度支付)基础设施。我们还可以选择可扩展的服务,如 GKE 或 Cloud Dataflow,这些服务可以处理数据处理负载的峰值,但在低需求时期可以缩减规模,对于非关键、容错的数据处理任务,我们可以使用预付费的虚拟机VMs),这通常比常规实例便宜。

考虑我们的数据位置也很重要,我们通常应尽可能在数据所在位置附近处理数据,出于多种原因,包括成本和延迟。例如,如果我们把数据存储在us-central1区域,而我们的处理基础设施位于us-east4区域,从延迟的角度来看将是不理想的,并且会因数据跨区域传输而产生额外的网络出口成本。这同样适用于混合云基础设施的情况,其中一些资源位于云中,而其他资源位于您的自有设施上。在这种情况下,考虑您的本地资源连接到云的位置,以及数据存储位置和数据处理位置。我们已在第三章中讨论了将您的本地资源连接到 Google Cloud 的各种方法(例如 VPN 和“互连”),您还可以通过使用 VPC-SC 在数据传输和处理过程中建立可信边界来进一步增强此类混合配置的安全性。

此外,如果我们正在使用虚拟机(VMs),并且这些虚拟机需要协同工作来处理我们的数据,我们可以使用Google Compute EngineGCE)的放置策略(特别是“紧凑放置策略”)来指定我们的虚拟机应彼此靠近,这对于高性能计算HPC)工作负载尤为重要。

最后,如果不需要实时处理,我们可以累积数据并批量处理,这通常比流式传输更经济。

成本监控和分析

我们可以使用诸如成本探索器或云监控中的自定义仪表板等工具来了解我们的支出模式,并设置账单警报以通知我们意外成本激增的情况,这样我们就可以及时采取相应措施。此外,我们还应定期分析我们的账单报告,以确定可以削减成本的区域,例如通过寻找未充分利用的资源或服务。

成本治理

良好的做法是为项目或部门设置预算,并为特定服务实施配额,以防止意外超支。建立资源组织和成本归属策略也很重要。我们可以使用 Google Cloud 项目、文件夹和标签来组织和分配成本,这使得跟踪和优化特定任务或团队的支出变得更容易,我们还应该推广一种文化,让团队意识到他们数据处理和活动相关的成本,并鼓励节约成本的做法。

定期审查

我们应该定期审查我们的数据收集和准备系统架构,因为随着时间的推移,可能会出现更新、更经济的解决方案。同样,我们也应该定期评估我们收集的数据的相关性,因为一些数据可能会随着时间的推移而变得不相关,与其收集、存储和处理相关的成本可以消除。

数据收集和准备中的性能优化

如我们在本章前面的概述部分所讨论的,性能优化和成本优化之间存在一些联系,因为表现最优的系统通常会更有效地使用资源。以下子部分将讨论我们如何将来自性能优化支柱的概念应用于机器学习模型开发生命周期的数据收集和准备阶段。

高性能数据收集

为了优化我们的实时数据摄取过程,我们可以使用如 Cloud Pub/Sub 或 Cloud Dataflow 等服务,这些服务可以帮助实现最小延迟和高效的数据流。我们还可以通过使用分布式系统从多个来源并发获取数据,在我们的数据收集策略中使用并行处理,从而使我们的数据收集更加高效。

高效数据存储

使用适当的数据结构,如列式格式(例如,Parquet)进行分析工作负载非常重要,这可以导致更快的查询。在高性能存储用例中,我们可以使用如 Cloud Bigtable 等存储解决方案,以低延迟、高吞吐量工作负载,这有助于确保在准备阶段快速访问数据。我们如何索引我们的数据集也可以提高检索和查询的速度,这在数据探索阶段对大型数据集尤为重要。

加速数据处理

我们可以使用如 Cloud Dataflow 和 Cloud Dataproc 等平台,这些平台提供托管 Beam、Spark 和 Hadoop 集群,以在多个节点间分配数据处理任务。对于机器学习中的特征工程或数据增强任务等工作负载,使用如 GPU/TPU 加速器等硬件加速器可以显著提高性能。此外,在如 BigQuery 等平台上,我们可以编写优化的 SQL 查询以最小化计算开销并提高处理速度。

网络优化

如果我们从本地系统向 Google Cloud 传输大量数据,专用互连提供高速、低延迟的连接。对于从全球来源收集数据,内容分发网络CDNs)确保最佳数据传输速度,我们还可以使用如 Traffic Director 等工具来管理和优化网络流量,确保服务之间高效的数据流。

资源分配和自动扩展

正如我们之前讨论的,确保服务根据需求自动扩展资源非常重要。例如,Cloud Dataflow 可以根据数据处理负载自动扩展工作实例。我们还应该根据数据收集和准备任务的具体需求调整虚拟机类型和配置(在内存和 CPU 资源方面)。

接下来,让我们讨论如何将 Google Cloud 架构框架应用于我们模型开发生命周期中的模型构建和训练步骤。

模型构建和训练

就像我们在上一节关于数据收集和准备中做的那样,我们将在这个模型开发生命周期阶段的背景下讨论每个支柱的概念。

模型构建和训练中的运营卓越

让我们从运营卓越开始,并探讨它如何应用于模型构建和训练。

标准化和自动化工作流程

这里关键组件是 MLOps 管道、版本控制和 CI/CD 工具。我们可以使用 Vertex AI Pipelines 创建标准化的、端到端的 ML 管道,自动化我们的模型训练和评估步骤,包括超参数优化。我们可以使用 Google Cloud 的源代码管理工具来管理我们的管道定义代码,以及 Google Cloud 的 CI/CD 工具,如 Cloud Build 和 Cloud Deploy,将我们的管道定义构建和部署到 Vertex AI Pipelines。

可观察性

在模型训练和构建阶段,我们需要实施两种主要的监控和日志记录类型。首先,我们需要在模型训练期间跟踪模型性能指标,如损失、准确性和验证分数。我们可以通过使用 Vertex AI 和 TensorBoard 等工具来实现这一点。第二是与系统资源监控相关,我们可以使用 Google Cloud Monitoring 来监控模型训练期间虚拟机、TPU 或 GPU 的资源消耗,这有助于实现最佳资源利用并及时检测可能出现的任何潜在瓶颈。

管理基础设施

我们应该为我们模型训练和构建步骤使用管理基础设施。通过使用 Vertex AI 等管理基础设施,我们自动使用了 Google Cloud 架构框架中 运营卓越 桩柱概述的建议。

模型构建和训练中的安全、隐私和合规性

考虑到训练过程涉及数据处理,数据安全仍将是本节的一个主要关注点。以下子节将讨论我们如何在机器学习模型开发生命周期的模型构建和训练阶段应用来自 安全、隐私和合规性 桩柱的概念。

数据安全

这里的机制与我们之前在数据收集和准备部分讨论的是相同的。我们应该确保用于模型构建和训练的数据在传输和静止状态下都进行了加密。当使用敏感数据进行训练时,我们可以使用数据掩码和标记化来掩码或标记特定字段,以防止暴露 PII 或其他敏感数据点。此外,我们可以使用 VPC-SC 等服务来限制可以访问我们数据的服务和资源,从而在用于训练的数据周围创建一个安全边界。

环境安全

我们可以设置安全训练环境,以确保虚拟机和容器被安全配置、打补丁和加固,或者使用 Vertex AI 等托管环境,这些环境为我们处理许多这些活动,并且我们可以使用 VPC 和防火墙规则来保护与模型训练相关的网络流量。

合规性监控

我们可以使用诸如云安全命令中心之类的工具来持续监控并确保训练环境符合合规标准,我们还应该定期审计训练数据源以确保遵守数据使用政策,尤其是如果从第三方获取数据时。

隐私

如果处理敏感数据集,我们可以使用差分隐私等技术向数据中引入噪声,确保单个数据点不可识别。我们还可以使用数据去标识化来删除 PI,使其无法与特定个人关联。

除了上述所有内容之外,我们还可以使用 IAM 来控制对训练环境和工件访问的权限。

模型构建和训练的可靠性

以下子部分讨论了如何在机器学习模型开发生命周期的模型构建和训练阶段应用可靠性支柱中的概念。

数据可靠性

正如我们在本书的早期章节中所做的那样,我们可以实施对传入数据的验证检查,以确保一致性、质量和完整性。我们还应该定期备份训练数据以防止数据丢失,并使用数据版本化以确保可重复性。

训练基础设施可靠性

我们可以在区域或跨区域部署中配置冗余资源,以确保即使一个数据中心出现问题,训练也能继续进行。在基础设施可伸缩性方面,Vertex AI 可以根据训练工作负载自动扩展资源。当然,使用监控工具来关注资源利用率和健康状况是非常重要的。

模型训练弹性

我们可以在训练过程中定期使用检查点来保存模型状态。在发生中断的情况下,训练可以从最新的检查点恢复,而不是从头开始。对于模型构建过程中的任何阶段的暂时性故障,我们应该实施重试策略,在引发错误之前自动尝试任务。

依赖关系管理

Vertex AI 允许我们使用容器化来确保在训练运行中软件和库版本的一致性,防止“在我的机器上可行”的问题。这也带来了容器化所固有的所有其他好处,例如标准化和可扩展性。想想我们在 MLOps 章节中的实践练习中是如何使用容器的。我们将自定义数据处理和训练代码打包到容器中,然后我们可以在模型开发过程的后续阶段无缝使用它们,只需在实施于 Vertex AI 和 Dataproc 等系统上的各个步骤中指向容器位置即可。这种打包方式,有助于实现可重复执行的结果,对于自动化 MLOps 管道中的步骤以及根据其不同的资源需求自动扩展我们的训练和推理工作负载至关重要。这种自动化是 MLOps 实践的核心好处。此外,通过以这种方式为 MLOps 生命周期中的每个步骤使用独立的代码包,我们可以独立扩展每个步骤,根据 Google Cloud 架构框架中“运营卓越”和“可靠性”支柱中概述的最佳实践提供灵活性。

为了进一步减轻潜在的依赖性问题,如果我们依赖于外部系统,如数据提供者,我们应该确保它们有正常运行时间和回退机制。

DR

定期备份模型架构、配置、训练权重和其他关键组件对于在数据损坏或丢失的情况下快速恢复至关重要。我们应该建立明确的恢复备份协议,确保在发生中断时最小化停机时间并快速恢复到操作状态。以下这一点不容忽视:我们必须定期测试我们的恢复程序。公司往往只关注备份机制,而不测试恢复过程。我们希望确保我们的恢复程序是有效的(即,它们实际上可行)和高效的(即,它们尽可能快地工作)。

模型构建和训练中的成本优化

以下子部分讨论了如何在机器学习模型开发生命周期的模型构建和训练阶段应用“成本优化”支柱中的概念。

资源效率

为了在模型构建和训练期间优化成本,我们应该确保用于训练的 VM、GPU 或 TPU 的大小适合工作负载。最初,这可能需要一些实验来找到最佳资源配置,但当我们把我们的训练过程标准化为 MLOps 管道时,我们应该对所需资源有一个很好的了解。使用 Vertex AI 和无服务器服务可以帮助我们优化成本,因为这些服务可以根据需求扩展我们的资源。我们还可以利用 CUDs 来节省计算成本。

对于可以处理中断的训练作业,我们可以使用可抢占的虚拟机,这可以提供实质性的节省。

还应注意的是,简单的模型架构可能比复杂的模型架构更容易、更快、更便宜地进行训练。在不使用时关闭所有资源也很重要,这样我们就不需要在它们空闲时支付费用。

定期审查和优化

我们可以使用如 Google Cloud Cost Management 之类的工具定期审查和分析基础设施成本,并确定优化机会。一如既往,我们可以使用预算、配额和账单警报来帮助控制成本,我们还应该定期审查我们的机器学习基础设施、数据存储和相关流程,以识别和消除低效之处。

模型构建和训练中的性能优化

下面的子章节讨论了如何在机器学习模型开发生命周期中的模型构建和训练阶段应用来自性能优化支柱的概念。

计算优化

为了优化性能,我们可以使用硬件加速和专门的硬件,如 GPU 和 TPU,这可以显著加速训练过程。

分布式训练

我们可以将训练过程分布在多个节点上并行运行,以减少训练时间。此外,对于超参数调整,我们可以使用如 Vertex AI Vizier 之类的服务进行并发试验,显著减少寻找最佳模型参数所需的时间。

数据 I/O 优化

我们应该使用高吞吐量的数据源和系统来处理高性能工作负载,以确保进入训练过程的数据不会成为瓶颈。

如本章其他部分所述,使用工具如 Google Cloud Monitoring 持续跟踪性能指标,如处理速度、内存使用和 I/O 吞吐量,并根据需要调整资源或配置,这一点非常重要。我们还可以使用分析来分析机器学习训练代码,识别性能瓶颈,然后优化耗时最长的部分。

接下来,让我们讨论 Google Cloud 架构框架如何将模型评估和部署步骤应用于我们的模型开发生命周期。

模型评估和部署

在本节中,我们将讨论模型开发生命周期中模型评估和部署阶段每个支柱的概念。请注意,在某些阶段,我们在模型开发生命周期的先前阶段已经讨论过的相同概念仍然适用。在本章剩余的部分,我将简要指出当相同的概念再次适用时。

模型评估和部署的运营卓越

让我们从运营卓越开始,以及它是如何应用于模型评估和部署的。

自动化、可观测性和可扩展性

在机器学习模型开发生命周期的这个阶段,与 运营卓越 柱相关的相同概念,例如自动化工作流程、可观察性和可伸缩性,我们在模型构建和训练阶段已经讨论过,现在再次适用。基本上,我们可以设置 MLOps 管道,使用 Vertex AI Pipelines 自动化我们的模型评估和部署步骤,并可以使用 Google Cloud Monitoring 和日志工具跟踪与我们的模型评估和部署模型性能相关的指标。我们还可以使用负载均衡器和 Vertex AI 自动扩展基础设施,以确保我们的模型能够处理不同级别的需求。

A/B 测试和金丝雀部署

当部署新的模型版本时,我们可以使用 A/B 测试来逐步转移流量,并与之前的版本比较性能。当然,我们希望确保正在部署的新版本性能优于之前的版本,并且不会对用户体验产生负面影响。使用金丝雀部署,我们可以首先将新的模型版本部署给一小部分用户,密切监控性能,然后逐步扩展到更广泛的用户群体。我们还应该使用模型版本控制,以便在较新版本导致意外行为或错误时能够快速回滚。

模型评估和部署中的安全、隐私和合规性

再次强调,关于数据安全和隐私的相同概念也适用,以及访问控制、合规法规和审计。除此之外,我们还可以使用网络安全控制措施和 VPC-SC 来保护我们模型托管端点。

模型评估和部署中的可靠性

在这种情况下,基础设施弹性的相同概念,例如在多个区域或地区部署资源,同样适用,以及健康检查、负载均衡、自动扩展、灾难恢复(DR)、监控、警报和依赖关系管理。

模型评估和部署中的成本优化

在讨论模型评估和部署中的成本优化时,我们之前阶段的一些概念再次适用,例如合理配置资源、关闭闲置资源、使用 CUDs、设置预算和警报。还应注意,较小的、简单的模型需要较少的资源,因此比较大的、更复杂的模型运行成本更低。

模型评估和部署中的性能优化

在模型评估和部署的性能优化以及优化计算和存储资源、硬件加速的背景下,听到 自动扩展负载均衡 这些术语并不令人惊讶。

我们还可以使用缓存机制来提高响应时间。例如,我们可以缓存频繁的预测结果,以便在不需要再次调用模型的情况下服务重复请求,并且我们可以将频繁访问的数据或中间模型评估结果存储在内存中,以便快速访问。

到现在为止,你已经成为了谷歌云架构框架以及它如何具体应用于机器学习模型开发生命周期的专家。让我们花一点时间来总结本章中我们涵盖的所有内容。

摘要

本章讨论了机器学习模型治理的各个方面,包括文档、版本控制、监控、审计、合规性、运营化和持续改进。然后我们探讨了行业特定和地区特定的法规,例如医疗保健行业的 HIPAA、金融行业的 SOX、欧盟的 GDPR 和加州的 CCPA。

接下来,我们专注于谷歌云架构框架及其支柱——运营卓越安全、隐私和合规性可靠性成本优化性能效率——如何应用于机器学习生命周期的各个阶段。我们深入探讨了每个支柱,详细说明了其在不同阶段的相关性,从数据收集和准备到模型评估和部署。这包括诸如成本效益模型部署、在整个模型生命周期中增强安全性以及保持高可靠性和性能标准等重要概念。总体而言,本章涵盖了与在谷歌云上部署和管理机器学习工作负载相关的许多因素,同时考虑了最佳实践和优化。

在下一章中,我们将探讨在谷歌云上使用一些其他流行的工具和框架——例如 Spark MLlib 和 PyTorch。

第十四章:额外的 AI/ML 工具、框架和考虑因素

到目前为止,我们已经涵盖了典型机器学习ML)项目中所有的主要步骤和考虑因素。考虑到人工智能/机器学习是技术行业中发展最快的研究领域之一,每天都有新的工具、方法和框架出现。

在本章中,我们将讨论数据科学行业中流行的其他工具和框架,这些我们之前还没有涉及。这包括重要主题,如BigQuery MLBQML)、我们可以用于 AI/ML 工作负载的各种硬件,以及使用 PyTorch、Ray 和 Spark MLlib 等开源库和框架。我们还将讨论一些关于如何在 Google Cloud 上实现大规模分布式训练的技巧。

在本章结束时,我将提供一些额外的背景信息,以帮助将本书剩余部分的重点转向生成式人工智能。这包括对我在本书前面以高层次描述的一些常用神经网络架构进行更深入的探讨。

例如,在第九章中,我们介绍了神经网络的基础知识,并介绍了常见的神经网络架构类型,如卷积神经网络CNNs)、循环神经网络RNNs)和转换器。在本章中,我们将更详细地探讨这些用例,为在剩余章节中讨论生成式人工智能建立一些基础知识。具体来说,本章包括以下主要主题:

  • 自定义 Jupyter 内核

  • BQML

  • AI/ML 工作负载的硬件考虑

  • 其他流行的开源工具和框架 - Spark MLlib、Ray 和 PyTorch 在 Google Cloud 上

  • 大规模分布式模型训练

  • 转向生成式人工智能

列表中的第一个主题也与一些我们需要覆盖的先决步骤相关,以便为本章中的实际活动设置我们的环境。这些将在下一节中描述。

先决主题和步骤

本节描述了设置我们的 Vertex AI 工作台环境的先决主题和步骤。

自定义 Jupyter 内核和包依赖管理

当我们在 Jupyter Notebook(例如 Vertex AI 工作台笔记本)中运行我们的代码时,我们的代码执行的运行环境被称为内核。Vertex AI 工作台实例已经预装了各种内核,用于流行的工具和框架,如 TensorFlow 和 PyTorch,我们将在本章中更深入地介绍这些内容。

然而,如果我们想定义具有特定已安装包的隔离环境,我们也可以创建自定义内核。当使用处于预览模式的包时,这是一个很好的做法,例如,因为它们可能有非常具体的依赖要求。我们将使用一个名为bigframes的库,我将在本章中详细描述。作为先决条件,我将概述如何创建自定义 Jupyter 内核,并解释与该过程相关的一些重要概念。让我们从虚拟环境的概念开始。

虚拟环境

当我们的代码执行时,它在一个环境中运行,这个环境包含我们的代码所需的全部依赖项,这些依赖项通常是其他软件包。管理各种包的依赖项可能很复杂,特别是如果我们有两件或更多软件依赖于特定包的不同版本。例如,想象以下场景:

  • 软件包 X 依赖于软件包 A 的版本 1.0.3

  • 软件包 Y 依赖于软件包 A 的版本 2.2.1

如果我们在环境中安装了软件包 Y 及其所有依赖项,那么我们的环境将包含软件包 A 的版本 2.2.1。

现在,如果我们尝试在我们的环境中运行软件包 X,它可能会失败,因为它特别需要安装不同版本(即版本 1.0.3)的软件包 A。这个问题被称为依赖冲突

虚拟环境可以帮助我们避免这个问题,因为正如其名所示,它们提供了一个虚拟执行环境,在其中我们可以运行我们的代码。当我们创建一个虚拟环境时,几乎就像创建了一个专门用于执行代码的机器,因为该环境以及其中的所有内容都与其他执行环境隔离,但这种隔离是虚拟的,因为它只是与其他可以在同一台机器上运行的环境的逻辑分离。

当我们使用 Vertex AI 笔记本实例时,我们可以创建两种主要的虚拟环境:

  • venv模块,因此它们是特定于 Python 包的。此选项使用pip进行包管理。

  • Conda 环境,它使用超越 Python 的 Conda 包和环境管理系统,可以管理各种其他语言的包,例如 R、Ruby 等。

在确定要使用哪个选项时,请记住,Python 虚拟环境更简单、更轻量级,但 Conda 提供了更多功能,并处理更复杂的场景(因此,Conda 环境可能比 Python 虚拟环境更大、设置速度更慢)。我们将使用 Conda 来处理我们的用例。我将在下面描述这一点。

创建 Conda 虚拟环境和自定义 Jupyter 内核

执行以下步骤以创建我们将在此章后面部分使用的 Python 虚拟环境和自定义 Jupyter 内核:

  1. 在您在 第五章 中创建的 Vertex AI Notebook 实例上打开 JupyterLab。

  2. 选择 文件 | 新建 | 终端,并在终端屏幕上执行以下步骤。

  3. 创建一个 Conda 环境:

    conda create --name bigframes-env -y
    
  4. 激活环境:

    conda activate bigframes-env
    
  5. 安装 bigframes(我们也可以安装我们想要的任何其他包,但现在我们将保持简单):

    conda install bigframes -y
    
  6. 在新环境中安装 JupyterLab(这将使我们的新 Conda 环境通过 JupyterLab 的自动发现功能作为内核可用):

    conda install jupyterlab -y
    
  7. 更改内核的显示名称(此更新可能需要几分钟才能在 Vertex AI Workbench JupyterLab 界面中显示):

    sed -i 's/"display_name": "Python 3 (ipykernel)"/"display_name": "Python 3 (bigframes)"/' /opt/conda/envs/bigframes-env/share/jupyter/kernels/python3/kernel.json
    

现在,我们的 Conda 环境和自定义 Jupyter 内核已经准备好用于本章的动手练习。在我们深入本章剩余主题之前,我们只需执行一个先决步骤,那就是为我们的无服务器 Spark MLlib 活动准备所需的文件。

为无服务器 Spark MLlib 活动准备文件

在本节中,我们将把一些文件存放在 Google Cloud Storage 中,以便在本章后面的无服务器 Spark MLlib 活动中使用。为此,请执行以下步骤:

  1. 进入 Google Cloud 控制台,通过点击 Cloud Shell 图标打开 Cloud Shell,如图 图 14 所示。此图标看起来像是一个“大于”符号,后面跟着一个下划线——即 >_

图 14.1:激活 Cloud Shell

图 14.1:激活 Cloud Shell

  1. 在 Cloud Shell 中运行以下命令以从我们的 GitHub 仓库下载所需的文件:

    wget https://raw.githubusercontent.com/PacktPublishing/Google-Machine-Learning-for-Solutions-Architects/main/Chapter-14/data/data_processed_titanic_part.snappy.parquet
    wget https://raw.githubusercontent.com/PacktPublishing/Google-Machine-Learning-for-Solutions-Architects/main/Chapter-14/pyspark-ml.py
    
  2. 在 Cloud Shell 中运行以下命令以将所需的文件上传到 Google Cloud Storage(重要:请将 [YOUR-BUCKET-NAME] 替换为在 早期章节 中创建的存储桶名称):

    gsutil cp pyspark-ml.py gs://[YOUR-BUCKET-NAME] /code/additional-use-cases-chapter/pyspark-ml.py
    gsutil cp *.parquet gs://[YOUR-BUCKET-NAME]/data/processed/mlops-titanic
    

现在,本章后面的动手练习准备工作已经完成。接下来,我们将深入探讨 BQML 的重要主题。

BQML

我们在 第三章 中首先介绍了 BigQuery,并在本书的各个章节中使用了它进行数据管理和处理。然而,鉴于大规模数据处理与机器学习的紧密关系,Google Cloud 已经将机器学习功能直接集成到 BigQuery 中,以及与 Google Cloud Vertex AI 的原生集成。这个功能被称为 BQML,本节将详细介绍这项服务。

BQML 允许我们使用 BigQuery 中的标准 SQL 查询创建和执行机器学习模型。考虑到许多公司已经在 BigQuery 中存储了大量的数据,BQML 使得这些公司的数据科学家能够在大型数据集上训练模型,并在数据库系统中直接进行预测,而无需在不同存储系统之间移动数据。

它支持各种 ML 算法,包括线性回归、逻辑回归、k-means 聚类和深度神经网络,以及基于存储在 BigQuery 中的时间序列数据的预测用例。

除了训练和预测,我们还可以使用 BQML 执行模型开发生命周期中的许多步骤,例如特征工程、模型性能评估和超参数调整。考虑到所有这些都可以使用标准 SQL 完成,数据科学家可以轻松开始使用 BQML,而无需在工具方面经历陡峭的学习曲线。这被称为降低入门门槛,其中入门门槛代表人们开始进行一项活动有多容易或有多难。例如,入门门槛高的活动会带来很多初始困难。一个例子是,在某人能够有效使用该系统之前,需要对其进行大量培训或复杂的先决条件,例如提供基础设施。一些技术系统需要数月培训和努力,某人才能有效使用它们。另一方面,BQML 可以被任何理解标准 SQL 语法的人轻松使用,并且不需要任何复杂的设施配置。就像 Google Cloud 提供的其他托管服务一样,BigQuery(以及由此扩展的 BQML)为我们管理基础设施,并且可以根据需求自动扩展和缩减。

有了这个想法,让我们来看看如何使用 BQML 开发和使用 ML 模型。

使用 BQML

虽然本章附带的 Jupyter Notebook 提供了如何使用 BQML 进行各种 ML 任务的动手操作指南,但我将在这里总结一些主要功能。为了了解背景,让我们回顾一下我们的 ML 模型开发生命周期,如图 14**.3 所示:

图 14.2:ML 模型开发生命周期

图 14.2:ML 模型开发生命周期

以下小节将更详细地探讨每个步骤。

数据准备

我们将把 图 14**.3 中显示的以下步骤组合到本节中:

  • 摄入数据

  • 存储输入数据

  • 探索数据

  • 处理/转换数据

  • 存储处理后的数据

从数据摄入和存储开始,我们有多种方式可以将数据导入 BigQuery。例如,我们可以直接通过 BigQuery 控制台 UI 或 CLI 上传文件。对于大型数据集,我们可以将它们存放在 Google Cloud Storage 中,然后从那里导入到 BigQuery。我们还可以使用 BigQuery 数据传输服务自动将数据移动到 BigQuery,无论是作为一次性传输还是按预定的时间表进行。我们可以通过与其他服务集成,如 Google Cloud Pub/Sub 和 Dataflow,将数据流式传输到 BigQuery。还有第三方 ETL 工具可以用于将数据传输到 BigQuery。

一旦我们将数据存储在 BigQuery 中,我们就可以使用各种工具来探索和转换数据,除了 BigQuery 控制台和标准 SQL 之外。我们在前面的章节中介绍了并使用了pandas库,我们知道它是一个在数据科学中非常广泛使用的库,尤其是在数据探索和处理方面。因此,许多数据科学家喜欢直接使用 pandas 与存储在 BigQuery 中的数据。幸运的是,有一些额外的库使得这样做变得容易:

  • BigQuery DataFrame Python API

  • pandas_gbq

让我们更详细地看看这些内容。

BigQuery DataFrame Python API

BigQuery DataFrame Python API 使我们能够使用 Python 在 BigQuery 中分析和处理数据,并执行各种机器学习任务。这是一个相对较新的开源选项,由 Google Cloud 推出并维护,用于使用 DataFrame 与 BigQuery 交互(在撰写本文的 2023 年 12 月时,它目前处于预览状态)。我们可以通过使用bigframes Python 库来访问它,该库由两个主要部分组成:

  • bigframes.pandas,它在大查询(BigQuery)之上实现了类似 pandas 的 API

  • bigframes.ml,它在大查询机器学习(BigQuery ML)之上实现了类似scikit-learn的 API

伴随本章的 Jupyter Notebook 提供了如何更详细地使用bigframes.pandas的说明。我们将在稍后深入这些步骤,但首先,我将简要介绍pandas_gbq

pandas_gbq

如果我几个月前写这一章,pandas_gbq库将是本节中包含的主要或唯一选项,因为在撰写本文时,它一直是使用 pandas 与 BigQuery 交互的主要选项。这是一个由 PyData 和志愿者维护的开源库,已经存在一段时间了(自 2017 年以来),因此它在行业中得到了广泛的应用。

实际上,它是对 BigQuery 客户端库(google-cloud-bigquery)的一个薄包装,提供了一个简单的接口来运行 SQL 查询并将 pandas DataFrame 上传到 BigQuery。这些查询的结果被解析成一个pandas.DataFrame对象,其形状和数据类型来自源表。

伴随本章的 Jupyter Notebook 也提供了如何更详细地使用此库的说明。现在是深入研究这些步骤的好时机。打开您在第五章中创建的 Vertex AI Workbench 实例上的 JupyterLab,并执行以下步骤:

  1. 在屏幕左侧的导航面板中,导航到Google-Machine-Learning-for-Solutions-Architects文件夹内的Chapter-14目录。

  2. 双击pandas-gbq.ipynb笔记本文件以打开它。当提示选择内核时,您可以使用默认的Python 3 (****ipykernel)内核。

  3. 双击bigframes.ipynb笔记本文件以打开它。当提示选择内核时,您可以使用我们在本章的“先决主题和步骤”部分创建的默认Python 3 (bigframes)内核。

  4. 在您打开的每个笔记本中,按Shift + Enter来执行每个单元格。

    笔记本中包含注释和 Markdown 文本,描述了每个单元格中代码的功能。

如您所见,在 Vertex AI 中有多种与 BigQuery 数据交互的选项。

由于pandas_gbq库在业界的广泛应用,以及谷歌已经推出了之前描述的官方 BigQuery DataFrames Python API,因此这两种选项很可能在数据科学家中继续流行。需要记住的关键一点是,pandas-gbq将数据下载到您的本地环境,而 BigQuery DataFrames Python API 用于在谷歌云分布式基础设施上运行您的数据操作。

接下来,让我们讨论如何使用 BQML 创建、使用和管理机器学习模型。本章附带的 Jupyter Notebook 文件可以用来实施以下步骤,但在深入到笔记本文件之前,让我们先讨论它们。

创建机器学习模型

我们可以使用 BigQuery 中的CREATE MODEL语句来定义和训练模型。例如,以下代码片段创建了一个名为my_model_name的线性回归模型,该模型在my_dataset.my_table中的数据上训练,使用target_column中的值作为标签:

CREATE OR REPLACE MODEL `my_dataset.my_model_name`
OPTIONS(model_type = 'linear_reg', input_label_cols=['target_column']) AS
SELECT * FROM `my_dataset.my_table`;

正如我们已经讨论过的,BQML 支持许多常用的算法类型。我们还可以从/到 Google Cloud Storage 导入和导出我们的模型,以与其他工具和框架交互,甚至在模型开发过程中进行超参数调整。

评估机器学习模型

一旦我们的模型经过训练,我们可以使用如下 SQL 代码来评估其性能:

SELECT * FROM ML.EVALUATE(MODEL `my_dataset.my_model_name`, 
TABLE `my_dataset.my_evaluation_table`);

这将返回评估指标,如准确率、精确率、召回率等,具体取决于模型类型。

生成预测

接下来,我们可以使用以下 SQL 代码之类的模型来生成预测:

SELECT * FROM ML.PREDICT(MODEL `my_dataset.my_model_name`, 
TABLE `my_dataset.my_input_table`);

此语句将数据从my_dataset.my_input_table输入到我们的训练模型中,以生成预测。

现在,我们可以使用本章附带的 Jupyter Notebook 文件来实施这些步骤。为此,打开您在第五章中创建的 Vertex AI Workbench 实例上的 JupyterLab,并执行以下步骤:

  1. 在屏幕左侧的导航面板中,导航到Google-Machine-Learning-for-Solutions-Architects文件夹内的Chapter-14目录。

  2. 双击BQML.ipynb笔记本文件以打开它。当提示时,选择默认的Python 3 (ipykernel)内核。

  3. Shift + Enter来执行每个单元格。

    笔记本中包含注释和 Markdown 文本,描述了每个单元格中代码的功能。

接下来,我们将讨论如何设置模型监控和持续训练。

模型监控和持续训练

为了实现持续模型监控和持续训练,我们可以设置计划任务来执行评估和训练查询。这是一个我们需要使用额外的 Google Cloud 服务来架构的解决方案,例如 Google Cloud Scheduler 和 Google Cloud Functions,其中我们可以使用 Google Cloud Scheduler 定期调用 Google Cloud Functions 来运行训练和评估查询。话虽如此,对于复杂的 MLOps 管道,Vertex AI 提供了更多用于定制的功能。这一点引出了我们的下一个话题,即确定何时使用 BQML 与其他 AI/ML 用例工具。

何时使用 BQML 与其他 AI/ML 用例工具

我们已经讨论过,BQML 对于希望使用熟悉的 SQL 语法在 BigQuery 中实现 ML 用例的数据分析师和数据科学家来说是一个很好的选择,并且简单性是其在此环境中的主要优势之一。请记住,简单性和定制性之间往往存在权衡。如果您需要构建高度先进和定制的模型,那么您可能会发现 SQL 的简单性无法提供使用 TensorFlow、PyTorch、Ray 和 Spark MLlib 等专用 AI/ML 框架时所能达到的相同级别的定制性。

您还可以通过与 Vertex AI 中托管模型交互来“兼得两者之优”,使用 BigQuery 远程函数,这些函数提供了与 Cloud Functions 和 Cloud Run 的集成。采用这种方法,您可以编写将在 Cloud Functions 或 Cloud Run 上执行代码,您可以从 BigQuery 中的查询调用该代码。该代码可以向在 Vertex AI 中训练和托管的模型发送推理请求,并将响应发送回 BigQuery。如果需要,您甚至可以在请求和响应中实现转换,以确保您的查询期望的数据类型与模型期望的数据类型之间的兼容性。您可以在以下链接的 Google Cloud 文档中了解更多关于 BigQuery 远程函数的信息,该链接描述了已知限制和最佳实践:cloud.google.com/bigquery/docs/remote-functions

注意

虽然 BigQuery 是为大规模分析工作负载而设计的,但 Google Cloud Spanner 是 Google Cloud 中另一个高度可扩展的数据库服务。Spanner 是为分布式和强一致性事务性用例而设计的,并且也支持 SQL 语法。它最近增加了与 Vertex AI 的集成,提供与 BQML 类似的功能(即通过 SQL 接口访问 Vertex AI 上托管的 ML 模型),但旨在用于事务性工作负载,而不是分析性工作负载。

接下来,我将用简短的讨论结束本节,讨论 BigQuery Studio,这是一个方便管理我们所有 BigQuery 任务和工作负载的方式。

BigQuery Studio

如其名所示,BigQuery Studio 提供了一种单窗口体验,使我们能够在 BigQuery 中执行许多不同类型的活动。它包括一个 SQL 编辑器界面,使我们能够直接在 Google Cloud 控制台中编写和运行查询,并通过与 Duet 集成获得智能代码开发辅助,Duet 是一个 Google Cloud 生成式 AI 实时代码助手,我们将在本书稍后部分更详细地介绍。BigQuery Studio 还使我们能够安排 SQL 查询以定期的时间间隔(例如,每天)运行,用于需要重复查询执行的场景,如生成每日报告。

通过 BigQuery Studio,我们可以访问 Dataform 来在 BigQuery 中定义和运行数据处理工作流程,并利用 BigQuery Studio 与 Dataplex 的集成进行数据发现、数据分析和数据质量管理。BigQuery Studio 还与 Colab Enterprise 集成,使我们能够直接在 BigQuery 控制台中使用 Jupyter Notebook。

我鼓励你访问 Google Cloud 控制台中的 BigQuery Studio 界面,并探索其各种功能和集成。

我们将在后面的章节中重新讨论 BigQuery,但就目前而言,让我们讨论一些 AI/ML 工作负载的硬件考虑因素。

AI/ML 工作负载的硬件考虑因素

本书的大部分内容都集中在 Google Cloud 上可用的软件和服务级功能。高级实践者也会对存在的硬件能力感兴趣。如果你的用例需要极端性能,那么选择运行工作负载的正确硬件组件是一个重要的决定。底层硬件的选择和高效使用也会影响成本,当然,这也是你解决方案架构中的另一个重要因素。在本节中,我们将转换讨论焦点,重点关注在 Google Cloud 中运行 AI/ML 工作负载的一些硬件考虑因素,从对中央处理器CPU)、图形处理器GPU)和张量处理器TPU)能力的概述开始。

CPU、GPU 和 TPU

你可能已经熟悉 CPU 和 GPU,但 TPU 更是 Google Cloud 的专有技术。简要概述一下,CPU 是为大多数消费设备提供动力的,例如笔记本电脑和移动电话,以及数据中心中的通用服务器。它们在执行广泛任务的多任务处理中非常有效,但它们执行的处理是某种程度的顺序的。

另一方面,GPU 采用了一种优化并行(而不是顺序)处理的架构。如果你能将一个过程分解成可以并行运行的类似任务,那么你将能够在 GPU 上比在 CPU 上更快地完成该过程。尽管,正如其名称所暗示的,GPU 最初是为处理图形而设计的,这涉及到并行处理大量像素和顶点,但结果证明,许多 AI/ML 工作负载固有的矩阵操作任务也可以通过 GPU 的并行架构来加速。

Google Cloud 设计的 TPU 旨在加速 TensorFlow 操作,并且它们在训练和运行模型方面比 CPU 和 GPU 更高效,适用于某些类型的工作负载。尽管它们最初是为 TensorFlow 而创建的,但现在也可以通过使用如 PyTorch/XLA 之类的库来与其他框架一起使用,PyTorch/XLA 是一个 Python 包,它使用加速线性代数XLA)深度学习编译器,使 PyTorch 能够连接到 TPU 并将 TPU 核心作为设备使用。

谷歌云提供了许多不同类型的硬件服务器,我们可以选择用于运行我们的 ML 工作负载,这些服务器提供各种数量的 CPU、GPU 和 TPU 功率。

在撰写本文的 2023 年 12 月时,谷歌云最近推出了其最强大的 TPU(Cloud TPU v5p),并与他们新的AI 超级计算机产品一起推出,为 AI/ML 工作负载提供高度优化的资源(即存储、计算、网络等)。

由于谷歌云提供了广泛的计算选项,我这里不会列出所有选项。谷歌云不断推出更多选项,因此我鼓励您查阅谷歌云文档以获取最新细节:cloud.google.com/compute/docs/machine-resource

接下来,让我们将讨论切换回软件层面,并探索一些在谷歌云上得到支持的 ML 和数据科学行业的流行开源工具和框架。

其他开源工具和框架——Spark MLlib、Ray 和 PyTorch 在谷歌云上

在本节中,我将介绍其他开源工具和框架,例如 PyTorch、Ray 和 Spark 机器学习库MLlib),并演示如何使用它们在谷歌云上实现 AI/ML 工作负载。

Spark MLlib

我们在之前的章节中介绍了 Apache Spark,并在第六章中使用它进行数据处理以执行特征工程。Apache Spark MLlib 是 Apache Spark 的一个组件,它提供了针对并行处理大数据集优化的 ML 工具和算法。除了特征工程外,我们还可以使用 MLlib 中的工具来实现我们 ML 模型开发生命周期中的各个阶段,例如模型训练、模型评估、超参数调整和预测,以及将这些阶段组装成可以端到端执行的管道。

正如我们在数据处理上下文中讨论的那样,Apache Spark(包括 MLlib)的一个主要优势是它执行大规模计算工作负载的能力。虽然像 scikit-learn 这样的库在单机上执行 ML 工作负载时表现良好,但 MLlib 可以将计算工作分布到多台机器上,这使得我们能够更有效地处理更大的数据集。

在本章伴随的实践活动中,我们将使用 Spark MLlib 通过 Vertex AI 中的无服务器 Spark 功能在 Google Cloud Dataproc 上训练一个模型。从解决方案架构的角度来看,这一点很重要:我们将在 Vertex AI 中执行步骤,但它将在后台在 Dataproc 上运行 Spark 作业。我们可以以多种方式实现这项工作负载,在我们的实践活动中,我们将介绍以下两种方法:

  1. 使用与我们在第十一章中执行的活动类似的 MLOps 管道。

  2. 使用 Vertex AI 中的无服务器 Spark 用户界面。

让我们从第一种方法开始:使用 MLOps 管道。

通过 Vertex AI 上的 Kubeflow Pipelines 实现的无服务器 Spark

第十一章中,我们使用了 Kubeflow Pipelines 中的DataprocPySparkBatchOp操作符来自动化 MLOps 管道中无服务器 Spark 作业的执行。在本章中,我们将再次使用该操作符,但这次我们将使用它来运行使用 Spark MLlib 进行模型训练和评估的作业。为此,打开你在第五章中创建的 Vertex AI Workbench 实例上的 JupyterLab,并执行以下步骤:

  1. 在屏幕左侧的导航面板中,导航到Google-Machine-Learning-for-Solutions-Architects文件夹中的Chapter-14目录。

  2. 双击spark-ml.ipynb笔记本文件以打开它。当你被提示选择内核时,选择Python 3 (****ipykernel)内核。

  3. 在你打开的每个笔记本中,按Shift + Enter来执行每个单元格。

    笔记本中包含注释和 Markdown 文本,描述了每个单元格中代码的功能。

如我们所见,将我们在第十一章中执行的活动扩展到使用 Kubeflow Pipelines 来自动化用于模型训练的无服务器 Spark 作业,Spark MLlib 非常简单。让我们看看运行我们的无服务器 Spark 作业的另一种选项,即通过 Vertex AI 的无服务器 Spark 用户界面直接运行。

Vertex AI 中的无服务器 Spark 用户界面

要访问 Vertex AI 中的无服务器 Spark 用户界面,打开你在第五章中创建的 Vertex AI 工作台实例上的 JupyterLab,并执行以下步骤:

  1. 文件菜单中选择新建启动器

  2. 滚动到Dataproc 作业和会话部分,并选择无服务器

  3. 选择创建批量

  4. 在出现的屏幕上(参见图 14.4以供参考),输入以下详细信息:

    1. pyspark-ml.py文件。它应该具有以下格式gs://YOUR-BUCKET-NAME/code/additional-use-cases-chapter/pyspark-ml.py

    2. --``processed_data_path=gs://YOUR-BUCKET-NAME/data/processed/mlops-titanic

    3. --``model_path=gs://YOUR-BUCKET-NAME/models/additional-use-cases-chapter/

  • 将所有其他字段保留在默认值,并在屏幕底部点击提交图 14.3:Vertex AI 中的无服务器 Spark 用户界面

图 14.3:Vertex AI 中的无服务器 Spark 用户界面

点击提交按钮后,将出现一个屏幕,显示一系列无服务器 Spark 作业的列表;你新提交的作业将出现在列表的顶部(你可能需要刷新浏览器页面来更新列表)。等待直到作业状态显示为成功

  1. 如果作业因任何原因失败,点击作业名称以显示其详细信息,然后点击屏幕顶部的查看云日志

  2. 日志填充可能需要一些时间。你可以定期点击运行查询按钮来刷新日志。

  3. 当作业执行完毕后,模型工件将被保存在两个目录中,分别命名为metadatastages,位于你为--model-path参数指定的位置。通过在 Google Cloud 控制台中执行以下步骤来验证这些目录是否已创建并填充:

    1. 前往 Google Cloud 服务菜单,通过点击路径的每个后续组件来选择--model-path参数 – 例如,YOUR-BUCKET-NAME/models/additional-use-cases-chapter/

干得好!你刚刚使用 Spark MLlib 实现了一个无服务器 Spark 工作负载,通过 Vertex AI 在 Dataproc 上训练模型。接下来,我们将简要讨论另一个在数据科学行业中越来越广泛使用的分布式计算框架:Ray。

Ray

在这本书中,我不会花太多时间讨论 Ray,但我想为了完整性而提及它。Ray 的开发者将其描述为“一个开源的统一计算框架,使扩展 AI 和 Python 工作负载变得容易。”Ray 是另一种近年来越来越受欢迎的分布式执行框架,尤其是在 AI/ML 应用中。

与 Spark 类似,Ray 能够并行化代码并在机器集群中分配任务。它还包括可以帮助特定模型开发步骤的组件,例如用于超参数调整的 Ray Tune 和用于强化学习的 Ray RLlib。Google Cloud Vertex AI 现在通过允许我们创建 Ray 集群来直接支持 Ray。

PyTorch

与 TensorFlow 和 Spark MLlib 类似,PyTorch 是一个开源框架,包括一套用于机器学习和深度学习用例的工具和库。它最初由 Facebook 的人工智能研究实验室开发,并从另一个名为 Torch 的 AI/ML 框架演变而来,该框架基于 Lua 编程语言。正如其名所示,PyTorch 具有 Pythonic 接口,近年来因其易用性和由其各种组件(如用于计算机视觉的 TorchVision、用于音频处理的 TorchAudio 和用于自然语言处理的 TorchText)提供的灵活性而受到欢迎。

PyTorch 使用动态(或“命令式”)计算图,称为定义即运行方法,其中图在执行操作时即时构建,这使得与某些其他框架中使用的静态图相比,模型开发更加直观和灵活。

注意

TensorFlow 过去只提供使用静态计算图的选择,但近年来,它引入了一个名为“即时模式”的选项,该选项提供了动态图功能。

同样,与 TensorFlow 一样,PyTorch 支持通过 NVIDIA 的 CUDA 框架进行张量计算的 GPU 加速,这显著加快了模型训练和推理的速度。

在加快模型训练的话题上,在计算中,通过在多个设备上并行执行操作以更快地完成更多工作是一种常见的做法。在下一节中,我们将讨论通过分布式训练实现这一目标的做法。

大规模分布式模型训练

想起我们在第一章的“AI/ML 和云计算”部分中进行的讨论,我在其中描述了将我们的模型扩展到更大尺寸的过程,从我们可以在笔记本电脑上训练的小型模型开始,逐步过渡到在强大、高端服务器上训练的大型模型,最终达到单台计算机(即使是市场上最强大的服务器)无法处理模型的大小或训练模型的数据集的规模。在本节中,我们将更详细地探讨训练这样的大型模型意味着什么。

我们在本书中详细介绍了模型训练过程,但为了知识复习,我将在下面简要总结这个过程,因为这些概念在讨论大规模分布式模型训练时很重要。对于这次讨论,我将专注于神经网络的监督训练。

监督训练过程在高级别上工作如下:

  1. 我们的训练数据集的实例被输入到模型中。

  2. 模型算法或网络处理训练实例,并且对于每个实例,它试图预测目标变量。在神经网络的情况下,这被称为前向传播。

  3. 在做出预测后,模型使用损失函数(例如,回归中的均方误差(MSE)或分类中的交叉熵)计算错误或损失,该函数衡量模型预测与实际标签(真实值)之间的差异。

  4. 然后开始反向传播过程,它将微积分中的链式法则应用于计算关于网络中每个权重的损失函数的梯度。

  5. 优化算法,如梯度下降,利用在反向传播期间计算的梯度来更新网络中的权重。

训练通常通过在一系列的 epoch 中多次循环执行前面的过程来完成,其中 epoch 是整个训练数据集的一次完整遍历。然而,当使用大型数据集时,训练过程可以将整体数据集划分为更小的批次,并且每个批次的遍历被视为一个训练步骤。此外,一些框架,如 TensorFlow,允许我们指定每个 epoch 的训练步骤数。随着时间的推移,如果模型学习有效,那么在每个 epoch 之后,其预测将变得更加准确,损失将减少(希望达到可接受的阈值)。

注意

在这些讨论中,术语处理器指的是 CPU、GPU 和 TPU。此外,本节中我们将讨论的概念可以应用于单个机器上多个处理器或多个机器上的多个处理器上分布的训练工作负载。

在分布式训练用例中,处理器之间需要一些通信和数据共享。当使用单个机器时,处理器通常共享相同的系统内存(RAM),这简化了数据共享,但当使用多台机器时,通信需要在网络(包括路由器、交换机等)上发生,这可能会引入延迟和额外的复杂性。

我们在本书中已经多次实现了训练过程。接下来,我们将讨论当我们使用多个处理器时它是如何工作的。

数据并行性和模型并行性

通常有两个主要原因我们需要实现分布式训练工作负载:

  • 我们希望使用一个非常大的数据集

  • 我们希望训练一个非常大的模型

注意,这两种场景可能同时存在(也就是说,我们可能需要在非常大的数据集上训练一个非常大的模型)。在本节中,我将详细解释这些场景,从使用大型数据集的情况开始。

数据并行

有时,我们需要在巨大的数据集上训练我们的模型,这些数据集仅在一个处理器上处理需要很长时间。为了使训练过程更高效,我们可以将数据集分成更小的子集或批次,并在多个处理器上并行处理它们。在这种情况下,我们可以在每个处理器上运行我们模型的副本,该副本处理加载到该处理器上的数据子集。一个简单的例子是,如果我们有一个包含 10,000 个数据点的数据集,并且我们运行了 10 个处理器,每个处理器处理数据集中的 1,000 个数据点。这种方法被称为数据并行,并在 图 14.5 中表示:

图 14.4:数据并行

图 14.4:数据并行

图 14.5 中,每个紫色方块代表我们的数据的一个批次,每个批次都并行发送到单独的处理器。图中的每个批次只包含几个数据点,但在现实中,批次会大得多(此图旨在从高层次上说明概念)。接下来,我们将讨论我们可能需要实现分布式训练工作负载的另一个主要场景。这被称为模型并行。

模型并行

有时,模型本身可能非常大,以至于无法在一个处理器上放入内存。在这些情况下,我们需要将模型分散到多个处理器上,每个处理器处理模型的不同部分或段。一个段可以是网络中的一层,或者在一些非常复杂的模型中是层的部分。图 14.6 展示了一个简单的模型并行示例,其中我们神经网络中的每一层都在一个单独的处理器上运行:

图 14.5:模型并行

图 14.5:模型并行

我们可以使用不同的方法将我们的模型分解成段,我们通常希望选择一种方法,以最小化处理器之间的通信开销。这是因为这个过程可能会引入最大的延迟和复杂性,尤其是在我们使用多台机器,通信需要在物理网络上发生时。

除了优化处理器之间的通信外,我们还需要以最大化每个处理器利用率的方式设计我们的训练程序。记住,我们神经网络中某一层的输出成为我们网络中其他层的输入,因此层之间存在顺序依赖性。当我们的层分布在不同的处理器上时,一些处理器可能会空闲,等待从网络中前一层传播输入。这当然是对我们处理资源的低效使用,我们可以使用一种称为流水线的方法,通过将输入数据分成微批来提高训练效率。在这种情况下,每个段或阶段处理其微批,并将输出传递到下一阶段。然后,当下一阶段开始处理输出时,前一阶段可以开始处理下一个微批,依此类推。这样,数据以更流畅的方式在网络中流动,而不是后续层的处理器在等待早期层处理整个大型数据集时处于空闲状态。

到目前为止,我主要在谈论如何从模型处理输入的角度(即在训练过程中的前向传递)来并行化训练过程。记住,训练过程还包括一个反馈循环来检查模型的输出,计算与真实值的损失,然后计算损失的梯度并更新权重。接下来,我们将深入探讨这些步骤如何以分布式的方式进行实现。

分布式训练更新过程

在模型并行的情况下,数据仍然按顺序通过网络进行处理——也就是说,网络中的每一层(或段)都会产生输出,这些输出成为下一层的输入(即使这些层或段在不同的处理器上被处理)。因此,反向传播过程也可以按顺序进行,其中梯度是从最后一个段开始计算到第一个段,类似于在非分布式设置中的做法。每个段独立地根据计算出的梯度更新其模型权重的部分。

然而,在数据并行的情况下,训练数据的子集会在不同的处理器上并行处理,因此整体工作流程不是顺序的。每个处理器都有一个模型的相同副本,但每个副本处理不同的数据子集。因此,每个处理器上的模型副本对其他处理器正在做什么一无所知。因此,在计算损失、梯度和权重时需要额外的协调。

我们可以通过各种方式实现这种协调,但我们应该通常选择以下两种选项之一:

  • 使用集中式的参数服务器进行协调

  • 实现一个协议,允许单个训练服务器作为一个社区行动(我将将其称为“协作计算”)

让我们更详细地讨论这些方法,从参数服务器方法开始。

参数服务器方法

在参数服务器方法中,分布式系统中的一个或多个节点被指定为参数服务器,这些节点持有全局模型参数。这意味着它们对所有节点在分布式训练系统或集群中的所有模型副本的梯度参数具有全局视图。

在这种情况下,单个训练节点(让我们称它们为“工作节点”)处理不同的数据子集并计算各自的梯度,然后每个工作节点将其梯度发送到集中的参数服务器(们)。然后参数服务器(们)根据这些梯度更新全局模型参数,并将更新的参数发送回工作节点。这种方法的简化架构图如图14.7所示:

图 14.6:参数服务器方法

图 14.6:参数服务器方法

图 14.7中,箭头表示工作节点和参数服务器(们)之间梯度和工作更新之间的交换。虚线和边框表示可能存在一个或多个参数服务器,因为单个参数服务器可能会成为解决方案的瓶颈。此外,在这个架构中还需要有一个协调实体来管理所有资源和它们的通信。这可以与参数服务器共址,也可以作为一个单独的服务器实现。

接下来,我们将讨论使用数据并行性实现模型训练的另一种选项,在这种选项中,不是使用集中式服务器来执行协调步骤,而是所有工作节点直接相互协作。

使用环全归约的协作计算方法

在协作计算方法中,没有中央服务器或一组服务器专门用于在训练集群中的独立工作节点之间执行协调。相反,使用分布式计算协议在节点之间进行协调。这意味着节点从彼此那里获取更新(在这种情况下,计算出的梯度)。存在许多用于分布式计算系统之间协调的通信协议,其中一种相当流行的协议被称为全归约。这类协议通常设计用于聚合分布式系统中的所有节点的数据,然后将结果返回给所有节点。这意味着,尽管每个节点可能处理我们数据集的不同子集,并且每个节点上的模型实例因此可能计算不同的梯度和权重,但每个节点最终都会得到一个梯度权重的聚合表示,该表示在所有节点上是一致的。

当使用全归约时,我们可以以各种方式连接处理器,例如通过实现完全连接的网格,如图14.8所示,环形架构,如图图 14**.9所示,或其他方法,例如树形和蝴蝶架构,我们在这里不会涉及:

图 14.7:完全连接的网格

图 14.7:完全连接的网格

图 14**.8所示,完全连接的网格架构,其中所有节点都与其他所有节点相连,将需要所有节点之间进行大量的复杂协调。因此,更简单、更有效的环形架构通常被选择:

图 14.8:环形架构

图 14.8:环形架构

在环形架构中,正如其名所示,节点在逻辑上排列成一个环。这个架构的一个重要方面,称为环形全归约,是每个节点只需将其计算出的梯度发送给其邻居之一。然后邻居将接收到的梯度与其自己的梯度合并(聚合),将聚合后的梯度传递给环形中的下一个节点,依此类推。这种聚合通常只是简单地将梯度相加。经过N-1步(其中N是节点数),每个节点都将拥有所有节点的聚合梯度的副本。然后它们可以简单地执行除法运算来计算平均梯度,并在优化步骤中使用这些值。

注意

更具体地说,环形全归约算法通常分为两个阶段,称为“归约-散射”阶段和“全收集”阶段,但这是理解本节所述的高层次过程工作原理时不需要的细节。

到目前为止,你可能想知道哪种方法更好——也就是说,使用集中式参数服务器或使用如环形全归约之类的协作方法。答案,正如许多解决方案架构决策的情况一样,是“这取决于。”让我们讨论一些影响这个决策的额外因素,例如我们是否想实现同步与异步数据并行。

同步与异步数据并行

在同步数据并行的案例中,所有节点需要同时更新其参数,或者至少以一种协调的方式进行。这种方法的一个好处是,它为所有节点的参数更新提供了一致性。然而,它可能导致瓶颈,从而减慢整体训练过程,因为所有节点必须等待最慢的那个节点。

相反,在异步数据并行的案例中,节点独立更新其参数,无需等待其他节点,这可以导致训练速度更快。然而,这有时会导致模型收敛和稳定性问题,因为如果程序没有正确实施,节点可能会失去同步。

异步实现也可以具有更高的容错性,因为节点之间不相互依赖,所以如果某个节点因某种原因停止服务,只要我们以容错方式设置了环境,集群的其余部分可以继续运行。

All-Reduce 通常以同步方式实现,因为节点需要共享它们的梯度,而参数服务器方法可以同步或异步实现,其中异步通常是更常见的选项。

接下来,我们将了解 Google Cloud Vertex AI 如何通过 Vertex AI Reduction Server 提供优化的 All-Reduce 机制。

Vertex AI Reduction Server

虽然 Ring All-Reduce 方法在业界已经相当成熟且受欢迎,但它也有一些局限性。例如,在实践中,发现延迟往往与环中工作节点的数量成线性关系(也就是说,我们添加的工作节点越多,延迟就越大)。此外,由于每个工作节点都需要等待环中所有其他节点,单个慢速节点可能会减慢整个环的速度。此外,环架构可能存在单点故障,如果其中一个节点失败,可能会破坏整个环。

因此,谷歌创建了一个名为 Reduction Server 的产品,它提供了一个更快的 All-Reduce 算法。除了工作节点外,Vertex AI Reduction Server 还提供了 reducer 节点。工作节点托管和执行模型副本,计算梯度并应用优化步骤,而 reducers 执行相对简单的任务,即只是从工作节点中汇总梯度。图 14**.10 展示了 Reduction Server 架构的示例:

图 14.9:Reduction Server 实现

图 14.9:Reduction Server 实现

图 14**.10 中,你会注意到它与参数服务器架构的相似之处,但请记住,reducers 执行的任务比参数服务器少得多,这种简单性带来了一些好处。例如,reducers 只是轻量级的实例,可以使用 CPU,在这种情况下,可能比 GPU 显著便宜。此外,与环架构不同,随着我们添加更多的 reducer 节点,延迟不会线性增长,并且没有单点故障可以破坏整体架构。

基于 Vertex AI Reduction Server 架构提供的改进,我建议在 Vertex AI 上进行分布式训练时使用这种方法。

分布式训练作业通常需要使用大量资源,这可能会产生费用,因此我们不会在本章中为此主题进行动手实践。如果您想了解如何在 Vertex AI 上使用分布式训练实现机器学习项目(可选,包括 Reduction Server),我建议参考cloud.google.com/vertex-ai/docs/training/distributed-training的文档。

接下来,我们将探讨分布式训练的其他一些重要因素。

分布式训练的其他重要因素

在分布式训练中,过程中最复杂且容易出错的部分通常是管理节点间的通信。如果这部分没有高效实现,可能会导致瓶颈并影响训练性能。我们之前已经讨论了如何尽量减少节点间需要传输的数据量,幸运的是,有一些技巧可以帮助我们在这方面,例如在传输之前压缩梯度。

此外,考虑到分布式训练作业通常需要处理大量数据,它们可能需要运行很长时间,即使在多个节点上并行化工作负载时也是如此。因此,我们应该建立机制来帮助我们从训练过程中可能发生的故障中恢复。例如,如果我们的作业已经运行了几个小时,我们不想在作业完成前发生故障时不得不从头开始。为此目的,一个常见且重要的机制是检查点,在训练过程中我们定期保存模型的状态,以便在发生故障时可以从最近的状态继续。这就像在我们处理文档时定期保存我们的工作,以防笔记本电脑意外崩溃。

我们在本节中讨论的所有分布式训练概念都假设我们已经在我们的环境中某个地方存储了所有所需的数据,我们只需要将数据(或模型)分布到多个节点上。然而,还有一种流行的分布式模型训练类型被称为联邦学习,我将在下面简要描述。

联邦学习

在前面的章节中,我们讨论了将机器学习模型部署到边缘设备,如手机或物联网设备,通常是为了在这些设备上提供低延迟的推理。我们也讨论了这些边缘设备通常比服务器拥有更少的计算能力和数据存储资源。因此,我们在这些设备上训练模型的能力是有限的。

让我们想象一下,部署到设备上的模型可以通过更新从其本地环境(例如传感器)获得的数据来改进。如果我们想为这些设备的用户提供最佳体验,那么我们希望确保模型定期更新以适应新的数据。然而,在某些情况下,不断从边缘设备向集中位置发送数据以进行大型模型训练工作可能既低效又不可取。

联邦学习是一种技术,它使我们能够定期更新模型,而无需将这些设备上的数据发送回集中位置。相反,每个设备上的模型副本通过设备可用的数据进行本地训练。每个设备上的模型训练过程经过熟悉的步骤,包括计算损失和梯度,然后相应地更新模型参数或权重。让我们想象一下,这种训练正在数百万台设备上执行,每台设备根据其可用的少量数据进行模型更新。鉴于每台设备有限的训练能力,这个过程本身在长期内不会导致模型有太多改进。然而,在联邦学习的情况下,更新的权重可以被发送回集中位置以合并,创建一个更强大的模型,该模型可以从数百万台设备上的小型训练过程中学习。这意味着数百万台设备上的所有权重都可以平均(即聚合)形成一个更高级的模型。然后,这个更新后的模型(或其优化版本)可以被发送到每个设备,并且这个过程可以持续进行,以随着时间的推移不断提高模型。

这个过程的有效之处在于,只需要将模型权重发送回集中式基础设施,而设备上的实际数据根本不需要传输。这有两个主要原因:

  • 权重(从数据大小方面来说)远小于训练数据,因此只发送权重比从设备发送训练数据到集中式基础设施要高效得多。

  • 由于只有权重被传输(并且没有实际的用户数据),这有助于保护用户数据的安全并保护隐私。

当然,还有其他实现分布式模型训练的方法,但在这里我们已经介绍了很多更受欢迎的方案。

本书剩余部分将专注于生成式 AI,因此这是一个很好的时机,让我们回顾一下本书早期以高层次讨论的一些重要主题,这些主题将帮助我们理解导致生成式 AI 时代到来的各种发展。

转向生成式 AI

在我们开始深入探讨生成式 AI 之前,我将提供一些关于我们在这本书中早期讨论的一些重要神经网络架构的额外细节。例如,在第九章中,我们简要介绍了某些常见的神经网络架构,如 CNN、RNN、长短期记忆LSTM)和转换器。在本节中,我们将深入探讨这些显著架构的工作原理,原因如下:

  • 伴随这一章的实践练习包括构建一个用于计算机视觉用例的 CNN,因此详细描述 CNN 的内部工作原理是很重要的。

  • 这里提到的其余神经网络架构可以被视为开发生成式 AI 技术的旅程中的里程碑。

让我们从对 CNN 和计算机视觉的深入探讨开始。

CNN 和计算机视觉

正如我们在第九章中讨论的那样,CNN 通常用于计算机视觉用例,如物体识别和视觉分类,它们的技巧是将图片分解成更小的组件,或“特征”,并分别学习每个组件。通过这种方式,网络学习图片中的较小细节,然后将它们组合起来以分层识别更大的形状或对象。

CNN 的架构

我们可能可以写一本关于 CNN 架构的整本书,但在这个书中我们不需要那么详细的程度。我将从高层次上介绍一些重要的概念,并且伴随这一章的 Jupyter Notebook 提供了如何构建一个相对简单的 CNN 用于计算机视觉用例的代码示例。

作为对第九章中我们讨论内容的简要回顾,如图图 14.11所示,最基本形式的神经网络被称为前馈神经网络FFNN),其中被输入到网络中的信息随着它通过网络而遵循一个简单的正向方向:

图 14.10:一个简单的神经网络

图 14.10:一个简单的神经网络

另一方面,CNN 在架构中添加了一些特定的层,这些层有助于实现我们在本节引言中提到的分层处理。这些类型的层将在以下子节中从高层次上进行解释。

卷积层

这些层执行一种称为卷积的数学运算,它涉及将一个滤波器(或核)在输入图像上滑动以生成一个特征图。滤波器是一个用于检测特定特征(如边缘、角或纹理)的小矩阵,每个滤波器在输入图像上卷积,计算滤波器和输入之间的点积,从而生成一个特征图。

因此,卷积层的输出是一组特征图,这些特征图代表了在输入图像的不同位置由过滤器检测到的特定特征。

池化层

池化层主要用于通过下采样特征图和减少参数数量来进行降维。我们在第七章中详细介绍了降维的概念,并讨论了在训练和部署机器学习模型时,通常有必要实现降维以减少所需的计算量,以及降低过拟合训练数据的可能性。可以使用不同的池化方法,但最常见的方法称为“最大池化”,它从一个区域(由池大小定义)的像素集中取最大值。另一种方法,称为“平均池化”,简单地取一个区域内像素值的平均值。

全连接层

将卷积层和池化层结合使用,可以得到从输入图像中提取的特征。在输入数据通过卷积层和池化层后,网络中的高级推理是通过使用全连接层来完成的。这些就是我们讨论前馈神经网络(FFNNs)时提到的层,其中每一层的神经元都与前一层的所有激活连接。正如 FFNNs 的情况一样,全连接层通常用于网络执行的最终分类或回归任务。

最终输出层通常使用 softmax 激活函数来输出模型试图识别的类别的概率分布。对于二分类,也可以使用 sigmoid 函数。

残差网络

残差网络,或称 ResNets,是一种为了解决梯度消失和梯度爆炸问题而开发的 CNN,我们曾在第九章中讨论过这个问题。它们通过引入“跳过连接”来实现这一点,这些跳过连接“跳过”网络中的某些层,并将一层输出直接连接到后续层的输入。

关于 CNN 内部工作原理的细节,我们就介绍到这里。许多研究论文都详细介绍了 CNN 的工作原理,但这超出了本书的范围。接下来,我们将深入探讨,并通过一些代码示例来构建我们第一个用于计算机视觉用例的 CNN!

在本章附带的 Jupyter Notebooks 中,我们将使用 Keras 构建一个简单的 CNN。这也是你开始学习如何使用 PyTorch 的地方,然后我们将使用 PyTorch 来完成相同的任务。

构建卷积神经网络(CNN)

要构建我们的 CNN,请在第五章中创建的 Vertex AI Workbench 实例上打开 JupyterLab,并执行以下步骤:

  1. 在屏幕左侧的导航面板中,导航到Google-Machine-Learning-for-Solutions-Architects文件夹中的Chapter-14目录。

  2. 双击Keras-CV.ipynb笔记本文件以打开它。当提示选择内核时,选择TensorFlow内核。

  3. 双击PyTorch-CV.ipynb笔记本文件以打开它。当提示选择内核时,选择PyTorch内核。

  4. 在你打开的每个笔记本中,按Shift + Enter执行每个单元格。

    笔记本中包含注释和 Markdown 文本,描述了每个单元格中的代码所执行的操作。

请花点时间品味一下这个事实:你刚刚已经使用了 Keras 和 PyTorch 在 Google Cloud Vertex AI 上为计算机视觉用例构建了 CNN。这是一些相当高级的内容!

接下来,我们将探讨一些通常用于序列数据和用例(如自然语言处理(NLP))的神经网络架构类型。

RNNs,LSTMs 和 transformers

再次,我们已经在第九章中从高层次介绍了这些概念。在本节中,我们将对这些类型的架构进行更深入的探讨。我们不会在本章中构建这些网络,也不会过于详细地介绍;我在这里主要介绍这些主题,主要是为了历史背景,为我在本书生成式 AI 章节中将要介绍的概念和活动铺路。这是因为本节中所有的神经网络架构都可以看作是我们今天使用的生成式 AI 模型发展的垫脚石,顺序如表 14.1:所示:

开发 时间框架 参考文献
RNN 1990 Elman, J. L. (1990). Finding structure in time. Cognitive Science, 14(2), 179-211.https://doi.org/10.1207/s15516709cog1402_1.
LSTM 1997 Hochreiter, Sepp & Schmidhuber, Jürgen. (1997). Long Short-term Memory. Neural computation. 9. 1735-80. 10.1162/neco.1997.9.8.1735.https://doi.org/10.1162/neco.1997.9.8.1735.
Transformer 2017 Ashish Vaswani, Noam Shazeer, Niki Parmar, Jakob Uszkoreit, Llion Jones, Aidan N. Gomez, Lukasz Kaiser, and Illia Polosukhin. Attention Is All You Need. [2017, June 12]. arXiv preprint arXiv:1706.03762. http://arxiv.org/abs/1706.03762.

表 14.1:序列模型开发中的垫脚石

让我们从深入研究 RNNs 开始。

RNNs

当你阅读这个句子中的每个单词时,你需要记住之前的单词,以便你可以理解整个句子的含义。这是自然语言理解(NLU)的应用,它是 NLP 的一个子领域。在更通用的意义上,这个句子代表了序列数据,因为句子中的数据点(在这种情况下,是单词)与句子中的其他单词相关,并且它们被处理的顺序很重要。图 14.12展示了序列数据被输入到神经网络中的例子:

图 14.11:序列数据被输入到神经网络中

图 14.11:序列数据被输入到神经网络中

图 14.12中,我们可以看到数据点 1 将首先被神经网络处理,然后是数据点 2,依此类推,其中每个数据点都是一次由网络处理的。

在简单的 FFNNs(前馈神经网络)中,每个数据点独立地通过网络传递,因此网络不会将数据点与之前的数据点关联起来。正如我们在第九章中简要提到的,RNNs 将一种循环机制引入网络架构中,这种循环机制使得网络能够“记住”之前的数据点。让我们更详细地看看这意味着什么。

在 RNNs(循环神经网络)中,每个数据点被网络处理的概念被称为时间步。需要注意的是,在 RNNs 中,每个时间步中神经元的输出可以被保存以供将来参考。我们称这个为网络的当前状态;这通常被称为网络的隐藏状态,因为它通常不会对外暴露。

在每个时间步,网络中的神经元接收两组输入:

  • 网络前一层神经元的输出(或者如果我们指的是网络中的第一个隐藏层,则是输入层的输入)。

  • 从上一个时间步保存的相同神经元(即自身)的输出。这是隐藏状态。

观察我们的图 14.12中的图,在第一个时间步,当序列中的第一个数据点(即数据点 1)通过网络时,过程将非常类似于我们在第九章中描述的标准 FFNN,因为没有之前的状态需要记住。

然而,当数据点 2 通过网络处理时,每个神经元都可以将这个新数据与网络的“当前状态”结合起来(即处理数据点 1 后创建的状态)。这个过程对每个通过网络的新数据点重复进行,通过这样做,网络保持了对之前处理的数据点的某种记忆。

时间反向传播(BPTT)

我们在第九章中讨论了神经网络学习中的反向传播过程。考虑到 RNN 使用时间步的概念,并组合了神经元随时间输出的结果,RNN 中的反向传播过程需要相应地进行修改。这种修改后的反向传播版本被称为BPTT

它涉及到在时间上“展开”RNN,这意味着时间步被处理为深度神经网络的不同层。一旦网络展开,就应用标准的反向传播算法——也就是说,在每个时间步计算网络的误差,计算梯度,然后使用这些梯度来更新网络中的权重。

RNN 的局限性——梯度与短期记忆

在 RNN 中,作为 BPTT 过程一部分执行的展开可能导致处理长序列时非常深的网络。记住,梯度消失和爆炸是由于微积分中的链式法则。随着梯度通过与长序列相关的深层网络反向传播,这可能会使梯度消失和爆炸的问题更加突出。

这也影响了 RNN 的“记忆”。随着序列变长,反向传播更新早期时间步梯度的能力越来越小(在梯度消失的情况下)。这导致网络“忘记”较长序列中的早期时间步,这意味着 RNN 通常限于处理短序列。

梯度消失和爆炸问题以及短期记忆限制导致了更先进的 RNN 架构,如 LSTMs 的发展,这些架构可以解决这些问题。我们将在下一节中更详细地讨论。

LSTMs

LSTM 是一种专门设计来克服传统 RNN 局限性的 RNN,尤其是在处理长序列时,如我们在上一节中讨论的梯度消失和爆炸问题。

除了我们在RNN部分描述的隐藏状态机制外,LSTMs 还引入了一个称为细胞状态的概念。这通常被比作一种贯穿整个 LSTM 网络链的传送带,这使得信息在处理过程中可以轻松地在多个步骤之间传输。隐藏状态仍然充当网络的短期记忆,而细胞状态充当长期记忆。

LSTMs 还引入了的概念,这些门可以看作是传送带上的检查点,决定应该保留、丢弃还是添加哪些信息。通过这种方式,门调节了网络中信息的流动。通常有三种类型的门:

  • 输入门,它使用新信息更新细胞状态

  • 输出门,它使用细胞状态来确定下一个隐藏状态应该是什么

  • 遗忘门,它决定从细胞状态中丢弃哪些信息

如果你想了解更多关于这些门控机制如何与隐藏状态和细胞状态结合使用的信息,我建议阅读原始论文(Hochreiter and Schmidhuber, 1997)direct.mit.edu/neco/article-abstract/9/8/1735/6109/Long-Short-Term-Memory

说到门控机制,最近引入了一种名为门控循环单元GRU)的 LSTM 变体(Cho et al., 2014)。它将遗忘门和输入门合并为一个更新门,并合并了细胞状态和隐藏状态,从而产生了一个更简单、更高效的模型。

接下来,我们将讨论近年来 AI/ML 行业最重要的突破之一:Transformer 架构。

Transformers

与大多数研究领域的情况一样,进步的速度通常以某种线性的速度进行,在时间线上偶尔会有变革性的突破。任何领域的线性进步代表了持续进行的逐步进步,而变革性的突破则代表了突然的、巨大的飞跃,完全改变了所有事物。当谷歌发明了 Transformer 架构(Vaswani, A., et al., 2017)时,这是 AI/ML 研究中的一次巨大飞跃,它构成了我们现在在世界范围内经历的生成式 AI 革命的基石。

从 RNNs 到 LSTMs 的进展是我认为的线性发展。然而,从 LSTMs 到 Transformer 架构的进展是 AI/ML 技术发展中的一个巨大飞跃。

首先,与 RNNs 和 LSTMs 不同,它们是逐步处理序列的,Transformer 可以同时处理整个序列(并行),这种并行处理使它们能够更有效地管理我们数据中的长距离依赖关系。这也使它们能够达到比以前模型架构更大的规模,从而产生了现在行业中最庞大、最强大的语言模型。然而,并行处理并不是 Transformer 架构最显著的特征。正如首次向世界介绍 Transformer 架构的论文标题所暗示的——“Attention Is All You Need”(arXiv:1706.03762 [cs.CL])——Transformer 的主要创新是自注意力机制,它允许模型权衡输入数据不同部分的重要性。例如,如果我们将一个句子(或序列)输入到 Transformer 模型中,自注意力机制允许模型理解整个句子及其内部关系(例如,单词之间的关系)。

转换器在序列上并行运行多个自注意力,这在论文中被称为多头注意力。希望你已经在我们链接到第九章时阅读了这篇论文,但如果没有,我强烈推荐阅读原始论文,以深入了解转换器如何工作的复杂细节,鉴于它们在人工智能/机器学习和生成式人工智能行业中的关键重要性。转换器是当前最先进的生成式人工智能模型的基础。

现在我们已经回顾了导致它们发展的进化步骤,我们准备进入下一章。但首先,让我们花点时间反思一下我们已经学到了什么。

摘要

在本章中,我们涵盖了通常由更高级的实践者使用的 AI/ML 重要概念,这些实践者对如何实现他们的 ML 工作负载有特定的需求或偏好,例如使用特定的框架,或者通过多个处理器并行化他们的工作负载。

我们首先讨论了 BQML,重点关注数据处理、数据分析与机器学习之间的紧密关系。我们学习了如何使用 BQML 训练和评估模型,以及如何使用 SQL 查询语法从该模型获取预测。

然后,我们讨论了我们可以用于我们的 AI/ML 工作负载的不同类型的硬件,以及我们在这本书中没有之前覆盖的流行工具和框架,例如 Spark MLlib、Ray 和 PyTorch。

接下来,我们深入探讨了卷积神经网络(CNNs)及其在计算机视觉中的应用,然后转向讨论特别适用于序列数据和使用案例(如自然语言处理 NLP)的神经网络架构,例如循环神经网络(RNNs)、长短期记忆网络(LSTMs)和转换器。我们深入研究了这些架构的内部工作原理,主要是为了理解导致生成式人工智能技术发展的进化步骤,这些技术将在本书剩余章节中概述。

最后,我们讨论了人工智能/机器学习中的分布式模型训练,包括为什么需要它,以及我们可以用来实现它的某些机制,例如数据并行和模型并行。我们还深入探讨了实现数据并行性的不同方法,例如使用集中式参数服务器,或者使用如环全归约这样的分布式协调机制。我们还探讨了联邦学习这一主题,以及它如何通过避免从设备传输数据的过程来帮助保护隐私。

接下来,我们将开始一段激动人心的旅程,我们将深入探索生成式人工智能的世界。请加入我,在下一章中开始吧!

第三部分:生成式 AI

在本部分,我们开始探索令人兴奋的生成式 AI 宇宙,它目前正席卷全球。本书的这一部分首先介绍了生成式 AI 的基本概念,并将其与“传统 AI”进行比较和对比。然后,我们继续探讨更高级的主题,并学习如何在 Google Cloud 中实现这些概念。本部分的最后一章将重点整合本书中我们所学到的核心概念,并概述了使用各种 Google Cloud 产品和服务构建 AI/ML 和生成式 AI 解决方案的指导方针。

本部分包含以下章节:

  • 第十五章**,生成式 AI 简介

  • 第十六章**,高级生成式 AI 概念和 应用

  • 第十七章**,Google Cloud 上的生成式 AI

  • 第十八章**, 将一切整合:使用 Google Cloud 和 Vertex AI 构建机器学习解决方案*

第十五章:生成式人工智能简介

生成式人工智能GenAI)无疑是现在大家都在谈论的术语。如果你还没有机会“亲身体验”GenAI,那么你很快就会了解到为什么它目前正席卷全球,当我们深入探讨我们可以用这套相对较新的技术做些什么时。在本章中,我们将探讨支撑 GenAI 是什么以及它与其他人工智能AI)/机器学习ML)方法的区别的一些概念。我们还将涵盖一些导致其迅速崛起的主要历史发展,以及它今天是如何被使用的例子。

我们将首先介绍一些基本概念,然后进入更复杂的话题以及各种生成式人工智能(GenAI)方法的演变,例如自编码器AEs)、生成对抗网络GANs)、扩散和大型语言模型LLMs)。鉴于这是一个入门章节,我们将主要为后续章节中更深入的探讨打下基础。具体来说,本章涵盖了以下主题:

  • GenAI 的基础知识

  • GenAI 技术和演变

  • LLMs

按照逻辑顺序,让我们从基础知识开始!

GenAI 的基础知识

本节介绍了在讨论 GenAI 时我们需要理解的基本概念,从对 GenAI 的概述开始!

什么是 GenAI?

我将通过关注区分 GenAI 与其他我们已讨论过的 AI/ML 方法的特点来开始解释这个主题。想想这本书中我描述的所有各种算法和方法,更具体地说,想想每种方法追求的主要目标。无论是我们使用scikit-learn中的线性回归来根据特征预测某个目标变量的数值,还是在 XGBoost 中使用逻辑回归来实现二元分类模型,或者在 TensorFlow 中使用时间序列数据来预测未来,都有一个共同的主题,那就是我们试图预测估计某事。

在这里要理解的关键概念是,我们各种复杂模型的输出通常是一个明确的数据点,要么是正确的,要么是错误的,或者至少尽可能接近正确。我们的模型通常基于模型在数据中学习(或估计)的关系产生一个单一、简单的答案。

即使是在像 K-means 聚类这样的无监督学习UL)方法中,模型也只是在数据中找到数学关系,并根据这些关系将数据点分类到不同的组中。

通用人工智能的引入所带来的巨大飞跃是,模型现在可以超越简单的“是”/“否”答案或基于纯粹数学计算和模式识别的数值估计。有了通用人工智能,模型现在可以创建(或生成)新的数据。这就是最大的区别,而且这一点的意义相当巨大!

退一步来说:当我年轻的时候,我以为人工智能研究可以设计出像人类一样思考的机器,这让我着迷,所以我开始学习机器学习算法是如何工作的。我相当失望地发现,尽管一些模型可以在“理解”消费者行为和准确推荐某人可能喜欢购买的产品方面做得非常出色,或者甚至根据与患者相关的输入数据诊断潜在的疾病,但这一切都是基于将大量数据输入到“学习”在数据中检测模式的数学算法中。那里并没有真正的“智能”,尽管科学仍然令人着迷。

通用人工智能(GenAI)模型能够超越特定的数学答案并创造新内容,这是在人工智能追求过程中的一大飞跃。与任何最新的顶级通用人工智能模型进行一次对话,我毫不怀疑你将会非常震撼于它们能够做到令人惊叹的事情,比如创作音乐、描绘一个富有想象力的场景、写一首吸引人的诗,或者创建一个网络应用程序。你将在本书的后面部分学习如何利用通用人工智能来实现许多不同的用例,我相信你也会同意这是一项重大的技术进步。

然而,重要的是要理解,通用人工智能模型所完成的惊人壮举仍然依赖于我们在这本书中已经涵盖的许多人工智能/机器学习概念。在核心上,通用人工智能通过理解和复制其训练数据中的底层模式和结构来工作,它仍然使用算法和神经网络NNs)来执行这些活动,尽管所使用的网络架构以及它们的使用方式都相当先进。在通用人工智能的情况下,目标不仅仅是解释数据,而是形成可以用来创造新事物的理解。让我们更深入地探讨这些主题,以更好地理解什么是使通用人工智能与其他人工智能方法不同的。

什么是非通用人工智能?

现在通用人工智能已经席卷全球,我们如何称呼它之前的所有人工智能/机器学习方法(即,本书中我们已经涵盖的大部分内容)?最流行的术语之一是“传统人工智能/机器学习”。你也可能听到它被称为“预测人工智能/机器学习”,因为目标通常是预测某事,或者在分类用例中被称为“判别人工智能/机器学习”。

深入探讨通用人工智能与非通用人工智能的区别

要理解生成式 AI(GenAI)与非生成式 AI 之间的基本区别,我们需要回顾一些支撑 AI/ML 的数学概念。别担心——我们只需覆盖到定义生成式 AI 与非生成式 AI 之间的区别所需的概念水平。

概率的角色

记住,数学概率是许多机器学习(ML)用例中的基本概念。例如,当我们要求一个模型将数据点分类到特定类别时,它很少会以 100%的确定性这样做。相反,它会计算数据点属于每个类别的概率。然后我们,或者模型本身,根据实现方式,可以选择概率最高的类别。

区分生成式 AI(GenAI)与传统 AI 的一个关键因素是概率在学习过程中的使用方式。让我们更详细地探讨这一点,从传统 AI 开始。

传统 AI 和条件概率

在传统 AI 的情况下,模型试图根据数据集中预测变量(或特征)的值来估计目标变量Y包含特定值的概率。这被称为基于输入特征值的目标变量值的条件概率。条件概率是在另一个事件已经发生的情况下发生事件的概率,它由以下公式表示:

P(B|A) = P(A∩B) / P(A)

这里,以下规则适用:

  • P(B|A) 是在 A 的条件下 B 的条件概率。

  • P(A ∩ B) 是事件 A 和事件 B 同时发生的概率。这也被称为“联合概率”,我们将在稍后更详细地探讨。

  • P(A) 是事件 A 发生的概率。

要理解条件概率,可以想象一个游戏场景,其中有三根稻草隐藏在我们的视线之外。在这三根稻草中,两根是长稻草,一根是短稻草。我们将轮流抽稻草,抽到短稻草的人输。每次轮到我们抽稻草时,都有特定的概率我们会抽到短稻草。

初始时没有抽稻草,所以在第一轮,抽到短稻草的概率是 1/3(或大约 33.3%)。现在,让我们想象我们抽了一根稻草,结果是一根长稻草。这意味着还剩下两根稻草,由于我们抽到了长稻草,这意味着还剩下一根长稻草以及一根短稻草。在下一轮,抽到短稻草的概率因此是 1/2(或 50%)。

这里需要注意的重要一点是,因为我们已经选择了一根长吸管,它会影响整个场景的概率分布。这是一个非常简单的概念示例。在 ML 中,可能涉及许多因素(即特征),导致可能影响结果的因素组合数量非常大。这就是为什么 ML 模型通常需要处理大量数据来学习这些特征组合中的模式。

将这一点映射回 ML 用例,考虑图 15.1中所示的数据集,它展示了 OpenML 中泰坦尼克号数据集的简化版本(www.openml.org/search?type=data&id=40945)。目标变量由survived列表示,并用绿色框突出显示。这代表了我们前面方程中的B。所有其他列的组合构成了输入特征,它们代表我们前面方程中的A,如红色框所示。本质上,这描绘了当 ML 模型学习根据输入变量的值来预测目标变量的值时,它是在问:“在A(即输入变量)的值给定的情况下,B(即目标变量)的概率是多少?”换句话说:“在A的情况下,B的概率是多少?”:

图 15.1:目标变量与输入特征的分离

图 15.1:目标变量与输入特征的分离

接下来,让我们看看概率如何在 GenAI 用例中以稍微不同的方式被使用。

GenAI 与联合概率

在 GenAI 的情况下,模型被设计来学习数据集的联合概率分布。正如我们在前面关于条件概率的方程中简要看到的,联合概率指的是两个或更多事件同时发生的概率。我们可以利用这一点来理解不同的变量或事件是如何相互关联以及它们是如何相互影响的。它表示如下:

P(A∩B) = P(A) × P(B)

这里,以下适用:

  • P(A)是事件 A 发生的概率

  • P(B)是事件 B 发生的概率

让我们再次用一个例子来更详细地描述这个概念。一个常见的类比是想象掷两个公平的六面骰子,并计算两个骰子同时显示某个数字的概率;例如:

  • 事件 A:第一个骰子显示 3

  • 事件 B:第二个骰子显示 5

这里,联合概率 P(A ∩ B)是当两个骰子静止时,第一个骰子显示 3 和第二个骰子显示 5 的概率。由于每次掷骰子都是独立的,每个面有 1/6 的概率出现,因此联合概率如下:

P(A∩B) = P(A) × P(B) = 1/6 x 1/6 = 1/36

这意味着两个骰子同时显示你预测的精确数字的概率是 1/36。这里要理解的关键点是事件是独立的,但有一个共享的概率分布来控制整体结果。

再次将此映射回机器学习用例,数据集中的联合概率分布包括目标变量以及输入变量,如图 15.2 中的红色方框所示。2*:

图 15.2:将目标变量与输入特征连接

图 15.2:将目标变量与输入特征连接

这里一个主要的不同点是,虽然判别模型使用条件概率来预测给定输入变量值的目标变量的值,但生成模型试图学习数据集的整体联合概率分布,包括目标变量。

通过学习数据集的整体联合概率分布,模型可以理解数据集是如何构建的,以及所有特征是如何相互关联的,包括目标变量。通过这种方式,通过准确近似训练数据集的构建方式,它可以估计如何创建在数据集中尚未存在但具有相似结构和组成的相似数据点——也就是说,它可以生成新的、相似的内容。

除了联合概率分布之外,今天的生成模型通过使用我们在本书中多次引用的著名论文《Attention Is All You Need》(Vaswani 等人,2017 年)中概述的注意力机制来学习数据集中的隐藏关系和结构。在注意力机制开发之前,模型主要平等地对待所有输入。考虑到所有输入特征(和相关隐藏特征)都携带信息,平等对待所有输入会导致信号与噪声比低,从而限制了学习和预测过程的有效性。例如,当模型试图预测句子中的下一个单词时,句子中不是所有先前的单词都对预测下一个单词有同等贡献。相反,最可能的下一个单词可能更多地依赖于(或与)句子中特定其他单词的存在。例如,考虑句子:“我加了一撮盐和一点[空白]。”当现代生成模型试图预测该句子的下一个单词时,它可能会预测单词“胡椒”。虽然单词“胡椒”必须在句子的整体语境中有意义(即,它将与句子中的其他单词有不同程度的关系),但单词“盐”对预测的影响可能比其他单词,如“一撮”,更大,而注意力机制有助于模型学习这些重要关系。

虽然本节主要关注 GenAI 和“传统 AI”之间的区别,但我还想提到,这种界限并不总是如此清晰,有时界限可能会变得模糊。

界限模糊

重要的是要理解,非 GenAI 和 GenAI 之间的界限往往变得模糊,因为许多应用结合了这两种方法。例如,一个分析文本并生成摘要的模型或应用可能会同时使用判别性和生成性过程。

以聊天机器人为例。聊天机器人通常通过“即时”构建句子来生成响应。构建句子的一个流行方法是基于句子中的先前单词预测最合适的下一个单词。这是一个使用条件概率的例子。然而,如果应用或模型只做这件事,那么它的能力将非常有限。为了生成复杂且连贯的响应,并遵循自然语言(NL)结构,模型需要学习到它生成响应的语言结构的准确表示(即,联合概率分布)。

另一个有趣的场景是使用 GenAI 生成新的数据,这些数据随后可以用作传统 ML 模型的特征。我的同事杰里米·沃茨(Jeremy Wortz)建议的一个例子是要求一个生成模型根据客户画像对歌曲进行评分(比如说 1 到 5 分),然后根据评分和“思维链推理”过程(即让 LLM 详细阐述其思维过程)生成的特征制作播放列表。我将在稍后更详细地描述思维链的概念。

既然我们已经讨论了 GenAI 和“传统 AI”之间的区别,我们将探讨导致 GenAI 演化的技术发展。

GenAI 技术和演化

正如我们之前讨论的,虽然 GenAI 和“传统 AI”之间有一些区别,但它们有着许多相同的历史。例如,在第一章中,我们讨论了 AI/ML 的简要历史,在第九章第十四章中,我们学习了各种类型的 NN(如循环神经网络(RNNs))、长短期记忆(LSTM)网络和 Transformers 的演变。所有这些概念和里程碑也适用于 GenAI 的历史和演变。鉴于 GenAI 是相对较新的 AI 子集,我们可以将其演化时间线视为 AI 总体演化的延伸。因此,本节中的主题建立在之前我们已经覆盖的内容之上。

GenAI 的演变本身可以构成一本书,为了本书的目的,全面覆盖所有对 GenAI 演变做出重大贡献的主要里程碑和发展将是不必要的详细信息级别。相反,我将从高层次总结一些最突出的里程碑和贡献性发展,例如马尔可夫链和隐马尔可夫模型(HMMs)、受限玻尔兹曼机(RBMs)、深度信念网络(DBNs)、AEs 和 GANs。

还需要注意的是,一些最初主要为了判别性用例开发的机制可以被重新用于生成性用例。例如,虽然简单的朴素贝叶斯分类器通常用于根据数据集中的特征预测给定类别(即,判别性用例的条件下概率应用),但由于它应用贝叶斯定理时(天真地)假设每个特征是独立的,该算法在训练过程中也能够学习数据集联合概率分布的近似。(要了解更多关于朴素贝叶斯分类器的工作原理,我建议查阅以下 URL 的论文:doi.org/10.48550/arXiv.1404.0933)。类似的重用也可以应用于更复杂的贝叶斯定理应用,如贝叶斯网络。

在深入探讨具体的 GenAI 方法之前,我想介绍两个重要的概念,这两个概念将构成本书余下部分讨论的许多主题的基础,被称为嵌入潜在空间

嵌入和潜在空间

第七章中,我们讨论了降维的话题,并使用了如主成分分析(PCA)这样的机制将我们的数据集特征投影到低维特征空间。这些低维特征空间可以被称为“潜在空间”,而我们在潜在空间中的数据表示可以被称为“嵌入”。让我更详细地解释这些重要概念,从嵌入开始。

嵌入

嵌入是数据在低维空间(即潜在空间)中的数值表示。它们可以被视为捕获原始数据意义或特征的数值“指纹”。例如,词嵌入捕获单词的意义,如果“king”和“queen”有相似的嵌入,语言模型可以推断两者之间的关系。模型还可以嵌入其他类型的数据,如图像、音频和图。

接下来,让我们更详细地探讨潜在空间的概念。

潜在空间

我们使用“潜在空间”这个术语来定义一个抽象的特征空间,其中数据集的内在属性或特征被表示。这个空间捕捉了数据中可能在其原始形式中不明显的基本结构和模式(因此得名“潜在”)。

重要的是要理解潜在空间及其维度以某种方式映射到原始特征。这意味着原始特征之间的关系被捕获为潜在空间中投影特征之间的关系(即,语义上下文以某种方式表示)。这些表示和映射通常在训练过程中由模型学习,因此通常不容易被人类解释,但也有一些方法可以通过我们为数据集的内容显式创建嵌入,我将在第十六章中更详细地描述。现在,我将简要解释嵌入和潜在空间是如何使用的。

使用嵌入和潜在空间

当模型为我们创建嵌入时,这些潜在空间中的表示可以以有趣的方式使用。使用这些数据最有用的方式之一是测量潜在空间中嵌入之间的距离,使用熟悉的距离度量,如欧几里得距离或余弦相似度。考虑到潜在空间中的嵌入捕捉了它们所代表概念的精髓,我们可以识别出可能与原始空间相似或相关的概念。一个例子是零售网站产品目录中的产品。通过嵌入产品细节并识别在潜在空间中彼此靠近的产品,我们的模型可以了解哪些产品可能彼此相关。然后,推荐系统可以使用这些信息来显示诸如“购买此商品的客户还购买了这些其他商品”之类的见解。

你可能会问,“为什么不在原始空间中执行相同类型的操作?”嵌入编码的过程将对象转换为向量,提供了一种更有效的方式来表示概念。此外,与处理单词和图像相比,机器学习算法和模型更喜欢与向量一起工作,因此这些向量化的表示更适合机器学习用例。

另一个突出嵌入效率的例子是当我们使用机器学习模型进行图像处理用例时。考虑包含数百万像素的高清图像,其中每个像素都被视为一个特征。如果我们有一个包含数亿张图像的数据集,并且每张图像都有数百万个特征,这可能导致极其计算密集的训练和推理处理。相反,将特征映射到低维特征空间将显著优化处理效率。此外,单个像素通常不传达很多意义;相反,通常是像素之间的关系和模式定义了图像所代表的内容。

我们将在本书的其余部分多次回顾嵌入和潜在空间的概念,因为它们是 GenAI 中的基础概念。现在,我已经介绍了这些重要概念,我们将开始探索各种重要里程碑和途径,这些途径导致了 GenAI 的发展,如图 15.3所示的高层次概述:

图 15.3:通用人工智能(GenAI)演变的里程碑

图 15.3:通用人工智能(GenAI)演变的里程碑

当然,在过去几十年中,除了图 15.3中所示的那些之外,还开发并发布了许多额外的 GenAI 模型和方法。但在这里,我专注于对 GenAI 演变影响最显著的、高层次里程碑和发展。让我们开始深入探讨每一个,从马尔可夫链和 HMMs 开始。

马尔可夫链和 HMMs

马尔可夫链的概念是由安德烈·马尔可夫在 1906 年提出的,它们基于所谓的马尔可夫性质,即在一个序列或场景中的下一个或未来状态只取决于当前状态。它们可以用来预测(因此生成)序列中的下一个项目。HMMs 将这一概念扩展到包括在给定场景中无法直接观察到的隐藏状态。一个非常简单的例子就是当前天气条件和雨伞销售之间的潜在相关性。如果我们可以直接观察到天气,并且我们看到现在正在下雨,那么这就是我们可以用于马尔可夫链来预测雨伞销售增加的可观察状态。另一方面,如果我们由于某种原因无法观察到天气(例如,我们可能在商场地下层的商店工作),但我们注意到雨伞销售增加,那么我们可以推测外面现在正在下雨。在这种情况下,天气的状态是隐藏的,但我们可以根据雨伞销售增加的次级可观察状态来推测下雨的概率。这将是 HMM 中隐藏状态的非常简单的表示。

我接下来要简要介绍的概念是 RBMs。

RBMs

玻尔兹曼机BMs)是一种基于能量模型EBM)的类型,它借鉴了一些物理学概念。“玻尔兹曼”指的是路德维希·玻尔兹曼,一位与统计力学相关的物理学家,统计力学使用统计学和概率论来模拟微观粒子的行为。玻尔兹曼概率分布(也称为吉布斯分布)根据系统的能量和温度提供系统处于特定状态的概率。这里的一个关键概念是,能量较低的状态比能量较高的状态更有可能发生。

将其映射到数据科学:与传统 AI 中描述的先验概率不同,EBMs 使用“能量函数”为每个变量的可能配置分配一个值,其中较低的“能量”值代表更可能或更理想的配置。

由于杰弗里·辛顿和鲁斯兰·萨拉胡丁诺夫的工作,玻尔兹曼机被精炼成 RBMs,这是一种由两层组成的人工神经网络ANN):

  • 可见层,它代表输入数据(例如,图像中的像素或句子中的单词)。

  • 隐藏层,它学会捕捉数据中的高级特征和依赖关系。这与我们之前介绍的“潜在空间”概念相关。

使用 RBMs,学习过程涉及调整可见层和隐藏层之间的权重,以最小化所谓的重建误差,这衡量了 RBM 能够多好地重现原始输入数据。通过这样做,RBM 学会模拟输入数据的概率分布。

在原始玻尔兹曼机中,所有层都是相互连接的,模型相当复杂,训练起来计算量很大。然而,在 RBMs 中,尽管可见层和隐藏层之间是完全连接的,但层内没有连接(因此得名“受限”),这使得它们在训练时计算量较小。

RBMs 通常用于 UL 用例,尤其是在特征提取和降维方面,它们也可以被视为深度学习DL)的一种构建块,可以用来构建许多其他类型的模型,包括分类和回归。使用 RBMs 作为构建块的想法让我想到了下一个话题:DBNs。

DBNs

DBNs 可以被视为由 RBMs 等简单无监督网络组成的组合,其中每个子网络的隐藏层作为下一个子网络的可见层。通过堆叠多个 RBMs,每一层都可以学习数据越来越抽象和复杂的表示。

训练 DBN 包括两个主要阶段:预训练和微调FT)。在预训练期间,DBN 以无监督的方式逐层训练。每一层都被训练为一个限制性玻尔兹曼机(RBM),它学会表示从下层传递过来的特征。这种逐层预训练有助于以使后续的微调阶段更有效的方式初始化网络的权重。

在预训练之后,一个深度信念网络(DBN)可以从它所学习到的表示中采样生成与原始数据集相似的新数据。我们还可以使用监督学习SL)方法来微调网络以适应更具体的应用。

我在本章中迄今为止概述的每个技术和算法都是我认为是基本里程碑和概念构建块,这些里程碑和构建块有助于推动我们今天看到的更高级的生成式人工智能(GenAI)应用的发展。接下来我将概述的两个方法在 GenAI 的演变中是重要的步骤。我将介绍的第一个概念是自动编码器(AEs)。

自动编码器

我们用于机器学习用例的大多数——如果不是所有——数据集都代表具有内在属性(或特征)的特定概念;例如,人、汽车、医学图像,甚至是更具体的概念,如登上泰坦尼克号的人或在公司网站上购买的商品。

在判别式机器学习(ML)用例的情况下,模型通常试图根据与所表示概念每个实例相关的特征值来预测某种输出。例如,根据他们之前的购买历史,哪些客户可能会购买某个特定的产品?

相反,在生成式人工智能(GenAI)的情况下,模型通常被期望生成代表训练数据集中原始概念的新数据点。例如,如果一个模型在许多不同概念(如猫和摩托车)的图像上进行了训练,那么可能会要求它绘制一张猫骑摩托车的卡通图像。为了做到这一点,模型需要“理解”这些概念是什么。

在本章的早期,我们介绍了嵌入和潜在空间的主题,其中定义了数据集中数据点的潜在表示。在潜在空间中创建嵌入的过程可以被称为编码,自动编码器(AEs)是一种用于对数据集的高效表示(编码)进行无监督学习(UL)的 ANN。从高层次来看,自动编码器接收输入数据,将其转换为更小、更密集的表示,该表示捕获数据的本质,然后尽可能从该表示中重建输入数据。让我们深入了解它们是如何工作的。

自动编码器的工作原理

自动编码器通常由三个主要组件组成:编码器、潜在空间(也称为瓶颈)和解码器,如图图 15**.4所示:

图 15.4:AE 架构

图 15.4:AE 架构

在自动编码器(AE)的前向传递过程中,每个输入数据点都会通过网络中的编码器部分。这一部分网络将输入压缩成潜在空间(隐藏层)中更小、更密集的表示。然后,编码后的数据会通过网络中的解码器部分,解码器试图从压缩的表示中重建原始输入数据。这是自动编码器(AE)与传统、判别性模型之间有趣的不同之处——也就是说,传统模型通常试图根据输入(X)预测输出(Y),而自动编码器(AE)则试图预测(或生成)原始输入(X)。

就像我们在传统的神经网络中所做的那样,我们可以计算输出值与预期值(X)之间的差异,这被称为重建误差,然后我们可以使用反向传播来更新网络并继续常规的训练周期。重建的质量取决于自动编码器(AE)在潜在空间中学习表示数据的程度。

在这个训练过程中,编码器学习只保留数据中最相关的特征,有效地学习了一种在较小维度的空间中表示输入数据的新方法。潜在空间随后包含了网络学习到的关于数据的压缩知识——即数据的本质。再次引用我的同事 Jeremy Wortz 的描述,瓶颈特征的概念与嵌入的质量相关;由于我们通常在编码器和解码器之间“挤压”我们最关键的信息,因此特征的重要性被隐式优化。

然而,需要注意的是,尽管自动编码器(AE)可以学习重建原始数据集,从而学习如何执行降维以在低维空间中准确表示数据,但它们并不是为了生成新数据而设计的。为了实现这一功能,我们需要将概率分布引入图像中,这就是变分自动编码器(VAEs)发展的原因,我将在下面描述。

VAEs

VAE 通过引入概率方法扩展了自动编码器(AE)的概念,以生成与训练数据结构相似的新数据点。基于我们关于自动编码器(AE)如何工作的讨论,描述 VAE 的最简单方法就是强调它们与常规自动编码器之间的细微差别。

与传统的自动编码器(AE)一样,变分自动编码器(VAE)由编码器和解码器组成。然而,与常规的自动编码器不同,VAE 中的编码器将输入数据映射到潜在空间上的概率分布。这需要很多内容,所以让我们进一步澄清。

如我们在前一节所学,常规的 AE 将输入数据编码成一个包含表示原始输入的潜在特征的向量。然而,在 VAEs 的情况下,编码器不是为每个数据样本学习潜在空间中的单个点,而是学习概率分布。更准确地说,编码器不是在潜在空间中输出特定的特征值,而是输出描述潜在空间中特征概率分布的参数(如均值和标准差)。这个分布代表了编码器认为输入数据应该被编码的位置。这种方法在编码过程中引入了随机性或可变性,这对于可能生成与输入数据相似的新数据点至关重要,而不仅仅是原始数据的重建。

以下是在输入通过 VAE 时执行的高级步骤:

  1. 编码器提供潜在空间内概率分布的参数。

  2. 从这个学习到的分布中采样一个点。

  3. 然后将这个采样点通过解码器,解码器试图从这个概率编码中重建输入数据。

目标,再次强调,是使原始输入与其重建之间的差异最小化,类似于常规的 AE。

然而,除了重建误差之外,VAEs 在其损失函数中还有一个额外的项,被称为Kullback-LeiblerKL)散度,它衡量了每个输入学习到的分布与标准正态分布偏离的程度。不深入数学细节,重要的是要理解 KL 散度正则化强制在潜在空间中保持平滑和连续性,这使得模型更加鲁棒,并有助于减少过拟合。

在本节中,我们讨论了一些复杂细节,但关键要点是 VAEs 引入了概率机制,使它们能够超越仅仅重建输入数据,并开始生成新的、类似的数据点。

我们现在已经深入到生成模型的领域,接下来我将概述 GANs 的方法。

GANs

我们在第九章中简要介绍了 GAN,在本节中,我们将更详细地探讨它们。你可能熟悉“深度伪造”的概念,其中 AI 被用来创建逼真的图像或电影或音频轨道。通过“逼真”,我们指的是看起来像真实照片或视频的合成数据,而通过“音频逼真”,我们指的是听起来像真实音频录音的合成数据。GAN 是生成模仿真实世界数据的合成数据的一种流行机制。与任何技术一样,GAN 可能被用于恶意目的,例如未经同意生成真实人物的深度伪造,但它们有许多有用的应用,我们将在稍后介绍。然而,让我们首先深入了解 GAN 是什么以及它们是如何工作的。

高级概念——生成器和判别器

“生成对抗网络”(Goodfellow et al., 2014)这个名字可能听起来有些抽象,但它完美地描述了这种用于生成式人工智能(GenAI)的方法中所使用的概念。简而言之,GAN 的实现包括两个神经网络,它们以对抗的方式工作(即,它们相互对抗),其中一个网络生成合成数据,而另一个网络试图确定数据是否真实。生成数据的网络被称为,不出所料,生成器,而试图确定数据真实性的网络被称为判别器。主要前提是生成器试图欺骗判别器,让它相信数据是真实的。

可以想象,拥有一个有效的生成器是 GAN 最重要的要求之一,但同样重要的是要有一个有效的判别器,因为判别器可以被视为生成数据的质量控制QC)机制。如果你有一个无效的判别器,它很容易被不准确地模仿真实数据的数据所欺骗。你的判别器在识别伪造数据方面越有效,你的生成器就需要越努力地工作来创建逼真的数据。因此,为了使 GAN 能够创建高质量的数据,对抗伙伴的双方都需要得到有效的训练。

常用来描述这一过程的类比是想象一个想要伪造昂贵艺术品的人(即,一个伪造者)和另一个致力于识别艺术品是否为真或伪造的人(即,一个艺术专家)。一开始,伪造品可能是容易识别为赝品的业余尝试。然而,随着伪造者改进他们的作品并学会创造更令人信服的伪造品,艺术专家必须变得更加擅长识别区分真艺术品和伪造艺术品之间的细微差别。然后,这个周期就会重复,直到理想情况下,生成器创建的数据与真实数据无法区分。

深入了解——GAN 训练过程

在 GAN 中,两个网络通常是卷积神经网络CNNs)。判别器通常是一个二元分类器,它将数据分类为真实或伪造。这意味着其训练过程涉及许多我们在这本书的早期章节中已经熟悉的步骤,其中我们训练了分类器模型。

例如,让我们假设我们想要生成猫的图像。判别器可以通过在标记的数据集上进行训练来学习识别猫的图像。在这个数据集中,一些输入是真实的猫的图像,并且相应地进行了标记。

正如我们在第九章中简要提到的,生成器和判别器进行一种对抗游戏。在这场游戏中,判别器的目标是最小化分类猫图像的错误率(也就是说,它尽可能准确地识别猫的图像)。另一方面,生成器试图最大化判别器的错误率。由于游戏参与者的目标是对立的,其中一方希望最小化某个指标,而另一方希望最大化相同的指标,因此这被称为最小-最大游戏。

除了在标记的训练数据集上训练判别器外,判别器还会接收到生成器的输出,并被要求对这些输出进行分类,如图15**.5所示:

图 15.5:GAN(来源:https://developers.google.com/machine-learning/gan/gan_structure)

图 15.5:GAN(来源:https://developers.google.com/machine-learning/gan/gan_structure)

如果判别器认为一个数据点是真实的,而实际上它是被生成器创建的,这算作一个错误。因此,这会增加判别器的错误率,这对生成器来说是一个胜利。相反,如果判别器能够准确地将数据点分类为伪造的,那么它就会降低判别器的错误率(当然,这对判别器来说也是一个胜利)。

当判别器使用典型的机制,如梯度下降,从其错误中学习并最小化损失时,生成器也可以从判别器的错误中学习,并通过一个旨在增加判别器错误率的反向过程调整其权重。这是 GANs 使用的创新方法,在训练过程中,生成器不会直接接收到“好”或“坏”的直接标签,而是接收到关于判别器性能的反馈。如果判别器能够准确识别出伪造的,那么梯度就会发送回生成器,以便它能够更新其权重,在下一轮中创建一个更能欺骗判别器的输出。

在这个过程中,生成器学习真实数据的潜在概率分布,并变得更加擅长生成与该概率分布一致的新数据(即具有与真实数据相似属性的新数据)。同时,了解每个网络在训练过程中轮流进行也很重要。当生成器正在训练时,判别器的权重被冻结,反之亦然。

通过以这种方式让模型相互对抗,它们必须不断变得更好才能超越对方。随着判别器在识别伪造数据方面变得更好,生成器学会生成更逼真的数据来欺骗判别器,如此循环。

自从 2014 年由 Ian Goodfellow 和同事们首次创建以来,GANs 获得了极大的流行,出现了多种不同类型的 GAN 实现,例如 条件 GANscGANs)、CycleGANs、StyleGANs、深度卷积 GANsDCGANs)和渐进式 GANs。对所有这些变体的全面讨论将超出本书所需的详细程度。如果您对这些变体有特别的兴趣,我鼓励您进一步研究。

重要提示 – 注意“模式崩溃”

除了在训练许多类型的神经网络架构时面临的典型挑战,如梯度爆炸和梯度消失,GANs 还经常遭受与它们的对抗训练过程相关的特定挑战。这个问题被称为“模式崩溃”,指的是生成器可能开始产生有限种类的输出,尤其是如果这些输出成功地欺骗了判别器。由于生成器的主要目标是欺骗判别器,它可能学会生成有效的模式来做到这一点,但这些模式并不能准确代表目标数据分布。这是一个持续的研究领域,其中正在引入新的机制来对抗这种现象。

接下来,让我们讨论一些 GANs 的常见应用。

GANs 的应用

除了生成逼真的图像和逼真的音频数据外,GANs 还可用于其他有趣的用例,例如风格迁移和图像到图像的翻译。例如,一些在线服务允许你上传一张照片,并将其转换为卡通或模仿梵高等著名艺术家的风格,使其看起来像油画。虽然这些应用很有趣,但 GANs 还被用于各种用例,如文本生成、新药发现以及其他类型的合成数据生成。

我们将在后面讨论高质量合成数据的重要性,但接下来,我想介绍另一种流行的 GenAI 方法,称为 扩散

扩散

扩散被用于许多与 GANs 相同类型的用例,如图像和音频生成、图像到图像的翻译、风格迁移,甚至新的药物发现。然而,扩散使用不同的方法,并且对于某些用例通常提供更理想的结果。在本节中,我们将深入了解扩散模型和 GANs 之间的差异,但首先,像往常一样,让我们了解什么是扩散以及它是如何工作的。

高层次概念——噪声和去噪

在高层次上,扩散主要由两个主要步骤组成:

  1. 向图像添加噪声

  2. 反转这个过程——即去除噪声以回到原始图像

我将更详细地描述这些概念,首先从阐明向图像添加噪声的含义开始。图 15.6显示了包含噪声的图像:

图 15.6:噪声图像(来源:https://commons.wikimedia.org/wiki/File:256x256_Dissolve_Noise_Texture.png)

图 15.6:噪声图像(来源:https://commons.wikimedia.org/wiki/File:256x256_Dissolve_Noise_Texture.png)

如果你们中的一些人曾经看到过图 15.6所示的图像,那么你们可能对在电视屏幕上未调谐到提供图像信号的频道时显示的噪声很熟悉。这个图像纯粹由噪声组成,我们无法辨认出任何可辨别的形状。然而,如果我们向一张高质量的图像添加一些噪声,那么它就会变得有些模糊,但我们仍然可以辨认出图像中的内容,只要添加的噪声不是太多。我们添加的噪声越多,识别图像内容就越困难。

这个概念在训练扩散模型时的噪声过程中被使用。我们向图像添加少量噪声,使其逐渐难以识别图像中的内容。这也被称为正向****扩散过程。

然后,反向扩散去噪过程试图从一个噪声图像中恢复,并逐步回到原始图像。这听起来可能有点没有意义——也就是说,为什么要费心向图像添加噪声,然后再训练一个模型来学习如何去除噪声以生成原始图像?好吧,正如 GANs 的情况一样,我们正在训练我们的模型来理解原始数据集的概率分布。更深入一点,我们的模型实际上学会了预测输入中的噪声。因此,过程的下一步就是简单地从输入中去除噪声,以便估计或生成所需的去噪输出。

这个被称为扩散的原因可能有些不言自明,但更具体地说,这个名字与非平衡热力学领域的一个概念有关。这听起来有点复杂,但不用担心——我们不会深入探讨物理概念,只是简要介绍为什么它被这样命名。

常常用来解释这个概念的类比是想象将一滴墨水添加到水桶中。当墨水被添加到水中时,最初,它在桶中一个特定的位置占据了一小片空间。然而,随着时间的推移,墨水会在整个水桶中扩散。很快,它就遍布了整个水桶,水桶中包含着水和墨水的混合物。水桶中内容的颜色可能与你添加墨水之前存在的颜色不同,但已无法确定墨水在水桶中的具体位置。这就是正向扩散过程,其中墨水在整个水桶中的水中扩散。

在物理世界中,这种扩散过程通常是不可能逆转的——也就是说,无论你尝试做什么,你都无法将墨水从水中分离出来,并将墨水滴重新凝结回最初添加到桶中的位置。

然而,在机器学习中的扩散过程中,我们试图逆转这个过程,回到原始输入状态。

深入探讨

重要的是要理解噪声是以受控方式添加到数据中的。我们不仅仅添加完全随机的噪声,而是添加所谓的高斯噪声,这意味着噪声具有“正常”(或“高斯”)概率分布的特征。作为复习,高斯分布由熟悉的“钟形曲线”表示,如图 15**.7所示:

图 15.7:高斯分布

图 15.7:高斯分布

如我们在图 15**.7中看到的那样,高斯分布是对称的,其均值位于钟形曲线的中心。曲线的宽度代表分布的方差(或其平方根,即标准差)——也就是说,我们可能会看到与分布相符合的数据点距离均值有多远。在高斯分布中,最有可能发生的数据点出现在均值附近,而较少见的数据点则离均值更远。在图 15**.7中,均值为 0,标准差为 1,这是一种被称为标准正态分布的特殊类型的高斯分布。通过使用正态分布的噪声,我们可以通过调整分布的方差来轻松改变噪声的强度。

除了通过确保其符合正态分布来控制噪声外,我们还在训练过程中以可控的方式引入噪声,通过逐步向我们的源图像添加噪声,而不是一次性添加过多噪声。以这种方式添加噪声是根据一个时间表进行的,在这个过程中,在不同的时间间隔内添加更多的噪声。记住,正如我们在本章前面的部分所讨论的,在生成过程中随机化很重要,因为我们不仅想要从原始数据集中生成精确的图像,而是想要生成相似的图像。

为了在过程中引入一些可控的随机化,每一步中添加噪声的均值和方差是不同的,我们还在时间表的各个部分添加不同数量的噪声。每次添加噪声,我们就在马尔可夫链中形成一个步骤。如您在本章前面的部分所记得,马尔可夫链中的每一步只依赖于直接 preceding 它的步骤,这在反向扩散过程的上下文中非常重要。当我们每一步(在正向扩散过程中)添加噪声时,我们正在训练我们的模型来识别(或预测)已经添加的噪声。然后,在反向扩散过程中,我们从一个噪声图像开始,我们想要尝试生成马尔可夫链中前一步的图像,并以此方式逐步通过链,直到我们回到原始图像的近似。

为了更详细地描述这个过程,想象一下我们从一个猫的图像开始,我们逐步在每一步添加噪声,直到最终我们得到一个与图 15**.6相似的图像,该图像几乎完全是噪声。试图从如此极端的噪声图像跳回到猫的图像是非常困难的,所以我们相反地训练我们的模型,使其能够逐步反向通过马尔可夫链中的每一步,预测每一步中添加的小量噪声。随着我们的模型越来越好,它能够更清楚地区分噪声和原始数据集的潜在概率分布。这种对概率分布的理解使我们能够通过从纯噪声开始并迭代去噪,根据模型所学的知识来采样新的图像。

在本节的开始,我承诺要概述一些扩散与 GANs 之间的重要差异。让我们接下来看看这些差异。

扩散与 GANs 的差异

我在 GANs 训练的上下文中提到了模式坍塌的概念,以及这如何可能引入训练过程中的不稳定性。扩散使用了一个更稳定的训练过程,但扩散模型需要许多步骤来生成数据,这可能会计算密集。一些最近的进展旨在减少所需的步骤和计算成本,但这仍然是扩散模型的一个显著考虑因素。

类似地,在推理时间,从扩散模型中生成样本可能计算成本很高,而 GANs 可以更快地生成样本,因为它们只需要通过生成网络的单次正向传递。

那么,哪种方法最好呢?好吧,这是一个根据特定用例的业务需求选择正确工具的问题。

接下来,是时候讨论可能是最近 GenAI 世界中的巅峰之作:LLMs 了。

LLMs

这又是一个技术名称非常准确地描述了该技术是什么的例子;LLMs 是大型模型,特别适用于基于语言的使用案例,例如大量文本数据的摘要,或者能够与人类进行对话的聊天机器人。

在幕后,它们使用统计方法根据提供的上下文处理、预测和生成语言。它们在包含大量文本信息的多样化数据集上进行训练,从书籍和文章到网站和人类交互,使它们能够学习语言模式、语法和语义。

它们有多大呢?好吧,截至 2024 年 2 月撰写本文时的一些最新模型由数十亿甚至数万亿个参数组成。这相当巨大!二十年后,有人可能会读到这本书并嘲笑我们把这些大小视为巨大,但这些都是目前地球上最大的模型,并且与之前存在的任何模型相比,它们构成了巨大的进步。

在深入探讨 LLMs 是如何创建的细节之前,让我们先看看一些历史里程碑,这些里程碑导致了它们的演变。

LLMs 的演变

语言模型的历史始于简单的基于规则的系统,这些系统使用手工编写的规则来解释和生成语言。事实证明,试图手工编写人类语言的所有复杂规则是非常不切实际的,但这一领域的研究必须从某个地方开始。

接下来,统计方法如 N-gram 模型使用概率来预测一系列单词的可能性。它们在大规模文本上进行了训练,能够比基于规则的系统捕捉到更多的语言细微差别,但它们在处理文本中的长期依赖关系方面仍然存在困难。

向前迈出的下一步是使用如 HMMs 和简单的 NNs 等模型进行语言任务,虽然这些模型通过学习数据中的更高级模式提供了更好的性能,但它们在复杂性方面仍然有限。

当科学家开始将深度神经网络(DNNs)应用于语言用例时,重大突破开始了。在第九章第十四章中,我们讨论了 RNNs、LSTM 网络和 Transformers 的演变,以及它们如何各自使语言处理变得更加复杂。行业中的一个关键事件是谷歌发明了 Transformer 架构(Vaswani 等人,2017 年),这已成为今天行业中最庞大和最先进的 LLMs 的主要技术。

当我们在第一章中讨论人工智能/机器学习的整体演变时,我提到,不仅更复杂的机器学习算法的发展导致了我们在最近几十年看到的突破,而且计算能力的进步和可用于训练模型的数据的激增也起到了作用。这些因素共同形成了一种生态系统,我们在其中共同推进所有这些技术。

接下来,我们将深入了解 LLMs 是如何创建的。

构建大型语言模型(LLMs)

让我们一开始就澄清一件事;由于两个主要原因,你或我不太可能从头开始创建自己的 LLMs:

  • 训练 LLMs 需要极其大量的数据。例如,你或我会与之交互的一些 LLMs 是在整个互联网上训练的。这就是它们如此强大和知识渊博的原因之一;它们不仅训练了人类所创建的所有公开可用的数据,还训练了一些由训练它们的公司拥有或获取的私有和专有数据集。

  • 由于需要大量的计算能力,训练 LLMs 通常极其昂贵。我指的是使用数千个高性能加速器,如最新的 GPU 和 TPUs,连续数月来训练这些模型,而这些东西并不便宜!

因此,大多数人公司和公司将使用已经预训练的 LLMs,我将在下面进行描述。

LLM 训练过程

虽然构建商业可用 LLMs 的公司几乎肯定在幕后使用了大量的秘密魔法,他们不太可能对外分享,但以下这些高级步骤通常涉及在 LLM 训练过程中:

  • 无监督或半监督预训练

  • 监督微调

让我们更详细地看看这些内容。

无监督或半监督预训练

记得本书前面的活动中提到的,监督训练需要标记的数据集,这可能很麻烦,而且获取或创建成本高昂。考虑到 LLM 通常是在大量数据上训练的,比如整个互联网,标记所有这些数据是不可能的。相反,使用一个非常巧妙的技巧来训练 LLM,这样它们可以从这些大量的文本中学习,而不需要显式标记,这个技巧被称为掩码语言模型MLM)。

MLM 实际上是一个非常简单但有效的概念;它本质上是一个“填空”游戏。你可能记得小时候玩过这个游戏,或者在考试场景中遇到过。简单来说,我们取一个句子,并掩盖(或掩盖)一个或多个单词,然后任务是猜测缺失的单词应该是什么。例如,考虑以下句子:

“你真的在最后那个评论中一针见血地指出了[空白]。”

你认为哪个词最适合用来填补那个句子的[空白]部分?如果你熟悉“一针见血”这个术语,那么你可能已经猜到“头”将是最佳选择,而且你的猜测是正确的。

这种方法在训练 LLM 时可以非常有效,因为我们可以向 LLM 提供数百万个句子,随机掩盖各种单词,并要求 LLM 预测正确的单词应该是什么。这种方法的优点是,掩盖的单词成为标签,所以我们不需要显式标记数据集。这就是为什么我们称这个过程为 UL 或半监督学习SSL)。例如,在 LLM 预测了要使用的单词之后,我们可以揭示句子中实际包含在掩盖位置上的单词,然后模型可以从中学习。如果模型预测了不同的单词,它将被视为错误,损失函数将在训练期间相应地反映这一点。

需要注意的重要一点是,模型在训练过程中可以看到数十亿个不同的句子,通过这样做,它可以看到单词在各种语境中的使用。随着时间的推移,它建立起对每个单词含义的理解以及它通常与哪些其他单词一起出现。从概念上讲,它可以建立起一个图,展示各种单词之间的关系,如图图 15.8所示:

图 15.8:单词关联图

图 15.8:单词关联图

图 15.8中,我们可以看到英语中各种单词之间的关系。注意有些单词可能是模糊的,比如单词“Turkey”,它可以指代国家、动物或食物。考虑以下句子:

  • “我真的很喜欢吃火鸡。”

  • “去年,我们去土耳其度假了。”

  • “我真的很喜欢土耳其的食物。”

假设 LLM 在训练过程中看到了所有这些句子。通过看到这些句子(以及数十亿个其他句子)并学习词汇在不同语境中的使用方式,LLM 形成了对词汇意义(或语义上下文)的概率理解。例如,它是如何知道“Turkey”这个词可能指一个国家,基于关于人们去那里度假的句子?嗯,通过在数百万或数十亿个句子中看到“vacation”这个词,它理解到人们去地方度假,所以在这个语境中,“Turkey”必须是一个地方。它也可能会看到包含“Turkey”和“immigration”这两个词的其他句子,并且会形成对移民不仅指地方,而且更具体地指国家的理解。它还会通过在许多其他语境中看到这些词来学习“country”这个词的含义以及它的复数形式是“countries”。同样,它学习到“eat”这个词指的是食物,所以在这个句子“我真的很喜欢吃火鸡”中,它理解到“turkey”必须是一种食物。

我在这里只展示了一小部分简单的句子,但我们已经可以看到不同潜在词汇组合的激增以及它们之间的关系。想象一下,当我们把互联网上的每一句话都纳入考虑范围时,组合的复杂性会有多大。这就是 LLM(大型语言模型)学习的内容:极其复杂的关联网络以及这些词汇所代表的概念的深层含义。这在智能方面是 LLM 为 AI 行业带来的巨大进步,而且这也是我们自己的大脑学习理解词汇的方式,这非常有趣。作为孩子,我们不仅学习单个词汇,而且学习词汇作为概念的代表,通常是通过形成关联图。例如,想象你是一个试图爬树的小孩子,你的父母说:“别爬那棵树,否则你可能会摔倒受伤。”你可能之前没有听过这些词汇,但通过听到这个句子,你可能会了解树、爬树、摔倒或受伤的概念,你也可能会直觉到摔倒和受伤是不希望发生的事情。

除了在句子中遮蔽单词之外,还有一种称为下一句预测NSP)的方法也可以用来训练我们的 LLMs,使其不仅能够预测单词,正如其名称所暗示的,还能根据提供的上下文预测整个句子。在这种情况下,LLM 会看到句子对,有时这些句子有自然的顺序关系(例如,文章中的连续两行),或者在其他情况下,它们是不相关的句子。LLM 的任务是判断第二个句子是否逻辑上跟随第一个句子,通过这样做,它学会了区分逻辑上连贯和不连贯的句子序列。这促使 LLM 在多个句子之间推理上下文,这有助于它在更长的响应请求中生成连贯的文本。

重要的是要注意,LLMs 的学习中还有一个额外的抽象层。在本章的早期,我们讨论了嵌入和潜在空间。一般来说,我刚才概述的关联发生在潜在空间中。潜在空间是 LLM 对世界的表示以及它所学习的所有各种概念和关联。具有相似意义或语义上下文的概念可能在潜在空间中彼此更近。

在 LLM 通过我刚才描述的过程从可用数据中学习到它能学到的一切之后,预训练阶段就完成了。在这个时候,LLM 已经建立了它对世界的潜在空间表示,下一步是教它如何对人类或其他机器的请求做出有用的响应。可以用于此目的的不同过程有很多,但我会从常见的监督调优实践开始。

LLMs 的监督调优

如我们所知,监督训练意味着我们有一个包含标签的数据集,这些标签可以用来教导一个模型。例如,如果我们想让我们的模型执行情感分析,我们可以在数据集中对短语进行标记,以反映这些短语所表达的情感,例如积极、消极或中性。同样,对于摘要,我们可以向模型展示好的摘要示例,模型可以从这些示例中学习。

虽然在预训练阶段通常需要巨大的数据集,但 LLM 的监督式调整需要更小的数据集,这些数据集需要精心策划和标记,以适应特定任务。考虑到 LLM 通常包含大量来自预训练阶段的知识,仅从调整数据集中的少量(或可能只有几百个)示例中就可以获得令人惊讶的调整结果。再次强调,这与人类逐步学习新技能的方式相似。例如,想象有两个人,其中一个人从未学习过开车,另一个人已经开车 20 年了。现在,我们希望这两个人都能在下周学会开大型卡车。谁更有可能成功?那个已经开车 20 年的人已经对交通规则和如何操作车辆有了很多知识,因此与从未开过车的人相比,学习如何开大型卡车只需要相对较少的增量学习。

同样重要的是要理解,我们可以应用各种不同的调整方法或级别。例如,少样本学习FSL)指的是一种实践,即我们只向 LLM 提供少量示例。我们甚至可以在我们的提示(即我们对 LLM 的请求)中提供这些示例,而不是需要提供专门的训练数据集。这对于某些任务可能是有效的,但当然,由于我们只提供了少量示例,所以这种方法相当有限。当示例与提示一起提供时,这是一个提示工程的例子,提示工程本身是一门新兴的科学,它专注于如何以产生最佳结果的方式向 LLM 提出请求。在这些情况下,底层 LLM 通常不会根据我们提供的示例进行重新训练。相反,LLM 只是使用提供的示例来调整其响应,使其与这些示例保持一致。

在光谱的另一端是全 FTFFT)。这种级别的调整可能需要数千个示例,并且模型的参数会根据这些示例进行更新(即模型学习并将新数据纳入其核心结构)。

然后,还有介于两者之间的级别,例如适配器调整,在这种调整中,适配器层被插入到原始模型中,并且只有这些层被调整和更新,而原始模型的权重保持冻结。另一种调整可能只关注更新模型的输出层,而其余模型保持不变。

在一个稍微独立但相关的方面,我想简要介绍从人类反馈中进行强化学习RLHF)这一主题。这种方法不是通过添加更多数据来更新 LLM,而是主要关注教会 LLM 以更符合人类的方式做出反应,例如与人类价值观保持一致。在这种方法中,LLM 可能会对一个提示提供多个响应,人类可以根据人类沟通和文化的细微差别(如语气、情感、道德考虑等许多因素)选择(并因此标记)哪个响应更受欢迎。我们在第一章中介绍了强化学习RL)的概念。在 RLHF 调整 LLM 的情况下,人类反馈被用作奖励信号,教会 LLM 生成更符合人类偏好的输出,即使可能存在多种技术上“正确”的响应方式。

我们将在下一章更详细地探讨调整,但在我们进入下一章之前,让我们反思一下到目前为止我们已经学到了什么。

摘要

我们以介绍支撑 GenAI 的基本主题开始本章,包括诸如嵌入和潜在空间等概念。然后,我们描述了 GenAI 是什么,以及它与“传统 AI”的区别,传统 AI 通常试图根据历史数据预测特定答案,例如收入预测或识别图像中是否含有猫,但 GenAI 超越了这些任务,并创造了新的内容。

我们探讨了概率在 GenAI 和传统 AI 中的作用,并讨论了传统 AI 通常如何使用条件概率根据数据集中特征的值来预测目标变量的值。另一方面,GenAI 的方法通常试图学习特征和目标变量的联合概率分布。

接下来,我们探讨了 GenAI 的演变以及导致我们今天使用的各种模型的各种模型开发里程碑。我们通过介绍早期发展,如马尔可夫链、HMMs、RBMs 和 DBNs 开始了这一探索。然后,我们介绍了更近期的进展,如 AEs、GANs 和扩散。

最后,我们深入到了 LLMs 的世界。我们通过回顾之前章节中关于 RNNs、LSTM 网络和 Transformers 的学习内容,突出了它们发展过程中的主要里程碑。然后,我们讨论了 LLMs 的训练过程,包括预训练阶段使用的各种机制,如 MLM 和 NSP,以及如何使用 FFT 来进一步训练针对特定用例的模型。

虽然这是我们书中 GenAI 部分的介绍章节,但我们已经相当深入地覆盖了许多重要概念,这将为我们剩余的章节提供一个坚实的基础。

在此基础上,让我们继续我们的 GenAI 之旅。

第十六章:高级生成式 AI 概念和应用案例

现在我们已经了解了生成式 AI(GenAI)的基础知识,是时候开始深入探讨了。在本章中,我们将介绍 GenAI 领域的更多高级主题。我们将从学习一些针对特定领域或任务的生成模型调优和优化技术开始。然后,我们将更详细地探讨嵌入和向量数据库的重要主题以及它们如何与使用检索增强生成(RAG)的新模式相关联,以将我们的大型语言模型(LLM)响应基于我们的数据。接下来,我们将讨论多模态模型,它们与基于文本的 LLM 有何不同,以及它们支持的使用案例。最后,我们将介绍 LangChain,这是一个流行的框架,使我们能够设计复杂的应用程序,这些应用程序可以建立在 LLM 提供的功能之上。具体来说,本章涵盖了以下主题:

  • 高级调优和优化技术

  • 嵌入和向量数据库

  • RAG

  • 多模态模型

  • GenAI 模型评估

  • LangChain

让我们直接深入探讨,开始学习高级调优和优化技术!

注意

LLM”这个术语在 GenAI 领域几乎成了同义词,但考虑到LLM代表大型语言模型,这个术语在技术上将其与语言处理联系起来。需要注意的是,还有其他类型的 GenAI 模型,例如一些图像生成和多模态模型,它们并不是严格意义上的语言模型。此外,一个更近的概念是大型动作模型大型代理模型LAMs)已经出现,它们结合了 LLM 的语言理解和生成能力,以及通过使用工具和代理与环境交互来执行动作(如规划和管理假期)的能力。然而,为了简单起见,在本书的其余部分,我将交替使用LLMGenAI 模型这两个术语。

高级调优和优化技术

在上一章的结尾,我们讨论了 LLM 以及它们的训练和调优。我提到了一些高级别的调优方法,在本节中,我们将深入探讨如何调优 LLM 以满足我们的特定需求。让我们首先概述我们如何与 LLM 互动,我们通常是通过提示来做到这一点的。

定义

提示是我们提供给 LLM 的一段文本或指令,以引导其响应或输出。它告诉 LLM 要做什么,在某些情况下,还提供了如何做的指导;例如,“总结这份财务文件,特别关注 2023 年第四季度 与公司业绩相关的细节。”

我们将要探索的第一个高级 LLM 调优技术是提示工程

提示工程

提示是我们可以用来调整 LLM 输出以满足我们特定需求的最直接方法。事实上,在 2022 年底和 2023 年初 GenAI 流行爆炸的早期,您可能还记得看到关于一种新兴的极高需求角色的新闻标题,称为提示工程师。在本节中,我们将讨论提示工程是什么,以及它如何被用来改进 GenAI 模型的输出,这将有助于解释为什么对这一领域有如此突然的需求增加。

为了开始我们的讨论,考虑以下提示:

Write a poem about nature.

这是一个非常简单的提示,它并没有向 LLM 提供很多关于我们希望它为我们写什么类型的诗的信息。如果我们想要特定的输出类型,我们可以在我们的提示中包含额外的指令,如下所示:

Write a poem about nature with the following properties:
Format: sonnet
Theme: how the changing seasons affect human emotions
Primary emotion: the poem should focus particularly on the transition from summer to autumn and the sense of longing that some humans feel when summer is coming to an end.

后者提示将生成一首更具体的诗,它遵循我们概述的参数。您可以自由尝试,访问以下网址,输入每个提示,看看不同的响应:gemini.google.com

注意

您可以使用上述网址测试本书中的所有提示。

这是一种基本的提示工程形式,它只是在提示中包含额外的指令,以帮助 LLM 更好地理解它应该如何响应我们的请求。我将在本节中解释额外的提示工程技术,首先概述一些制定有效提示的标准最佳实践。

核心提示设计原则

以下是我们创建提示时应记住的一些原则:

  • 清晰表达:我们应该清楚地了解我们希望 LLM 做什么,并避免使用含糊的语言。

  • 具体明确:使用具体指令可以帮助我们获得更好的结果。

  • 提供足够的上下文:如果没有适当的上下文,LLM 的响应可能不会与我们试图实现的目标相关。

我在上一个示例提示中包含了一些这些原则,我将在这里更明确地概述它们。在大多数情况下,由于 LLM 的纯粹和不断增长的多样性,提示尽可能清晰和具体是很重要的。例如,如果我要求 LLM 写一个关于幸福的小说,几乎无法知道它会想出什么样的细节。虽然这是 LLM 的一个美妙特性,但当我们希望 LLM 在特定参数内提供结果时,这可能会很具挑战性。

在我提供关于清晰性和具体性的额外示例之前,考虑一下我们可能不希望清晰和具体的情况,例如当我们还不确定我们的确切需求时,我们希望 LLM 帮助我们探索各种潜在选项。在这种情况下,我们可以从向 LLM 发送一个广泛的提示开始,如下所示:

Suggest ideas for a new business that will help me make money.

对于这样一个广泛的提示,LLM 可能会提出各种各样的随机想法,从烘焙蛋糕到开发帮助儿童学习数学的视频游戏。

在从 LLM 获得一些初步输出后,我们可以通过更具体地深入研究某些想法来迭代地改进这个过程。例如,如果我们非常喜欢为儿童开发视频游戏的想法,我们可以跟进一个更具体的提示,如下所示:

I want to develop a video game that helps kids to learn mathematics. The target audience will be kids between ten and fifteen years old, and the game will focus on algebra and precalculus. List and explain the steps I need to take to start this business.

如我们所见,这个提示比之前的提示更具体,可能会提供更针对性和可操作性的回应。这个更新的提示遵循了我们概述的所有原则,因为它在确切想要实现的目标方面是具体的(即开始创建视频游戏业务),它提供了上下文,例如游戏的内容和目标受众,并且它在我们希望 LLM 如何回应方面是清晰的(即列出并解释步骤)。

有时,我们需要提供大量的上下文,我们将在本章的后面讨论如何做到这一点。然而,接下来,让我们探讨如何使用链接来细化我们从 LLM 获得的输出。

链接

我在上一个章节中描述的过程,即我们将第一个提示的输出作为后续提示的输入,这个过程被称为提示链。这可以通过交互式过程,如聊天界面,或者使用我稍后将要描述的工具(如 LangChain)以自动化的方式完成。还有一个名为 ReAct 的框架,我们可以将多个动作链接在一起以实现更广泛的目标,我将在下一节中描述。

ReAct 和代理

我在本章的开头简要提到了 LAMs 的概念,在这里我将更详细地介绍它。

ReAct代表推理和行动,它是一个将 LLM 的推理能力与采取行动和与外部工具或环境交互的能力相结合的框架,这有助于我们构建超越简单生成内容的解决方案,以实现更复杂的目标。外部工具的例子包括软件、API、代码解释器、搜索引擎或自定义扩展。

通过使用 ReAct 超越生成内容,我们可以构建被称为代理的东西。代理的作用是解释用户期望的结果,并决定使用哪些工具来实现既定目标。在这里,我再次强调规划并预订假期的例子,这可能包括预订航班、住宿、餐厅预订和远足等活动。

链接不应与另一种名为思维链CoT)的提示工程方法混淆,我们可以使用它来帮助 LLM 处理复杂的推理任务,我将在下一节中描述。

思维链提示

CoT 提示涉及以引导模型通过逐步推理过程到达最终答案的方式创建提示,这与人类在解决问题时可能采取的方式非常相似。有趣的是,仅仅在提示中添加“逐步”这个词就可以导致模型以不同的方式响应,并以逻辑方式处理问题,而如果没有这些词,它可能不会这样做。我们还可以通过以逐步的方式描述任务来帮助模型。例如,考虑以下作为基线的提示,它没有实现 CoT 提示:

If an investor places $10,000 in a savings account with an annual interest rate of 5% and the interest is compounded annually, how much money will be in the account after 3 years?

我们知道 LLM 是大型语言模型,而不是大型数学模型,但我们可以通过教它逐步的过程来教 LLM 如何进行复杂的数学计算。如果 LLM 在提供准确答案时遇到困难,我们可以按以下步骤解释:

Annually compounded interest means the interest is added to the principal amount at the end of each year, and in the next year, interest is earned on the new principal. Based on that information, work through the following process step by step: If an investor places $10,000 in a savings account with an annual interest rate of 5% and the interest is compounded annually, how much money will be in the account after 3 years?

虽然模型可能无法立即提供所需的答案,但我们可以通过教它每个步骤应该发生什么来帮助它达到目标,然后它可以依次连接这些步骤以得到最终结果。要了解更多关于这个有趣的主题,我建议阅读标题为《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models》(Wei 等人,2022 年)的研究论文,该论文可在以下网址找到:

doi.org/10.48550/arXiv.2201.11903

接下来,我将介绍另一种流行的提示工程技术,我在第十五章中简要提到了它,称为少样本提示

少样本提示

本章中我包含的所有提示都是零样本提示的例子,因为我只是简单地要求 LLM(大型语言模型)做某事,而没有提供任何关于如何做那件事的可参考示例。

少样本提示是一个相当简单的概念,它仅仅意味着我们在提示中提供了一些示例,教 LLM 如何执行我们请求的任务。少样本提示的一个例子如下:

The following are some examples of product reviews, as well as the categorized customer sentiment associated with those reviews:
Review: "Sending this back because the strap broke the first time I used it." Sentiment: Negative. Properties: construction.
Review: "Love the color! It's the perfect size and seems well-made." Sentiment: Positive. Properties: appearance, construction.
Review: "Disappointed. The zipper gets stuck constantly." Sentiment: Negative. Properties: construction.
Based on those reviews and their associated sentiment categorizations, categorize the sentiment of the following review:
"The fabric feels flimsy, and I'm worried it might tear easily."

正如我们在提示中看到的那样,我指导了 LLM 如何对评论的情感进行分类,并提供了我想要 LLM 以特定格式响应的详细示例,包括情感似乎参考的具体产品属性。

在少样本提示的情况下,我们在提示中为 LLM 提供了一个迷你“训练集”,它可以使用这些示例来理解输入和期望输出之间的预期映射。这有助于 LLM 理解它应该关注什么以及如何构建其响应,希望提供更符合我们特定用例需求的结果。

虽然这些例子可以被视为包含在我们提示中的小训练集,但重要的是要注意,我们提供的示例不会改变底层 LLM 的权重。这对于大多数提示工程技术都是正确的,其中响应可能会根据我们的输入而显著变化,但底层 LLM 的权重保持不变。

少样本提示和提示工程通常可以出奇地有效,但在某些情况下,我们需要向 LLM 提供许多示例,并且我们希望进行增量训练(即更新权重),尤其是在复杂任务中。我将在稍后概述我们如何处理这些场景,但首先,我将介绍一个重要的新兴领域——提示管理。

提示管理实践和工具

虽然新技术带来了新的功能和机会,但它们通常也会带来新的挑战。随着提示工程的不断发展,公司面临的一个常见挑战是需要有效地存储和管理他们的提示。例如,如果公司的员工提出了提供出色结果的出色提示,他们希望跟踪和重用这些提示。随着时间的推移,LLM 和其他解决方案组件的演变,他们可能还希望更新提示,在这种情况下,他们希望跟踪提示的不同版本及其结果。

在软件开发中,我们使用版本控制系统来跟踪和管理我们应用程序代码的更新。我们可以将这些原则应用于提示工程,使用版本控制系统和模板来帮助我们有效地开发、重用和共享提示。执行高级提示工程实践的公司可能会最终为这些目的整理提示库和存储库。

提示模板可以用来标准化有效提示的结构,这样我们就不需要继续使用试错和重新发明轮子来创建最适合特定用例的提示。例如,想象我们在市场营销部门工作,我们运行月度报告来衡量我们营销活动的成功。我们可能希望使用 LLM 来总结报告,并且很可能有一些特定信息是某些团队成员每次都希望审查的。我们可以创建以下提示模板来制定这些要求:

Summarize the [Report Name] report for [Target Audience], considering that [Target Audience] is particularly interested in reviewing increases or decreases in [Metric 1] and [Metric 2].

现在,市场营销团队成员只需使用这个提示模板,并在模板中的每个占位符处填写他们希望使用的值。与个人提示一样,我们可以维护我们提示模板的不同版本,并评估每个版本的表现。

我们可能会在未来几年看到更多提示工程和提示管理方法的开发。除此之外,我们甚至可以将机器学习ML)技术应用于寻找或建议最适合我们用例的最佳提示,无论是通过让 LLM 建议最佳提示,还是通过使用传统的 ML 优化方法,如分类和回归,来寻找或建议可能导致给定用例最佳结果的提示。预计在这个领域将继续出现有趣的方法。

超越提示工程和管理,下一节将描述更大规模的 LLM 调优技术,这些技术主要可以归类在迁移学习TL)的范畴下。

TL

第十五章中,我简要提到 LLMs 通常经过一个无监督预训练阶段,随后是一个监督调优阶段。本节将更详细地描述一些用于微调 LLMs 的监督训练技术。让我们从 TL 的定义开始。

定义

TL 是一种机器学习方法,它使用一个已经在某个任务(或一系列任务)上训练好的模型作为新模型的起点,这个新模型将执行类似任务(或一系列任务),但参数或数据不同但有一定关联。

TL 的一个例子是,取一个在通用图像识别任务上预训练的模型,然后通过逐步在包含道路场景的数据集上训练,将其微调以识别与驾驶场景特别相关的对象。

TL 方法可以被看作是一种光谱,其中一些 TL 技术和用例只需要更新模型权重的一小部分,而其他则涉及更广泛的更新。光谱上的不同点代表了定制性和计算成本之间的权衡。例如,更新大量模型权重提供了更多的定制性,但计算成本更高,而更新少量模型权重提供了较少的定制性,但计算成本也更低。

让我们从光谱的一端开始讨论,在这一端我们将更新原始模型的所有或大部分权重,我们称之为完全微调

完全微调

在完全微调 LLMs 的情况下,我们可以从一个在大量数据上预训练并学习了对训练概念广泛理解的模型开始。然后,我们将该模型引入一个针对当前任务特定的新数据集(例如,理解交通规则)。这个数据集通常比初始预训练阶段使用的数据集更小、更专注。在微调过程中,模型所有层的权重都会更新,以最小化与我们新任务相关的损失。

有几点需要注意,全微调可能需要大量的计算资源,而且还有风险,即模型可能会忘记它在预训练期间学习的一些有用的表示(有时被称为灾难性遗忘),尤其是如果新任务与预训练任务有相当大的不同。

记住,LLMs 很大——实际上,它们非常大!考虑到这一点,许多公司可能会因为数据量、计算资源以及通常所需的费用而发现全微调不可行。

而不是调整巨大 LLM 中的所有权重,研究已经发现,有时我们只需更改一些权重,就可以在某些特定任务上获得有效的改进。在这种情况下,我们可以“冻结”模型的一些权重(或参数),以确保它们在更新时不会改变,同时允许其他权重更新。这些方法可以更高效,因为它们需要更新的参数更少,因此被称为参数高效微调(PEFT),我将在以下小节中更详细地描述,从适配器调整开始。

适配器调整

在适配器调整的情况下,原始模型层保持不变,但我们添加适配器层适配器模块,这些是插入到预训练模型层之间的小型神经网络(NNs),仅包含几个可学习的参数。当输入数据被输入到模型中时,它通过原始预训练层和新插入的适配器模块流动,适配器略微改变了数据处理流程,这导致某些层中引入了额外的转换步骤。

在数据通过网络后执行的计算损失步骤与我们关于 NNs 章节中学到的步骤相同,计算出的损失用于计算模型参数的梯度。然而,与传统全模型微调不同,梯度仅应用于更新适配器模块的权重,而预训练模型的权重本身保持冻结,并保持其初始值不变。

另一种流行的 PEFT 技术是低秩调整(LoRA),我将在下面进行描述。

LoRA

LoRA 基于这样一个前提,即一个神经网络中的所有参数在将学习到的知识转移到新任务时并不同等重要,并且通过仅识别和改变模型参数的小子集,可以适应特定任务而无需完全重新训练模型。LoRA 不是直接修改原始权重矩阵,而是创建低秩矩阵,可以将其视为全矩阵的简化或压缩版本,它以更少的参数捕获最重要的属性。

这就是 LoRA 更参数高效的原因。与适配器微调类似,在反向传播过程中,只有低秩矩阵的参数被更新,原始模型参数保持不变。由于低秩矩阵比它们所代表的完整矩阵具有更少的参数,因此训练和更新过程可以更加高效。

除了提高模型在特定任务上的性能外,还有一些更微妙但同样重要的性能改进实践,例如与人类价值观和期望保持一致。让我们接下来更详细地探讨这个概念。

与人类价值观和期望保持一致

你有没有遇到过一些非常聪明和有才华的人,但沟通技巧却很差?例如,这样的人在解决和修复技术问题时可能表现得非常出色,但他们可能不适合主持客户会议。他们可能会说出一些可能被认为是不礼貌或不恰当的话,或者可能只是因为沟通技巧差而显得有些奇怪。这就是我喜欢用来解释调整 GenAI 模型以与人类价值观和期望保持一致的概念的类比,因为这样的价值观和期望往往比科学更微妙,因此需要定制的方法。例如,除了模型的输出要准确外,人类的期望可能还要求模型的输出要友好、安全、无偏见,以及其他微妙、细腻的品质。从现在起,我将把这个概念称为一致性,在本节中,我将描述两种今天常用于人类价值观一致性的方法,首先是从人类反馈中进行强化学习RLHF)。

RLHF

我们在本书的第一章中探讨了强化学习RL)的概念,并解释说,在 RL 中,模型在追求特定目标的过程中,通过与环境的交互从奖励或惩罚中学习。RLHF 是那些技术名称高度描述性且准确捕捉技术内涵的例子之一。正如其名所示,RLHF 是 RL 的扩展,其中模型通过人类提供反馈。

在 RLHF 的情况下,我们从一个已经在大量数据集上预训练的 LLM 开始。该模型会对一个提示生成多个可能的响应,人类根据各种偏好评估这些响应。然后,人类反馈数据被用来训练一个名为奖励模型的独立模型,该模型学习根据反馈预测人类可能更喜欢的响应类型。这个过程旨在以可衡量的方式捕捉人类偏好。

LLM 随后使用这种反馈(如奖励信号)通过 RL 技术更新其参数,使其更有可能在将来生成人类认为理想的响应。

另一种可以用来与人类价值观和期望保持一致的技术是直接偏好优化DPO)。让我们接下来讨论这个话题。

DPO

DPO 也使用人类反馈来提高模型在符合人类价值观和期望方面的性能。在 DPO 的情况下,模型可能会对一个提示提供多个响应,而人类可以选择他们更喜欢的响应(类似于 RLHF)。然而,DPO 不涉及训练一个单独的奖励模型。相反,它使用成对比较作为优化信号,并直接根据用户偏好优化策略,而不是预定义的奖励函数,这在难以定义明确的奖励函数的情况下特别有用。

需要注意的是,虽然强化学习与人类反馈(RLHF)和直接偏好优化(DPO)是很有价值和重要的技术,但人类交互本身会带来一些挑战。例如,任何需要人类交互的过程都可能难以扩展。这意味着通过人类的反馈收集大量数据可能会很困难。此外,人类可能会犯错误,或者将主观或无意识的偏见引入结果中。如果你实施 RLHF 或 DPO 解决方案,这些是一些你需要监控和缓解的因素。

除了我在这里介绍的对齐方法之外,还有其他大型语言模型(LLM)调优技术正在出现,并且在这个领域投入了大量的研究。这又是一个你可以期待继续看到在开发方面取得突破性进展的空间。

接下来,让我们更深入地探讨嵌入和向量数据库在生成人工智能(GenAI)中的作用。

嵌入和向量数据库

第十五章中,我们讨论了嵌入和潜在空间的重要性,并解释了它们可以通过不同的方式创建。一种方式是当生成模型在其训练过程中内在地学习它们时,另一种方式是我们使用特定类型的模型来明确地创建它们。

我还简要提到了我们为什么要明确创建它们,因为它们可以更有效地处理,并且更适合用于机器学习用例的格式。在这种情况下,当我们为某物创建嵌入时,我们只是在创建一个代表它的数值向量(我们实际上是如何做到这一点的是一个更高级的话题,我们将在稍后讨论)。

我还简要提到了嵌入在向量空间中关系的重要性。例如,嵌入在向量空间中的邻近性可以反映它们所代表的概念之间的相似性。让我们更详细地考察这种关系。

概念的嵌入和相似性

一个构建良好的嵌入包含描述和解释其所代表概念所需的一切——即,该概念的“意义”。这在我们看来可能有些抽象,因为我们不经常思考构成某物意义的一切。例如,当我提到“汽车”这个词时,你脑海中可能会浮现出一个特定的形象,并且许多其他信息也会立即由这个词所关联。你知道你可以驾驶汽车;你知道它们通常相对昂贵;你知道它们有轮子和窗户,而且它们传统上是由某种金属制成的。你对汽车这一概念的了解有很多,这有助于你理解它是什么。想象一下,所有构成汽车这一想法的信息都存储在你心中的一个向量中。现在,想象一下你以前从未听说过卡车,我突然给你展示一张卡车的图片。它有轮子和窗户;它是由钢制成的;它看起来像你可以驾驶的东西。尽管你以前从未见过类似的东西,但你能够理解这个新物体与汽车相似。这是因为与之相关的信息片段(即信息向量)与汽车非常相似。

我们如何建立这些类型的关联?这感觉有些直观,而且大多数普通人(包括我自己)都不理解这一切在我们大脑中是如何真正发生的。然而,在嵌入的情况下,理解要容易得多,因为我们的老朋友数学(计算机和机器学习模型都非常喜欢)来帮忙了。正如我之前提到的,我们可以通过在向量空间中计算它们之间的距离来数学地比较不同的向量,使用诸如欧几里得距离或余弦相似度等已建立的距离度量。

如果概念在向量空间中彼此接近,它们在意义上也可能接近,在这种情况下,我们可以说它们是语义相似的。例如,在一个基于文本的向量数据库中,“The cat sat on the mat”和“The feline rested on the rug”这两个短语会有非常相似的向量嵌入,尽管它们的精确单词不同。对这些向量之一进行查询很可能也会将另一个识别为高度相关的结果。这个概念的一个经典例子是“man”、“woman”、“king”和“queen”这些词的表示,如图 16.1所示:

图 16.1:嵌入和语义相似性

图 16.1:嵌入和语义相似性

图 16**.1所示,根据项目嵌入在向量空间中的方式,我们可能在向量表示和向量之间的距离中看到某种一致性投影。示例显示,二元性别(或某种一致的语义关系)在“男人”、“女人”、“国王”和“王后”这些词中得到了体现,而且从“男人”到“女人”的距离和方向与从“国王”到“王后”的距离和方向相似。此外,从“男人”到“国王”的距离和方向与从“女人”到“王后”的距离和方向相似。在这种情况下,假设你可以在向量空间中执行以下数学运算来推断值“王后”:

国王 – 男人 + 女人 = 王后

也就是说,如果你将“国王”的概念减去男性性别,并添加女性性别,你最终得到的是“王后”的概念。

我们还可以更广泛地应用这种方法。例如,在一个存储图像嵌入的向量数据库中,一个柚子的图片可能靠近一个金桔的图片。这些物体具有相似的性质,如大小、形状和颜色,而代表香蕉的向量可能不会像它们彼此之间那样接近,因为香蕉与它们共享的相似性较少。然而,从多模态的角度来看,我们将在本章后面描述,考虑到它们都是水果类型,香蕉向量可能仍然比代表汽车或雨伞的向量更接近它们。这个概念在图 16**.2中以简化的方式表示:

图 16.2:嵌入和语义相似性的详细示例

图 16.2:嵌入和语义相似性的详细示例

注意,在现实中,嵌入空间由许多抽象维度组成,通常无法可视化或直接对人类进行解释。嵌入可以被视为将现实世界的混乱复杂性转化为机器学习模型可以理解的数值语言的一种方式。

如果我们创建嵌入,我们可能希望有一个地方来存储它们,并在需要时轻松找到它们。这就是向量数据库发挥作用的地方。让我们更详细地探讨这个问题,并解释什么是向量数据库。

向量数据库

向量数据库是专门设计用于存储和管理向量嵌入的数据库。与关注精确匹配的传统数据库(例如,查找具有特定 ID 的客户)不同,向量数据库更适合用于相似性搜索等用例,它们使用距离度量来确定在潜在空间中两个向量嵌入的接近程度和相似程度。

这种方法显著改变了我们检索和分析数据的方式。虽然传统方法依赖于关键词或预定义的属性,但向量数据库允许我们执行语义搜索,其中我们可以根据意义进行查询,这开辟了新的应用。例如,如果我搜索“裤子”,响应也可以包括牛仔裤、休闲裤和卡其裤,因为这些都是在语义上相似的概念。大多数现代搜索引擎,例如谷歌,例如,使用复杂的机制,如语义搜索(以及其他技术的组合),而不是简单的关键词匹配。

语义搜索为用户提供更好的客户体验,同时也可能为公司带来潜在的收入增长。例如,如果你经营一个零售网站,请记住,如果客户找不到产品,他们就不会购买,他们的业务可能会转向你的竞争对手。通过实施语义搜索,我们可以理解用户的含义和意图,因此可以向他们展示最相关的产品。

这些新的搜索能力在 GenAI 的背景下也非常重要,原因我将在稍后解释。首先,让我们更深入地探讨向量数据库是如何工作的。

向量数据库是如何工作的

在解释向量数据库是如何工作的之前,让我们简要地谈谈数据库通常是如何工作的。任何数据库的主要目的是以使其尽可能快速找到的方式存储和组织数据。大多数数据库为了这个目的使用索引,我将在下面描述。

索引和邻近搜索

为了理解索引的作用,想象我给你一本书,并要求你尽可能快地在这本书中找到关于“拟人化”的信息。如果没有任何辅助机制,你就必须逐页阅读每个单词,直到找到那个词。这当然是一个非常低效的过程,除非信息恰好出现在书的开始附近,否则你很可能需要很长时间才能找到信息。这在数据库世界中被称为全表扫描,我们通常希望尽可能避免这种情况。这就是索引发挥作用的地方——如果我所给你的书包含索引,你可以在索引中查找包含“拟人化”引用的哪些页面,然后直接前往这些页面,从而避免大量的低效搜索。

关系型数据库通常使用树形(例如,B 树)或基于哈希的索引进行快速查找,但向量数据库的索引可能更复杂,因为嵌入空间和每个向量在可能的高维空间中的表示都很复杂。这样的索引可以类似于图结构,将嵌入之间的关系映射出来,以实现基于邻近度的搜索。

在向量数据库世界中,与全表扫描相当的操作被称为暴力搜索,这个名字借用了网络安全领域的术语,并涉及到尝试所有可能的输入组合以找到期望结果的做法。这是恶意行为者尝试猜测某人密码的常见方式——他们在一定参数内尝试所有可能的字符组合。密码越长,他们通过暴力猜测就越困难,因为每个额外的字符都会指数级增加可能的组合数量。

在向量数据库的情况下,我们的查询通常试图在向量空间中找到与查询项附近的项。如果我们数据库中有大量的向量,那么暴力搜索将是不切实际的,尤其是在高维空间中,维度诅咒CoD)使得精确搜索的计算成本很高。幸运的是,通常不需要暴力搜索,因为它寻求精确地找到与查询向量最接近的向量(称为精确最近邻),但我们并不总是需要精确的最近邻。例如,像推荐引擎这样的用例,它推荐与特定项目相似的项,通常只需要找到与查询向量在附近区域的向量,但不必是查询向量的精确最近邻。这被称为近似最近邻ANN)搜索,在向量数据库的上下文中非常有用,因为它允许在搜索结果的准确性和查询速度之间进行权衡——也就是说,对于这类用例,快速得到足够接近查询向量的结果比花费大量时间找到最佳结果更好。

注意 - CoD 和向量邻近度

在高维空间中,点变得越来越分散,随着维数的增加,最近点和最远点之间的距离变得稀释,这使得基于距离度量的真正相似和不同项的区分变得更加困难。

一些向量数据库实现了混合方法,将 ANN 与其他索引或搜索策略相结合,例如分层索引结构、多索引哈希和基于树的方法,以提高准确性、减少搜索延迟或优化资源使用。基于图的方法,如 可导航小世界NSW)图、分层可导航小世界HNSW)图等,创建了一个图,其中节点代表向量,查询随后遍历图以找到最近的邻居。一些向量数据库还使用分区或聚类算法将数据集划分为更小、更易于管理的块或簇,然后在这些分区或簇内进行索引,通常使用多种方法首先识别相关的分区,然后在其中执行 ANN 搜索。

此外,我们可以使用诸如乘积量化或标量量化等方法,通过将向量映射到有限个参考向量集来压缩向量,这减少了向量在索引前的维度和存储需求,并通过在压缩空间中近似距离来加速搜索。

第十七章 中,我们将介绍 Google Cloud 中提供的各种向量数据库产品,但到目前为止,让我们继续讨论我们如何首先创建嵌入。

创建嵌入

我们已经在 第十五章 中讨论了 自编码器AEs),我们学习了它们如何被用来创建输入的潜在空间表示。我们可以以许多其他方式创建嵌入,我将在本节中描述一些更受欢迎的方法,从最著名的词嵌入模型 Word2Vec 开始。

Word2Vec

Word2Vec(简称“词向量化”)是由谷歌(Mikolov 等人,2013 年)发明的一组算法,用于学习将单词表示为向量的表示。它通常被认为是词嵌入方法的鼻祖,尽管它不是第一个被发明的词嵌入技术,但它推广了将单词表示为密集向量,这些向量能够捕捉到高维空间中单词的语义意义和关系。它通过构建一个独特的单词词汇表,并为每个单词学习一个向量表示来实现,其中具有相似意义的单词具有相似的向量。

Word2Vec 中使用的两种主要方法是 连续词袋CBOW)模型,它根据周围的单词预测目标词,以及 跳字模型skip-gram),它根据给定的目标词预测周围的单词。

虽然 Word2Vec 已经是一种流行且有用的方法,但基于新近的、基于转换器的技术已经出现,提供了更高级的功能。让我们接下来看看那些方法。

转换器

我们已经在之前的章节中介绍了变压器,在本节中,我将简要描述基于变压器的创建嵌入的方法。虽然有很多选项可以选择,但我将重点关注著名的双向编码器表示从变压器BERT)及其衍生版本。

BERT

在本书的早期,我提到,在 AI/ML 研究中,每隔一段时间就会有一个重大的进步,而谷歌在 2017 年(Vaswani 等人,2017)发明变压器架构已被确立为那些重大飞跃之一。BERT 是由谷歌在 2018 年(Devlin 等人,2018)发明的,这是另一个重大的进步。

正如其名称所示,BERT 基于变压器架构,并在大量文本和代码数据集上进行了预训练。在训练过程中,它学会了模拟单词之间的复杂模式和关系,并理解诸如上下文、语法以及句子不同部分之间如何相互关联等细微差别。

BERT 使用的两种主要方法是掩码语言建模MLM),它根据周围上下文预测句子中的缺失单词,以及下一句预测NSP),它试图确定两个句子是否在逻辑上相连。这些都是第十五章中描述的预训练阶段的例子。通过结合这两种方法,BERT 发展了对语言结构的理解。

BERT 的核心是变压器层,它接受我们给出的文本并产生词嵌入,这些嵌入根据周围的单词捕捉意义,这比静态嵌入(如 Word2Vec)是一个重大的改进。

BERT 是一个如此重要的突破,以至于自其最初发布以来已经创建了多种变体,如 DistilBERT 和 ALBERT,它们是 BERT 的较小、精简版本,参数更少(以一些准确性换取计算效率),以及特定领域的变体,如 SciBERT(在科学出版物上训练)和 FinBERT(针对金融行业用例微调)。

此外,还有一些更针对特定领域的模型建立在基于变压器的模型之上,如 BERT。例如,句子变压器不是关注单个单词,而是使用池化策略,如平均池化或最大池化,来创建整个句子的语义上有意义的嵌入。

对于图像嵌入,虽然我们在之前的章节中讨论了卷积神经网络CNNs)在图像分类等用例中的应用,但需要注意的是,CNNs 也可以用于创建图像嵌入。

既然我们已经了解了创建嵌入的一些选项,以及将嵌入存储在向量数据库中的选项,让我们探索一个相对较新的模式,它在行业中越来越受欢迎,并且结合了这些主题,被称为 RAG。

RAG

虽然 LLMs(大型语言模型)无疑是令人印象深刻且强大的技术,但它们也有一些局限性。首先,LLMs 的表现取决于它们训练时所使用的数据,而且训练它们可能既昂贵又耗时,因此对于大多数公司来说,每天用新信息重新训练它们并不可行。因此,在许多情况下,LLMs 的更新版本通常每隔几个月就会发布一次。这意味着它们提供的回答信息取决于它们最近的训练数据集。如果你想要询问昨天发生的事情,但 LLM 上次更新是一个月前,那么它将简单地没有关于这个主题的任何信息。这在当今快节奏的商业世界中可能相当受限,因为人们和应用程序需要随时掌握最新的知识。

其次,除非你是那些创建了今天广泛使用的流行 LLM 的大型企业之一,否则你很可能没有从头开始自己训练 LLM,因此它没有针对你的特定数据进行训练。想象一下,你是一家零售公司,想使用 LLM 通过聊天界面让客户了解你的产品。由于 LLM 没有针对你的产品目录进行专门训练,它将不熟悉你产品的细节。

为了应对这些挑战,我们不仅可以依赖用于训练 LLM 的数据,还可以将额外的数据插入到发送给 LLM 的提示上下文中。我们已经在本章的 提示工程 部分提到了这一点,我们在提示中提供了额外的信息,以便引导 LLM 的回答更准确地匹配我们所需的输出。这种方法对于少量数据非常有效,但如果考虑到上述 LLM 回答产品目录问题的用例,我们不可能在每次提示中都包含整个产品目录。这就是 RAG(Retrieval-Augmented Generation)能发挥作用的地方。

使用 RAG,我们可以在首先从数据存储中检索相关信息并将其包含在发送给 LLM 的提示中之后,增强 LLM 生成的响应。这个数据存储可以包含我们想要的信息,例如我们产品目录的内容。让我们更详细地看看这个模式。

RAG 的工作原理

为了解释 RAG 的工作原理,让我们通过回顾没有 RAG 的 LLM 交互通常是如何工作的来统一讨论的基准。这非常简单,如 图 16.3 所示:

图 16.3:LLM 提示和响应

图 16.3:LLM 提示和响应

如我们所见,典型的 LLM 交互简单地说就是发送一个提示并得到一个响应。请注意,LLM 只能理解数值,因此幕后,用户发送的文本提示被分解成标记,这些标记被编码成 LLM 可以理解的向量。当向用户发送响应时,执行反向过程。接下来,让我们看看 RAG 如何改变这个过程,如图 16.4 所示:

图 16.4:RAG

图 16.4:RAG

图 16.4 概述了 RAG 在高级别上是如何工作的。步骤如下:

  1. 用户或客户端应用程序发送文本请求或提示。

  2. 将提示内容转换为向量(嵌入)。

  3. 在过程的“检索”部分,使用提示嵌入在向量数据库中查找相似的嵌入。这些嵌入代表我们想要用来增强提示的数据(例如,代表我们产品目录数据的嵌入)。

  4. 将我们的向量数据库中的嵌入与用户提示的嵌入相结合,并发送到 LLM。

  5. LLM 使用用户提示和检索到的嵌入的组合来增强其响应,旨在提供不仅基于其最初训练的数据,而且在从我们的向量数据库检索到的数据上下文中也相关的响应。

  6. 将响应嵌入解码以向用户或客户端应用程序提供文本响应。

我们将在本书的后续章节中实现 RAG。接下来,让我们开始探讨多模态模型的主题。

多模态模型

由于 LLM(语言模型)顾名思义,专注于语言,因此在 2024 年初撰写本文时,你很可能交互的许多流行 LLM 的主要模态可能是文本。然而,GenAI 的概念也超越了文本,扩展到其他模态,如图片、声音和视频。

“多模态”一词在 GenAI 领域变得越来越突出。在本节中,我们将探讨这意味着什么,从“模态”的定义开始。

定义

牛津高阶英汉双解大词典将模态定义为:

事物与它的模式、方式或状态有关的部分,与它的实质或身份不同;概念或实体的非本质方面或属性。也指表示某物存在模式或方式的特定品质或属性 *。”

牛津高阶英汉双解大词典s.v. “modality (n.), sense 1.a,” 2023 年 12 月doi.org/10.1093/OED/1055677936。”

考虑到这种模态的正式定义,与只关注单一数据类型的传统模型不同,多模态模型旨在处理来自多个模态或数据类型的信息。这是 AI 研究中的另一个重要飞跃,因为它为 AI 开辟了新的用例和应用。让我们更详细地探讨这一点。

为什么多模态很重要

在本章关于 RAG 的部分,我提到了一个公司使用 LLM 通过聊天界面帮助客户探索产品细节的例子,以及这需要与公司产品目录中的数据进行交互。更详细地探讨这个例子,考虑一下产品目录中的项目可以与许多不同类型的信息相关联。这可能包括具有标准化字段的结构化数据,如产品尺寸、颜色、价格和其他属性。它也可能与半结构化或非结构化数据相关联,如客户评论以及产品图片。想象一下,如果我们的模型能够摄取和理解所有这些数据模态,它将能够对我们的目录中的项目获得多么详细的理解。如果产品描述中缺少关于产品颜色的细节,模型可以从产品图片中学习这些信息。此外,除了书面客户评论外,一些网站允许客户在其评论中发布视频。模型可以从这些视频中学习更多信息。总的来说,这可以为最终用户提供更丰富的体验。这只是多模态力量的一例,当创建需要与物理世界交互的模型,如机器人和自动驾驶汽车时,这一概念变得更加重要。

多模态实现对于 AI 研究也很重要,因为在创建有用且强大的模型时,一个主要挑战是获取相关数据。考虑到世界上已经创作了有限数量的文本,如果文本是唯一模态,它最终将成为 AI 发展的限制因素。正如我们都可以在各种社交媒体平台和其他网站上清楚地看到,视频、音频和图片已经等同于或超过了文本,成为用户生成内容中的主要模态,我们可以预期这些趋势会继续。我们都听说过这句话,“一图胜千言”,当训练和与大型生成模型交互时,这一点(以及其他模态)变得更加真实!

表达了多模态模型实现的重要性和优势后,我将通过强调一些相关挑战来平衡讨论。

多模态挑战

我将从本节开始,介绍在本书中讨论的许多情境中反复出现的一个挑战。一般来说,创建更强大的模型需要更多的计算资源。多模态方法也不例外,训练多模态模型通常需要大量的计算资源。

另一个挑战是复杂性——结合来自不同模态的数据可能很复杂,需要仔细的预处理,特别是考虑到不同模态的特征表示通常具有非常不同的特征空间,一些模态的数据比其他模态更丰富或更稀疏。例如,文本通常是序列的,图像是空间的,而音频和视频具有时间属性,因此对于模型来说,将这些属性对齐以建立一个统一的理解可能很困难。

在前面的章节中,我们探讨了数据质量问题以及解决这些问题的数据准备步骤和管道。然而,棘手的是,不同模态的数据有不同的潜在质量问题、准备步骤和管道,这些是使数据准备好用于模型训练所必需的。

尽管存在挑战,但多模态是一个快速发展的领域,在可预见的未来将继续受到显著的关注。

尽管本节主要关注训练通用人工智能模型(特别是多模态方法),但在模型开发的生命周期中,其他部分也有独特的处理方法,当处理通用人工智能模型而不是传统人工智能模型时,必须考虑这些方法。接下来要强调的重要话题是如何评估通用人工智能模型,以及在某些情况下,这种评估可能与传统人工智能模型的评估有所不同。

通用人工智能模型评估

虽然评估传统人工智能模型通常涉及将模型的输出与一个真实数据集进行比较,并计算已建立的、客观的指标,如准确率、精确率、召回率、F1 分数、均方误差MSE)以及本书中提到的其他指标,但评估生成模型并不总是那么直接。

当评估一个通用人工智能模型时,我们可能希望关注不同的因素,例如模型在保持与当前任务相关的同时,产生具有创造性和类似人类输出的能力。在这种情况下,一个额外的挑战是评估这些属性可能有些模糊和主观。例如,如果要求一个生成模型写一首诗或创建一幅草地上的猫的逼真图片,那么这首诗的质量或图片的真实性并不总是容易用数学计算出的数字来表示,尽管存在一些公式化的测量方法,我将在本节中描述。然而,让我们首先讨论人工评估。

人工评估

可能最直接但同时也缓慢、繁琐且可能昂贵的做法是让人类评估者评估生成输出的质量、创造力、连贯性以及它们与任务要求的匹配程度。有一些工具、框架、服务和整个公司致力于执行这类评估。这种方法的一些常见挑战是,评估的质量仅与提供给评估者的指示一样好,因此有必要清楚地理解和解释如何评估响应,并且评估可能是主观的,基于评估者的个人解释。

接下来,我将描述一些可以用于评估生成模型的正式化方法,从评估文本语言模型的指标开始,如双向评估辅助者BLEU)和基于回忆的摘要评估辅助者ROUGE)。

BLEU

BLEU 主要用于评估机器翻译用例,它通过衡量生成文本与人工编写的文本的相似性来工作,因此当我们使用 BLEU 时,我们需要一组参考、人工编写的文本示例,这些示例与生成的文本进行比较。更具体地说,BLEU 衡量的是所谓的n-gram 重叠,即生成文本和参考文本之间单词序列的重叠。

ROUGE

ROUGE 同样衡量生成文本与人工编写的参考示例之间的重叠,但它通过衡量召回率来专注于总结用例,召回率表示生成的摘要从参考摘要中捕获重要信息的程度。

除了基于重叠的评估之外,我们还可以使用诸如困惑度负对数似然NLL)等指标来评估文本生成性能,这些指标可以用来评估模型在预测单词序列方面的性能,例如预测句子中的下一个单词。

接下来,让我们考虑一些评估图像生成模型的方法,例如Inception ScoreIS)和Fréchet Inception DistanceFID)。

IS

IS 用于衡量生成图像的质量和多样性,一个好的图像生成模型应该能够生成各种各样的图像,而不仅仅是同一事物的变体,并且图像应该看起来清晰、逼真。我们可以通过使用预训练的图像分类模型来对生成模型生成的图像进行分类,从而计算 IS。

FID

虽然 IS 独立评估生成图像,但 FID 旨在通过衡量生成图像的分布与真实图像分布的相似性来改进它(它得名于使用 Fréchet 距离来衡量两个分布之间的距离)。

为了本章的目的,我们主要需要意识到存在一些用于评估某些生成模型的特定指标,但深入探讨这些指标是如何计算的数学细节,在这个阶段将提供比所需更多的信息。除了我们在本节中介绍的方法和指标之外,还有其他的方法和指标。接下来,我将介绍一种评估生成模型的不同方法,即使用自动评分器

自动评分器和并行评估

在高层次上,自动评分器是一个机器学习模型,用于评分或评估模型的输出。这可以通过不同的方式进行,我将在 Google Cloud Vertex AI 的背景下解释这个概念。

Google Cloud Vertex AI 最近推出了一项名为自动并行AutoSxS)的服务,可用于评估 Vertex AI 模型注册表中的预生成预测或生成 AI 模型。这意味着,除了 Vertex AI 基础模型之外,我们还可以使用它来评估第三方语言模型。

为了比较两个模型的结果,它使用自动评分器来决定哪个模型对提示给出了更好的响应。相同的提示被发送到两个模型,自动评分器评估每个模型的响应,并针对各种标准进行评估,例如相关性、全面性、模型遵循指令的能力以及响应是否基于既定事实。

如我在本节开头所提到的,评估生成模型通常需要一定的主观性和比传统机器学习模型简单客观评估更多的灵活性。Google Cloud Vertex AI AutoSxS 支持的各项标准提供了这种额外的灵活性。

现在我们对生成 AI 模型的评估在某些方面与传统机器学习模型的评估有何不同有了高层次的理解,让我们继续介绍生成 AI 中的另一个重要主题——LangChain。

LangChain

通过向 LLM 发送提示,我们可以实现惊人的成就并获得有用的信息。然而,我们可能希望构建比单个提示所能实现的更复杂的逻辑的应用程序,并且这些应用程序可能需要与 LLM 之外的多个系统进行交互。

LangChain 是一个流行的框架,用于使用大型语言模型(LLM)开发应用程序,它使我们能够将多个步骤组合成一个链,其中每个步骤实现一些逻辑,例如从数据存储中读取、向 LLM 发送提示、获取 LLM 的输出并在后续步骤中使用它们。

LangChain 的一个优点是它采用模块化方法,因此我们可以通过组合较小的、更简单的逻辑模块来构建复杂的流程。它提供了创建提示模板和管理与 LLM 交互集成上下文的工具,并且我们可以轻松地找到访问来自 Google 搜索、知识库或自定义数据存储等信息源的集成。

在本书的后面部分,我们将使用 LangChain 来编排工作流程中的多个不同步骤。现在,在我们继续下一章之前,让我们总结一下本章所涵盖的内容。

摘要

在本章关于高级通用人工智能(GenAI)概念和用例的章节中,我们首先深入探讨了调整和优化大型语言模型(LLMs)的技术。我们学习了提示工程实践如何影响模型输出,以及全微调、适配器调整和 LoRA 等调整方法如何使预训练模型能够适应特定领域或任务。

接下来,我们深入探讨了嵌入和向量数据库,包括它们如何表示概念的意义,并启用基于相似性的搜索。我们研究了特定的嵌入模型,如 Word2Vec 和基于 transformer 的编码。

然后,我们继续描述了如何使用 RAG(Retrieval-Augmented Generation)将来自自定义数据存储的信息结合到发送给 LLM 的提示中,从而使得 LLM 能够根据我们数据存储的内容调整其响应。

之后,我们讨论了多模态模型以及它们如何打开超越文本语言的额外用例。然后,我们继续讨论了 GenAI 模型的评估与传统机器学习(ML)模型评估在某些方面的不同,并介绍了一些新的评估 GenAI 模型的方法和指标。

最后,我们介绍了 LangChain 这个重要主题,以及它如何帮助我们通过连接简单的模块或构建块来构建实现复杂逻辑的应用程序。

在下一章中,我们将学习关于 Google Cloud 上提供的各种 GenAI 服务和实现。

第十七章:谷歌云上的生成式 AI

既然我们已经涵盖了生成式 AI 世界中的许多重要主题,本章将专门探讨谷歌云中的生成式 AI。我们将讨论谷歌的专有模型,如 Gemini、PaLM、Codey、Imagen 和 MedLM API,这些模型各自针对不同类型的任务而设计,从语言处理到医学分析。

我们还将回顾谷歌云上通过 Vertex AI Model Garden 和 Hugging Face 等存储库提供的开源和第三方模型。

继续上一章关于向量数据库的讨论,我们将探索谷歌云中的各种向量数据库选项,以及每个选项的潜在用例。

最后,我们将利用本章所涵盖的信息开始构建谷歌云中的生成式 AI 解决方案。

具体来说,本章涵盖了以下主题:

  • 谷歌云中生成式 AI 概述

  • 对谷歌云生成式 AI 的详细探索

  • 在谷歌云中实施生成式 AI 解决方案

让我们从对谷歌云中生成式 AI 的高层次概述开始。

谷歌云中生成式 AI 概述

谷歌云中生成式 AI 的发展速度令人惊叹。几乎每天都有新的模型版本、服务或功能被宣布。在本节中,我将从高层次介绍各种模型和产品,为本章后面的深入探讨奠定基础。

总体而言,模型和产品按模态分类,如文本、代码、图像和视频。让我们从讨论谷歌的各种生成式 AI 模型开始我们的旅程。

谷歌的生成式 AI 模型

在过去的几年里,谷歌创建了众多生成式 AI 模型,新模型和模型版本在去年推出的速度显著加快。本节讨论的是截至 2024 年初在谷歌云上可用的谷歌第一方基础模型,从相当著名的“Gemini”开始。

Gemini API

截至 2024 年初,Gemini 是谷歌最大、功能最强大的 AI 模型系列。它包括三个模型系列:

  • Gemini Ultra:这是 Gemini 家族中最大的模型,旨在处理高度复杂任务。在 2023 年 12 月宣布推出时,它在 LLM 研究广泛使用的 32 个学术基准中的 30 个上超过了当前最先进的结果。

  • Gemini Pro:虽然这不是最大的模型,但它被认为是谷歌在广泛任务中扩展的最佳模型。截至 2024 年初撰写本文时,其最新版本为 1.5,引入了一百万个 token 的上下文窗口——在发布时是行业内最大的上下文窗口。这使得我们能够在单个提示中发送大量数据,开辟了新的用例,并解决了早期 LLM 的重大限制。

  • Gemini Nano: 这是 Google 最有效的 Gemini 模型系列,旨在加载到单个设备的内存中,以执行设备上的任务。它最初以两种略有不同大小的变体推出,即 Nano-1 和 Nano-2。

此外,还有多模态变体——例如,Gemini Ultra VisionGemini Pro Vision——这些变体在多种输入数据上进行了训练,包括文本、代码、图像、音频和视频。这意味着我们可以在与 Gemini 的交互中混合模态,例如在提示中发送图像,通过文本询问照片内容,并接收文本输出。

PaLM API 模型

PaLM 是 Google 的路径语言模型,基于 Google 创建的“路径”系统,旨在构建能够执行多个任务(与传统单一用途模型相对)的模型。当前 PaLM 模型套件基于 PaLM 2 发布,并且在这个套件中有多个提供,例如 PaLM 2 for Text、PaLM 2 for Chat 和 Text 的嵌入,接下来我将描述这些变体。

PaLM 2 for Text

正如其名所示,这个模型系列是为文本用例设计的。目前这个模型系列有三个变体:

  • text-bison: 这可以用于多种基于文本的语言用例,如摘要、分类和提取。它可以处理最多 8,192 个标记的输入和最多 1,024 个标记的输出。

  • text-unicorn: PaLM 家族中最先进的模型,用于复杂自然语言任务。虽然它比 text-bison 更先进,但输入和输出标记限制相同。

  • text-bison-32k: 这个变体与上述 text-bison 类似,但可以处理最多 8,192 个标记的输出,以及总共最多 32,768 个标记(输入和输出总和)。

当我们向PaLM 2 for Text模型发送提示时,模型会生成文本作为响应,每次交互都是独立的。然而,我们可以构建外部逻辑来链接多个交互。接下来,我们将讨论一系列为交互式提示集成而设计的 Google Cloud 产品。

PaLM 2 for Chat

使用PaLM 2 for Chat,我们可以与 PaLM 模型进行多轮对话。这个产品系列包括两个变体:

  • chat-bison: 这个变体是为交互式对话用例设计的。它可以处理最多 8,192 个标记的输入和最多 2,048 个标记的输出。

  • chat-bison-32k: 这个变体与上述 chat-bison 类似,但可以处理最多 8,192 个标记的输出,以及总共最多 32,768 个标记(输入和输出总和)。

由于这些产品变体的特性,它们非常适合需要跨多个提示保持上下文,以提供自然、类似人类的对话体验的用例。我们还可以使用 PaLM 模型生成文本嵌入。我们将在下一节中查看这些模型。

PaLM 2 嵌入模型

我们已经泛泛地讨论了可以用来创建嵌入的模型。在本节中,我们将探讨谷歌的 PaLM 2 嵌入模型,这些模型也分为两种变体:

  • textembedding-gecko:名称“gecko”指的是较小的模型。考虑到我们使用这些模型来创建文本的嵌入,我们通常不需要一个非常大的模型来处理这种情况,因此在这些上下文中,这些较小且更高效的模型更有意义。这个特定的模型专注于英语单词。

  • textembedding-gecko-multilingual:这个变体与上述的 textembedding-gecko 类似,但这个模型可以支持超过 100 种语言。

到目前为止,我描述的所有 PaLM 2 模型都专注于自然人类语言。接下来,我们将讨论为涉及计算机编程语言用例而设计的模型。

Codey API 模型

Codey 是一个为实施代码用例而设计的模型的有趣名称。Codey 模型可以根据自然语言请求生成代码,甚至可以将一种编程语言的代码转换为另一种语言。与基于文本的 PaLM 2 模型一样,Codey 模型根据我们是否只想让模型对独立提示生成不同的响应,或者我们想要实现一个交互式、基于聊天的用例而分为不同的变体。让我们更详细地探讨每一个。

Codey 用于代码生成

这套产品是为独立提示设计的(尽管,再次强调,如果我们愿意,我们可以构建逻辑将它们串联起来),并且它们也分为两种变体:

  • 编写一个 Java 函数,从'customer' MySQL 数据库中的'accounts'表中获取 customer_id 和 account_balance 字段。 这个变体可以处理最大输入为 6,144 个标记和最大输出为 1,024 个标记。

  • code-bison-32k:这个变体与上述的 code-bison 类似,但它可以处理最大输出为 8,192 个标记,以及整体最大为 32,768 个标记(输入和输出总和)。

接下来,让我们讨论用于交互式编码用例的模型变体。

Codey 用于代码聊天

这个产品系列使我们能够参与关于代码的多轮对话。这些模型也分为两种变体:

  • codechat-bison:这个模型可以用来实现涉及代码相关问题的聊天机器人对话。与 code-bison 模型一样,它可以处理最大输入为 6,144 个标记和最大输出为 1,024 个标记。

  • codechat-bison-32k:这与上述的 codechat-bison 类似,但它可以处理最大输出为 8,192 个标记,以及整体最大为 32,768 个标记(输入和输出总和)。

除了代码生成和代码聊天模型之外,还有一个用于代码补全的 Codey 版本,我将在下面描述。

Codey 用于代码补全

Codey 的代码补全变体旨在用于 集成开发环境IDEs)。这个模型有一个变体,称为 code-gecko,它被设计成作为有用的编码助手,帮助开发者实时编写有效的代码。这意味着它可以在开发者编写代码时在 IDE 中建议代码片段。我们都熟悉手机上的预测文本和自动纠错功能。这是一个类似的概念,但针对代码,它有助于开发者更快更有效地完成工作。

现在,让我们将讨论转向另一种模式:图像。

Imagen API 模型

Imagen 是谷歌为处理图像而设计的模型套件的名字,其中套件中的每个模型都可以用于不同类型的图像相关用例,例如以下内容:

  • 图像生成:正如其名称所示,imagegeneration 模型可以用于根据自然语言提示生成图像。例如,图 17.1 中的图像是通过提示“一个夏末傍晚,一位女士在小船上在平静的河流上钓鱼的印象派画作。”生成的。我们还可以交互式地编辑我们的图片,根据我们期望的结果进行细化:

图 17.1:由 Imagen 生成的图像

图 17.1:由 Imagen 生成的图像

  • 图像标题生成:我们可以将图像发送到我们的 imagetext 模型,它将根据该图像的内容生成描述性文本。这可以用于许多商业用例,例如根据零售网站上产品目录中的图像生成产品描述,为新闻文章中的图像生成标题,或为网站上的图像生成“alt 文本”。

  • 视觉问答(VQA):除了为我们的图片生成标题外,imagetext 模型还允许我们交互式地询问关于图像内容的问题。

  • 多模态嵌入:虽然我们可以使用 textembedding-gecko 模型生成文本嵌入,但 multimodalembedding 模型可以生成图像和文本的嵌入。

除了我刚才描述的通用模型之外,谷歌还提供了专门针对医疗用例设计的模型。下一节将简要介绍这些模型。

MedLM API 模型

在这个模型套件中有两种模型变体,medlm-mediummedlm-large,两者都符合 HIPAA 标准,可用于总结医疗文档并帮助医疗保健从业者解答医疗问题。

我们可以期待谷歌持续添加更多模型和变体,以支持不断增长的众多用例。除了上一小节中描述的谷歌的第一方模型之外,谷歌云支持并拥抱开源开发,这是我们接下来要探讨的。

谷歌云上的开源和第三方生成式 AI 模型

谷歌是开源社区的一个知名贡献者,它创造了和贡献了许多至关重要的发明,如 Android、Angular、Apache Beam、Go(编程语言)、Kubernetes、TensorFlow 等。在本节中,我们将探讨谷歌的开源生成式 AI 模型,以及我们可以在谷歌云上轻松使用的第三方(开源和专有)生成式 AI 模型。我们将首先讨论谷歌云 Vertex AI 模型园地,它使我们能够访问这些模型。

Google Cloud Vertex AI 模型园地

Vertex AI 模型园地是一个集中式库,提供了一个“一站式商店”,使我们能够轻松找到、定制和部署预训练的 AI 模型。

在模型园地中,我们可以访问基础模型,如 Gemini 和 PaLM 2,以及开源模型,如即将描述的 Gemma 和 Llama 2,以及第三方模型,如 Anthropic 的 Claude 3。我们还可以访问针对特定任务的模型,例如内容分类和情感分析,以及其他许多用例。

Vertex AI 模型园地与谷歌云和 Vertex AI 生态系统紧密集成,使我们能够通过访问我们在前几章中讨论的所有数据处理和解决方案构建工具,以及许多超出本书范围的工具,轻松构建企业级解决方案。

除了通过 Vertex AI 模型园地使模型可访问外,谷歌云还与 Hugging Face 建立了战略合作伙伴关系,我将在下文中进行描述。

Hugging Face

Hugging Face 是一家公司,也是一个社区,它使分享 ML 模型、工具和数据集变得容易。虽然它最初是一家聊天机器人公司,但由于其模型中心和 Transformer 库的流行,它迅速获得了广泛的社区贡献者,并使得访问和使用大型预训练模型变得容易。随着谷歌云和 Hugging Face 之间相对较新的直接合作伙伴关系的建立,谷歌云客户现在可以轻松地从运行在 Vertex AI 和Google Kubernetes EngineGKE)等服务上的谷歌云环境中获得大量模型、工具和数据集。

考虑到这是一本关于谷歌机器学习和生成式 AI 的书,这里的描述性讨论将侧重于谷歌的模型;我将为您推荐外部文档来了解非谷歌开源和第三方模型。考虑到这一点,在下一节中,我将介绍谷歌的开源模型套件,命名为“Gemma”。

Gemma

Gemma 是 Google 提供的一系列最先进和开源的轻量级模型(DOI 引用:10.34740/KAGGLE/M/3301),这些模型是从创建 Gemini 模型所使用的相同技术和研究中构建的。这些是仅具有解码器功能的文本到文本的 LLM,具有预训练的指令调整变体和开放权重,这些权重是在来自网页、文档、代码和数学文本等多种来源的数据上训练的。它们适用于许多不同类型的文本生成用例,如摘要或问答,它们的开放权重意味着它们可以根据特定用例进行定制。此外,由于它们相对较轻量,它们不需要专门的或大规模的计算资源来运行,因此我们可以在许多环境中使用它们,例如在本地笔记本电脑上,这使得开发者可以轻松地开始实验它们。

有趣的事实

Gemma 碰巧是我姐姐的名字,所以当这个名字被选用来命名这个模型系列时,我感到非常高兴,尽管我在这些模型的命名过程中没有任何参与。

我们将在稍后更详细地探讨 Gemma 模型。在第十五章中,我描述了嵌入和向量数据库在生成式 AI 中的重要性。现在我们已经探讨了 Google Cloud 中的各种生成式 AI 模型,让我们来讨论 Google Cloud 中的向量数据库。

Google Cloud 中的向量数据库

本节简要介绍了 Google Cloud 中的向量数据库,我们将在本章的后续部分更详细地探讨它们。我将从这个简单的问题开始: “Google Cloud 数据库服务中哪一个提供向量数据库功能?” 简单来说,答案是,“几乎所有的都提供,只有少数例外!

那么,下一个问题可能是,“我应该使用哪一个?” 这个问题的答案要复杂一些。我们将在本章中更详细地探讨这些选项,从几个简单的决定开始。首先,几乎所有 Google Cloud 数据库服务都提供向量数据库功能的原因是,Google 希望尽可能简化您访问此功能的过程。如果您已经使用 AlloyDB 来管理应用程序的操作数据,您可以轻松地继续使用 AlloyDB AI 来满足您的向量数据库需求。如果您使用 BigQuery 来满足您的分析需求,请继续使用 BigQuery Vector Search,但请注意,BigQuery 主要设计用于大规模数据处理,而不是优化延迟。如果您有严格的低延迟要求,您的负载可能更适合我们稍后将要介绍的 Google Cloud 的其他选项。

如果您是 Google Cloud 的新用户并想设置矢量数据库,请从 Vertex AI 下的产品开始您的旅程。如果您需要一个完全托管的平台,使开发者能够为网站、结构化和非结构化数据构建 Google 级别的搜索体验,或者将您的应用程序与基于企业数据的生成式 AI 和搜索功能集成,请从 Vertex AI Search 和 Conversation 开始。如果您想创建和存储您的矢量,并快速搜索数十亿语义相关的项目,请考虑 Vertex AI Vector Search。

在下一节中,我们将更深入地探讨 Google Cloud 的生成式 AI 产品,从对模型的动手探索开始,然后更详细地介绍各种矢量数据库产品。

对 Google Cloud 生成式 AI 的详细探索

在本节中,我们将开始与 Google Cloud 的生成式 AI 产品进行交互。为了设定场景,我将首先简要介绍 Google Cloud Vertex AI Studio。

Google Cloud Vertex AI Studio

Vertex AI Studio 可以在 Google Cloud 控制台 UI 中访问,它提供了一个界面,可以轻松开始使用我在上一节中描述的所有生成式 AI 模型。

要访问 Google Cloud Vertex AI Studio 用户界面,请执行以下步骤:

  1. 在 Google Cloud 控制台中,导航到 Google Cloud 服务菜单并选择 Vertex AI

  2. Get started with Vertex AI 部分下,点击 图 17.2 中所示 ENABLE ALL RECOMMENDED API

图 17.2:启用推荐 API

图 17.2:启用推荐 API

  1. 等待几分钟以启用 API。一旦 API 已启用,您就可以开始使用它们。您可以通过点击屏幕左侧菜单中的每个模态(例如 LanguageVisionSpeechMultimodal)来与上一节中描述的每个模型进行交互。

  2. 例如,如果我们点击 Language,将显示一个类似于 图 17.3 的屏幕:

图 17.3:语言部分

图 17.3:语言部分

  1. 从这里,我们可以点击各种链接和按钮来尝试不同的模型。例如,点击 TEXT CHAT 按钮将展示一个聊天界面,我们可以在其中输入提示,如图 图 17.4 所示:

图 17.4:文本聊天

图 17.4:文本聊天

我们可以配置的参数可以在屏幕右侧找到。让我们更仔细地看看:

  • 模型:我们想要发送提示的模型。

  • 区域:我们想要运行提示的区域。

  • 温度:此参数配置模型响应中的创造性和随机性水平。这可以看作是我们希望模型在生成响应时使用的想象力水平。如果我们考虑 LLM 预测序列中下一个单词的使用案例,温度参数会影响下一个单词的整体概率分布,这样更高的温度可以导致更富有创造性的输出,而更低的温度则引导模型提供更保守和可预测的结果。如果我们希望模型创作富有想象力的艺术或文本,例如,我们可以配置一个高温度,而如果我们希望得到更正式、事实性的响应,我们就会配置一个低温度。

  • 输出标记限制:我们希望模型在其响应中生成的最大标记数。

我们可以点击屏幕底部的高级部分来展开它。在这里,我们将看到额外的参数,例如最大响应数,它配置了我们希望模型返回的最大示例响应数量(请注意,此参数仅适用于某些类型的交互 – 例如,它不适用于聊天交互,因为聊天在对话的每一轮中总是会提供一个响应),以及Top-KTop-P。与温度类似,Top-KTop-P可以用来控制模型生成输出的创造性和随机性,但它们的工作方式略有不同。考虑一个 LLM 在生成响应时选择序列中的下一个单词(或标记)的情况。它是通过预测下一个单词在给定序列中最有可能发生的概率来做到这一点的。如果 LLM 总是只选择概率最高的单词,那么在生成响应时它不会提供太多的灵活性。然而,我们可以通过理解它们的工作方式来使用Top-KTop-P来增加一层灵活性。所以,让我们更仔细地看看:

  • Top-K:这使用概率分布来预测基于当前提示和上下文的下一个可能单词的概率。K 是我们希望模型从中选择概率最高的单词的数量。例如,如果 K 的值为 3,那么模型将从最有可能的三个单词中选择下一个单词(即概率最高的三个单词)。如果 K 的值为 1,那么模型将只选择最有可能的(即概率最高的)单词。这是我们所说的贪婪选择的特定情况。

  • Top-P:这稍微有点复杂,但也不算太复杂。模型不会选择一个特定数量的最高概率词进行选择,而是计算所有可能下一个词的累积概率——也就是说,它会将最可能词的概率相加,直到概率总和达到指定的阈值(P),此时它将从低于概率阈值的词池中随机选择一个词。

对于Top-KTop-P,较低的值会引导输出趋向于保守的响应,而较高的值则允许一些灵活性,以便产生更具创造性的响应,类似于(并且与)温度参数一起。

高级部分,对于某些模型,我们还可以启用基础功能,在这种情况下,我们可以根据存储在 Vertex AI 搜索和对话中的数据进行响应。我们还有流式响应的选项,这指的是在生成时打印响应。

我鼓励您探索 Vertex AI Studio 中的不同模态和模型类型。如果您需要帮助思考创意提示来写作,您可以要求一个基于文本的模型为您建议一些示例供您使用!

除了通过 Vertex AI Studio UI 访问各种模型外,您还可以通过 REST API 和 SDK 以编程方式与模型交互。

接下来,让我们探索 Google Cloud 中可用的向量数据库选项。

对 Google Cloud 向量数据库选项的详细探讨

在本章的前面部分,我提到几乎所有的 Google Cloud 数据库服务都提供了向量数据库支持。在本节中,我们将更详细地查看每一个服务,从 Vertex AI 搜索和对话开始。

Vertex AI 搜索和对话

虽然 Vertex AI 搜索和对话产品套件的主要目的是构建搜索和对话应用,正如其名称所暗示的,我们也可以将其用作向量数据库来实现检索增强生成RAG)解决方案。正如我们在本章前面讨论的,如果您在 Google Cloud 上开始使用 RAG,除非您有特别需要控制分块、嵌入和索引过程,或者您有特别的需求需要将所有数据与另一个 Google Cloud 数据库服务链接起来,否则 Vertex AI 搜索和对话应该是您首先考虑的选择。这是因为它为您执行所有分块、嵌入和索引过程,并通过一个简单方便的编排界面抽象出所有这些步骤,为您节省了大量时间和精力。您还可以使用数据连接器从第三方应用程序,如 JIRA、Salesforce 和 Confluence 中摄取数据。

如果您需要特别控制分块、嵌入和索引过程,您可以选择其他 Google Cloud 数据库服务,如以下所述。

Vertex AI 向量搜索

正如我们在整本书中看到的那样,Vertex AI 为我们提供了几乎在机器学习和人工智能领域所能做的一切的完整工具和服务生态系统。因此,它包括一个向量数据库是有意义的,而这个向量数据库被称为 Vertex AI 向量搜索。它使我们能够以高速和低延迟存储和搜索大量嵌入,以找到最相似或相关的项目。

虽然我们需要创建块、嵌入和索引(与使用 Vertex AI 搜索和对话不同),但它仍然提供了一个完全托管的服务,我们不需要担心基础设施或扩展,因为 Vertex AI 会为我们处理所有这些。我们需要创建块、嵌入和索引的事实意味着,如果需要的话,我们可以对这些过程实施更细粒度的控制,例如用于创建我们的嵌入的模型(请注意,这也适用于本章余下部分我们将讨论的所有其他向量数据库选项)。

Vertex AI 向量搜索还紧密集成了 Vertex AI 和 Google Cloud 生态系统中的其他部分,作为需要使用嵌入的大规模编排解决方案的一部分。在更广泛的生态系统话题上,让我们考虑 Vertex AI 之外的额外 Google Cloud 向量数据库,从 BigQuery 开始。

BigQuery 向量搜索

BigQuery 向量搜索是 Google Cloud BigQuery 中的一个功能,允许我们存储和查找嵌入。我们可以通过使用 BigQuery 的 VECTOR_SEARCH 函数将查询嵌入发送到 BigQuery,该函数将快速在向量数据库中找到相似的嵌入。这对于熟悉 SQL 语法的人来说是一个主要的好处,它使得语义搜索和基于相似性的分析可以直接在您的 BigQuery 数据仓库中进行。

我们还可以选择创建一个向量索引来加速嵌入检索过程。当我们使用向量索引时,会使用近似最近邻ANN)搜索来返回近似结果,这比进行暴力搜索以找到精确匹配要快得多。如果我们不创建向量索引,那么将执行暴力搜索。我们还有选择在存在向量索引的情况下显式实现暴力搜索的选项,如果我们想要得到精确结果的话。

BigQuery 向量搜索是数据科学团队的一个很好的选择,因为他们已经在 BigQuery 中存储了大量的数据,它还提供了 BigQuery 的自动和巨大可扩展性的好处。继续可扩展性的主题,Google Cloud 中另一个以其令人印象深刻的可扩展性而闻名的数据库服务是 Google Cloud Spanner。让我们更深入地了解一下。

Spanner 向量搜索

Google Cloud Spanner 是一种完全托管且性能极高的数据库服务,能够实现全球规模。它通常被称为“NewSQL”数据库,因为它结合了非关系型(NoSQL)数据库的可扩展性和灵活性以及关系型数据库熟悉的 SQL 接口。它可以轻松处理 PB 级的数据,并且与许多 NoSQL 数据库不同,即使在分布式全球的情况下,它也可以保证事务的强一致性。

考虑到所有这些,Spanner 适用于需要高度分布式和强一致性数据的应用程序,例如在线银行用例。到 2024 年初,Spanner 还推出了对余弦距离和欧几里得距离比较的支持,我们可以使用这些向量距离函数来执行 K-最近邻KNN)向量搜索,用于相似性搜索或 RAG 等用例。这意味着这种常用于企业级、业务关键工作负载的高度分布式数据库服务现在也支持向量数据库功能。

虽然 Spanner 结合了 NoSQL 和关系型数据库功能的最佳之处,但我将先描述关系型数据库选项,然后再明确介绍 NoSQL 选项。

Cloud SQL 和 pgvector

Cloud SQL 是 Google Cloud 中的一项完全托管的关系型数据库服务,它支持 PostgreSQL、MySQL 和 SQL Server。根据 Google Cloud 文档,“超过 95% 的 Google Cloud 前 100 名客户使用 Cloud SQL 来运营他们的业务。”它通常被视为在 Google Cloud 中使用的默认关系型数据库服务,考虑到它是完全托管的,我们无需担心服务器配置、操作系统更新或数据库补丁,因为 Google 会为我们处理所有这些活动。

虽然 Cloud SQL 本身不支持向量数据库功能,但我们可以使用 <->) 来计算向量之间的距离度量,例如余弦相似度,以帮助我们找到最相似的嵌入。令人兴奋的是,它允许我们使用 SQL 来执行所有这些向量操作,这使得对于熟悉 PostgreSQL 的人来说使用起来非常方便。

除了在 Cloud SQL 中使用 pgvector 与 PostgreSQL 一起使用外,我们还可以将其与 AlloyDB 一起使用,我将在下面进行描述。

AlloyDB AI 向量搜索

AlloyDB 是 Google Cloud 上的一种完全托管且兼容 PostgreSQL 的数据库服务,专为高性能企业级工作负载而设计。与标准 PostgreSQL 相比,它显著提高了性能和可扩展性,并提供了高级功能,如自动扩展、自动故障转移,以及内置的数据库备份和更新。它也适用于混合事务和分析工作负载,最近,它还增加了多个与机器学习相关的功能。

AlloyDB AI 现在也包含了向量相似性搜索功能,因为它在数据库中原生地使用了 pgvector

接下来,我们将讨论在 Google Cloud 中用于向量相似性搜索的 NoSQL 数据库选项。

Google Cloud 中用于向量相似搜索的 NoSQL 数据库选项

Firestore 是 Google Firebase 生态系统中的 NoSQL 数据库。Firebase 本身是一个 Google Cloud 框架,它提供了一系列工具和服务,用于开发移动和 Web 应用程序。除了 Firebase 提供的原始功能外,还有 Firebase 扩展中心,它为用户提供了一种向他们的解决方案添加更多功能的方式。虽然 Firestore 默认不提供向量数据库支持,但可以通过名为 Vertex AI 的语义搜索 的扩展来添加该功能,该扩展通过集成 Vertex AI 向量搜索将文本相似性搜索添加到 Firestore 应用程序中。

在 Google Cloud 中,另一个非常流行的 NoSQL 数据库是 Bigtable。与 Firestore 类似,Bigtable 目前不提供对向量相似搜索用例的原生支持,但它可以与 Vertex AI 向量搜索集成,以帮助构建该目的的解决方案。

现在我们已经介绍了在 Google Cloud 中提供向量数据库支持的数据库选项,包括关系型数据库和无数据库,现在重要的是要描述一种额外的数据存储类型,称为 Memorystore,它用于实现针对极低延迟工作负载的缓存解决方案。

Redis 的 Memorystore

Redis 是一个开源的内存数据存储,这意味着与存储在磁盘上的传统数据库不同,Redis 主要在 RAM 中存储数据,从而提供超快的性能。Redis 的 Memorystore 是 Google Cloud 中的一项完全托管 Redis 服务,它提供可扩展的、高度可用和安全的 Redis 实例,而无需我们管理实例或相关基础设施。

Redis 的 Memorystore 现在也支持 ANN 和 KNN 向量搜索,使我们能够为需要极低延迟响应的应用程序实现内存中的向量存储缓存。

到目前为止,我们已经介绍了 Google Cloud 上大多数主要的生成式人工智能服务。现在,是我们将一些知识付诸实践的时候了,我们将开始在 Google Cloud 上实施生成式人工智能解决方案。

在 Google Cloud 上实施生成式人工智能解决方案

在本节中,我们将创建一个 Vertex AI 搜索和对话应用程序,这将使我们能够询问关于一组文档内容的问题。我们将使用一些公开可用的医学研究报告作为示例,但这种模式可以应用于许多不同的用例。以下是一些其他流行的应用模式:

  • 通过问答界面让零售网站的用户获取有关网站上产品的信息,他们可以提出人类语言问题,并获得有关目录中产品的实际回答。

  • 询问关于财务文件的问题。例如,公司财务部门的员工可以上传公司的财务文件,例如季度收益报告,并就报告内容提出自然语言问题,以识别趋势或其他重要信息。

  • 在公司庞大的内部文档库上提供自然语言搜索。例如,给定一个简单的搜索界面,员工可以询问,“我如何修改我的退休贡献?”他们可以得到一个告诉他们如何操作的响应,以及一个链接到详细描述该过程的内部文档。

我们将使用 Vertex AI 搜索和对话 API 来构建此应用,具体内容将在以下小节中描述。

构建 Vertex AI 搜索和对话应用

在高层次上,我们将执行三个主要活动来构建我们的 Vertex AI 搜索和对话应用:

  1. 启用 Vertex AI 搜索和对话 API。

  2. 创建一个数据存储来存储我们在应用中将使用的数据。

  3. 创建 Vertex AI 搜索和对话应用,以便它可以与我们的数据存储交互。

让我们从启用 Vertex AI 搜索和对话 API 开始。

启用 Vertex AI 搜索和对话 API

要启用 Vertex AI 搜索和对话 API,请执行以下步骤:

  1. 在 Google Cloud 控制台中,在搜索框中输入search并选择搜索和对话

  2. 如果这是您第一次使用此服务,将显示一个类似于图 17.5的页面:

图 17.5:激活 Vertex AI 搜索和对话

图 17.5:激活 Vertex AI 搜索和对话

  1. 点击继续并激活 API(此复选框为可选 – 您可以选择它或将其留空)。

  2. 几秒钟后,您的环境将被创建。将显示一个类似于图 17.6的页面:

图 17.6:Vertex AI 搜索和对话环境页面

图 17.6:Vertex AI 搜索和对话环境页面

现在我们已经启用了 API,我们可以开始设置应用的下一个先决步骤,即创建数据存储。

为 Vertex AI 搜索和对话创建数据存储

在撰写本文时,即 2024 年 3 月,Vertex AI 搜索和对话 API 可以支持以下数据存储源:

  • 网站 URL:自动从您定义的域名列表中爬取网站内容

  • BigQuery:从您的 BigQuery 表中导入数据

  • 云存储:从您的存储桶中导入数据

  • API:通过调用 API 手动导入数据

我们将使用 Google Cloud Storage 作为我们的数据存储,因此我们将首先设置一个位置并将我们的数据上传到那里。下一个小节将描述此过程。

注意

在本书的 第四章 中,我们在云壳环境中创建了一个本地目录,并将我们的 GitHub 仓库克隆到该目录中。如果您没有执行这些步骤,请现在参考这些说明。它们可以在 创建目录和克隆我们的 GitHub 仓库 部分找到。

确保本书的 GitHub 仓库已被克隆到您的云壳环境中的本地目录后,继续执行以下步骤。

将我们的数据存储在 Google Cloud Storage 中

将我们的数据部署到云存储的最简单方法是使用 Google Cloud Shell。要设置我们的数据存储,请执行以下步骤:

  1. 点击屏幕右上角的云壳符号,如图 17.7* 所示:

图 17.7:激活云壳

图 17.7:激活云壳

  1. 这将激活云壳环境,它将出现在屏幕底部。激活环境需要几秒钟。一旦您的环境激活,您可以将以下步骤中提到的命令粘贴并运行到云壳中。

  2. 运行以下命令以设置环境变量,以便您可以存储您首选的区域、云存储桶名称和数据路径(将 YOUR-REGION 替换为您首选的区域,例如 us-central1,将 YOUR-BUCKET-NAME 替换为您 的桶名称):

    export REGION=YOUR-REGION
    export BUCKET=YOUR-BUCKET-NAME
    export BUCKET_PATH=${BUCKET}/data/Chapter-17/
    
  3. 验证桶路径(您还应该复制此命令的响应内容,以备后续步骤参考):

    echo $BUCKET_PATH
    
  4. 如果尚不存在,则创建桶:

    gsutil mb -l $REGION gs://${BUCKET}
    
  5. 切换到存储本章数据的目录:

    cd ~/packt-ml-sa/Google-Machine-Learning-for-Solutions-Architects/Chapter-17/data
    
  6. 将文件上传到桶中(这也会在桶内创建路径):

    for i in *; do gsutil cp $i gs://${BUCKET_PATH}; done
    
  7. 验证文件是否已上传(以下命令应列出文件):

    gsutil ls gs://${BUCKET_PATH}
    

现在我们已经将文件上传到我们的云存储桶中,我们可以为我们的应用程序创建 Vertex AI 搜索和对话数据存储,具体步骤将在下一小节中描述。

注意

本练习中使用的文档的引用可以在本书 GitHub 仓库的 Chapter-17 目录中的 document_citations.txt 文件中找到:github.com/PacktPublishing/Google-Machine-Learning-for-Solutions-Architects/blob/main/Chapter-17/document_citations.txt

创建 Vertex AI 搜索和对话数据存储

在 Vertex AI 搜索和对话中,我们将定义一个与上传到云存储的文件关联的数据存储。为此,请执行以下步骤:

  1. 在 Vertex AI 搜索和对话控制台 UI 中,选择 数据存储 | 创建数据存储 | 云存储

  2. 将显示与图 17.8* 类似的屏幕:

图 17.8:从云存储导入数据

图 17.8:从云存储导入数据

  1. 输入上传文件的路径(这是您在上一节中在 Cloud Shell 环境中为BUCKET_PATH环境变量指定的值)。

  2. 在本例中,我们将使用非结构化文档,因此非结构化文档选项应保持选中状态。

  3. 点击继续。将显示一个类似于图 17.9的屏幕:

图 17.9:配置您的数据存储

图 17.9:配置您的数据存储

  1. 多区域下选择全局(全球)

  2. 默认文档解析器下选择数字解析器

  3. 为数据存储输入一个名称,例如AIML-SA-DS,然后点击创建

现在数据存储已创建,是时候创建 Vertex AI 搜索和对话应用了。

创建 Vertex AI 搜索和对话应用

要创建 Vertex AI 搜索和对话应用,请执行以下步骤:

  1. 在 Vertex AI 搜索和对话控制台 UI 中,选择应用 | 创建新应用 | 搜索

  2. 在随后出现的屏幕上,确保企业版功能高级 LLM 功能复选框已启用,如图 17.10 所示(阅读每个选项的描述以了解其功能):

图 17.10:启用搜索和对话功能

图 17.10:启用搜索和对话功能

  1. 接下来,输入应用名称和公司名称,选择应用的位置,然后选择继续,如图 17.11 所示(注意,如果没有合规性或监管原因需要在特定多区域定位您的数据,请选择全局位置):

图 17.11:应用详情

图 17.11:应用详情

  1. 接下来,选择您希望与我们的应用集成的数据存储,如图 17.12 所示:

图 17.12:选择数据存储

图 17.12:选择数据存储

我们应用的数据处理需要一些时间。定期刷新页面以检查其状态。一旦完成,将显示文件列表。到那时,我们就准备好配置我们希望应用如何表现,如以下小节所述。

配置我们新创建的应用

我们的新搜索和对话应用有多种工作方式,我们可以通过修改其配置来指定我们希望它如何工作。为此,执行以下步骤:

  1. 在 Vertex AI 搜索和对话控制台 UI 中,从页面左侧菜单中选择应用

  2. 点击我们新创建的应用。

  3. 从页面左侧菜单中选择配置

    对于搜索类型配置,有三个选项:

    1. 搜索:只需用相关结果列表响应搜索查询。

    2. 使用答案搜索:在搜索结果列表上方提供生成摘要。

    3. 使用后续问题搜索:提供具有生成摘要和后续问题支持的对话搜索。

  4. 选择使用后续问题搜索选项。

  5. 滚动到用于摘要的大型语言模型部分,并选择 Gemini 的最新版本。

  6. 除非你有任何特定要求更改它们,否则你可以将所有其他选项保留在默认值。

  7. 点击保存并发布

到目前为止,我们已经准备好开始使用我们的应用程序,如下一个子节所述。

使用我们新创建的应用程序

现在我们已经创建了我们的应用程序,我们可以开始使用它。为此,执行以下步骤:

  1. 在 Vertex AI 搜索和对话控制台 UI 中,选择我们新创建应用程序的预览部分。

  2. 我们将看到一个搜索框,我们可以用它来询问我们数据存储中文档的内容。

  3. 从以下问题开始:肉桂对健康有什么影响?

  4. 点击哪些特定的属性有助于其调节血糖水平的能力?

    注意,后续问题只是简单地提到“它”,并没有直接提到肉桂。然而,模型使用前一个问题中的上下文来理解我们的意图。

    此外,请注意,生成的答案可能包含参考文献,用于生成答案的参考文献列在响应中。

  5. 尝试以下附加问题:

    1. 研究中使用的每日肉桂剂量与典型的饮食肉桂摄入量相比如何?

    2. 在 4 周试验期之后,是否有观察到肉桂补充剂的任何长期效果?

    3. 肉桂补充剂如何与其他饮食或生活方式干预措施相互作用以管理糖尿病前期?

    4. 该研究关于肉桂调节血糖作用的发现能否扩展到 1 型或 2 型糖尿病患者?

  6. 接下来,让我们提出一些问题,这些问题将使模型根据集合中的其他文档进行响应。尝试以下问题:

    1. FIM 项目在尝试使用 EHR 数据进行评估时面临的主要挑战是什么?

    2. FIM 项目如何克服有效访问和利用 EHR 数据的障碍?

    3. FIM 项目除了 EHR 数据之外,还可以使用哪些替代数据源来评估健康结果和医疗保健利用?

    4. 医疗保健合作伙伴的隐私和责任担忧如何影响与 FIM 项目共享 EHR 数据?

    5. 白蛋白在儿童的营养状况中扮演什么角色,红豆饼干如何有效改善它?

    6. 哪些具体的饮食干预措施已显示出在改善患有疾病的患者肠道微生物群方面的前景?

    7. 肠道微生物群与身体的相互作用如何影响心理健康障碍,以及涉及哪些机制?

    8. 肠道微生物组的改变能否作为慢性肾脏病发展的早期指标?

这些只是其中的一些例子——请随意尝试使用额外的文档和问题,并思考这种模式如何因为这些奇妙模型的广泛知识而扩展到几乎任何用例。

就这些!你已经成功地在 Google Cloud 中构建了你的第一个生成式 AI 应用!正如你所见,Vertex AI 搜索和对话使我们能够非常容易地做到这一点。幕后,这可以被视为一个 RAG 解决方案,因为我们正在与 Gemini 模型交互,并使其生成基于我们上传到数据存储的文档内容的响应,尽管 Vertex AI 搜索和对话抽象并管理了实现解决方案所需的全部复杂性和步骤。

在下一章中,我们将构建一些额外的更复杂的用例。然而,首先,让我们总结一下本章所学的内容。

摘要

在本章中,我们深入探讨了 Google Cloud 中的生成式 AI,探索了 Google 的本地生成式 AI 模型,如 Gemini、PaLM、Codey、Imagen 和 MedLM API。我们讨论了每个模型的多个版本以及每个的一些示例用例。然后,我们介绍了 Vertex AI Studio,并讨论了通过如 Vertex AI 模型花园和 Hugging Face 等存储库在 Google Cloud 上可用的开源和第三方模型。

接下来,我们讨论了 Google Cloud 中的向量数据库,涵盖了各种可用的选项,例如 Vertex AI 搜索和对话、Vertex AI 向量搜索、BigQuery 向量搜索、Spanner 向量搜索、pgvector和 AlloyDB AI 向量搜索,包括一些在选择一种解决方案而不是另一种时的决策因素。这些决策点通常在解决方案架构师的角色中最为重要,并且决策将根据客户或项目的具体需求而变化,包括每种解决方案的成本。我建议始终咨询每个产品的最新定价信息,并将其纳入你的决策过程中。

最后,我们将本章的一些主题付诸实践,并在 Google Cloud 中构建了一个生成式 AI 应用——具体来说,我们构建了一个 Vertex AI 搜索和对话应用,使我们能够就文档集合的内容提出自然语言问题。

在下一章中,我们将继续使用本书中涵盖的主题,在 Google Cloud 中构建解决方案。请加入我,开始更深入地探索!

第十八章:将一切整合:使用 Google Cloud 和 Vertex AI 构建机器学习解决方案

你终于做到了!这是我们书籍的最后一章。在本章中,我们将通过构建几个示例解决方案来整合本书中学到的主题,这些解决方案结合了我们在整本书中讨论的多个概念和 Google Cloud 服务。本章主要关注构建解决方案,因此文本内容将相对较少,主要活动将在章节附带的 Jupyter Notebook 文件中概述。

本章我们将构建两个解决方案:第一个将更深入地探讨检索增强生成RAG),第二个将是一个端到端解决方案,它结合了传统的机器学习ML)、MLOps 和生成式 AI。

本章的主题如下:

  • 逐步构建 RAG 实现组件

  • 一个示例商业用例和参考架构

  • 构建和实施用例

  • 回顾与下一步

在深入探讨架构细节之前,我们需要执行一个快速先决步骤,以在我们的 Google Cloud 项目中设置所需的环境设置。

先决条件

本节描述了我们需要执行的步骤,以便为本章后面的实施步骤设置我们的环境。

注意

在本书的第四章中,我们在 Cloud Shell 环境中创建了一个本地目录,并将我们的 GitHub 仓库克隆到该目录中。如果您没有执行这些步骤,请现在参考名为 创建目录和克隆我们的 GitHub 仓库第四章中的说明。

当您确保本书的 GitHub 仓库已克隆到您的 Cloud Shell 环境中的本地目录后,继续执行本节中的先决步骤。

使用 Google Cloud Shell

我们将使用 Google Cloud Shell 来执行本节的活动。您可以通过点击 Google Cloud 控制台屏幕右上角的 Cloud Shell 图标来访问它,如图 18.1所示。

图 18.1:激活 Cloud Shell

图 18.1:激活 Cloud Shell

图 18.1所示打开 Google Cloud Shell,并执行以下步骤:

  1. 将目录更改为存储本章代码的位置:

    cd ~/packt-ml-sa/Google-Machine-Learning-for-Solutions-Architects/Chapter-18/prereqs/
    
  2. 运行 chapter-18-prereqs.sh 脚本:

    bash chapter-18-prereqs.sh
    
  3. 如果您被提示授权 Cloud Shell,请点击授权

    该脚本代表我们执行以下步骤:

    1. 授予我们的项目默认 Compute Engine 服务帐户(我们的 Jupyter Notebook、Cloud Functions 和其他组件使用此服务帐户)Eventarc 事件接收器 IAM 角色。如果您想使用除默认 Compute Engine 服务帐户之外的其他服务帐户,则需要将Eventarc 事件接收器 IAM 角色授予该服务帐户。

    2. 授予我们的项目 Pub/Sub 服务代理的服务账户令牌创建者 IAM 角色。这在我们在本章后面使用 Pub/Sub 时是必需的。

现在所有先决条件都已完成,我们可以继续本章的主要内容。我们将首先关注的是逐步构建一个 RAG 实现。

逐步构建 RAG 实现

第十七章中,我们使用 Vertex AI Search 实现了一个 RAG 解决方案。我解释说,Vertex AI Search 使整个过程变得非常简单,因为它抽象掉了过程中的步骤,例如对内容进行块化和嵌入,并在幕后为我们执行所有这些步骤。还有一些流行的框架,如 LlamaIndex,有助于简化 RAG 实现,Vertex AI 还推出了一个基础服务(Vertex AI Grounding),您可以使用它将来自生成模型的响应与 Google 搜索的结果或您自己的数据(使用上述 Vertex AI Search 解决方案)进行关联。在本节中,我们将更深入地探讨这个过程,并逐步构建一个 RAG 解决方案。在我们深入解决方案架构之前,我们将介绍一些在第十七章中抽象掉的概念,特别是关于标记的概念。

标记和块

在本节中,我们将讨论标记和块的概念,从标记开始。

标记

LLMs 通常与标记而不是单词一起工作。例如,在处理文本时,标记通常表示单词的子部分,标记化可以以不同的方式进行,例如通过字符分割文本,或使用基于子词的标记化(例如,“unbelievable”这个词可以分解成子词如“un”,“believe”,“able”)。

标记的确切大小和定义会根据不同的标记化方法、模型、语言和其他因素而有所不同,但使用子词标记化器对英文文本进行标记时,平均每个标记大约有四个字符。

接下来,让我们讨论一下“块”的概念。

在创建嵌入时,我们通常将文档分解成块,然后为这些块创建嵌入。同样,这可以通过不同的方式完成,使用不同的工具。在本章附带的 Jupyter Notebook 文件中,我们使用 Google Cloud Document AI 将我们的文档分解成块。

为了这个目的,我们需要为我们的 Document AI 处理器指定的一个参数是使用的块大小,这在此情况下是通过每个块的标记数来衡量的。你可能需要尝试这个参数的值,以找到最适合你用例的块大小(例如,基于文档部分的长度和结构)。我们通常希望我们的块能够捕捉到一定程度的语义粒度,但在这种粒度方面存在权衡。例如,较小的块可以捕捉到更细粒度的语义上下文并提供更精确的搜索结果,但可能在处理上效率较低。我们还需要确保块大小在所使用的嵌入模型的输入长度限制内,以避免可能的截断。一个好的做法是从一个适中的块大小开始,并根据它如何满足我们的需求进行调整。

幸运的是,Document AI 可以自动根据布局处理块分割,即使你没有指定预配置的块大小,这在你不知道使用什么块大小时可能很有帮助。

现在我们已经涵盖了这些概念,让我们深入了解本章我们将构建的 RAG 实现的架构。

示例 RAG 解决方案架构

在本节中,我们将回顾我们示例 RAG 实现的架构。所提出的解决方案架构显示在图 18.2中。

图 18.2:在 Google Cloud 上逐步展示的 RAG 解决方案

图 18.2:在 Google Cloud 上逐步展示的 RAG 解决方案

你可以看到,在图 18.2中的一些步骤之间,Google Cloud StorageGCS)被用来存储每个步骤的输入和输出,但这些中间过程被省略以使图表更易于阅读。此外,当我们在这个章节伴随的 Jupyter Notebook 中实现此解决方案时,笔记本是协调整个过程中每个步骤的应用程序/用户。

图 18.2中展示的解决方案步骤描述如下:

  1. 我们存储在 GCS 中的文档被发送到 Google Cloud Document AI 进行块分割。正如其名所示,块分割过程将文档分割成块,这些块是文档的较小部分。这是为了创建标准大小的块,作为下一步嵌入过程的输入。块的大小在 Document AI 中是可配置的,关于此过程的更多细节将在稍后描述。

  2. 这些块随后被发送到 Google Cloud 文本嵌入 LLM 以创建块的嵌入。生成的嵌入存储在 GCS 中,与各自的块一起(此步骤在图中省略)。

  3. 我们创建一个 Vertex AI Vector Search 索引,并将嵌入从 GCS 摄入到 Vertex AI Vector Search 索引中(图中省略了 GCS 中间步骤)。

  4. 然后,应用程序/用户提出一个问题,该问题与我们的文档内容相关。该问题作为查询发送到 Google Cloud 文本嵌入 LLM 进行嵌入/向量化。

  5. 将向量化的查询用作请求 Vertex AI 向量搜索的输入,以搜索我们的索引以找到相似的嵌入。记住,嵌入代表语义意义的一个元素,因此相似的嵌入具有相似的意义。这就是我们如何执行语义搜索以找到与我们的查询相似的嵌入。

  6. 接下来,我们从 Vertex AI 向量搜索查询返回的嵌入中找到与这些嵌入相关的 GCS 中的块(记住,我们解决方案中的步骤 2创建了一个块和嵌入的存储关联)。

  7. 现在,终于到了向 Gemini 发送提示的时候了。从步骤 6检索到的文档块作为提示的上下文。这有助于 Gemini 根据我们文档中的相关内容来响应我们的提示,而不仅仅是基于其预训练的知识。

    Gemini 对提示做出响应。

既然我们已经走过了这个过程中的步骤,我们就来实施这个解决方案吧!

在 Google Cloud 上构建 RAG 实现

要构建我们的解决方案,请打开与本章一起提供的 Jupyter Notebook 文件,并执行该文件中描述的活动。我们可以使用在第十四章中创建的相同的 Vertex AI Workbench 实例来完成此目的。请在笔记本实例上打开 JupyterLab。在屏幕左侧的目录浏览器中,导航到 Chapter-18 目录并打开 rag.ipynb 笔记本文件。您可以选择 Python (local) 作为内核。同样,您可以通过选择单元格并在键盘上按 Shift + Enter 来运行笔记本中的每个单元格。除了相关代码外,笔记本文件还包含描述代码正在做什么的 markdown 文本。

当您完成笔记本中的步骤后,您将正式构建自己的 RAG 解决方案——干得好!

注意,在这种情况下,我们使用存储在 GCS 中的文档作为我们的真相来源,但我们也可以使用其他数据,例如存储在 BigQuery 中的数据。

文档引用

为了保持一致性和可比性,我们将使用我们在第十七章中 RAG 实现中使用的相同参考文档之一,如下所示:

Hila Zelicha, Jieping Yang, Susanne M Henning, Jianjun Huang, Ru-Po Lee, Gail Thames, Edward H Livingston, David Heber, and Zhaoping Li, 2024. Effect of cinnamon spice on continuously monitored glycemic response in adults with prediabetes: a 4-week randomized controlled crossover trial. DOI:https://doi.org/10.1016/j.ajcnut.2024.01.008

接下来,我们将构建一个更广泛的解决方案,将本书中许多主题汇集在一起。我将首先解释用例。

一个示例商业用例和参考架构

我们将关注一个计算机视觉CV)用例,用于识别图像中的对象。扩展我们在第十五章中实现的 CV 用例,我们将通过一个 MLOps 管道构建我们的 CV 模型,该管道结合了本书早期章节中的大多数主要主题,例如以下内容:

  • 数据准备、清理和转换

  • 模型训练、部署、推理和评估

我们在这里采用的新颖方法是利用生成式 AI 生成用于测试和评估我们模型的数据。在我们开始构建之前,我将介绍为什么我选择将这个用例作为示例的额外背景。

关于我们用例的额外背景

在整本书中,有一个主题比其他任何主题出现得更频繁:数据往往是训练高质量机器学习模型最重要的因素。没有足够的数据,你的机器学习项目将不会成功。我们讨论过获取足够的数据往往很困难,而且随着模型平均规模的增加,这个挑战正变得越来越普遍(今天的模型拥有万亿级别的参数,需要巨大的数据量)。我们还讨论过世界上数据是有限的,但一个可以帮助解决这个挑战的机制是创建合成数据和使用生成式 AI 模型来生成新数据。本节中我概述的使用案例结合了传统机器学习模型开发生命周期中的所有步骤,并将过程扩展到包括生成可用于测试我们模型的测试数据。在下一小节中,我将描述这个解决方案的架构。

参考架构

本节概述了我们将要构建的解决方案架构的组件。除了 Vertex AI 组件外,参考架构还将其他 Google Cloud 服务纳入范围,以构建整体解决方案,例如 Google Cloud Functions、Pub/Sub、Eventarc 和 Imagen。我们最初在本书的第三章中介绍了并描述了所有这些 Google Cloud 服务。如果您不熟悉它们,我建议您从那一章中复习相关知识。

我们解决方案的起点是一个 MLOps 管道,该管道将训练和部署我们的 CV 模型,我将在稍后详细描述。生成的模型随后被用于更广泛的架构中,以实现整体解决方案。我将首先概述 MLOps 管道。

关于数据集(CIFAR-10)的说明

在我们的模型训练和评估代码中,我们使用一个叫做CIFAR-10加拿大高级研究研究所,10 个类别)的数据集,这是一个 CV 和图像分类中常用的基准数据集。它包含属于十个不同类别的 60,000 个彩色图像:飞机、汽车、鸟、猫、鹿、狗、青蛙、马、船和卡车。每个图像具有固定的 32x32 像素大小,图像存储在 RGB 颜色空间中,这意味着每个像素由三个值表示,分别对应红色、绿色和蓝色颜色通道。当我们想在推理时将生成数据发送到我们的模型时,这些细节非常重要。

CIFAR-10 数据集因其常用于 CV 模型的基准测试而被广泛使用,它包含在 Tensorflow/Keras 的内置数据集模块中。这意味着我们可以通过简单地导入该模块来使用它,而无需从外部源下载数据。

我们的 MLOps 流水线

本节将介绍我们 MLOps 流水线中实现的步骤,如图图 18.3所示。

图 18.3:CV 模型的 MLOps 流水线

图 18.3:CV 模型的 MLOps 流水线

图 18.3中,过程如下所示:

  1. 我们流水线中的第一步——模型训练步骤被调用。虽然我们为表格形式的 Titanic 数据集在第十一章中构建的 MLOps 流水线从使用 Serverless Spark 在 Dataproc 中的独立数据预处理步骤开始,但在本章的流水线中,数据摄取和准备步骤直接在我们的模型训练作业代码中处理。此外,正如所注,在这种情况下,我们使用 Tensorflow/Keras 内置的 CIFAR-10 图像数据集,而不是从外部源获取数据集。Vertex AI 流水线通过向 Vertex AI 训练服务提交模型训练作业来启动模型训练过程。

  2. 为了执行我们的自定义训练作业,Vertex AI 训练服务从 Google Artifact Registry 获取我们的自定义 Docker 容器。

    当我们的模型训练完成后,训练好的模型工件将被保存在 GCS 中。

    模型训练作业状态已完成。

  3. 我们流水线中的下一步——模型导入步骤被调用。这是一个中间步骤,它准备模型元数据,以便在流水线的后续组件中引用。在这种情况下,相关的元数据包括模型工件在 GCS 中的位置以及用于服务我们的模型的 Google Artifact Registry 中 Docker 容器镜像的规范。

  4. 我们流水线中的下一步——模型上传步骤被调用。这一步骤引用了模型导入步骤中的元数据。

  5. 模型元数据被用于在 Vertex AI 模型注册表中注册模型。这使得在 Vertex AI 中部署我们的模型以处理服务流量变得容易。

    模型上传作业状态已完成。

  6. 我们流水线中的下一步——端点创建步骤被调用。

  7. 在 Vertex AI 预测服务中创建了一个端点。这个端点将用于托管我们的模型。

    端点创建作业状态已完成。

  8. 我们流程中的下一步——模型部署步骤被调用。

  9. 我们的模型已部署到 Vertex AI 预测服务中的端点。这一步骤引用了我们流程刚刚创建的端点元数据,以及 Vertex AI 模型注册表中我们的模型元数据。

    模型部署作业状态已完成。

现在我们已经走过了模型训练和部署流程的步骤,我将开始概述本章中我们将构建的更广泛的解决方案架构,其中我们的 MLOps 流程只是其中的一部分。

端到端解决方案

我们将构建一个事件驱动架构,这是开发旨在自动响应事件或一系列事件的无服务器解决方案的流行模式。这是包含本书中我们讨论的大多数主题的端到端解决方案,如图 18.4所示。

图 18.4:端到端解决方案

图 18.4:端到端解决方案

图 18.4中,我们的 MLOps 流程在图的上左角被简化。它仍然实现了我们在上一节中讨论的所有相同步骤,但图被简化了,这样我们就可以将讨论的重点放在更广泛的端到端解决方案上。在这种情况下,MLOps 流程在整体过程中被表示为一个单独的步骤。

注意,Eventarc 在我们的解决方案中占有一席之地,因为它是编排基于事件架构中步骤的主要机制。在伴随本章的 Jupyter Notebook 文件中,我将更详细地解释 Eventarc 在幕后是如何配置的。

以下步骤描述了图 18.4中实现的架构:

  1. 我们的 MLOps 流程训练并部署我们的 CV 模型。

  2. 当 MLOps 流程完成时,它将消息发布到我们为此目的创建的 Pub/Sub 主题。

  3. Eventarc 检测到已向 Pub/Sub 主题发布了一条消息。

  4. Eventarc 触发我们创建的用于生成图像的 Cloud Function。

  5. 我们图像生成函数中的代码调用 Imagen API,并带有提示以生成包含模型训练以识别的一种对象类型的图像(CIFAR-10 数据集支持的对象类型)。

  6. Imagen 生成一个图像并将其返回到我们的函数中。

  7. 我们的功能将新图像存储在 GCS 中。

  8. GCS 发出一个事件,指示已将新对象上传到我们的存储桶。Eventarc 检测到这个事件。

  9. Eventarc 调用我们的下一个 Cloud Function,并将 GCS 事件元数据传递给我们的函数。这些元数据包括诸如存储桶和对象的标识符等详细信息。

  10. 我们的预测函数从事件元数据中获取有关存储桶和所涉及对象的详细信息,并使用这些详细信息来获取新创建的对象(即,从 Imagen 生成的新的图像)。

  11. 我们预测函数随后对图像进行一些预处理,将其转换为模型期望的格式(即,类似于模型训练时所使用的 CIFAR-10 数据的格式)。然后,我们的函数将转换后的数据作为预测请求发送到托管我们模型的 Vertex AI 端点。

  12. 我们的模型预测图像中包含的对象类型,并将预测响应发送到我们的 Cloud Function。

  13. 我们的 Cloud Function 将预测响应保存到 GCS。

当过程完成后,您可以在 GCS 中查看生成的图像和模型的结果预测。

注意,解决方案中的所有步骤都是自动实现的,无需配置任何服务器。这是一个完全无服务器、事件驱动的解决方案架构。

这个解决方案的一个有趣的副作用是,尽管主要目的是在生成数据上测试我们新训练的模型,但此解决方案也可以应用于逆向用例。也就是说,如果我们对我们的模型已经有效训练并提供了持续准确的结果有信心,我们可以使用它来评估生成数据的质量。例如,如果我们的模型预测生成数据包含特定类型的对象,概率为 99.8%,我们可以将其解释为生成数据质量的反映。

既然我们已经讨论了过程中的各个步骤,让我们开始构建它!

在 Google Cloud 上构建和实施用例

要构建我们的解决方案,请打开本章附带的 Jupyter Notebook 文件,并执行该文件中描述的活动。我们可以使用在 第十四章 中创建的相同的 Vertex AI Workbench 实例来完成此目的。请在笔记本实例上打开 JupyterLab。在屏幕左侧的目录浏览器中,导航到 Chapter-18 目录并打开 end-to-end-mlops-genai.ipynb 笔记本文件。您可以选择 Python (local) 作为内核。同样,您可以通过选择单元格并在键盘上按 Shift + Enter 来运行笔记本中的每个单元格。除了相关代码外,笔记本文件还包含描述代码正在做什么的 Markdown 文本。

如果你已经遵循了所有实际步骤并成功构建了解决方案,那么是时候给自己一个热烈的掌声了。让我们花点时间反思一下你所做的事情。你成功构建并执行了一个 MLOps 管道,该管道训练和部署了一个实现 CV 用例的 Keras 卷积神经网络。然后,你使用多种 Google Cloud 服务构建了一个完全无服务器、事件驱动的解决方案架构。这绝对是一件值得骄傲的事情!

当我们接近本章和本书的结尾时,让我们总结一下我们学到了什么,并讨论如何在这个领域继续学习。

概述和下一步

在本章中,我们结合了本书中涵盖的大多数重要概念,并解释了它们是如何相互关联的。我们通过构建包含我们讨论的许多主题和 Google Cloud 产品的解决方案来实现这一点。

首先,你逐步构建了一个 RAG 实现,在这个过程中,你专注于结合各种生成式 AI 概念,例如使用 Google Cloud Document AI 将文档分割成块,同时保留原始文档的层次结构。这个解决方案还包括使用 Google Cloud 文本嵌入 LLM 为文档块创建嵌入,并使用 Vertex AI Vector Search 存储和索引这些嵌入。你使用这个解决方案来实现了一个与 Gemini 结合的问题回答用例,将答案基于文档内容。为此,你使用 Google Cloud 文本嵌入 LLM 创建提示问题的嵌入,并使用这些嵌入在 Vertex AI Vector Search 中执行语义相似度搜索,以找到与文档特定块相关的相似嵌入。然后,将这些块作为上下文提供,当向 Gemini 发送请求时。

接下来,你构建了一个结合了本书中许多主题的解决方案,包括传统模型开发生命周期的所有步骤,以及生成式 AI 和更广泛解决方案架构的概念。这导致了一个完全自动化、无服务器、事件驱动的解决方案,其中包含了多个 Google Cloud 服务,如 Google Cloud Functions、Pub/Sub、Eventarc 和 Imagen。

我们在这本书中确实涵盖了大量的主题,学习之旅永远不会结束。让我们通过讨论如何在 Google Cloud 解决方案架构、机器学习和生成式 AI 领域继续你的学习之旅来结束这一部分。

下一步

本书所讨论的技术领域正以越来越快的速度发展,每天都有新的框架和模式出现,其中生成式 AI 可以说是发展最快的领域之一。例如,除了本书中讨论的流行 LangChain 框架,它还可以在 Vertex AI 推理引擎中实现为托管体验之外,这些框架的扩展,如 LangGraph、LangSmith 以及许多其他扩展也不断涌现,为构建生成式 AI 解决方案和应用提供了额外的功能和灵活性。由于这一领域的发展速度不断加快,以及整体上的兴奋情绪,新的学习资源将持续出现。除了与本书相关的 GitHub 仓库之外,许多其他示例仓库提供了关于如何实现各种模式的宝贵教程。其中最有价值的当然是官方 Vertex AI 示例仓库,您可以通过以下链接访问:

github.com/GoogleCloudPlatform/vertex-ai-samples

我还发现langchain.com上提供的信息是一个有用的学习资源,我强烈推荐您参考 Google Cloud 解决方案中心中的示例架构用例,您可以通过以下链接访问:

solutions.cloud.google.com/

在我们结束之前,请记住,本书中使用的实际练习和笔记本在 Google Cloud 上创建了资源,这可能会产生费用。因此,我建议您回顾本书中执行的所有实际步骤,并确保如果您不再计划使用它们,则删除所有资源。与本书相关的 GitHub 仓库包含删除模型、端点和数据存储等资源的方法。对于其他类型的资源,请参阅 Google Cloud 文档,以确保删除相关资源。

我在撰写这个最后一部分时,感到一种悲伤,因为我们共同的经历即将结束,我想感谢您与我一起踏上这段旅程。如果您已经阅读到本书的这一部分,那么您已经获得了 AI/ML、生成式 AI、Google Cloud 和解决方案架构的专家知识,并且您现在对这些主题的了解比世界上大多数人都多!恭喜您,做得好!我祝愿您在未来的 AI 冒险中一切顺利,并希望您能运用您的知识和技能取得美好的成就!

posted @ 2025-09-04 14:10  绝不原创的飞龙  阅读(52)  评论(0)    收藏  举报