🔎大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎
📝个人主页-Sonhhxg_柒的博客_CSDN博客 📃
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
📣系列专栏 - 机器学习【ML】 自然语言处理【NLP】 深度学习【DL】
🖍foreword
✔说明⇢本人讲解主要包括Python、机器学习(ML)、深度学习(DL)、自然语言处理(NLP)等内容。
如果你对这个系列感兴趣的话,可以关注订阅哟👋
文章目录
让我们从一位高管告诉我的一个故事开始这一章,许多读者可能会对此产生共鸣。大约两年前,他的公司聘请了一家咨询公司来开发一个 ML 模型,以帮助他们预测下周他们需要的每种杂货商品的数量,以便他们可以相应地补货。这家咨询公司花了六个月的时间来开发这个模型。当咨询公司移交模型时,他的公司部署了它,并对它的性能非常满意。他们终于可以向投资者吹嘘他们是一家人工智能驱动的公司。
然而,一年后,他们的人数下降了。对某些物品的需求一直被高估,导致额外的物品过期。与此同时,对某些商品的需求一直被低估,导致销售损失。1最初,他的库存团队手动更改了模型的预测以纠正他们注意到的模式,但最终,模型的预测变得如此糟糕,以至于他们无法再使用它。他们有三个选择:向同一家咨询公司支付巨额资金来更新模型,向另一家咨询公司支付更多的钱,因为这家公司需要时间来跟上进度,或者聘请内部团队来维护模型向前。
他的公司以惨痛的方式吸取了业内其他人也发现的重要教训:部署模型并不是过程的结束。在生产过程中,模型的性能会随着时间的推移而下降。部署模型后,我们仍然必须持续监控其性能以检测问题并部署更新以解决这些问题。
在本章和下一章中,我们将介绍必要的主题,以帮助您将模型保持在生产中。我们将首先介绍在开发过程中表现出色的 ML 模型在生产中失败的原因。然后,我们将深入探讨影响生产中几乎所有 ML 模型的一个特别普遍且棘手的问题:数据分布变化。当生产中的数据分布与模型在训练期间暴露的数据分布不同并背离时,就会发生这种情况。我们将继续讨论如何监控分布变化。在下一章中,我们将介绍如何在生产中不断更新您的模型以适应数据分布的变化。
机器学习系统故障的原因
在我们确定 ML 系统故障的原因之前,让我们简要讨论一下 ML 系统故障是什么。失败当系统的一个或多个期望被违反时,就会发生这种情况。在传统软件中,我们主要关心系统的操作预期:系统是否在预期的操作指标内执行其逻辑,例如延迟和吞吐量。
对于 ML 系统,我们关心其操作指标和 ML 性能指标。例如,考虑一个英法机器翻译系统。它的操作预期可能是,给定一个英文句子,系统在一秒钟的延迟内返回一个法语翻译。它的 ML 性能期望是返回的翻译在 99% 的时间都是对原始英语句子的准确翻译。
如果你在系统中输入了一个英文句子并且没有返回一个翻译,那么就违反了第一个期望,所以这是一个系统故障。
如果您返回不正确的翻译,则不一定是系统故障,因为准确度预期允许存在一定的误差范围。但是,如果你不断地在系统中输入不同的英文句子并不断返回错误的翻译,则违反了第二个期望,从而导致系统故障。
运营预期违规更容易检测到,因为它们通常伴随着操作中断,例如超时、网页上的 404 错误、内存不足错误或分段错误。然而,ML 性能预期违规更难检测,因为这样做需要测量和监控生产中 ML 模型的性能。在前面的英法机器翻译系统示例中,如果我们不知道正确的翻译应该是什么,则很难检测返回的翻译是否 99% 的时间正确。用户使用谷歌翻译的错误翻译的例子不胜枚举,因为他们不知道这些是错误的翻译。出于这个原因,我们说 ML 系统经常默默地失败。
为了有效地检测和修复生产中的 ML 系统故障,了解为什么模型在开发过程中证明运行良好后会在生产中失败是很有用的。我们将检查两种类型的故障:软件系统故障和特定于 ML 的故障。
软件系统故障
软件系统故障是非 ML 系统会发生的故障。以下是软件系统故障的一些示例:
依赖失败
软件包或代码库您的系统依赖于中断,这会导致您的系统崩溃。当依赖由第三方维护时,这种故障模式很常见,如果维护依赖的第三方不再存在,则尤其常见。2
部署失败
部署错误导致的故障,例如,当您不小心部署了模型的旧版本而不是当前版本的二进制文件时,或者当您的系统没有读取或写入某些文件的正确权限时。
硬件故障
当您使用的硬件部署模型(例如 CPU 或 GPU)的行为不符合预期。例如,您使用的 CPU 可能会过热并发生故障。3
停机或崩溃
如果您的系统的一个组件从某处的服务器(例如 AWS 或托管服务)运行,并且该服务器已关闭,您的系统也将关闭。
仅仅因为某些故障不是 ML 特有的,并不意味着它们对于 ML 工程师来说并不重要。2020 年,Google 的两名 ML 工程师 Daniel Papasian 和 Todd Underwood 研究了 96 个 Google 大型 ML 管道发生故障的案例。他们回顾了过去 15 年的数据以确定原因,发现这 96 次故障中有 60 次是由于与 ML 没有直接关系的原因而发生的。4大多数问题与分布式系统有关,例如,工作流调度程序或协调器出错,或与数据管道有关,例如,来自多个源的数据被错误地连接或使用了错误的数据结构。
解决软件系统故障需要的不是 ML 技能,而是传统的软件工程技能,解决它们超出了本书的范围。由于传统软件工程技能在部署 ML 系统中的重要性,ML 工程主要是工程,而不是 ML。5对于有兴趣从软件工程的角度学习如何使 ML 系统可靠的读者,我强烈推荐由 O'Reilly 和 Todd Underwood 作为作者之一出版的Reliable Machine Learning一书。
软件系统故障盛行的一个原因是,由于行业中 ML 的采用仍处于初期阶段,围绕 ML 生产的工具有限,最佳实践尚未得到很好的开发或标准化。然而,随着 ML 生产的工具和最佳实践的成熟,有理由相信软件系统故障的比例将会降低,而 ML 特定故障的比例将会增加。
特定于 ML 的故障
特定于 ML 的故障是特定于 ML 系统的故障。示例包括数据收集和处理问题、糟糕的超参数、训练管道中的更改未在推理管道中正确复制(反之亦然)、导致模型性能随时间恶化的数据分布变化、边缘情况和退化的反馈循环。
在本章中,我们将专注于解决特定于 ML 的故障。尽管它们占故障的一小部分,但它们可能比非 ML 故障更危险,因为它们难以检测和修复,并且它们可以阻止 ML 系统完全被使用。我们在第 4 章中详细介绍了数据问题,在第 6章中讨论了超参数调整,以及在第 7 章中使用两个单独的管道进行训练和推理的危险。. 在本章中,我们将讨论部署模型后出现的三个新的但非常常见的问题:生产数据不同于训练数据、边缘情况和退化的反馈循环。
生产数据与训练数据不同
当我们说 ML 模型学习从训练数据中,这意味着模型学习了训练数据的潜在分布,目的是利用这种学习的分布来为看不见的数据(它在训练期间没有看到的数据)生成准确的预测。我们将在“数据分布变化”一节中讨论这在数学上的含义。当模型能够为看不见的数据生成准确的预测时,我们说这个模型“泛化到了看不见的数据”。6我们在开发过程中用来评估模型的测试数据应该代表看不见的数据,并且模型在测试数据上的表现应该让我们了解模型的泛化程度。
我在 ML 课程中学到的第一件事就是训练数据和看不见的数据必须来自类似的分布。假设是看不见的数据来自 与训练数据分布相同的平稳分布。如果看不见的数据来自不同的分布,则模型可能无法很好地概括。7
这种假设在大多数情况下是不正确的,原因有二。首先,现实世界数据的底层分布不可能 与训练数据的底层分布相同。管理一个能够准确表示模型在生产中遇到的数据的训练数据集被证明是非常困难的。8现实世界的数据是多方面的,在许多情况下几乎是无限的,而训练数据是有限的,并且受数据集创建和处理期间可用的时间、计算和人力资源的限制。如第 4 章所述,存在许多不同的选择和抽样偏差,这可能会发生并使真实世界的数据与训练数据不同。这种差异可能与使用不同类型的表情符号编码的真实世界数据一样小。这种类型的分歧导致了一种常见的故障模式,称为训练服务偏差:一种在开发中表现出色但在部署时表现不佳的模型。
其次,现实世界不是静止的. 事情会改变的。数据分布发生变化。2019 年,人们搜索武汉时,他们可能想获取旅行信息,但自从 COVID-19 以来,人们搜索武汉时,他们可能想了解 COVID-19 的起源地。另一种常见的故障模式是模型在首次部署时表现出色,但随着数据分布的变化,其性能会随着时间的推移而下降。
当我以导致数据转移的 COVID-19 为例时,有些人的印象是数据转移只是由于不寻常的事件而发生,这意味着它们不会经常发生。数据变化无时无刻不在发生,突然、逐渐或季节性地发生。它们可能由于特定事件而突然发生,例如当您现有的竞争对手改变他们的定价政策并且您必须更新您的价格预测作为回应时,或者当你在一个新的地区推出你的产品,或者当名人提到你的产品时,这会导致新用户的激增,等等。它们可以逐渐发生,因为社会规范、文化、语言、趋势、行业等只是随着时间的推移而变化。它们也可能由于季节变化而发生,例如人们可能在寒冷多雪的冬天比春天更可能要求拼车。这会导致新用户激增,等等。它们可以逐渐发生,因为社会规范、文化、语言、趋势、行业等只是随着时间的推移而变化。它们也可能由于季节变化而发生,例如人们可能在寒冷多雪的冬天比春天更可能要求拼车。这会导致新用户激增,等等。它们可以逐渐发生,因为社会规范、文化、语言、趋势、行业等只是随着时间的推移而变化。它们也可能由于季节变化而发生,例如人们可能在寒冷多雪的冬天比春天更可能要求拼车。
由于 ML 系统的复杂性和部署它们的不良实践,监控仪表板上可能看起来像数据转移的很大一部分是由内部错误引起的,9例如数据管道中的错误、错误输入的缺失值、之间的不一致在训练和推理过程中提取的特征、使用来自错误数据子集的统计数据标准化的特征、错误的模型版本或强制用户改变行为的应用界面。
由于这是一种影响几乎所有 ML 模型的错误模式,我们将在“数据分布转变”部分详细介绍这一点。
边缘案例
想象一下,有一辆自动驾驶汽车可以在 99.99% 的时间里安全地驾驶你,但在另外 0.01% 的时间里,它可能发生灾难性事故,可能使您永久受伤甚至死亡。10你会用那辆车吗?
如果你想拒绝,你并不孤单。如果这些故障导致灾难性后果,则在大多数情况下表现良好但在少数情况下失败的 ML 模型可能无法使用。出于这个原因,主要的自动驾驶汽车公司正致力于让他们的系统在边缘情况下工作。11
边缘案例是极端的数据样本,它们会导致模型出现灾难性错误。尽管边缘情况通常是指从同一分布中提取的数据样本,但如果您的模型表现不佳的数据样本数量突然增加,则可能表明基础数据分布已发生变化。
自动驾驶汽车通常用于说明边缘情况如何阻止 ML 系统的部署。但这也适用于任何安全关键型应用,例如医疗诊断、交通控制、电子发现、12等。它也适用于非安全关键型应用。想象一下,一个客服聊天机器人可以对大多数请求做出合理的回应,但有时,它会吐出令人发指的种族主义或性别歧视内容。对于任何想要使用它的公司来说,这个聊天机器人都会带来品牌风险,从而使其无法使用。
边缘案例和异常值
您可能想知道异常值和边缘情况之间的区别。边缘案例的定义因学科而异。在 ML 中,由于最近在生产中采用,边缘情况仍在被发现,这使得它们的定义存在争议。
在本书中,异常值指的是数据:一个与其他示例显着不同的示例。边缘案例是指性能:模型表现明显比其他示例差的示例。异常值可能导致模型表现异常差,这使其成为边缘情况。但是,并非所有异常值都是边缘情况。例如,在高速公路上乱穿马路的人是异常值,
在模型开发过程中,异常值会对模型的性能产生负面影响,如图 8-1所示. 在许多情况下,删除异常值可能是有益的,因为它可以帮助您的模型学习更好的决策边界并更好地泛化到看不见的数据。但是,在推理过程中,您通常无法选择删除或忽略与其他查询有显着差异的查询。您可以选择对其进行转换——例如,当您在 Google 搜索中输入“mechin learning”时,谷歌可能会问你是否指的是“机器学习”。但很可能您会想要开发一个模型,以便它即使在意外输入上也能表现良好。
图 8-1。左边的图像显示了没有异常值时的决策边界。右图显示了存在异常值时的决策边界,这与第一种情况下的决策边界非常不同,并且可能不太准确。
退化的反馈回路
在“自然标签”一节中,我们讨论了反馈循环作为从显示预测到提供有关预测的时间反馈所花费的时间。反馈可用于提取自然标签以评估模型的性能并训练模型的下一次迭代。
退化的反馈回路当预测本身影响反馈时,就会发生这种情况,而反馈反过来又会影响模型的下一次迭代。更正式地说,当系统的输出用于生成系统的未来输入时,就会创建一个退化的反馈回路,这反过来又会影响系统的未来输出。在 ML 中,系统的预测会影响用户与系统的交互方式,并且由于用户与系统的交互有时被用作同一系统的训练数据,因此可能会出现退化的反馈循环并导致意想不到的后果。退化反馈循环在具有用户自然标签的任务中尤其常见,例如推荐系统和广告点击率预测。
具体来说,假设您构建了一个系统来向用户推荐他们可能喜欢的歌曲。系统排名靠前的歌曲首先展示给用户。因为它们首先显示,所以用户点击它们的次数更多,这使系统更加确信这些推荐是好的。一开始,A和B两首歌的排名可能只有一点点不同,但因为A本来排名高一点,所以在推荐榜上的排名更高,让用户点击A的次数多了,系统排名A就更高了。一段时间后,A的排名变得比B高很多。13退化的反馈循环是流行电影、书籍或歌曲越来越受欢迎的原因之一,这使得新项目很难进入流行列表。这种类型的场景在生产中非常常见,并且已经过大量研究。它有许多不同的名称,包括“曝光偏差”、“人气偏差”、“过滤气泡”,有时还有“回声室”。
这是另一个将退化反馈回路的危险带回家的例子。想象一下,建立一个简历筛选模型来预测具有特定简历的人是否有资格胜任这份工作。该模型发现特征 X 可以准确预测某人是否合格,因此它会推荐具有特征 X 的简历。您可以将 X 替换为“去了斯坦福”、“在 Google 工作”或“识别为男性”等特征。14了解您的模型如何进行预测——例如衡量每个特征对模型的重要性,如第 5 章所述——可以帮助检测在这种情况下对特征 X 的偏差。
无人看管的退化反馈循环可能会导致您的模型表现不佳。在最坏的情况下,他们可以使嵌入数据中的偏见长期存在并放大,例如对没有特征 X 的候选人的偏见。
检测退化的反馈回路
如果退化反馈回路如此糟糕,我们如何知道系统中的反馈回路是否退化?当系统离线时,很难检测到退化的反馈回路。用户反馈会导致退化循环,系统在上线之前(即部署给用户)才会有用户。
对于推荐系统的任务,即使系统处于离线状态,也可以通过测量系统输出的流行度多样性来检测退化反馈循环。一个项目的受欢迎程度可以基于它过去被交互的次数(例如,看到、喜欢、购买等)来衡量。所有项目的受欢迎程度可能会遵循长尾分布:少数项目与大量交互,而大多数项目根本没有交互。各种指标,例如 Brynjolfsson 等人提出的长尾项目的总体多样性和平均覆盖率。(2011)、Fleder 和 Hosanagar (2009) 以及Abdollahpouri 等人。(2019) 可以帮助您衡量推荐系统输出的多样性。15低分意味着你的系统的输出是同质的,这可能是由流行度偏差引起的。
2021 年,Chia 等人。更进一步,提出了命中率与人气的衡量标准。他们首先根据物品的受欢迎程度将物品分为桶——例如,桶 1 由交互次数少于 100 次的项目组成,桶 2 由交互次数超过 100 次但小于 1000 次的项目组成,等等。然后他们测量了每个桶的推荐系统的预测准确性。如果推荐系统在推荐受欢迎的商品方面比推荐不太受欢迎的商品要好得多,那么它可能会受到受欢迎程度偏差的影响。16一旦您的系统投入生产,并且您注意到它的预测随着时间的推移变得更加同质化,它可能会受到退化的反馈回路。
纠正退化的反馈回路
因为退化的反馈回路是一个常见的问题,所以有很多关于如何纠正的方法他们。在本章中,我们将讨论两种方法。第一个是使用随机化,第二个是使用位置特征。
我们已经讨论过退化的反馈回路会导致系统的输出随着时间的推移变得更加均匀。在预测中引入随机化可以降低它们的同质性。在推荐系统的情况下,我们不会只向用户显示系统对他们排名靠前的项目,而是向用户显示随机项目并使用他们的反馈来确定这些项目的真实质量。这是 TikTok 遵循的方法。每个新视频都会随机分配一个初始流量池(最多可有数百次展示)。此流量池用于评估每个视频的无偏见质量,以确定是否应将其移至更大的流量池或将其标记为不相关。每个新视频都会随机分配一个初始流量池(最多可有数百次展示)。此流量池用于评估每个视频的无偏见质量,以确定是否应将其移至更大的流量池或将其标记为不相关。每个新视频都会随机分配一个初始流量池(最多可有数百次展示)。此流量池用于评估每个视频的无偏见质量,以确定是否应将其移至更大的流量池或将其标记为不相关。17
随机化已被证明可以提高多样性,但以牺牲用户体验为代价。18向我们的用户展示完全随机的项目可能会导致用户对我们的产品失去兴趣。一种智能探索策略,例如“上下文强盗作为探索策略”一节中讨论的那些,可以帮助增加项目的多样性,同时具有可接受的预测精度损失。施纳贝尔等人。使用少量随机化和因果推理技术来估计每首歌曲的无偏值。19他们能够证明该算法能够纠正推荐系统,使推荐对创作者公平。
我们还讨论过退化的反馈循环是由用户对预测的反馈引起的,并且用户对预测的反馈会根据其显示的位置而产生偏差。考虑前面的推荐系统示例,每次向用户推荐五首歌曲。您意识到与其他四首歌曲相比,最受推荐的歌曲更有可能被点击。
如果显示预测的位置以任何方式影响其反馈,您可能希望使用 位置特征对位置信息进行编码。位置特征可以是数字的(例如,位置是 1、2、3,...)或布尔值(例如,预测是否显示在第一个位置)。请注意,“位置特征”不同于第 5 章中提到的“位置嵌入”.
这是一个简单的例子来展示如何使用位置特征。在训练过程中,您将“是否首先推荐歌曲”作为特征添加到您的训练数据中,如表 8-1所示。此功能使您的模型可以了解成为热门推荐对歌曲被点击的可能性有多大影响。
表 8-1。 向您的训练数据添加位置特征以减轻退化的反馈循环
ID | Song | Genre | Year | Artist | User | 1st Position | Click |
---|---|---|---|---|---|---|---|
1 | Shallow | Pop | 2020 | Lady Gaga | listenr32 | False | No |
2 | Good Vibe | Funk | 2019 | Funk Overlord | listenr32 | False | No |
3 | Beat It | Rock | 1989 | Michael Jackson | fancypants | False | No |
4 | In Bloom | Rock | 1991 | Nirvana | fancypants | True | Yes |
5 | Shallow | Pop | 2020 | Lady Gaga | listenr32 | True | Yes |
在推理过程中,您想要预测用户是否会点击歌曲,而不管歌曲在哪里被推荐,因此您可能希望将 1st Position 特征设置为 False。然后,您查看模型对每个用户的各种歌曲的预测,并可以选择显示每首歌曲的顺序。
这是一个幼稚的例子,因为单独这样做可能不足以对抗退化的反馈循环。更复杂的方法是使用两种不同的模型。第一个模型预测用户将看到并考虑推荐的概率,同时考虑到该推荐将显示的位置。看到并考虑了它。第二个模型根本不关心职位。
数据分布转变
在上一节中,我们讨论了 ML 系统故障的常见原因。在本节中,我们将归零特别棘手的故障原因:数据分布转移,或简称数据转移。数据分布偏移是指监督学习中模型处理的数据随时间变化的现象,这导致该模型的预测随着时间的推移变得不那么准确。训练模型的数据分布称为源分布。模型运行推理的数据分布称为目标分布。
尽管随着 ML 在行业中越来越多地采用近年来有关数据分布转变的讨论才变得普遍,但早在 1986 年就已经研究了从数据中学习的系统中的数据分布转变。20 还有一本关于数据集分布的书shifts, Quiñonero-Candela 等人在机器学习中的数据集转移,麻省理工学院出版社于 2008 年出版。
数据分布变化的类型
虽然数据分布偏移通常与概念偏移和协变量偏移以及偶尔的标签偏移互换使用,但这是数据偏移的三种不同子类型。请注意,关于不同类型的数据转移的讨论涉及大量数学,并且从研究的角度来看最有用:开发有效的算法来检测和解决数据转移需要了解这些转移的原因。在生产中,当遇到分布变化时,数据科学家通常不会停下来想知道它是什么类型的变化。他们最关心的是他们能做些什么来应对这种转变。如果您发现此讨论很密集,请随时跳到该部分“一般数据分布变化”。
要了解概念漂移、协变量偏移和标签偏移的含义,我们首先需要定义几个数学符号。让我们称模型X的输入及其输出Y。我们知道,在监督学习中,训练数据可以看作是来自联合分布P ( X , Y ) 的一组样本,然后 ML 通常对P ( Y | X ) 进行建模。这种联合分布P( X , Y ) 可以通过两种方式分解:
-
P ( X , Y ) = P ( Y | X ) P ( X )
-
P ( X , Y ) = P ( X | Y ) P ( Y )
P ( Y | X ) 表示给定输入的输出的条件概率——例如,给定电子邮件内容的电子邮件成为垃圾邮件的概率。P ( X ) 表示输入的概率密度。P ( Y ) 表示输出的概率密度。标签偏移、协变量偏移和概念偏移定义如下:
协变量移位
当P ( X ) 改变但 P ( Y | X ) 保持不变时。这指的是联合分布的第一次分解。
标签移位
当P ( Y ) 改变但 P ( X | Y ) 保持不变时。这是指到联合分布的第二次分解。
概念漂移
当P ( Y | X ) 改变但 P ( X ) 保持不变时。这是指关节的第一次分解分配。21
如果您发现这令人困惑,请不要惊慌。我们将在下一节中通过示例来说明它们的区别。
协变量移位
协变量移位是最常见的一种广泛研究的数据分布变化形式。22在统计学中,协变量是一个独立变量,它可以影响给定统计试验的结果,但不是直接感兴趣的。假设您正在进行一项实验,以确定位置如何影响房价。房价变量是您的直接兴趣,但您知道面积会影响价格,因此面积是协变量。在有监督的 ML 中,标签是直接感兴趣的变量,
从数学上讲,协变量移位是指 P ( X ) 发生变化,但 P ( Y | X ) 保持不变,这意味着输入的分布发生了变化,但给定输入的输出的条件概率保持不变。
为了具体说明这一点,请考虑检测乳腺癌的任务。你知道40、23岁以上的女性患乳腺癌的风险更高所以你有一个变量“年龄”作为你的输入。您的训练数据中 40 岁以上的女性可能比推理数据中的多,因此您的训练和推理数据的输入分布不同。但是,对于具有给定年龄(例如 40 岁以上)的示例,该示例患有乳腺癌的概率是恒定的。所以P ( Y | X),40 岁以上患乳腺癌的概率是相同的。
在模型开发过程中,由于数据选择过程中的偏差可能会发生协变量变化,这可能是由于难以为某些类别收集示例造成的。例如,假设要研究乳腺癌,您从女性去检测乳腺癌的诊所获取数据。因为医生鼓励 40 岁以上的人进行检查,所以您的数据以 40 岁以上的女性为主。因此,24
协变量变化也可能发生,因为人为地更改了训练数据以使您的模型更容易学习。如第 4 章所述,ML 模型很难从不平衡的数据集中学习,因此您可能希望收集更多稀有类的样本或对稀有类的数据进行过采样,以使您的模型更容易学习稀有类。
模型的学习过程也可能导致协变量偏移,尤其是通过主动学习。在 第 4 章,我们将主动学习定义如下:我们不是随机选择样本来训练模型,而是根据一些启发式方法使用对模型最有帮助的样本。这意味着训练输入分布被学习过程改变为不同于现实世界的输入分布,并且协变量变化是副产品。25
在生产环境中,协变量偏移通常是由于环境或应用程序使用方式的重大变化而发生的。想象一下,您有一个模型来预测免费用户转换为付费用户的可能性。用户的收入水平是一个特征。贵公司的营销部门最近发起了一项活动,该活动从比您当前的人口统计更富裕的人口统计中吸引用户。模型中的输入分布发生了变化,
如果您事先知道实际输入分布与训练输入分布有何不同,您可以利用 重要性加权等技术训练您的模型以处理真实世界的数据。重要性加权包括两个步骤:估计现实世界输入分布和训练输入分布之间的密度比,然后根据这个比对训练数据进行加权,并在这个加权数据上训练一个机器学习模型。26
但是,由于我们事先不知道分布在现实世界中会如何变化,因此很难预先训练您的模型以使其对新的、未知的模型具有鲁棒性分布。已经有研究试图帮助模型学习在数据分布中不变的潜在变量的表示,27 但我不知道它们在行业中的应用。
标签移位
标签偏移,也称为先验偏移、先验概率偏移或目标偏移,是当P ( Y ) 发生变化但P ( X | Y ) 保持不变时。您可以将其视为输出时的情况分布发生变化,但 对于给定的输出,输入分布保持不变。
请记住,协变量偏移是输入分布发生变化的时候。当输入分布发生变化时,输出分布也会发生变化,从而导致协变量移位和标签移位同时发生。考虑前面关于协变量偏移的乳腺癌示例。因为在我们的训练数据中超过 40 岁的女性比在我们的推理数据中更多,所以在训练期间 POSITIVE 标签的百分比更高。然而, P ( X | Y ) 或 40 岁以上患乳腺癌的概率是相同的。所以这也是标签移位的情况。
但是,并非所有协变量移位都会导致标签移位。这是一个微妙的点,所以我们将考虑另一个例子。想象一下,现在每个女性都服用一种预防性药物,有助于降低患乳腺癌的几率。概率 P ( Y | X) 减少了所有年龄段的女性,因此它不再是协变量偏移的情况。然而,给定一个患有乳腺癌的人,年龄分布保持不变,所以这仍然是一个标签转移的例子。
因为标签移位与协变量移位密切相关,所以检测和调整模型以适应标签移位的方法类似于协变量移位自适应方法。我们将在本章稍后部分讨论它们。
概念漂移
概念漂移,也称为后移,是指输入分布保持不变但条件 给定输入变化的输出分布。您可以将其视为“相同的输入,不同的输出”。假设您负责一个模型,该模型根据房屋的特征预测房屋的价格。在 COVID-19 之前,旧金山的三居室公寓可能要花费 2,000,000 美元。然而,在 COVID-19 开始时,许多人离开了旧金山,因此同样的公寓只需 1,500,000 美元。
在许多情况下,概念漂移是周期性的或季节性的。例如,拼车价格将在工作日和周末波动,而机票价格在假日季节会上涨。公司可能有不同的模型来处理周期性和季节性漂移。例如,他们可能有一个模型来预测工作日的拼车价格和另一个模型来预测周末的价格。
一般数据分布变化
现实世界中还有其他类型的变化,即使在研究中没有得到很好的研究,仍然会降低模型的性能。
一种是功能变化,比如当添加新功能,删除旧功能或更改功能的所有可能值的集合。28例如,您的模型使用年作为“年龄”特征,但现在它使用月,因此该特征的值的范围发生了漂移。有一次,我们的团队意识到我们的模型的性能直线下降,因为我们管道中的一个错误导致一个特征变成了 NaN(“不是数字”的缩写)。
标签架构更改是指Y的一组可能值发生更改。随着标签移位,P ( Y ) 发生变化,但P ( X | Y ) 仍然是相同的。随着标签模式的改变,P ( Y ) 和P ( X | Y ) 都会改变。模式描述了数据的结构,因此任务的标签模式描述了该任务的标签结构。例如,从一个类映射到一个整数值的字典,例如 {“POSITIVE”: 0, “NEGATIVE”: 1}
,就是一个模式。
对于回归任务,标签模式可能会发生变化,因为标签值的可能范围发生了变化。想象一下,您正在构建一个模型来预测某人的信用评分。最初,您使用范围从 300 到 850 的信用评分系统,但您切换到了范围从 250 到 900 的新系统。
对于分类任务,标签架构可能会发生变化,因为您有新的类。例如,假设您正在构建一个模型来诊断疾病,并且要诊断一种新疾病。类也可能变得过时或更细粒度。想象一下,您负责为提及您的品牌的推文建立情绪分析模型。最初,您的模型仅预测三个类别:正、负和中性。但是,您的营销部门意识到最具破坏性的推文是愤怒的推文,所以他们想把 NEGATIVE 类分成两个类:SAD 和 ANGRY。您的任务现在有四个类,而不是三个类。当类的数量发生变化时,模型的结构可能会发生变化,29并且您可能需要重新标记数据并从头开始重新训练模型。标签架构更改在高基数任务(具有大量类的任务)中尤其常见,例如产品或文档 分类。
没有规则说一次只能发生一种类型的转变。一个模型可能会遭受多种类型的漂移,这使得处理它们变得更加困难。
检测数据分布变化
数据分布变化只有在导致模型性能下降时才会成为问题。所以第一个想法可能是在生产中监控模型与准确性相关的指标——准确性、F1 分数、召回率、AUC-ROC 等,以查看它们是否发生了变化。这里的“变化”通常意味着“降低”,但如果我的模型的准确度突然上升或无缘无故大幅波动,我想调查一下。
与准确性相关的指标通过将模型的预测与真实标签进行比较来发挥作用。30在模型开发期间,您可以访问标签,但在生产中,您并不总是可以访问标签,即使您这样做,标签也会被延迟,如“自然标签”部分所述。在合理的时间范围内访问标签将极大地帮助您了解模型的性能。
当地面实况标签不可用或延迟太久而无用时,我们可以监控其他感兴趣的分布。感兴趣的分布是输入分布 P ( X )、标签分布 P ( Y ) 和条件分布 P ( X | Y ) 和 P ( Y | X )。
虽然我们不需要知道真实标签Y来监控输入分布,但监控标签分布和两个条件分布都需要知道Y。在研究中,已经努力从目标分布中理解和检测没有标签的标签移位。一项这样的努力是黑盒移位估计 立顿等人。(2018 年)。然而,在业界,大多数漂移检测方法都侧重于检测输入分布的变化,尤其是特征分布,我们将在本章详细讨论。
统计方法
在工业界,许多公司的简单方法用于检测两个分布是否相同的方法是比较它们的统计量,如最小值、最大值、均值、中值、方差、各种分位数(如第 5、25、75 或 95 分位数)、偏度、峰度等。例如,您可以在推理期间计算特征值的中值和方差,并将它们与训练期间计算的指标进行比较。截至 2021 年 10 月,即使是TensorFlow Extended 的内置数据验证工具仅使用汇总统计数据来检测训练数据和服务数据之间的偏差以及不同日期训练数据之间的变化。这是一个好的开始,但这些指标还远远不够。31均值、中值和方差仅对均值/中值/方差是有用摘要的分布有用。如果这些指标存在显着差异,则推理分布可能已偏离训练分布。但是,如果这些指标相似,则不能保证没有变化。
更复杂的解决方案是使用双样本假设检验,简称为双样本检验。这是一项用于确定两个总体(两组数据)之间的差异是否具有统计显着性的测试。如果差异在统计上显着,则差异是由于抽样变异性引起的随机波动的概率非常低,因此,差异是由于这两个种群来自两个不同的分布。如果您将昨天的数据视为源人口,而将今天的数据视为目标人口并且它们在统计上有所不同,则基础数据分布很可能在昨天和今天之间发生了变化。
需要注意的是,仅仅因为差异在统计上显着并不意味着它实际上很重要。但是,一个很好的启发式方法是,如果您能够从相对较小的样本中检测到差异,那么它可能是一个严重的差异。如果需要大量样本来检测,那么差异可能不值得担心。
基本的两样本检验是 Kolmogorov-Smirnov 检验,也称为 KS 或 KS 检验。32这是一个非参数统计测试,这意味着它不需要任何基础分布的参数即可工作。它不对底层分布做任何假设,这意味着它可以适用于任何分布。然而,KS 检验的一个主要缺点是它只能用于一维数据。如果您的模型的预测和标签是一维的(标量数字),那么 KS 测试对于检测标签或预测偏移很有用。但是,它不适用于高维数据,并且特征通常是高维的。33 KS 测试也可能很昂贵,并且会产生过多的误报警报。34
另一个测试是最小二乘密度差,一种基于最小二乘密度差估计方法的算法。35还有 MMD,最大平均差异(Gretton 等人,2012 年),一种基于内核的多变量双样本测试技术及其变体Learned Kernel MMD(刘等人,2020)。MMD 在研究中很受欢迎,但在撰写本书时,我不知道有任何公司在行业中使用它。Alibi Detect是一个很棒的开源软件包,实现了许多漂移检测算法,如图 8-2所示。
因为二样本测试通常在低维数据上比在高维数据上效果更好,所以强烈建议您在执行二样本测试之前降低数据的维数在上面。36
图 8-2。Alibi Detect实现的一些漂移检测算法。来源:项目的 GitHub 仓库截图
用于检测班次的时间尺度窗口
并非所有类型的班次都是平等的——有些班次更难比别人检测。例如,变化以不同的速率发生,突变比缓慢、渐进的变化更容易被发现。37转变也可以发生在两个维度上:空间或时间。空间转移是跨接入点发生的转移,例如您的应用程序获得了一组新用户,或者您的应用程序现在在不同类型的设备上提供服务。时间变化是随时间发生的变化。为了检测时间变化,一种常见的方法是将 ML 应用程序的输入数据视为时间序列数据。38
在处理时间变化时,我们查看的数据的时间尺度窗口会影响我们可以检测到的变化。如果您的数据具有每周周期,则少于一周的时间尺度不会检测到该周期。考虑图 8-3中的数据. 如果我们使用第 9 天到第 14 天的数据作为源分布,那么第 15 天看起来就像一个转变。但是,如果我们使用第 1 天到第 14 天的数据作为源分布,那么第 15 天的所有数据点很可能都是由同一分布生成的。如本例所示,当变化与季节变化相混淆时,检测时间变化是很困难的。
图 8-3。分布是否随时间漂移取决于指定的时间尺度窗口
在计算一段时间内的运行统计信息时,区分 累积统计信息和滑动统计信息很重要. 滑动统计在单个时间尺度窗口内计算,例如一个小时。累积统计数据会不断更新更多数据。这意味着,对于每个时间尺度窗口的开始,滑动精度会被重置,而累积滑动精度不会。由于累积统计数据包含来自先前时间窗口的信息,因此它们可能会掩盖特定时间窗口中发生的情况。图 8-4显示了累积准确度如何隐藏第 16 到 18 小时之间准确度突然下降的示例。
图 8-4。 累积准确度掩盖了 16 到 18 小时之间准确度的突然下降。来源:改编自MadeWithML的图片
在时间空间中处理数据会使事情变得更加复杂,需要时间序列分析技术的知识,例如时间序列分解,这超出了本书的范围。对于对时间序列分解感兴趣的读者,Lyft 工程部门提供了一个很好的案例研究,说明他们如何分解时间序列数据以应对市场的季节性。
时至今日,很多公司都将训练数据的分布作为基础分布,并以一定的粒度级别监控生产数据的分布,例如每小时和每天。39您的时间尺度窗口越短,您就能越快地检测到数据分布的变化。然而,太短的时间尺度窗口会导致错误的班次警报,如图 8-3中的示例。
一些平台,尤其是那些处理实时数据分析(如监控)的平台,提供了合并操作,允许合并来自较短时间尺度窗口的统计数据,以创建较大时间尺度窗口的统计数据。例如,您可以每小时计算您关心的数据统计信息,然后将这些每小时统计信息块合并到每日视图中。
更高级的监控平台甚至尝试使用根本原因分析 (RCA) 功能,自动分析跨区域的统计数据各种时间窗口大小,以准确检测数据发生变化的时间窗口。40
解决数据分布变化
公司如何处理数据转移取决于他们的机器学习基础设施设置的复杂程度。在一最后,我们有一些公司刚刚开始使用 ML,并且仍在努力将 ML 模型投入生产,因此他们可能还没有达到数据转移对他们来说是灾难性的地步。然而,在未来的某个时候——可能是三个月,也可能是六个月——他们可能会意识到他们最初部署的模型已经退化到弊大于利的地步。然后,他们需要调整他们的模型以适应变化的分布或用其他解决方案替换它们。
与此同时,许多公司认为数据转移是不可避免的,因此他们会定期重新训练他们的模型——每月一次、每周一次或每天一次——无论转移的程度如何。如何确定重新训练模型的最佳频率是一个重要的决定,许多公司仍然根据直觉而不是实验数据来确定。41我们将在第 9 章中详细讨论再培训频率。
要使模型与生产中的新分布一起工作,有三种主要方法。第一种是目前主导研究的方法:使用海量数据集训练模型。这里的希望是,如果训练数据集足够大,模型将能够学习到如此全面的分布,以至于模型在生产中遇到的任何数据点都可能来自这个分布。
第二种在研究中不太流行的方法是使经过训练的模型适应目标分布而不需要新的标签。张等人。(2013) 使用因果解释以及条件和边际分布的核嵌入来纠正模型对协变量偏移和标签偏移的预测,而不使用来自目标分布的标签。42同样,赵等人。(2020)提出域不变表示学习:一种无监督的域适应技术,可以学习不随变化分布变化的数据表示。43然而,这一研究领域还没有得到充分的探索,也没有在工业中得到广泛采用。44
第三种方法是当今行业通常采用的方法:使用来自目标分布的标记数据重新训练您的模型。然而,重新训练你的模型并不是那么简单。重新训练可能意味着在新旧数据上从头开始重新训练您的模型,或者继续在新数据上训练现有模型。后一种方法也称为微调。
如果你想重新训练你的模型,有两个问题。首先,是从头开始训练你的模型(无状态再训练)还是从最后一个检查点继续训练(有状态训练)。其次,使用什么数据:过去 24 小时、上周、过去 6 个月的数据,或者数据开始漂移时的数据。您可能需要进行实验以确定哪种再培训策略最适合您。45
在本书中,我们使用“再训练”来指代从头开始的训练和微调。我们将在下一章讨论更多关于再培训策略的内容。
熟悉数据转移文献的读者可能经常会看到与领域适应和迁移学习一起提到的数据转移。如果您将分布视为域,那么如何使模型适应新分布的问题类似于如何使模型适应不同域的问题。
类似地,如果您考虑将学习联合分布 P ( X , Y ) 作为一项任务,那么将在一个联合分布上训练的模型适应另一个联合分布可以被视为迁移学习的一种形式。如第 4 章所述,迁移学习是指为一个任务开发的模型被重用作为第二个任务的模型的起点的方法族。不同之处在于,通过迁移学习,您无需为第二个任务从头开始重新训练基础模型。但是,为了使您的模型适应新的分布,您可能需要从头开始重新训练您的模型。
解决数据分布变化不必在变化发生后开始。可以设计您的系统以使其对班次更加稳健。一个系统使用多个特征,并且不同的特征以不同的速率移动。假设您正在构建一个模型来预测用户是否会下载应用程序。您可能会想将该应用在应用商店中的排名用作一项功能,因为排名较高的应用往往会被下载更多。但是,应用排名变化非常快。相反,您可能希望将每个应用程序的排名分为一般类别,例如前 10、11 和 100 之间、101 和 1,000 之间、1,001 和 10,000 之间等。同时,一个应用程序的类别可能会不太频繁地更改,但它们预测用户是否会下载该应用程序的能力可能较小。在为模型选择特征时,您可能需要考虑性能和特征稳定性之间的权衡:一个特征可能对准确性非常好,但会迅速恶化,
您可能还想设计您的系统,使其更容易适应轮班。例如,旧金山等主要城市的房价变化可能比亚利桑那州农村快得多,因此服务于亚利桑那州农村的房价预测模型的更新频率可能低于服务于旧金山的模型。如果您使用相同的模型服务于两个市场,则必须使用来自两个市场的数据以旧金山要求的速度更新您的模型。但是,如果您为每个市场使用单独的模型,
在我们进入下一部分之前,我想重申,并非生产中模型的所有性能下降都需要 ML 解决方案。今天的许多机器学习失败仍然是由人为造成的 错误。如果您的模型失败是由人为错误引起的,您首先需要找到这些错误来修复它们。检测数据偏移很困难,但确定导致偏移的原因可能更加困难。
监控和可观察性
随着业界意识到 ML 系统可能出现许多问题,许多公司开始投资于生产中的 ML 系统的监控和可观察性。
监控和可观察性有时是可以互换使用,但它们是不同的。监控是指跟踪、测量和记录不同指标的行为,这些指标可以帮助我们确定何时出现问题。可观察性意味着以某种方式设置我们的系统,使我们能够看到我们的系统,以帮助我们调查出了什么问题。以这种方式设置我们的系统的过程也称为“仪器”。检测的示例包括向函数添加计时器、计算特征中的 NaN、跟踪输入如何通过系统转换、记录异常事件(例如异常长的输入)等。可观察性是监控的一部分。如果没有一定程度的可观察性,就不可能进行监控。
监控是关于指标的。因为 ML 系统是软件系统,所以您需要监控的第一类指标是操作指标。这些指标旨在传达系统的健康状况。它们一般分为三个层次:运行系统的网络、运行系统的机器和运行系统的应用程序。这些指标的示例是延迟;吞吐量;您的模型在最后一分钟、一小时、一天收到的预测请求数;返回带有 2xx 代码的请求的百分比;CPU/GPU 利用率;内存利用率;等等。无论您的 ML 模型有多好,如果系统出现故障,您将无法从中受益。
让我们看一个例子。生产中软件系统最重要的特征之一是可用性——系统多久可以为用户提供合理的性能。此特性由uptime衡量,即系统正常运行的时间百分比。确定系统是否正常运行的条件在服务水平目标 (SLO) 或服务水平协议 (SLA) 中定义。例如,如果服务的中位延迟小于 200 毫秒且第 99 个百分位小于 2 秒,则 SLA 可能会指定该服务被视为已启动。
服务提供商可能会提供一个 SLA,其中指定了他们的正常运行时间保证,例如 99.99% 的时间,如果不满足此保证,他们将向客户退款。例如,截至 2021 年 10 月,AWS EC2 服务提供的每月正常运行时间百分比至少为 99.99%(四个 9),如果每月正常运行时间百分比低于此值,他们将向您返还服务积分,用于未来的 EC2 付款. 46 99.99% 的每月正常运行时间意味着服务每月只允许下降 4 分钟多一点,而 99.999% 意味着每月只有 26 秒!
但是,对于 ML 系统,系统运行状况超出了系统正常运行时间。如果你的机器学习系统已经启动,但它的预测是垃圾,你的用户不会高兴。您要监控的另一类指标是特定于 ML 的指标,它们可以告诉您 ML 模型的运行状况。
ML 特定指标
在特定于 ML 的指标中,通常需要监控四个工件:模型的准确性相关指标、预测、特征和原始输入。这些是在 ML 系统管道的四个不同阶段生成的工件,如图 8-5所示. 工件越深入管道,它经历的转换就越多,这使得该工件的更改更有可能是由其中一个转换中的错误引起的。然而,一个工件经历的转换越多,它就变得越结构化,并且越接近你真正关心的指标,这使得它更容易监控。我们将在以下部分详细介绍这些工件。
图 8-5。工件经历的转换越多,其变化就越可能是由其中一个转换中的错误引起的
监测预测
预测是最常见的监控对象。如果是回归任务,每个预测都是连续的 值(例如,房屋的预测价格),如果是分类任务,则每个预测都是对应于预测类别的离散值。因为每个预测通常只是一个数字(低维),所以预测很容易可视化,并且它们的汇总统计数据很容易计算和解释。
您可以监控分布变化的预测。因为预测是低维的,所以计算两样本测试来检测预测分布是否发生变化也更容易。预测分布变化也是输入分布变化的代表。
您还可以监控任何奇怪发生的预测,例如连续预测异常数量的 False。正如“自然标签”一节中所讨论的,预测和真实标签之间可能存在很长的延迟。与准确性相关的指标的变化可能在几天或几周内不会变得明显,而可以检测到预测 10 分钟内全部为 False 的模型立即地。
监控功能
行业内的机器学习监控解决方案专注于跟踪特征的变化,包括模型用作输入的特征以及从原始输入到最终特征的中间转换。特征监控很有吸引力,因为与原始输入数据相比,特征按照预定义的模式结构良好。特征监控的第一步是特征验证:确保您的功能遵循预期的模式。预期的模式通常是从训练数据或常识中生成的。如果在生产中违反了这些预期,则潜在分布可能会发生变化。例如,以下是您可以检查给定功能的一些内容:
-
如果特征的最小值、最大值或中值在可接受的范围内
-
如果特征的值满足正则表达式格式
-
如果一个特征的所有值都属于一个预定义的集合
-
如果一个特征的值总是大于另一个特征的值
因为特征通常被组织成表格——每一列代表一个特征,每一行代表一个数据样本——特征验证也称为表格测试或表格验证。有些人称它们为数据的单元测试。有许多开源库可以帮助您进行基本的功能验证,最常见的两个是 AWS 的Great Expectations和Deequ。图 8-7展示了 Great Expectations 的一些内置功能验证功能以及如何使用它们的示例。
图 8-7。Great Expectations 的一些内置功能验证功能以及如何使用它们的示例。来源:改编自 Great Expectations GitHub 存储库中的内容
除了基本特征验证之外,您还可以使用两个样本测试来检测一个特征或一组特征的底层分布是否发生了变化。由于一个特征或一组特征可能是高维的,因此您可能需要在对它们执行测试之前降低它们的维度,这可能会降低测试的效率。
进行功能监控时有四个主要问题:
一家公司可能有数百个正在生产的模型,每个模型都使用数百个甚至数千个功能。
即使是像每小时计算所有这些功能的摘要统计这样简单的事情也可能很昂贵,不仅在所需的计算方面,而且在使用的内存方面。跟踪(即不断计算)过多的指标也会减慢您的系统并增加用户体验的延迟以及您检测系统异常所需的时间。
虽然跟踪特征对于调试目的很有用,但对于检测模型性能下降不是很有用。
理论上,一个小的分布变化会导致灾难性的失败,但在实践中,单个特征的微小变化可能根本不会损害模型的性能。特征分布一直在变化,而这些变化大多是良性的。48如果您想在某项功能似乎出现偏差时收到警报,您可能很快就会被警报淹没,并意识到这些警报中的大多数都是误报。这可能会导致一种称为“警报疲劳”的现象,其中监控团队不再关注警报,因为它们太频繁了。特征监控的问题变成了试图决定哪些特征转变是关键的,哪些不是。
特征提取通常在多个步骤(例如填充缺失值和标准化),在多个服务(例如 BigQuery 或 Snowflake)上使用多个库(例如 pandas、Spark)。
您可能将关系数据库作为特征提取过程的输入,将 NumPy 数组作为输出。即使您检测到某个特征的有害更改,也可能无法检测到此更改是由基础输入分布的更改引起的,还是由多个处理步骤之一中的错误引起的。
您的功能遵循的架构可能会随着时间而改变。
如果您无法对架构进行版本化并将每个功能映射到其预期架构,则报告警报的原因可能是架构不匹配,而不是数据更改。
这些担忧并不是要忽视特征监控的重要性;特征空间的变化是了解机器学习系统健康状况的有用信号来源。希望,考虑这些问题可以帮助您选择适合您的功能监控解决方案。
监控原始输入
如前所述部分,特征的变化可能是由处理步骤中的问题引起的,而不是由数据的变化引起的。如果我们在处理原始输入之前监控它们会怎样?原始输入数据可能不容易监控,因为它可能来自不同格式的多个来源,遵循多种结构。当今许多 ML 工作流程的设置方式也使 ML 工程师无法直接访问原始输入数据,因为原始输入数据通常由数据平台团队管理,他们处理数据并将其移动到数据仓库等位置,而 ML 工程师只能从数据已经部分处理的数据仓库中查询数据。因此,监控原始输入通常是数据平台团队的职责,而不是数据科学或 ML 团队的职责。因此,它超出了本书的范围。
到目前为止,我们已经讨论了要监控的不同类型的指标,从通常用于软件系统的操作指标到帮助您跟踪 ML 模型健康状况的 ML 特定指标。在下一节中,我们将讨论可用于帮助进行指标监控的工具箱。
监控工具箱
测量、跟踪和解释复杂系统的指标是一项艰巨的任务,工程师依靠一组工具来帮助他们做到这一点。业界通常将指标、日志和跟踪视为监控的三大支柱。但是,我发现它们的区别很模糊。它们似乎是从开发监控系统的人的角度生成的:跟踪是日志的一种形式,可以从日志中计算出指标。在本节中,我想从监控系统用户的角度重点介绍一组工具:日志、
日志
传统的软件系统依靠日志来记录运行时产生的事件。事件是任何东西系统开发人员可能会感兴趣,无论是在事件发生时还是稍后用于调试和分析目的。事件的示例包括容器何时启动、占用的内存量、函数何时被调用、该函数何时完成运行、该函数调用的其他函数、该函数的输入和输出等。另外,不要不要忘记记录崩溃、堆栈跟踪、错误代码等。用 Etsy 的 Ian Malpass 的话来说,“如果它移动,49他们还会跟踪尚未更改的内容,以防他们稍后移动。
日志的数量可以非常快速地增长。例如,早在 2019 年,约会应用程序 Badoo 每天处理 200 亿个事件。50当出现问题时,您需要在日志中查询导致它的事件顺序,这个过程就像大海捞针一样。
在软件部署的早期,一个应用程序可能是一个单一的服务。当事情发生时,你知道发生在哪里。但是今天,一个系统可能由许多不同的组件组成:容器、调度程序、微服务、多语言持久性、网格路由、临时自动扩展实例、无服务器 Lambda 函数。从发送请求到收到响应,请求可能会经过 20 到 30 次跳跃。困难的部分可能不在于检测何时发生,51
当我们记录一个事件时,我们想让它尽可能容易让我们以后找到它。这种使用微服务架构的做法称为分布式跟踪. 我们希望给每个进程一个唯一的 ID,以便当出现问题时,错误消息将(希望)包含该 ID。这使我们能够搜索与之关联的日志消息。我们还希望为每个事件记录所有必要的元数据:事件发生的时间、发生的服务、调用的函数、与进程关联的用户(如果有的话)等。
由于日志变得如此庞大且难以管理,因此开发了许多工具来帮助公司管理和分析日志。预计 2021 年日志管理市场价值 23 亿美元,预计到 2026 年将增长到 41 亿美元。52
手动分析数十亿记录的事件是徒劳的,因此许多公司使用 ML 来分析日志。ML 在日志分析中的一个示例用例是异常检测:检测系统中的异常事件。更复杂的模型甚至可以根据事件的优先级对每个事件进行分类,例如通常、异常、异常、错误和致命。
ML 在日志分析中的另一个用例是,当服务失败时,了解相关服务受到影响的概率可能会有所帮助。当系统受到网络攻击时,这可能特别有用。
许多公司以批处理方式处理日志。在这种情况下,您收集大量日志,然后定期查询它们以使用 SQL 查找特定事件,或使用 Spark、Hadoop 或 Hive 集群中的批处理过程来处理它们。这使得日志处理变得高效,因为您可以利用分布式和 MapReduce 进程来增加处理吞吐量。但是,由于您定期处理日志,
要在异常发生时立即发现日志中的异常,您希望在事件记录后立即处理它们。这使得日志处理成为流处理问题。53您可以使用实时传输(例如 Kafka 或 Amazon Kinesis)来传输记录的事件。要实时搜索具有特定特征的事件,您可以利用流式 SQL 引擎,如 KSQL 或 Flink SQL。
仪表板
一张图片胜过千言万语。一系列的数字对你来说可能毫无意义,但在图表上可视化它们可能会揭示这些数字之间的关系。可视化指标的仪表板对于监控至关重要。
仪表板的另一个用途是使非工程师可以访问监控。监控不仅适用于系统开发人员,也适用于非工程利益相关者,包括产品经理和业务开发人员。
尽管图表对理解指标有很大帮助,但它们本身还不够。您仍然需要经验和统计知识。考虑图 8-8中的两个图。从这些图中唯一可以明显看出的是损失波动很大。如果这两个图表中的任何一个存在分布变化,我无法判断。绘制图表以绘制摆动线比理解这条摆动线的含义更容易。
图 8-8。图表对于理解数字很有用,但还不够
仪表板上的过多指标也可能适得其反,这种现象称为仪表板腐烂。选择正确的指标或抽象出较低级别的指标以计算更适合您的特定任务的更高级别的信号非常重要。
警报
当我们的监控系统检测到某些东西时可疑,有必要提醒正确的人。警报由以下三个部分组成:
警报政策
这描述了条件一个警报。您可能希望在指标超出阈值时(可选地在特定持续时间)创建警报。例如,您可能希望在模型的准确度低于 90% 或 HTTP 响应延迟高于一秒至少 10 分钟时收到通知。
通知渠道
这些描述了在满足条件时将通知谁。警报将显示在您使用的监控服务中,例如 Amazon CloudWatch 或 GCP Cloud Monitoring,但您还希望在负责人不在这些监控服务上时联系他们。例如,您可以将警报配置为发送到电子邮件地址,例如 mlops-monitoring@ [您的公司电子邮件域],或发布到 Slack 频道,例如 #mlops-monitoring 或 PagerDuty。
警报的描述
这有助于被提醒的人了解正在发生的事情。描述应尽可能详细,例如:
## Recommender model accuracy below 90%
${timestamp}: This alert originated from the service ${service-name}
根据警报的受众,通常需要通过提供缓解说明或运行手册(可能有助于处理警报的常规过程和操作的汇编)来使警报具有可操作性。
警觉疲劳是一种真实的现象,因为本章前面讨论过。警觉疲劳可能会令人沮丧——没有人喜欢在半夜被吵醒,因为他们的职责之外的事情。这也很危险——暴露于琐碎的警报会使人们对严重警报失去敏感性。设置有意义的条件很重要,以便只发送关键警报。
可观察性
自 2010 年代中期以来,该行业开始采用“可观察性”一词,而不是“监控”。监控不对系统内部状态与其输出之间的关系做任何假设。您监控系统的外部输出以找出系统内部何时出现问题 - 无法保证外部输出会帮助您找出问题所在。
在软件部署的早期,软件系统非常简单,以至于监控外部输出足以进行软件维护。一个系统过去只包含几个组件,而一个团队过去可以控制整个代码库。如果出现问题,可以对系统进行更改以测试并找出问题所在。
然而,在过去十年中,软件系统变得更加复杂。今天,一个软件系统由许多组件组成。其中许多组件是由其他公司运行的服务——提示所有云原生服务——这意味着团队甚至无法控制其系统所有组件的内部。当出现问题时,团队不能再分解他们的系统来找出问题。团队必须依靠系统的外部输出来弄清楚内部发生了什么。
可观察性是用来应对这一挑战的术语。这是一个源自控制理论的概念,它指的是“使用在运行时从系统收集的 [输出] 来更好地了解软件的复杂行为”。54
遥测
运行时收集的系统输出也称为遥测。遥测是过去十年软件监控行业出现的另一个术语。“遥测”一词来自希腊词根tele,意思是“远程”,而metron,意思是“测量”。所以遥测基本上意味着“远程测量”。在监控上下文中,它指的是从远程组件(例如云服务或在客户设备上运行的应用程序)收集的日志和指标。
换句话说,可观察性比传统监控做出了一个更强的假设:系统的内部状态可以从其外部输出的知识中推断出来。内部状态可以是当前状态,例如“当前的 GPU 利用率”,也可以是历史状态,例如“过去一天的平均 GPU 利用率”。
当可观察系统出现问题时,我们应该能够通过查看系统的日志和指标来找出问题所在,而无需向系统发送新代码。可观察性是关于以某种方式检测您的系统,以确保收集和分析有关系统运行时的足够信息。
监控中心围绕指标,指标通常是聚合的。可观察性允许更细粒度的指标,因此您不仅可以了解模型的性能何时下降,还可以了解哪些类型的输入或哪些用户子组或模型在多长时间内下降。例如,您应该能够在日志中查询以下问题的答案:“显示模型 A 在过去一小时内返回错误预测的所有用户,按他们的邮政编码分组”或“显示过去 10 分钟内的异常值请求”或“显示此输入通过系统的所有中间输出”。为了实现这一点,您需要使用标签和其他识别关键字记录系统的输出,以允许这些输出稍后沿数据的不同维度进行切片和切块。
在 ML 中,可观察性包含可解释性。可解释性帮助我们理解 ML 模型是如何工作的,而可观察性帮助我们理解包括 ML 模型在内的整个 ML 系统是如何工作的。例如,当模型的性能在过去一小时内下降时,能够解释在过去一小时内做出的所有错误预测中哪个特征贡献最大将有助于找出系统出了什么问题以及如何修复它。55
在本节中,我们讨论了监控的多个方面,从要监控的数据和要跟踪的指标到用于监控和可观察性的不同工具。尽管监控是一个强大的概念,但它本质上是 被动的。您等待发生转变以检测到它。监控有助于在没有问题的情况下发现问题纠正它。在下一节中,我们将介绍持续学习,这是一种可以 积极帮助您更新模型以应对变化的范例。
概括
这可能是我在这本书中写出的最具挑战性的一章。原因是,尽管了解 ML 系统在生产中失败的方式和原因很重要,但围绕它的文献却很有限。我们通常认为研究先于生产,但这是 ML 的一个领域,研究仍在努力赶上生产。
为了理解 ML 系统的故障,我们区分了两种类型的故障:软件系统故障(也发生在非 ML 系统上的故障)和 ML 特定的故障。尽管今天的大多数 ML 故障都不是特定于 ML 的,但随着围绕 MLOps 的工具和基础设施的成熟,这种情况可能会改变。
我们讨论了 ML 特定失败的三个主要原因:生产数据不同于训练数据、边缘情况和退化的反馈循环。前两个原因与数据有关,而最后一个原因与系统设计有关,因为它发生在系统的输出影响同一系统的输入时。
我们将注意力集中在近年来引起广泛关注的一个失败上:数据分布的变化。我们研究了三种类型的转变:协变量转变、标签转变和概念漂移。尽管研究分布变化是 ML 研究的一个不断发展的子领域,但研究界还没有找到一个标准的叙述。不同的论文用不同的名称来称呼相同的现象。许多研究仍然基于我们事先知道分布将如何变化或具有来自源分布和目标分布的数据的标签的假设。然而,在现实中,
为了能够检测到变化,我们需要监控我们部署的系统。对于生产中的任何软件工程系统,监控都是一组重要的实践,而不仅仅是 ML,它是 ML 的一个领域,我们应该尽可能多地从 DevOps 世界中学习。
监控是关于指标的。我们讨论了需要监控的不同指标:运营指标——任何软件系统都应该监控的指标,例如延迟、吞吐量和 CPU 利用率——以及特定于 ML 的指标。监控可以应用于与准确性相关的指标、预测、特征和/或原始输入。
监控很困难,因为即使计算指标很便宜,理解指标也并不简单。构建仪表板以显示图表很容易,但要理解图表的含义要困难得多,它是否显示出漂移的迹象,如果有漂移,是由底层数据分布变化还是由管道中的错误引起的。可能需要了解统计数据才能理解数字和图表。
检测模型性能在生产中的下降是第一步。下一步是如何使我们的系统适应不断变化的环境,我们将在下一章讨论。