当前位置: 首页 > news >正文

机器学习:数据分布的漂移问题及应对方案

首先,让我们从一位高管告诉我的一个故事开始,很多读者可能对此感同身受。

大约两年前,他的公司聘请了一家咨询公司开发一个机器学习模型,帮助他们预测下周每种食品杂货需要多少,以便他们可以相应地补货。这家咨询公司花了六个月的时间来开发这个模型。当咨询公司将模型交给他时,他的公司就部署了它,并对其表现非常满意。他们终于可以向投资者夸耀他们是一家人工智能公司了。

然而,一年后,他们的数字下降了。一些商品的需求一直被高估,导致多余的商品过期。与此同时,一些商品的需求一直被低估,导致销售额下降。最初,他的库存团队手动更改了模型的预测,以纠正他们注意到的模式,但最终,模型的预测变得如此糟糕,以至于他们无法再使用它。他们有三个选择:向同一家咨询公司支付巨额费用来更新模型,向另一家咨询公司支付更多费用,因为这家公司需要时间来跟上进度,或者聘请内部团队来维护模型。

他的公司从惨痛经历中学到了一个重要的教训,而业内其他人也正在发现:部署模型并不是流程的结束。模型的性能会随着生产时间的推移而下降。部署模型后,我们仍然必须持续监控其性能以检测问题,并部署更新以解决这些问题。

NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割 

1、自然标签和反馈循环

具有自然基本事实标签的任务是模型的预测可以由系统自动评估或部分评估的任务。一个例子是估计谷歌地图上到达时间的模型。在旅行结束时,谷歌地图知道旅行实际花费了多长时间,因此可以评估预测到达时间的准确性。

自然标签是评估模型性能的理想选择。但是,即使你的任务本身没有自然标签,也可以设置你的系统,以便收集一些关于模型的反馈。

例如,如果你正在构建像谷歌翻译这样的翻译系统,可以选择让社区为糟糕的翻译提交替代翻译。新闻源排名不是具有固有标签的任务,但通过在每个新闻源项目中添加点赞按钮和其他反应,Facebook 能够收集对其排名算法的反馈。

对于具有自然基本事实标签的任务,从提供预测到提供反馈所需的时间就是反馈循环长度。

具有短反馈循环的任务是通常在几分钟内即可获得基本事实标签的任务。此类任务的典型示例是推荐系统。推荐系统的目标是向用户推荐他们喜欢的商品。用户是否点击推荐商品可以看作是对该推荐的反馈。被点击的推荐可以被认为是好的推荐(即标签为正面),未被点击的推荐可以被认为是不好的推荐(即标签为负面)。

许多任务可以定义为推荐任务。例如,你可以将预测广告点击率的任务定义为根据用户的活动历史和个人资料向用户推荐最相关的广告。

但是,并非所有推荐系统都具有短反馈循环。根据要推荐商品的性质,标签的延迟时间可能是几秒到几小时,在某些极端情况下,可能是几天或几周。如果推荐的商品是 Reddit 上要订阅的子版块、Twitter 上要关注的人、Tiktok 上接下来要观看的视频等,那么从推荐商品到用户点击(如果真的被点击)的时间就是几秒钟。如果你处理的是较长的内容类型,如博客文章或 YouTube 视频,则可能需要几分钟甚至几小时。但是,如果你建立一个像 Stitch Fix 那样的系统来为用户推荐衣服,那么在用户收到商品并试穿后你才会得到反馈,而这可能需要几周时间。

除非每个推荐商品旁边都有提示:“你喜欢这个推荐吗?是/否”,否则推荐系统没有明确的负面标签。即使你添加了这个提示,也不能保证用户会对此做出回应。通常,如果缺乏正面反馈,则认为推荐不好。在一定时间窗口后,如果没有点击,则认为标签是负面的。

选择合适的窗口长度需要仔细考虑,因为它涉及速度和准确性的权衡。较短的窗口长度意味着你可以更快地捕获标签,这允许你使用这些标签进行监控和持续学习。然而,较短的窗口长度也意味着你可能会在商品被点击之前过早地将其标记为无点击。

无论将窗口长度设置为多长,仍可能存在过早的负面标签。2021 年初,Twitter 广告团队的一项研究发现,尽管大多数广告点击发生在前 5 分钟内,但有些点击发生在广告展示后的数小时后。这意味着这种标签往往会低估实际点击率。如果你只记录了 1000 次点击,那么实际点击次数可能会略多于 1000 次。

2、机器学习系统故障的原因

在确定机器学习系统故障的原因之前,让我们先简单讨论一下什么是机器学习系统故障。当系统的一个或多个期望被违反时,就会发生故障。在传统软件中,我们主要关心系统的运行期望:系统是否在预期的运行指标(例如预期的延迟和吞吐量)内执行其逻辑。

对于机器学习系统,我们既关心其运行指标,也关心其机器学习性能指标。例如,考虑一个英法机器翻译系统。其运行期望可能是,给定一个英文句子,系统在一秒的延迟内返回法语翻译。其机器学习性能期望是,返回的翻译在 99% 的时间内是原始英文句子的准确翻译。

如果你在系统中输入英文句子但没有得到翻译,则第一个期望被违反,因此这是系统故障。

如果你得到的翻译不正确,则不一定是系统故障,因为准确性期望允许一定的误差幅度。但是,如果你不断向系统输入不同的英语句子并不断得到错误的翻译,则第二个期望被违反,这使其成为系统故障。

操作期望违规更容易检测,因为它们通常伴随着操作中断,例如超时、网页上的 404 错误、内存不足错误、分段错误等。但是,ML 性能期望违规更难检测,因为它需要测量和监控 ML 模型在生产中的性能。在上面的英法机器翻译系统的例子中,如果我们不知道正确的翻译应该是什么,那么检测返回的翻译是否 99% 的时间都是正确的是很困难的。有无数的例子表明,谷歌翻译的错误翻译被用户使用,因为他们不知道这些是错误的翻译。因此,我们说 ML 系统经常默默地失败。

为了有效地检测和修复生产中的 ML 系统故障,了解为什么一个模型在开发期间被证明运行良好后会在生产中失败是很有用的。我们将研究两种类型的故障:软件系统故障和 ML 特定故障。软件系统故障是非 ML 系统可能发生的故障。以下是一些软件系统故障的示例。

对于反馈循环较长的任务,自然标签可能要数周甚至数月才能到达。欺诈检测就是一个反馈循环较长的任务的例子。在交易后的一段时间内,用户可以对该交易是否为欺诈提出异议。例如,当客户阅读信用卡账单并看到一笔他们不认识的交易时,他们可能会向银行提出异议,并向银行反馈将该交易标记为欺诈。典型的争议窗口是一个月到三个月。争议窗口过后,如果用户没有提出异议,则可以假定该交易是合法的。

反馈循环较长的标签有助于在季度或年度业务报告中报告模型的表现。但是,如果你想尽快发现模型的问题,它们就没什么用了。如果你的欺诈检测模型存在问题,并且需要数月时间才能发现,那么等到问题解决时,有缺陷的模型所允许的所有欺诈交易可能已经导致一家小企业破产。

  • 依赖项故障:系统所依赖的软件包或代码库发生故障,导致系统崩溃。当依赖项由第三方维护时,这种故障模式很常见,如果维护依赖项的第三方不再存在,则尤其常见。
  • 部署失败:由部署错误导致的故障,例如当你意外部署模型旧版本而不是当前版本的二进制文件时,或者当你的系统没有读取或写入某些文件的正确权限时。
  • 硬件故障:当你用于部署模型的硬件(例如 CPU 或 GPU)无法正常运行时。例如,你使用的 CPU 可能会过热并发生故障。
  • 停机或崩溃:如果系统的某个组件从某个服务器(例如 AWS 或托管服务)运行,并且该服务器已关闭,则你的系统也会关闭。

某些故障并非特定于 ML,并不意味着 ML 工程师不需要了解它们。

2020 年,谷歌的两位机器学习工程师 Daniel Papasian 和 Todd Underwood 研究了谷歌大型机器学习管道发生故障的 96 起案例。他们审查了过去 15 年的数据以确定原因,发现这 96 起故障中有 60 起是由于与 ML 无直接关系的原因造成的。大多数问题与分布式系统有关,例如工作流调度程序或编排器出错,或与数据管道有关,例如来自多个来源的数据连接不正确或使用了错误的数据结构。

解决软件系统故障不需要机器学习技能,而是需要传统的软件工程技能,而解决这些技能超出了本课程的范围。由于传统软件工程技能在部署机器学习系统中的重要性,因此大部分机器学习工程都是工程,而不是 ML。对于有兴趣从软件工程角度学习如何使机器学习系统可靠的读者,我强烈推荐《可靠的机器学习》一书,该书也是由 O'Reilly 出版的,Todd Underwood 是作者之一。

软件系统故障普遍存在的一个原因是,由于机器学习在行业中的应用仍处于起步阶段,围绕机器学习生产的工具有限,最佳实践尚未得到很好的开发或标准化。然而,随着机器学习生产工具和最佳实践的成熟,有理由相信软件系统故障的比例将会下降,而机器学习特定故障的比例将会上升。

机器学习特定故障是机器学习系统特有的故障。示例包括数据收集和处理问题、较差的超参数、训练管道中的变化未在推理管道中正确复制,反之亦然、导致模型性能随时间恶化的数据分布变化、极端情况和退化反馈回路。

