谷歌机器学习和生成式人工智能的解决方案架构(三)
原文:
annas-archive.org/md5/90c02ac66d0c0f03912aac73223f0fbf译者:飞龙
第十二章:偏差、可解释性、公平性和血统
现在我们已经学习了在谷歌云中构建和部署模型以及自动化整个机器学习(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)的指标来衡量这种差异,该指标由以下公式定义:
这里,代表无特权组获得有利结果的可能性,而 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 美元)表示,当使用收入作为目标变量时,这创建了一个二元分类用例。
在探索这些数据时,我们可以提出以下问题:
-
特征值,如种族和性别,是否在一定程度上均匀或不均匀地表示?
-
是否存在某些特征值与该人收入之间的相关性?
我们可以通过使用数据可视化技术轻松地看到数据集中的不平衡。让我们看看一些例子。
按性别划分的收入分布
以下代码将向我们展示数据集中每个性别在两种不同的收入类别(即每年收入不超过 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中,我们可以看到,总体而言,数据集中收入超过 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中,对于“<=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 中,我们可以看到诸如年龄、每周小时数和资本收益等特征似乎在预测收入方面非常重要。这些特征的影响是否对你来说直观易懂?
注意,特征重要性并不表示因果关系。仅仅因为一个特征被认为很重要,并不意味着它会导致目标变量发生变化;只是表示存在关联。
当我们在 Jupyter 笔记本中具体使用 scikit-learn 的feature_importances_属性时,其他流行的机器学习库也提供了类似的机制。例如,TensorFlow 的增强树(tf.estimator.BoostedTreesClassifier或tf.estimator.BoostedTreesRegressor)也提供了feature_importances_属性来获取每个特征的重要性。同样,LightGBM 和 CatBoost 分别提供了feature_importances_和get_feature_importance(),而 XGBoost 提供了plot_importance()函数用于可视化。
虽然feature_importances_和其他机器学习库中的类似机制非常有用,但我们还可以使用更高级的工具来评估特征重要性,我将在下文中描述。
局部依赖性图
部分依赖图(PDPs)是用于理解输入特征(或一组输入特征)与模型预测结果之间关系的图形可视化。使用 PDPs,我们只改变一个特征的值,同时保持所有其他特征的值不变,以确定该特定特征的各个值如何影响预测。PDPs 也可以同时使用多个输入特征,这可以揭示多个特征之间的相互作用。还有 PDPs 的扩展形式,称为个体条件期望(ICE)图。虽然 PDPs 显示了特征对预测的平均影响,但 ICE 图显示了特征对单个实例预测的影响。
使用 PDPs,对于感兴趣特征的每个唯一值,都会执行以下高级步骤:
-
将数据集中每个实例的感兴趣特征设置为该值。
-
使用模型进行预测。
-
平均预测值。
-
将平均预测与特征的唯一值进行绘图。
以下代码使用 scikit-learn 的PartialDependenceDisplay属性创建并显示 PDP 图形:
features = ['age', 'hours-per-week']
PartialDependenceDisplay.from_estimator(clf, X, features)
此代码将生成一个类似于图 12.4所示的图形:
图 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的顶部,我们看到模型对输入实例的预测。在这种情况下,由于这是一个二元分类问题,它显示了模型预测的类别,以及与该预测相关的概率分数。我们还看到一个表示各种特征对预测影响的水平条形图。每个条形代表一个特征及其影响。条形的长度表示影响的重要性,其方向(左或右)表示影响的方向(例如,指向“<=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 值是该特征值对每个可能预测的平均贡献(对所有实例进行平均),它考虑了与其他特征的复杂交互,以及特征本身的影响。
虽然我们可以将 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 Tool(WIT)最初由 Google 开发,是一个早期的可解释性工具,具有可视化界面,允许检查模型的预测、比较不同模型以及检查潜在的偏差。它相对容易使用,不需要太多编码,并且包括了对我们在本章中讨论的许多概念的支持,例如反事实和 PDPs。
AI Fairness 360
IBM 的AI Fairness 360(AIF360)是一个开源库,包括一组用于数据集和模型的公平性指标以及减轻偏差的算法。它可以用来提供详细的解释,以理解公平性指标及其在特定环境中的含义,并使用户能够可视化地探索数据集和模型中的偏差。它还可以帮助识别训练好的模型是否产生了偏差的结果,并提供一些工具来帮助在每个模型开发生命周期阶段(如预处理、训练和后处理)减轻偏差。
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 控制台中,执行以下步骤:
-
导航到Vertex AI > Pipelines。
-
点击在第十一章中创建的管道运行名称(除非在此期间你在该 Google Cloud 项目中运行了其他管道,否则它应该是最近的管道运行)。
-
你将看到管道运行的执行图。
-
在屏幕顶部,点击展开工件(Expand Artifacts)左侧的切换按钮(参见图 12.7 以获取参考):
图 12.7:展开工件
-
现在我们可以开始探索与管道中每个步骤和工件相关的元数据。
-
你还会注意到,屏幕右侧的管道运行分析部分包含大量关于此管道运行的信息。摘要(SUMMARY)选项卡提供了有关管道运行本身的信息,包括用作输入的参数。这些是我们第十一章中管道定义中定义的参数。
-
我们可以点击管道执行图中的元素,以查看与该特定元素相关的元数据。让我们从开始的地方开始。我们想知道哪个数据集被用作管道的初始输入。考虑到我们的管道中的第一步是数据预处理步骤,并且该步骤检索数据集,点击预处理步骤,其元数据将显示在屏幕右侧,如图图 12.8 所示:
图 12.8:预处理步骤详情
-
在图 12.8 中,绿色的箭头指向
source_dataset输入参数,它提供了源数据集的路径(为了隐藏我的存储桶名称,图像中的实际细节已被删除)。 -
我们还可以看到
preprocessed_data_path参数的值,它提供了预处理脚本将存储结果处理数据的文件夹路径。如果你向下滚动(截图未显示),你也会看到main_python_file_uri参数的值,它提供了我们用于管道预处理步骤的 PySpark 脚本的路径。实际上,如果我们点击查看作业按钮,我们可以查看用于在 Google Cloud Dataproc 上执行我们的脚本的实际无服务器 Spark 作业的详细信息,包括其执行日志。 -
现在我们已经成功追踪了我们的源数据集、对数据集进行转换的脚本和作业,以及用于训练我们的模型的处理后的数据集,接下来让我们转向管道中的下一个步骤,即模型训练步骤。
-
在我们的管道执行图中点击
custom-training-job步骤。在右侧的信息面板中,可能最重要的参数是worker_pool_specs参数。如图图 12.9所示,该参数提供了关于我们的模型如何训练的大量信息,例如用于训练的数据集(这是前一个预处理步骤的输出),训练模型工件保存的位置,用于运行自定义训练代码的容器镜像,训练期间使用的超参数值,以及训练作业使用的机器类型和机器数量:
图 12.9:worker_pool_specs
-
再次,如果我们点击屏幕顶部的查看作业按钮,我们可以看到在 Vertex AI 训练服务上运行的实际作业,以及该作业的执行日志。
-
因为我们使用自定义脚本来训练我们的模型,并将工件简单地保存在 Google Cloud Storage 中,在这个管道阶段,我们的模型被称为
importer作业,用于导入我们的模型工件。 -
管道中的
model-upload步骤是将我们的模型注册到 Vertex AI 模型注册表中的步骤。如果你在执行图中点击该步骤并查看其元数据,在输出参数部分,你会看到 Vertex AI 模型注册表中结果资源的 URI。 -
剩余的步骤
endpoint-create和model-deploy具有类似的格式。正如它们的名称所暗示的,endpoint-create步骤在 Vertex AI 预测服务中创建一个端点,而model-deploy步骤将我们的模型部署到该端点。它们的输出参数将显示由这些步骤创建的资源 URI。 -
我想引起您的注意,在管道中
endpoint和model工件。如果您点击这些工件,并在屏幕右侧的信息面板中点击出现的查看谱系按钮,它将直接带您到 Vertex AI 元数据服务控制台,并显示步骤和工件之间相互关系的另一种视图,如图图 12.10所示。再次强调,点击图中每个元素都会显示该元素的元数据:
图 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 实验
当我们在第十一章中创建管道定义时,我们指定了一个实验名称来关联我们的管道运行。这为我们提供了另一种查看与我们的管道运行和它们创建的模型版本相关的步骤和工件的方式。此功能对于共享和协作以及比较不同的模型版本非常有用。要查看与我们的管道运行关联的实验,请执行以下步骤:
-
在 Google Cloud 控制台中,导航到Vertex AI > 实验。
-
点击我们在 MLOps 章节中指定的实验名称(
aiml-sa-mlops-experiment)。 -
点击最近运行的名称,并探索如图图 12.11所示的工件标签页:
图 12.11:Vertex AI 实验 – 工件视图
- 点击每个工件 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 审计日志捕获三种类型的日志。
数据隐私
虽然与数据安全内在相关,但数据隐私更具体地关注于个人信息(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
算法
在我们的文档中,我们应该讨论为什么选择特定的机器学习算法,包括与其他考虑的算法的比较,以及解释该算法为何适合当前问题的理由,根据适当的相关文献或经验证据进行引用。同样重要的是详细说明算法的配置,包括针对项目的任何特定定制。
超参数
我们应该包括模型使用的所有超参数的详细信息,为每个提供定义和范围,以及用于超参数调整的过程,例如网格搜索、随机搜索或贝叶斯优化。此外,我们还应包括每个超参数选择的最终值,并解释为什么选择这些特定的值,并支持调整过程的结果。
额外因素
我们的文档还应解释如何评估模型的表现,包括使用的指标(均方误差(MSE),ROC 曲线下面积(ROC-AUC))以及这些评估的结果。我们应该记录模型已知的任何局限性,记录模型预测中的潜在偏差,并描述这些偏差如何影响不同的群体或个人。我们还需要详细说明与模型相关的任何监管标准或伦理指南,并讨论如何确保合规性。最后,我们需要概述在生产环境中持续监控模型表现和行为的计划,包括处理模型漂移、异常或性能下降的策略。
模型版本控制
就像在传统软件开发中的代码版本控制一样,在机器学习项目中进行模型版本控制对于确保团队能够追踪模型的演变过程、复制结果、在必要时回滚到先前版本,以及维护整个模型生命周期中所有变更的记录至关重要。这在大型或协作环境中尤为重要,因为在这样的环境中,随着时间的推移,可能由许多不同的人或团队开发出多个模型的多个迭代。对于调试、持续改进、审计和合规性目的来说,这也同样重要。图 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 目录
这种一致控制的观念在治理的背景下尤其相关。使用 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 Storage(GCS)中的存储层或优化 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 模型开发生命周期
让我们从模型开发生命周期中的数据收集和准备活动开始,这些活动包括收集、摄取、存储和处理数据。
揭秘!
你会注意到,我们已经在整本书中使用了许多这些实践。在这里,我们明确指出这些实践,以便你了解它们如何应用于一般的工作负载。
数据收集和准备
数据管理可能是与 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 Engine(GCE)的放置策略(特别是“紧凑放置策略”)来指定我们的虚拟机应彼此靠近,这对于高性能计算(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 ML(BQML)、我们可以用于 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 内核:
-
在您在 第五章 中创建的 Vertex AI Notebook 实例上打开 JupyterLab。
-
选择 文件 | 新建 | 终端,并在终端屏幕上执行以下步骤。
-
创建一个 Conda 环境:
conda create --name bigframes-env -y -
激活环境:
conda activate bigframes-env -
安装
bigframes(我们也可以安装我们想要的任何其他包,但现在我们将保持简单):conda install bigframes -y -
在新环境中安装 JupyterLab(这将使我们的新 Conda 环境通过 JupyterLab 的自动发现功能作为内核可用):
conda install jupyterlab -y -
更改内核的显示名称(此更新可能需要几分钟才能在 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 活动中使用。为此,请执行以下步骤:
- 进入 Google Cloud 控制台,通过点击 Cloud Shell 图标打开 Cloud Shell,如图 图 14 所示。此图标看起来像是一个“大于”符号,后面跟着一个下划线——即 >_:
图 14.1:激活 Cloud Shell
-
在 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 -
在 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*.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,并执行以下步骤:
-
在屏幕左侧的导航面板中,导航到
Google-Machine-Learning-for-Solutions-Architects文件夹内的Chapter-14目录。 -
双击
pandas-gbq.ipynb笔记本文件以打开它。当提示选择内核时,您可以使用默认的**Python 3 (**ipykernel)内核。 -
双击
bigframes.ipynb笔记本文件以打开它。当提示选择内核时,您可以使用我们在本章的“先决主题和步骤”部分创建的默认**Python 3 (bigframes)**内核。 -
在您打开的每个笔记本中,按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,并执行以下步骤:
-
在屏幕左侧的导航面板中,导航到
Google-Machine-Learning-for-Solutions-Architects文件夹内的Chapter-14目录。 -
双击
BQML.ipynb笔记本文件以打开它。当提示时,选择默认的**Python 3 (ipykernel)**内核。 -
按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 作业。我们可以以多种方式实现这项工作负载,在我们的实践活动中,我们将介绍以下两种方法:
-
使用与我们在第十一章中执行的活动类似的 MLOps 管道。
-
使用 Vertex AI 中的无服务器 Spark 用户界面。
让我们从第一种方法开始:使用 MLOps 管道。
通过 Vertex AI 上的 Kubeflow Pipelines 实现的无服务器 Spark
在第十一章中,我们使用了 Kubeflow Pipelines 中的DataprocPySparkBatchOp操作符来自动化 MLOps 管道中无服务器 Spark 作业的执行。在本章中,我们将再次使用该操作符,但这次我们将使用它来运行使用 Spark MLlib 进行模型训练和评估的作业。为此,打开你在第五章中创建的 Vertex AI Workbench 实例上的 JupyterLab,并执行以下步骤:
-
在屏幕左侧的导航面板中,导航到
Google-Machine-Learning-for-Solutions-Architects文件夹中的Chapter-14目录。 -
双击
spark-ml.ipynb笔记本文件以打开它。当你被提示选择内核时,选择**Python 3 (****ipykernel)**内核。 -
在你打开的每个笔记本中,按Shift + Enter来执行每个单元格。
笔记本中包含注释和 Markdown 文本,描述了每个单元格中代码的功能。
如我们所见,将我们在第十一章中执行的活动扩展到使用 Kubeflow Pipelines 来自动化用于模型训练的无服务器 Spark 作业,Spark MLlib 非常简单。让我们看看运行我们的无服务器 Spark 作业的另一种选项,即通过 Vertex AI 的无服务器 Spark 用户界面直接运行。
Vertex AI 中的无服务器 Spark 用户界面
要访问 Vertex AI 中的无服务器 Spark 用户界面,打开你在第五章中创建的 Vertex AI 工作台实例上的 JupyterLab,并执行以下步骤:
-
从文件菜单中选择新建启动器。
-
滚动到Dataproc 作业和会话部分,并选择无服务器。
-
选择创建批量。
-
在出现的屏幕上(参见图 14.4以供参考),输入以下详细信息:
-
pyspark-ml.py文件。它应该具有以下格式gs://YOUR-BUCKET-NAME/code/additional-use-cases-chapter/pyspark-ml.py。 -
--``processed_data_path=gs://YOUR-BUCKET-NAME/data/processed/mlops-titanic -
--``model_path=gs://YOUR-BUCKET-NAME/models/additional-use-cases-chapter/
-
- 将所有其他字段保留在默认值,并在屏幕底部点击提交:
图 14.3:Vertex AI 中的无服务器 Spark 用户界面
点击提交按钮后,将出现一个屏幕,显示一系列无服务器 Spark 作业的列表;你新提交的作业将出现在列表的顶部(你可能需要刷新浏览器页面来更新列表)。等待直到作业状态显示为成功。
-
如果作业因任何原因失败,点击作业名称以显示其详细信息,然后点击屏幕顶部的查看云日志。
-
日志填充可能需要一些时间。你可以定期点击运行查询按钮来刷新日志。
-
当作业执行完毕后,模型工件将被保存在两个目录中,分别命名为
metadata和stages,位于你为--model-path参数指定的位置。通过在 Google Cloud 控制台中执行以下步骤来验证这些目录是否已创建并填充:- 前往 Google Cloud 服务菜单,通过点击路径的每个后续组件来选择
--model-path参数 – 例如,YOUR-BUCKET-NAME/models/additional-use-cases-chapter/。
- 前往 Google Cloud 服务菜单,通过点击路径的每个后续组件来选择
干得好!你刚刚使用 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 和云计算”部分中进行的讨论,我在其中描述了将我们的模型扩展到更大尺寸的过程,从我们可以在笔记本电脑上训练的小型模型开始,逐步过渡到在强大、高端服务器上训练的大型模型,最终达到单台计算机(即使是市场上最强大的服务器)无法处理模型的大小或训练模型的数据集的规模。在本节中,我们将更详细地探讨训练这样的大型模型意味着什么。
我们在本书中详细介绍了模型训练过程,但为了知识复习,我将在下面简要总结这个过程,因为这些概念在讨论大规模分布式模型训练时很重要。对于这次讨论,我将专注于神经网络的监督训练。
监督训练过程在高级别上工作如下:
-
我们的训练数据集的实例被输入到模型中。
-
模型算法或网络处理训练实例,并且对于每个实例,它试图预测目标变量。在神经网络的情况下,这被称为前向传播。
-
在做出预测后,模型使用损失函数(例如,回归中的均方误差(MSE)或分类中的交叉熵)计算错误或损失,该函数衡量模型预测与实际标签(真实值)之间的差异。
-
然后开始反向传播过程,它将微积分中的链式法则应用于计算关于网络中每个权重的损失函数的梯度。
-
优化算法,如梯度下降,利用在反向传播期间计算的梯度来更新网络中的权重。
训练通常通过在一系列的 epoch 中多次循环执行前面的过程来完成,其中 epoch 是整个训练数据集的一次完整遍历。然而,当使用大型数据集时,训练过程可以将整体数据集划分为更小的批次,并且每个批次的遍历被视为一个训练步骤。此外,一些框架,如 TensorFlow,允许我们指定每个 epoch 的训练步骤数。随着时间的推移,如果模型学习有效,那么在每个 epoch 之后,其预测将变得更加准确,损失将减少(希望达到可接受的阈值)。
注意
在这些讨论中,术语处理器指的是 CPU、GPU 和 TPU。此外,本节中我们将讨论的概念可以应用于单个机器上多个处理器或多个机器上的多个处理器上分布的训练工作负载。
在分布式训练用例中,处理器之间需要一些通信和数据共享。当使用单个机器时,处理器通常共享相同的系统内存(RAM),这简化了数据共享,但当使用多台机器时,通信需要在网络(包括路由器、交换机等)上发生,这可能会引入延迟和额外的复杂性。
我们在本书中已经多次实现了训练过程。接下来,我们将讨论当我们使用多个处理器时它是如何工作的。
数据并行性和模型并行性
通常有两个主要原因我们需要实现分布式训练工作负载:
-
我们希望使用一个非常大的数据集
-
我们希望训练一个非常大的模型
注意,这两种场景可能同时存在(也就是说,我们可能需要在非常大的数据集上训练一个非常大的模型)。在本节中,我将详细解释这些场景,从使用大型数据集的情况开始。
数据并行
有时,我们需要在巨大的数据集上训练我们的模型,这些数据集仅在一个处理器上处理需要很长时间。为了使训练过程更高效,我们可以将数据集分成更小的子集或批次,并在多个处理器上并行处理它们。在这种情况下,我们可以在每个处理器上运行我们模型的副本,该副本处理加载到该处理器上的数据子集。一个简单的例子是,如果我们有一个包含 10,000 个数据点的数据集,并且我们运行了 10 个处理器,每个处理器处理数据集中的 1,000 个数据点。这种方法被称为数据并行,并在 图 14.5 中表示:
图 14.4:数据并行
在 图 14.5 中,每个紫色方块代表我们的数据的一个批次,每个批次都并行发送到单独的处理器。图中的每个批次只包含几个数据点,但在现实中,批次会大得多(此图旨在从高层次上说明概念)。接下来,我们将讨论我们可能需要实现分布式训练工作负载的另一个主要场景。这被称为模型并行。
模型并行
有时,模型本身可能非常大,以至于无法在一个处理器上放入内存。在这些情况下,我们需要将模型分散到多个处理器上,每个处理器处理模型的不同部分或段。一个段可以是网络中的一层,或者在一些非常复杂的模型中是层的部分。图 14.6 展示了一个简单的模型并行示例,其中我们神经网络中的每一层都在一个单独的处理器上运行:
图 14.5:模型并行
我们可以使用不同的方法将我们的模型分解成段,我们通常希望选择一种方法,以最小化处理器之间的通信开销。这是因为这个过程可能会引入最大的延迟和复杂性,尤其是在我们使用多台机器,通信需要在物理网络上发生时。
除了优化处理器之间的通信外,我们还需要以最大化每个处理器利用率的方式设计我们的训练程序。记住,我们神经网络中某一层的输出成为我们网络中其他层的输入,因此层之间存在顺序依赖性。当我们的层分布在不同的处理器上时,一些处理器可能会空闲,等待从网络中前一层传播输入。这当然是对我们处理资源的低效使用,我们可以使用一种称为流水线的方法,通过将输入数据分成微批来提高训练效率。在这种情况下,每个段或阶段处理其微批,并将输出传递到下一阶段。然后,当下一阶段开始处理输出时,前一阶段可以开始处理下一个微批,依此类推。这样,数据以更流畅的方式在网络中流动,而不是后续层的处理器在等待早期层处理整个大型数据集时处于空闲状态。
到目前为止,我主要在谈论如何从模型处理输入的角度(即在训练过程中的前向传递)来并行化训练过程。记住,训练过程还包括一个反馈循环来检查模型的输出,计算与真实值的损失,然后计算损失的梯度并更新权重。接下来,我们将深入探讨这些步骤如何以分布式的方式进行实现。
分布式训练更新过程
在模型并行的情况下,数据仍然按顺序通过网络进行处理——也就是说,网络中的每一层(或段)都会产生输出,这些输出成为下一层的输入(即使这些层或段在不同的处理器上被处理)。因此,反向传播过程也可以按顺序进行,其中梯度是从最后一个段开始计算到第一个段,类似于在非分布式设置中的做法。每个段独立地根据计算出的梯度更新其模型权重的部分。
然而,在数据并行的情况下,训练数据的子集会在不同的处理器上并行处理,因此整体工作流程不是顺序的。每个处理器都有一个模型的相同副本,但每个副本处理不同的数据子集。因此,每个处理器上的模型副本对其他处理器正在做什么一无所知。因此,在计算损失、梯度和权重时需要额外的协调。
我们可以通过各种方式实现这种协调,但我们应该通常选择以下两种选项之一:
-
使用集中式的参数服务器进行协调
-
实现一个协议,允许单个训练服务器作为一个社区行动(我将将其称为“协作计算”)
让我们更详细地讨论这些方法,从参数服务器方法开始。
参数服务器方法
在参数服务器方法中,分布式系统中的一个或多个节点被指定为参数服务器,这些节点持有全局模型参数。这意味着它们对所有节点在分布式训练系统或集群中的所有模型副本的梯度参数具有全局视图。
在这种情况下,单个训练节点(让我们称它们为“工作节点”)处理不同的数据子集并计算各自的梯度,然后每个工作节点将其梯度发送到集中的参数服务器(们)。然后参数服务器(们)根据这些梯度更新全局模型参数,并将更新的参数发送回工作节点。这种方法的简化架构图如图14.7所示:
图 14.6:参数服务器方法
在图 14.7中,箭头表示工作节点和参数服务器(们)之间梯度和工作更新之间的交换。虚线和边框表示可能存在一个或多个参数服务器,因为单个参数服务器可能会成为解决方案的瓶颈。此外,在这个架构中还需要有一个协调实体来管理所有资源和它们的通信。这可以与参数服务器共址,也可以作为一个单独的服务器实现。
接下来,我们将讨论使用数据并行性实现模型训练的另一种选项,在这种选项中,不是使用集中式服务器来执行协调步骤,而是所有工作节点直接相互协作。
使用环全归约的协作计算方法
在协作计算方法中,没有中央服务器或一组服务器专门用于在训练集群中的独立工作节点之间执行协调。相反,使用分布式计算协议在节点之间进行协调。这意味着节点从彼此那里获取更新(在这种情况下,计算出的梯度)。存在许多用于分布式计算系统之间协调的通信协议,其中一种相当流行的协议被称为全归约。这类协议通常设计用于聚合分布式系统中的所有节点的数据,然后将结果返回给所有节点。这意味着,尽管每个节点可能处理我们数据集的不同子集,并且每个节点上的模型实例因此可能计算不同的梯度和权重,但每个节点最终都会得到一个梯度权重的聚合表示,该表示在所有节点上是一致的。
当使用全归约时,我们可以以各种方式连接处理器,例如通过实现完全连接的网格,如图14.8所示,环形架构,如图图 14**.9所示,或其他方法,例如树形和蝴蝶架构,我们在这里不会涉及:
图 14.7:完全连接的网格
如图 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*.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:一个简单的神经网络
另一方面,CNN 在架构中添加了一些特定的层,这些层有助于实现我们在本节引言中提到的分层处理。这些类型的层将在以下子节中从高层次上进行解释。
卷积层
这些层执行一种称为卷积的数学运算,它涉及将一个滤波器(或核)在输入图像上滑动以生成一个特征图。滤波器是一个用于检测特定特征(如边缘、角或纹理)的小矩阵,每个滤波器在输入图像上卷积,计算滤波器和输入之间的点积,从而生成一个特征图。
因此,卷积层的输出是一组特征图,这些特征图代表了在输入图像的不同位置由过滤器检测到的特定特征。
池化层
池化层主要用于通过下采样特征图和减少参数数量来进行降维。我们在第七章中详细介绍了降维的概念,并讨论了在训练和部署机器学习模型时,通常有必要实现降维以减少所需的计算量,以及降低过拟合训练数据的可能性。可以使用不同的池化方法,但最常见的方法称为“最大池化”,它从一个区域(由池大小定义)的像素集中取最大值。另一种方法,称为“平均池化”,简单地取一个区域内像素值的平均值。
全连接层
将卷积层和池化层结合使用,可以得到从输入图像中提取的特征。在输入数据通过卷积层和池化层后,网络中的高级推理是通过使用全连接层来完成的。这些就是我们讨论前馈神经网络(FFNNs)时提到的层,其中每一层的神经元都与前一层的所有激活连接。正如 FFNNs 的情况一样,全连接层通常用于网络执行的最终分类或回归任务。
最终输出层通常使用 softmax 激活函数来输出模型试图识别的类别的概率分布。对于二分类,也可以使用 sigmoid 函数。
残差网络
残差网络,或称 ResNets,是一种为了解决梯度消失和梯度爆炸问题而开发的 CNN,我们曾在第九章中讨论过这个问题。它们通过引入“跳过连接”来实现这一点,这些跳过连接“跳过”网络中的某些层,并将一层输出直接连接到后续层的输入。
关于 CNN 内部工作原理的细节,我们就介绍到这里。许多研究论文都详细介绍了 CNN 的工作原理,但这超出了本书的范围。接下来,我们将深入探讨,并通过一些代码示例来构建我们第一个用于计算机视觉用例的 CNN!
在本章附带的 Jupyter Notebooks 中,我们将使用 Keras 构建一个简单的 CNN。这也是你开始学习如何使用 PyTorch 的地方,然后我们将使用 PyTorch 来完成相同的任务。
构建卷积神经网络(CNN)
要构建我们的 CNN,请在第五章中创建的 Vertex AI Workbench 实例上打开 JupyterLab,并执行以下步骤:
-
在屏幕左侧的导航面板中,导航到
Google-Machine-Learning-for-Solutions-Architects文件夹中的Chapter-14目录。 -
双击
Keras-CV.ipynb笔记本文件以打开它。当提示选择内核时,选择TensorFlow内核。 -
双击
PyTorch-CV.ipynb笔记本文件以打开它。当提示选择内核时,选择PyTorch内核。 -
在你打开的每个笔记本中,按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.doi.org/10.1207/s15…. |
| LSTM | 1997 | Hochreiter, Sepp & Schmidhuber, Jürgen. (1997). Long Short-term Memory. Neural computation. 9. 1735-80. 10.1162/neco.1997.9.8.1735.doi.org/10.1162/nec…. |
| 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. arxiv.org/abs/1706.03…. |
表 14.1:序列模型开发中的垫脚石
让我们从深入研究 RNNs 开始。
RNNs
当你阅读这个句子中的每个单词时,你需要记住之前的单词,以便你可以理解整个句子的含义。这是自然语言理解(NLU)的应用,它是 NLP 的一个子领域。在更通用的意义上,这个句子代表了序列数据,因为句子中的数据点(在这种情况下,是单词)与句子中的其他单词相关,并且它们被处理的顺序很重要。图 14.12展示了序列数据被输入到神经网络中的例子:
图 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:目标变量与输入特征的分离
接下来,让我们看看概率如何在 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:将目标变量与输入特征连接
这里一个主要的不同点是,虽然判别模型使用条件概率来预测给定输入变量值的目标变量的值,但生成模型试图学习数据集的整体联合概率分布,包括目标变量。
通过学习数据集的整体联合概率分布,模型可以理解数据集是如何构建的,以及所有特征是如何相互关联的,包括目标变量。通过这种方式,通过准确近似训练数据集的构建方式,它可以估计如何创建在数据集中尚未存在但具有相似结构和组成的相似数据点——也就是说,它可以生成新的、相似的内容。
除了联合概率分布之外,今天的生成模型通过使用我们在本书中多次引用的著名论文《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 模型和方法。但在这里,我专注于对 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 架构
在自动编码器(AE)的前向传递过程中,每个输入数据点都会通过网络中的编码器部分。这一部分网络将输入压缩成潜在空间(隐藏层)中更小、更密集的表示。然后,编码后的数据会通过网络中的解码器部分,解码器试图从压缩的表示中重建原始输入数据。这是自动编码器(AE)与传统、判别性模型之间有趣的不同之处——也就是说,传统模型通常试图根据输入(X)预测输出(Y),而自动编码器(AE)则试图预测(或生成)原始输入(X)。
就像我们在传统的神经网络中所做的那样,我们可以计算输出值与预期值(X)之间的差异,这被称为重建误差,然后我们可以使用反向传播来更新网络并继续常规的训练周期。重建的质量取决于自动编码器(AE)在潜在空间中学习表示数据的程度。
在这个训练过程中,编码器学习只保留数据中最相关的特征,有效地学习了一种在较小维度的空间中表示输入数据的新方法。潜在空间随后包含了网络学习到的关于数据的压缩知识——即数据的本质。再次引用我的同事 Jeremy Wortz 的描述,瓶颈特征的概念与嵌入的质量相关;由于我们通常在编码器和解码器之间“挤压”我们最关键的信息,因此特征的重要性被隐式优化。
然而,需要注意的是,尽管自动编码器(AE)可以学习重建原始数据集,从而学习如何执行降维以在低维空间中准确表示数据,但它们并不是为了生成新数据而设计的。为了实现这一功能,我们需要将概率分布引入图像中,这就是变分自动编码器(VAEs)发展的原因,我将在下面描述。
VAEs
VAE 通过引入概率方法扩展了自动编码器(AE)的概念,以生成与训练数据结构相似的新数据点。基于我们关于自动编码器(AE)如何工作的讨论,描述 VAE 的最简单方法就是强调它们与常规自动编码器之间的细微差别。
与传统的自动编码器(AE)一样,变分自动编码器(VAE)由编码器和解码器组成。然而,与常规的自动编码器不同,VAE 中的编码器将输入数据映射到潜在空间上的概率分布。这需要很多内容,所以让我们进一步澄清。
如我们在前一节所学,常规的 AE 将输入数据编码成一个包含表示原始输入的潜在特征的向量。然而,在 VAEs 的情况下,编码器不是为每个数据样本学习潜在空间中的单个点,而是学习概率分布。更准确地说,编码器不是在潜在空间中输出特定的特征值,而是输出描述潜在空间中特征概率分布的参数(如均值和标准差)。这个分布代表了编码器认为输入数据应该被编码的位置。这种方法在编码过程中引入了随机性或可变性,这对于可能生成与输入数据相似的新数据点至关重要,而不仅仅是原始数据的重建。
以下是在输入通过 VAE 时执行的高级步骤:
-
编码器提供潜在空间内概率分布的参数。
-
从这个学习到的分布中采样一个点。
-
然后将这个采样点通过解码器,解码器试图从这个概率编码中重建输入数据。
目标,再次强调,是使原始输入与其重建之间的差异最小化,类似于常规的 AE。
然而,除了重建误差之外,VAEs 在其损失函数中还有一个额外的项,被称为Kullback-Leibler(KL)散度,它衡量了每个输入学习到的分布与标准正态分布偏离的程度。不深入数学细节,重要的是要理解 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(来源:developers.google.com/machine-lea…
如果判别器认为一个数据点是真实的,而实际上它是被生成器创建的,这算作一个错误。因此,这会增加判别器的错误率,这对生成器来说是一个胜利。相反,如果判别器能够准确地将数据点分类为伪造的,那么它就会降低判别器的错误率(当然,这对判别器来说也是一个胜利)。
当判别器使用典型的机制,如梯度下降,从其错误中学习并最小化损失时,生成器也可以从判别器的错误中学习,并通过一个旨在增加判别器错误率的反向过程调整其权重。这是 GANs 使用的创新方法,在训练过程中,生成器不会直接接收到“好”或“坏”的直接标签,而是接收到关于判别器性能的反馈。如果判别器能够准确识别出伪造的,那么梯度就会发送回生成器,以便它能够更新其权重,在下一轮中创建一个更能欺骗判别器的输出。
在这个过程中,生成器学习真实数据的潜在概率分布,并变得更加擅长生成与该概率分布一致的新数据(即具有与真实数据相似属性的新数据)。同时,了解每个网络在训练过程中轮流进行也很重要。当生成器正在训练时,判别器的权重被冻结,反之亦然。
通过以这种方式让模型相互对抗,它们必须不断变得更好才能超越对方。随着判别器在识别伪造数据方面变得更好,生成器学会生成更逼真的数据来欺骗判别器,如此循环。
自从 2014 年由 Ian Goodfellow 和同事们首次创建以来,GANs 获得了极大的流行,出现了多种不同类型的 GAN 实现,例如 条件 GANs(cGANs)、CycleGANs、StyleGANs、深度卷积 GANs(DCGANs)和渐进式 GANs。对所有这些变体的全面讨论将超出本书所需的详细程度。如果您对这些变体有特别的兴趣,我鼓励您进一步研究。
重要提示 – 注意“模式崩溃”
除了在训练许多类型的神经网络架构时面临的典型挑战,如梯度爆炸和梯度消失,GANs 还经常遭受与它们的对抗训练过程相关的特定挑战。这个问题被称为“模式崩溃”,指的是生成器可能开始产生有限种类的输出,尤其是如果这些输出成功地欺骗了判别器。由于生成器的主要目标是欺骗判别器,它可能学会生成有效的模式来做到这一点,但这些模式并不能准确代表目标数据分布。这是一个持续的研究领域,其中正在引入新的机制来对抗这种现象。
接下来,让我们讨论一些 GANs 的常见应用。
GANs 的应用
除了生成逼真的图像和逼真的音频数据外,GANs 还可用于其他有趣的用例,例如风格迁移和图像到图像的翻译。例如,一些在线服务允许你上传一张照片,并将其转换为卡通或模仿梵高等著名艺术家的风格,使其看起来像油画。虽然这些应用很有趣,但 GANs 还被用于各种用例,如文本生成、新药发现以及其他类型的合成数据生成。
我们将在后面讨论高质量合成数据的重要性,但接下来,我想介绍另一种流行的 GenAI 方法,称为 扩散。
扩散
扩散被用于许多与 GANs 相同类型的用例,如图像和音频生成、图像到图像的翻译、风格迁移,甚至新的药物发现。然而,扩散使用不同的方法,并且对于某些用例通常提供更理想的结果。在本节中,我们将深入了解扩散模型和 GANs 之间的差异,但首先,像往常一样,让我们了解什么是扩散以及它是如何工作的。
高层次概念——噪声和去噪
在高层次上,扩散主要由两个主要步骤组成:
-
向图像添加噪声
-
反转这个过程——即去除噪声以回到原始图像
我将更详细地描述这些概念,首先从阐明向图像添加噪声的含义开始。图 15.6显示了包含噪声的图像:
图 15.6:噪声图像(来源:commons.wikimedia.org/wiki/File:2…
如果你们中的一些人曾经看到过图 15.6所示的图像,那么你们可能对在电视屏幕上未调谐到提供图像信号的频道时显示的噪声很熟悉。这个图像纯粹由噪声组成,我们无法辨认出任何可辨别的形状。然而,如果我们向一张高质量的图像添加一些噪声,那么它就会变得有些模糊,但我们仍然可以辨认出图像中的内容,只要添加的噪声不是太多。我们添加的噪声越多,识别图像内容就越困难。
这个概念在训练扩散模型时的噪声过程中被使用。我们向图像添加少量噪声,使其逐渐难以识别图像中的内容。这也被称为正向****扩散过程。
然后,反向扩散或去噪过程试图从一个噪声图像中恢复,并逐步回到原始图像。这听起来可能有点没有意义——也就是说,为什么要费心向图像添加噪声,然后再训练一个模型来学习如何去除噪声以生成原始图像?好吧,正如 GANs 的情况一样,我们正在训练我们的模型来理解原始数据集的概率分布。更深入一点,我们的模型实际上学会了预测输入中的噪声。因此,过程的下一步就是简单地从输入中去除噪声,以便估计或生成所需的去噪输出。
这个被称为扩散的原因可能有些不言自明,但更具体地说,这个名字与非平衡热力学领域的一个概念有关。这听起来有点复杂,但不用担心——我们不会深入探讨物理概念,只是简要介绍为什么它被这样命名。
常常用来解释这个概念的类比是想象将一滴墨水添加到水桶中。当墨水被添加到水中时,最初,它在桶中一个特定的位置占据了一小片空间。然而,随着时间的推移,墨水会在整个水桶中扩散。很快,它就遍布了整个水桶,水桶中包含着水和墨水的混合物。水桶中内容的颜色可能与你添加墨水之前存在的颜色不同,但已无法确定墨水在水桶中的具体位置。这就是正向扩散过程,其中墨水在整个水桶中的水中扩散。
在物理世界中,这种扩散过程通常是不可能逆转的——也就是说,无论你尝试做什么,你都无法将墨水从水中分离出来,并将墨水滴重新凝结回最初添加到桶中的位置。
然而,在机器学习中的扩散过程中,我们试图逆转这个过程,回到原始输入状态。
深入探讨
重要的是要理解噪声是以受控方式添加到数据中的。我们不仅仅添加完全随机的噪声,而是添加所谓的高斯噪声,这意味着噪声具有“正常”(或“高斯”)概率分布的特征。作为复习,高斯分布由熟悉的“钟形曲线”表示,如图 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中,我们可以看到英语中各种单词之间的关系。注意有些单词可能是模糊的,比如单词“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 只是使用提供的示例来调整其响应,使其与这些示例保持一致。
在光谱的另一端是全 FT(FFT)。这种级别的调整可能需要数千个示例,并且模型的参数会根据这些示例进行更新(即模型学习并将新数据纳入其核心结构)。
然后,还有介于两者之间的级别,例如适配器调整,在这种调整中,适配器层被插入到原始模型中,并且只有这些层被调整和更新,而原始模型的权重保持冻结。另一种调整可能只关注更新模型的输出层,而其余模型保持不变。
在一个稍微独立但相关的方面,我想简要介绍从人类反馈中进行强化学习(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 的语言理解和生成能力,以及通过使用工具和代理与环境交互来执行动作(如规划和管理假期)的能力。然而,为了简单起见,在本书的其余部分,我将交替使用LLM和GenAI 模型这两个术语。
高级调优和优化技术
在上一章的结尾,我们讨论了 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**.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 提示和响应
如我们所见,典型的 LLM 交互简单地说就是发送一个提示并得到一个响应。请注意,LLM 只能理解数值,因此幕后,用户发送的文本提示被分解成标记,这些标记被编码成 LLM 可以理解的向量。当向用户发送响应时,执行反向过程。接下来,让我们看看 RAG 如何改变这个过程,如图 16.4 所示:
图 16.4:RAG
图 16.4 概述了 RAG 在高级别上是如何工作的。步骤如下:
-
用户或客户端应用程序发送文本请求或提示。
-
将提示内容转换为向量(嵌入)。
-
在过程的“检索”部分,使用提示嵌入在向量数据库中查找相似的嵌入。这些嵌入代表我们想要用来增强提示的数据(例如,代表我们产品目录数据的嵌入)。
-
将我们的向量数据库中的嵌入与用户提示的嵌入相结合,并发送到 LLM。
-
LLM 使用用户提示和检索到的嵌入的组合来增强其响应,旨在提供不仅基于其最初训练的数据,而且在从我们的向量数据库检索到的数据上下文中也相关的响应。
-
将响应嵌入解码以向用户或客户端应用程序提供文本响应。
我们将在本书的后续章节中实现 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 Score(IS)和Fréchet Inception Distance(FID)。
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 服务和实现。