在本讲座中,我们将重点介绍解决机器学习特定故障。尽管它们只占故障的一小部分,但它们可能比非机器学习故障更危险,因为它们很难检测和修复,并且可能会阻止整个机器学习系统的使用。在之前的讲座中,我们介绍了数据问题、超参数调整以及训练和推理两个独立管道的危险。在本讲座中,我们将讨论部署模型后出现的三个新问题,但这些问题非常常见:数据分布变化、极端情况和退化反馈循环。

3、生产数据不同于训练数据

当我们说 ML 模型从训练数据中学习时,这意味着该模型学习训练数据的底层分布,目的是利用这种学习到的分布为没见过的数据(即训练期间未看到的数据)生成准确的预测。我们将在下面的数据分布偏移部分中深入探讨这在数学上的含义。

当模型能够为没见过的数据生成准确的预测时,我们说这个模型“推广到看不见的数据”。我们在开发过程中用来评估模型的测试数据应该代表没见过的数据,而模型在测试数据上的表现应该让我们了解模型的推广效果。

我在机器学习课程中学到的第一件事就是,训练数据和未知数据必须来自同一分布。假设未知数据来自与训练数据分布相同的平稳分布。如果未知数据来自不同的分布,模型可能无法很好地泛化。

软件系统故障普遍存在的一个原因是,由于机器学习在行业中的应用仍处于起步阶段,围绕机器学习生产的工具有限,最佳实践尚未完善或标准化。然而,随着机器学习生产工具和最佳实践的成熟,有理由相信软件系统故障的比例将会下降,而机器学习特定故障的比例将会上升。

这种假设在大多数情况下是不正确的,原因有二。

首先,现实世界数据的底层分布不太可能与训练数据的底层分布相同。整理一个能够准确表示模型在生产中会遇到的数据的训练数据集非常困难。现实世界的数据是多方面的,在许多情况下几乎是无限的,而训练数据是有限的,受到数据集创建和处理过程中可用的时间、计算和人力资源的限制。可能会发生许多不同的选择和采样偏差,并使现实世界数据与训练数据不同。这种差异可能很小,例如现实世界数据使用了不同类型的表情符号编码。这种类型的差异导致一种常见的故障模式,称为训练服务偏差(train-serving skew):模型在开发中表现出色,但在部署时表现不佳。

其次,现实世界并不是一成不变的。事情在变化。数据分布在变化。 2019 年,当人们搜索德特里克堡时,他们可能想要获取军事信息,但自 COVID-19 以来,当人们搜索德特里克堡时,他们可能想要了解 COVID-19 的发源地。另一种常见的故障模式是模型在首次部署时表现良好,但随着数据分布的变化,其性能会随着时间的推移而下降。只要模型仍在生产中,就需要持续监控和检测这种故障模式。

当我以 COVID-19 为例,它会导致数据漂移(data shifts),有些人会认为数据漂移只会因为不寻常的事件而发生,这意味着它们并不经常发生。数据转移随时都在发生,突然、逐渐或季节性。它们可能因为特定事件而突然发生,

例如当你现有的竞争对手改变定价政策时,你必须更新价格预测以做出响应,或者当你在新地区推出产品时,或者当名人提到你的产品导致新用户激增时,等等。它们可能逐渐发生,因为社会规范、文化、语言、趋势、行业等会随着时间的推移而变化。这些情况也可能由于季节变化而发生,例如人们在寒冷多雪的冬季比在春季更有可能要求拼车

谈到数据漂移时,许多人会认为这是由于外部变化造成的,例如自然灾害、节假日或用户行为。但实际上,由于 ML 系统的复杂性以及部署不当,监控仪表板上看似数据转移的很大一部分是由内部错误8 引起的,例如数据管道中的错误、错误填写的缺失值、训练和推理期间提取的特征不一致、使用错误数据子集的统计数据标准化的特征、错误的模型版本或迫使用户改变行为的应用程序界面中的错误。

由于这是一种影响几乎所有 ML 模型的错误模式,我们将在数据分布漂移部分详细介绍这一点。

4、极端情况

想象一下,有一辆自动驾驶汽车可以在 99.99% 的时间里安全地驾驶你,但在另外 0.01% 的时间里,它可能会发生灾难性的事故,让你永久受伤甚至死亡。你会使用那辆车吗?

如果你想说“不”,你并不孤单。如果一个 ML 模型在大多数情况下表现良好,但在少数情况下失败,并且这些失败会导致灾难性后果,那么它可能无法使用。因此,主要的自动驾驶汽车公司正专注于让他们的系统在极端情况下工作。

极端情况(edge cases)是极端的数据样本,它们会导致模型犯下灾难性错误。尽管极端情况通常是指从同一分布中提取的数据样本,但如果你的模型表现不佳的数据样本数量突然增加,则可能表明底层数据分布发生了变化。

自动驾驶汽车通常用于说明极端情况如何阻止 ML 系统的部署。但这也适用于任何安全关键型应用,例如医疗诊断、交通管制、电子取证等。对于非安全关键型应用也是如此。想象一下,一个客服聊天机器人对大多数请求都给出了合理的回应,但有时,它会吐出令人发指的种族主义或性别歧视内容。对于任何想要使用它的公司来说,这个聊天机器人都会带来品牌风险,从而使其无法使用。

4.1 极端情况 vs. 异常值

你可能想知道异常值(outliers)和极端情况(edge cases)之间的区别。极端情况的定义因学科而异。在机器学习中,由于最近才开始投入生产,极端情况仍在被发现,这使得它们的定义存在争议。

在本讲座中,异常值指的是数据:与其他样本有显著差异的示例。极端情况指的是性能:模型性能明显低于其他示例的示例。异常值可能导致模型性能异常差,这使其成为极端情况。但是,并非所有异常值都是边缘情况。例如,在高速公路上乱穿马路的人是异常值,但如果你的自动驾驶汽车可以准确检测到该人并适当地决定运动响应,则它不是极端情况。

在模型开发过程中,异常值可能会对模型的性能产生负面影响。在许多情况下,删除异常值可能会有所帮助,因为它可以帮助你的模型学习更好的决策边界并更好地推广到看不见的数据。然而,在推理过程中,你通常无法选择删除或忽略与其他查询有显著差异的查询。你可以选择对其进行转换 - 例如,当你在 Google 搜索中输入“mechin learnin”时,Google 可能会询问是否指的是“机器学习”。但最有可能的是,你需要开发一个模型,以便它即使在意外输入的情况下也能表现良好:

左图显示没有异常值时的决策边界。右图显示有一个异常值时的决策边界,这与第一种情况下的决策边界非常不同,并且可能不太准确

5、退化反馈循环

在本讲座前面的自然标签和反馈循环部分中,我们讨论了反馈循环,即从显示预测到提供预测反馈所花费的时间。反馈可用于提取自然标签以评估模型的性能。

当预测本身影响反馈时,就会发生退化反馈循环(degenerate feedback loop),然后使用反馈提取标签来训练模型的下一次迭代。更正式地说,当系统的输出用于创建或处理同一系统的输入时,就会产生退化反馈循环,而输入又会影响系统的未来输出。

在机器学习中,系统的预测会影响用户与系统的交互方式,并且由于用户与系统的交互有时被用作同一系统的输入,因此可能会发生退化反馈循环并导致意想不到的后果。退化反馈循环在具有来自用户的自然标签的任务中尤其常见,例如推荐系统和广告点击率预测。

为了具体说明这一点,假设你构建了一个系统来向用户推荐他们可能喜欢的歌曲。系统排名靠前的歌曲会优先显示给用户。因为它们被优先显示,所以用户点击它们的次数更多,这使得系统更加确信这些推荐是好的。一开始,两首歌曲 A 和 B 的排名可能只有微小的差别,但是因为 A 最初的排名略高,所以点击次数更多,这使得系统将 A 排得更高。过了一段时间,A 的排名就比 B 高得多。退化的反馈回路是流行电影、书籍或歌曲越来越受欢迎的原因之一,这使得新作品很难进入流行榜单。这种情况在制作中极为常见,而且得到了大量研究。它有许多不同的名字,包括“曝光偏差”、“流行偏差”、“过滤气泡”,有时也叫“回音室”。

这是另一个例子,可以进一步说明退化反馈循环的概念。想象一下,建立一个简历筛选模型来预测具有特定简历的人是否适合这份工作。该模型发现特征 X 可以准确预测某人是否符合条件,因此它会推荐具有特征 X 的简历。你可以用“就读斯坦福大学”、“在谷歌工作过”或“男性身份”等特征替换 X。招聘人员只会面试简历被模型推荐的人,这意味着他们只会面试具有特征 X 的候选人,这意味着公司只会聘用具有特征 X 的候选人。这反过来又使模型更加重视特征 X15。了解模型如何进行预测(例如,衡量每个特征对模型的重要性)可以帮助检测本例中对特征 X 的偏见。

如果不加以注意,退化反馈循环可能会导致你的模型表现不佳。在最坏的情况下,它可以延续和放大数据中嵌入的偏见,例如对没有上述特征 X 的候选人产生偏见。

5.1 检测退化反馈回路

如果退化反馈回路如此糟糕,我们如何知道系统中的反馈回路是否退化?当系统处于离线状态时,退化反馈回路很难检测到。退化回路是由用户反馈引起的,系统只有在上线(例如部署给用户)时才会有用户。

对于推荐系统的任务,即使系统处于离线状态,也可以通过测量系统输出的流行度多样性来检测退化反馈回路。可以根据过去与之交互的次数(例如看到、喜欢、购买等)来衡量项目的流行度。所有项目的流行度可能都遵循长尾分布:少数项目交互很多,而大多数项目几乎不交互。Brynjolfsson 等人(2011 年)、Fleder 等人提出了各种指标,例如长尾项目的总体多样性和平均覆盖率。 (2009)和 Abdollahpouri 等人(2019)可以帮助您衡量推荐系统输出的多样性。低分意味着您的系统的输出是同质的,这可能是由流行度偏差造成的。

2021 年,Chia 等人更进一步,提出了命中率与流行度的衡量标准。他们首先根据项目的流行度将其划分为不同的桶 — — 例如,桶 1 由交互次数少于 100 次的项目组成,桶 2 由交互次数超过 100 次但少于 1000 次的项目组成,等等。然后他们测量了推荐系统对每个桶的预测准确率。如果推荐系统在推荐热门项目方面比推荐不太受欢迎的项目要好得多,那么它很可能受到流行度偏差的影响。一旦你的系统投入生产,你就会注意到它的预测随着时间的推移变得更加同质,它很可能受到退化反馈循环的影响。

5.2 纠正退化反馈回路

由于退化反馈回路是一个常见问题,因此提出了许多纠正方法。在本讲座中,我们将讨论两种方法。第一种方法是使用随机化,第二种方法是使用位置特征。

我们已经讨论过,退化反馈回路会导致系统的输出随着时间的推移变得更加同质。在预测中引入随机化可以降低其同质性。在推荐系统中,我们不会只向用户显示系统为他们排名较高的项目,而是向用户显示随机项目,并使用他们的反馈来确定这些项目的真实质量。这是 TikTok 遵循的方法。每个新视频都会随机分配一个初始流量池(最多可达数百次展示)。这个流量池用于评估每个视频的无偏质量,以确定是否应将其移动到更大的流量池或标记为不相关。

事实证明,随机化可以提高多样性,但代价是用户体验。向用户展示完全随机的项目可能会导致用户对我们的产品失去兴趣。智能探索策略(例如上下文老虎机)可以帮助增加项目多样性,同时将预测准确度损失控制在可接受范围内。Schnabel 等人使用少量随机化和因果推理技术来估计每首歌曲的无偏值。他们能够证明该算法能够纠正推荐系统,使推荐对创作者公平。

我们还讨论了退化反馈循环是由用户对预测的反馈引起的,并且用户对预测的反馈会根据显示位置而产生偏差。考虑上面的推荐系统示例,每次您向用户推荐 5 首歌曲。您意识到与其他 4 首歌曲相比,最热门的推荐歌曲被点击的可能性要大得多。您不确定您的模型是否特别擅长挑选热门歌曲,或者用户是否会点击任何歌曲(只要它被推荐在最热门的位置)。

如果预测显示的位置以任何方式影响其反馈,您可能需要使用位置特征对位置信息进行编码。位置特征可以是数值(例如位置为 1、2、3 等)或布尔值(例如预测是否显示在第一个位置)。请注意,“位置特征”与上一节课中提到的“位置嵌入”不同。

下面是一个简单示例,展示了如何使用位置特征。在训练期间,你将“是否首先推荐一首歌曲”作为特征添加到训练数据中,如表 7-1 所示。此功能可让你的模型了解成为热门推荐对歌曲被点击的可能性有多大影响。

向训练数据中添加位置特征以缓解退化的反馈回路

在推理过程中,无论歌曲推荐在哪里,你都希望预测用户是否会点击该歌曲,因此你可能希望将第一个位置特征设置为 False。然后,你可以查看模型对每个用户的各种歌曲的预测,并选择显示每首歌曲的顺序。

这是一个简单的例子,因为仅这样做可能不足以对抗退化的反馈循环。更复杂的方法是使用两个不同的模型。第一个模型预测用户看到并考虑推荐的概率,同时考虑该推荐的位置。然后,第二个模型预测用户在看到并考虑该项目的情况下点击该项目的概率。第二个模型根本不关心位置。

6、数据分布漂移

在上一节中,我们讨论了 ML 系统故障的常见原因。在本节中,我们将集中讨论一个特别棘手的故障原因:数据分布漂移(data distribution shifts),简称数据漂移(data shifts)。数据分布漂移是指监督学习中模型处理的数据随时间变化的现象,这会导致该模型的预测随着时间的推移变得不那么准确。模型训练所依据的数据分布称为源分布。模型运行推理所依据的数据分布称为目标分布。

尽管围绕数据分布漂移的讨论只是近年来随着 ML 在行业中的日益普及才变得普遍,但早在 1986 年,从数据中学习的系统中的数据分布偏移就已被研究。Quiñonero-Candela 等人还撰写了一本关于数据集分布漂移的书,由麻省理工学院出版社于 2008 年出版。

6.1 数据分布偏移的类型

虽然数据分布偏移通常与概念漂移、协变量漂移以及偶尔的标签漂移互换使用,但这是数据漂移的三种不同子类型。要理解它们的含义,我们首先需要定义几个数学符号。

我们将模型的输入称为 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) 保持不变。这指的是联合分布的第一次分解。

如果你觉得这令人困惑,请不要惊慌。我们将在下一节中通过示例来说明它们的区别。

6.2 协变量漂移

协变量漂移(covariate shifts)是研究最广泛的数据分布漂移形式之一。

在统计学中,协变量是一个独立变量,它可以影响给定统计试验的结果,但不是直接感兴趣的变量。

假设你正在进行一项实验,以确定位置如何影响房价。房价变量是你直接感兴趣的变量,但你知道平方英尺会影响价格,因此平方英尺是一个协变量。在监督式机器学习中,标签是直接感兴趣的变量,输入特征是协变量。

从数学上讲,协变量漂移是指 P(X) 发生变化,但 P(Y|X) 保持不变,这意味着输入的分布发生变化,但给定输入的标签的条件概率保持不变。

为了具体化,考虑检测乳腺癌的任务。你知道 40 岁以上的女性患乳腺癌的风险更高,因此你有一个变量“年龄”作为输入。你的训练数据中 40 岁以上的女性可能比推理数据中多,因此训练数据和推理数据的输入分布不同。但是,对于给定年龄(例如 40 岁以上)的示例,该示例患有乳腺癌的概率是恒定的。因此,P(Y|X),即年龄超过 40 岁时患乳腺癌的概率是相同的。

在模型开发过程中,协变量漂移可能会由于数据选择过程中的偏差而发生,这可能是由于难以收集某些类别的示例而导致的。例如,假设要研究乳腺癌,你会从女性前去检测乳腺癌的诊所获取数据。由于医生鼓励 40 岁以上的人进行检查,因此你的数据以 40 岁以上的女性为主。因此,协变量漂移与样本选择偏差问题密切相关。

协变量漂移也可能因为训练数据被人为更改而发生,以使你的模型更容易学习。 ML 模型很难从不平衡的数据集中学习,因此你可能需要收集更多稀有类别的样本或对稀有类别的数据进行过度采样,以使你的模型更容易学习稀有类别。

协变量漂移也可能由模型的学习过程引起,尤其是通过主动学习(active learning)。在之前的讲座中,我们对主动学习进行了如下定义:我们不是随机选择样本来训练模型,而是根据一些启发式方法使用对该模型最有帮助的样本。这意味着训练输入分布会因学习过程而改变,从而不同于现实世界的输入分布,而协变量漂移是副产品。

在生产中,协变量漂移通常是由于环境或应用程序使用方式发生重大变化而发生的。假设你有一个模型可以预测免费用户转化为付费用户的可能性。用户的收入水平是一个特征。贵公司的营销部门最近发起了一项活动,以吸引比当前人口更富裕的人口群体中的用户。输入到模型中的分布已经发生变化,但具有给定收入水平的用户转化的概率保持不变。

或者假设你想建立一个模型,根据咳嗽的声音来检测某人是否患有 COVID-19。要训练模型,你可以使用从医院收集的录音。这些录音是在安静的房间中录制的,开始时间一致。但是,当你将模型部署为移动应用程序时,用户可以直接对着手机麦克风咳嗽,录音会非常不同 - 它们可能在咳嗽前几秒开始,也可能直到咳嗽中途才开始。它们还可能包含各种各样的背景噪音。你的模型在电话录音中的表现不会很好。

如果事先知道现实世界的输入分布与训练输入分布有何不同,你可以利用重要性加权等技术来训练你的模型以适用于现实世界数据。重要性加权包括两个步骤:估计现实世界输入分布与训练输入分布之间的密度比,然后根据该比率对训练数据进行加权,并在此加权数据上训练 ML 模型。

但是,由于我们事先不知道分布在现实世界中会如何变化,因此很难预先训练你的模型以使其对新的未知分布具有鲁棒性。有研究尝试帮助模型学习在数据分布中不变的潜在变量的表示,但我不知道它们在业界是否得到应用。

6.3 标签漂移

标签漂移(label shifts),也称为先验漂移(prior shifts)、先验概率漂移(prior probability shifts)或目标漂移(target shifts),是指 P(Y) 发生变化但 P(X|Y) 保持不变的情况。你可以将其视为输出分布发生变化但对于给定输出,输入分布保持不变的情况。

请记住,协变量漂移是指输入分布发生变化的情况。当输入分布发生变化时,输出分布也会发生变化,从而导致协变量漂移和标签漂移同时发生。考虑上述乳腺癌协变量漂移的示例。由于我们的训练数据中 40 岁以上的女性比我们的推理数据中多,因此训练期间 POSITIVE 标签的百分比更高。但是,如果你从训练数据中随机选择患有乳腺癌的人 A,从推理数据中随机选择患有乳腺癌的人 B,则 A 和 B 年龄超过 40 岁的概率相同。这意味着 P(X|Y) 或患有乳腺癌的年龄超过 40 岁的概率是相同的。所以这也是标签漂移的情况。

但是,并非所有协变量漂移都会导致标签漂移。这是一个微妙的点,所以我们将考虑另一个例子。想象一下,现在有一种预防药物,每个女人都服用,有助于降低她们患乳腺癌的几率。对于所有年龄段的女性,概率 P(Y|X) 都会降低,因此这不再是协变量漂移的情况。然而,对于一个患有乳腺癌的人,年龄分布保持不变,所以这仍然是标签漂移的情况。

由于标签漂移与协变量漂移移密切相关,检测和调整模型以适应标签漂移的方法类似于协变量漂移适应方法。我们将在下面的处理数据漂移部分中进一步讨论它们。

6.4 概念漂移

概念漂移(concept shifts),也称为后验漂移(posterior shifts),是指输入分布保持不变,但给定输入的输出条件分布发生变化的情况。你可以将其视为“输入相同,输出不同”。

假设你负责一个根据房屋特征预测房屋价格的模型。在 COVID-19 之前,旧金山的一套三居室公寓可能要花费 2,000,000 美元。然而,在 COVID-19 开始时,许多人离开了旧金山,所以同样的房子只需 1,500,000 美元。因此,即使房屋特征的分布保持不变,给定房屋特征的房屋价格的条件分布也发生了变化。

在许多情况下,概念漂移是周期性的或季节性的。例如,拼车的价格在工作日和周末会波动,机票价格在假日季节会上涨。公司可能有不同的模型来应对周期性和季节性漂移。例如,他们可能有一个模型来预测工作日的拼车价格,另一个模型来预测周末的价格。

6.5 一般性的数据分布漂移

现实世界中还有其他类型的变化,即使研究中没有得到很好的研究,它们仍然会降低模型的性能。

一个是特征变化(feature change),例如添加新特征、删除旧特征或特征的所有可能值集合发生变化。例如,你的模型使用年份作为“年龄”特征,但现在使用月份,因此此特征值的范围发生了变化。有一次,我们的团队意识到我们模型的性能下降,因为我们的管道中的一个错误导致一个特征变为 NaN。

标签模式变化(label schema change)是指 Y 的可能值集合发生变化。随着标签变化,P(Y) 发生变化,但 P(X|Y) 保持不变。随着标签模式变化,P(Y) 和 P(X|Y) 都会发生变化。模式描述了数据的结构,因此任务的标签模式描述了该任务标签的结构。例如,从类映射到整数值的字典,如 {“POSITIVE”: 0, “NEGATIVE”: 1},是一种模式。

对于回归任务,标签模式变化可能会因为标签值的可能范围发生变化而发生。假设你正在构建一个模型来预测某人的信用评分。最初,你使用的信用评分系统范围是 300 到 850,但你切换到了一个范围从 250 到 900 的新系统。

对于分类任务,标签模式变化可能会因为你有新的类别而发生。例如,假设你正在构建一个诊断疾病的模型,并且有一种新的疾病需要诊断。类别也可能变得过时或更细粒度。

想象一下,你负责针对提及你品牌的推文的情绪分析模型。最初,你的模型只预测了 3 个类别:POSITIVE、NEGATIVE 和 NEUTRAL。然而,你的营销部门意识到最具破坏性的推文是愤怒的推文,因此他们希望将负面类别分为两类:悲伤和愤怒。你的任务现在有四个类别,而不是三个类别。当类别数量发生变化时,你的模型结构可能会发生变化,你可能需要重新标记数据并从头开始重新训练模型。标签模式更改在高基数任务(具有大量类别的任务)中尤其常见,例如产品或文档分类。

没有规则说一次只能发生一种类型的偏移。一个模型可能会受到多种类型的漂移的影响,这使得处理它们变得更加困难。

7、处理数据分布漂移

公司如何处理数据漂移取决于其 ML 基础设施设置的复杂程度。

一方面,有些公司刚刚开始使用 ML,仍在努力将 ML 模型投入生产,因此它们可能还没有达到数据变化对它们造成灾难性的程度。然而,在未来的某个时候——可能是 3 个月,可能是 6 个月——他们可能会意识到他们最初部署的模型已经退化到弊大于利的程度。然后,他们将需要调整模型以适应变化的分布或用其他解决方案替换它们。

与此同时,许多公司认为数据变化是不可避免的,因此他们会定期重新训练他们的模型——每季度一次、每月一次、每周一次甚至每天一次——无论变化程度如何。如何确定重新训练模型的最佳频率是一个重要的决定,许多公司仍然根据直觉而不是实验数据来决定。我们将在持续学习讲座中进一步讨论重新训练频率。

很多公司希望更有针对性地处理数据转移,这包括两部分:第一,检测漂移;第二,解决漂移。

7.1 检测数据分布漂移

数据分布漂移只有在导致模型性能下降时才会成为问题。因此,第一个想法可能是在生产过程中监控模型的准确度相关指标,以查看它们是否发生了变化。这里的“变化”通常意味着“减少”,但如果我的模型准确度突然上升或无缘无故地大幅波动,我会想要调查。

准确度相关指标通过将模型的预测与真实值标签进行比较来工作。在模型开发期间,你可以访问真实值,但在生产过程中,你并不总是可以访问真实值,即使你可以访问真实值,真实值标签也会延迟,如上文“自然标签和反馈循环”部分所述。在合理的时间范围内访问真实值将极大地帮助你了解模型的性能。

当真实值标签不可用或延迟太久而无法使用时,我们可以改为监控其他感兴趣的分布。我们感兴趣的分布是输入分布 P(X)、标签分布 P(Y) 以及条件分布 P(X|Y) 和 P(Y|X)。

虽然我们不需要知道基本事实标签 Y 来监控输入分布,但监控标签分布和两个条件分布都需要知道 Y。在研究中,人们一直在努力理解和检测没有标签的标签偏离目标分布的情况。其中一项努力是 Lipton 等人于 2018 年提出的黑盒漂移估计(blackbox shift estimatin)。然而,在业界,大多数漂移检测方法侧重于检测输入分布的变化,尤其是特征分布的变化。

7.2 检测分布漂移的统计方法

在行业中,许多公司用来检测两个分布是否相同的一种简单方法是比较它们的统计数据,例如均值、中位数、方差、分位数、偏度、峰度等。

例如,你可以在推理过程中计算特征值的中位数和方差,并将它们与训练期间计算的指标进行比较。截至 2021 年 10 月,即使是 TensorFlow Extended 的内置数据验证工具也仅使用汇总统计数据来检测训练数据和服务数据之间的偏差以及不同天数的训练数据之间的偏差。这是一个好的开始,但这些指标还远远不够。均值、中位数和方差仅适用于均值/中位数/方差是有用摘要的分布。如果这些指标差异很大,则推理分布可能已从训练分布中漂移。但是,如果这些指标相似,则不能保证没有偏移。

更复杂的解决方案是使用双样本假设检验,简称为双样本检验(two-sample test)。这是一项测试,用于确定两个总体(两组数据)之间的差异是否具有统计学意义。如果差异具有统计学意义,那么差异是由于抽样变异而随机波动的概率非常低,因此差异是由这两个总体来自两个不同的分布这一事实造成的。如果你将昨天的数据视为源总体,将今天的数据视为目标总体,并且它们在统计上存在差异,则底层数据分布很可能在昨天和今天之间发生了变化。

基本的双样本检验是 Kolmogorov-Smirnov 检验,也称为 K-S 或 KS 检验。它是一种非参数统计检验,这意味着它不需要任何底层分布的参数即可工作。它不对底层分布做任何假设,这意味着它可以适用于任何分布。但是,KS 检验的一个主要缺点是它只能用于一维数据。如果模型的预测和标签是一维的(标量),那么 KS 检验可用于检测标签或预测偏移。但是,它不适用于高维数据,而特征通常是高维的。K-S 检验也可能很昂贵并且会产生太多的误报警报。

另一个测试是最小二乘密度差,这是一种基于最小二乘密度差估计方法的算法。还有 MMD,即最大均值差异 (Gretton 等人,2012),这是一种基于核的多变量双样本测试技术,以及其变体学习核 MMD (Liu 等人,2020)。MMD 在研究中很流行,但截至撰写本文时,我还没有发现任何公司在行业中使用它。alibi-detect 是一个很棒的开源软件包,其中实现了许多漂移检测算法。

需要注意的是,差异具有统计学意义并不意味着它在实践中很重要。但是,一个好的启发式方法是,如果你能够从相对较小的样本中检测到差异,那么它可能是一个严重的差异。如果需要大量样本,那么它可能不值得担心。

alibi-detect 实现的一些漂移检测算法

由于双样本检验在低维数据上的效果通常比在高维数据上更好,因此强烈建议您在对数据进行双样本检验之前降低数据的维数37。

7.3 用于检测偏移的时间尺度窗口

并非所有类型的漂移都是相同的——有些比其他类型的更难检测。例如,漂移发生的速率不同,突变比缓慢、渐进的变化更容易检测。漂移也可以发生在两个维度上:空间或时间。空间偏移是跨接入点发生的偏移,例如你的应用程序获得了一组新用户,或者你的应用程序现在在不同类型的设备上提供服务。时间偏移是随时间发生的偏移。要检测时间偏移,一种常见的方法是将 ML 应用程序的输入数据视为时间序列数据。

在处理时间偏移时,我们查看的数据的时间尺度窗口会影响我们可以检测到的偏移。如果你的数据有每周周期,那么少于一周的时间尺度将无法检测到周期。考虑下图中的数据。如果我们使用第 9 天到第 14 天的数据作为源分布,那么第 15 天看起来就像是一个偏移。但是,如果我们使用第 1 天到第 14 天的数据作为源分布,那么第 15 天的所有数据点很可能都是由同一分布生成的。如本例所示,当偏移受到季节变化的影响时,检测时间偏移很困难:

分布是否随时间漂移取决于指定的时间尺度窗口。如果我们使用第 9 天到第 14 天的数据作为基础分布,那么第 15 天看起来就像是漂移。但是,如果我们使用第 1 天到第 14 天的数据作为基础分布,那么第 15 天的所有数据点都可能是由同一分布生成的

在计算一段时间内的运行统计数据时,区分累积统计数据和滑动统计数据非常重要。滑动统计数据是在单个时间尺度窗口内计算的,例如一个小时。累积统计数据会不断更新更多数据。这意味着,对于每个时间尺度窗口的开始,滑动精度都会重置,而累积滑动精度则不会重置。由于累积统计数据包含来自之前时间窗口的信息,因此它们可能会掩盖特定时间窗口中发生的情况。这是累积精度如何隐藏 16 点到 18 点之间精度突然下降的一个例子。此图基于 MadeWithML 的一个示例:

累积准确度掩盖了 16 点到 18 点之间准确度的突然下降

在时间空间中处理数据会使事情变得更加复杂,需要了解时间序列分析技术,例如超出本课程范围的时间序列分解。对于对时间序列分解感兴趣的读者,这里有一个由 Lyft 工程部门提供的关于他们如何分解时间序列数据以应对市场季节性的出色案例研究。

截至目前,许多公司使用训练数据的分布作为基础分布,并以一定的粒度级别(例如每小时和每天)监控生产数据分布。时间尺度窗口越短,你就能越快地检测到数据分布的变化。但是,时间尺度窗口太短可能会导致错误警报,如上例所示。

某些平台,尤其是那些处理实时数据分析(例如监控)的平台,提供了合并操作,允许合并较短时间尺度窗口的统计数据以创建较大时间尺度窗口的统计数据。例如,你可以按小时计算您关心的数据统计数据,然后将这些每小时统计数据块合并到每日视图中。

更先进的监控平台甚至尝试使用根本原因分析 (RCA) 功能,该功能可以自动分析不同时间窗口大小的统计数据,以准确检测数据发生变化的时间窗口。

7.4 解决数据分布漂移问题

要使模型在生产中适应新的分布,主要有三种方法。

第一种方法是目前占主导地位的研究方法:使用海量数据集训练模型。这里的希望是,如果训练数据集足够大,模型将能够学习如此全面的分布,以至于模型在生产中遇到的任何数据点都可能来自这个分布。

第二种方法在研究中不太流行,它是将训练好的模型调整到目标分布,而不需要新的标签。Zhang 等人 (2013) 使用因果解释以及条件和边际分布的核嵌入来校正模型对协变量漂移和标签漂移的预测,而无需使用目标分布中的标签。同样,Zhao 等人 (2020) 提出了领域不变表示学习:一种无监督领域自适应技术,可以学习对变化的分布不变的数据表示。然而,这一研究领域严重未被充分探索,尚未在工业界得到广泛采用。

第三种方法是当今业界通常采用的方法:使用来自目标分布的标记数据重新训练模型。但是,重新训练模型并不那么简单。重新训练可能意味着在旧数据和新数据上从头开始重新训练模型,或者继续在新数据上训练现有模型。后一种方法也称为微调(fine-tuning)。

如果你想微调模型,问题可能是使用什么数据:过去一小时、过去 24 小时、上周或过去 6 个月的数据。一种常见的做法是从数据开始漂移的点开始微调模型。另一种方法是使用上次微调收集的数据来微调模型。你可能需要进行实验来确定哪种重新训练解决方案最适合你。

在本讲座中,我们使用“再训练”来指从头开始训练和微调。

熟悉数据转移文献的读者可能经常会看到数据转移与领域适应和迁移学习一起被提及。如果你将分布视为领域,那么如何将模型适应新分布的问题与如何将模型适应不同领域的问题类似。

同样,如果你将学习联合分布 P(X, Y) 视为一项任务,那么将在一个联合分布上训练的模型适应另一个联合分布可以视为一种迁移学习(transfer learning)。迁移学习是指将为一项任务开发的模型重新用作第二项任务模型的起点的方法系列。不同之处在于,使用迁移学习,你无需为第二项任务从头开始重新训练基础模型。但是,要使你的模型适应新的分布,你可能需要从头开始重新训练模型。

解决数据分布漂移问题不必在漂移发生后开始。可以设计你的系统以使其对转移更具鲁棒性。一个系统使用多种特征,不同特征的变化速率也不同。

假设你正在构建一个模型来预测用户是否会下载某个应用。你可能想将该应用在应用商店中的排名用作特征,因为排名较高的应用往往下载次数较多。但是,应用排名变化非常快。你可能希望将每个应用的排名分为一般类别,例如前 10 名、11-100 名之间、101-1000 名之间、1001-10,000 名之间等等。同时,应用的类别变化频率可能要低得多,但可能不太能预测用户是否会下载该应用。在为模型选择特征时,你可能需要考虑特征的性能和稳定性之间的权衡:某个特征可能非常有利于提高准确性,但很快就会下降,从而迫使你更频繁地训练模型。

显然,只对新数据进行微调是首选,因为它需要的计算资源更少,而且运行速度比在旧数据和新数据上从头开始重新训练模型更快。然而,根据他们的设置,许多公司发现微调并不能使他们的模型获得足够好的性能,因此必须从头开始重新训练。

你可能还希望设计系统以使其更容易适应变化。例如,旧金山等大城市的房价变化速度可能比亚利桑那州农村地区快得多,因此为亚利桑那州农村地区服务的房价预测模型可能需要比为旧金山服务的模型更新频率更低。如果你使用相同的模型来服务两个市场,则必须使用来自两个市场的数据以旧金山要求的速度更新模型。但是,如果你为每个市场使用单独的模型,则可以仅在必要时更新每个模型。

在我们进入下一讲之前,我只想重申,并非所有生产模型的性能下降都需要 ML 解决方案。当今的许多 ML 故障(不是软件系统故障和 ML 特定故障)仍然是由人为错误造成的。如果你的模型故障是由人为错误引起的,你首先需要找到这些错误来修复它们。检测数据漂移很难,但确定导致漂移的原因可能更难。

8、监控和可观察性

随着业界意识到机器学习系统可能出现许多问题,许多公司开始在生产中投资监控和可观察性,以改善其机器学习系统。

监控(monitoring)和可观察性(observability)有时可以互换使用,但它们是不同的。监控是指跟踪、测量和记录不同指标的行为,这些指标可以帮助我们确定何时出现问题。可观察性意味着以一种让我们能够看到系统的方式设置我们的系统,以帮助我们调查出了什么问题。以这种方式设置系统的过程也称为仪表化(instrumentation)。仪表化的示例包括向函数添加计时器、计算特征中的 NaN、跟踪输入如何通过系统进行转换、记录异常事件(例如异常长的输入)等。可观察性是监控的一部分。没有一定程度的可观察性,监控就不可能实现。

监控就是指标。由于机器学习系统是软件系统,因此你需要监控的第一类指标是操作指标。这些指标旨在传达系统的健康状况。它们通常分为三个级别:系统运行的网络、系统运行的机器以及系统运行的应用程序。这些指标的示例包括延迟、吞吐量、模型在最后一分钟、一小时、一天收到的预测请求数、返回 2XX 代码的请求百分比、CPU/GPU 利用率、内存利用率等。无论你的 ML 模型有多好,如果系统宕机,你都不会从中受益。

让我们看一个例子。生产中的软件系统最重要的特性之一是可用性——系统多久可以向用户提供合理的性能。此特性通过正常运行时间(系统正常运行时间的百分比)来衡量。确定系统是否正常运行的条件在服务级别目标 (SLO) 或服务级别协议 (SLA) 中定义。例如,SLA 可以指定如果服务的中位延迟小于 200 毫秒且第 99 个百分位数低于 2 秒,则认为该服务已启动。

注意:可用性对系统有多重要是一个权衡决定。CAP 定理指出,任何分布式数据存储只能提供以下三个保证中的两个:一致性、可用性和分区容错性。

服务提供商可能会提供指定其正常运行时间保证的 SLA,例如 99.99% 的时间,如果未达到此保证,他们将退还客户款项。例如,截至 2021 年 10 月,AWS EC2 服务提供至少 99.99%(四个九)的每月正常运行时间百分比,如果每月正常运行时间百分比低于该百分比,他们将退还你未来 EC2 付款的服务信用额度。99.99% 的每月正常运行时间意味着服务每月仅允许停机 4 分钟多一点,而 99.999% 意味着每月仅允许停机 26 秒!

但是,对于 ML 系统,系统健康状况超出了系统正常运行时间。如果你的 ML 系统正常运行但其预测是垃圾,你的用户不会满意。你想要监控的另一类指标是特定于 ML 的指标,它可以告诉你 ML 模型的健康状况。

8.1 ML 特定指标

在 ML 特定指标中,通常有四个工件(artifacts)需要监控:模型的准确性相关指标、预测、特征和原始输入。

这些是在 ML 系统管道的四个不同阶段生成的工件。工件在管道中的位置越深,它经历的转换就越多,这使得该工件的更改更有可能是由其中某个转换中的错误引起的。但是,工件经历的转换越多,它就变得越结构化,并且越接近你真正关心的指标,这使得它更容易监控。我们将在以下部分中详细介绍每个工件。

工件经历的转变越多,其变化就越有可能是由其中一次转变中的错误导致的

8.2 监控与准确度相关的指标

如果您的系统收到任何类型的用户反馈,以了解其所做的预测(点击、隐藏、购买、点赞、点踩、收藏、收藏、分享等),你绝对应该记录并跟踪它。一些反馈可用于推断自然标签,然后可用于计算模型的准确度相关指标。准确度相关指标是帮助你确定模型性能是否下降的最直接指标。

即使反馈不能直接用于推断自然标签,也可以用于检测 ML 模型性能的变化。例如,当你构建一个系统来向用户推荐接下来在 YouTube 上观看哪些视频时,你不仅要跟踪用户是否点击了推荐的视频(点击率),还要跟踪用户在该视频上花费的时间以及他们是否看完了该视频(完成率)。如果随着时间的推移,点击率保持不变,但完成率下降,则可能意味着你的推荐系统正在变差。

8.3 监控预测

预测是监控的最常见工件。如果是回归任务,则每个预测都是一个连续值(例如房屋的预测价格),如果是分类任务,则每个预测都是与预测类别相对应的离散值。由于每个预测通常只是一个数字(低维度),因此预测很容易可视化,并且它们的汇总统计数据很容易计算和解释。

你可以监控预测的分布变化。由于预测是低维的,因此计算双样本测试以检测预测分布是否发生了变化也更容易。预测分布变化也是输入分布变化的代理。假设从输入映射到输出的函数没有改变 - 模型的权重和偏差没有改变 - 那么预测分布的变化通常表示底层输入分布发生了变化。

你还可以监控预测是否发生任何奇怪的事情,例如连续预测异常数量的 False。预测和基本事实标签之间可能会有很长的延迟。与准确度相关的指标的变化可能在几天或几周内都不会变得明显,而 10 分钟内预测全为错误的模型可以立即被检测到。

8.4 监控功能

行业中的 ML 监控解决方案专注于跟踪功能(features)的变化,包括模型用作输入的功能以及从原始输入到最终功能的中间转换。功能监控之所以具有吸引力,是因为与原始输入数据相比,功能遵循预定义的模式,结构良好。

功能监控的第一步是功能验证:确保你的功能遵循预期的模式。如果违反了这些预期,则底层分布可能会发生变化。例如,以下是你可以针对给定功能检查的一些内容:

  • 功能的最小值、最大值或中值是否在可接受范围内
  • 功能的值是否满足正则表达式格式
  • 功能的所有值是否属于预定义集
  • 功能的值是否始终大于另一个功能的值

由于功能通常组织成表格 - 每列代表一个功能,每行代表一个数据样本 - 功能验证也称为表测试(table testing)或表验证(table validation)。有些人称它们为数据的单元测试。有许多开源库可帮助您进行基本的功能验证,其中最常见的两个是 Great Expectations 和 AWS 的 Deequ。下图显示了 Great Expectations 的一些内置功能验证函数以及如何使用它们的示例:

Great Expectations 的一些内置功能验证函数及其使用示例

除了基本的特征验证之外,你还可以使用双样本测试来检测特征或特征集的底层分布是否发生了变化。由于特征或特征集可能具有高维性,因此你可能需要在对它们进行测试之前降低其维度,这可能会降低测试的效率。

进行特征监控时有四个主要问题。首先,一家公司可能有数百个模型在生产中,每个模型使用数百甚至数千个特征。即使是每小时计算所有这些特征的汇总统计数据这样简单的事情也可能代价高昂,不仅在所需的计算方面,而且在内存使用方面。跟踪太多指标(即不断计算太多指标)也会降低系统速度,并增加用户体验到的延迟以及检测系统异常所需的时间。

其次,虽然跟踪特征对于调试目的很有用,但它对于检测模型性能下降并不是很有用。理论上,小的分布变化可能会导致灾难性的故障,但在实践中,单个特征的微小变化可能根本不会损害模型的性能。特征分布一直在变化,而且大多数变化都是良性的。如果你想在某个特征似乎发生漂移时收到警报,你可能很快就会被警报淹没,并意识到大多数警报都是误报。这可能会导致一种称为“警报疲劳”的现象,即监控团队不再关注警报,因为它们太频繁了。功能监控的问题变成了试图决定哪些功能变化是关键的,哪些不是。

第三个问题是,特征提取通常分多个步骤完成(例如填充缺失值和标准化),使用多个库(例如 Pandas、Spark),在多个服务(例如 Kubernetes 或 Snowflake)上进行。您可能将关系数据库作为特征提取过程的输入,将 NumPy 数组作为输出。即使您检测到特征中的有害变化,也可能无法检测出这种变化是由底层输入分布的变化引起的,还是由多个处理步骤之一中的错误引起的。

第四个问题是,特征遵循的模式可能会随时间而变化。如果你没有办法对模式进行版本控制并将每个特征映射到其预期模式,则报告警报的原因可能是由于模式不匹配而不是数据发生变化。

8.5 监控原始输入

如果我们将监控提前一步,转向原始输入会怎样?原始输入数据可能并不容易监控,因为它们可能来自多个来源,格式各异,遵循多种结构。如今,许多 ML 工作流的设置方式也使得 ML 工程师无法直接访问原始输入数据,因为原始输入数据通常由数据平台团队管理,该团队处理数据并将其移动到数据仓库等位置,而 ML 工程师只能从已经部分处理过数据的数据仓库中查询数据。

到目前为止,我们已经讨论了要监控的不同类型的指标,从通常用于软件系统的操作指标到可帮助你跟踪 ML 模型运行状况的 ML 特定指标。在下一节中,我们将讨论可用于帮助监控指标的工具箱。

9、监控工具箱

测量、跟踪和理解复杂系统的指标并非易事,工程师依靠一套工具来帮助他们完成这项工作。业界通常将指标(metrics)、日志(logs)和跟踪(traces)称为监控的三大支柱。然而,我发现它们的区别很模糊。它们似乎是从开发监控系统的人员的角度生成的:跟踪是日志的一种形式,指标可以从日志中计算出来。在本节中,我想从监控系统用户的角度重点介绍这套工具:日志、仪表板和警报。

9.1 日志

传统软件系统依靠日志(logs)来记录运行时产生的事件。事件(events)是系统开发人员可能感兴趣的任何事物,无论是在事件发生时还是稍后出于调试和分析目的。事件的示例包括容器启动时、占用的内存量、函数调用时、该函数完成运行时、此函数调用的其他函数、该函数的输入和输出等。此外,不要忘记记录崩溃、堆栈跟踪、错误代码等。用 Etsy 的 Ian Malpass 的话来说,“如果它移动,我们会跟踪它。”他们还会跟踪尚未更改的内容,以防它们以后移动。

日志的数量可以非常迅速地增长。例如,早在 2019 年,约会应用程序 Badoo 每天处理 200 亿个事件。当出现问题时,你需要查询日志以查找导致问题的事件序列,这个过程就像大海捞针。

在软件部署的早期,应用程序可能是一个单一的服务。当发生某事时,你知道它发生在哪里。但如今,系统可能由许多不同的组件组成:容器、调度程序、微服务、多语言持久性、网格路由、临时自动扩展实例、无服务器、lambda 函数。请求从发送到收到响应可能要经过 20-30 次跳转。困难的部分可能不在于检测某事发生的时间,而在于问题出在哪里45。

当我们记录事件时,我们希望尽可能方便我们稍后找到它。微服务架构的这种做法称为分布式跟踪(distributed tracing)。我们希望为每个进程提供一个唯一的 ID,这样当出现问题时,错误消息(希望)将包含该 ID。这使我们能够搜索与其关联的日志消息。我们还希望记录每个事件所需的所有元数据:事件发生的时间、发生的服务、调用的函数、与流程关联的用户(如果有)等。

由于日志变得如此庞大且难以管理,因此已经开发了许多工具来帮助公司管理和分析日志。据估计,2021 年日志管理市场价值为 23 亿美元,预计到 2026 年将增长到 41 亿美元。

手动分析数十亿个已记录的事件是徒劳的,因此许多公司使用机器学习来分析日志。异常检测是机器学习在日志分析中的用例:检测系统中的异常事件。更复杂的模型甚至可以根据优先级对每个事件进行分类,例如正常、异常、异常、错误和致命事件。

机器学习在日志分析中的另一个用例是,当服务发生故障时,了解相关服务受到影响的概率可能会有所帮助。当系统受到网络攻击时,这可能特别有用。

许多公司以批处理方式处理日志。在这种情况下,你收集大量日志,然后定期使用 SQL 查询它们以查找特定事件,或使用批处理(如 Spark 或 Hadoop 或 Hive 集群)处理它们。这使得日志处理变得高效,因为你可以利用分布式和 mapreduce 进程来提高处理吞吐量。但是,由于你定期处理日志,因此只能定期发现问题。

为了在日志发生异常时立即发现它们,你需要在记录事件后立即处理它们。这使得日志处理成为流处理问题。你可以使用 Kafka 或 AWS Kinesis 等实时传输来传输记录的事件。要实时搜索具有特定特征的事件,你可以利用流式 SQL 引擎,如 KSQL 或 Flink SQL。

9.2 仪表板

一张图片胜过千言万语。一系列数字可能对你毫无意义,但在图表上可视化它们可能会揭示这些数字之间的关系。可视化指标的仪表板(dashboards)对于监控至关重要。

仪表板的另一个用途是让非工程师能够进行监控。监控不仅适用于系统开发人员,也适用于非工程利益相关者,包括产品经理和业务开发人员。

尽管图表可以帮助理解指标,但仅靠它们还不够。你仍然需要经验和统计知识。请考虑下面的两个图表。从这些图表中唯一明显的是损失波动很大。如果这两个图表中的任何一个存在分布漂移,我都看不出来。绘制图表来绘制一条摆动线比理解这条摆动线的含义更容易。

图表对于理解数字很有用,但还不够

过多的指标和仪表板也可能适得其反,这种现象称为仪表板腐烂(dashboard rot)。选择正确的指标或抽象出较低级别的指标来计算更适合你的特定任务的高级信号非常重要。

9.3 警报

当我们的监控系统检测到可疑情况时,有必要向相关人员发出警报。警报由以下三个部分组成。

  • 描述警报条件的警报策略(alert policy)。你可能希望在指标超出阈值时(可选在一定持续时间内)创建警报。例如,你可能希望在模型的准确率低于 90% 时收到通知,或者在 HTTP 响应延迟高于一秒至少十分钟时收到通知。
  • 描述在满足条件时应通知谁的通知渠道(notification channels)。警报将显示在您使用的监控服务中,例如 AWS Cloudwatch 或 GCP Cloud Monitoring,但你也希望在负责人不使用这些监控服务时联系他们。例如,你可以将警报配置为发送到电子邮件地址(例如 mlops-monitoring@claypot.ai),发布到 Slack 频道(例如 #mlops-monitoring)或 PagerDuty。
  • 警报描述(alert description),帮助收到警报的人了解发生了什么。描述应尽可能详细,例如:
## Recommender model accuracy below 90%${timestamp}: This alert originated from the service ${service-name}

根据警报的受众,通常需要通过提供缓解说明或运行手册、可能有助于处理警报的常规程序和操作的汇编来使警报可操作。

正如本讲座前面所讨论的,警报疲劳(alert fatigue)是一种真实存在的现象。警报疲劳会让人士气低落——没有人喜欢半夜因为职责之外的事情被叫醒。它也很危险——接触琐碎的警报会使人们对关键警报变得麻木。设置有意义的条件很重要,这样只发出关键警报。

10、可观察性

自 2010 年代中期以来,业界开始采用可观察性(observability)一词,而不是监控。监控不会对系统的内部状态与其输出之间的关系做出任何假设。你可以监控系统的外部输出,以确定系统内部何时出现问题——外部输出并不能保证能帮助你找出问题所在。

在软件部署的早期,软件系统非常简单,监控外部输出就足以进行软件维护。系统过去只由几个组件组成,团队过去可以控制整个代码库。如果出现问题,可以对系统进行更改以测试并找出问题所在。

然而,在过去十年中,软件系统变得复杂得多。今天,软件系统由许多组件组成。其中许多组件是由其他公司运行的服务——提示所有云原生服务——这意味着团队甚至无法控制系统所有组件的内部。当出现问题时,团队不能再简单地拆开他们的系统来找出问题所在。团队必须依靠系统的外部输出来了解内部情况。

可观察性是用于解决这一挑战的一个术语。它源自控制理论,指的是“使用运行时从系统收集的[输出]更好地了解软件的复杂行为。”

注意:运行时收集的系统输出也称为遥测(telemetry)。遥测是过去十年软件监控行业出现的另一个术语。“遥测”一词来自希腊语词根“tele”(表示“远程”)和“metron”(表示“测量”)。因此,遥测基本上意味着“远程测量”。在监控环境中,它指的是从远程组件(例如云服务或运行在客户设备上的应用程序)收集的日志和指标。

换句话说,可观察性比传统监控做出了更强的假设:系统的内部状态可以从对其外部输出的了解中推断出来。内部状态可以是当前状态,例如“当前的 GPU 利用率”,也可以是历史状态,例如“过去一天的平均 GPU 利用率”。

当可观察系统出现问题时,我们应该能够通过查看系统的日志和指标来找出问题所在,而无需向系统发送新代码。可观察性是关于以某种方式对系统进行检测,以确保收集和分析有关系统运行时的足够信息。

监控以指标为中心,指标通常是汇总的。可观察性允许更细粒度的指标,这样你不仅可以知道模型性能何时下降,还可以知道模型因哪些类型的输入、哪些用户子组或什么时间段而下降。例如,你应该能够查询日志以获取以下问题的答案:“显示过去一小时内模型 A 返回错误预测的所有用户,按邮政编码分组”或“显示过去 10 分钟内的异常请求”或“显示此输入通过系统的所有中间输出”。要实现这一点,您需要使用标签和其他标识关键字记录系统的输出,以便稍后根据数据的不同维度对这些输出进行切片和切块。

在机器学习中,可观察性包含可解释性(interpretability)。可解释性有助于我们理解机器学习模型的工作原理,而可观察性有助于我们理解整个机器学习系统(包括机器学习模型)的工作原理。例如,当模型的性能在过去一个小时内下降时,能够解释哪个特征对过去一个小时内做出的所有错误预测贡献最大,将有助于找出系统出了什么问题以及如何修复它。

在本节中,我们讨论了监控的多个方面,从要监控哪些数据、要跟踪哪些指标,到用于监控和可观察性的不同工具。尽管监控是一个强大的概念,但它本质上是被动的。你等待转变发生以检测到它。监控有助于发现问题而无需纠正它。在下一节中,我们将介绍持续学习(continual learning),这是一种可以主动帮助你更新模型以应对漂移的范例。


原文链接:数据分布漂移及对策 - BimAnt

相关文章:

机器学习:数据分布的漂移问题及应对方案

首先,让我们从一位高管告诉我的一个故事开始,很多读者可能对此感同身受。 大约两年前,他的公司聘请了一家咨询公司开发一个机器学习模型,帮助他们预测下周每种食品杂货需要多少,以便他们可以相应地补货。这家咨询公司…...

公链常用的共识算法

1. 工作量证明(Proof of Work, PoW) 工作原理:要求节点(矿工)解决一个数学难题,这个过程称为挖矿。第一个解决难题的矿工将有权添加一个新的区块到区块链上,并获得一定数量的加密货币作为奖励。…...

详解 Flink Table API 和 Flink SQL 之函数

一、系统内置函数 1. 比较函数 API函数表达式示例Table API&#xff0c;>&#xff0c;<&#xff0c;!&#xff0c;>&#xff0c;<id1001&#xff0c;age>18SQL&#xff0c;>&#xff0c;<&#xff0c;!&#xff0c;>&#xff0c;<id‘1001’&…...

rsa加签验签C#和js以及java互通

js实现rsa加签验签 https://github.com/kjur/jsrsasign 11.1.0版本 解压选择需要的版本&#xff0c;这里选择all版本了 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>JS RSA加签验签</title&g…...

C语言中数组和指针的关系

在C语言中&#xff0c;数组和指针之间存在着密切的关系&#xff0c;尽管它们在概念上是不同的。以下是关于C语言中数组和指针关系的一些要点&#xff1a; 数组名作为指针&#xff1a; 在大多数情况下&#xff0c;数组名在表达式中会被当作指向其第一个元素的指针。例如&#x…...

idea 新建一个 JSP(JavaServer Pages)项目

环境设置&#xff1a; 确保你的开发环境中已经安装了 Java 开发工具包&#xff08;JDK&#xff09;和一个 Java Web 开发的集成开发环境&#xff08;IDE&#xff09;&#xff0c;比如 Eclipse、IntelliJ IDEA 或者 NetBeans。你还需要一个 Web 服务器&#xff0c;比如 Apache T…...

【名词解释】Unity中的表格布局组件及其使用示例

Unity中的表格布局组件通常指的是GridLayoutGroup&#xff0c;这是一个在Unity的UI系统中用来布局子对象的组件。它可以帮助开发者将UI元素按照网格的形式进行排列&#xff0c;非常适合创建表格、网格视图等布局。 名词解释&#xff1a; GridLayoutGroup&#xff1a;Unity UI…...

判断当前设备为移动端自适应 平板和pc端为375移动端样式

在libs的setRem.js中&#xff1a; let html document.querySelector("html"); function setRem() {let ui_w 375;let cl_w document.documentElement.clientWidth || document.body.clientWidth;cl_w > 750 ? cl_w 375 : "";html.style.fontSize …...

Science Advances|用于胃部pH监测和早期胃漏检测的生物可吸收无线无源柔性传感器(健康监测/柔性传感/柔性电子)

2024年4月19日,美国西北大学 John A. Rogers和中国科学技术大学吕頔(Di Lu)团队,在《Science Advances》上发布了一篇题为“Bioresorbable, wireless, passive sensors for continuous pH measurements and early detection of gastric leakage”的论文。论文内容如下: 一、…...

C# 使用 webview2 嵌入网页

需求&#xff1a;C#客户端程序, 窗口里嵌入一个web网页&#xff0c;可通过URL跳转的那种。并且&#xff0c;需要将登录的身份验证信息&#xff08;token&#xff09;设置到请求头里。 核心代码如下&#xff1a; // 打开按钮的点击事件 private void openBtn_Click(object sen…...

公司面试题总结(五)

25.谈一谈箭头函数与普通函数的区别&#xff0c;箭头函数主要解决什么问题&#xff1f; 箭头函数与普通函数的区别&#xff1a; ⚫ 语法简洁性&#xff1a; ◼ 箭头函数使用>符号定义&#xff0c;省略了 function 关键字&#xff0c;使得语法更为紧凑。 ◼ 对于单行函…...

Flutter笔记:关于WebView插件的用法(上)

Flutter笔记 关于WebView插件的用法&#xff08;上&#xff09; - 文章信息 - Author: 李俊才 (jcLee95) Visit me at CSDN: https://jclee95.blog.csdn.netMy WebSite&#xff1a;http://thispage.tech/Email: 291148484163.com. Shenzhen ChinaAddress of this article:htt…...

计算机毕业设计Python+Django农产品推荐系统 农产品爬虫 农产品商城 农产品大数据 农产品数据分析可视化 PySpark Hadoop Hive

课题研究的意义&#xff0c;国内外研究现状、水平和发展趋势 研究意义21世纪是一个信息爆炸的时代&#xff0c;人们在日常生活中可接触到的信息量非常之巨大。推荐系统逐步发展&#xff0c;其中又以个性化推荐系统最为瞩目。个性化推荐系统的核心在于个性化推荐算法&#xff0c…...

phpcms仿蚁乐购淘宝客网站模板

phpcms仿蚁乐购网站模板&#xff0c;淘宝客行业模板免费下载&#xff0c;该模板网站很容易吸引访客点击&#xff0c;提升ip流量和pv是非常有利的。本套模板采用现在非常流行的全屏自适应布局设计&#xff0c;且栏目列表以简洁&#xff0c;非常时尚大气。页面根据分辨率大小而自…...

leetcode695 岛屿的最大面积

题目 给你一个大小为 m x n 的二进制矩阵 grid 。 岛屿 是由一些相邻的 1 (代表土地) 构成的组合&#xff0c;这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0&#xff08;代表水&#xff09;包围着。 岛屿的面积是岛上值…...

小程序无法调用服务端问题排查

1、问题描述 突然有一天线上的小程序不能登录&#xff0c;经查小程序无法调用。经查无法小程序页面无法调用后台服务。 2、排查过程 由于无法登录小程序发布服务器&#xff0c;无法测试小程序前端服务器到服务端网络&#xff0c;并且小程序无法看到日志。所以就得从服务端和网…...

Linux:多线程的操作

多线程操作 进程与线程线程的创建 create_pthread创建线程池给线程传入对象的指针 线程等待 pthread_join退出线程 pthread_exit线程等待参数 retval 与 线程退出参数 retval 线程中断 pthread_cancel获取线程编号 pthread_self线程分离 pthread_detach 进程与线程 进程是资源…...

kunpeng的aarch64架构cpu、openeuler系统、昇腾服务器适配文档转换功能(doc转docx、ppt转pptx)

一、安装flatpak sudo yum install flatpak flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo二、安装libreoffice flatpak install flathub org.libreoffice.LibreOffice三、使用 对于使用 flatpak 安装的 LibreOffice,不需要手…...

unity 打包PC安装包中常见文件的功能

目录 前言 一、打包好的文件 二、常用文件 1.文件夹XXX_Data 2.文件夹MonoBleedingEdge 3.文件夹XXX_Data内部 三、文件的应用 1.如果你替换了一个图片 2.如果你新增了或减少了图片和资源 3.场景中有变动 4.resources代码加载的资源改了 5.如果你代码替换了 四、作…...

【Ardiuno】实验使用ESP32单片机实现高级web服务器暂时动态图表功能(图文)

接下来&#xff0c;我们继续实验示例代码中的Wifi“高级web服务器”&#xff0c;配置相关的无线密码后&#xff0c;开始实验 #include <WiFi.h> #include <WiFiClient.h> #include <WebServer.h> #include <ESPmDNS.h>const char *ssid "XIAOFE…...

深入浅出服务网格(Service Mesh):现代微服务架构的护航者

什么是服务网格&#xff1f; 服务网格是一种专用于处理微服务间通信的基础设施层&#xff0c;通常以轻量级代理&#xff08;sidecar&#xff09;的形式部署在每个服务实例旁边。它主要负责以下几项任务&#xff1a; 服务发现&#xff1a;自动检测和注册服务实例&#xff0c;使…...

node调试

vscode安装插件&#xff1a;JavaScript Debugger (Nightly) 点击后生成一个launch.json文件 打断点&#xff0c;并发送一个请求来执行代码到断点处 按右上的向下箭头&#xff0c;进入源码&#xff0c;进行查看&#xff0c;左边查看变量等值...

docker拉取镜像失败超时的解决方法,docker配置国内镜像源

更换国内源 创建或修改 /etc/docker/daemon.json 文件 安装docker后一般只有 /etc/docker 这个目录 下面并没有 daemon.json 文件 我们直接创建 &#xff1a; vim /etc/docker/daemon.json {"registry-mirrors" : ["https://registry.docker-cn.com"…...

建造气膜结构体育馆需要注意的事项—轻空间

气膜结构体育馆以其快速建造、低成本、灵活性高等优势&#xff0c;越来越受到各类运动场所的青睐。气膜结构利用空气压力支撑膜材&#xff0c;从而形成自持结构&#xff0c;无需传统的钢筋混凝土框架。这类建筑适用于各种气候条件&#xff0c;且可根据需要快速搭建和拆卸。然而…...

使用脚手架创建vue2项目(关闭eslint语法检查 、运行项目时自动打开网址、src文件夹简写方法)

使用脚手架创建vue2项目会默认安装的插件&#xff08;eslint) 这个插件是检查语法的。 假设我们在main.js中定义了一个变量&#xff0c;没有使用 eslint 就会检测出错误 &#xff08;事实是我们并没有写错而是eslint 给我们判断是错的&#xff0c;所以这样会很麻烦&#xff…...

谷粒商城实战(036 k8s集群学习2-集群的安装)

Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强 总时长 104:45:00 共408P 此文章包含第343p-第p345的内容 k8s 集群安装 kubectl --》命令行操作 要进入服务器 而且对一些不懂代码的产品经理和运维人员不太友好 所以我们使用可视化…...

复旦微FMQL20SM全国产ARM+FPGA核心板,替代xilinx ZYNQ7020系列

FMQL20SM核心板一款全国产工业核心板。基于复旦微FMQL20S400M四核ARM Cortex-A7&#xff08;PS端&#xff09; FPGA可编程逻辑资源&#xff08;PL端&#xff09;异构多核SoC处理器设计的全国产工业核心板&#xff0c;PS端主频高达1GHz。 核心板简介 FMQL20SM核心板是一款全国…...

NPM常见问题

文章目录 NPM常见问题1. 使用淘宝源安装包出错2. listen EADDRINUSE 服务端口被占用报错3. npm start 启动后过一会崩溃结束&#xff1a;内存溢出4. npm install的时候使用特定的源安装5. npm安装指定版本、最新版本6. npm ERR! cb() never called! 解决7. Unable to authentic…...

二开版视频CMS完整运营源码/新版漂亮APP手机模板/集成员分销功能等

一个二开的影视CMS&#xff0c;直接上传源码至网站根目录&#xff0c;访问网站域名即可安装。 测试环境&#xff1a;Nginx 1.20.1—MySQL 5.6.50–PHP-7.2&#xff08;安装拓展/fileinfo&#xff09; 上传源码&#xff0c;访问域名直接安装 后台地址&#xff1a;域名/MDadmi…...

JavaScript的数组排序

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…...

学生做爰网站/资源网站优化排名优化

很久没有更新博客了&#xff0c;主要是《线索》的开发&#xff0c;一个小小小的文字游戏&#xff0c;但对于我来说依旧是很艰难的。每天利用下班后的两三个小时&#xff0c;一周五个晚上&#xff0c;持续了一个半月&#xff0c;今天终于将《线索》提交审核了&#xff0c;虽然还…...

利于优化的网站/谷歌在线搜索

音视频实践学习 android全平台编译ffmpeg以及x264与fdk-aac实践ubuntu下使用nginx和nginx-rtmp-module配置直播推流服务器android全平台编译ffmpeg合并为单个库实践android-studio使用cmake编译ffmpeg实践android全平台编译ffmpeg视频解码器实践android全平台编译ffmpeg支持命…...

商城网站如何建设/小说百度风云榜

本故事纯属改编 如有共鸣 实属意外-说到“家”&#xff0c;一下想起了小时候学的儿歌&#xff1a;“小毛虫的摇篮是树叶&#xff0c;住在花瓣上的是蝴蝶……我最幸福了&#xff0c;一生下来爸爸妈妈就准备好了家&#xff0c;让我安安稳稳地在家里长大。”从那时起&#xff0c;我…...

广告传媒公司名字/网站优化外包找谁

1.比赛结果 2.比赛整体感觉 初赛的题目是写一个代理实现高性能的协议解析和转发&#xff0c;复赛是是实现一个单机的100g的mq存储。 题目都和io有关&#xff0c;自己实际在比赛过程中&#xff0c;实现了一套能跑的方案后&#xff0c;后续优化的效果不明显&#xff0c;例如 初赛…...

电子书网站 跟我学做家常菜800/河北网站seo外包

概念&#xff1a; 回溯法采用深搜剪枝来搜索生成树&#xff1a; 步骤&#xff1a; 1. 假设规定左叉标1&#xff08;代表选择该物品装入背包&#xff09;&#xff0c;右叉标0&#xff08;代表不选择该物品装入背包&#xff09;。给定示例输入&#xff1a; 背包容量c10 物品…...

自助建站 源码/天津seo关键词排名优化

关于network partition网络设备故障导致的网络分裂。比如&#xff0c;存在A\B\C\D\E五个节点&#xff0c;A\B处于同一子网&#xff0c;B\C\D处于另外一子网&#xff0c;中间通过交换机相连。若两个子网间的交换机故障了即发生了网络分区&#xff0c;A\B和C\D\E便不能通讯。某些…...