NeptuneAI-博客中文翻译-六-
NeptuneAI 博客中文翻译(六)
模型部署挑战:来自 6 ML 工程师的 6 堂课
部署机器学习模型很难!如果你不相信我,去问任何一个被要求将他们的模型投入生产的 ML 工程师或数据团队。为了进一步支持这一说法, Algorithima 的“ 2021 年企业 ML 状态”报告称,组织部署机器学习模型所需的时间正在增加,64%的组织需要一个月或更长时间。同一份报告还指出,38%的组织将超过 50%的数据科学家时间用于将机器学习模型部署到生产中,并且随着规模的扩大,情况只会变得更糟。
由于 MLOps 仍然是一个新兴领域,很难找到既定的最佳实践和模型部署示例来实施机器学习解决方案,因为问题的解决方案可能会因以下因素而异:
-
1 业务用例的类型
-
2 使用的技术
-
3 涉及的人才
-
4 组织规模和结构
-
5 和可用资源
不管您的机器学习模型部署管道如何,在本文中,您将了解许多 ML 工程师及其团队所面临的模型部署挑战,以及他们为应对这些挑战而采用的变通方法。本文的目的是让您从不同行业、组织规模、不同用例的角度来看待这些挑战,如果您在部署场景中面临类似问题,希望这可以成为您的一个良好起点。
注意:这些挑战在发布前已经得到前述工程师的批准和审核。如果你有任何想要解决的问题,请随时通过 LinkedIn 联系我。
事不宜迟,ML 工程师告诉我们关于模型部署的 6 个难点:
挑战 1:为机器学习解决方案选择正确的生产需求
组织: 网飞
团队规模:没有专门的 ML 团队
行业:媒体和娱乐
用例
网飞内容推荐问题是机器学习的一个众所周知的用例。这里的业务问题是:如何为用户提供个性化的、准确的和按需的内容推荐?反过来,他们又如何获得推荐内容的优质流媒体体验?
感谢一位来自网飞的前软件工程师(他不愿透露姓名)在这篇文章发表前给了我一次采访和审阅的机会。
挑战
网飞内容推荐问题
对于网飞的工程团队来说,部署推荐服务是一项艰巨的挑战。内容推荐服务提出了一些有趣的挑战,其中为用户和下游服务提供高度可用和个性化的推荐是主要的挑战。正如一位前网飞工程师指出的:
"流和推荐的业务目标是,每次任何人登录网飞,我们都需要能够提供推荐。因此,生成推荐的服务器的可用性必须非常高。
Ex-Software Engineer at Netflix
当用户想要观看内容时,提供点播推荐也直接影响内容的可用性:
“假设我向你推荐《纸牌屋》,作为你需要观看的节目,如果你最终点击并播放了该节目,那么我们还需要保证我们能够以非常可靠的方式向你提供流媒体。因此,我们无法将所有这些内容从我们的数据中心传输到您的设备,因为如果我们这样做,网飞运营所需的带宽将会摧毁许多国家的互联网基础设施。”
Ex-Software Engineer at Netflix
例如,当你流媒体播放你推荐的节目时,为了确保一个质量的流媒体体验,网飞不得不从成千上万受欢迎的内容中选择推荐的标题,这些内容被主动缓存在他们由成千上万开放连接设备 (OCAs)组成的全球网络中。这有助于确保推荐的标题对于观众来说也是高度可用的,因为如果它们不能无缝地流式传输,那么提供点播推荐又有什么用呢!
推荐服务将需要以高精度容易地预测他们的用户将观看什么以及他们将在一天中的什么时间观看,以便他们可以利用非高峰带宽在这些可配置的时间窗口期间将大多数内容更新下载到他们的 OCA。你可以在本公司博客中了解更多关于网飞 Open Connect 技术的信息。
因此,面临的挑战是在部署他们的建议模型之前选择正确的生产要求,以确保:
- 推荐服务是高度可用的,
- 向用户提供新鲜的、个性化的推荐,
- 推荐的标题已准备好从 OCA 传输到用户的设备。
解决办法
为业务目标和工程目标选择最佳生产要求
团队必须选择一个对工程和商业问题都最优的生产需求。因为推荐不必为每个用户每分钟或每一小时改变,因为它们不会实时改变,所以模型评分可以离线进行,并且在用户登录到他们的设备后提供:
“在生成推荐方面,网飞所做的是离线训练他们的推荐模型,然后部署这些模型,为每一个离线消费者生成一组推荐。然后他们会将这些生成的推荐存储在数据库中。”
Ex-Software Engineer at Netflix
这解决了工程问题,因为:
- 大规模推荐是为每个用户离线评分和预先计算的。
- 它们也不依赖于为每个用户大规模运行推荐服务的高可用性服务器——这将非常昂贵——而是依赖于存储在数据库中的结果。
这使得网飞能够以更高效的方式向全球用户群提供推荐。
对于商业问题,当用户登录到他们的设备时,可以向他们显示推荐的标题。由于标题可能已经为用户缓存在 Open Connect CDN 中,一旦用户点击“播放”,推荐的标题就准备好被流式传输。这里需要注意的一点是,如果推荐在几个小时后稍微过时,那么与加载缓慢或过时数天、数周或数月的推荐相比,用户体验可能不会受到影响。
在高可用性方面,网飞规模的在线评分或学习将不可避免地导致服务器的延迟问题。这很可能会给基础架构和运营带来压力,进而影响用户体验,进而影响业务。选择一个从工程和商业角度来看都是最佳的生产要求,有助于团队确保解决这一挑战。
挑战 2:简化模型部署和机器学习操作(MLOps)
机构 : 宣传者
团队规模:小团队
行业:公关&传播,媒体情报
感谢 越南阮氏 允许我使用宣传者在 AWS 上发表的 文章。
用例
一种广告预测功能,用于过滤直接从出版社、数千种不同媒体内容(如杂志和报纸)接收的付费广告。这些媒体内容以数字文件的形式流入数据处理管道,该管道从这些来源中提取相关细节,并预测它是否是广告。
Hypefactors dashboard | Source
挑战
在构建 ad-predictor 的第一个版本时,该团队选择在无服务器平台上部署该模型。他们在外部服务上部署了一个独立的 ad predictor 端点,该端点将从数据管道中获取数据并执行无服务器推理。
虽然无服务器部署具有自动扩展实例、按需运行以及提供易于集成的接口等优势,但它也带来了一些众所周知的挑战:
- 将数据管道与预测服务分离,增加操作难度。
- 高网络调用和长启动时间(冷启动问题),导致返回预测结果的高延迟。
- 自动缩放数据管道和预测服务以补偿来自管道的高流量。
“由于网络调用和启动时间,预测具有更高的延迟,从而导致超时和因实例中断导致预测器不可用而产生的问题。我们还必须自动扩展数据管道和预测服务,考虑到不可预测的事件负载,这一点非常重要。”
Hypefactors team
解决办法
“我们对这些挑战的解决方案以结合两个框架的优势为中心: 开放神经网络交换 (ONNX)和深度 Java 库(DJL)。通过 ONNX 和 DJL,我们在渠道中直接部署了新的多语言广告预测模型。这取代了我们的第一个解决方案,即无服务器广告预测器。”
Hypefactors team
为了解决他们在第一个版本中遇到的挑战,他们使用 ONNX 运行时来量化模型,并将其与深度 Java 库 (DJL)一起部署,这与他们基于 Scala 的数据管道兼容。将模型直接部署在管道中确保了模型与管道的耦合,并且可以随着数据管道扩展到流传输的数据量而扩展。
该解决方案还在以下方面帮助他们改进了系统:
- 该模型不再是一个独立的外部预测服务;它现在与数据管道相结合。这确保了延迟的减少并且推理是实时进行的,不需要启动另一个实例或将数据从管道移动到另一个服务。
- 它帮助简化了他们的测试套件,带来了更多的测试稳定性。
- 它允许团队将其他机器学习模型与管道集成,进一步改善数据处理管道。
- 它简化了模型管理,帮助团队轻松地发现、跟踪和重现推理错误。
要从 Hypefactors 团队了解这个特定用例的解决方案的更多信息,您可以查看他们在 AWS 博客上发布的这篇文章。
挑战 3:为机器学习操作导航组织结构
组织 : 阿科拉
团队规模 : 4 名数据科学家和 3 名数据分析师
行业:金融科技——市场情报
感谢 拉斯洛·斯拉格纳 在本节选发表前给予我采访和审阅的机会。
用例
一个处理新兴市场新闻的系统,为交易者、资产管理者和对冲基金管理者提供情报。
Arkera.ai LinkedIn cover image | Source
挑战
“我看到的最大挑战是,生产环境通常属于软件工程师或 DevOps 工程师。机器学习工程师和软件工程师之间需要就他们的 ML 模型如何在 DevOps 或软件工程团队的监督下投入生产进行某种交流。必须保证你的代码或模型能够正确运行,你需要找出最好的方法。”
Laszlo Sragner, ex-Head of Data Science at Arkera
数据科学家面临的一个常见挑战是,编写生产代码与开发环境中的代码有很大不同。当他们为实验编写代码并提出模型时,移交过程很棘手,因为将模型或管道代码部署到生产环境会带来不同的挑战。
如果工程团队和 ML 团队不能就模型或管道代码在部署到生产时不会失败达成一致,这很可能会导致可能导致整个应用程序错误的失败模式。故障模式可能是:
- 系统故障:由于加载或评分时间慢、异常错误、非统计错误等错误导致生产系统崩溃。
- 统计失败:或“无声”失败,即模型持续输出错误的预测。
这两种故障模式中的一种或两种都需要由两个团队来解决,但是在解决之前,团队需要知道他们负责什么。
解决办法
模型检验
为了解决 ML 和软件工程团队之间的信任挑战,需要有一种方法让每个人都可以确保交付的模型能够按预期工作。到那时为止,两个团队能够达成一致的唯一方法是在部署之前测试模型,使模型能够按预期工作。
“我们是如何解决这个(挑战)的?这个用例是大约 3 年前的事了,比 【谢顿】 或者任何一种部署工具都要早得多,所以我们需要竭尽所能。我们所做的是将模型资产存储在 protobufs 中,并将它们发送给工程团队,他们可以在那里对模型进行测试,并将其部署到生产中。”
Laszlo Sragner, ex-Head of Data Science at Arkera
软件工程团队必须测试该模型,以确保它按照要求输出结果,并与生产中的其他服务兼容。他们会向模型发送请求,如果服务失败,他们会向数据团队提供一份报告,说明他们向模型传递了什么类型的输入。
他们当时使用的技术是 TensorFlow 、 TensorFlow Serving 和 Flask 为基础的微服务 directtensor flow Serving实例。Laszlo 承认,如果他要再次解决这个部署挑战,他会使用 FastAPI 并将模型直接加载到 Docker 容器中,或者只是使用供应商创建的产品。
FastAPI + Docker deployment tool | Source: Author
创建有界上下文
Laszlo 团队采用的另一种方法是创建一个“有界上下文”,为 ML 和软件工程团队形成领域边界。这使得机器学习团队知道他们负责的错误并拥有它们——在这种情况下,模型内发生的一切,即统计错误。软件工程团队负责模型之外的领域。
这有助于团队了解在任何给定的时间点谁负责什么:
- 如果一个错误发生在生产系统中,工程团队追溯到模型,他们会把错误交给 ML 团队。
- 如果需要快速修复错误,工程团队将退回到旧模型(作为应急协议),以给机器学习团队时间来修复模型错误,因为他们无法在生产环境中进行故障排除。
这个用例也是在模型注册中心爆炸之前,所以模型(序列化为 protobuf 文件)被存储在一个 S3 桶中,并作为目录列出。当对模型进行更新时,它是通过一个拉请求来完成的。
在紧急协议的情况下,负责维护模型之外的基础设施的软件工程师将回滚到模型的前一个拉请求,而 ML 团队用最近的拉请求来排查错误。
更新预测服务
如果 ML 团队想要部署一个新的模型,并且它不需要对它的部署方式进行任何改变,那么这个模型将被重新训练,新的模型资产被创建并作为一个单独的模型被上传到 S3 存储桶,并且一个拉取请求与模型目录一起被创建,因此工程团队可以知道有一个更新的模型可以被部署。
挑战 4:模型开发(离线)和部署(在线推断)度量的相关性
组织 : LinkedIn
团队规模:未知
行业:面向商业的社交网络
感谢 斯凯勒·佩恩 在这篇节选发表前给我一次采访和审阅。
用例
推荐匹配是 LinkedIn 的 LinkedIn Jobs 产品中的一项功能,它为用户的公开招聘职位提供候选人推荐,随着时间的推移,这些推荐会根据用户的反馈变得更有针对性。该功能的目标是让用户不必花费时间费力地浏览数百个应用程序,并帮助他们更快地找到合适的人才。
A screenshot from the Recommended Matches feature | Source
挑战
同一模型的离线和在线指标的相关性
Skylar 的团队在部署候选人推荐服务时遇到的一个挑战是在线和离线指标之间的相关性。对于推荐问题,通常很难将模型的离线结果与适当的在线指标联系起来:
“部署模型的一个真正大的挑战是在您的离线和在线指标之间建立关联。搜索和推荐在在线和离线指标之间建立关联已经是一个挑战,因为你有一个很难解决或评估的反事实问题。”
Skylar Payne ex-Staff Software Engineer at LinkedIn
对于像这样的大规模推荐服务,使用离线学习的模型(但使用活动特征进行在线推断)的一个缺点是,在当前搜索会话期间,当招聘人员审查推荐的候选人并提供反馈时,很难将招聘人员的反馈考虑在内。这使得很难用正确的标签在线跟踪模特的表现,即他们不能确定推荐给招聘人员的候选人是否是可行的候选人。
从技术上来说,您可以将这样的挑战归类为训练-服务偏斜挑战,但是这里要注意的关键点是,该团队拥有推荐引擎的部分排序和检索堆栈,他们无法在离线时非常有效地再现,因此训练要部署的健壮模型提出了模型评估挑战。
模型建议的覆盖范围和多样性
团队面临的另一个问题是建议的覆盖面和多样性,这导致了对部署模型的结果进行度量的困难。有许多潜在候选人的数据从未向招聘人员展示过,因此团队无法判断该模型在选择过程中是否有偏差,或者这是基于招聘人员的要求。由于没有对这些候选人进行评分,因此很难跟踪他们的指标并了解部署的模型是否足够健壮。
“挑战的一部分是偏见和产品中事物的呈现方式,因此当你对检索的工作方式进行小调整时,很可能我在重新排序和排序后从检索中获得的新文档集将没有该查询的标签。
这部分是一个稀疏标签的问题。如果你不提前思考如何解决这个问题,这将是一个挑战。在您的模型评估分析中,您可以将自己置于一个糟糕的境地,在那里您不能真正地对您的模型执行健壮的分析。"
Skylar Payne ex-Staff Software Engineer at LinkedIn
解决办法
“归根结底,我们在如何进行评估方面变得更加稳健。我们使用了许多不同的工具…”
Skylar Payne ex-Staff Software Engineer at LinkedIn
该团队试图用几种技术来解决这些挑战:
- 使用反事实评估标准。
- 避免对推荐引擎堆栈的检索层进行更改。
使用反事实评估技术
该团队用来对抗模型选择偏差的技术是反向倾向评分(IPS)技术,旨在根据从在线招聘人员与产品的互动中收集的日志,离线评估候选人排名政策。正如 Skylar 解释的那样:
“我们经常关注和使用的一种技术是反向倾向评分技术。基本上,你可以通过反向倾向评分来消除样本中的一些偏差。这是有帮助的。”
Skylar Payne ex-Staff Software Engineer at LinkedIn
本文作者杨等人。艾尔。根据为反事实评估开发的 IPS 技术,提供了使用无偏见评估者的更多细节。
避免对检索层进行更改
根据 Skylar 的说法,当时的临时解决方案是,他们避免对推荐堆栈中的检索层进行任何可能影响候选人被推荐给招聘人员的更改,从而无法在线跟踪模型结果。正如 Skylar 在下面指出的,一个更好的解决方案可能是构建支持更健壮的工具或帮助测量检索层的变化的工具,但当时,构建这种工具的资源是有限的。
“最终发生的情况是,我们只是尽可能避免对检索层进行更改,因为如果我们进行了更改,它是否会被在线翻译是非常不确定的。
我认为真正的解决方案应该是建立更复杂的工具,比如模拟或分析工具,来衡量恢复阶段的变化。"
Skylar Payne ex-Staff Software Engineer at LinkedIn
挑战 5:模型部署和机器学习操作(MLOps)的工具和基础设施瓶颈
组织:未公开
团队规模:团队 15 人
行业:零售和消费品
感谢 伊曼纽尔·拉吉 在本节选发表前接受我的采访和审阅。
用例
这个用例是一个为零售客户开发的项目,帮助客户使用机器学习以自动化的方式解决问题。当人们提出问题或由维护问题产生问题时,机器学习用于将问题归类到不同的类别,帮助更快地解决问题。
挑战
数据科学家和 ML 工程师之间缺乏标准的开发工具
大多数数据团队在协作时面临的主要挑战之一是团队中人才使用的工具的多样性。如果没有标准工具,每个人都使用他们知道如何最好地使用的工具进行开发,那么统一工作将永远是一个挑战,尤其是在必须部署解决方案的情况下。这是 Emmanuel 的团队在处理这个用例时面临的挑战之一。正如他解释的那样:
“一些数据科学家使用 sklearn 开发模型,一些使用 TensorFlow 和不同的框架进行开发。团队没有采用一个标准框架。”
Emmanuel Raj, Senior Machine Learning Engineer
由于工具使用的差异,并且因为这些工具不具有互操作性,团队很难部署他们的 ML 模型。
模型基础设施瓶颈
团队在模型部署过程中面临的另一个问题是整理模型的运行时依赖性和生产中的内存消耗:
- 在某些情况下,在模型容器化和部署之后,一些包会随着时间而贬值。
- 其他时候,当模型在生产环境中运行时,基础设施不会稳定地工作,因为容器集群经常会耗尽内存,导致团队不时地重新启动集群。
解决办法
对模型使用开放格式
因为让人们学习一个通用工具要困难得多,所以团队需要一个能够:
- 使使用不同框架和库开发的模型具有互操作性,
- 将团队中每个人的努力整合到一个应用程序中,该应用程序可以被部署来解决业务问题。
该团队决定加入流行的开源项目开放神经网络交换(或 ONNX),这是一个机器学习模型的开放标准,允许团队跨不同的 ML 框架和工具共享模型,促进这些工具之间的互操作性。这样,团队很容易使用不同的工具开发模型,但是相同的模型以特定的格式打包,这使得这种模型的部署不那么具有挑战性。正如 Emmanuel 所承认的:
谢天谢地,ONNX 出现了,开放神经网络交换,这帮助我们解决了这个问题。因此,我们会以特定的格式将其序列化,一旦我们有了序列化文件的类似格式,我们就可以将模型容器化并进行部署。”
Emmanuel Raj, Senior Machine Learning Engineer
挑战 6:处理部署前后的模型大小和比例
机构 : 总部
团队规模:小团队
行业:金融科技
感谢 【埃梅卡】鲍里斯 在本节选发表前给予我采访和审阅。
用例
MonoHQ 的交易元数据产品使用机器学习对交易语句进行分类,这些交易语句有助于各种企业客户应用程序,如信贷申请、资产规划/管理、BNPL(立即购买,稍后支付)和支付。数以千计的客户的交易基于叙述被分类成不同的类别。
挑战
模型尺寸
自然语言处理 (NLP)模型以其规模著称——尤其是基于 transformer 的 NLP 模型。埃梅卡面临的挑战是确保他的模型大小满足部署到公司基础架构所需的要求。模型通常加载在内存有限的服务器上,因此它们需要符合一定的大小阈值才能通过部署。
模型可扩展性
埃梅卡在尝试部署他的模型时遇到的另一个问题是,当它与系统中的上游服务集成时,该模型如何扩展以对收到的大量请求进行评分。正如他提到的:
“由于该模型在我们的微服务架构中与其他服务相集成,如果我们有 20,000 个事务,这些事务中的每一个都会被单独处理。当多达 4 个客户查询事务元数据 API 时,我们观察到了严重的延迟问题。这是因为该模型连续处理事务,导致对下游服务的响应速度变慢。
在这种情况下,该模型将为每个客户记录多达 5,000 笔交易,并且这是连续发生的,而不是同时发生的。"
Emeka Boris, Senior Data Scientist at MonoHQ.
解决方法
通过端点访问模型
优化 NLP 模型的大小通常是在模型鲁棒性或准确性(模型的推理效率)和获得更小的模型之间进行权衡的游戏。埃梅卡以不同的方式处理这个问题。他决定最好将模型存储在其集群上,并通过 API 端点使其可访问,以便其他服务可以与之交互,而不是每次请求时都将模型从 S3 加载到服务器。
使用 Kubernetes 集群来扩展模型操作
在撰写本文时,埃梅卡正在考虑采用 Kubernetes 集群来扩展他的模型,以便它们可以同时对请求进行评分,并满足下游服务所需的 SLA 。他计划在这个解决方案中使用完全管理的 Kubernetes 集群,这样就不用担心管理维护集群所需的基础设施。
结论
在本文中,我们了解到 ML 工程师和数据团队面临的模型部署挑战不仅仅是将模型投入生产。它们还包括:
- 思考并选择正确的业务和生产需求,
- 不可忽视的基础设施和运营关注点,
- 组织架构;团队如何参与和构建项目,
- 模型测试,
- 模型和服务的安全性和合规性,
- 以及一大堆其他的问题。
希望这些案例中的一个或多个对您有用,因为您也希望解决在您的组织中部署 ML 模型的挑战。
参考资料和资源
一般
网飞
催眠因子
商务化人际关系网
斯蒂芬·奥拉德勒
开发者倡导者和 MLOps 技术内容创建者。
阅读下一篇
Continuum Industries 案例研究:如何跟踪、监控和可视化 CI/CD 管道
7 分钟阅读| 2021 年 8 月 9 日更新
Continuum Industries 是一家基础设施行业的公司,希望自动化和优化线性基础设施资产的设计,如水管、架空传输线、海底电力线或电信电缆。
其核心产品 Optioneer 允许客户输入工程设计假设和地理空间数据,并且使用进化优化算法来寻找可能的解决方案,以在给定约束的情况下连接 A 点到 B 点。
首席科学家安德烈亚斯·马莱科斯(Andreas Malekos)致力于研究人工智能发动机,他解释道:
“建造像电力线这样的东西是一个巨大的项目,所以你必须在开始之前获得正确的设计。你看到的设计越合理,你就能做出更好的决定。Optioneer 可以在几分钟内为您提供设计资产,而成本只是传统设计方法的一小部分。”
但是,创建和操作 Optioneer 引擎比看起来更具挑战性:
- 目标函数不代表现实
- 有很多土木工程师事先不知道的假设
- 不同的客户给它提出完全不同的问题,算法需要足够健壮来处理这些问题
与其构建完美的解决方案,不如向他们展示一系列有趣的设计选项,以便他们做出明智的决策。
引擎团队利用来自机械工程、电子工程、计算物理、应用数学和软件工程的各种技能来实现这一目标。
问题
无论是否使用人工智能,构建一个成功的软件产品的一个副作用是,人们依赖它工作。当人们依赖您的优化引擎做出价值百万美元的基础设施设计决策时,您需要有一个强大的质量保证(QA)。
正如 Andreas 所指出的,他们必须能够说,他们返回给用户的解决方案是:
- 好,意思是这是一个土木工程师可以看到并同意的结果
- 更正,这意味着计算并返回给最终用户的所有不同工程数量都尽可能准确
除此之外,该团队还在不断改进优化引擎。但要做到这一点,您必须确保这些变化:
- 不要以这样或那样的方式破坏算法
- 实际上,它们不仅改善了一个基础设施问题的结果,还改善了所有问题的结果
基本上,您需要建立适当的验证和测试,但是团队试图解决的问题的性质带来了额外的挑战:
- 您无法自动判断算法输出是否正确。这不像在 ML 中,你已经标记了数据来计算你的评估集的准确度或召回率。
- 您需要一组示例问题,代表算法在生产中需要解决的那类问题的。此外,这些问题需要被版本化,以便尽可能容易地实现可重复性。
可能让您付出巨大代价的 5 个模型部署错误
原文:https://web.archive.org/web/https://neptune.ai/blog/model-deployment-mistakes
在数据科学项目中,模型部署可能是整个生命周期中最关键的和复杂的部分。
运营或任务关键型 ML 需要全面的设计。您必须考虑工件传承和跟踪、避免人为错误的自动部署、测试和质量检查、模型在线时的功能可用性…以及许多其他事情。
在本文中,我们整理了一份通常发生在生命周期最后阶段的常见错误列表。这些更关注软件架构,但在处理推理服务时扮演着非常重要的角色。
错误 1:手动部署您的模型
手动部署推理服务有很大的风险。大多数 ML 服务需要执行多个命令才能部署。假设我们正在部署一个 FastAPI web 服务,它是在线推理的标准。以下是成功部署需要执行的典型步骤:
- 执行测试套件并获得代码覆盖率
- 2 获取 Docker 注册表的凭证
- 3 构建推理服务映像
- 4 调用 Kubernetes 从 Docker 注册中心获取图像并部署服务
想象一下手动执行这些步骤(以及您需要的所有设置)。很有可能发生人为错误——您可能忘记从您的模型注册中心更新模型路径,您可能忘记运行测试,您可能没有首先进入预生产环境就直接部署到生产环境中,等等。
您可以尝试的:自动持续集成和部署
持续集成工具
*Model deployment – CI/CD pipelines I Source *
幸运的是,有各种各样的工具可以用来自动化这些步骤。Github 动作、詹金斯和 Gitlab CI/CD 就是很好的例子。你可以在这篇文章中读到更多关于它们的信息。
这些工具允许您定义基于服务代码库中发生的某些事件触发的工作流。当将一个分支合并到开发中时,您可以部署到集成环境中,当新特性到达主分支时,您可以部署到生产中。
持续部署工具
对于持续部署步骤,有像 ArgoCD 、 Jenkins-X 或 Flux 这样的工具,它们是基于 GitOps 的 Kubernetes pods 部署器(如果你不知道那是什么,Gitlab 提供了一篇非常全面的文章解释它是什么这里是)。这些工具将负责将您的变更发布到生产中。
本质上,这些 CI/CD 管道是 UNIX 命令集,它们自动执行上面定义的所有步骤,并且总是在容器化的环境中执行。这保证了每个部署都是可重复的和确定的。
错误 2:忽视部署策略的使用
最简单的 ML 模型部署策略基本上是通过更新运行 API 的容器映像,将旧服务转换为新服务。这通常被称为 重建部署模式 ,这是一个非常过时的策略,很少有公司还在使用。这种部署的主要缺点是它会导致服务停机一段特定的时间(只要服务需要启动),这在某些应用中是不可接受的。除此之外,如果你没有一个更复杂的策略,你将无法利用一些强大的技术来提高可靠性、跟踪和实验。
您可以尝试的:使用一种部署策略
蓝绿色部署
该部署策略包括同时在生产环境中部署服务的两个版本(旧版本和新版本)。当部署新版本时,消费者的流量通过负载均衡器逐渐被重定向到这个版本。如果新服务产生任何类型的错误,流量负载将立即重定向到旧版本(作为一种自动回滚)。
蓝绿色部署的好处是,您可以在很早的阶段发现错误,同时仍然为大多数消费者提供服务。它有一个嵌入式的灾难恢复功能,可以切换回之前的工作版本。在 ML 空间中,这种技术特别有用,因为模型容易由于各种原因产生错误。
*Blue-green model deployment | Source *
查看这个 Martin Fowler 对蓝绿部署的解释来了解更多关于这个策略的信息。
金丝雀部署
金丝雀部署类似于蓝绿色部署。主要区别在于,新旧版本之间的流量平衡不是基于百分比完成的,而是基于向新用户逐渐增加的模型版本。
基本上,该模型首先发布给特定的生产用户群体,以便在早期捕捉错误和问题(您甚至可以在向公众推出之前向内部员工发布)。在确认该服务对他们有效后,该服务逐渐推广到越来越多的用户。部署受到密切监控,以捕捉潜在的问题,如错误、不良行为、高延迟、CPU 或 RAM 的过度使用等。这通常是一个缓慢的过程,但比其他类型的部署风险更小。如果出现问题,回滚相当容易。
影子部署
*Canary model deployment | Source *
这种部署不像以前的那样常见,而且被低估了。它提供了一个巨大的好处,不必直接将模型放归自然。
它的工作方式是通过将传入的请求复制到另一个 sidecar 服务,该服务包含 ML 模型的新版本。这个新模型不会对消费者产生任何影响,也就是说,响应来自于唯一存在的稳定版本。
例如,如果您刚刚为在线交易构建了一个新的欺诈检测模型,但您不太愿意在没有使用真实数据进行测试的情况下将其发布到产品中,您可以将其部署为影子服务。旧的服务仍将与不同的系统交互,但您将能够实时评估新版本。如果您有一个定义良好的 ML 监控架构(进行 ML 模型监控的最佳工具),您将能够通过引入一个具有基本事实的反馈回路来评估模型的准确性。对于这个用例,这意味着知道交易最终是否是欺诈性的。
这种类型的部署还需要配置负载平衡器,以便一次将请求复制到两个版本。根据使用案例,还可以将生产负载流量异步重放到影子版本中,以避免影响负载平衡器的性能。
Shadow model deployment | Source
错误#3:没有启用自动化(预测)服务回滚
想象一下,你有一个生产模型,负责你的应用程序主要服务的动态定价。高度依赖这种模式的公司有优步、Bolt AirBnB、亚马逊、Shopify 等等。,
然后,假设数据科学团队创建了 ML 模型的一个新的改进版本。但是部署失败了(由于任何原因)。应用程序将不得不切换到备用价格,因为模型 API 不会响应。现在,价格不是个性化的(在最好的情况下),当然也不是动态的。
这个问题可能会导致收入大幅下降,直到服务得到解决,新模式得到部署。
您可以尝试的:为您的部署启用自动回滚
如果您的 ML 模型服务于您的应用程序的一个非常重要的特性,那么拥有一个健壮的回滚系统是至关重要的。回滚系统允许将服务切换回之前的版本,并减少应用程序运行不良的时间。正如我们之前已经看到的,这是蓝绿部署的重要部分。如果在渐进版本中没有出现任何错误,新版本只能接收 100%的流量。
手动回滚触发器
回滚到以前版本的另一种简便方法是启用手动回滚触发器。这对于在生产中部署的 ML 模型特别有用。有时 ML 服务不会失败,但是它们会开始返回异常输出,由于低效的模型编译和许多其他原因,需要很长时间来响应。这类问题通常不会被自动检测到,过一会儿就会被发现。通常,客户支持票开始到达,您会收到问题通知。
可以通过多种方式部署手动回滚触发器。比如 Github 允许设置 工作流调度 事件。这些允许您通过提供一些输入,从您的服务存储库中手动运行 Github 工作流。您可以设置要回滚到的提交、标记或分支。
*Kubernetes deployment | Source *
错误 4:忽略推理服务中的负载测试!
ML 服务往往比典型的后端服务要慢。ML 模型在做出预测时并不总是很快。这真的取决于你建立的模型的类型。例如,如果您使用一个转换器模型进行文本分类,那么根据输入序列的长度,推断时间可能会花费一些时间。一般来说,神经网络也是高度 CPU 密集型的,在某些情况下,它们也会占用大量 RAM 内存。
你可以尝试的:想想交通高峰!做压力测试,把自动缩放策略
由于这些潜在的性能问题,设计一个高效的硬件基础设施对于及时返回响应至关重要。有必要了解哪种配置策略是根据硬件使用情况自动扩展系统、设置服务主机的基本内存和 CPU 能力、设置服务主机的初始数量等的最佳配置策略。
所有这些都可以在你的 Kubernetes 配置 YAMLs 中定义,如果你正在部署一个 web 服务,或者在你的 Lambda 配置中定义,如果你正在 AWS 中部署一个无服务器架构。(GCP 和 Azure 的无服务器功能也有类似选项)。获得这些数字的最好方法是进行压力和负载测试。您也可以跳过这一步,在服务已经投入生产的情况下校准配置,但是这样风险更大。
什么是负载测试?
负载测试由模拟临时环境中的真实流量负载组成。也就是说,尝试估计服务每秒将接收多少请求(也包括峰值),并从外部主机或云本地执行测试。有几个开源和付费的工具可以用来做这件事,比如蝗虫(如果你使用 Python 就很容易使用)或者 Apache JMeter 。你可以在这里找到更多选项。
您必须定义每秒请求数和以特定速率产生的用户数,以模拟您的服务。这些工具还允许您定义定制负载。例如,您可以模拟在一天的高峰时段有较高的流量,而在周末有较低的负载。
负载测试结果将显示服务返回 503 错误或返回高延迟响应的比率。你甚至可以用自己的监控系统来复查这种行为( Datadog 、 Grafana 等)。
负载测试结果将如何帮助您优化您的架构?
这些测试结果将允许您定义在正常的请求/秒速率下您需要有多少个 pod,并估计您的 T2 服务需要扩展多少。然后,您将能够设置 CPU 和 RAM 阈值来触发水平自动扩展策略。它还将为您提供延迟分布的感觉,并决定它对于手头的用例是否足够,或者在投入生产之前是否需要应用任何必要的优化。
然而,模拟真实行为总是困难的,极端的交通高峰也不总是可预测的。这将我们引向下一点,拥有一个健壮的和定义良好的监控系统将允许团队在任何问题发生时得到早期通知。您需要有警报来监控延迟、错误、日志模式中的异常等。
错误 5:没有监控你的 ML 系统!
很明显,在您的生产模型上没有一个适当的监控层是一个很大的错误。这在过去几年变得更加重要,因为云环境中的技术堆栈越来越多。许多不同的组件相互作用,使得根本原因分析更加困难。当其中一个组件出现故障时,非常有必要准确地了解问题是如何发生的。
此外,在处理 ML 系统时,我们还有一个额外的挑战。机器学习模型依赖于它们接受训练的数据,但它们在生产中使用从未见过的数据。这提出了一个明显的问题,ML 模型本质上是错误的,但是正如常见的统计学格言所说,“……有些是有用的”。因此,随着时间的推移,监控我们的模型有多错误是至关重要的。
您可以尝试的:实现一个监控层
ML 系统非常复杂,难以监控。为了获得完整的可观测性图层,您需要设置多个监控级别。这些是硬件&服务监控、反馈回路和模型退化。
硬件和服务监控
硬件和服务监控是绝对必须实施的,包括:CPU 和 RAM 使用情况、网络吞吐量、响应延迟、完整的端到端跟踪和日志记录。这将允许足够快地补救技术问题,以避免对用户体验以及公司的最终收入产生负面影响。这可以通过一些已经提到的工具很好的解决,比如DatadogGrafana或者其他的比如 New Relic 或者 Dynatrace 。****
****还值得一提的是 Neptune 如何帮助监控训练指标和硬件消耗(在文档中阅读更多相关信息)。如果您的模型需要定期重新训练,或者是您的生产服务的一部分(例如:训练+预测发生在同一作业中),这将特别有用。
反馈回路
离线评估中使用的传统 ML 指标也可以在生产中进行评估,但前提是有实际数据可用。这就是通常所说的 反馈回路 。计算这些非常依赖于地面真实数据出现的方式。
Monitoring dashboard in Datadog | Source
在一些用例中,您需要等待一段特定的时间,直到您得到预测的真实结果(欺诈检测),在另一些用例中,您得到一个模糊的结果(语法错误纠正),在另一些用例中,它们甚至不可用。但大多数时候,你可以得出一个用户行为结果,作为检查模型是否支持你试图优化的业务指标的代理。
模型退化
Hardware monitoring in Neptune | Source
除了这两个(硬件、服务和反馈回路),ML 模型暴露了一个新的基本复杂性。这叫 型号退化 。这种效应不会在系统中产生错误,但意味着预测的质量会逐渐下降,如果没有复杂的 ML 友好监控层,很难检测到这一点。
模型退化主要是由的数据漂移引起的。*这意味着你输入在线算法的数据相对于训练数据已经发生了某种程度的变化。这通常通过比较生产数据与训练数据的分布来进行统计测试。在的论文中,你可以读到更多关于这种效果的细节。***
***由于 MLOps 完全是自动化,因此检测这种类型的问题对公司来说是一个巨大的工程挑战。大多数提供 MLOps 工具的公司已经解决了监控培训阶段的问题,但是生产模型退化监控仍然是一个难以概括解决的概念( SageMaker 、 Whylabs 和 Aporia 是少数几个已经提出了通用用例解决方案的工具)。
将 web 服务日志移动到一个数据存储区,在那里它们可以被批量提取和分析,这通常是通过使用一个流管道将记录放入一个流中来解决的,这些记录稍后将被写入对象存储区。例如,您可以使用 Kafka 主题和 Lambda 函数来接收要素和预测记录,并将它们保存在 S3。稍后,您可以设置一个定期的气流作业,提取 S3 的所有这些数据,并将它们与训练数据进行比较。如果差异很大,你可以向 ML 工程团队发送一个延迟通知。如果降级对您的系统至关重要,您可以触发模型训练并自动部署新模型。
结束了!
在本文中,我们介绍了 ML 工程师在部署他们的第一个模型时犯的一些关键错误。所有这些对于基于 ML 的生产系统的长期成功都是至关重要的。作为一个提示,小心过度设计!迭代是解决 ML 项目的最佳方式,因为实现所有这些建议的成本和工作量都很高。您的模型用例 ROI 需要支持它。
如果您想了解更多关于本文中出现的所有主题的信息,请查看以下文章:
参考
Moving web services logs to a data store where they can be extracted and analyzed in bulk is usually solved by using a streaming pipeline to put records in a stream which are later written in object storage. For example, you could use a Kafka topic and a Lambda function to receive features and prediction records and save them in S3. Later on, you can set up a periodic Airflow job that extracts all these data in S3 and compare them against the training data. If there’s a big difference, you could send a Slack notification to the ML engineering team. And if the degradation is critical for your system, you can trigger model training and deploy the new model automatically.
Wrapping up!
In this article, we introduced some of the key mistakes that ML engineers make when deploying their first models. All of these are critical for the long-term success of an ML-based production system. And just as a note, beware of over-engineering! Iteration is the best way to solve ML projects because the cost and effort of implementing all of these suggestions are high. Your model use case ROI needs to support it.
If you want to know more about all the topics surfaced in this article, check out these articles:
References*******
模型部署策略
原文:https://web.archive.org/web/https://neptune.ai/blog/model-deployment-strategies
近年来,大数据和机器学习已经被大多数主要行业采用,大多数初创公司也倾向于同样的做法。随着数据成为所有公司不可或缺的一部分,处理数据的方法,即获得有意义的见解和模式是必不可少的。这就是机器学习发挥作用的地方。
我们已经知道机器学习系统处理大量数据的效率有多高,并根据手头的任务,实时产生结果。但是这些系统需要正确地管理和部署,以便手头的任务高效地执行。本文旨在为您提供关于模型部署策略的信息,以及如何选择最适合您的应用的策略。
The image above depicts the entire pipeline of a data-science project | Source
我们将介绍以下模型部署的策略和技术:
- 1 影子评估
- 2 A/B 测试
- 3 多臂土匪
- 4 蓝绿色展开
- 金丝雀测试
- 6 特征标志
- 7 滚动部署
- 8 再造战略
这些策略可以分为两类:
- 静态部署策略:这些是手动处理流量或请求分配的策略。例如影子评估、A/B 测试、金丝雀测试、滚动部署、蓝绿色部署等等。
- 动态部署策略:这些是自动处理流量或请求分配的策略。多臂强盗就是一个例子。
Model deployment strategies | Source
首先,让我们快速了解一下什么是模型生命周期和模型部署。
ML 模型的生命周期
机器学习模型的生命周期指的是构建整个数据科学或人工智能项目的整个过程。它类似于软件开发生命周期(SDLC ),但在一些关键领域有所不同,例如在部署之前使用实时数据来评估模型性能。ML 模型的生命周期或模型开发生命周期(MDLC)主要有五个阶段:
- 1 数据采集
- 2 创建模型和培训
- 3 测试和评估
- 4 部署和生产
- 5 监控
Model development lifecycle (MDLC) | Source
现在,另一个你必须熟悉的术语是 MLOps 。MLOps 通常是实现 ML 生命周期的一系列实践。它将机器学习和软件应用结合在一起。简而言之,这是数据科学家和运营团队之间的合作,负责并协调整个 ML 生命周期。MLOps 关注的三个关键领域是持续集成、持续部署、和持续测试。
什么是模型部署(或模型发布)?
模型部署(发布)是一个过程,使您能够将机器学习模型集成到生产中,以根据真实世界的数据做出决策。这实际上是在监控之前的 ML 生命周期的倒数第二个阶段。一旦部署完毕,还需要对模型进行监控,以检查数据摄取、特征工程、培训、测试等整个过程是否正确对齐,从而无需人工干预,整个过程是自动的。
但是在部署模型之前,必须评估和测试经过训练的 ML 模型是否适合部署到生产中。对模型的性能、效率、甚至错误和问题进行测试。在部署 ML 模型之前,可以使用各种策略。让我们探索它们。
模型部署策略
策略允许我们评估 ML 模型的性能和能力,并发现与模型相关的问题。要记住的一个关键点是,策略通常取决于手头的任务和资源。有些策略可能是很好的资源,但计算量很大,而有些策略可以轻松完成工作。我们来讨论其中的几个。
1.影子部署策略
在影子部署或影子模式中,新模型与实时模型一起部署新特性。在这种情况下,新部署的模型被称为影子模型。影子模型处理所有的请求,就像真实模型一样,只是它没有向公众发布。
这种策略允许我们通过在真实世界的数据上测试影子模型来更好地评估影子模型,同时不中断真实模型提供的服务。
Shadow deployment strategy | Source
方法论:冠军 vs 挑战者
在影子评估中,使用两个 API 端点将请求发送给彼此并行运行的两个模型。在推断过程中,来自两个模型的预测被计算和存储,但是在返回给用户的应用中仅使用来自活动模型的预测。
将来自实时和阴影模型的预测值与地面真实值进行比较。一旦有了结果,数据科学家就可以决定是否在生产中全面部署影子模型。
但是人们也可以使用冠军/挑战者框架,以测试多个影子模型并与现有模型进行比较的方式。本质上,具有最佳准确性或关键性能指数(KPI)的模型被选择和部署。
优点:
- 模型评估是高效的,因为两个模型并行运行,对流量没有影响。
- 无论交通状况如何,都不能超载。
- 您可以监控影子模型,它允许您检查稳定性和性能;这降低了风险。
缺点:
- 因为支持影子模型所需的资源而昂贵。
- 影子部署可能是乏味的,尤其是如果您关注模型性能的不同方面,比如度量比较、延迟、负载测试等等。
- 不提供用户响应数据。
什么时候用?
- 如果你想相互比较多个模型,那么阴影测试是很棒的,尽管很乏味。
- 影子测试将允许您评估管道、延迟,同时产生结果以及承载能力。
2.A/B 测试模型部署策略
A/B 测试是一种基于数据的策略方法。它用于评估两个模型,即 A 和 B,以评估哪一个在受控环境中表现更好。它主要用于电子商务网站和社交媒体平台。通过 A/B 测试,数据科学家可以根据从用户那里收到的数据来评估和选择网站的最佳设计。
这两种型号在功能上略有不同,它们迎合不同的用户群。根据交互和从用户处收到的数据(如反馈),数据科学家选择一个可以在全球范围内部署到生产中的模型。
方法学
在 A/B 中,两个模型以不同的特征并行设置。目的是提高给定车型的转化率。为了做到这一点,数据科学家建立了一个假设。假设是基于对数据的抽象直觉的假设。这个假设是通过实验提出的,如果这个假设通过了测试,它就被接受为事实,这个模型就被接受,否则,它就被拒绝。
假设检验
在 A/B 测试中,有两种假设:
- 1 零假设是指模型中出现的现象纯属偶然,并不是因为某个特征。
- 2 替代假设通过陈述模型中发生的现象是由于某个特征而挑战原假设。
在假设测试中,目标是通过设置类似 A/B 测试的实验并向少数用户展示具有特定功能的新模型来拒绝无效假设。新模型本质上是基于另一个假设设计的。如果替代假设被接受而无效假设被拒绝,那么该特征被添加并且新模型被全局部署。
要知道为了拒绝零假设你必须证明 统计显著性 的检验。
A/B testing model deployment strategy | Source
优点:
- 很简单。
- 快速产生结果,并有助于消除低性能模型。
缺点:
- 如果复杂性增加,模型可能不可靠。在简单假设检验的情况下,应该使用 A/B 检验。
什么时候用?
如前所述,A/B 测试主要用于电子商务、社交媒体平台和在线流媒体平台。在这种情况下,如果您有两个模型,您可以使用 A/B 来评估并选择要全局部署的模型。
3.多股武装匪徒
多臂土匪或 MAB 是 A/B 测试的高级版本。它也受到强化学习的启发,其思想是探索和利用使奖励函数最大化的环境。
MAB 利用机器学习来探索和利用收到的数据,以优化关键绩效指数(KPI)。使用这种技术的优点是根据两个或更多模型的 KPI 来转移用户流量。产生最佳 KPI 的模型在全球范围内部署。
Multi Armed Bandit strategy | Source
方法学
MAB 在很大程度上依赖于两个概念:勘探和开发。
探索:这是一个概念,模型探索统计上有意义的结果,就像我们在 A/B 测试中看到的那样。A/B 测试的主要焦点是寻找或发现两个模型的转换率。
利用:这是一个概念,其中算法使用贪婪的方法,利用它在探索过程中获得的信息来最大化转化率。
与 A/B 测试相比,MAB 非常灵活。它可以在给定时间内与两个以上的模型一起工作,这增加了转化率。该算法根据发出请求的路由的成功情况,连续记录每个模型的 KPI 分数。这允许算法更新其最佳得分。
Building machine learning powered application | Source
优点:
- 随着探索和利用 MAB 提供适应性测试。
- 资源不会像 A/B 测试那样被浪费。
- 更快更有效的测试方法。
缺点:
- 这是昂贵的,因为开发需要大量的计算能力,这在经济上是昂贵的。
什么时候用?
MAB 对于转化率是你唯一关心的,并且做决定的时间很短的情况非常有用。例如,在有限的时间内优化产品的优惠或折扣。
4.蓝绿部署策略
蓝绿色部署策略涉及两个生产环境,而不仅仅是模型。蓝色环境由实时模型组成,而绿色环境由模型的新版本组成。
Blue-green deployment strategy | Source
绿色环境被设置为分级环境,即真实环境的精确复制品,但具有新的特征。让我们简单了解一下方法论。
方法学
在蓝绿色部署中,两个相同的环境由相同的数据库、容器、虚拟机、相同的配置等组成。请记住,设置一个环境可能会很昂贵,所以通常情况下,一些组件(如数据库)会在两者之间共享。
包含原始模型的蓝色环境是活动的,并不断为请求提供服务,而绿色环境充当模型新版本的登台环境。它要经过部署和针对真实数据的测试的最后阶段,以确保它性能良好,并准备好部署到生产中。一旦测试成功完成,确保所有的错误和问题都得到纠正,新模型就可以投入使用。
一旦这个模型被激活,流量就从蓝色环境转移到绿色环境。在大多数情况下,蓝色环境充当备份,以防出现问题,请求可以被重新路由到蓝色模型。
优点:
- 它确保应用程序全天候可用。
- 回滚很容易,因为一旦出现问题,您可以快速将流量转移到蓝色环境。
- 由于两种环境相互独立,部署风险较小。
缺点:
- 由于两种模式都需要独立的环境,因此成本很高。
什么时候用?
如果您的应用程序无法承受停机时间,那么应该使用蓝绿色部署策略。
5.金丝雀部署策略
canary 部署旨在通过逐渐增加用户数量来部署新版本的模型。与我们看到的之前的策略不同,在之前的策略中,新模型要么对公众隐藏,要么建立一个小的控制组,金丝雀部署策略使用真实的用户来测试新模型。因此,在为所有用户全局部署模型之前,可以检测到错误和问题。
Canary deployment strategy | Source
方法学
与 canary deployment 中的其他部署策略类似,新模型与当前的实际模型一起进行测试,但在这里,新模型在几个用户身上进行测试,以检查其可靠性、错误、性能等。
可以根据测试要求增加或减少用户数量。如果模型在测试阶段是成功的,那么模型可以被推出,如果不是,那么它可以在没有停机时间的情况下被回滚,但是只有一些用户将被暴露给新模型。
金丝雀部署策略可以分为三个步骤:
- 1 设计一个新模型,并将一小部分用户请求发送到新模型。
- 检查新模型中的错误、效率、报告和问题,如果发现,则执行回滚。
- 3 在将所有流量路由到新模型之前,重复步骤 1 和 2,直到所有错误和问题都得到解决。
优点:
- 与蓝绿色部署相比更便宜。
- 易于根据真实数据测试新模型。
- 零停机时间。
- 在失败的情况下,模型可以很容易地回滚到当前版本。
缺点:
- 推出很容易,但速度很慢。
- 由于测试是针对真实数据进行的,用户很少,因此必须进行适当的监控,以便在失败的情况下,用户可以有效地路由到实时版本。
什么时候用?
当根据真实世界的实时数据评估模型时,必须使用 Canary 部署策略。此外,它比 A/B 测试更有优势,因为从用户那里收集足够的数据来找到具有统计意义的结果需要很长时间。金丝雀部署可以在几个小时内完成。
6.其他模型部署策略和技术
特征标志
特性标志是一种技术,而不是一种策略,它允许开发人员将代码推入或集成到主分支中。这里的想法是保持特性休眠,直到它准备好。这允许开发人员在不同的想法和迭代上合作。一旦特性完成,就可以激活和部署它。
如前所述,特性标志是一种技术,因此它可以与前面提到的任何部署技术结合使用。
滚动部署
滚动部署是一种逐渐更新和替换旧版本模型的策略。这种部署发生在正在运行的实例中,它不涉及阶段化,甚至不涉及私有开发。
上图展示了滚动部署的工作方式。如您所见,服务是水平扩展的,这是关键因素。
左上角的图像代表三个实例。下一步是部署 1.2 版。随着 1.2 版单个实例的部署,1.1 版的一个实例将被淘汰。所有其他实例都遵循相同的趋势,即每当部署新的实例时,旧的实例就被淘汰。
优点:
- 它比蓝/绿部署更快,因为没有环境限制。
缺点:
- 虽然这样更快,但是如果进一步的更新失败,回滚会很困难。
重新制定战略
重建是一个简单的策略,即关闭模型的活动版本,然后部署新版本。
上图描述了重建策略的工作原理。实际上,旧实例(即 V1 实例)被关闭并丢弃,而新实例(即 V2 实例)被部署。
优点:
- 轻松简单的设置。
- 整个环境焕然一新。
缺点:
- 对用户有负面影响,因为它会停机并重启。
比较:使用哪种模型发布策略?
可以使用各种指标来确定哪种策略最适合他们。但这主要取决于项目的复杂性和资源的可用性。下面的比较表给出了一些何时使用哪种策略的想法。
Model release (deployment) strategies | Source
关键要点
部署策略通常有助于数据科学家了解他们的模型在给定情况下的表现。一个好的策略取决于产品的类型和目标用户。综上所述,以下是你应该记住的几点:
- 如果你想在真实世界的数据中测试模型,那么必须考虑影子评估策略或类似的策略。与使用用户样本的其他策略不同,影子评估策略使用实时和真实的用户请求。
- 检查任务的复杂性,如果模型需要简单或微小的调整,那么 A/B 测试是可行的。
- 如果有时间限制和更多的想法,那么你应该选择多臂强盗,因为它在这种情况下给你最好的结果。
- 如果你的模型很复杂,在部署之前需要适当的监控,那么蓝绿策略将帮助你分析和监控你的模型。
- 如果您不想停机,并且您可以向公众公开您的模型,那么选择 Canary 部署。
- 当您想要逐步部署模型的新版本时,必须使用滚动部署。
希望你们喜欢阅读这篇文章。如果您想了解更多关于这个主题的内容,可以参考附加的参考资料。继续学习!
参考
- 使用 Python 进行数据科学的 A/B 测试——数据科学家的必读指南
- 以影子模式部署机器学习模型
- 2021 年的机器学习生命周期
- 机器学习生命周期解释!
- 机器学习模型的自动金丝雀释放
- 部署策略介绍:蓝绿色、淡黄色等
- 部署机器学习模型的策略
- 机器学习部署策略
- 什么是蓝绿部署?
- 安全推出量产车型
- 最大限度地减少因低性能变化导致的 A/B 测试损失
- 部署机器学习模型的终极指南
- 机器学习部署:影子模式
- 多臂土匪
- 顺序 A/B 测试与多臂 Bandit 测试
- 什么是蓝绿部署?
- 金丝雀发布的利与弊以及连续交付中的特征标志
- 滚动部署
- 滚动部署:这是什么以及它如何消除软件部署的风险
- AWS 中机器学习模型的影子部署
- 在亚马逊 SageMaker 中部署影子 ML 模型
- 阴影 AB 测试模式
- MLOps 解释
- MLOps:它是什么,为什么重要,以及如何实施
- 用亚马逊 SageMaker MLOps 项目对机器学习模型进行动态 A/B 测试
- 多臂土匪对亚马逊评分数据集进行推荐和 A/B 测试
- 自动化金丝雀测试,确保持续质量
- CanaryRelease
- 最佳的 Kubernetes 部署策略是什么?
时间序列的模型监控
原文:https://web.archive.org/web/https://neptune.ai/blog/model-monitoring-for-time-series
模型监控是 CI/CD 管道的重要组成部分。它确保了一致性,并为部署的应用程序提供了健壮性。深度学习模型的一个主要问题是,它可能在开发阶段表现良好,但在部署时,它可能表现不佳,甚至可能失败。时间序列模型尤其如此,因为数据集中的变化可能非常快。
Model monitoring for time series | Source
在本文中,我们将探讨时间序列预测模型,以实际了解我们如何监控它。这篇文章基于一个案例研究,它将使读者能够理解 ML 监控阶段的不同方面,并且同样地执行能够使 ML 模型性能监控在整个部署中保持一致的操作。
所以让我们开始吧。
模型监控过程:定义项目
在这篇文章的开始,我们将定义一个简单的项目或案例研究,在这里我们可以深入了解模型监控过程的细节。对于这个项目,我们将设计一个 ML 模型,它可以预测在不同商店出售的商品的单位销售额。我发现厄瓜多尔的大型杂货零售商 Corporación Favorita 在 Kaggle 为我们提供了他们的数据。
这个想法是利用一个准确的预测模型,帮助零售商通过在正确的时间提供正确的产品来取悦他们的客户。使用深度学习模型进行时间序列预测可以帮助零售商对其运营做出更明智的战略决策,并提高其在市场中的竞争力。
理解目标
该项目的目标是:
- 使用 Pytorch-Forecasting 构建深度学习模型,这是一个完全致力于时间序列分析和预测的库
- 在 neptune.ai 仪表板中监控训练期间的 ML 模型性能,包括其准确性和损失,例如
- 对称平均绝对百分比误差
- mqf 2 分布损失
- 分位数损失
- 监控硬件性能
- 在部署后监控模型的性能,我们将使用深度检查来监控:
描述数据
如前所述,我们将在 Kaggle 中使用 Corporación Favorita 提供的数据。该数据包括日期、商店、产品信息以及关于产品促销的信息。其他功能包括销售数字和补充信息。
Dataset | Source: Author
数据很复杂,因为它包含不同类别的要素。有目标特征、静态分类特征、时变已知分类特征、时变已知真实特征、时变未知真实特征。
由于数据集中的复杂性,我们必须非常小心地选择适当的模型,在数据集中探索和发现模式和表示。
探索模型[理论上]
对于这个项目,我们将使用一个时间融合变压器或 TFT。TFT 是一种专门设计用于处理时序数据(如时间序列或自然语言)的神经网络架构。它结合了通常用于 NLP 任务的 transformer 架构。TFT 最初是在 2020 年的一篇论文中介绍的,该论文描述了一种用于时间序列分析的多时段预测方法,其中一个模型根据过去的数据进行训练,以预测未来。在多时段预测中,模型根据过去的数据进行训练,以预测未来。
Multi-horizon forecasting | Source
TFT 的基本构建模块由四个组件组成:
- 门控机制:用于跳过架构中任何未使用的组件。这里使用 gru,它提供有效的信息流,提供自适应的深度和网络复杂性。它还可以适应广泛的数据集和场景。
- 变量选择网络:该模块用于选择每个时间步的相关输入特征。
- 静态协变量编码器:该编码器用于将静态元数据集成到网络中。元数据被编码成上下文向量,并且它被用于调节时间动态。
- 时态处理:该组件负责两种类型的处理:
- 时间相关处理其中 LSTMs 被用于信息的本地处理。
- 长期依赖关系被多头关注块捕获。
- 预测区间:本质上是在给定的地平线上近似变量的可能性。这就是所谓的分位数预测。因此,TFT 不会产生回归模型中常见的特定值,而是在给定时间内提供一系列可能的结果。
也就是说,TFT 是预测该项目的销售的完美模型。数据本身有许多输入特征,一些是静态的,而另一些是时变的。监控这样一个系统可能具有挑战性,因为有许多功能会妨碍模型的性能。
Multi-horizon forecasting with many inputs | Source
建立性能基线
模型性能必须在整个部署阶段保持一致。我们衡量模型一致性的方法是选择正确的性能指标,从而建立基线。
作者使用分位数损失来最小化分位数输出的误差。类似地,对于不同的层位长度 H ,可以使用均方误差和平均绝对误差来计算模型的精度。
Mean squared error and mean absolute error | Source
有了度量标准,我们现在必须定义模型的基线性能。基准性能由两种方法定义:
-
持久性:该基线使用前一时间点的变量值作为当前时间点的预测。这对于评估时间序列深度学习模型在预测任务中的性能非常有用,预测任务的目标是根据变量的过去值预测其未来值。
-
基准模型:在某些情况下,将时间序列深度学习模型的性能与被视为该领域“基准”的成熟且广泛使用的模型进行比较可能是合适的。这可以给出模型相对于最先进的方法表现如何的感觉。
当我们一切从头开始时(在我们的情况下),我们将使用第一种方法。在下一节中,我们将学习如何使用 Pytorch-Forecasting 定义基线模型。一般我们会用某些不同的配置对模型进行优化,这样可以得到不同的模型。然后,我们将选择最佳部署,其准确性将作为现有模型的基准。
部署后,我们将使用当前最佳模型监控模型性能,并检查数据漂移和模型漂移。
构建时间序列模型[py torch]
现在,让我们使用 Pytorch 预测库构建一个 TFT 时间序列模型。该库由 Jan Beitner 创建,用于预测时间序列,具有最先进的网络架构,如 TFT、NHiTS、NBeats 等。该库构建在 Pytorch-Lightning 之上,用于在 GPU 和 CPU 上进行可扩展的培训,并用于自动日志记录。
可以查看完整的笔记本。在本文中,我将只提供必要的组件。
让我们安装 Pytorch-Forecasting 并导入必要的库。
!pip install pytorch-forecasting
import torch
import pytorch_lightning as pl
from pytorch_lightning.callbacks import EarlyStopping
from pytorch_forecasting import Baseline, TimeSeriesDataSet, TemporalFusionTransformer
from pytorch_forecasting.data import GroupNormalizer
from pytorch_forecasting.metrics import QuantileLoss
Pytorch-Forecasting 提供了一个名为“TimeSeriesDataSet”的数据集对象。其本质上根据模型的要求准备数据。该数据集包括以下功能。见下图。
The dataset | Source: Author
这些功能必须小心处理,以便模型可以提取和捕获信息。使用时间序列数据集,我们可以为训练目的准备数据集。
training = TimeSeriesDataSet(
df_train[lambda x: x.time_idx <= training_cutoff],
time_idx="time_idx",
target="sales",
group_ids=["store_nbr", "family"],
min_encoder_length=max_encoder_length // 2,
max_encoder_length=max_encoder_length,
min_prediction_length=1,
max_prediction_length=max_prediction_length,
static_categoricals=["store_nbr",
"family",
"city",
"state",
"store_cluster",
"store_type"],
time_varying_known_categoricals=["holiday_nat",
"holiday_reg",
"holiday_loc",
"month",
"dayofweek",
"dayofyear"],
time_varying_known_reals=["time_idx", "onpromotion", 'days_from_payday', 'dcoilwtico', "earthquake_effect"
],
time_varying_unknown_categoricals=[],
time_varying_unknown_reals=[
"sales",
"transactions",
"average_sales_by_family",
"average_sales_by_store",
],
target_normalizer=GroupNormalizer(
groups=["store_nbr", "family"], transformation="softplus"
),
add_relative_time_idx=True,
add_target_scales=True,
add_encoder_length=True,
allow_missing_timesteps=True
您还可以查看准备好的数据集的参数。
print(training.get_parameters())
{'time_idx': 'time_idx', 'target': 'sales', 'group_ids': ['store_nbr', 'family'], 'weight': None, 'max_encoder_length': 60, 'min_encoder_length': 30, 'min_prediction_idx': 0, 'min_prediction_length': 1, 'max_prediction_length': 16, 'static_categoricals': ['store_nbr', 'family', 'city', 'state', 'store_cluster', 'store_type'], 'static_reals': ['encoder_length', 'sales_center', 'sales_scale'], 'time_varying_known_categoricals': ['holiday_nat', 'holiday_reg', 'holiday_loc', 'month', 'dayofweek', 'dayofyear'], 'time_varying_known_reals': ['time_idx', 'onpromotion', 'days_from_payday', 'dcoilwtico', 'earthquake_effect', 'relative_time_idx'], 'time_varying_unknown_categoricals': [], 'time_varying_unknown_reals': ['sales', 'transactions', 'average_sales_by_family', 'average_sales_by_store'], 'variable_groups': {}, 'constant_fill_strategy': {}, 'allow_missing_timesteps': True, 'lags': {}, 'add_relative_time_idx': True, 'add_target_scales': True, 'add_encoder_length': True, 'target_normalizer': GroupNormalizer(
method='standard',
groups=['store_nbr', 'family'],
center=True,
scale_by_group=False,
transformation='softplus',
method_kwargs={}
), 'categorical_encoders': …}
如您所见,数据集被分成子样本,其中包括静态分类特征、时变已知分类特征、时变已知真实特征和时变未知真实特征。
现在我们建立一个 TFT 模型。
在 Pytorch-Forecasting 中构建模型非常简单,您只需要调用模型对象并根据您的需求配置它,类似于我们看到的数据集。您只需要调用 TemporalFusionTransformer 对象并相应地配置模型。
tft = TemporalFusionTransformer.from_dataset(
training,
learning_rate=0.03,
hidden_size=16,
attention_head_size=1,
dropout=0.1,
hidden_continuous_size=8,
output_size=7,
loss=QuantileLoss(),
reduce_on_plateau_patience=4)
训练和评估模型
在开始培训之前,让我们首先定义基线。如果你还记得的话,我们将使用持久方法来得到我们的基线分数。在 Pytorch 预测中,您可以调用 Baseline()。predict 函数根据最后一个已知的目标值来预测值。一旦生成了值,就可以计算 MAE 来找出误差差。
actuals = torch.cat([y for x, (y, weight) in iter(val_dataloader)])
baseline_predictions = Baseline().predict(val_dataloader)
print((actuals - baseline_predictions).abs().mean().item())
ML 模型性能监控:可视化学习曲线
一旦基线值被设置,我们就可以开始我们的训练并监控模型。那么,为什么在培训阶段需要模型监控呢?
模型监控是培训阶段的一个重要方面,原因如下:
-
过度拟合:当模型被训练时,它可能开始太好地拟合训练数据,导致验证数据的表现不佳,这可能导致过度拟合。模型监控允许您在早期检测过度拟合并采取措施防止它,例如调整或提前停止。
-
收敛:有时候,在训练的时候,模型在一个数值范围内停滞不前。如果模型没有收敛到一个好的解决方案,就会发生这种情况。如果模型没有进展或者陷入次优解决方案,您可以调整模型的架构、学习率或其他超参数,以帮助它收敛到更好的解决方案。
为了监控模型,您可以使用类似于 neptune .ai 的平台。neptune 提供了一个实时监控仪表板,使我们能够随时随地查看模型的性能。您可以使用下面的代码下载这个包。
!pip install neptune-client
由于我们使用 Pytorch Lightning,我们可以使用以下代码导入 Neptune 记录器:
from pytorch_lightning.loggers import NeptuneLogger
现在,让我们通过运行以下 Pytorch-Lightning 脚本来开始培训:
trainer.fit(tft, train_dataloaders=train_dataloader,
val_dataloaders=val_dataloader)
Neptune’s dashboard | Source: Author
从图中可以看出,损失在下降,这意味着模型收敛得很好。
监控硬件指标
与监视模型的性能一样,监视硬件性能也很重要。为什么?
在训练 DL 模型期间监视硬件性能可以帮助识别系统中的瓶颈。例如,监控 GPU 内存使用可以确保模型不会耗尽内存而导致训练突然停止。它还可以确保硬件得到高效利用。
Monitoring hardware metrics in Neptune | Source: Author
上面的图像显示内存使用是最优的,训练是平滑和高效的。
生产中的 ML 模型性能监控
当模型投入生产时,我们必须确保我们必须持续地监控模型的性能,并将其与最近的性能指标进行比较。除此之外,我们还必须持续监控数据。
在本节中,我们将了解如何监控模型的性能、模型漂移和数据漂移。
模型漂移:根据新数据和看不见的数据检查模型的准确性
该模型可以在两个数据集上进行测试:没有任何新条目的原始数据集和具有新条目的新数据集。通常,模型会在新数据集上进行测试。但是,如果您在旧数据集上测试模型,并且准确性下降,那么可能有一个有效的理由来重新训练模型,因为模型的参数已经改变。
大多数情况下,在用旧数据集测试模型时,准确性会有一点波动,因此模型可以保持不变。但是,当使用新数据集测试模型时,准确性会显著下降,那么数据的分布就有可能发生了变化。这是您必须检查数据漂移的地方。
给定的代码片段可以帮助您在新数据集或现有数据集上评估模型。
encoder_data = new_data[lambda x: x.time_idx > x.time_idx.max() - max_encoder_length]
last_data = new_data[lambda x: x.time_idx == x.time_idx.max()]
decoder_data = pd.concat([last_data.assign(date=lambda x: x.date +
pd.offsets.MonthBegin(i)) for i in range(1,
max_prediction_length + 1)], ignore_index=True)
decoder_data["time_idx"] = decoder_data["date"].dt.year * 12 + decoder_data["date"].dt.month
decoder_data["time_idx"] += encoder_data["time_idx"].max() + 1 - decoder_data["time_idx"].min()
decoder_data["month"] = decoder_data.date.dt.month.astype(str).astype("category")
new_prediction_data = pd.concat([encoder_data, decoder_data], ignore_index=True)
best_tft = TemporalFusionTransformer.load_from_checkpoint(best_model_path)
new_raw_predictions, new_x = best_tft.predict(new_prediction_data, mode="raw", return_x=True)
for idx in range(10):
best_tft.plot_prediction(new_x, new_raw_predictions, idx=idx, show_future_observed=False)
Source: Author
您还可以添加一些额外的技术来评估性能。例如,您可以评估模型如何对每个要素进行预测。
predictions, x = best_tft.predict(val_dataloader, return_x=True)
predictions_vs_actuals =
best_tft.calculate_prediction_actual_by_variable(x, predictions)
best_tft.plot_prediction_actual_by_variable(predictions_vs_actuals)
Model predictions for different features | Source: Author
从上面的图片中可以看出,该模型能够准确预测不同的特征。我想鼓励你测试和评估模型的每一个可能的方面。
我要举的另一个例子是检查模型的可解释性。例如:
interpretation = best_tft.interpret_output(raw_predictions, reduction="sum")
best_tft.plot_interpretation(interpretation)
Checking the interpretability of the model | Source: Author
可解释性确保人类能够理解深度学习模型做出决定的原因。从上面的图像中,您可以看到销售规模和销售额是模型中的顶级预测因素。
确保前几个预测值在两个数据集中保持相同,即原始数据集和新数据集。
检查数据漂移
我们将使用 apparent . ai 监控数据漂移。如果我们遇到任何漂移,我们将看到采取什么必要的步骤。为了检查数据漂移,我们将首先安装并导入所有必要的函数。这里有一个简短的注释:
显然,ai 是一种监控工具,它使用户能够评估、测试和监控数据和机器学习模型。它为用户提供了一个交互式的仪表板,所有的结果和报告都在这里生成。?
!pip install evidently
from evidently.dashboard import Dashboard
from evidently.report import Report
from evidently.model_profile import Profile
from evidently.profile_sections import DataDriftProfileSection
from evidently.metric_preset import DataDriftPreset, TargetDriftPreset
from evidently.dashboard.tabs import (
DataDriftTab,
DataQualityTab,
CatTargetDriftTab,
ClassificationPerformanceTab,
ProbClassificationPerformanceTab,
)
我将向您展示生成数据漂移报告的两种方法:
- 1 使用报表对象
- 2 使用仪表板对象
使用报告对象
报告对象将指标作为参数之一,并生成关于数据的完整报告。很好用,也挺有效的。
report = Report(metrics=[DataDriftPreset()])
一旦初始化了对象,就需要有两个样本数据集。其中一个将用作基准的参考数据集,另一个将用作当前数据集。实质上,这两个数据集将用于相互比较统计特性的漂移。
注:参考数据集是用于初始训练的原始数据,而当前数据集是新数据集。在现实世界中,我们必须比较这两个数据集。
在本例中,我们将从原始数据集创建两个样本数据集。
reference = df_train.sample(n=5000, replace=False)
current = df_train.sample(n=5000, replace=False)
一旦创建了两个样本,您就可以在下面的函数中传递它们并查看报告。
report.run(reference_data=reference, current_data=current)
Comparison of the two datasets distribution | Source: Author
生成的仪表板将表示所有特征/列。它将比较两个数据集的分布。每个特性都可以扩展,这将提供分布图和其他相关信息。
The drift summary | Source: Author
你还会发现漂移总结。
Dataset drift | Source: Author
免责声明:在这个数据集中,你不会发现任何漂移,因为数据集没有新的条目。
使用仪表板和列映射对象
仪表板和列映射对象类似于报告,但它不是自动检查漂移,而是允许您指定类型列来检查数据漂移。这是因为列类型会影响一些测试、度量和可视化。通过指定列的类型,您显然能够产生准确的结果。
以下是使用仪表板和列映射的示例:
column_mapping = ColumnMapping()
column_mapping.prediction = None
column_mapping.id = "id"
column_mapping.datetime="date"
column_mapping.target="sales",
column_mapping.numerical_features=["city",
"dcoilwtico",
"transactions",
"earthquake_effect",
"days_from_payday",
"average_sales_by_family",
"average_sales_by_store",
"onpromotion"]
column_mapping.categorical_features=["store_nbr",
"family",
"city",
"state",
"store_cluster",
"store_type",
"holiday_nat",
"holiday_reg",
"holiday_loc",
"month",
"dayofweek",
"dayofyear"]
column_mapping.task = "regression"
在上面的代码中,您会发现列(我觉得这个任务很有趣)是在一个列表中指定的,该列表由数字、分类、id、日期、时间等组成。这是一项繁琐的任务,但是您可以使用这个 df_train.info()函数来获取列并为特定的类别创建一个列表。
>>> <class>Int64Index: 3000888 entries, 0 to 3000887
Data columns (total 23 columns):
# Column Dtype
--- ------ -----
0 id int64
1 date datetime64[ns]
2 store_nbr category
3 family category
4 sales float64
5 onpromotion int64
6 city category
7 state category
8 store_type category
9 store_cluster category
10 holiday_nat category
11 holiday_reg category
12 holiday_loc category
13 dcoilwtico float64
14 transactions float64
15 earthquake_effect float64
16 days_from_payday int64
17 average_sales_by_family float64
18 average_sales_by_store float64
19 dayofweek category
20 month category
21 dayofyear category
22 time_idx int64</class>
一旦初始化了 ColumnMapping,就可以将它传递给下面的函数。
datadrift_dashboard = Dashboard(tabs=[DataDriftTab(verbose_level=1)])
datadrift_dashboard.calculate(reference, current, column_mapping=column_mapping)
datadrift_dashboard.show()
Detection of the drift | Source: Author
模型监控之后的下一步是什么?
既然我们已经了解了如何监控我们的模型,这里有一些提示可以帮助您采取后续步骤:
- 定期监控模型的性能,在添加新技术的同时使用相同的方法。例如,您可以使用新的度量或比较来评估损失,如对称平均绝对百分比误差(SMAPE),并将其与分位数损失进行比较。SMAPE 描绘了模型有预测问题的区域。它衡量所有预测范围内预测值和实际值之间的平均百分比差异。
下面是一个实现 SMAPE 的示例:
from pytorch_forecasting.metrics import SMAPE
predictions = best_tft.predict(val_dataloader)
mean_losses = SMAPE(reduction="none")(predictions, actuals).mean(1)
indices = mean_losses.argsort(descending=True)
for idx in range(10):
best_tft.plot_prediction(
x, raw_predictions, idx=indices[idx], add_loss_to_title=SMAPE(quantiles=best_tft.loss.quantiles)
)
Source: Author
如您所见,该模型可以很好地处理分位数损失,但不能处理 SMAPE。
- 跟踪数据统计特征的任何变化。这将有助于您尽早发现数据漂移。
- 使用诸如特征工程和数据扩充之类的技术来提高你的模型的健壮性。这可以帮助您的模型更好地处理与定型数据具有不同统计特征的数据。
- 在新的数据集和最新数据上重新训练您的模型,这些数据与您期望在测试时看到的数据具有相似的统计特征。这可以帮助您的模型即使在存在数据漂移的情况下也能保持良好的性能。
- 使用迁移学习或微调等技术来使预训练模型适应新数据集,而不是从头开始训练它,因为这样可以节省时间,并且可以更快、更有效。
- 使用在线学习算法:另一种解决方案是使用在线学习算法,这种算法能够适应数据分布随时间的变化。这可以通过不断向模型输入新数据并定期重新训练来实现。
- 集成学习:另一种解决方案是使用集成学习,它涉及训练多个模型并结合它们的预测来做出最终预测。这有助于减轻模型漂移的影响,因为集合的整体性能对任何单个模型的性能不太敏感。
- 使用领域知识:另一个解决方案是使用领域知识来识别模型漂移的最可能来源,并相应地设计模型或训练过程。例如,如果您知道数据的某些特征可能会随着时间的推移而改变,则可以在模型中降低这些特征的权重,以减少模型漂移的影响。
- 注意季节性趋势,并快速适应和重新训练模型。
- 监控和警报系统:最后,另一个解决方案是建立监控和警报系统来检测模型漂移何时发生,以便您可以在它成为问题之前采取措施解决它。
请记住,数据漂移和模型漂移是机器学习中的常见问题,解决它们是一个持续的过程,需要定期监控和维护您的模型。
重新训练模型——是还是不是?
重新训练模型是必须的。但是时机很重要。考虑再培训时,请记住以下几点:
- 如果数据分布每周频繁变化,您必须每周对模型进行微调。
- 2 如果您正在处理一项数据随季节变化且添加了新功能的任务,那么请遵循一个时间表,即每月三次及时微调模型,并在新数据集上从头开始重新训练一个新模型。
- 基于以上两点,迁移学习在许多方面也有帮助。这包括使用预先训练的模型作为起点,然后通过冻结原始模型中的一些层并仅训练层的子集,在新的任务上训练它。如果数据集很小,并且希望防止模型忘记在原始任务中学习到的信息,这可能是一个不错的选择。
更新数据管道
更新培训渠道时,遵循一些最佳实践会有助于确保平稳过渡,并最大限度地减少错误和部署延迟。以下是一些你可以考虑的策略:
- 提前计划:在上一节课中,我提到数据集的分布可能会偶尔、频繁和季节性地发生变化。在对您的培训渠道进行任何更改之前,提前计划并考虑您正在进行的更改的影响是非常重要的。这可能包括评估对模型性能的潜在影响,确定进行更改所需的资源,以及估计实现更新所需的时间。
- 利用领域知识:当在一个特定的领域工作时,你会知道什么时候需要什么时候不需要。组织和分离将在特定季节使用的数据集格式。
- 测试增量变化:建立在上述基础上。与其一次完成所有的更改,不如在继续之前对它们进行增量测试,并验证它们是否按预期工作。这有助于尽早发现任何问题,并在必要时更容易回滚更改。
- 使用版本控制:使用版本控制来跟踪你的培训管道的变化是一个好主意。这使得在必要时回滚更改变得更加容易,并且它还可以提供一个随着时间的推移所做的修改的记录。版本控制也将帮助您找到问题的答案。就像他们说的“历史重演?,所以版本控制是个好主意。
- 记录您的修改:确保记录您对培训渠道所做的任何更改,包括更改背后的原因以及预期的影响。这有助于确保将来可能需要使用管道的其他人了解您的更新。
- 监控绩效:在对您的培训渠道进行更改后,确保监控您的模型的绩效,以确保它不会受到更新的负面影响。这可能包括跟踪诸如准确性和损失之类的度量,并在做出更改之前将它们与模型的性能进行比较。
承认
特别感谢路易斯·布兰奇、T2、卡迪普·辛格、简·贝特纳。这篇文章的代码就是受他们的启发,没有他们,这篇文章就不可能完成。
参考
- 型号:
- 指标:
- 图书馆:
- 实验:
模型注册使 MLOps 工作:原因如下
原文:https://web.archive.org/web/https://neptune.ai/blog/model-registry-makes-mlops-work
模型注册是机器学习生命周期或 MLOps 的一部分。它是一个管理多个模型工件的服务,在 ML 生命周期的不同阶段跟踪和治理模型。Model registry 是一个协作中心,团队可以在机器学习生命周期的不同阶段一起工作,从实验阶段开始到生产阶段。它实现了批准、治理和监控的无缝衔接,并提高了工作流性能。它帮助您管理 ML 模型的整个开发生命周期,并标准化部署。在未来几年,75%的公司/初创公司正计划将其机器学习项目从试点转向运营。因此,当涉及到生产时,我们有时会使用完全不适合数据科学家或 ML 工作流的 ML 工具。因此,模型注册中心是让 MLops 工作的关键。我们将探索几个平台和 Model registry 的关键特性。
什么是模型注册中心?
Model Registry 是一个允许机器学习工程师和数据科学家发布、测试、监控、管理和共享它们以便与其他团队合作的系统。本质上,当您完成了试验阶段,并准备好与团队和涉众共享时,就可以使用模型注册。
Source: Author
为什么我们需要模型注册
假设您已经花费了大量资源来开发一个 ML 算法,该算法运行良好,并且有很好的潜力来影响您的业务成果。将 ML 推向生产的过程极其缓慢,公司需要一年,有时两年才能发布一款产品。我们缺少的是透明度和与其他团队成员合作的方式。那么,如果你有一个中央回购平台来存放你所有的生产就绪模型,会怎么样呢?这将简化整个生产和工作流程。使用模型注册中心,您可以确保所有的键值(包括数据、配置、环境变量、模型代码、版本和文档)都在一个地方,每个人都可以访问。
缺乏治理和安全性是许多行业的主要问题。它最终会拖慢生产,然后公司不得不回到白板前思考哪里出了问题以及如何解决。现实生活中有许多缺乏适当管理导致严重问题的案例。适当的管理、治理和测试可能不会首先产生任何问题。借助模型注册,您可以:
- 管理模型生命周期
- 工作流的模型风险和批准
- 更快、无缝地推出
- 轻松协作和管理
关键特征
- 中央存储库:在一个地方无缝管理您的所有实验,管理带有版本和其他元数据的注册模型。这个协作中心帮助团队在一个地方轻松访问和共享所有类型的信息。
- 模型版本化:自动跟踪版本。你的机器学习模型有这么多不同的组成部分——数据使用、超参数、预定义算法或你自己开发的算法、模型架构。通过模型版本控制,您可以轻松地管理所有这些组件。版本控制是机器学习治理过程的重要组成部分。有许多版本控制工具可以帮助您改进 ML 工作流。下面是一些用于数据版本控制的顶级工具。
- Neptune:其直观的用户界面和易于使用的管理系统可以帮助您自动化、跟踪和监控您的实验。
- DVC:这是一个开源系统,允许你维护不同的数据类型、配置和代码。它帮助您跟踪完整的代码和数据来源。
- GIT (LFS): Git 用于监控和管理你的实验。Git 跟踪您的代码,让您存储、合并和实现这些更改。而 GIT LFS 是对大型文件和数据集进行版本控制的扩展。
- CI/CD 工作流集成:这是一个工作流,允许开发人员和数据科学家更改、更新和合并代码到一个中央报告中。您可以控制试运行过程,批准和检查更改。它允许团队自动将模型转换到基于生产的状态,或者团队可以手动控制和验证生命周期阶段。
- 每次更新代码时,CI 都依赖于一套自动化的测试。该套件让您知道什么时候出现了问题,让团队可以很容易地解决问题。
- 它的架构允许你用小的迭代工作,并帮助你迭代发布。以可部署的方式保存代码。
- 提高团队生产力,更快的部署,更频繁的发布,并且风险最小。
- 模型管理:将 ML 模型作为在线部署或测试的 API。公司在不同阶段往往会有成千上万的机器学习模型。模型注册使得在测试、实验和生产阶段的治理、跟踪和管理变得容易。有时,跟踪所有的机器学习实验可能具有挑战性,但通过适当的管理,事情可以变得非常简单。模型管理有助于您获得正确的见解、轻松的协作以及机器学习实验的详细记录。
示范登记册平台
让我们讨论几个最好的和最常用的模型注册工具。为了更好地理解,我们还将比较几个关键特性,并运行一个小型模型注册表演示。
Neptune 是 MLOps 的一个元数据存储库,为运行大量实验的研究和生产团队而构建。
它为您提供了一个中心位置来记录、存储、显示、组织、比较和查询机器学习生命周期中生成的所有元数据。个人和组织使用 Neptune 进行实验跟踪和模型注册,以控制他们的实验和模型开发。
- 在一个地方记录和版本化你所有的机器学习模型开发元数据。
- 无缝版本笔记本电脑,。git 信息、模型代码、数据集和图像。
- 在中央 ML 模型注册表中组织模型,版本存储,在仪表板中过滤、排序和分组所有机器学习模型训练运行。
- Neptune 提供了一种简单的方法来调试和比较您的模型度量。它会在两次运行之间自动生成表格,让毫不费力地进行比较。
- 机器学习模型的团队协作安全地与您的团队共享一切。获取关于模型的变更内容、时间和人员的信息。
- 您可以重新运行您的 ML 模型,并跟踪所有运行及其结果。
开始使用 Neptune 非常简单:
- 安装
pip install neptune-client
- 培训脚本准备
创建一个文件(main.py)并粘贴下面提到的代码
import neptune.new as neptune
run = neptune.init(project="your_workspace/your_project")
run["JIRA"] = "NPT-952"
run["parameters"] = {"learning_rate": 0.001,
"optimizer": "Adam"}
for epoch in range(100):
run["train/accuracy"].log(epoch * 0.6)
run["train/loss"].log(epoch * 0.4)
run["f1_score"] = 0.66
- 运行您的脚本
转到终端并运行:
python main.py
您将看到一个 Web 链接,您可以在 UI 中看到您的实验数据
查看他们的文档页面,了解一切是如何工作的。
使用 Neptune 构建元数据的日志模型:
确保安装了正确的库,并从 Neptune 系统配置了 API。
- 连接海王星
import neptune.new as neptune
run = neptune.init(project='common/quickstarts',
api_token='ANONYMOUS')
- 测井参数
PARAMS = {'lr': 0.1, 'epoch_nr': 10, 'batch_size': 32}
run['parameters'] = PARAMS
- 添加指标和损失
loss = ...
run["train/loss"].log(loss)
下面是创建回调的示例,该回调使用 Keras 在每个时期后记录指标和损失:
run = neptune.init(project='common/myproject',
api_token=”YOUR_API_TOKEN”)
class NeptuneLogger(keras.callbacks.Callback):
def on_batch_end(self, batch, logs={}):
for log_name, log_value in logs.items():
run['batch/{}'.format(log_name)].log(log_value)
def on_epoch_end(self, epoch, logs={}):
for log_name, log_value in logs.items():
run['epoch/{}'.format(log_name)].log(log_value)
*将其传递给回调参数:
model.fit(x_train, y_train,
epochs=PARAMS['epoch_nr'],
batch_size=PARAMS['batch_size'],
callbacks=[NeptuneLogger()])
- 测试分数记录
run['test/acc'] = 0.76
- 添加模型文件的日志
run["model"].upload('my_model.pkl')
现在就试试 Neptune】或者阅读更多关于它的模型注册表特性。
2. Azure 机器学习
Azure ML 是一个基于云的平台,用于训练、部署、自动化、管理和监控所有的机器学习实验。Azure ML 使用 MLOPs 方法来提高机器学习实验的质量和性能。在 Azure 中,你可以选择用 UI 创建和注册一个模型,或者用 API 注册。
- Azure 让你创建可重用的管道和环境,帮助你轻松处理模型训练、数据准备和机器学习模型的部署。
- 注册和部署 ML 模型,从任何地方监控与您的模型相关联的元数据。
- 管理整个机器学习生命周期,包括何时、何地以及谁对模型进行了更改。
- 部署不同事件的定制通知,例如您的实验完成或建模。
- 监控和探索不同类型的指标,为您的机器学习实验获取定制警报。
无论部署在哪里,Azure ML 工作流都是一样的。
- 注册模型
- 准备入口脚本和配置
- 模型的部署(云/本地)
- 监测和分析
- 将模型重新部署到云中
- 测试性能
从本地机器注册模型
wget https://aka.ms/bidaf-9-model -o model.onnx
az ml model register -n bidaf_onnx -p ./model.onnx
将-p 设置为要注册的文件夹或文件的路径。
从 Azure 机器学习的训练运行中注册模型
az ml model register -bidaf_onnx --asset-path outputs/model.onnx --experiment-name myexperiment --run-id myrunid --tag area=qna
使用 API 注册模型
有三种方法可以向 Azure 注册模型。
with mlflow.start_run(run_name=<run-name>) as run:
...
mlflow.<model-flavor>.log_model(<model-flavor>=<model>,
artifact_path="<model-path>",
registered_model_name="<model-name>"
)
要用某个特定的名称注册一个模型,在运行完所有实验之后,使用 mlflow.register_model()方法。
result=mlflow.register_model("runs:<model-path>", "<model-name>")
要创建一个具有惟一名称的新注册模型,您可以使用客户机 api 方法 create_registered_model()
client = MlflowClient()
result = client.create_registered_model("<model-name>")
3. MLFlow
MLFlow 是一个开源平台,用于管理您的机器学习模型生命周期。这是一个带有 API 的集中式模型库,以及一个可轻松管理 MLops 生命周期的 UI。它提供了许多特性,包括模型沿袭、模型版本化、生产到部署的转换以及注释。
- 使用名称、版本、部署阶段的 POC 和其他数据在模型注册中心注册模型。
- 版本控制功能可以让你在机器学习模型更新时跟踪它们的版本。
- 不同的模型版本可以在特定的时间分配一个阶段,它提供了一个预定义的模型阶段。它可用于不同的阶段,如准备、生产或存档。
- 自动记录转变度量、事件或对您的机器学习实验所做的更改。
- 注释和模型描述,您可以注释顶级模型和任何对其他团队成员有用的描述或信息。例如,算法信息或数据集信息。
- MLFlow 允许您查看并更改作为 CI/CD 管道一部分的每个阶段转换,以实现更好的治理和监控。
MLFlow 模型注册工作流程
您可以通过 UI 或 API 访问模型注册中心。如果您运行自己的服务器,则必须使用数据库支持的存储来访问 MLFlow 模型注册表。
UI 工作流程
- 进入 MLFlow details 部分的工件页面,注册模型。
- 在 Model name 字段中添加一个新模型,确保您为它提供了一个唯一的名称,否则您可以选择您的现有模型。
- 现在您的模型已经注册,您可以通过进入注册的模型部分查看模型的详细信息。
- 每个模型都有一个细节部分,其中显示了所有活动版本。
- 只需从下拉菜单中进行选择,您就可以将模型阶段从准备阶段更改为生产阶段。
API 工作流程
API 工作流是使用模型注册表的另一种方法。您可以在 MLflow 实验运行期间或所有实验运行之后注册模型。
with mlflow.start_run(run_name="YOUR_RUN_NAME") as run:
params = {"n_estimators": 5, "random_state": 42}
sk_learn_rfr = RandomForestRegressor(**params)
mlflow.log_params(params)
mlflow.log_param("param_1", randint(0, 100))
mlflow.log_metrics({"metric_1": random(), "metric_2": random() + 1})
mlflow.sklearn.log_model(
sk_model=sk_learn_rfr,
artifact_path="sklearn-model",
registered_model_name="sk-learn-random-forest-reg-model"
)
- 从注册表获取 MLFlow 模型
model_name = "sk-learn-random-forest-reg-model"
model_version = 1
model = mlflow.pyfunc.load_model(
model_uri=f"models:/{model_name}/{model_version}"
)
model.predict(data)
- 从注册表提供 MLflow 模型
export MLFLOW_TRACKING_URI=http://localhost:5000
mlflow models serve -m "models:/sk-learn-random-forest-reg-model/Production"
- 更新您的模型信息/描述
client = MlflowClient()
client.update_model_version(
name="sk-learn-random-forest-reg-model",
version=1,
description="This model version is a scikit-learn random forest containing 100 decision trees"
)
模型注册中心有什么问题吗?
大多数模型注册中心,包括我们在这里讨论的,都是灵活的,并且易于与其他 MLOps 框架一起使用。但是,并不是每个平台都会满足你所有的机器学习实验需求。
- MLFlow 没有添加用户权限的选项,有时当您处于部署阶段时,事情会变得很棘手。
- 在 Azure ML 和 Neptune 中,日志记录更加容易和无缝,有时当您有更多的实验要运行时,MLFlow UI 会变得滞后。同时,Sagemaker 使用 Cloudwatch 来记录指标,而 cloud watch 和指标可视化在 sage maker 中不太受欢迎。
- MLFlow 中不允许进行实验分析的跟踪,而 Neptune 和 Azure 提供了无缝的跟踪体验。
下面是我们讨论的工具之间的表格比较:
天蓝色* | 海王星 | MLFlow | |
---|---|---|---|
笔记本和数据版本
| | | |
| | | | |
| | | | |
| | | | |
|
监控模型性能
| | | |
| | | | |
| | | | |
| |
免费试用,
|
个人免费,
团队有偿
| |
*Azure 机器学习工作室
无论您使用什么平台,模型注册都将帮助您加快推广过程,使您的 ML 实验易于管理,并使协作更容易。它将为您的团队创建一个无缝的移交,增加安全性和治理。每个平台都有自己的特点,取决于你的需要和你想如何跟踪所有的 ML 实验,你可以选择免费试用。这是了解哪个平台适合您的机器学习实验并帮助您推进部署的好方法。
额外研究和推荐阅读*
如何解决 MLOps 堆栈的模型服务组件
原文:https://web.archive.org/web/https://neptune.ai/blog/model-serving-component-mlops-stack
模型服务和部署是 MLOps 体系的支柱之一。在本文中,我将深入探讨这个问题,并讨论模型服务的基本、中级和高级设置。
让我们从一些基础知识开始。
什么是 ML 模型服务?
训练机器学习模型似乎是一项伟大的成就,但在实践中,它甚至还没有实现商业价值。为了让机器学习计划取得成功,我们需要部署该模型,并确保它满足我们的性能和可靠性要求。你可能会说,“但是我可以把它打包成一个 Docker 映像,然后就完事了”。在某些情况下,这可能已经足够了。但大多数时候,不会。当人们谈论生产 ML 模型时,他们使用术语服务而不是简单的部署。那么这意味着什么呢?
服务一个模型就是将它暴露给现实世界,并确保它满足您的所有生产需求,也就是说,您的延迟、准确性、容错和吞吐量都处于“业务愉快”的水平。仅仅将模型打包到 Docker 映像中并不是“解决方案”,因为您仍然需要考虑如何运行模型、缩放模型、部署新的模型更新等等。不要误会我的意思,有一个时间和地点的 Flask-server-in-Docker-image 服务风格;它只是针对有限数量的用例的有限工具,我将在后面概述。
现在我们知道了服务意味着什么,让我们开始吧。
模型服务场景
在决定如何为我们的 ML 模型服务时,我们必须问自己几个问题。回答这些问题应该有助于我们塑造服务于架构的模型。
我们的模型是面向用户的吗?
换句话说,用户是否通过某个动作触发它,并且需要实时查看依赖于我们的模型输出的效果?如果这听起来太抽象,举个例子怎么样?我们是否正在创建一个类似 Gmail 的电子邮件自动完成解决方案?我们的用户写了一些文本,并期待一个相关的完成。这种场景需要“交互式”部署。这可能是最常见的服务 ML 模型的方式。但这不是唯一的方法。
假设我们现在不需要模型的预测。为了得到我们需要的东西,我们甚至可以等上一个小时或更久。我们需要多久才能得到这些预测?我们是否需要像每周 excel 报告或每天标记一次库存项目描述这样的东西?如果这听起来差不多,我们可以运行一个“批处理”过程来服务我们的模型。这种设置可能是最容易维护和扩展的。但是还有第三条路。
延迟很重要吗?
你不需要“回应”用户,但仍然必须根据用户的动作来行动。类似于用户交易触发的欺诈检测模型。这个场景要求一个“流”设置。像这样的场景通常被认为是最复杂的。尽管听起来交互式设置更难构建,但流式传输通常更难推理,因此也更难正确实现。
让我们深入了解每种设置的细节、使用它们的最佳时间以及权衡。
模型部署设置
当涉及到向外界公开 ML 模型以供消费时,我们应该基于我们的业务需求考虑一些通用的“设置”。
批量模型服务
这是所有可能的设置中最容易实现和操作的。批处理不是交互式的,也就是说,它们不等待与另一个用户或进程的交互。他们只是跑,开始到结束。正因为如此,大多数情况下没有延迟需求;它只需要能够扩展到大型数据集。
由于这种延迟不敏感,您可以使用复杂的模型-类似 Kaggle 的集合,巨大的梯度增强树或神经网络,任何事情都可以,因为预计这些操作无论如何都不会在毫秒内完成。要处理甚至数百 GB 的数据集,您需要的只是 CRON 之类的东西,一个工作站/一个相对强大的云 VM,并知道如何开发核外数据处理脚本。不相信我?这里有一个用视频来证明我的观点的例子。
如果您需要处理数 TB 的数据,这将变得更具挑战性。您将需要处理多节点 Apache Spark、Apache Airflow 或类似的东西。您必须考虑潜在的节点故障,以及如何最大化这些节点的资源利用率。
最后,如果你在谷歌大小的数据集上操作,检查这个链接。以这样的规模运营会带来诸如“喋喋不休的邻居”、分散的任务/工作、“雷鸣般的牛群”和时区等问题。是啊,祝贺你的巨大规模。
流式模型服务
正如我们已经提到的,批处理不是唯一不需要等待用户交互的,也就是说,它们不是交互式的。我们也可以让我们的模型作用于数据流。这些场景比批处理对延迟更加敏感。
用于流模型服务的标准工具是 Apache Kafka、Apache Flink 和 Akka。但是如果您需要将您的模型作为一个流/事件驱动的基础设施组件来操作,这些并不是您唯一的选择。您可以创建一个组件,一方面作为事件的消费者,另一方面作为生产者。无论你做什么,都要注意反压力。流设置非常关心能够处理大量连续流动的数据,所以一定不要让您部署的 ML 模型成为该设置的瓶颈。
开发流式 ML 服务解决方案时要考虑的另一件事是模型序列化。大多数流式事件处理系统都是基于 JVM 的,要么是 Java,要么是 Scala 原生的。因此,您可能会发现您的模型结构受到了序列化程序能力的限制。关于模型序列化如何成为一个问题的故事,请查看本文的小节——生成的模型部署起来可能会很乏味。
以下是一些关于这个主题的有用链接:
交互式模型服务
服务 ML 模型最流行的方式——使用服务器!事实上,很多人在讨论 ML 服务时,指的是这个特定的设置,而不是这三个中的任何一个。交互式设置意味着用户以某种方式触发一个模型,并等待输出或由输出引起的某些东西。基本上,这是一种请求-响应交互模式。
在这种情况下,有许多方法可以为 ML 模型提供服务。从带有内存加载 ML 模型的 Flask 或 FastAPI 服务器到专门的解决方案,如 TF Serving 或 NVIDIA Triton,以及任何介于两者之间的解决方案。在本文中,我们将主要关注这种设置。
我见过有人开发批处理解决方案,其中 ML 组件实际上是由所述批处理程序调用的服务器。或者调用服务于 ML 模型的 HTTP 服务器的流式事件处理系统中的组件。作为一种灵活的、推理起来相当简单的、有良好文档记录的方法,许多人正在“滥用”交互模式。
关于云、边缘和客户端服务的说明
如果我们正在开发一个移动应用程序,并希望我们的 ML 功能在没有互联网的情况下也能工作,该怎么办?如果我们想为用户提供神奇的响应能力呢?让在网页上等待回应成为过去。输入客户端服务和边缘服务 ML。
需要考虑的事项
当设计 ML 系统时,我们需要意识到这种可能性和这种部署场景的挑战。
- 使用 TF.js 、 ONNX 在浏览器客户端上部署特别简单,尽管有点复杂。
- 至于移动,我们有多个变种,包括苹果的 CoreML ,谷歌的 TFLite ,以及 ONNX 。
- 对于边缘设备,根据它们的计算性能,我们可以像在云中一样运行 ML 模型,也可以创建定制的 TinyML 解决方案。
注意,理论上,浏览器和智能手机都是边缘设备。实际上,由于编程模型大相径庭,它们受到不同的对待。通常情况下,边缘服务器是传统的计算机,要么运行在 ARM 上,要么运行在 x86 硬件上,使用传统的操作系统,只是在网络方面更接近用户。移动设备需要不同的编程,因为移动和更常见的操作系统之间有很大的差异。最近,移动设备拥有专门的 DSP 或协处理器,为人工智能推理进行了优化。
浏览器甚至更不同,因为浏览器代码通常是围绕沙箱环境和事件循环的思想构建的。最近,我们有了 web workers,这使得创建多进程应用程序变得更加容易。此外,当在浏览器中提供 ML 模型时,我们不能对模型将在其上运行的硬件做出任何假设,从而导致潜在的可怕的用户体验。很可能是用户在低端移动设备上用 ML 模型打开了我们的 web 应用程序。想象一下这个网站会有多滞后。
权衡取舍
将 ML 服务移近边缘可能有多种原因。通常的动机是延迟敏感性、带宽控制、隐私问题和离线工作的能力。请记住,我们可以有各种分层部署目标,从用户的客户端设备到离用户最近的物联网集线器或路由器,再到城市或区域范围的数据中心。
在边缘设备或客户端设备上部署通常会牺牲模型大小和性能来降低网络延迟或大幅降低带宽。例如,在手机上部署一个自动人脸识别和分类的模型可能不是一个好主意,但一个微小而简单的模型可以检测场景中是否有人脸。这同样适用于自动电子邮件响应生成器和自动完成键盘模型。前者通常不需要安装在设备上,而后者必须安装在设备上。
在实践中,可以将边缘/设备上的模型与云部署的模型混合使用,以便在在线时获得最大的预测性能,但在离线时也有可能保留一些人工智能功能。这主要可以通过编写自定义代码来完成,但如果您的边缘设备能够运行 KubeEdge,也可以使用类似于 Sedna 的东西来运行 KubeEdge 。
真实世界的用例
在 edge 上部署的一个常见但较少讨论的场景是,一家零售商希望在其杂货店中使用视频分析。他们开发了一套强大的计算机视觉模型来分析来自店内摄像头的视频,但遇到了一个硬约束。互联网提供商无法确保上传延迟,并且他们所在位置的带宽无法支持多个视频流。
解决办法?他们在每家商店购买了一台游戏电脑,放在员工房间,在本地进行视频分析,而不需要从商店传输视频。是的,这是一个边缘 ML 场景。边缘计算不仅仅是物联网。
以正确的方式为机器学习模型服务
ML 模型服务与元数据存储、ML 模型注册、监控组件和特性存储有着紧密的关系。那是相当多的。另外,根据具体的组织需求,模型服务可能必须与 CI/CD 工具集成。可能需要确保一个试运行环境来测试新训练的模型,或者甚至持续部署到生产环境中,最有可能作为影子或金丝雀部署。
End-to-end MLOps architecture and workflow with functional components and roles | Source
什么使模型部署变得好?
请记住,一个好的模型服务解决方案不仅要考虑成本效益和延迟,还要考虑它与堆栈其余部分的集成程度。如果我们有一个高性能的服务器,集成我们的可观察性、特征存储和模型注册是一场噩梦,那么我们就有一个糟糕的模型服务组件。
-
实现整个模型部署/服务工作流的一种常见方式是让模型服务组件基于来自 ML 模型注册中心和/或元数据存储的信息来获取具体的模型。
- 比如使用 Neptune.ai 这样的工具,我们可以追踪多个实验。在某种程度上,如果我们决定我们有一个好的候选模型,我们将它标记为一个准备就绪的模型/金丝雀。记住,我们还在和 Neptune.ai 交互,不需要使用任何其他工具。我们的 ML 服务组件定期向 ML 模型注册中心登记,如果有带有兼容标签的新模型,它将更新部署。这种方法允许更易访问的模型更新,而不会触发映像构建或其他昂贵而复杂的工作流。
- 另一种方法是重新部署一个预构建的服务组件,并且只更改其配置来获取一个更新的模型。这种方法在云本地(Kubernetes)服务解决方案中更常见。
-
当然,如前所述,模型服务组件经常需要与特征库进行交互。为了与特性库进行交互,我们不仅需要能够服务于序列化的 ML 模型,还需要支持定制的支持 IO 的组件。在某些情况下,这可能是一场噩梦。一种解决方法是在应用服务器级别集成特性存储,而不是在 ML 服务组件级别。
-
最后,我们还需要记录和监控我们部署的 ML 模型。许多定制解决方案都集成了工具,如用于日志的 ELK stack ,用于跟踪的 OpenTelemetry ,以及用于度量的 Prometheus 。不过,ML 确实带来了一些特殊的挑战。
在服务 ML 模特的时候,我们真正在意的是什么?
除了常见的疑点——尾部延迟、每秒请求数和应用程序错误率,还建议跟踪模型性能。这是棘手的部分。几乎不可能实时或在短时间内获得真实标签。如果延迟显著,则需要更长时间来确定影响用户体验的问题。
正因为如此,跟踪输入和输出的分布,并在它们明显偏离模型预期时触发一些动作是很常见的。虽然这很有用,但它对跟踪我们的预测性能 SLO(服务级别目标)没有太大帮助。
跟踪性能的问题
让我解释一下,一方面,我们可以合理地假设输入和输出分布的差异会导致性能下降,但另一方面,我们实际上并不知道两者之间的确切关系。
我们可以有这样的场景,其中特征的分布偏离预期分布很多,但是对我们的 ML 模型性能没有显著影响。在这种情况下,我们会有一个错误的警报。但是这些关系会随着时间而改变。因此,下一次,当相同的特征再次漂移时,它会导致我们的 ML 模型的预测能力的显著损失。你可以想象,这是一场噩梦。那么能做些什么呢?
解决方案–检测和缓解
我们部署和更新 ML 模型以改善我们的业务。理想情况下,我们必须将我们的模型 SLO 与业务指标“联系”起来。例如,如果我们注意到点击我们推荐的用户比率下降,我们知道我们做得不好。对于文本自动校正解决方案,类似的商业衍生模型 SLO 可以是被接受建议的比率。如果它低于某个阈值,也许我们的模型并不比之前的好。遗憾的是,这并不总是这么容易做到。
因为这个问题非常棘手,我们通常将 ML 模型性能监控提取到一个单独的组件中,并且只跟踪 ML 服务组件级别的系统级度量、跟踪和日志。我们希望,随着 ML 模型监控的基础设施变得更好,ML 服务组件将提供与这些工具更好的集成,从而使部署模型的故障排除变得更加容易。
从基本到完全开发的模型服务设置
因为交互式服务设置是生产 ML 模型最流行的方式,我们将讨论基本、中级和高级设置是什么样子的。一个好的设置和一个普通的设置的区别在于成本效益、可伸缩性和延迟情况。当然,与 MLOps 堆栈的其余部分集成也很重要。
模型服务:基本设置
回想一下,在文章的开头,我提到过 ML-model-in-Flask-server-in-a-Docker-container 式的服务是有时间和地点的。关于这种服务已经说了很多,所以我就不赘述了。请注意,ML 模型既可以放在容器中,也可以作为卷附加。如果你只是创建一个演示 API,或者你确实知道你不会有很多流量(可能是一个内部应用,只有 3-5 个人会使用),这可能是一个可以接受的解决方案。
或者,如果您可以为多个非常强大的云虚拟机配置强大的 GPU 和 CPU,并且不担心资源利用率低和尾部延迟次优,那么它也可以工作。我的意思是,脸书为他们的软件做了很少的测试,并且仍然设法成为一个巨大的科技公司,所以遵循所有的软件工程最佳实践可能并不总是有意义的。
赞成的意见
- 这种设置的优点是非常容易实现并且相对可伸缩(需要处理更多的请求= >运行多个副本)。
骗局
- 最大的问题是资源利用率低,因为模型在每次请求单个输入条目时都会被触发,而且 web 服务器不需要与 ML 模型相同的硬件。
- 此外,对尾部延迟的控制严重不足,这意味着您无法通过这种设置实施几乎任何 SLO。控制尾部延迟的唯一希望是一个好的负载平衡器和足够强大的机器来运行 ML 服务组件的多个副本。
Simple ML serving with a replicated container. The ML model can be either backed in or attached as a volume | Source: Author
为了改进这种设置,我们必须转向中级配置。
模型服务:中间设置
如上所述,我们需要将 ML 推理从应用服务器组件中分离出来,以优化资源利用并更好地控制我们的延迟。一种方法是使用发布者-订阅者异步通信模式,例如用 ZeroMQ 或 Redis PubSub 实现。
因此,在这种“分裂”之后,我们可以做许多很酷的技巧来完善我们的服务组件,使之成为一个高级组件。
- 首先,我们可以实施更精细的超时和重试。有了这样的设置,就有可能独立于应用服务器来扩展 ML 服务器。
- 然后,最神奇的方法是做自适应批处理。事实上,这是一项非常棒的技术,它将使解决方案在性能方面几乎达到高级水平。
一个好的模型服务解决方案不仅仅在于服务器性能有多好,还在于集成 ML 子系统的其他部分有多容易。机器学习服务组件将需要提供至少一些模型管理能力,以便容易地更新模型版本,而不需要重新构建整个系统。对于这种类型的设置,ML/MLOps 团队可以设计他们的 ML workers 来定期检查模型注册,如果有任何更新,获取新的模型,类似于 this 。
A medium ML serving blueprint, with both replicated application servers and ML servers. The solution also uses a feature store and a model registry | Source: Author
我相信你已经注意到中等设置比基本设置要复杂得多。这种复杂性给这种方法带来了很大的缺点。在这个阶段,需要某种形式的容器编排,通常是 K8s,至少需要某种系统可观察性,例如,Prometheus 和 ELK。
模型服务:高级设置
公平地说,对于大多数 ML 服务场景,中等水平的设置就足够了。你不应该认为先进的 ML 服务设置是上一个设置的必要发展。高级设置更像“重炮”,只有在特殊情况下才需要。
在上面的解决方案中提出了所有的花里胡哨,一个问题出现了——“如果有现成的解决方案,我们为什么要为所有这些技巧费心呢?”。事实上,为什么呢?答案通常是——他们需要为他们的设置定制一些东西。
像 NVIDIA Triton、Tensorflow Serving 或 TorchServe 这样的专业解决方案有坚实的卖点,也有相当弱的卖点。
赞成的意见
- 首先,这些服务解决方案经过了很好的优化,通常比“中等+花哨”的解决方案表现得更好。
- 其次,这些解决方案易于部署;大多数提供一个码头集装箱或舵图。
- 最后,这些解决方案通常包含对模型管理和 A/B 测试的相对基本的支持。
骗局
- 现在是不利的一面。最大的一个问题是与 MLOps 生态系统的其他部分的尴尬集成。
- 其次,与第一点相关,这些解决方案很难扩展。解决这两个问题最方便的方法是创建定制的应用服务器,作为高性能预构建 ML 服务器的代理/装饰者/适配器。
- 第三,这可能是我个人不喜欢的一点,就是这些解决方案在可以部署什么模型方面非常有限。我想保留我的选择,拥有一个只接受 TF SavedModels 或 ONNX-serialized 的服务解决方案与我的价值观不一致。是的,甚至 ONNX 也有局限性,例如,当您有一个定制模型(参见小节——生成的模型部署起来可能很繁琐)时,它使用了 ONNX 不支持的操作。
您可能已经猜到了,我在大多数情况下并不使用这些解决方案。我更喜欢 PyTorch,所以 TF 发球对我来说是不可行的。注意,这只是我的上下文。如果用 TF,可以考虑用 TF 发球。几年前我在一个 TF 项目中尝试过。如果你问我的话,这对于服务来说很好,但是对于模型管理来说有点麻烦。
我说我主要用 PyTorch,所以也许 TorchServe?坦率地说,我甚至没有尝试过。看起来不错,但是恐怕它和 TF 上菜有同样的模型管理问题。海卫一呢?我可以说它的老版本,TensorRT 推理服务器。这是一个噩梦,配置,然后发现,因为一个定制的模型头,它不能得到适当的服务。再加上模型量化问题,再加上与前两个候选人相同的模型版本管理的困境…公平地说,我听说它变得更好了,但我仍然非常怀疑它。因此,除非我知道我的模型架构没有改变,并且我需要最大可能的性能,否则我不会使用它。
Adaptive batching as a way to more efficiently use ML models | Source
总之,像 NVIDIA Triton 或 Tensorflow Serving 这样的专业解决方案是强大的工具,但如果您选择使用它们,您最好有严重的性能需求。否则,我建议不要这样做。但这还不是全部——
-
即使这些解决方案功能丰富、性能卓越,它们仍然需要大量的支持基础设施。这样的服务器最适合作为 ML 工作者,所以您仍然需要应用服务器。为了拥有一个真正先进的 ML 服务组件,你需要考虑与其他系统的紧密集成,ML 和数据的可观察性,定制或使用像 Arize 和 Montecarlo 这样的服务。
-
此外,您需要能够执行高级流量管理。上面提到的系统为 A/B 测试提供了一些有限的支持。尽管如此,在实践中,您必须以不同的方式实现它,要么在应用服务器级别实现更细粒度的控制,要么在基础设施级别使用像 Istio 这样的工具。您通常需要能够支持新模型的逐步推出、金丝雀部署和流量阴影。没有现有的预建服务系统提供所有这些业务模式。如果你想支持这些,准备好弄脏你的手和白板。
关于 MLOps 云产品的说明
TL;DR: 云产品为您提供“全生命周期”解决方案,这意味着模型服务与数据集管理、培训、超参数调整、监控和模型注册的解决方案相集成。
云产品试图为您提供简单的基本设置,丰富的高级设置功能和中等设置的性能。对我们大多数人来说,这是一笔了不起的交易。
云产品的共同优势是无服务器和自动扩展推理,以及 GPU 和/或特殊芯片支持。
- 以谷歌的 Vertex AI 为例。它们为您提供完整的 MLOps 体验和相对简单的模型部署,可以作为云功能或自动缩放容器,甚至作为批处理作业。因为是谷歌,他们有 TPU,这对于真正大规模的部署来说很方便。
- 或者,如果有更完整的解决方案,可以使用 AWS。他们的 SageMaker 就像 Vertex AI 一样,在整个 MLOps 生命周期中为您提供帮助。尽管如此,它也增加了一种简单而具有成本效益的方式来运行模型,以便用弹性推理加速器进行推理,这些加速器似乎是分数 GPU,可能通过英伟达的安培代 MIGs,或使用一种称为推理的定制芯片。更好的是,SageMaker 允许对目标硬件进行训练后模型优化。
然而,两者都没有提供自适应批处理、某种形式的推测性执行/请求对冲或其他高级技术。根据您的 SLO,您可能仍然需要使用 NVIDIA Triton 等系统或开发内部解决方案。
结论
在生产中运行 ML 可能是一项艰巨的任务。要真正掌握这一点,必须针对许多目标进行优化——成本效率、延迟、吞吐量和可维护性,等等。如果你能从这篇文章中得到什么,那就让它成为这三个想法:
- 为您的 ML 模型服务时,要有明确的目标和优先顺序
- 让业务需求和约束驱动您的 ML 服务组件架构,而不是相反。
- 将模型视为更广泛的 MLOps 堆栈中的一个组件。
有了这些想法,您应该能够从好的解决方案中筛选出不合格的 ML 服务解决方案,从而最大化对您的组织的影响。但是不要犯从一开始就试图把一切都做好的错误。尽早开始服务,迭代您的解决方案,让本文中的知识帮助您更好地完成最初的几次迭代。部署一般的东西总比什么都不部署好。
参考
8 位创作者和核心贡献者谈论他们来自 PyTorch 生态系统的模型训练库
原文:https://web.archive.org/web/https://neptune.ai/blog/model-training-libraries-pytorch-ecosystem
雅各布·查肯
大部分是 ML 的人。构建 MLOps 工具,编写技术资料,在 Neptune 进行想法实验。
我在 2018 年初使用 py torch 0 . 3 . 1 版本开始训练我的模型。我被 Pythonic 的手感、易用性和灵活性深深吸引。
在 Pytorch 中做事情要比在 Tensorflow 或 Theano 中容易得多。但是我错过的是 PyTorch 的类似 Keras 的高级接口,当时还没有太多。
快进到 2020 年,我们在 PyTorch 生态系统中有 6 个高级培训 API。
- 但是你应该选择哪一个呢?
- 每一种使用的利弊是什么?
我想:谁能比作者自己更好地解释这些库之间的差异呢?
我拿起我的手机,请他们和我一起写一篇文章。他们都同意,这就是这个职位是如何创建的!
所以,我请作者们谈谈他们图书馆的以下几个方面:
- 项目理念
- API 结构
- 新用户的学习曲线
- 内置功能(开箱即用)
- 扩展能力(研究中集成的简单性)
- 再现性
- 分布式培训
- 生产化
- 流行
…他们确实回答得很透彻🙂
可以跳转到自己感兴趣的库或者直接到最后我的主观对比。
斯科奇发展背后的理念可以总结如下:
- 遵循 sklearn API
- don’t hide PyTorch
- 不要多此一举
- 可以被黑客攻击
这些原则规划了我们的设计空间。关于 scikit-learn API ,它最明显的表现在你如何训练和预测:
from skorch import NeuralNetClassifier
net = NeuralNetClassifier(...)
net.fit(X_train, y_train)
net.predict(X_test)
因为 skorch 正在使用这个简单且完善的 API ,所以每个人都应该能够很快开始使用它。
但是 sklearn 的整合比“适应”和“预测”更深入。您可以将您的 skorch 模型无缝集成到 sklearn 的“Pipeline”中,使用 sklearn 的众多指标(无需重新实现 F1、R 等。),并配合GridSearchCV
使用。
说到参数扫描:你可以使用任何其他的超参数搜索策略,只要有一个 sklearn 兼容的实现。
我们特别自豪的是你可以搜索几乎任何超参数,而不需要额外的工作。例如,如果您的模块有一个名为num_units
的初始化参数,您可以立即对该参数进行网格搜索。
这里有一个的列表,你可以用网格搜索现成的:
- 您的
Module
上的任何参数(单元和层数、非线性度、辍学率等) - 优化器(学习率、动力……)
- 标准
DataLoader
(批量大小,洗牌,…)- 回调(任何参数,甚至是自定义回调)
这是它在代码中的样子:
from sklearn.model_selection import GridSearchCV
params = {
'lr': [0.01, 0.02],
'max_epochs': [10, 20],
'module__num_units': [10, 20],
'optimizer__momentum': [0.6, 0.9, 0.95],
'iterator_train__shuffle': [True, False],
'callbacks__mycallback__someparam': [1, 2, 3],
}
net = NeuralNetClassifier(...)
gs = GridSearchCV(net, params, cv=3, scoring='accuracy')
gs.fit(X, y)
print(gs.best_score_, gs.best_params_)
据我所知,没有其他框架提供这种灵活性。最重要的是,通过使用 dask 并行后端,您可以 将超参数搜索 分布到您的集群中,而不会有太多麻烦。
使用成熟的 sklearn API,skorch 用户可以避免在纯 PyTorch 中编写训练循环、验证循环和超参数搜索时常见的样板代码。
从 PyTorch 方面来说,我们决定不像 keras 那样将后端隐藏在抽象层之后。相反,我们公开了 PyTorch 的众多组件。作为用户,你可以使用 PyTorch 的Dataset
(想想 torchvision,包括 TTA)DataLoader
,和学习率调度器。最重要的是,你可以不受限制地使用 PyTorch Module
s。
因此,我们有意识地努力尽可能多地重用 sklearn 和 PyTorch 的现有功能,而不是重新发明轮子。这使得 skorch 易于在你现有的代码库上使用,或者在你最初的实验阶段后移除它,而没有任何锁定效应。
例如,您可以用任何 sklearn 模型替换神经网络,或者您可以提取 PyTorch 模块并在没有 skorch 的情况下使用它。
在重用现有功能的基础上,我们添加了一些自己的功能。最值得注意的是,skorch 可以开箱即用地处理许多常见的数据类型。除了Dataset
s,您还可以使用:
- numpy 数组,
- 火炬张量,
- 熊猫,
- 保存异构数据的 Python 字典,
- 外部/自定义数据集,如 torchvision 的 ImageFolder。
我们已经付出了额外的努力来使这些与 sklearn 一起很好地工作。
此外,我们实现了一个简单而强大的回调系统,你可以用它来根据你的喜好调整 skorch 的大部分行为。我们提供的一些回调包括:
- 学习率调度程序,
- 评分功能(使用自定义或 sklearn 指标),
- 提前停车,
- 检查点,
- 参数冻结,
- 以及 TensorBoard 和 Neptune 集成。
如果这还不足以满足您的定制需求,我们尽力帮助您实施自己的回访或您自己的模型培训师。我们的文档包含了如何实现定制回调和定制训练者的例子,修改每一个可能的行为直到训练步骤。
对于任何熟悉 sklearn 和 PyTorch 的人来说,不重新发明轮子的哲学应该使 skorch 易于学习。由于我们围绕定制和灵活性设计了 skorch,因此应该不难掌握。要了解更多关于 skorch 的信息,请查看这些示例和笔记本。
sko rch面向生产并用于生产。我们讨论了一些关于生产化的常见问题,特别是:
- 我们确保是向后兼容的,并在必要时给出足够长的折旧期。
- 可以在 GPU 上训练,在 CPU 上服务,
- 你可以腌制一整只包含 skorch 模型的 sklearn
Pipeline
以备后用。 - 我们提供了一个助手函数来 将您的训练代码转换成命令行脚本 ,它将您的所有模型参数,包括它们的文档,作为命令行参数公开,只需要三行额外的代码
也就是说,我已经实现了,或者知道有人已经实现了,更多的研究 -y 的东西,像 GANs 和无数类型的半监督学习技术。不过,这确实需要对 skorch 有更深入的了解,所以您可能需要更深入地研究文档,或者向我们寻求 github 的指导。
就我个人而言,我还没有遇到任何人使用 skorch 进行强化学习,但我想听听人们对此有什么体验。
自从我们在 2017 年夏天首次发布 skorch 以来,该项目已经成熟了很多,并且围绕它已经发展了一个活跃的社区。在一个典型的星期里,github 上会打开一些问题,或者在 stackoverflow 上提出一个问题。我们会在一天之内回答大多数问题,如果有好的功能需求或 bug 报告,我们会尝试引导报告者自己实现它。
通过这种方式,在项目的整个生命周期中,我们有 20 多个贡献者,其中 3 个是常客,这意味着项目的健康不依赖于一个人。
fastai 说,skorch 和其他一些高级框架的最大区别是 skorch 不“包含电池”。这意味着,实现他们自己的模块或者使用许多现有集合中的一个(比如 torchvision)的模块取决于用户。斯科奇提供骨架,但你得带上肉。
何时不使用 skorch
- 超级自定义 PyTorch 代码,可能是强化学习
- 后端不可知代码(在 PyTorch、tensorflow 等之间切换)
- 根本不需要 sklearn API
- 避免非常轻微的性能开销
何时使用 skorch
- 获得 sklearn API 和所有相关的好处,如超参数搜索
- 大多数 PyTorch 工作流都能正常工作
- 避免样板文件,规范代码
- 使用上面讨论的许多实用程序中的一些
哲学
催化剂背后的想法很简单:
- 在一个框架中收集所有技术、开发、深度学习的东西,
- 使重复使用枯燥的日常组件变得容易,
- 在我们的项目中关注研究和假设检验。
为了实现这一点,我们研究了一个典型的深度学习项目,它通常具有以下结构:
for stage in stages:
for epoch in epochs:
for dataloader in dataloaders:
for batch in dataloader:
handle(batch)
想想看,大多数时候,您需要做的就是为新模型指定处理方法,以及如何将数据批量提供给该模型。那么,为什么我们把这么多时间花在实现流水线和调试训练循环上,而不是开发新东西或测试假设呢?
我们意识到有可能将工程与研究分开,这样我们就可以将我们的时间一次性投入到高质量、可重复使用的工程主干上在所有项目中使用它。
Catalyst 就是这样诞生的:一个开源的 PyTorch 框架,它允许你编写紧凑但功能齐全的管道,抽象工程样板文件,让你专注于项目的主要部分。
我们在 Catalyst 的任务。团队将使用我们的软件工程和深度学习专业知识来标准化工作流,并实现深度学习和强化学习研究人员之间的跨领域交流。
我们相信,开发摩擦的减少和思想的自由流动将导致未来数字图书馆的突破,这样的 R&D 生态系统将有助于实现这一目标。
学习曲线
Catalyst 可以被 DL 新手和经验丰富的专家轻松采用,这得益于两个 API:
- 笔记本 API ,它的开发重点是简单的实验和 Jupyter 笔记本的使用-开始你的可重复 DL 研究之路。
- Config API ,主要关注可伸缩性和 CLI 接口——即使在大型集群上也能发挥 DL/RL 的威力。
说到 PyTorch 用户体验,我们真的希望它尽可能简单:
- 您可以像平时一样定义加载器、模型、标准、优化器和调度器:
import torch
loaders = {"train": ..., "valid": ...}
model = Net()
criterion = torch.nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters())
scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer)
- 你把这些 PyTorch 对象传递给 Catalyst
Runner
from catalyst.dl import SupervisedRunner
logdir = "./logdir"
num_epochs = 42
runner = SupervisedRunner()
runner.train(
model=model,
criterion=criterion,
optimizer=optimizer,
scheduler=scheduler,
loaders=loaders,
logdir=logdir,
num_epochs=num_epochs,
verbose=True,)
在几乎没有样板文件的情况下,将工程与深度学习明确分离。这是我们觉得深度学习代码应该有的样子。
要开始使用这两种 API,你可以遵循我们的教程和管道或者如果你不想选择,只需检查最常见的:分类和分割。
设计和架构
关于 Notebook 和 Config API 最有趣的部分是它们使用了相同的“后端”逻辑–Experiment
、Runner
、State
和Callback
抽象,这是 Catalyst 的核心特性。
- 实验 : 包含实验信息的抽象——模型、标准、优化器、调度器以及它们的超参数。它还包含有关使用的数据和转换的信息。总的来说,实验知道你想要运行什么。
- Runner : 知道如何进行实验的类。它包含了如何运行实验、阶段(催化剂的另一个显著特征)、时期和批次的所有逻辑。
- 状态 : 实验和运行程序之间的一些中间存储,保存实验的当前状态——模型、标准、优化器、调度器、度量、记录器、加载器等
- 回调 : 一个强大的抽象,让你定制你的实验运行逻辑。为了给用户最大的灵活性和可扩展性,我们允许在训练循环的任何地方执行回调:
on_stage_start
on_epoch_start
on_loader_start
on_batch_start
on_batch_end
on_epoch_end
on_stage_end
on_exception
通过实现这些方法,您可以实现任何额外的逻辑。
因此,你可以在几行代码(以及 Catalyst 之后)中实现任何深度学习管道 。RL 2.0 版本-强化学习管道),从可用的原语中组合它(感谢社区,他们的数量每天都在增长)。
其他一切(模型、标准、优化器、调度器)都是纯 PyTorch 原语。Catalyst 不会在顶层创建任何包装器或抽象,而是让在不同框架和领域之间重用这些构件变得容易。
扩展能力/研究中集成的简单性
由于灵活的框架设计和回调机制,Catalyst 可以很容易地扩展到大量基于 DL 的项目。你可以在 awesome-catalyst-list 上查看我们的 Catalyst-powered 知识库。
如果您对强化学习感兴趣,也有大量基于 RL 的回购和竞争解决方案。来比较催化剂。使用其他 RL 框架,你可以查看开源 RL 列表。
其他内置特性(开箱即用)
知道你可以很容易地扩展它会让你感觉很舒服,但是你有很多现成的特性。其中一些包括:
- 基于灵活的回调系统,Catalyst 已经轻松集成了如常见的深度学习最佳实践,如梯度累积、梯度裁剪、权重衰减校正、top-K 最佳检查点保存、tensorboard 集成以及许多其他有用的日常深度学习实用程序。
- 由于我们的贡献者和贡献模块, Catalyst 可以访问所有最新的 SOTA 功能,如 AdamW、OneCycle、SWA、Ranger、LookAhead 和许多其他研究开发。
- 此外,我们整合了像 Nvidia apex、albuminations、 SMP 、 transformers 、wandb 和 neptune.ai 这样的流行库,让您的研究更加人性化。由于这样的集成,Catalyst 完全支持测试时间扩充、混合精度和分布式训练。
- 为了满足行业需求,我们还提供了对 PyTorch 跟踪的框架式支持,这使得将模型投入生产变得更加容易。此外,我们在每个版本中部署预定义的基于 Catalyst 的 docker 映像,以便于集成。
- 最后,我们支持针对模型服务—反应(面向行业)和实验监控—炼金术(面向研究)的额外解决方案。
一切都集成到库中,并涵盖了 CI 测试(我们有一个专用的 gpu 服务器)。感谢 Catalyst 脚本,您可以安排大量实验,并从命令行在所有可用的 GPU 上并行运行它们(查看 catalyst-parallel-run 了解更多信息)。
再现性
我们做了大量的工作,使你用催化剂运行的实验具有可再现性。由于基于库的确定性,基于 Catalyst 的实验是可重复的不仅在一个服务器上的服务器运行之间,而且在不同服务器和不同硬件部件(当然,使用 docker 封装)上的几次运行之间也是如此。感兴趣的话可以在这里看到实验。
而且,强化学习实验也是面向再现性的(就 RL 而言 RL 是可再现的)。例如,通过同步实验运行,由于采样轨迹的确定性,您可以获得非常接近的性能。这是众所周知的困难,据我所知催化剂有最可再生的 RL 管道。
为了实现 DL 和 RL 再现性的新水平,我们必须创造几个额外的功能:
- 完整的源代码转储:由于实验、运行器和回调抽象,保存这些原语以备后用非常容易。
- Catalyst 源代码包:有了这样的特性,即使使用 Catalyst 的开发版本,您也可以随时重现实验结果。
- 环境版本化: Catalyst 转储 pip 和 conda 包版本(稍后可用于定义您的 docker 映像)
- 最后,Catalyst 支持几个监控工具,如 Alchemy、Neptune.ai、Wandb,以存储您的所有实验指标和附加信息,从而更好地跟踪研究进度和再现性。
由于这些基于库的解决方案,您可以确保在 Catalyst 中实现的管道是可重复的,并且保存了所有实验日志和检查点以供将来参考。
分布式培训
基于我们的集成,Catalyst 已经有了对分布式培训的本地支持。此外,我们支持 Slurm 培训,并致力于更好地整合 DL 和 RL 管道。
生产化
既然我们知道 Catalyst 如何帮助深度学习研究,我们就可以谈论将训练好的模型部署到生产中。
正如已经提到的,Catalyst 支持开箱即用的模型跟踪。它允许您将 PyTorch 模型(使用 Python 代码)转换为 TorchScript 模型(集成了所有内容)。TorchScript 是一种从 PyTorch 代码创建可序列化和可优化模型的方法。任何 TorchScript 程序都可以从 Python 进程中保存,并在没有 Python 依赖的进程中加载。
此外,为了帮助 Catalyst 用户将其管道部署到生产系统中,Catalyst。团队有一个 Docker Hub ,带有预构建的基于 Catalyst 的映像(包括 fp16 支持)。
此外,为了帮助研究人员将他们的想法投入生产和现实世界的应用,我们创造了 Catalyst。生态系统:
- 反应 : 我们自己的 PyTorch 服务解决方案,具有同步/异步 API、批处理模式支持、quest,以及所有其他你可以从一个设计良好的生产系统中期待的典型后端。
- 炼金 : 我们的监控工具用于实验跟踪、模型对比、研究成果共享。
人气
自从 12 个月前第一次发布 pypi 以来,Catalyst 已经在 Github 上获得了 1.5k 颗星,超过 100k 次下载。我们很自豪成为这样一个开源生态系统的一部分,非常感谢我们所有的用户和贡献者的不断支持和反馈。
其中一个特别有帮助的在线社区是 ods.ai: 世界上最大的数据科学家和机器学习实践者的 slack 渠道之一(40k+用户)。没有他们的想法和反馈,Catalyst 就不会有今天。
特别感谢我们的早期用户,
这一切都是值得的。
[Acknowledgments](/web/20220926085913/https://neptune.ai/blog/model-training-libraries-pytorch-ecosystem)
自从сcatalyst 开始发展以来,许多人以不同的方式影响了它。为了表达我的感激之情,我要向...表示我个人的谢意:
感谢所有这些支持,Catalyst 已经成为 Kaggle docker image 的一部分,被添加到 PyTorch 生态系统 中,现在我们正在开发我们自己的 DL R & D 生态系统以加速您的研究和生产需求。
阅读更多关于 Catalyst 的信息。生态系统,请查看我们的愿景和项目宣言。
最后,我们总是乐意帮助我们的催化剂。朋友:公司/初创公司/研究实验室,他们已经在使用 Catalyst,或者正在考虑将它用于他们的下一个项目。
感谢阅读,并…打破循环-使用催化剂!
何时使用催化剂
- 拥有灵活和可重用的代码库,没有样板文件。你希望与来自不同深度学习领域的其他研究人员分享你的专业知识。
- 使用 Catalyst.Ecosystem 提高您的研究速度
何时不使用催化剂
- 你才刚刚开始你的深度学习之路——从这个角度来说,低级 PyTorch 是一个很好的入门。
- 你想用一堆不可复制的技巧创建非常具体的、定制的管道🙂
注意:](https://web.archive.org/web/20220926085913/https://twitter.com/guggersylvain)
下面是关于将于 2020 年 7 月发布的 fastai 的版本 2。你可以在这里去回购,在这里查文件。
What follows is about the version 2 of fastai that will be released in July 2020. You can go to repo here and check the documentation here.
Fastai 是一个深度学习库,它提供:
从业者:有了可以快速便捷地提供标准深度学习领域最先进成果的高级组件,
- 研究人员:用可以混合搭配的低级组件来构建新的东西。
- 它的目标是在不牺牲易用性、灵活性或性能的情况下做到这两点。
得益于精心分层的架构,这成为可能。它以解耦抽象的形式表达了许多深度学习和数据处理技术的通用底层模式。重要的是,这些抽象可以用清晰简洁地表达出来,这使得 fastai 变得平易近人快速高效,同时也是深度可黑客化和可配置的。
一个高级 API 提供了可定制的模型和合理的默认值,它建立在一个由低级构建块构成的层级之上。
本文涵盖了该库功能的一个代表性子集。有关详细信息,请参见我们的 fastai 论文和文档。
API
当谈到 fastai API 时,我们需要区分高级和中级/低级 API。我们将在接下来的章节中讨论这两者。
高级 API
高级 API 对于初学者和主要对应用预先存在的深度学习方法感兴趣的从业者非常有用。
它为主要应用领域提供了简明的 API:
视觉,
- 文字,
- 扁平的
- 时间序列分析,
- 推荐(协同过滤)
- 这些API 基于所有可用信息选择智能默认值和行为。
例如,fastai 提供了一个 Learner
类,它集合了架构、优化器和数据,并且在可能的情况下自动选择一个合适的损失函数。
再举一个例子,一般来说,训练集应该洗牌,验证集不应该洗牌。fastai 提供了一个单独的 Dataloaders
类,该类自动构造验证和训练数据加载器,这些细节已经得到处理。
为了了解这些“清晰简洁的代码”原则是如何发挥作用的,让我们在牛津 IIT Pets 数据集上微调一个 imagenet 模型,并在单个 GPU 上几分钟的训练内实现接近最先进的精度:
这不是摘录。这是这项任务所需的所有代码行。每一行代码都执行一项重要的任务,让用户专注于他们需要做的事情,而不是次要的细节:
from fastai.vision.all import *
path = untar_data(URLs.PETS)
dls = ImageDataloaders.from_name_re(path=path, bs=64,
fnames = get_image_files(path/"images"), path = r'/([^/]+)_\d+.jpg$',
item_tfms=RandomResizedCrop(450, min_scale=0.75),
batch_tfms=[*aug_transforms(size=224, max_warp=0.),
Normalize.from_stats(*imagenet_stats)])
learn = cnn_learner(dls, resnet34, metrics=error_rate)
learn.fine_tune(4)
从库中导入所有必需的棋子。值得注意的是,这个库是经过精心设计的,以避免这些风格的导入搞乱名称空间。
from fastai.vision.all import *
将标准数据集从 fast.ai 数据集集合(如果之前没有下载)下载到一个可配置的位置,提取它(如果之前没有提取),并返回一个带有提取位置的pathlib.Path
对象。
path = untar_data(URLs.PETS)
设置Dataloaders
。注意项目级和批次级转换的分离:
dls = ImageDataloaders.from_name_re(path=path, bs=64,
fnames = get_image_files(path/"images"), pat = r'/([^/]+)_\d+.jpg$',
item_tfms=RandomResizedCrop(450, min_scale=0.75),
batch_tfms=[*aug_transforms(size=224, max_warp=0.),
Normalize.from_stats(*imagenet_stats)])
项 变换应用到 CPU 上的单个图像
- 批处理 变换应用到 GPU (如果可用)上的一个小批处理。
aug_transforms()
选择一组数据扩充。与 fastai 中的一贯做法一样,我们选择了一个适用于各种视觉数据集的默认设置,但如果需要,也可以进行完全定制。
创建一个Learner
,这个结合了一个优化器、一个模型和一个用于训练的数据。每个应用程序(视觉、文本、表格)都有一个定制的函数,创建一个Learner
,它能为用户自动处理任何细节。例如,在这个图像分类问题中,它将:
learn = cnn_learner(dls, resnet34, metrics=error_rate)
下载 ImageNet 预训练模型(如果还没有),
- 去掉模型的分类头,
- 用适合于这个特定数据集的报头来替换它,
- 设置适当的优化器、权重衰减、学习率等等
- 微调模型。在这种情况下,它使用 1 周期策略,这是最近用于训练深度学习模型的最佳实践,但在其他库中并不广泛可用。很多事情发生在
.fine_tune()
的引擎盖下:
learn.fine_tune(4)
退火学习率和动量,
- 在验证集上打印指标,
- 在 HTML 或控制台表格中显示结果
- 在每批之后记录损失和度量,等等。
- 如果有可用的 GPU,将会使用它。
- 当模型的主体被冻结时,它将首先训练头部一个时期,然后使用区别学习率微调给定的许多时期(这里是 4 个)。
- fastai 库的优势之一是 API 跨应用程序的一致性。
例如,使用 ULMFiT 对 IMDB 数据集上的预训练模型进行微调(文本分类任务)只需 6 行代码:
用户在其他领域得到非常相似的体验,比如表格、时间序列或推荐系统。一旦一个Learner
被训练,你可以用命令learn.show_results()
来探索结果。这些结果如何呈现取决于应用,在视觉中你得到的是带标签的图片,在文本中你得到的是汇总样本、目标和预测的数据框架。在我们的宠物分类示例中,您会看到类似这样的内容:
from fastai2.text.all import *
path = untar_data(URLs.IMDB)
dls = TextDataloaders.from_folder(path, valid='test')
learn = text_classifier_learner(dls, AWD_LSTM, drop_mult=0.5, metrics=accuracy)
learn.fine_tune(4, 1e-2)
在 IMDb 分类问题中,你会得到这样的结果:
另一个重要的高级 API 组件是数据块 API,,它是一个用于数据加载的表达性 API。这是我们所知的第一次尝试,系统地定义为深度学习模型准备数据所必需的所有步骤,并为用户提供一个混合搭配的食谱,用于组合这些片段(我们称之为数据块)。
下面是一个如何使用数据块 API 让 MNIST 数据集为建模做好准备的示例:
中低档 API
mnist = DataBlock(
blocks=(ImageBlock(cls=PILImageBW), CategoryBlock),
get_items=get_image_files,
splitter=GrandparentSplitter(),
get_y=parent_label)
dls = mnist.databunch(untar_data(URLs.MNIST_TINY), batch_tfms=Normalize)
在上一节中,您看到了如何使用具有大量开箱即用功能的高级 api 快速完成大量工作。然而,有些情况下,你需要调整或扩展已经存在的东西。
这就是中级和低级 API 发挥作用的地方:
中级 API 为这些应用中的每一个提供核心的深度学习和数据处理方法,
- 低级 API 提供了一个优化的原语库以及功能和面向对象的基础,允许中间层进行开发和定制。
- 可以使用
Learner
新型双向回调系统定制训练循环。它允许梯度、数据、损失、控制流和任何东西其他在训练期间的任何点被读取和改变。
使用回调来定制数值软件有着悠久的历史,今天几乎所有现代深度学习库都提供了这一功能。然而,fastai 的回调系统是我们所知的第一个支持完成双向回调所必需的设计原则的系统:
在训练的每一点都应该有回叫,这给了用户充分的灵活性。每个回调都应该能够访问训练循环中该阶段可用的每条信息,包括超参数、损耗、梯度、输入和目标数据等等;
- 每次回调都应该能够在使用这些信息之前的任何时候修改所有这些信息,
- 训练循环的所有调整(不同的调度器、混合精度训练、在 TensorBoard 、 wandb 、 neptune 或等效物、mix、过采样策略、分布式训练、GAN 训练……)都在回调中实现,最终用户可以将它们与自己的进行混合和匹配,从而更容易试验和进行消融研究。方便的方法可以为用户添加这些回调,使得混合精度的训练就像说的那样简单
或者在分布式环境中培训一样简单
learn = learn.to_fp16()
fastai 还提供了一个新的通用优化器抽象,允许用几行代码实现最近的优化技术,如 LAMB、RAdam 或 AdamW。
learn = learn.to_distributed()
多亏了将优化器抽象重构为两个基本部分:
stats ,跟踪并汇总梯度移动平均线等统计数据
- 步进器 ,它结合了统计数据和超参数,使用一些函数来“步进”权重。
- 有了这个基础,我们可以用 2-3 行代码编写 fastai 的大部分优化器,而在其他流行的库中,这需要 50 多行代码。
还有许多其他的中间层和低层 APIs】使得研究人员和开发人员可以在快速灵活的基础上轻松构建新方法。
这个图书馆已经在研究、工业和教学中广泛使用。我们已经用它创建了一个完整的,非常受欢迎的深度学习课程:程序员实用深度学习(最后一次迭代的第一个视频有 256k 的浏览量)。
在撰写本文时,库拥有 16.9k 恒星,并在超过 2000 个项目中使用。社区在 fast.ai 论坛上非常活跃,无论是澄清课程中不清楚的点,帮助调试还是合作解决新的深度学习项目。
何时使用 fastai
我们的目标是让一些东西对初学者来说足够简单,但对研究人员/从业者来说足够灵活。
- 何时不使用 fastai
我能想到的唯一一件事是,你不会使用 fastai 在生产中服务于你在不同框架中训练的模型,因为我们不处理那个方面。
- 维克多·福明 核心撰稿人
Pytorch Ignite 是一个高级库,帮助在 Pytorch 中训练神经网络。自 2018 年初以来,我们的目标一直是:
“让普通的事情变得容易,让困难的事情变得可能”。
为什么要使用 Ignite?
Ignite 的高抽象级别很少假设用户正在训练的模型类型或多个模型。我们只要求用户定义要在训练和可选验证循环中运行的闭包。它为用户提供了很大的灵活性,允许他们在任务中使用 Ignite,例如共同训练多个模型(即 gan)或在训练循环中跟踪多个损失和指标
点燃概念和 API
您需要了解 Ignite API 中的一些核心对象:
引擎 :精华库
- 事件&处理程序 :与
Engine
交互(如提前停止、检查点、日志记录) - 指标 :各种任务的现成指标
- 我们将提供一些基础知识来理解主要思想,但可以随意深入挖掘存储库中的示例。
引擎
它只是遍历提供的数据,执行一个处理函数并返回一个结果。
一个 Trainer
是一个Engine
,以模型的权重更新作为处理函数。
一个 Evaluator
(验证模型的对象)是一个以在线度量计算逻辑为处理功能的Engine
。
from ignite.engine import Engine
def update_model(trainer, batch):
model.train()
optimizer.zero_grad()
x, y = prepare_batch(batch)
y_pred = model(x)
loss = criterion(y_pred, y)
loss.backward()
optimizer.step()
return loss.item()
trainer = Engine(update_model)
trainer.run(data, max_epochs=100)
这段代码可以悄悄地训练一个模型,并计算总损失。
from ignite.engine import Engine
total_loss = []
def compute_metrics(_, batch):
x, y = batch
model.eval()
with torch.no_grad():
y_pred = model(x)
loss = criterion(y_pred, y)
total_loss.append(loss.item())
return loss.item()
evaluator = Engine(compute_metrics)
evaluator.run(data, max_epochs=1)
print(f”Loss: {torch.tensor(total_loss).mean()}”)
在下一节中,我们将了解如何使培训和验证更加用户友好。
事件&经手人
为了提高Engine
的灵活性,并允许用户在运行的每一步进行交互,我们引入了事件和处理程序。这个想法是,用户可以在训练循环内部执行一个自定义代码作为事件处理程序,类似于其他库中的回调。
在每次 fire_event 调用时,它的所有事件处理程序都会被执行。例如,用户可能希望在训练开始时设置一些运行相关变量(Events.STARTED
),并在每次迭代中更新学习率(Events.ITERATION_COMPLETED
)。使用 Ignite,代码将如下所示:
fire_event(Events.STARTED)
while epoch < max_epochs:
fire_event(Events.EPOCH_STARTED)
for batch in data:
fire_event(Events.ITERATION_STARTED)
output = process_function(batch)
fire_event(Events.ITERATION_COMPLETED)
fire_event(Events.EPOCH_COMPLETED)
fire_event(Events.COMPLETED)
处理程序(相对于“回调”接口)的酷之处在于,它可以是任何具有正确签名的函数(我们只要求第一个参数是 engine),例如 lambda、简单函数、类方法等。我们不需要从一个接口继承,也不需要覆盖它的抽象方法。
train_loader = …
model = …
optimizer = …
criterion = ...
lr_scheduler = …
def process_function(engine, batch):
trainer = Engine(process_function)
@trainer.on(Events.STARTED)
def setup_logging_folder(_):
@trainer.on(Events.ITERATION_COMPLETED)
def update_lr(engine):
lr_scheduler.step()
trainer.run(train_loader, max_epochs=50)
内置事件过滤
trainer.add_event_handler(
Events.STARTED, lambda engine: print("Start training"))
mydata = [1, 2, 3, 4]
def on_training_ended(engine, data):
print("Training is ended. mydata={}".format(data))
trainer.add_event_handler(
Events.COMPLETED, on_training_ended, mydata)
有些情况下,用户希望定期/一次性执行代码,或者使用自定义规则,如:
每 5 个时期运行一次验证,
- 每 1000 次迭代存储一个检查点,
- 在第 20 个时期改变一个变量,
- 在前 10 次迭代中记录梯度。
- 等等。
- Ignite 提供了这样的灵活性,将“要执行的代码”与逻辑“何时执行代码”分开。
例如,为了使每 5 个时期运行一次验证,只需简单编码:
类似地,为了在第 20 个时期改变一些训练变量一次:
@trainer.on(Events.EPOCH_COMPLETED(every=5))
def run_validation(_):
更一般地,用户可以提供自己的事件过滤功能:
@trainer.on(Events.EPOCH_STARTED(once=20))
def change_training_variable(_):
现成的处理程序
@trainer.on(Events.EPOCH_STARTED(once=20))
def change_training_variable(_):
Ignite 提供了一系列处理程序和指标来简化用户代码:
检查点 :保存训练检查点(由训练器、模型、优化器、lr 调度器等组成),保存最佳模型(按验证分数)
-
提前停止 : 如果没有进展(根据验证分数)则停止训练
-
终止南: 遇到南就停止训练
-
优化器参数调度: 串接,添加预热,设置线性或余弦退火,任意优化器参数的线性分段调度(lr,momentum,betas,…)
-
记录到通用平台:TensorBoard、Visdom、MLflow、Polyaxon 或 Neptune(批量损失、度量 GPU 内存/利用率、优化器参数等)。
-
指标
Ignite 还为各种任务提供了一个现成的指标列表:精度、召回率、准确度、混淆矩阵、IoU 等,大约 20 个回归指标
例如,下面我们计算验证数据集的验证准确度:
from ignite.metrics import Accuracy
def compute_predictions(_, batch):
return y_pred, y_true
evaluator = Engine(compute_predictions)
metric = Accuracy()
metric.attach(evaluator, "val_accuracy")
evaluator.run(val_loader)
> evaluator.state.metrics[“val_accuracy”] = 0.98765
Ignite 指标有一个很酷的特性,即用户可以使用基本的算术运算或 torch 方法构建自己的指标:
库结构
precision = Precision(average=False)
recall = Recall(average=False)
F1_per_class = (precision * recall * 2 / (precision + recall))
F1_mean = F1_per_class.mean()
F1_mean.attach(engine, "F1")
该库由两个主要模块组成:
核心 模块包含像引擎、指标、一些必要的处理程序这样的基础。它把 PyTorch 作为唯一的附属国。
- Contrib 模块可能依赖于其他库(如 scikit-learn、tensorboardX、visdom、tqdm 等),并可能在版本之间有向后兼容性破坏更改。
- 单元测试涵盖了这两个模块。
扩展能力/研究中集成的简单性
我们相信,我们的事件/处理程序系统相当灵活,使人们能够与培训过程的每个部分进行交互。正因为如此,我们已经看到 Ignite 被用来训练 GANs (我们提供了两个基本例子来训练 DCGAN 和 CycleGAN )或强化学习模型。
根据 Github 的“被使用”,Ignite 是被研究人员用于他们的论文的:
BatchBALD:深度贝叶斯主动学习的高效多样批量获取, github
- 一个寻找可合成分子的模型, github
- 本地化的生成流, github
- 从生物医学文献中提取 T 细胞的功能和分化特征, github
- 由于这些(以及其他研究项目),我们坚信 Ignite 为您提供了足够的灵活性来进行深度学习研究。
与其他库/框架的集成
如果其他库或框架的特性不重叠的话,Ignite 可以很好地与它们配合。我们拥有的一些很酷的集成包括:
用 Ax ( 点火示例)调整超参数。
- 使用 Optuna 进行超参数调整( Optuna 示例)。
- 登录 TensorBoard,Visdom,MLflow,Polyaxon,Neptune (Ignite 的代码),Chainer UI (Chainer 的代码)。
- 使用 Nvidia Apex 进行混合精度训练( Ignite 的例子)。
- 再现性
我们为 Ignite 培训的可重复性付出了巨大努力:
Ignite 的引擎自动处理随机状态,并在可能的情况下强制数据加载器在不同的运行中提供相同的数据样本;
- Ignite 集成了 MLflow、Polyaxon、Neptune 等实验跟踪系统。这有助于跟踪 ML 实验的软件、参数和数据依赖性;
- 我们提供了几个关于视觉任务的可重复训练的示例和【参考文献】(灵感来自 torchvision】(例如 CIFAR10 上的分类、ImageNet 和 Pascal VOC12 上的分割)。
- 分布式培训
Ignite 也支持分布式培训,但是我们让用户来设置它的并行类型:模型或数据。
例如,在数据分布式配置中,要求用户正确设置分布式过程组、包装模型、使用分布式采样器等。Ignite 处理度量计算:减少所有进程的值。
我们提供了几个示例(例如分布式 CIFAR10 )来展示如何在分布式配置中使用 Ignite。
人气
在撰写本文时,Ignite 大约有 2.5k stars ,根据 Github 的“用户”功能,有被 205 个存储库使用。一些荣誉奖包括:
来自 HuggingFace 的 Thomas Wolf 也在他的一篇博客文章中为图书馆留下了一些令人敬畏的反馈(谢谢,Thomas!):
“使用令人敬畏的 PyTorch ignite 框架和 NVIDIA 的 apex 提供的自动混合精度(FP16/32)的新 API,我们能够在不到 250 行训练代码中提取+3k 行比赛代码,并提供分布式和 FP16 选项!”
Max LapanThis 是一本关于深度强化学习的书,其中第二版的例子是用 Ignite 编写的。
- Project MONAI: 用于医疗保健成像的 AI 工具包。该项目主要关注医疗保健研究,旨在开发医学成像的 DL 模型,使用 Ignite 进行端到端培训。
- 关于其他用例,请看看 Ignite 的 github 页面和它的“使用者”。
何时使用 Ignite
使用 Ignite API 的高度可定制模块,删除样板文件并标准化您的代码。
- 当您需要分解的代码,但不想牺牲灵活性来支持复杂的训练策略时
- 使用各种各样的实用工具,如度量、处理程序和记录器,轻松地评估/调试您的模型
- 何时不使用 Ignite
当有一个超级自定义 PyTorch 代码,其中 Ignite 的 API 是开销。
- 当纯 PyTorch API 或另一个高级库完全满足时
- 感谢您的阅读! Pytorch-Ignite 由 PyTorch 社区用爱献给您!
哲学
PyTorch Lightning 是 PyTorch 上的一个非常轻量级的包装器,它更像是一个编码标准,而不是一个框架。这种格式可以让你摆脱一大堆样板代码,同时保持易于理解。
钩子的使用在训练的每个部分都是标准的,这意味着你可以忽略内部功能的任何部分,直到如何向后传球——这非常灵活。
结果是一个框架,给了研究人员、学生和制作团队终极的灵活性去尝试疯狂的想法,而不必学习另一个框架,同时自动化掉所有的工程细节。
Lightning 还有另外两个更雄心勃勃的动机:深度学习社区中研究的可重复性和最佳实践的民主化。
显著特征
在不改变你的代码的情况下,在 CPU、GPU 或 TPUs 上训练!
- 唯一支持 TPU 训练的库(训练者(数量 _ TPU _ 核心=8))
- 琐碎的多节点训练
- 琐碎的多 GPU 训练
- 普通的 16 位精度支持
- 内置性能分析器(
Trainer(profile=True)
) - 与 tensorboard、comet.ml、neptune.ai 等库的大量集成… (
Trainer(logger=NeptuneLogger(...))
) - 团队
Lightning 有 90 多名贡献者和一个由 8 名贡献者组成的核心团队,他们确保项目以闪电般的速度向前推进。
文档
Lightning 文档非常全面,但简单易用。
API
在核心部分,Lightning 有一个以两个对象Trainer
和LightningModule
T3为中心的 API。
培训师抽象出所有的工程细节,照明模块捕获所有的科学/研究代码。这种分离使得研究代码更具可读性,并允许它在任意硬件上运行。
照明模块
所有的研究逻辑进入LightningModule
。
例如,在癌症检测系统中,这部分将处理主要的事情,如对象检测模型、医学图像的数据加载器等。
它将构建深度学习系统所需的核心成分进行了分组:
计算(初始化,向前)。
- 训练循环(training_step)中会发生什么。
- 验证循环中发生了什么(validation_step)。
- 测试循环中发生了什么(test_step)。
- 要使用的优化器(configure _ optimizers)。
- 要使用的数据(训练、测试、评估数据加载器)。
- 让我们看看文档中的例子,了解一下那里发生了什么。
如你所见,LightningModule 构建在纯 PyTorch 代码之上,并简单地将它们组织在的九个方法中:
import pytorch_lightning as pl
class MNISTExample(pl.LightningModule):
def __init__(self):
super(CoolSystem, self).__init__()
self.l1 = torch.nn.Linear(28 * 28, 10)
def forward(self, x):
return torch.relu(self.l1(x.view(x.size(0), -1)))
def training_step(self, batch, batch_idx):
x, y = batch
y_hat = self.forward(x)
loss = F.cross_entropy(y_hat, y)
tensorboard_logs = {'train_loss': loss}
return {'loss': loss, 'log': tensorboard_logs}
def validation_step(self, batch, batch_idx):
x, y = batch
y_hat = self.forward(x)
return {'val_loss': F.cross_entropy(y_hat, y)}
def validation_end(self, outputs):
avg_loss = torch.stack([x['val_loss']
for x in outputs]).mean()
tensorboard_logs = {'val_loss': avg_loss}
return {'avg_val_loss': avg_loss, 'log': tensorboard_logs}
def test_step(self, batch, batch_idx):
x, y = batch
y_hat = self.forward(x)
return {'test_loss': F.cross_entropy(y_hat, y)}
def test_end(self, outputs):
avg_loss = torch.stack([x['test_loss']
for x in outputs]).mean()
tensorboard_logs = {'test_loss': avg_loss}
return {'avg_test_loss': avg_loss, 'log': tensorboard_logs}
def configure_optimizers(self):
return torch.optim.Adam(self.parameters(), lr=0.02)
@pl.data_loader
def train_dataloader(self):
return DataLoader(
MNIST(os.getcwd(), train=True, download=True,
transform=transforms.ToTensor()), batch_size=32)
@pl.data_loader
def val_dataloader(self):
return DataLoader(
MNIST(os.getcwd(), train=True, download=True,
transform=transforms.ToTensor()), batch_size=32)
@pl.data_loader
def test_dataloader(self):
return DataLoader(
MNIST(os.getcwd(), train=False, download=True,
transform=transforms.ToTensor()), batch_size=32)
init(): 定义本模型或多个模型,并初始化权重
- forward(): 您可以将它视为标准的 PyTorch forward 方法,但它具有额外的灵活性,可以在预测/推理级别定义您希望发生的事情。
- training_step(): 定义了训练循环中发生的事情。它结合了一个向前传球,损失计算,以及任何其他你想在训练中执行的逻辑。
- validation _ step():定义了验证循环中发生的事情。例如,您可以计算每个批次的损失或准确度,并将它们存储在日志中。
- validation _ end():验证循环结束后,你希望发生的一切。例如,您可能想要计算认证批次的平均损失或准确度
- test_step() : 你希望每一批在推断时发生什么。你可以把你的测试时间增强逻辑或者其他东西放在这里。
- 【test _ end():与 validation_end 类似,您可以使用它来聚合 test_step 期间计算的批处理结果
- configure _ optimizer():初始化一个或多个优化器
- train/val/test _ data loader():返回训练、验证和测试集的 PyTorch 数据加载器。
- 因为每个 PytorchLightning 系统都需要实现这些方法,所以很容易看到研究中到底发生了什么。
比如要了解一篇论文在做什么,你要做的就是看LightningModule
的training_step
!
这种可读性以及核心研究概念和实现之间的紧密映射是 Lightning 的核心。
教练
这是深度学习的工程部分发生的地方。
在癌症检测系统中,这可能意味着你使用多少 GPU,当你停止训练时你何时保存检查点,等等。这些细节构成了许多研究的“秘方”,这些研究是深度学习项目的标准最佳实践(即:与癌症检测没有太大的相关性)。
请注意,LightningModule
没有任何关于 GPU 或 16 位精度或早期停止或日志记录之类的东西。所有这些都由教练自动处理。
这就是训练这个模型的全部!培训师为您处理所有事情,包括:
from pytorch_lightning import Trainer
model = MNISTExample()
trainer = Trainer()
trainer.fit(model)
提前停止
- 自动记录到 Tensorboard(或 comet、mlflow、neptune 等)
- 自动检查点
- 更多(我们将在接下来的章节中讨论)
- 所有这些都是免费的!
学习曲线
因为LightningModule
只是简单地重组纯 Pytorch 对象,一切都是“公开的”,所以将 PyTorch 代码重构为 Lightning 格式是微不足道的。
更多关于从纯 PyTorch 到 Lightning 转换的信息,请阅读这篇文章。
内置特性(开箱即用)
Lightning 提供了大量现成的高级功能。例如,一行程序可以使用以下内容:
随时间截断反向传播
Trainer(gpus=8)
Trainer(num_tpu_cores=8)
Trainer(gpus=8, num_nodes=8, distributed_backend=’ddp’)
Trainer(gradient_clip_val=2.0)
Trainer(accumulate_grad_batches=12)
Trainer(use_amp=True)
- 如果你想看完整的免费魔法特性列表,请点击这里。
Trainer(truncated_bptt_steps=3)
扩展能力/研究中集成的简单性
拥有大量内置功能固然很好,但对于研究人员来说,重要的是不必学习另一个库,直接控制研究的关键部分,如数据处理,而无需其他抽象操作。
这种灵活的形式为培训和验证提供了最大的自由度。这个接口应该被认为是一个系统,而不是一个模型。该系统可能有多个模型(GANs、seq-2-seq 等)或只有一个模型,如这个简单的 MNIST 例子。
因此,研究人员可以自由地尝试他们想做的疯狂的事情,,并且只需要担心结果。
但是也许你需要更多的灵活性。在这种情况下,您可以这样做:
更改后退步骤的完成方式。
- 更改 16 位的初始化方式。
- 添加您自己的分布式培训方式。
- 添加学习率计划程序。
- 使用多个优化器。
- 更改优化器更新的频率。
- 还有很多很多东西。
- 在引擎盖下,Lightning 中的所有东西都被实现为可以被用户覆盖的钩子。这使得培训的每个方面都具有高度的可配置性,而这正是研究或生产团队所需要的灵活性。
但是等等,你会说…这对于你的用例来说太简单了?别担心,闪电是我在 NYU 和脸书人工智能研究所攻读博士学位时设计的,对研究人员来说尽可能灵活。
以下是一些例子:
需要自己的后传球?覆盖此挂钩:
- 需要自己的放大器初始化?覆盖此挂钩:
def backward(self, use_amp, loss, optimizer):
if use_amp:
with amp.scale_loss(loss, optimizer) as scaled_loss:
scaled_loss.backward()
else:
loss.backward()
- 想要深入到添加您自己的 DDP 实现?覆盖这两个挂钩:
def configure_apex(self, amp, model, optimizers, amp_level):
model, optimizers = amp.initialize(
model, optimizers, opt_level=amp_level,
)
return model, optimizers
像这样的钩子有 10 个,我们会根据研究人员的要求增加更多。
def configure_ddp(self, model, device_ids):
model = LightningDistributedDataParallel(
model,
device_ids=device_ids,
find_unused_parameters=True
)
return model
def init_ddp_connection(self):
try:
default_port = os.environ['SLURM_JOB_ID']
default_port = default_port[-4:]
default_port = int(default_port) + 15000
except Exception as e:
default_port = 12910
try:
default_port = os.environ['MASTER_PORT']
except Exception:
os.environ['MASTER_PORT'] = str(default_port)
try:
root_node = os.environ['SLURM_NODELIST'].split(' ')[0]
except Exception:
root_node = '127.0.0.2'
root_node = self.trainer.resolve_root_node_address(root_node)
os.environ['MASTER_ADDR'] = root_node
dist.init_process_group(
'nccl',
rank=self.proc_rank,
world_size=self.world_size
)
底线是, Lightning 对于新用户来说使用起来很简单,如果你是一名研究人员或从事前沿人工智能研究的生产团队,它可以无限扩展。
可读性和走向再现性
正如我提到的,Lightning 的创建还有第二个更大的动机:可复制性。虽然真正的再现性需要标准代码、标准种子、标准硬件等,但 Lightning 以两种方式为可再现性研究做出了贡献:
为了标准化 ML 代码的格式,
- 将工程与科学分离以便该方法可以在不同的系统中进行测试。
- 结果是一个用于研究的表达性强、功能强大的 API。
如果每个研究项目和论文都是使用 LightningModule 模板实现的,那么就很容易发现发生了什么(但是可能不容易理解哈哈)
分布式培训
闪电让多 GPU 甚至多 GPU 多节点训练变得琐碎。
例如,如果您想在多个 GPU 上训练上述示例,只需向训练器添加以下标志:
使用上述标志将在 4 个 GPU 上运行该模型。如果您想在 16 个 GPU 上运行,其中有 4 台机器,每台机器有 4 个 GPU,请将教练标志更改为:
trainer = Trainer(gpus=4, distributed_backend='dp')
trainer.fit(model)
并提交以下 SLURM 作业:
trainer = Trainer(gpus=4, nb_gpu_nodes=4, distributed_backend='ddp')
trainer.fit(model)
考虑到引擎盖下发生了多少事情,这简直太简单了。
source activate $1
export NCCL_DEBUG=INFO
export PYTHONFAULTHANDLER=1
srun python3 mnist_example.py
有关 Pytorch lightning 分布式训练的更多信息,请阅读这篇关于“如何使用 Pytorch 在 128 GPUs 上训练 GAN”的文章。
生产化
Lightning 模型很容易部署,因为它们仍然是简单的 PyTorch 模型。这意味着我们可以利用 PyTorch 社区在支持部署方面的所有工程进展。
人气
Pytorch Lightning 在 Github 上拥有超过 3800 颗星星,最近的下载量达到了 110 万次。更重要的是,该社区正在快速发展,有超过 90 名贡献者,许多来自世界顶级人工智能实验室,每天都在添加新功能。你可以在 Github 或者 Slack 上和我们交流。
何时使用 PyTorch 闪电
Lightning 是为从事尖端研究的专业研究人员和生产团队而制造的。当你知道你需要做什么的时候,那是很棒的。这种关注意味着它为那些希望快速测试/构建东西而不陷入细节的人增加了高级特性。
- 何时不使用 PyTorch 闪电
虽然 lightning 是为专业研究人员和数据科学家设计的,但新来者仍然可以从中受益。对于新来者,我们建议他们使用纯 PyTorch 从头构建一个简单的 MNIST 系统。这将向他们展示如何建立训练循环等。一旦他们明白这是如何工作的,以及向前/向后传球是如何工作的,他们就可以进入闪电状态。
我们的博客部分将与其他部分略有不同,因为火炬手即将结束(有点)。特别是,我们加入了 PyTorch-Lightning 团队。这一举动源于在 NeurIPS 2019 上与威廉·法尔肯的一次会面,并于最近在 PyTorch 博客上宣布。
因此,我们认为我们应该写我们做得好的地方,我们做错的地方,以及我们为什么要转向闪电,而不是试图向你推销火炬手。
我们做得好的地方
lib 变得非常受欢迎,在 GitHub 上获得了 500 多颗星,这远远超出了我们的想象。
- 我们成为 PyTorch 生态系统的一部分。对我们来说,这是一次重要的经历,让我们觉得自己是更广泛的社区中有价值的一部分。
- 我们已经建立了一套全面的内置回调和指标。这是我们的主要成功之一;使用 torchbearer,一行代码就可以实现许多强大的成果。
- 火炬手的一个重要特点是使极端的灵活性是状态对象。这是一个可变字典,包含核心训练循环使用的所有变量。通过在循环中不同点的回调中编辑这些变量,可以实现最复杂的结果。
- 火炬手拥有良好的文件对我们来说一直很重要。我们关注的是可以在你的浏览器中用 Google Colab 执行的示例文档。示例库非常成功,它提供了关于 torchbearer 更强大的用例的快速信息。
- 最后要注意的是,在过去的两年里,我们俩都在用火炬手进行我们的博士研究。我们认为这是一个成功,因为我们几乎从来不需要为了原型化我们的想法而改变火炬手 API ,即使是那些荒谬的想法!
- 我们做错了什么
使这个库如此灵活的状态对象也有问题。从任何其他地方访问库的任何部分的能力会像全局变量一样导致滥用。特别是,一旦不止一个对象作用于它,确定状态对象中的特定变量是如何以及何时被改变的是具有挑战性的。此外,为了使状态有效,你需要知道每个变量是什么,以及在哪个回调中可以访问它,所以学习曲线很陡。
- 火炬手本质上不适合分布式训练,甚至在某种程度上不适合低精度训练。既然状态的每一部分在任何时候都是可用的,那么如何将它分块并在设备间分配呢?PyTorch 可以以某种方式处理这个问题,因为火炬手可以在分发时使用,但目前还不清楚 state 在这些时候会发生什么。
- 改变核心训练循环并非易事。Torchbearer 提供了一种完全编写自己的核心循环的方法,但是您必须手动编写回调点,以确保所有内置的 Torchbearer 功能。与库的其他方面相比,再加上较低的文档标准,定制循环过于复杂,大多数用户可能完全不知道。
- 在攻读博士的同时管理一个开源项目变得比预期的更加困难。结果,该库的一些部分经过了彻底的测试并且是稳定的(因为它们对我们的博士工作很重要),而其他部分则开发不足并且充满错误。
- 在我们最初的成长过程中,我们决定大幅改变核心 API 。这极大地改进了火炬手,但也意味着从一个版本到下一个版本需要大量的努力。这感觉是合理的,因为我们仍然是 1.0.0 之前的稳定版本,但它肯定会促使一些用户选择其他库。
- 为什么我们要加入 PyTorch Lightning?
我们愿意迁移到 Lightning 的第一个关键原因是它的受欢迎程度。有了 Lightning,我们成为发展最快的 PyTorch 培训库的一部分,这已经让它的许多竞争对手黯然失色。
- 我们此举的第二个关键原因,也是 Lightning 成功的一个关键部分,是它是从头开始构建的,以支持分布式训练和低精度,这两者在火炬手中实现都具有挑战性。在 Lightning 开发的早期阶段做出的这些实际考虑对现代深度学习实践者来说是非常宝贵的,而在《火炬手》中进行改造将是一个挑战。
- 此外,在 Lightning 我们将成为更大的核心开发团队的一部分。这将使我们能够确保更高的稳定性,支持更广泛的用例,而不是像现在这样只有两个开发人员。
- 最终,我们始终相信,推动事情向前发展的最佳方式是与另一个图书馆合作。这是我们实现这一目标并帮助闪电成为 PyTorch 最好的培训库的机会。
可能有用
查看如何使用 Neptune 跟踪模型训练,这要归功于与以下软件的集成:
➡️catalyst➡️fastai ➡️py torch ignite ➡️py torch lightning
➡️sko rch
(主观)比较和最终想法
雅各布·查肯
大部分是 ML 的人。构建 MLOps 工具,编写技术资料,在 Neptune 进行想法实验。
在这一点上,我想给一个…
非常感谢所有作者!
哇,这是很多第一手资料,我希望它能让你更容易选择适合你的图书馆。
当我和他们一起写这篇文章并仔细观察他们的库所提供的东西(并创建一些拉请求)时,我得到了自己的观点,我想在这里和你们分享。
如果你想要类似 sklearn 的 API,那么 Skorch 就是你的 lib。它经过了很好的测试和记录。实际上给出了比我在撰写这篇文章之前所预期的更多的灵活性,这是一个很好的惊喜。也就是说,这个图书馆的重点不是尖端研究,而是生产应用。我觉得它真的兑现了他们的承诺,并且完全符合设计初衷。我真的很尊重这样的工具/库。
长期以来,Fastai一直是人们进入深度学习的绝佳选择。它可以用 10 行近乎神奇的代码为您提供最先进的结果。但是库还有的另一面,也许不太为人所知,它让你访问低级 API并创建自定义构建块给研究人员和从业者实现非常复杂的系统的灵活性。也许是超级受欢迎的 fastai 深度学习课程在我的脑海中创造了这个库的错误形象,但我肯定会在未来使用它,特别是最近的 v2 预发布。***
点燃是一种有趣的动物。有了它,有点异国情调(对我个人来说),引擎,事件和处理程序 API ,你可以做任何你想做的事情。它有大量开箱即用的功能,我完全理解为什么许多研究人员在日常工作中使用它。我花了一点时间来熟悉这个框架,但是你只需要停止用“回调术语”来思考,你就没事了。也就是说,API 对我来说不像其他一些库那样清晰。不过你应该去看看,因为这对你来说可能是个不错的选择。
在研究 Catalyst 之前,我认为它是一个创建深度学习管道的沉重(有点)框架。现在我的看法完全不同了。它以一种美丽的方式将工程材料与研究分离开来。纯 PyTorch 对象进入处理训练的训练器。它非常灵活,有一个单独的模块来处理强化学习。它也给你很多现成的功能,当谈到可重复性,并在生产中服务模型。还有我跟你说过的那些多级管道?您可以用最少的开销轻松创建它们。总的来说,我认为这是一个很棒的项目,很多人可以从使用它中受益。
闪电也想把科学和工程分开,我认为它在这方面做得很好。有大量的内置功能使它更具吸引力。但是这个库有一点不同的是,它通过使深度学习研究实现可读来实现的可重复性。遵循 LightningModule 内部的逻辑真的很容易,其中培训步骤(以及其他内容)没有被抽象掉。我认为以这种方式交流研究项目会非常有效。它很快变得非常受欢迎,随着火炬手的作者加入核心开发团队,我认为这个项目有一个光明的未来在它前面,甚至是闪电一样的光明🙂
那么你应该选择哪一个呢?像往常一样,这要视情况而定,但我认为你现在有足够的信息来做出一个好的决定!
阅读下一篇
如何使用海王星跟踪 PyTorch 中的实验
4 分钟阅读| Aayush Bajaj |发布于 2021 年 1 月 19 日
4 mins read | Aayush Bajaj | Posted January 19, 2021
机器学习开发看起来很像传统的软件开发,因为它们都需要我们编写大量的代码。但其实不是!让我们通过一些要点来更好地理解这一点。
机器学习代码不会抛出错误(当然我说的是语义),原因是,即使你在神经网络中配置了错误的方程,它仍然会运行,但会与你的预期混淆。用安德烈·卡帕西、的话说,“神经网络无声无息地失败了”。
- 机器学习代码/项目严重依赖结果的可重复性。这意味着,如果一个超参数被推动,或者训练数据发生变化,那么它会在许多方面影响模型的性能。这意味着你必须记下超参数和训练数据的每一个变化,以便能够重现你的工作。当网络很小时,这可以在一个文本文件中完成,但是如果是一个有几十或几百个超参数的大项目呢?文本文件现在不那么容易了吧!
- 机器学习项目复杂性的增加意味着复杂分支的增加,必须对其进行跟踪和存储以供将来分析。
- 机器学习也需要大量的计算,这是有代价的。你肯定不希望你的云成本暴涨。
- 有组织地跟踪实验有助于解决所有这些核心问题。海王星是一个完整的工具,可以帮助个人和团队顺利跟踪他们的实验。它提供了许多功能和演示选项,有助于更轻松地跟踪和协作。
Tracking experiments in an organized way helps with all of these core issues. Neptune is a complete tool that helps individuals and teams to track their experiments smoothly. It presents a host of features and presentation options that helps in tracking and collaboration easier.
什么是 ModelOps,它与 MLOps 有什么不同?
原文:https://web.archive.org/web/https://neptune.ai/blog/modelops
在过去的几年里,我们已经看到现实生活中人工智能和机器学习解决方案的增加。在大公司中,这些解决方案必须在数百个用例中实施,并且很难手动完成。
在企业层面,人工智能解决方案和机器学习模型的部署需要可操作化。数据科学家和 ML 工程师拥有创建和部署模型的工具,但这只是一个开始。模型需要在生产中部署,以处理真实世界的用例。因此,我们需要一个框架或方法来减少人工劳动并简化 ML 模型的部署。这个框架就是 ModelOps。
它是由 IBM 研究人员在 2018 年 12 月提出的,被称为“可重用、平台无关、可组合的人工智能工作流的编程模型”。该论文的作者 Waldemar Hummer 和 Vinod Muthusamy 后来将这一想法扩展为“基于云的框架和平台,用于人工智能(AI)应用程序的端到端开发和生命周期管理”。
“人工智能(AI)模型操作化(ModelOps)是一组主要关注所有 AI 和决策模型的治理和全生命周期管理的功能。这包括基于机器学习(ML)、知识图、规则、优化、自然语言技术和代理的模型。与 MLOps(只关注 ML 模型的可操作性)和 AI ops(IT 运营的 AI)相反,ModelOps 关注的是所有 AI 和决策模型的可操作性。”–Gartner
Model lifecycle governance | Source: Forrester
在 2020 年 3 月的,ModelOp,Inc .出版了第一份全面的 ModelOps 方法指南。该指南涵盖了模型操作的功能,以及实施模型操作实践的技术和组织要求。
基本上,ModelOps 是部署、监控和管理机器学习模型的工具、技术和最佳实践的集合。这是在企业层面扩展和管理人工智能的关键能力。
ModelOps Enterprise Capability | Source
它基于 DevOps 的概念,但经过调整以确保机器学习模型的高质量。一般来说,模型操作包括:
您可以将 ModelOps 视为对 MLOps 的扩展,其主要重点是通过持续的重新培训和同步部署来保持已部署的模型为未来做好准备。
“真正的 ModelOps 框架允许您在这些不同的环境中实现标准化和可扩展性,以便开发、培训和部署流程能够以平台无关的方式一致运行。”–首席信息官-维基
为什么是 ModelOps?企业人工智能的关键
2018 年,Gartner 向大型企业询问 AI 采用情况。经理们曾预计,到第二年,他们 23%的系统将集成人工智能。Gartner 在 2019 年进行了跟进,发现只有 5%的部署成功投入生产。大多数企业无法快速扩展并将人工智能集成到他们的系统中。
这种未部署模型的建立最终会影响公司的发展。模型需要复杂的重新训练。对于每个新的业务领域,都有一组新的数据。此外,模型需要放置在 24/7 运行环境中,因为大多数数据科学家使用开源建模工具,如 Jupyter notebook 或 R studio。数据科学家不知道或无法访问可以观察到延迟的环境。
这就是 ModelOps 的用武之地。它可以帮助解决这些挑战,并使组织能够轻松地扩展和管理人工智能计划。
“与传统软件相比,模型对业务负有更大的责任。他们必须接受监管审查和合规。一个适当的运营模式可以极大地改变特定业务部门的总体业绩。因此,业务部门和合规部门之间的整合至关重要。”–福布斯
在过去的几年里,企业已经看到了人工智能开发的激增。但是,正如一项调查显示的那样,“84%的首席执行官认为他们必须利用人工智能(AI)来实现他们的增长目标,然而 76%的人报告说他们正在为如何扩大规模而挣扎。”
The Nuances of ModelOps | Source: Gartner
ModelOps 在动态环境中表现出色。只要定义的条件发生变化,就可以很容易地调整模型。企业针对不同的业务问题采用不同类型的模型。ModelOps 使他们能够相应地切换或扩展系统。
ModelOps 就像是数据科学家、数据工程师、应用程序所有者和基础设施所有者之间的桥梁。它促进动态协作并提高生产率。企业使用 ModelOps 解决以下挑战:
- 法规遵从性—为了遵从法规要求,我们需要系统地再现每个模型的培训、评估和评分。模型监控有助于加强合规性关口和控制,确保满足所有业务和法规要求。
- 筒仓环境–当一个模型从部署到监控的过程中,涉及到多个团队。跨团队的无效协作会使扩展人工智能变得困难。团队需要走到一起,ModelOps 有助于创建一个环境,在这个环境中,模型可以很容易地从数据科学团队转移到 IT 生产团队。
- 不同的模型有不同的解决方案——企业对于不同的业务问题会有上百种模型。每个模型都考虑了特定的业务流程变化、独特的客户细分等。ModelOps 提供单一视图来查看工作流、审计、性能调整和治理,以控制成本和创造价值。
- 复杂的技术–有各种各样的解决方案、工具和技术可用于解决数据和分析问题。很难通过持续创新来管理所有这些。即使是最专业的团队也可能跟不上。ModelOps 使集成和采用新技术变得更加容易。
modelos 用例
许多经理都难以证明分析的价值,因为分析解决方案往往无法投入生产。ModelOps 可以解决这个问题。
以下是 ModelOps 被广泛用于克服模型部署挑战的一些领域:
- 金融—例如,银行一直在使用统计模型进行信贷审批,如今大多数运营决策都是由实时分析推动的。这种基于模型的方法帮助银行减少了工时,但大规模管理这些复杂的模型也很困难。这些模型应该是公平和稳健的,这有助于做出公正的决策。ModelOps 使得监控模型偏差或异常并相应地更新它们变得更加容易。
- 医疗保健–人工智能可以提高效率和改善患者护理,同时减少代价高昂的管理错误。但是,机器学习模型必须用当前数据、新的 KPI 等来更新。此外,还对异常情况进行监控。更新后的模型应该在不同的系统上随时可用,例如,移动应用程序或实验室的系统,以保持结果同步。
- 零售—当新冠肺炎来袭时,一切都必须转移到网上,但很难有效地部署和监控人工智能解决方案。ModelOps 提供了监控模型的能力,并创建关键指标的多级视图来查看生产中的模型性能。为了了解增长领域并减少数据科学家和 IT 专家的工作,零售公司选择了 ML 操作员的自动化和标准化。像 Domino's Pizza 这样的公司能够提高大规模管理多个模型的效率。
modelos 平台
有几个在线中心可以指导企业完成模型生命周期。一些最常用的平台是:
2016 年,ModelOp 成立,旨在解决模型部署和维护之间的巨大差距。为了操作机器学习模型,该团队提出了 ModelOp Center。该中心通过确保治理和法规要求的实施,帮助加快了模型的可操作性。
**
ModelOp on AI Initiatives | Source: ModelOp
" ModelOp Center 自动治理、管理和监控跨平台和团队部署的 AI、ML 模型,从而实现可靠、合规和可扩展的 AI 计划。”
模型中心可以帮助您完成模型生命周期中的步骤:
- 注册—在ModelOp center 中,您可以使用 Jupyter 插件或 CLI 注册模型,并通过预定义的元素(模型源、附件、模式和模型平台)传递信息。该模型的源代码可分为 4 个功能:初始化、评分、指标和培训。
您还可以随时通过编辑模式或向其中添加新资产来更新注册的模型。
Registering a model | Source: ModelOp
- 编排–ModelOp Center 有一个 MLC(模型生命周期)管理器,可以自动执行模型操作,如部署、监控和治理。该模型可以在生产中高效、轻松地部署和监控。这也让企业可以灵活地只自动化生命周期的一部分。
MLC 管理器是一个执行、监控和管理 MLC 进程的框架。MLC 流程通过外部事件触发,例如:
- 基于时间的
- 数据到达
- 通知
- 人工干预
- 标记为–准备生产
使用 ModelOp Center 可以处理一些常见的 MLC 流程:生产化、刷新、再培训和性能监控。
-
监控—ModelOp Center 为全面的模型监控提供了各种指标。您可以使用 F1 得分、ROC、AUC 等常用指标来评估模型。通过使用 SLA 或数据度量,您还可以监控操作、质量、风险和过程性能。
-
治理—一个中央存储库,用于治理模型生命周期的每一步。治理确保了模型的标准表示。利益相关者可以查看生产模型清单以查看细节,修改和改进模型,或者操作流程。
ModelOp Center 还集成了许多开发平台、IT 系统和企业应用程序。这些集成可以用来扩展人工智能投资,释放人工智能的价值。
ModelOps: orchestration and model life cycle | Source: ModelOp
有了 ModelOp Center 这样的平台,企业可以加快模型部署速度,降低业务风险。
建立模型不是问题,而是组织。我们正在构建 Datatron 来解决这一问题,方法是加快部署、及早发现问题,并提高大规模管理多个模型的效率。
Automating and accelerating ML management | Source: Datatron
Datatron 是一个一站式解决方案,您可以在其中自动化、优化和加速 ML 模型。它支持广泛的框架和语言,如 TensorFlow、H2O、Scikit-Learn、SAS、Python、R、Scala 等。此外,它支持内部和基于云的基础架构。他们将模型操作活动分为以下几类:
-
模型目录—探索由您的数据科学团队构建和上传的模型,所有这些都来自一个集中的存储库。
-
模型部署–通过几次点击创建可扩展的模型,并使用任何语言或框架进行部署。
-
模型监控—创建条件警报,比较模型预测,检查模型准确性,并检查模型是否会衰退。
-
模型治理–您可以轻松验证您的模型并执行内部审计。该平台还可以用来调试和解释模型。
-
模型管理—动态在运行时选择最佳模型,以帮助提供更好的预测并减少错误。强制执行延迟以防止任何服务中断,并对模型序列执行 A/B 测试。
-
模型工作流–设置工作流有助于将业务逻辑与模型结果相集成。例如,您可以设置预处理工作流,在该工作流中定义数据源和特征工程流程,然后将它们输入到模型中。
SAS 模型管理软件用于简化分析模型的部署和管理。但是,企业在实施和持续增值方面需要帮助,因此 SAS 推出了 ModelOps。这是一个包含模型管理器软件和服务的组合包。一些关键特征是:
- 管理分析模型
- 交付详细的项目计划
- 评估当前模型
- SAS 模型管理器的实现和激活支持。
Superwise 每天保证多个预测的健康。它可以预测性能随时间和版本的变化,并使您能够在没有反馈时获得可见性。
EmpoweringAI Stakeholder | Source: Superwise
它支持高级事件管理,有助于模型监控并提供模型性能的粒度可见性。
**
One solution to monitor, analyze and optimize | Source: Superwise
它是 API 驱动的,因此解决方案可以轻松集成到现有环境中。它可以通过查看数据来发现功能、生成 KPI 和设置阈值。
Modzy 成立于 2019 年,其明确的目的是建立一个人类和机器共同工作的世界,胜过单独工作。
“Modzy 为人工智能提供了十年前不存在的规模,它拥有一个 ModelOps 平台和现成模型的市场。”
Easy integration | Source: Modzy
- Modzy 集成了广泛的工具、框架、数据管道和 CI/CD 系统。
- 它提供了预定义模型的列表,您可以在新的输入数据中重用这些模型。
Searching for a sentiment analysis model | Source: Modzy
- 它拥有 Python、JavaScript 和 Java SDKs,使开发人员能够轻松地将 ML 功能集成到他们的应用程序中。
modelos 的优势
在前面的章节中,我们谈到了 ModelOps 给企业带来了什么,以及为什么他们需要与 ModelOps 集成来扩展 AI 系统。让我们探索更多这些优势:
- 加速部署—许多大型企业发现按时交付人工智能解决方案具有挑战性。要么是缺乏熟练的数据科学家,要么是调整或发现模型的问题需要太多时间。ModelOps 平台提供了所有模型和各种管道的单一视图,有助于加速模型部署。这样,企业可以更专注于创新和价值创造。
- 减轻模型漂移–可能有数百个模型,管理它们可能会很困难。ModelOps 有助于解释模型是如何得到的,并测量它们的公平性,同时有助于纠正是否存在任何偏离定义基线的情况。
- 人工智能结果驱动——有价值的见解—ModelOps 通过生成关键见解和模式,帮助将模型结果映射到业务 KPI。管理者可以利用自动化、预测和优化等战略手段。这有助于创建符合您业务需求的解决方案。
- 更简单的入门–model ops 是一个统一的环境,可带来巨大收益,同时减少在模型构建、部署和管理上投入的时间。这些平台帮助您装载模型和流程,并让您通过几次点击来监控和管理它们。
- 经济—ModelOps 平台与云集成,有助于经济地优化云服务和人工智能模型。企业可以选择灵活的服务消费进行建模。
modelos 的特点
我们在上一节中已经介绍了一些 ModelOps 工具,它们中的大多数都有共同的特征,因为它们都服务于一个目标——将模型操作化。
ModelOps 是开启价值的钥匙,它是你的人工智能技术栈中的结缔组织。让我们来看看其中的一些特性,看看为什么 ModelOps 如此重要:
- 生成模型管道—只需最少的人工干预和几次点击,ModelOps 平台就能自动生成管道。一旦第一次设置完成,整个建模生命周期——准备数据、选择模型、特征工程、超参数优化——将实现自动化。
- 监控模型–监控数百种不同的模型是一项挑战。ModelOps 有助于监控各种型号。它寻找任何可能的偏见,然后学习如何解决它。
- 部署模型–在 ModelOps 平台上构建的模型可以轻松集成到任何应用程序中。您几乎可以在任何地方部署和发送模型。
- 一站式解决方案–构建、运行和管理模型–数据科学家使用开源平台(如 Jupyter、R 等)构建模型。然后,IT 专业人员使用不同的平台在生产中部署这些模型。这一过程通常需要时间,并缩短上市时间。ModelOps 平台旨在通过这一复杂而漫长的过程拯救企业。它们是一站式解决方案,团队可以在其中轻松地构建、运行和管理模型。
ModelOps 和 MLOps 一样吗?
ModelOps 和 MLOps 之间只有一线之隔,如果你观察它们的架构,你会发现 ModelOps 是 MLOps 的延伸。模型操作指的是在生产中操作和管理人工智能模型的过程。ModelOps 可以被视为 SDLC,它帮助组织生命周期流程,即创建模型、测试、部署和监控它。
ModelOps 做 MLOps 做的一切,甚至更多。它有助于企业从人工智能投资中获得更多回报。MLOps 使数据科学家和 IT 专业人员能够有效地协作和沟通,同时自动化机器学习模型。ModelOps 是 MLOps 的发展,关注于 ML 模型的持续再培训、同步开发和部署、决策优化和转换模型。
AI at Scale with MLOps & ModelOps | Source
“ModelOps 已经成为解决人工智能部署最后一英里交付挑战的关键环节。ModelOps 是 MLOps 的超集,指的是在生产系统中操作和管理人工智能模型所涉及的过程。”–Modzy
模型操作 vs 模型操作
很容易混淆 ModelOps 和 MLOps。为了理解这些差异,我们需要知道它们到底是如何帮助建模的。创建可扩展的人工智能解决方案需要这两者。
让我们来看看这两者之间的一些共同差异:
性能 | MLOps | 莫德洛斯 |
---|---|---|
关注机器学习模型的可操作化
|
所有 AI 和决策模型可操作化
|
| |
模型开发、部署和性能监控的连续循环
|
关注模型的治理和全生命周期管理
|
| |
亚马逊 SageMaker,海王星,DataRobot,MLFlow,还有更有
|
Cnvrg,Cloudera,ModelOps,Modzy,SAS
|
| |
旨在通过为各种团队和利益相关者创建有效的协作环境来创建支持人工智能的应用
|
使用仪表盘提供人工智能使用的透明度,向业务领导汇报
|
要了解更多差异,请检查 ModelOp 中心。
结论
通过这篇文章,我们了解了什么是 ModelOps,以及企业如何使用它来操作 AI 解决方案。有各种各样的平台和工具可以帮助创建模型工作流,只需点击几下鼠标就可以进行监控和治理。我们还确定了 MLOps 和 ModelOps 是如何不同的,但是属于相同的概念。
总之,使用 ModelOps,创建人工智能解决方案并将其部署到生产中的企业将不得不不断更新这些模型,以便它们不会过时,并能够跟上市场。有了 ModelOps,企业可以自动完成这些更新。
ModelOps 解决方案通过为商业领袖提供量身定制的信息和见解,解决了当今人工智能采用中最紧迫的问题之一。这种在整个企业中对人工智能使用的透明性,以一种商业领袖可以理解的方式为模型提供了可解释性。一句话:ModelOps 促进信任,从而增加人工智能的采用。”–数据科学中心****
现代数据堆栈有什么现代之处?
原文:https://web.archive.org/web/https://neptune.ai/blog/modern-data-stack
在圣诞假期,我终于有时间去补上所有的书签文章、保存的播客和标有星号的 GitHub 库。在浏览它们的时候,我注意到它们都有一个重复出现的趋势。
所有闪亮的新数据产品广告都有相同的主题:“
**现代数据栈(MDS) 已经流行了几年,但是直到最近才在定义上有了共识。简而言之,如果您使用以下任何一项,您就有可能拥有现代数据堆栈的基础部分:
- 雪花
- 红移
- 大查询(GCP)
- 数据砖
- Synapse (Azure)
但是等一下,仅仅拥有像雪花这样的现代工具并不意味着你是现代的。这完全取决于你如何使用它。在我们深入了解什么是 MDS 的哲学和技术指标之前,让我们先来谈谈传统数据堆栈的失败之处。
为什么 MDS 越来越受欢迎?
一个简单的原因是,传统的数据堆栈(TDS)无法满足任何现代组织的数据需求。为了保持竞争优势,组织需要能够在正确的时间处理的数据,以及足够灵活以适应变化的数据。TDS 通常指的是内部部署的 Hadoop(生态系统)和 SQL 仓库,它们在逻辑上相互耦合,并且非常复杂。
想象一下,TDS 就像盒子里的圣诞灯饰。圣诞派对需要适时的灯光,但你发现有些灯泡需要更换。你必须解开所有的东西才能找到坏掉的灯泡。过了一会儿,你终于换上了灯泡,但是当你换好的时候,派对已经结束了。
“…and now we have to put it all back in the box.” | Source
然而,随着新技术的不断涌现,很难跟上并确定哪些新技术可以为您的业务带来价值,这是可以理解的。这个 MDS 只是另一个在新词被发明出来之前会消失的时髦词吗?
因此,在我们深入了解什么是现代数据堆栈之前,让我们先来看看仍在使用 TDS 的组织所面临的一些问题。
典型的 TDS 设置会导致三个主要问题
1.解决问题和建立基础设施的周转时间很长
- 使用内部基础架构的公司负责所有相关成本,例如维护和平稳运行一切所需的工程师队伍。
- 由于这种设置是如此紧密相连,看似微小的变化可能会破坏系统的其他部分。在对现有环境进行任何改进之前,找到系统之间的确切逻辑耦合需要大量的工作时间来分析。
2.对新信息反应缓慢
- 随着公司的发展,其数据和计算能力需求也在增长。横向扩展(扩展)内部基础架构在资源和时间方面的成本非常高。
- 由于内部基础设施难以扩展,这自然会限制用于分析数据的计算能力。数据管道可能需要几个小时才能完成,随着组织的发展,这个问题变得更加复杂。
- TDS 需要缓慢的 ETL(提取、转换、加载)操作,然后新获取的数据才能符合数据模型的其余部分。一个新的数据更新可能需要数周甚至数小时的重构,然后才会出现真知灼见。当数据准备就绪时,组织无法及时采取行动,导致错失良机。
3.昂贵的洞察之旅
- 大量的报告生成是手工完成的,尤其是当数据来自不同的来源时。报表手动生成,手动清理,手动转 Excel(喘息!).这会导致出错,占用其他关键业务任务的时间,并且无法扩展。
- 由于复杂的形势,分析师无法高效地履行他们的职责。数据工程师被拉入操作查询中,这使他们无法完成实际工作(例如使数据管道更具可伸缩性!).
看到竞争如此激烈的业务环境以及快速适应新信息的需求,很明显传统的数据堆栈不是理想的解决方案。这就是现代数据堆栈帮助您的企业保持竞争力的地方。
现代数据堆栈有什么好处?
1.从以 IT 为中心转向以业务为中心的运营模式
- 有了 MDS,您的组织重新获得了关注业务方面的自由,而不是陷入与 IT 相关的困境。
- 您的组织可以拥有更精简的数据团队,并可以专注于更高价值的数据任务,而不是浪费时间进行传统数据堆栈的管理和性能优化。
- MDS 提供的工具在设计时考虑了更大的可访问性(不需要代码或只需要很少的代码),大大降低了进入的技术门槛。
- MDS 将自助服务视为核心功能,减少了对数据专业人员的依赖。这意味着首席营销官可以自己提取营销活动分析,并将数据团队视为推动者而非瓶颈。
2.即插即用的灵活性取代了长期承诺
- 由于基础架构不再是本地的,也不再部署在云中,公司不再需要担心硬件/平台维护及其相关成本(这将带来显著的节约)。
- 存储和计算随时可用,通过云提供商的灵活性缩短了数据处理响应时间。
- 现代数据堆栈利用软件即服务平台(SaaS),创建开箱即用的工具。这意味着您的团队可以以最低的设置要求开始工作。(因此,我们将使用现代数据堆栈作为每个新的 DataOps/MLOps 工具的口号)
3.从一次性分析转向运营 BI 和 AI
- 现代数据堆栈的建立和迭代要快得多,消除了对大型 IT 团队的需求。这使得非科技公司可以在几个小时内开始产生可行的见解,而不是通常的几天或几周。
- 数据可以来自各种第一和第三方来源。现代数据堆栈可以将所有这些来源集成到其数据摄取工具中,该工具反过来将与商业智能工具一起工作。
4.将数据治理视为一等公民
- 我们处理那些可以尽早发现和缓解问题的地方。
- MDS 供应商提供的工具允许更好的数据质量、隐私控制和访问治理。随着网络安全威胁的增加、负责任的人工智能以及越来越多的数据法规,不考虑数据治理而构建的系统是每个首席信息官的噩梦。无法保护数据可能会给组织带来灾难性的后果。
- 虽然保护整个堆栈仍然是一个挑战,但 MDS 技术提供商不会将数据治理视为事后想法。这导致数据治理成为整个堆栈流程的一部分。
那么什么是现代数据堆栈呢?
很简单,现代数据堆栈(MDS)是一组托管在云中的工具,使组织能够实现高效的数据集成。我们相信 MDS 是数据操作和移动操作的基础。
MDS 创建干净、可信和始终可用的数据,使业务用户能够进行自助发现,从而实现真正的数据驱动型文化。
MDS 由什么组成?
MDS 由多层堆叠而成(像蛋糕一样),每层都有自己的功能。
Modern Data Stack | Source: Author, icons
1.数据摄取
这是数据从各种来源(数据库、服务器日志、第三方应用程序等)传输到存储介质的地方。
示例工具: 事件枢纽, Fivetran , Airbyte
2.数据存储
数据仓库或数据湖(或湖屋!)是一个(通常基于云的)解决方案,用于存储从数据摄取工具发送的所有收集的数据。在这里可以访问和分析数据。
3.数据转换
一旦原始数据被转移到存储中,就需要将其转换成用户友好的数据模型。这使得分析师或数据科学家可以轻松地查询数据,以提取见解,构建仪表板甚至 ML 模型。
4.数据分析/商业智能
这里对数据进行分析,并为用户创建仪表板来浏览数据。现代数据分析工具也是为非技术用户设计的。这使得领域专家能够在不依赖开发人员和分析师的情况下回答业务问题。
示例工具:LookerPower BIthought spot
5.数据治理
数据目录和治理
- 允许组织跟踪和理解他们的数据,这有助于数据的可发现性、质量和共享。没有这些工具,数据湖很容易变成数据沼泽。
数据隐私和访问治理
- 这些工具帮助组织在数据保护方面保持法律合规性。敏感数据的数据泄露等问题可以得到缓解。
我需要所有这些不同的组件吗?
好消息是,不,你不需要所有的功能!MDS 的设置就像点餐一样,你可以根据当时的需求进行设置。例如,你可以点一个蛋糕,但不要奶油。需要注意的重要一点是,尽管没有任何奶油,但最终结果是你仍然有一个可以吃的蛋糕。
MDS 安装是模块化的,旨在与其他组件和工具兼容(即插即用)。这意味着您可以根据组织的需要切换组件。您还可以定制您的设置,使其与您现有的基础设施一起工作,而不是完全抛弃它。
这种模块化的另一个优点(相对于单片)是,您可以水平旋转组件,避免供应商锁定。不喜欢供应商为数据存储层提供的特定工具?换成更符合您需求的不同供应商。如果组织很年轻,它很可能不需要所有的组件,因为它的需求比较简单。随着组织的发展,它可以根据需要切换或添加更多组件。
不同 MDS 设置的示例
不是所有的组织都是一样的,也不是所有的事情都是千篇一律的。以下是不同类型的组织可以在其 MDS 中使用的工具示例。
1.具有商业智能和数据科学需求的企业 MDS
EventHub + 三角洲湖 + 数据块 + PowerBI
随着许多组织订阅 Microsoft 365,PowerBI 成为自然的选择,因为它包含在企业订阅中。随着实时报告的需求变得越来越重要,将结构化流与 PowerBI 相结合可以无缝集成到现有的分析架构中。
2.具有混合/多云计算抱负的中型分析团队
中小型企业有不同程度的需求,并且倾向于混合搭配工具和云提供商。雪花是一个合适的选择,因为它与云无关,并且与大多数 ETL 工具兼容。与 Azure 解决方案相比,列出的工具非常昂贵。
3.数据驱动启动
初创公司的团队规模较小,基础设施需求较简单,因此工具需要既经济高效又易于使用。例如,Metabase 是一个可视化工具,构建时不需要 SQL 知识,使用时也不需要 BI 专家的帮助。
建立一个 MDS 有多难?
对于开始全新前景的组织来说,这非常简单,因为主要的云提供商提供了 MDS 模板(re。AWS 湖形成)。但是对于拥有现有传统数据堆栈的组织来说,这并不像将所有东西都迁移到云中那么简单。
如果您要从现有的成熟数据堆栈迁移到云,仔细的重新架构将是至关重要的。如果您的新云基础架构是以耦合整体的方式建立的(将一堆本地虚拟机迁移到云中),那么您只是在浪费时间。
下一节概述了设置新 MDS 时需要注意的重要事项。
使用 MDS 时需要注意的事项
我们必须记住,MDS 不仅仅是为专业数据科学家服务的,也是为任何想与数据打交道的人服务的。由于 MDS 在设计上是模块化的,许多组织倾向于找到所有最好的工具并将它们集成在一起。问题解决了,对吧?
这种方法的问题是,MDS 现在是围绕工具而不是为用户构建的。虽然从架构和工程的角度来看这没什么问题,但它会导致最常见的故障模式:糟糕和令人沮丧的用户体验。
首次实施 MDS 时,通常的方法是了解组织需要什么,并相应地购买工具(仪表板、分析工具等)。不幸的是,这就形成了一个 MDS,它是各种奇特工具的不连贯的集合;这与旨在解决问题的协作堆栈相去甚远。
一个考虑不周的用户体验的 MDS 将导致一个设计精美的数据平台,而他们试图支持的分析师和科学家却不会采纳。
好的 MDS 和坏的有什么区别?
这一切都归结为一个简单的概念:用户体验。仅仅因为一个组织拥有最好和最昂贵的工具,并不能保证会有和谐。这些工具的用户应该能够完成工作,而不会感觉像是在打一场硬仗。从本质上讲,一个组织应该构建一个以最适合其用户为中心的 MDS。
“Just let me do my job, please!” | Source
最终,这一切都归结于用户体验。牢记用户的需求和痛点,设计您的现代数据堆栈:
要有同理心和包容性
- MDS 需要对所有用户可用且包容。
- 允许用户培养对数据的信任,鼓励协作。
- 使用户能够执行他们应该做的工作(不要强迫分析师编写复杂的转换)。
周密计划;简单开始
- MDS 不需要具备所有的功能组件。
- 规划您的组织当时需要的组件,以避免不必要的成本和复杂性。
- 简单地开始,一个包含摄取、转换和存储的简单设置仍然是一个有效的 MDS。
- 相应地展开并添加组件。
找到合适的合作伙伴
- 每个组织都是不同的,这意味着没有放之四海而皆准的解决方案。你不能只是采用与另一个组织相同的设置,并期望它能工作。
- 因此,不要羞于联系供应商来帮助您设计适合您组织的 MDS。你甚至可以要求一个演示。
- 有许多公司专门帮助组织构建和设置适合其环境的现代数据堆栈,无论是初创企业还是大型企业。与人交谈,阅读那里的内容,加入 Slack 社区的行列。
在哪里可以找到关于 MDSs 的更多信息?
这是一个大规模爆炸的景观,每天都在不断发展!以下是一些可帮助您快速了解现代数据堆栈的资源:
结论
就在第二次世界大战后,汽车制造商努力降低生产成本,在生产过程中遇到了许多障碍,损害了他们的利润。后来,丰田创造了准时制(JIT)生产系统,消除了大部分问题,提高了效率,同时又不影响质量。没过多久,其他制造商也意识到了其中的好处,并采用了类似的方法。
回到科技行业,组织意识到数据正变得越来越复杂,他们的传统数据堆栈根本无法应对。现代数据堆栈是一种可以帮助组织节省时间、精力和资金的解决方案。它比传统的数据堆栈更快、更易扩展、更易访问。MDS 还帮助组织过渡到现代的数据驱动型组织,这对于创建业务解决方案至关重要。在当今时代,没有可操作的数据,任何组织都无法保持竞争力。
仅仅这些好处就足以成为任何组织认真重新评估其当前系统的理由。然而,重要的是不要被技术的热潮所吸引,不要为了现代化而现代化。要真正受益于 MDS,需要仔细规划以实现良好的用户体验。设计一个好的 MDS,让你的员工做他们的工作,回报将是无价的。**
海王星现场监测 ML 实验完全指南
原文:https://web.archive.org/web/https://neptune.ai/blog/monitoring-machine-learning-experiments-guide
训练机器学习或深度学习模型可能需要很长时间。
如果你和我一样,你想知道那段时间发生了什么,你可能会感兴趣:
- 监控您的培训和验证损失,
- 再看 GPU 消耗,
- 每隔一个时期查看图像预测
- 还有一堆其他的东西。
海王星让你做到这一切,在这篇文章中,我会告诉你如何做到这一点。循序渐进。
看看这个例子,运行,看看它在 Neptune 应用程序中会是什么样子。
如果你想在没有注册的情况下尝试 Neptune monitoring,只需跳转到Initialize Neptune
部分,作为一个匿名用户从那里开始。
设置您的 Neptune 帐户
建立一个项目并将你的脚本连接到 Neptune 是非常简单的,但是你仍然需要这样做🙂
让我们尽快解决这个问题。
1.创建一个项目
让我们先创建一个项目。
为此:
- 进入海王星 app ,
- 点击左边的
New project
按钮, - 给它一个名字,
- 决定它是公开的还是私人的,
- 完成了。
2.获取您的 API 令牌
您将需要一个 Neptune API 令牌(您的个人密钥)来连接您用 Neptune 运行的脚本。
为此:
- 点击右边的用户标志
- 点击
Get Your API token
- 复制您的 API 令牌
- 将它粘贴到环境变量、配置文件中,或者直接粘贴到您的脚本中(如果您真的喜欢冒险的话)🙂
令牌就像密码一样,所以我尽量保护它的安全。
因为我是 Linux 爱好者,所以我把它放在了我的环境文件~/.bashrc
中。如果您使用不同的系统,请查看文档中的 API 令牌部分。
有了它,无论你何时运行我的训练脚本,Neptune 都会知道你是谁,并适当地记录事情。
3.安装客户端库
要使用 Neptune,您需要一个客户端库来记录您所关心的一切。
因为我正在使用 Python,所以我将使用 Python 客户端,但是您也可以通过 R 语言使用 Neptune。
您可以用 pip 安装它:
pip install neptune-client
4.初始化海王星
现在您已经设置好了一切,您可以开始监控了!
首先,通过在脚本顶部添加以下内容,将脚本连接到 Neptune:
import neptune.new as neptune
run = neptune.init_run(
project="workspace-name/project-name",
api_token="Your Neptune API token",
)
5.创建跑步
使用 init_run() 方法创建一个新的运行。当我们执行上面的 neptune.init_run()时,我们开始了一次运行。
然后,开始的运行在后台跟踪一些系统指标,以及您在代码中记录的任何元数据。默认情况下,Neptune 会定期在后台与服务器同步数据。检查【Neptune 到底自动记录了什么。
到 Neptune 的连接保持打开,直到运行停止或者脚本执行完毕。您可以通过调用 run.stop()来显式停止运行。
但是什么是跑步呢?
一个' run '是项目中的一个名称空间,您可以在其中记录模型构建元数据。
通常,每次执行进行模型训练、重新训练或推理的脚本时,都会创建一个运行。可以将运行视为您在代码中定义的类似字典的结构。
他们有:
- 字段,您可以在其中记录您的 ML 元数据
- 名称空间,它组织你的字段
无论您创建什么层次元数据结构,Neptune 都会在 UI 中反映出来。
要创建结构化名称空间,请使用正斜杠/
run["metrics/f1_score"] = 0.67
run["metrics/test/roc"] = 0.82
上面的片段:
- 创建两个名称空间:metrics 和 metrics/test。
- 为字段 f1_score 和 roc 赋值。
关于 run 参数的完整列表,可以参考 Neptune 的 API 文档。
海王星上的监测实验:方法
记录基本的东西
简而言之,登录 Neptune 非常简单:
run["WHAT_YOU_WANT_TO_LOG"] = ITS_VALUE
让我们来看看一些不同的方式,你可以记录重要的事情到海王星。
您可以记录:
- 度量和损失->
run["accuracy"]=0.90
- 图像和图表->
run["images"].upload("bboxes.png")
; - 模型文件之类的工件->
run["model_checkpoints"].upload("my_model.pt")
- 和许多其他事情。
有时你可能只是想在训练前后记录一些东西。
在这种情况下,只要做:
params = {
"activation": "sigmoid",
"dropout": 0.25,
"learning_rate": 0.1,
"n_epochs": 100,
}
在其他场景中,有一个训练循环,您可能希望在其中记录一系列值。为此,我们使用。log()函数。
for epoch in range(params["n_epochs"]):
# this would normally be your training loop
run["train/loss"].log(0.99**epoch)
run["train/acc"].log(1.01**epoch)
run["eval/loss"].log(0.98**epoch)
run["eval/acc"].log(1.02**epoch)
这将创建名称空间“train”和“eval”,每个名称空间都有一个loss
和acc
字段。
稍后你可以在应用程序中看到这些可视化的图表。
集成日志记录
为了使日志更容易,我们为大多数 Python ML 库创建了集成,包括 PyTorch、TensorFlow、Keras、scikit-learn 等等。你可以在这里看到所有海王星的整合。这些集成为您提供了现成的实用程序,可以记录您通常会在这些 ML 库中记录的大多数 ML 元数据。我们来看几个例子。
Monitor TensorFlow/Keras models
Neptune–Keras 集成会自动记录以下元数据:
- 模型摘要
- 用于定型模型的优化程序的参数
- 训练期间传递给 model.fit 的参数
- 每个时期的当前学习率
- 训练期间的硬件消耗和 stdout/stderr 输出
- 培训代码和 Git 信息
要在使用 Keras 训练模型时记录元数据,可以按以下方式使用 NeptuneCallback。
from neptune.new.integrations.tensorflow_keras import NeptuneCallback
run = neptune.init_run()
neptune_cbk = NeptuneCallback(run=run)
model.fit(
x_train,
y_train,
epochs=5,
batch_size=64,
callbacks=[neptune_cbk],
)
您的训练指标将自动记录到 Neptune:
See this example in the Neptune app
查看文档,了解更多关于如何使用 Neptune-Keras 集成的信息。
监控时间序列先知模型
Prophet 是一个流行的时间序列预测库。通过 Neptune-Prophet 集成,您可以在使用 Prophet 训练模型时跟踪参数、预测数据框、残差诊断图表、交叉验证折叠和其他元数据。
这里有一个如何一次性记录关于你的先知模型的相关元数据的例子。
import pandas as pd
from prophet import Prophet
import neptune.new as neptune
import neptune.new.integrations.prophet as npt_utils
run = neptune.init_run()
dataset = pd.read_csv(
"https://raw.githubusercontent.com/facebook/prophet/main/examples/example_wp_log_peyton_manning.csv"
)
model = Prophet()
model.fit(dataset)
run["prophet_summary"] = npt_utils.create_summary(
model, dataset, log_interactive=True
)
See this example in the Neptune app
查看文档以了解更多关于 Neptune-Prophet 整合的信息。
监控 Optuna 超参数优化
参数调整框架 Optuna 也有一个回调系统,您可以很好地将 Neptune 插入其中。每次参数搜索迭代后,所有结果都会被记录和更新。
import neptune.new.integrations.optuna as optuna_utils
run = neptune.init_run()
neptune_callback = optuna_utils.NeptuneCallback(run)
study = optuna.create_study(direction="maximize")
study.optimize(objective, n_trials=20, callbacks=[neptune_callback])
See this example in the Neptune app
访问文档以了解更多关于 Neptune-Optuna 整合的信息。
大多数 ML 框架都有回调系统。它们略有不同,但想法是一样的。你可以看看 Neptune 支持的工具的完整列表。如果您无法在这个列表中找到您的框架,您总是可以求助于通过 Neptune 客户端登录的老方法,正如上面已经讨论过的。
在海王星能监测到什么?
您可以登录 Neptune 并实时监控许多不同的事情。
可以记录每个实验的指标和学习曲线、硬件消耗、模型预测、ROC 曲线、控制台日志等,并进行实时探索。
让我们一个接一个地检查其中的几个。
监控 ML 指标和损失
您可以使用= assignment 将分数和度量记录为单个值,或者使用 log()方法将分数和度量记录为一系列值。
# Log scores (single value)
run["score"] = 0.97
run["test/acc"] = 0.97
# Log metrics (series of values)
for epoch in range(100):
# your training loop
acc = ...
loss = ...
metric = ...
run["train/accuracy"].log(acc)
run["train/loss"].log(loss)
run["metric"].log(metric)
See this example in the Neptune app
监控硬件资源和控制台日志
这些实际上是自动记录到 Neptune 的:
run = neptune.init_run(capture_hardware_metrics=True)
直接去Monitoring
版块看就知道了:
监控图像预测
您可以记录单个图像或一系列图像(如下例所示)。
from neptune.new.types import File
for name in misclassified_images_names:
y_pred = ...
y_true = ...
run["misclassified_imgs"].log(File("misclassified_image.png"))
它们将出现在应用程序的图库中:
监控文件更新
你可以通过使用upload()
方法从任何深度学习框架中保存模型权重。在下面的例子中,它们被记录在名称空间model_checkpoints
中名为my_model
的字段下。
# Log PyTorch model weights
my_model = ...
torch.save(my_model, "my_model.pt")
run["model_checkpoints/my_model"].upload("model_checkpoints/my_model.pt")
模型检查点出现在所有元数据部分。
See this example in the Neptune app
将正在进行的实验与以前的实验进行比较
在海王星监测 ML 实验很酷的一点是,你可以将正在运行的实验与你之前的实验进行比较。
这使得确定正在训练的模型是否显示出改进的希望变得容易。如果没有,你甚至可以从用户界面中止实验。
为此:
- 转到实验仪表板
- 选择几个实验
- 单击比较以覆盖学习曲线,并显示参数和指标的差异
- 如果你看不到训练的重点,点击中止正在进行的训练
通过链接与其他人分享跑步实验
您可以通过复制实验的链接并将其发送给某人来分享您正在进行的实验。
就像我在这里和你分享这个实验一样:
https://ui . Neptune . ai/o/shared/org/STEP-by-STEP-monitoring-experiments-live/e/STEP-22
最酷的是,你可以让人们直接进入你实验中有趣的部分,比如代码、硬件消耗图表或学习曲线。你也可以通过链接分享实验对比。
最后的想法
有了这些信息,你应该能够监控你所关心的机器学习实验的每一部分。
如需更多信息,您可以:
实验监控快乐!
蒙特卡洛模拟:实践指南
原文:https://web.archive.org/web/https://neptune.ai/blog/monte-carlo-simulation
蒙特卡洛模拟是一系列实验,帮助我们理解当随机变量的干预存在时,不同结果的概率。这是一种可以用来理解预测和预测模型中风险和不确定性的影响的技术。
虽然蒙特卡罗方法可以在许多方面进行研究和应用,但我们将重点关注:
- 蒙特卡罗模拟/方法实际上是什么,以及一些例子和一些实验。
- 用蒙特卡罗和推断统计的方法模拟轮盘游戏。
- 了解它在赌丨博之外的应用领域。
为什么要学习蒙特卡洛模拟?
蒙特卡罗模拟利用了一种叫做蒙特卡罗抽样技术的东西,它随机抽样一个概率分布。在本文后面,我们将看到一个基于这种技术的模拟。
蒙特卡洛模拟在商业和金融等领域有着广泛的潜在应用。电信公司用它们来评估不同场景下的网络性能,帮助他们优化网络。分析师用它们来评估一个实体违约的风险,并分析期权等衍生品。保险公司和油井钻探者也使用它们。蒙特卡罗模拟在商业和金融之外有无数的应用,例如气象学、天文学和粒子物理学。[2]
在机器学习中,蒙特卡罗方法为重采样技术提供了基础,如用于估计数量的 bootstrap 方法,如有限数据集上模型的准确性。
bootstrap 方法是一种重采样技术,用于通过替换对数据集进行采样来估计总体的统计数据。
蒙特卡罗模拟的一些历史
波兰裔美国数学家 Stanislaw Ulam 首先被认为研究了蒙特卡罗模拟。在玩单人纸牌游戏时,他想知道赢这场游戏的概率有多大。所以,他花了很多时间去尝试,但是失败了。这是可以理解的,因为纸牌游戏有大量的组合来进行计算,也是手工计算。
为了解决这个问题,他想走实验路线,计算赢的手数/玩的手数。但他已经玩了很多手牌,但都没有赢过,所以他要花好几年才能玩够牌,才能得到一个好的估值。所以他想到了在电脑上模拟游戏,而不是玩所有的手牌。
那时候,接触电脑并不容易,因为周围没有很多机器。因此,尽管他很有影响力,他还是联系了当时很受欢迎的数学家约翰·冯·诺依曼,使用他的 ENIAC 机器,他们能够模拟单人纸牌游戏。由此,蒙特卡洛模拟诞生了!
蒙特卡洛模拟是什么?
蒙特卡洛模拟是一种利用推断统计原理估算未知量数值的方法。推断统计对应于对样本/随机变量应用统计算法,从样本中抽取,该样本往往表现出与总体(从中抽取)相同的属性。
Source: original image
在单人纸牌游戏的情况下,人口是所有可能玩的单人纸牌游戏的总体,样本是我们玩的游戏(> 1)。现在,推断统计告诉我们,我们可以根据对样本的统计对总体进行推断。
注:推断统计量的陈述只有在样本被随机抽样时才成立。
**推理统计学的一个主要部分是决策。但是要做决定,你必须知道可能发生的结果的组合,以及会有什么样的变化。
让我们举个例子来更好地理解这一点。假设给你一枚硬币,你必须估计如果你把硬币抛一定次数,你会得到多少正面。你有多大把握说所有的空翻都会让你回头?还是第(t+1)次会出现人头?让我们权衡一些可能性,让它变得有趣:
- 抛了两次硬币。两个都是正面,如果你要预测第三次投掷的结果,你会称重吗?
- 如果有 100 次尝试,都是正面朝上,你会觉得第 101 次翻转是正面朝上更舒服吗?
- 现在,如果 100 次试验中,有 52 次是正面朝上呢?你的最佳猜测是 52/100 吗?
对于 t=2 次,你不太有信心预测第三个 1 头,对于 t=100,你更有信心预测第 101 次翻转是头,而所有的都是头,而不是 52 次翻转是头。
这个的答案是方差。对我们估计的信心取决于两件事:
- 样本的大小(100 比 2)
- 样本的方差(所有头对 52 头)
随着方差的增大,我们需要更大的样本来获得相同程度的置信度。当几乎一半是正面,一半是反面时,方差很高,但当结果总是正面,方差几乎为 0。
现在让我们看看一些基于蒙特卡罗方法的实验。
蒙特卡罗模拟实验
统计学家和赌徒中最流行的游戏之一是!当然,由于各种不同的原因,我们将通过运行轮盘赌游戏来观看蒙特卡洛模拟。
*为了好玩,我们会把它分成三个互相影响的实验:
- 公平轮盘赌:你的赌注回报的期望值应该是 0%。
- 欧洲轮盘赌:你的赌注回报的期望值应该是~-2.7%
- 美国轮盘赌:你下注回报的期望值应该是~-5.5%。
公平轮盘赌
让我们定义一个简单的 python 类来模拟这个游戏:
import random
random.seed(0)
class FairRoulette():
def __init__(self):
self.pockets = []
for i in range(1,37):
self.pockets.append(i)
self.ball = None
self.pocketOdds = len(self.pockets) - 1
def spin(self):
self.ball = random.choice(self.pockets)
def betPocket(self, pocket, amt):
if str(pocket) == str(self.ball):
return amt*self.pocketOdds
else: return -amt
def __str__(self):
return 'Fair Roulette'
- 共有 36 个口袋,编号从 1 到 36
- 最初,球是零。轮子旋转,球随机落在其中一个口袋里
- 如果球落地的口袋号码与你先前下注的号码相符,你就赢了这场游戏。因此,如果您在开始时下注$1,并且赢了这手牌,那么您最后会得到$36。很神奇,不是吗?
现在是一个把所有指令和规则放在一起的函数:
def playRoulette(game, numSpins, pocket, bet, toPrint):
totalPocket = 0
for i in range(numSpins):
game.spin()
totalPocket += game.betPocket(pocket, bet)
if toPrint:
print(f'{numSpins} spins of {game}')
print(f'Expected return betting {pocket} = {str(100*totalPocket/numSpins)}% n')
return (totalPocket/numSpins)
代码基本上是不言自明的。 totalPocket 是一个变量,保存您赢/输的钱的总和。 numSpins 是你下注或旋转轮盘的次数。
现在让我们运行 100 次和 100 万次旋转。
game = FairRoulette()
for numSpins in (100, 1000000):
for i in range(3):
playRoulette(game, numSpins, 2, 1, True)
你可以在上图中看到
- 对于 100 次旋转,你得到了 44%的正回报,然后是负 28%,再次是正 44%,方差高得多,但当你看到更大的图片时,事情变得有趣了。
- 对于一百万次旋转,回报总是在平均值 0 附近徘徊,这就是我们开始时的情况。方差很低。
人们一定想知道为什么要为一百万次旋转而烦恼?赌徒可能不会,但赌场肯定会。对于一个赌徒来说,更难预测他那天会赢或输多少,因为他在那天可以玩 100 场游戏。但是,一个赌场必须在数千名赌徒参与数千万手牌的情况下运营数年。
所以这个实验进行的就是所谓的大数定律。根据大数定律:
从大量试验中获得的结果的平均值应该接近预期值,并且随着进行更多的试验,将趋向于变得更接近预期值。
这意味着,如果我们旋转轮盘赌轮盘无限次,预期回报将为零。所以当旋转一百万次比一百次时,我们得到的结果更接近于零。
让我们现在运行欧洲和美国轮盘赌。你看,赌场是不公平的。毕竟,他们必须坚持“房子总是赢家!”。在欧洲轮盘赌的情况下,他们在轮盘上加上一个绿色的“0 ”,而在美国轮盘赌中,他们偷偷加上另一个绿色的“00 ”,使得赌徒更难获胜。
American roulette vs European roulette | Source
让我们模拟两者,并将其与公平轮盘模拟进行比较。
class EuRoulette(FairRoulette):
def __init__(self):
FairRoulette.__init__(self)
self.pockets.append('0')
def __str__(self):
return 'European Roulette'
class AmRoulette(EuRoulette):
def __init__(self):
EuRoulette.__init__(self)
self.pockets.append('00')
def __str__(self):
return 'American Roulette'
我们只是继承了 FairRoulette 类,因为我们添加了额外的口袋,功能和属性保持不变。现在运行试验并保存回报的函数:
def findPocketReturn(game, numTrials, trialSize, toPrint):
pocketReturns = []
for t in range(numTrials):
trialVals = playRoulette(game, trialSize, 2, 1, toPrint)
pocketReturns.append(trialVals)
return pocketReturns
为了进行比较,我们转动三个转盘,看每个转盘 20 次试验的平均回报。
numTrials = 20
resultDict = {}
games = (FairRoulette, EuRoulette, AmRoulette)
for G in games:
resultDict[G().__str__()] = []
for numSpins in (1000, 10000, 100000, 1000000):
print(f'nSimulate, {numTrials} trials of {numSpins} spins each')
for G in games:
pocketReturns = findPocketReturn(G(), numTrials,
numSpins, False)
expReturn = 100*sum(pocketReturns)/len(pocketReturns)
print(f'Exp. return for {G()} = {str(round(expReturn, 4))}%')
运行上面的摘录会得到这样的结果:
你可以在这里看到,当我们接近无穷大时,每场比赛的回报越来越接近他们的期望值。因此,如果你做多,你很可能在欧洲损失 3%,在美国损失 5%。告诉过你,赌场是稳赚不赔的生意。
注意:无论何时你随机抽样,你都不能保证得到完美的准确性。总是有可能得到奇怪的样本,这也是我们平均进行 20 次试验的原因之一。
你已经到达终点了!
您现在了解了什么是蒙特卡罗模拟以及如何进行模拟。我们只举了轮盘赌的例子,但是你可以在其他的机会游戏上做实验。访问笔记本这里在这个博客中找到完整的代码和我们为你做的一个额外的实验!
以下是您可能想关注的一些其他研究资源:
参考
- 蒙特卡洛模拟
- https://www . investopedia . com/terms/m/montecallosimulation . ASP
- https://en.wikipedia.org/wiki/Monte_Carlo_method***
机器学习行业中最常用的工具、框架和库(综述)
机器学习越来越受欢迎,越来越多的公司正在利用这项新技术的力量。然而,关于团队本身的知识仍然有限——他们使用什么?他们喜欢什么?他们是谁?
Neptune 是由数据科学家为数据科学家打造的——中间没有晦涩难懂的东西。因此,当面临知识缺失的挑战时,我们会尽最大努力收集数据。受益于我们的联系人和读者网络,其中许多人本身就是机器学习专家,我们发起了一项投票,以获得关于最流行的技术、团队的性质及其日常工作的答案。
结果?看下面!
你在研究机器学习的哪个领域?
第一个问题——团队在做什么?炒作其他技术的墙后面是不是有某种隐藏的王者?一些现代机器学习的和平领导者,在服务器机房的无菌光线下稳步增长,而媒体供应商继续追逐过度兴奋的幽灵?
我们将类别分为:
计算机视觉
- 强化学习
- 自然语言处理
- 预测
- 扁平的
- 其他的
- 我们发现团队中最突出的领域是 NLP(自然语言处理),其次是计算机视觉、预测、表格、其他和强化学习。
根据 2019 年的一份报告,在未来 5 年内,您 80%的数据将是非结构化的,我们可以使用这些数据来为情感分析、命名实体识别、主题分割、文本摘要、关系提取等任务建立机器学习模型——只要是您能想到的。
考虑到 NLP 技术的进步,更多的用例将很快出现。
当您连接到公司的服务中心时,您可能会在电话中听到“此电话可能会出于质量和培训目的而被录音”,或者在您从某个组织购买服务或产品后被要求填写调查问卷。
这些信息可以用来了解受众对某个组织的产品或服务的情感倾向。
在进行的调查中,31 个团队中的 26 个团队确认他们都与 NLP 一起处理文本数据。
几乎所有的团队都在几乎所有的领域工作过,除了强化学习。
“强化学习是一种基于代理的学习,它使代理能够在交互式环境中通过试错来学习。”
但考虑到强化学习仍然是更学术和研究的领域,而不是商业领域,这并不奇怪。一个严重的原因是——强化学习可能不适合初创公司,因为强化学习所需的数据是海量的,面临众多技术挑战。
OpenAIFive 系统的估计批量超过 100 万次观测。这意味着我们有超过一百万的国家行动奖励来更新每个模拟。这使得强化学习样本有效,因为需要大量训练数据来达到期望的性能。
例如, AlphaGo ,第一个在围棋中击败世界冠军 Lee Sedol 的 AI 智能体,通过玩数百万场游戏不间断地接受了几天的训练,在这些模拟中积累了数千年的知识,估计仅计算能力就花费了近300 万美元。
AlphaGo Zero 向所有人展示了建立甚至可以击败世界冠军的系统是可能的,但由于模型的昂贵,大多数初创公司仍然无法开发这种系统。
关键要点——在有钱的地方工作。无论是在面向商业的领域,还是对拥有大量现金用于强化学习的科技巨头来说。
你和什么类型的模特一起工作?
我们向所有团队询问了他们用来构建模型的方法,并将它们分为四类。
深度学习
- 增强树(LightGBM、XGBoost、Catboost)
- 线性回归
- 其他的
- 深度学习模型在这里被证明是赢家,被 14 个团队经常使用。
31 个团队中至少有 29 个在某个时候使用了深度学习模型。
我们在这里可以再次看到,深度学习是赢家。由于在大量数据集上训练时的预测准确性,深度学习越来越受欢迎。
深度学习往往最适合非结构化数据,根据 Gartner 、的数据,80%的企业数据是以文本、图像、pdf 等形式存在的非结构化数据。
深度学习方法应用于社交媒体和非结构化数据,以更好地了解客户并对其进行细分。金融行业正在快速采用深度学习方法来构建用于检测欺诈交易、交易、股票预测等的系统。
医疗保健行业正在利用深度学习的力量进行药物发明、疾病诊断、虚拟医疗保健,这样的例子不胜枚举。
因此,团队在保持其通用性的同时,坚持使用交付结果的技术。因此,深度学习是一项领先的技术,似乎没有什么可以改变这一进程。
你现在用什么来训练你的 ML 模型?
由于计算能力有限,训练机器学习或深度学习模型有时可能会令人生畏。另一方面,聪明的数据科学家可以调整模型,减少对数据的渴求,使用更少的资源。因此,我们向所有 31 个团队询问了他们用于训练或建立预测模型的基础设施。
我们可以将它们分为四类。
本地机器(笔记本电脑或个人电脑)
- 本地集群
- 大云(AWS、GCP、Azure)
- 专用 ML 云(Sagemaker、Floydhub)
- 我们在这里看到的使用最少的基础设施是专用的 ML 云(SageMaker,Floydhub),使用最多的是这里的本地 pc 和大云(AWS,GCP,Azure) 。
也许是因为在专门的 ML 云服务上训练你的模型有时会在你的口袋里烧一个洞。对于现金充裕的团队来说,它们很酷——确实有这样的团队,但不是很多。
除了专用的 ML cloud (SageMaker,Floydhub)之外,我们可以看到所有平台上的模型训练,无论是本地机器,大云还是本地集群,都在某个时候被使用过。这并不奇怪——在本地以较低的成本运行 prototype 以节省云中的试错过程是很常见的——最终,每一秒都要花费实实在在的现金。
我们可以看到,训练预测模型最常用的基础设施是大云(Azure、AWS、GCP)。
有时候你可能只有有限的 RAM 和 GPU 来训练一个预测模型,你只是不能随心所欲的升级系统来满足你的系统需求;这就是云服务发挥作用的地方。或者你希望在一个小时内完成训练,而不是一周——毕竟钱不是唯一的价值。
数据科学团队倾向于让每个数据科学家的机器学习任务成为他们框架武器库中的武器,以解决任何数据科学问题。
数据科学家最常用的库
Scikit-learn 是一个开源库,适用于任何公司或初创公司的每个数据科学家的机器学习任务。它建立在几个现有的 python 包之上,如 Numpy、Scipy 和 Matplotlib。
我们可以执行各种各样的机器学习算法,如回归、分类、聚类等。具有各种性能度量,如 MSE(均方误差)、AUC(曲线下面积)、ROC(接收机工作特性)等。
像摩根大通、 Spotify 、 Inria 、抱脸、等的公司。正在将 scikit-learn 用于他们的机器学习工作流程。
TensorFlow 是一个开源库,由 Google 开发,用于进行端到端的机器学习项目。
TensorFlow 使用数据流图,其中数据(张量)可以由一系列处理。TensorFlow 提供了简单的模型构建、ML 工具如 TensorBoard 和 ML 产品。
像英伟达、 Snapchat 、高通、苹果公司这样的公司正在将 TensorFlow 用于他们基于人工智能的应用。
PyTorch 是由脸书创建的一个开源机器学习库,使用户能够使用 GPU 加速进行张量计算,并建立深度学习模型。
像微软、 Airbnb 和 OpenAI 这样的公司似乎利用 PyTorch 来利用人工智能的力量。OpenAI 甚至终止了它对强化学习教育研究的 TensorFlow 使用。
数据科学家最常用的工具
除了硬件和技术方面,还有日常工作使用常见的贸易工具。铁匠有他的锤子,木匠有他的凿子,数据科学家有…
是的,每个人的朋友都来了。Jupyter Notebook 是一个基于网络的交互式环境,用于构建机器学习模型和数据可视化。您可以执行其他几项任务,如数据清理、数据转换、统计建模等。
Weka 引用“无需编程的机器学习”。Weka 可以建立机器学习管道,训练分类器,而无需编写一行代码。
Weka 还提供了一个用于深度学习的包,名为 WekaDeepLearning4j ,它有一个 GUI,可以直接构建神经网络、卷积网络和递归网络。
Apache spark 提供了一个名为 MLlib 的机器学习 API,用于分类、聚类、频繁模式匹配、推荐系统、回归等机器学习任务。
最后的想法
参加调查让我们深入了解了最突出的领域,用于 ML 工作流的机器学习基础设施,最常用的机器学习方法,为什么深度学习压倒了传统的机器学习,以及强化学习的问题。
但与流行的方法相反,这是来自数据科学家之间的数据科学家,没有旨在出售任何东西的夸大其词。答案的真诚和准确性为我们提供了对数据科学界的乐观看法——当涉及到我们使用的技术堆栈或工具时,我们有自知之明,充满常识,并抵制胡说八道。
在今天这个臃肿而充满活力的世界里,这很酷。
But contrary to the popular approach, this has come from data scientists to data scientists with no overhyped babble aimed to sell anything. The sincerity and accuracy of the answers provided us with an optimistic view of the data science community – we are self aware, full of the common sense and bullshit-resistant when it comes to tech stack or tools we use.
And that’s cool in today’s bloated and pumped-up word.
从 TensorFlow 迁移到 PyTorch
原文:https://web.archive.org/web/https://neptune.ai/blog/moving-from-tensorflow-to-pytorch
深度学习框架、库和众多工具的概念的存在是为了减少否则必须计算的大量手动计算。TensorFlow 和 PyTorch 是目前构造神经网络架构最流行的两种框架。
虽然 TensorFlow 比 PyTorch 早一年发布,但最近大多数开发人员都倾向于转向 PyTorch。在本文中,我们将探讨如何从 TensorFlow 切换到 PyTorch 的大部分细节。我们将首先理解使用这两种深度学习框架的原因。
然后,我们将更深入地研究这些库的安装过程以及成功过渡的实践方法。我们还将研究 PyTorch 库在 MNIST 的执行情况,并最终理解 PyTorch 在所有情况下是否都是最好的。
两种深度学习框架简介
在文章的这一部分,我们将简要概述这两个深度学习框架,即 TensorFlow 和 PyTorch 。我们还将尝试理解为什么人们会从 TensorFlow 过渡到 PyTorch,并给出一些实际的解释,然后再用更实际的方法来解决这个问题。
TensorFlow
TensorFlow 是谷歌在 2015 年推出的用于开发神经网络的深度学习框架的较老解释之一。谷歌大脑团队的产品总是最值得信赖的方法之一,用于开始任何类型的复杂任务。
TensorFlow 是一个开源库,使用它可以开发和构建大多数机器学习和人工智能模型。TensorFlow 2.0 的更新版本也集成了 Keras,是相应地培训、开发、操作和运行机器学习模型的一个很好的选择。
PyTorch
PyTorch 由脸书人工智能研究(FAIR)团队于 2016 年 9 月开发。它已经获得了很多关注,尤其是最近,大多数数据科学家和研究人员都试图从 TensorFlow 成功过渡到 PyTorch。它与 Python 编程语言无缝集成,大多数开发人员发现使用它非常自然。
PyTorch 可以被认为是一个平台,在这个平台上,你可以与张量(类似于 NumPy 这样的库,我们使用数组)一起使用 GPU 加速来计算深度学习模型。在 PyTorch 的帮助下,您还能够获得动态图表,使用这些图表您可以动态地分析您的模型的工作方法。
为什么人们要从 TensorFlow 迁移到 PyTorch?
虽然 TensorFlow 似乎是您的军火库中用于大多数深度学习任务的一个很好的工具,但大多数人现在更喜欢从 TensorFlow 切换到 PyTorch。让我们讨论一下从一个深度学习框架过渡到另一个框架的一些主要原因。
-
Tensorflow 创建静态图,而 PyTorch 创建动态图。在 TensorFlow 中,机器学习模型的大多数计算图都应该完全从头开始定义
-
在 PyTorch 中,您可以定义、操作和适应特定的工作图,这在像 RNNs 中的可变长度输入这样的场景中特别有用。
-
使用 PyTorch 处理模型更加直观,因为它主要是用 Python 开发的,并且它与 Python 编程语言的自然工作方式无缝结合。
-
另一方面,TensorFlow 的学习曲线很陡,大多数用户乍一看会觉得很难掌握。即使当你学习张量流时,一些概念也需要重新审视。
-
PyTorch 最适合开发快速原型和研究项目,这就是为什么大多数人选择从 TensorFlow 过渡到 PyTorch。
从 TensorFlow 切换到 PyTorch 容易吗?
在文章的这一部分,我们将关注从 TensorFlow 切换到 PyTorch 是否容易。从任何深度学习框架转换的第一步是安装过程。该库必须易于安装,以便开发人员可以开始构建模型,而不必太担心安装过程的复杂细节。
虽然安装 TensorFlow 和 PyTorch 库的 CPU 版本非常简单,但是使用 CPU 来训练复杂的模型是很原始的。让我们来看看他们的 GPU 安装程序之间的快速概述和比较。
探索张量流安装的复杂过程
如果你试图在你的 Windows 操作系统或任何 Linux 系统上安装 TensorFlow 的 GPU 版本,整个过程相当复杂。即使您正在使用 Anaconda 软件来开发您的深度学习项目,获得 TensorFlow 最新版本的过程也比您预期的要长一些。但是,如果您对使用任何版本的 TensorFlow 感兴趣,可以使用以下命令在您的虚拟环境中安装 TensorFlow 2.0。
conda install -c anaconda tensorflow-gpu
然而,TensorFlow 的版本不断更新,上面的安装并不总是这样。因此,在共享代码或从事研究项目时,可能会引发许多问题。
要在您的系统上安装最新版本的 TensorFlow,您需要确保下载了安装过程所需的特定驱动程序。您需要查看官方的 TensorFlow 文档,了解您需要下载并安装到系统上的 CUDA 文件和 CuDNN 版本的具体信息。
CUDA 和 CuDNN 版本由 Nvidia 不断更新,类似于它们的驱动程序。每当有 TensorFlow 最新版本的新发布,他们通常也会更新 CUDA 和 CuDNN 需求。
一些功能在新版本中被贬低,因此,下载新版本以保持更新变得至关重要。但是每次我们需要安装新的 TensorFlow 版本时,Cuda 和 CuDNN 更新都必须单独下载和安装。整个过程非常繁琐,每次更新都需要重复。
了解更简单的 PyTorch 安装
与 TensorFlow 安装相比,PyTorch 安装要简单得多。为了成功安装 PyTorch,您需要做的就是访问 PyTorch 官方网站获取安装指南,您可以通过此链接选择您的软件需求类型、您的开发包和您的计算平台。该网站将自动为您提供准确的命令,您可以复制粘贴在您的默认或虚拟环境中开始安装。安装语句示例如下:
conda install pytorch torchvision torchaudio cudatoolkit=10.2 -c pytorch
如何从 TensorFlow 切换到 PyTorch
对于 TensorFlow 的专家来说,可能想知道从一个库切换到另一个库的区别。从 TensorFlow 转换到 PyTorch 并不复杂,因为 PyTorch 提供了一种python 式的方法来解决大多数问题。在本节中,我们将介绍从 TensorFlow 成功转换到 PyTorch 的一些主要基础知识。
我们将了解如何在这两个深度学习框架中实现张量并与之合作。然后我们将了解他们的图形工作机制,即 TensorFlow 中的静态图形方法和 PyTorch 中的动态图形。最后,在本节中,我们还将比较 TensorFlow 和 PyTorch 的训练循环。
理解如何实现张量
张量是 n 维数组,通过它你可以开发和构造大部分的机器学习项目。大多数深度学习框架的核心方面是张量的概念,张量是向量和矩阵的推广。在您的系统上安装 PyTorch 后,您可以继续比较 TensorFlow 和 PyTorch 的编码过程之间的一些基本差异。
让我们比较并实现一些基本实现,开始从一个库到另一个库的转换。我们将首先看看如何导入这两个库,初始化张量,并用这些张量执行一些基本操作。初始化张量的张量流代码如下:
import tensorflow as tf
rank_2_tensor = tf.constant([[1, 2],
[3, 4],
[5, 6]], dtype=tf.int32)
在 PyTorch 中,同样的实现可以按如下方式完成:
import torch
rank_2_tensor = torch.tensor([[1, 2],
[3, 4],
[5, 6]], dtype=torch.int32)
在这两个框架中,库的导入和张量的定义都非常简单。让我们分析一下如何在这两个库中执行一些基本的张量计算。首先,让我们看看下面的 TensorFlow 实现示例(注意,如果需要,您也可以将示例中显示的值直接定义为变量)。
a = tf.constant([[1, 2],
[3, 4]])
b = tf.constant([[1, 1],
[1, 1]])
a = tf.Variable(a)
b = tf.Variable(b)
print(tf.add(a, b), "n")
print(tf.multiply(a, b), "n")
print(tf.matmul(a, b), "n")
在 PyTorch 中,以下实现可以解释如下:
a = torch.tensor([1, 2, 3], dtype=torch.float)
b = torch.tensor([7, 8, 9], dtype=torch.float)
print(torch.add(a, b))
print(torch.subtract(b, a))
print(a.mul(b))
print(a.dot(b))
现在,我们已经简要了解了如何在这两个深度学习框架中与张量合作,让我们通过实践方法来理解它们的工作机制。
它们的工作机制(理解各自的图表)
大多数深度学习框架都利用了计算图。这些计算图定义了必须执行计算的顺序,以便我们可以相应地获得最佳结果。
通常有两个解释器用于深度学习问题的计算,其中每个解释器服务于不同的目的。其中一个解释器用于编程语言(大多数情况下是 Python),另一个解释器根据需要管理计算图形。
因此,大多数深度学习框架利用像 Python 这样的编程语言来设置计算图,并且还设置了执行机制,这与宿主语言大不相同。
这种奇怪的设置主要是出于效率和优化的原因。计算图形可以在目标 GPU 中优化和并行运行。因此,由于并行性和依赖性驱动调度,整个计算过程被加速并且更高效。
在 TensorFlow 中,我们使用静态计算图。这些工作遵循典型的“定义并运行”惯例。?在这样的构建中,我们在开始时创建并连接所有的变量,并将它们初始化成一个静态的(不变的)会话。
然而,有必要在静态图中定义一些可变参数,这有时被认为是不方便的,尤其是对于使用 RNN 型网络的任务。我建议查看下面的网站,了解更多关于这些静态图如何工作的详细信息。让我们看看静态张量流图的实现。
import tensorflow as tf
a = tf.Variable(15)
b = tf.Variable(15)
prod = tf.multiply(a, b)
sum = tf.add(a, b)
result = prod/sum
print(result)
输出
tf.Tensor(7.5, shape=(), dtype=float64)
图表
The computational graph | Source
在 PyTorch 中,我们利用了动态图,其中计算图是在我们键入代码时构建的。当用户最初声明变量时,直接构建计算图,并且在每次迭代训练后重新构建计算图。动态图和静态图都有其特定的用例,在特定的场景中,一个比另一个更好。
动态图通常比静态图更好,因为我们可以相应地修改感兴趣的元素,而无需强调其他因素,从而在训练和模型构建过程中实现更高的灵活性。使用这种方法的唯一缺点是,有时需要更长的时间来重建图形。下面显示的 GIF 表示是 PyTorch 中一个项目如何工作的最好例子之一。
训练循环的比较
在 TensorFlow 中,创建训练循环的过程有点复杂,而且不是很直观。我们通常使用一个 tf.function,它作为一个装饰器,根据静态图来编译模型。
TensorFlow 中的正常执行使用的是急切执行,这对于调试来说是好的,但是对于模型的更快的性能和实现来说是不好的。因此,我们利用 tf.function 使框架能够应用全局性能优化。
然后,我们定义训练步骤,在该步骤中,我们通常使用梯度带函数,该函数执行自动微分。然后,我们可以定义培训过程将要发生的模型,并相应地计算损失。
应用梯度值,经历反向传播过程,最后更新训练度量。在模型完成训练后,我们可以返回我们想要的指标和值。
@tf.function
def train_step(x, y):
with tf.GradientTape() as tape:
logits = model(x, training=True)
loss_value = loss_fn(y, logits)
grads = tape.gradient(loss_value, model.trainable_weights)
optimizer.apply_gradients(zip(grads, model.trainable_weights))
train_acc_metric.update_state(y, logits)
return loss_value
这种训练循环的 PyTorch 实现非常简单和直观。我们可以动态地创建变量和定义动态图,然后继续训练我们的模型。我们可以将我们的数据和目标分配给设备(CPU 或 GPU)的状态,并继续计算前向传播,这是神经网络的前馈计算。
一旦模型完成前馈训练过程,我们就可以在 PyTorch 中一些预定义实体的帮助下计算元素的反向传播。我们计算梯度,应用反向传播方法,并执行参数更新。以下计算的代码如下所示。
for epoch in range(epochs):
for batch, (data, target) in enumerate(train_loader):
data = data.to(device=device)
target = target.to(device=device)
score = model(data)
loss = criterion(score, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
现在,我们已经理解了从 TensorFlow 切换到 PyTorch 的一些基本要求,让我们借助 PyTorch 深度学习框架来理解深度学习项目的代码演练。
PyTorch 中 MNIST 的代码演练
在本文的这一部分,我们将了解 TensorFlow 和 PyTorch 之间的一些主要差异。进一步了解他们工作程序的最好方法之一是亲自动手实施一个项目。我们将在这个代码演练比较中对 MNIST 数据集中的数字进行分类,我们将在 PyTorch 的帮助下训练一个模型,对数字从 0 到 9 进行分类。
第一步是导入计算 MNIST 项目所需的所有基本库。因为我们正在从 TensorFlow 过渡到 PyTorch,所以我们将为这个项目导入所有需要的 PyTorch 库。使用这个深度学习框架,我们可以在我们将要构建的神经网络架构中构建所有需要的层。PyTorch 的必要导入在下面的代码块中描述如下。
import torch
import torchvision
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader
import numpy as np
import matplotlib.pyplot as plt
我们的下一步是相应地设置设备参数。我们可以选择是否要将 PyTorch 中用于训练的默认设备设置为 CPU 或 GPU。如果你有一个可以使用的 GPU,那么使用它总是更好。然而,对于这个项目,即使一个 CPU 设备也能满足要求,培训不需要太长时间。在 TensorFlow 中,默认设备通常根据您的安装设置为 GPU 版本。
device = torch.device('cuda' if torch.cuda.is_available() else cpu)
我们的下一步是定义一些超参数,用于模型的构建和训练。定义了添加到总共 10 个类别中的类别数(0-9)。我们将设置默认输入大小为 784 (28×28 是 MNIST 数据的图像大小),学习率为 0.0001,批量大小为 64,并且我们将在总共 3 个时期上训练构建的模型。
num_classes = 10
input_size = 784
batch_size = 64
lr = 0.0001
epochs = 3
下一步,我们将加载我们的数据。PyTorch 框架类似于 TensorFlow 库,可以访问一些默认数据集,MNIST 就是其中之一。我们将以训练和测试数据集的形式分离图像(大约 60000 个)。DataLoader 函数在加载我们的数据时提供了非常好的工具。下面的代码片段展示了如何在 PyTorch 中加载数据。
T = torchvision.transforms.Compose([torchvision.transforms.ToTensor()])
X_train = torchvision.datasets.MNIST(root='/datasets', train=True, download=True, transform=T)
train_loader = DataLoader(dataset=X_train, batch_size=batch_size, shuffle=True)
X_test = torchvision.datasets.MNIST(root='/datasets', train=False, download=True, transform=T)
test_loader = DataLoader(dataset=X_test, batch_size=batch_size, shuffle=True)
现在我们已经收集了所需的数据,我们终于可以使用 PyTorch 深度学习框架来构建神经网络架构了。我们将使用完全连接的层类型构建来解决我们的问题。
使用 PyTorch 构建深度学习模型的过程非常简单,并且遵循 Pythonic 方法。我们将为神经网络定义一个类,并为我们的模型声明完全连接的层。功能。注意,在张量流的情况下,我们将对完全连接的层使用稠密函数。
class neural_network(nn.Module):
def __init__(self, input_size, num_classes):
super(neural_network, self).__init__()
self.fc1 = nn.Linear(in_features=input_size, out_features=50)
self.fc2 = nn.Linear(in_features=50, out_features=num_classes)
def forward(self, x):
x = self.fc1(x)
x = F.relu(x)
x = self.fc2(x)
return x
既然我们已经用 PyTorch 完成了数据收集和深度学习模型的构建,我们可以继续定义我们将利用的损失类型和最适合该任务的优化器类型。交叉熵损失对于像 MNIST 项目这样的多类分类问题来说是一个非常好的选择。
Adam 是最好的默认优化器之一,几乎可以在任何场景中找到效用。我们将为指定数量的纪元训练我们的模型。对于训练过程,我们将使用前馈完全卷积网络,然后应用反向传播来学习相应的最佳权重。
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=lr)
for epoch in range(epochs):
for batch, (data, target) in enumerate(train_loader):
data = data.to(device=device)
target = target.to(device=device)
data = data.reshape(data.shape[0], -1)
score = model(data)
loss = criterion(score, target)
optimizer.zero_grad()
loss.backward()
optimizer.step()
最后,现在我们的训练方法已经完成,我们可以继续训练和评估构建的模型,并相应地检查训练和测试的准确性。完成以下操作的步骤也非常简单,因为我们可以在正确分类的图像和错误分类的图像之间进行评估,并相应地计算准确度。
def check_accuracy(loader, model):
num_correct = 0
num_samples = 0
model.eval()
with torch.no_grad():
for x, y in loader:
x = x.to(device=device)
y = y.to(device=device)
x = x.reshape(x.shape[0], -1)
scores = model(x)
_, predictions = scores.max(1)
num_correct += (predictions == y).sum()
num_samples += predictions.size(0)
if num_samples == 60000:
print(f"Train accuracy = "
f"{float(num_correct) / float(num_samples) * 100:.2f}")
else:
print(f"Test accuracy = "
f"{float(num_correct) / float(num_samples) * 100:.2f}")
model.train()
check_accuracy(train_loader, model)
check_accuracy(test_loader, model)
通过这个构建模型来解决深度学习任务的简单过程,您可以在测试和训练数据上实现大约 91%的准确率。即使我们只利用了一个简单的全连接神经网络结构,我们也能够获得不错的结果。更重要的是,我们明白在 PyTorch 的帮助下,构建几乎任何类型的研究项目都非常简单。
该不该从 TensorFlow 转到 PyTorch?
在本节中,我们将权衡 PyTorch 的利弊,以得出最终结论,即是否值得从 TensorFlow 转换到 PyTorch。为了深度学习神经网络的研究和开发,研究人员花费所有时间从 TensorFlow 过渡到 PyTorch,这值得吗?让我们开始分析 PyTorch 的利弊。
PyTorch 的优点
1.自然界中的蟒蛇
PyTorch 的构建方式直观易懂,易于开发机器学习项目。PyTorch 中部署的大部分代码都是 Python 化的,这意味着过程化编码类似于 Python 的大部分元素。当使用 TensorFlow 时,代码更低级,更难理解,即使您对框架有很好的理解。
因此,现在有一个额外的 Keras 高级 API 集成到 TensorFlow 2.0 中,您可以在其中更轻松地开发模型。PyTorch 的功能可以很容易地用其他神奇的库实现,比如 Numpy、Scipy 和 Cython。因为 Pytorch 的大部分语法和应用程序与传统的 Python 编程非常相似,所以学习起来也非常容易。
2.良好的文档和社区支持
PyTorch 拥有最好的文档之一,可用于掌握大多数基本概念。他们有详细的描述,在那里你可以理解大部分的核心话题:火炬。张量,张量属性,张量视图,火炬。亲笔签名,等等。你也有一些深度学习项目的博客和教程支持。除了默认文档之外,整个社区都高度支持 PyTorch 及其相关项目。
3.动态图表
正如在本文前面一节中详细讨论的,PyTorch 支持动态图,而不是 TensorFlow 的静态图。这个特性对于动态创建图表特别有用。当您无法预先确定特定计算的内存分配或其他细节时,动态创建的图形最有用。它们为用户开发项目提供了更高的灵活性。
4.许多开发人员选择 PyTorch 进行项目
最近,开发人员和研究人员倾向于更多地转向 PyTorch 来构建深度学习项目。大多数研究人员更喜欢在 GitHub 等网站上分享他们的代码和他们的 PyTorch 项目实现。
这个社区充满了奇妙的资源,当人们对某个特定的话题有任何困惑时,他们愿意伸出援助之手。在研究项目中,工作、共享和开发 PyTorch 项目更加容易。
PyTorch 的缺点
1.缺乏可视化技术
在 Tensorboard 的帮助下,TensorFlow 为其开发的模型的工作可视化提供了最佳选择之一。Tensorboard 是一个非常棒的数据可视化工具包,通过它您可以监控一些功能,如训练和验证的准确性和损失、模型图、查看构建的直方图、显示图像等等。PyTorch 在可视化方面没有太大的选择,通常最好将 Tensorboard 与 PyTorch 一起使用。
2.生产所需的 API 服务器
TensorFlow 相对于 PyTorch 的另一个优势是,它有许多生产工具,可以随时部署已开发的模型。TensorFlow 提供的可伸缩性很高,因为它是为生产准备的。
TensorFlow 服务为针对生产环境设计的机器学习模型提供了一个灵活的高性能服务系统。它处理大多数推理方面,并管理训练模型的生命周期。
另一方面,我们有 TorchServe,它灵活且易于使用,但它没有 TensorFlow 的紧凑性,在与高级部署工具竞争之前还有很长的路要走。
结论
在本文中,我们已经涵盖了从 TensorFlow 深度学习框架成功过渡到 PyTorch 所需的大部分要素。PyTorch 非常适合快速原型的开发。现代的开发人员在大多数研究项目中使用 PyTorch 来产生快速有效的结果。
TensorFlow | PyTorch | |
---|---|---|
直截了当的蟒方法
|
| |
用于高质量可视化的张量板
|
在这方面稍有欠缺
|
| |
复低阶张量流码
| |
| | | |
| | |
研究型快速原型开发
|
深度神经网络实现的多功能性、Pythonic 性质、巨大的灵活性和构造的高速度使得该框架成为研究和开发的最佳选择之一。
相关来源
多 GPU 模型训练:监控和优化
你是否纠结于在多个 GPU 上监控和优化深度神经网络的训练?如果是的话,你来对地方了。
在本文中,我们将讨论 Pytorch Lightning 的多 GPU 训练,并找出优化训练过程应该采用的最佳实践。我们还将看到如何在训练过程中监控所有 GPU 的使用情况。
让我们从一些基础知识开始。
什么是使用 GPU 的分布式训练?
有时对于复杂的任务,如在计算机视觉或自然语言处理中,训练一个深度神经网络 (DNN)涉及到解决数百万或数十亿参数的梯度下降,因此它成为一个计算复杂的过程,可能需要几天甚至几周才能完成。
例如,生成式预训练变压器 3 (GPT-3)是一个自回归语言模型,具有 1750 亿个参数,在单个 NVIDIA Tesla V100 GPU 上训练它需要大约 355 年。但是如果用 1024 个 NVIDIA A100 GPUs 并行训练同一个模型,我们可以估计训练时间在 34 天左右。因此,在 GPU 上进行并行训练是目前广泛使用的加速过程的方法。
另请查看:https://Neptune . ai/blog/distributed-training-frameworks-and-tools
为了清楚地了解我们如何能够使用多个 GPU 来训练深度神经网络,让我们简单地看看神经网络是如何训练的:
- 深度神经网络模型通常使用小批量梯度下降进行训练,其中训练数据被随机采样为小批量。
- 将小批量输入模型,分两个阶段遍历模型:
- 前进传球
- 偶数道次
- 正向传递生成预测,并计算预测和地面实况之间的损失。
- 反向传递通过网络的层传递误差(称为反向传播),以获得梯度来更新模型权重。
- 通过正向和反向阶段的小批量被称为迭代,并且时期被定义为通过整个训练数据集执行正向-反向传递。
- 训练过程持续多个时期,直到模型收敛。
如果这对你来说似乎是压倒性的,我会建议这篇文章来更深入地了解神经网络是如何被训练的。
为了加快训练过程,我们使用多个 GPU 来并行化训练过程,并且数据并行和模型并行是用于并行化任务的两种技术。
数据并行性
在数据并行中,每个 GPU 保存模型的副本,并且数据被分成 n 个分区,其中每个分区用于在每个 GPU 上训练模型的副本。
当应用异步数据并行时,参数服务器负责权重更新。每个 GPU 将其梯度发送到参数服务器,然后参数服务器更新权重,并将更新后的权重发送回该 GPU。
这样,GPU 之间就没有同步了。这种方法解决了分布式计算环境中不稳定的网络问题,但是它引入了不一致性问题。此外,这种方法不会减少 GPU 之间的数据传输次数。
模型并行性
模型并行性在多个 GPU 之间划分模型,其中每个 GPU 负责模型的指定层的权重更新。中间数据,例如用于前向传递的神经网络层的输出和用于后向传递的梯度,在 GPU 之间传送。
由于这些分区具有依赖性,在模型并行性的简单实现中,一次只有一个 GPU 是活动的,导致 GPU 利用率低。为了实现并行执行,流水线并行将输入小批分成多个微批,并在多个 GPU 之间流水线执行这些微批。下图对此进行了概述:
Pipeline parallelism | Source
上图表示的是一个模型,有 4 个层放在 4 个不同的 GPU 上(纵轴)。横轴表示随着时间的推移对该模型进行训练,表明 GPU 得到了更高效的利用。但是,仍然存在一个气泡(如图所示),其中某些 GPU 没有得到利用。
为了对模型并行性和数据并行性有一个完整的了解,我强烈建议阅读分布式培训:数据科学家指南。
PyTorch Lightning 的多 GPU 训练
在本节中,我们将重点讨论如何使用 PyTorch Lightning 在多个 GPU 上进行训练,因为它在去年越来越受欢迎。PyTorch Lightning 使用起来非常简单方便,它帮助我们缩放模型,没有样板文件。样板代码是大多数人在缩放模型时容易出错的地方。
有一些编码实践可以帮助您毫无问题地将代码迁移到 GPU。你应该参考 PyTorch Lightning 文档来获得更多关于这个的信息。
分布式模式
在本节中,我们将介绍 Pytorch lightning 提供的不同分布式模式。
数据并行
我们可以在一台拥有多个 GPU 的机器上训练一个模型。使用 DataParallel (DP)方法,一个批处理会在一个节点的所有选定 GPU 之间平均分配,之后根节点会聚合所有结果。但是 Pytorch lightning 开发人员不建议使用这种方法,因为它还不稳定,如果在 forward()或*_step()方法中为模块分配状态,您可能会看到错误或行为不当。
trainer = Trainer(gpus=4, accelerator="dp")
分布式数据并行
分布式数据并行(DDP)的工作方式如下:
- 每个节点上的每个 GPU 都有自己的进程。
- 每个 GPU 都可以看到整个数据集的子集。它只会看到那个子集。
- 每个进程初始化模型。
- 每个进程并行执行完整的向前和向后传递。
- 梯度在所有过程中被同步和平均。
- 每个进程更新它的优化器。
我们可以通过两种方式使用该方法,即“ddp”和“ddp_spawn”。在“ddp”方法中,使用正确的环境变量多次调用脚本。
trainer = Trainer(gpus=8, accelerator="ddp")
trainer = Trainer(gpus=8, accelerator="ddp", num_nodes=4)
虽然在大多数情况下这似乎是一个不错的选择,但它有一些局限性,因为它不能在 Jupyter Notebook、Google COLAB 和 Kaggle 等工具中工作。此外,当有一个没有根包的嵌套脚本时,它似乎不起作用。在这些情况下,首选“ddp_spawn”方法。
“ddp_spawn”除了使用 torch.multiprocessing.spawn()方法启动训练过程之外,与 ddp 完全一样。因此,人们可能会认为总是首选“ddp_spawn”方法而不是“ddp ”,但“ddp_spawn”也有这些限制:
- spawn 方法在子流程中训练模型,而主流程中的模型不会更新。
- Dataloader(num_workers=N),其中 N 很大,使用 DDP 训练会遇到瓶颈,即它会非常慢或者根本不起作用。这是 PyTorch 的限制。
- 这个方法强制所有东西都是可选择的。
trainer = Trainer(gpus=8, accelerator="ddp_spawn")
就速度和性能而言,“ddp”方法应始终优先于“ddp_spawn”。
分布式数据并行 2
DDP2 在单台机器上的行为类似于 DP,但在多个节点上使用时,它就相当于 DDP。有时,在同一台机器上使用所有批次而不是子集可能是有用的,ddp2 方法在这种情况下可能会很方便。DDP2 执行以下操作:
- 将数据的子集复制到每个节点。
- 在每个节点上初始化一个模型。
- 使用 DP 向前和向后传递。
- 跨节点同步渐变。
- 应用优化程序更新。
trainer = Trainer(gpus=8, accelerator="ddp2", num_nodes=4)
目前不建议使用这种技术,因为它对所有 PyTorch 版本> = 1.9 都不适用,不清楚如何使它适用于 PyTorch >= 1.9,并且没有对这种方法进行功能测试
霍罗沃德
Horovod 是一个用于 TensorFlow、Keras、PyTorch 和 Apache MXNet 的分布式深度学习培训框架,它使分布式深度学习变得快速和易于使用。
- 每个进程都使用单个 GPU 来处理固定的数据子集。
- 在反向过程中,梯度在所有 GPU 上并行平均。
- 在进入下一阶段之前,在开始下一步之前,同步应用这些梯度。
- 在训练脚本中,Horovod 将检测环境中的工作人员数量,并自动调整学习速率以补偿增加的总批量。
Horovod 使用相同的训练脚本支持单 GPU、多 GPU 和多节点训练。它可以在培训脚本中配置为与任意数量的 GPUs 进程一起运行,如下所示:
trainer = Trainer(accelerator="horovod", gpus=1)
trainer = Trainer(accelerator="horovod")
启动培训作业时,驱动程序应用程序将用于指定工作进程的总数:
horovodrun -np 4 python train.py
horovodrun -np 8 -H hostname1:4,hostname2:4 python train.py
共享培训
在训练大型模型或尝试较大批量时,您可能会遇到一些内存问题。人们可能会想到在这种情况下使用模型并行,但是目前,由于与之相关的复杂实现,我们使用分片训练来代替。
在底层,分片训练类似于数据并行训练,只是优化器状态和梯度是跨 GPU 分片的。在内存受限的多 GPU 设置中,或者在训练较大的模型(500M 以上的参数模型)时,强烈建议使用这种方法。
要使用分片训练,您需要首先使用下面的命令安装 FairScale 。
pip install fairscale
trainer = Trainer(strategy="ddp_sharded")
当使用分片训练策略时,在内存和性能之间存在折衷,因为由于设备之间的高度分布式通信,训练可能变得更慢。
如何在多个 GPU 上优化训练
当在多个 GPU 上训练具有大型数据集的大型模型时,我们可能会遇到一些内存或性能瓶颈问题。在本节中,我们将了解如何优化培训流程。
FairScale 激活检查点
激活检查点一旦在正向传递中不再需要激活,就从内存中释放激活。然后,根据需要为向后传递重新计算它们。当中间层产生大量激活时,激活检查点非常有用。
与 PyTorch 实现不同,FairScales 的检查点包装器还可以正确处理批处理规范层,确保由于多次转发而正确跟踪统计数据。
这在训练较大的模型时节省了内存,但是,需要包装您想要使用激活检查点的模块。你可以在这里阅读更多相关信息。
from fairscale.nn import checkpoint_wrapper
class Model(LightningModule):
def init(self):
super().__init__()
self.block1 = checkpoint_wrapper(nn.Sequential(nn.Linear(32, 32), nn.ReLU()))
self.block_2 = nn.Linear(32, 2)
混合精度(16 位)定型
默认情况下,PyTorch 和大多数深度学习框架一样,使用 32 位浮点(FP32)算法。另一方面,许多深度学习模型可以通过 16 位等低位浮点实现完全的准确性。因为它们需要更少的存储器,所以有可能训练和部署大型神经网络,这导致由于更少的存储器带宽需求而增强数据传输操作。
但是要使用 16 位浮点,您必须:
- 支持 16 位精度的 GPU,如 NVIDIA pascal 架构或更新版本。
- 你的优化算法,即 training_step,应该是数值稳定的。
混合精度结合了 32 位和 16 位浮点的使用,提高了性能,并消除了我们可能面临的任何内存问题。Lightning 通过本机或 APEX amp 后端为 GPU 提供混合精度训练。
Trainer(precision=16, amp_backend="native")
Trainer(amp_backend="apex", precision=16)
除非您需要更精细的控制,否则建议始终使用本机 amp_backend。
比起数据并行(DP ),更喜欢分布式数据并行(DDP)
正如前面提到的,我们应该更喜欢使用 DDP 策略而不是 DP。这背后的原因是 DP 每批使用 3 个转移步骤,而 DDP 仅使用 2 个转移步骤,因此速度更快。
DP 执行以下步骤:
- 将模型复制到设备。
- 将数据复制到设备。
- 将每个器件的输出复制回主器件。
GPU data parallel strategy | Source
DDP 执行以下步骤:
- 将数据移动到设备。
- 传输和同步渐变。
GPU distributed data parallel strategy | Source
随着技术和策略的改变,我们也可以在代码中做一些改变来优化我们的训练过程,下面是其中的一些。
增加批量
如果您在训练时使用小批量,则更多的时间将花费在训练数据的加载和卸载上,而不是计算操作上,这会降低训练速度。因此,建议使用更大的批处理大小来提高 GPU 利用率。但是增加批量大小可能会对模型的准确性产生不利影响,因此我们应该用不同的批量大小进行实验,以找到最佳的批量大小。
使用 PyTorch 的 DataLoader 方法更快地加载数据
Pytorch 中的 DataLoader 类是加载和批处理数据的一种快速简便的方法。我们可以使用参数“num_workers ”,通过将它的值设置为一个以上来更快地为训练加载数据。使用 PyTorch lightning 时,它会为您推荐 num_workers 的最佳值。
但是,如果数据集非常大,因为加载器工作进程和父进程将为父进程中从工作进程访问的所有 Python 对象消耗相同数量的 CPU 内存,则可能会遇到内存问题。避免这个问题的一个方法是在 Dataloader getitem 方法中使用 Pandas、Numpy 或 PyArrow 对象,而不是 python 对象。
将梯度设置为无
我们可以通过覆盖 optimizer_zero_grad()方法并将其设置为 None 来提高性能和速度,而不是将梯度设置为零,这样通常会占用更少的内存。
class Model(LightningModule):
def optimizer_zero_grad(self, epoch, batch_idx, optimizer, optimizer_idx):
optimizer.zero_grad(set_to_none=True)
模型切换
当我们必须在分布式设置中使用多个优化器执行梯度累积时,这种方法特别有用。当执行梯度累积时,将 sync_grad 设置为 False 将阻止此同步,并提高您的训练速度。
LightningOptimizer 为高级用户提供了一个 toggle_model()函数作为 contextlib.contextmanager()。这里有一个来自 PyTorch Lightning 官方文档的例子。
class SimpleGAN(LightningModule):
def __init__(self):
super().__init__()
self.automatic_optimization = False
def training_step(self, batch, batch_idx):
g_opt, d_opt = self.optimizers()
X, _ = batch
X.requires_grad = True
batch_size = X.shape[0]
real_label = torch.ones((batch_size, 1), device=self.device)
fake_label = torch.zeros((batch_size, 1), device=self.device)
is_last_batch_to_accumulate = (batch_idx + 1) % 2 == 0 or self.trainer.is_last_batch
g_X = self.sample_G(batch_size)
with d_opt.toggle_model(sync_grad=is_last_batch_to_accumulate):
d_x = self.D(X)
errD_real = self.criterion(d_x, real_label)
d_z = self.D(g_X.detach())
errD_fake = self.criterion(d_z, fake_label)
errD = errD_real + errD_fake
self.manual_backward(errD)
if is_last_batch_to_accumulate:
d_opt.step()
d_opt.zero_grad()
with g_opt.toggle_model(sync_grad=is_last_batch_to_accumulate):
d_z = self.D(g_X)
errG = self.criterion(d_z, real_label)
self.manual_backward(errG)
if is_last_batch_to_accumulate:
g_opt.step()
g_opt.zero_grad()
self.log_dict({"g_loss": errG, "d_loss": errD}, prog_bar=True)
正如您在代码中看到的,我们将 sync_grad 参数设置为 False,并仅在一个时期结束时或每两个批次后将其设置为 True。通过这样做,我们实际上是在每两个批次之后或者在时期结束时累积梯度。
避免。item(),。numpy(),。cpu()调用
避免。item(),。numpy(),。cpu()调用代码。如果您必须删除连接的图调用,您可以使用。请改用 detach()方法。这是因为这些调用中的每一个都将导致数据从 GPU 传输到 CPU,并将导致性能大幅下降。
清除缓存
每次调用 torch.cuda.empty_cache()方法,所有的 GPU 都要等待同步。所以避免不必要的调用这个方法。
如何在多个 GPU 上监控训练
在训练模型时,监控 GPU 的使用是非常重要的,因为它可能会提供一些有用的见解来改进训练,如果 GPU 未得到充分利用,我们可以相应地处理它。有各种工具,如 Neptune 和 Wandb,可用于监控多个 GPU 上的训练。
在本节中,我们将使用 Neptune 来监控 GPU 和 GPU 内存,同时在多个 GPU 上进行训练。
用海王星监控训练
Neptune 是一个可以在任何 MLOps 工作流中使用的元数据存储库。它允许我们在训练时监控我们的资源,因此我们可以使用它来监控训练时使用的不同 GPU 的使用情况。
将 Neptune 并入 PyTorch Lightning 代码非常简单,您所要做的就是创建一个 NeptuneLogger 对象并将其传递给 Trainer 对象,如下所示:
from pytorch_lightning import Trainer
from pytorch_lightning.loggers import NeptuneLogger
neptune_logger = NeptuneLogger(
api_key="ANONYMOUS",
project="common/pytorch-lightning-integration",
tags=["training", "resnet"],
)
trainer = Trainer(max_epochs=10, logger=neptune_logger)
trainer.fit(my_model, my_dataloader)
如果这是你第一次接触 Neptune,我强烈建议你通过这个一步一步的指南来安装所有必要的库以使它工作。之后,查看海王星+ PyTorch 闪电集成文档。
运行该文件后,您应该会得到一个到控制台的链接。您可以看到监控部分(下图中的圆圈),在这里您可以看到所有 GPU 在训练时的使用情况以及一些其他指标。
Monitor training on multiple GPUs | Source
让我们看看我们可以从 GPU 利用率图表中推断出什么样的有意义的见解。
Monitor training on multiple GPUs | Source
- 正如您在上面看到的,GPU 的使用是波动的,有一些短暂的时间没有被使用,解释其原因并不容易。
- 这可能发生在验证期间,因为我们在此阶段不计算梯度,或者这可能是由于一些其他瓶颈,例如,您可能使用 CPU 对数据使用一些数据预处理技术,这可能非常慢。
- 此外,在 Caffe 等一些框架中,默认情况下在验证阶段只使用一个 GPU,因此在这种情况下,您可能会发现只有一个 GPU 的使用率很高。
- 因此,根据您训练神经网络的方式,您可能会发现一个不同的图表,表明不同的 GPU 是如何被利用的。
结论
本文讨论了我们为什么要用多个 GPU 来训练机器学习模型。我们还发现了使用 Pytorch lightning 在多个 GPU 上进行训练是多么容易,以及优化训练过程的最佳方法。最后,我们发现了如何在训练时使用 Neptune 来监控 GPU 的使用情况。
如果你正在寻找关于这个主题的深入知识,我建议你浏览这个广泛的资源改进共享计算环境中的 ML 应用或者这个研究论文。
参考
米尔扎·穆杰塔巴
经验丰富的机器学习工程师,具有金融服务行业的工作经历。精通分析技能、PHP、数据科学、数据分析和数据分析。拥有技术学士学位的优秀工程专业人士——来自克什米尔大学的 BTech 专注于计算机科学。
阅读下一篇
如何跟踪海王星的 PyTorch 闪电实验
5 分钟阅读|作者 Jakub Czakon |年 7 月 19 日更新
使用 PyTorch Lightning 并想知道应该选择哪个记录器来跟踪您的实验?
考虑使用 PyTorch Lightning 来构建您的深度学习代码,并且不介意了解它的日志功能吗?
不知道闪电有一个相当可怕的海王星积分?
这篇文章(很可能)适合你。
为什么是 PyTorch 闪电和海王星?
如果你从未听说过,PyTorch Lightning 是 PyTorch 之上的一个非常轻量级的包装器,它更像是一个编码标准而不是框架。这种格式可以让你摆脱大量的样板代码,同时保持简单易懂。
其结果是一个框架,为研究人员、学生和生产团队提供了尝试疯狂想法的终极灵活性,而不必学习另一个框架,同时自动化掉所有的工程细节。
将模型投入生产之前,必须进行 5 项误差分析
原文:https://web.archive.org/web/https://neptune.ai/blog/must-do-error-analysis
深度学习时代的繁荣始于 2012 年,当时 Alex Krizhevsky 创建了一个卷积神经网络,将图像分类的准确率提高了 10%以上。这一巨大成功很快被其他研究领域所效仿,很快其他企业——企业集团和初创企业——希望将这一前沿技术应用到自己的产品中:银行现在使用 ML 模型来检测欺诈;自动驾驶采用传感器结果,自动做出自信的决策。
然而,从研究到生产的快速转变往往会导致一些经常被忽视但却是必须考虑的差距。许多公司仅仅根据实验室结果,甚至简单的准确性来判断他们的机器学习模型,以加快展示他们的产品线的步伐,这实际上可能导致巨大的性能差距,甚至未知的偏差。
本文深入探讨了机器学习(ML)模型表面精度性能之外的现实场景,这是人们在将其投入生产之前应该考虑的。具体来说,虽然特定模型的训练精度可能看起来令人信服,但分析不同的数据集分布是否会保持性能是很重要的。我们提供了五个必做的分析,以确保您的模型在上线时能如预期一样运行。
错误分析:初步知识
在探索为什么每个错误分析是不同的并且必须完成之前,我们首先必须正确理解 ML 模型的核心概念,以实现其内在的约束。
在传统的工程环境中,我们希望设计将输入映射到指定输出的数学系统——这种数学建模并不总是可行的,尤其是当系统未知且过于复杂而难以找到时。这就是机器学习(特别是监督学习)发挥重要作用的时候。我们不是创建模型,而是基于一组已知的输入和输出来学习它。
为了充分训练和评估 ML 模型,典型的设置是将可用数据集分成训练集和验证集,其中在模型设置期间仅看到训练集,而验证仅用于评估。我们通常基于验证集的性能,作为我们的模型在真实世界设置下推广的基准。因此,了解验证数据集的构造方式以及模型投入生产时可能出现的潜在分布变化非常重要,因为所有的误差分析都围绕这一概念进行。
错误分析 1:训练和验证数据集的大小
如前一节所述,模型的表现完全取决于训练和验证数据集。这导致每个人在生产之前必须进行的第一个也是最重要的错误分析:确定训练和验证数据集的大小是否足够。我们可以用一个狗和猫的图像识别模型来说明这一点的重要性。
假设我们希望创建一个 ML 模型,它可以确定图像中的动物是狗还是猫。为了训练模型,我们需要收集一组图像来进行训练和验证。现在考虑这样一种情况,有 50 种狗,然而我们只有 40 种用于训练和验证的图像。我们的模型可能在训练和验证上都表现得非常好,但我们永远不会知道它对 10 种未知物种的概括能力有多强,当模型投入生产进行真实世界测试时,这些物种是有效的例子。
这个案例听起来可能过于极端,导致人们质疑它是否真的会在现实中发生。然而,许多真实世界的数据包含更复杂的分布,超出了我们的知识范围——一个模型可能不会暴露出一个重要的特征,而我们甚至不会注意到!下面进一步描述了当训练/验证集太小时可能导致的问题。
-
当训练集太小的时候:我们可以把训练集想象成整个真实世界数据集的一个小群体。因此,如果我们希望 ML 模型是稳健的,我们会希望这个小群体从真实世界数据可能具有的所有可能性中提取样本。如果没有,模型将只学习可用数据的少量分布,使其在测试中几乎不可推广。
-
当验证集过小时:当验证集过小时,可能会出现不同的问题。一个小的验证集可能意味着不是所有的可能性都被测试过,而不是不可推广。这可能会给人以错误的印象;如果学习了当前的分布,我们可以看到一个非常好的结果,反之亦然。
“太小”的确切原因是一个困难的问题,因为答案基于许多未知因素,如任务的难度和数据集分布的复杂程度。但是,根据经验,如果影像数据集包含的影像少于几千幅,或者如果回归数据集包含的条目少于几千条,则模型通常不能很好地进行概化。如果你的 ML 模型是基于深度学习的(需要神经网络),由于深度学习模型有大量的参数可用,你肯定需要更多的数据。
解决办法
解决方法很简单—增加数据集的大小。考虑你的模型将要应用到什么样的现实场景中。在相同的设置下收集更多的数据,并将它们放入训练和验证数据集中。虽然看起来很简单,但这实际上是许多公司(如谷歌、脸书)一直试图通过他们庞大的客户数据库实现的:他们不断收集所有数据(搜索历史的图像),因为他们具体意识到数据集大小增加的好处是机器学习。
之后,考虑训练集和验证集的平衡。80/20 是标准的划分,但是根据数据集的大小,您可以减少验证集以使训练更加稳健,反之亦然,以便更好地了解模型的执行情况。
错误分析 2:数据集的平衡和每类的准确性
第二个错误分析挖掘数据集的内容,以找到标签的平衡。我们可以回到上面提到的狗/猫分类任务来说明这个问题。
考虑一个数据集,在 1000 幅图像中,990 幅是狗,剩下的 10 幅是猫。如果一个模型学会将所有东西都归类为狗(这是非常不准确的,基本上是无用的),它将在整个数据集上获得 99%的准确率。如果不深入研究错误的形成,许多人会直截了当地认为模型训练有素,可以投入生产了。
这个问题可以很容易地通过研究每个类的样本数量来规避。在最佳情况下,我们希望每个单独的类拥有大致相同数量的数据。如果这样的设置是不可能的,那么我们至少应该关注每个类有足够数量的数据(几百个)。
然而,即使数据集完全平衡,网络也可能在某些类上表现得更好,而在其他类上表现得更差,或者如果您的任务是二元分类,则在检测阳性方面表现得比阴性更好。要意识到这一点,我们不能只直接看准确度,而是要通过不同的度量来看每个类的准确度和真/假阳性/阴性。以下是一些可用于准确性之外的进一步分析的指标。
- F1 得分:对于二元分类,我们可以计算 F1 得分(上面的公式),这可以让我们了解我们给定模型的精度和召回率。请注意,我们还可以专门取出精度,并逐个召回进行评估。根据手头的任务,我们可能希望最大限度地提高精确度,或者回忆并放弃另一个。例如,如果您的目标是为您的产品找到一组目标客户,您可能希望召回量大一些,这样您就不会错过潜在客户,但是如果您找到的客户不完全是您的目标客户,精确度可能会受到影响。
Example of a confusion matrix on iris dataset to show the percentages
of predictions for each label | Source
- 混淆矩阵:(上图)显示每个类别被分类为所有类别的百分比。伴随着颜色编码,当我们试图理解哪一类更容易出错以及错误是如何产生的时候,这个矩阵就变成了一个很好的可视化工具。
- ROC 曲线:如果我们在做分类,可以通过改变阈值来区分阳性和阴性来构造一条曲线。这将使我们更好地了解哪个阈值更好。
解决办法
如果您遇到一个数据少得多或者性能比其他类差得多的类,那么增加这个特定类的数据量是明智的。如果无法获得真实世界的数据,也可以使用数据扩充等技巧作为替代(关于数据扩充的更多内容将在后一节中讨论)。此外,我们还可以对数据应用随机权重采样,或者直接对每个样本硬编码采样权重,以应对数据集的不平衡。
错误分析 3:细粒度的错误分类错误
既然您可能计算的所有数字都显示了良好的结果,那么仍然有必要对细粒度的分类结果进行一些粗略的定性分析,以准确理解是什么导致了错误。
通常,一些错误可能非常明显,但仅仅从类信息中是看不出来的。例如,在我们的狗/猫问题中,我们可能会注意到,通过简单地可视化所有错误分类的猫,所有的白猫都被错误分类了,然而猫的整体类别表现得非常好。这种错误分析变得至关重要,因为白猫可能是现实世界案例的主要部分(再次是验证和现实世界测试之间的分布差异问题)。然而,由于 labels 本身根本不能反映这样的问题,研究这个问题的唯一方法是通过人在回路中的定性分析。
解决办法
细粒度错误分类的解决方案非常类似于不平衡数据集的解决方案,其中直接且唯一的解决方案是向数据集添加更多内容。然而,为了定位一个特定的细粒度类,我们应该只添加那些性能很差的子类。
错误分析 4:调查过度拟合的程度
当模型学习仅出现在训练集中的模式/数据分布时,会发生过度拟合。当将模型转移到测试时,使用这些模式会降低模型的性能。
过度拟合可能以两种方式出现,一种更常见,另一种不太常见。下面描述了这两个问题及其各自的解决方案。
过度适应训练集
当网络从训练集中学习到不适用于验证集的东西时,就会发生这种情况。在每个时期之后,借助于绘制用于训练和验证的损失曲线,该问题很容易观察到。如果在验证变得停滞后,训练损失继续下降(导致性能差距扩大),则过度拟合正在发生。
解决办法
训练集过拟合有多种解决方案,下面我们列出了 6 种可行的解决方案。
- 提前停止:我们在每个历元/a 一定数量的迭代之后绘制训练和验证损失。如果验证损失在一定数量的时期内停止下降,我们就完全停止训练。这可以防止模型在训练集中学习不需要的模式。
- 降低 ML 模型的复杂性:当一个模型太复杂(参数太多)时,它很可能会学习模式,特别是当手头的任务实际上很简单时(例如,如果我们正在学习一个函数 y = wx,但我们有 100 个参数{w1,w2 …,w100},那么很可能 w2 到 w100 实际上学习的是数据中的噪声,而不是真实的函数)。如果您正在训练神经网络,这相当于减少层的深度和宽度。如果你正在训练决策树/森林,那将会限制树的深度或数量。
- 添加 L1/L2 正则化:这些正则化防止特定参数过大,过拟合时经常出现这种情况。具体来说,L1 正则化旨在最小化每个权重的绝对值,而 L2 正则化则最小化每个权重的平方值。因此,平方曲线会将所有值推到接近 0 的状态。本质上,这两个正则化确保了每个因素对最终预测的贡献是相似的。
Comparison of a neural network with and without dropout | Picture retrieved
from the original dropout paper from JMLR
- 加入退出项:对于一个神经网络,我们可以随机地退出某些神经元,不考虑它们的输出。这将使我们的模型对输入数据的微小变化不太敏感,从而防止过度拟合。
Visualization of a data augmentation technique called “mixup” | Source: Author
- 数据扩充:增加更多的训练数据将使得某个模式不太可能存在于训练集中而不存在于验证集中。数据扩充是一种综合当前可用条目中的数据并将其用作训练的附加数据的技术。例如,我们可以裁剪、旋转和移动图像,并将它们视为“新”图像,以添加到训练中,并使模型更加健壮。一些更复杂和最新的增强技术还包括 mixup、cutout、cutmix 等。
- 集成学习:如果计算资源可用,人们可以训练多个模型,并将它们的预测组合在一起,以做出最终的预测。不太可能所有模型都过度适应相同的模式。因此,预测将更加平滑,进一步防止过度拟合。事实上,集成模型有多种方式,从简单的打包和提升到更复杂的深度模型组合——所有这些都取决于手头案例所用的场景和模型。
过度适应验证集
这不是一个常见的问题,因为实际上只有训练数据用于调整模型。但是,如果您基于验证执行早期停止,仍然有可能您实际上为该特定集合而不是为整个真实总体选择了最佳模型。
解决办法
防止这种情况的一种方法是通过交叉验证等方法采用多重验证。交叉验证将整个数据集分成多个片段,每次我们取其中一个片段用于验证,其余的用于训练。此外,我们还应该确保验证集足够大,并且当我们手动增加验证集的大小时,精确度保持大致相同。
错误分析 5:模仿模型将被应用的场景
最后,在您可以使用培训和验证集进行所有详细分析之后,是时候模拟您的模型将如何应用的场景并测试实际结果了。
我们可以通过狗/猫的分类问题再次说明这一点。假设你正在为 iPhone 用户创建一个给狗和猫分类的 app 你根据从网上获得的一堆狗和猫的图片,经过仔细分析,训练了你的模型。对于这最后一部分,您可能希望通过在不同的 iPhone 相机上进行测试来模拟真实场景。换句话说,我们希望确保在测试集上进行评估时,您训练和验证的模型之间的分布差距很小。
解决办法
由于这是误差分析的最后阶段,并且假设其他一切都表明您的模型具有巨大的潜力,您可以潜在地将您的模型投入生产,但添加在线学习机制以继续模型的微调。
在线学习是一种学习机制,通过将新的测试数据添加到训练中来不断改进模型。随着添加越来越多的数据来微调模型,准确性可能会增加,因为模型将开始更符合您最终目标的测试分布。许多应用程序(如 Siri、面部识别)实际上都采用了这种方案,这就是当你继续使用手机时,它们如何慢慢适应你的外观和声音。
失败的案例
只有上述错误分析的理论支持,人们实际上可能会怀疑这种数据分析的实用性和必要性:如果没有这些修复,机器学习模型真的会出错吗?要回答这个,我们其实可以深挖一个 AI 工具失败的两个经典案例:2014 年亚马逊 AI 招聘的偏差和 2019 年 FB 广告。
亚马逊 AI 招聘
为了加快招聘过程,亚马逊在 2014 年致力于开发一种人工智能驱动的招聘工具,以审查和筛选简历。然而,在投入生产一年后,他们在 2015 年意识到性别偏见的严重问题,尽管性别不是投入因素的一部分,特别是对于软件开发人员或其他技术角色。
这是怎么发生的?
这个问题的答案实际上深深植根于模型数据集最初是如何收集的:使用过去 10 年的简历,这些简历最终以男性为主。事实上,美国顶级科技公司技术岗位的男女员工比例约为 3:1。
Tech Industry is dominated by men | Source
正因为如此,这种模式天生就给人一种错误的印象,即男性候选人更受青睐,因此更多地与男性相关的词汇联系在一起,从而摧毁了包含“女子象棋俱乐部队长”等词汇的简历的价值。
如何才能避免这种情况?
实际上,我们可以将这种情况追溯到错误 2 和错误 5,在这两种情况下,数据集中的严重不平衡(男女比例)以及未能模拟真实的评估场景。因此,为了在生产之前避免这些严重的错误,必须考虑数据集的平衡,并且潜在地对特定类别的样本/扩充增加权重,以避免这样的问题。
脸书广告偏见
类似地,脸书推出了一个机器学习和推荐系统,但这种推荐最终将女性排除在某些广告之外,反之亦然,这是由于一般人群的一般化和相关的刻板印象,正如南加州大学的研究所表明的。
如何才能避免这种情况?
同样,通过大量测试来平衡和发现细粒度错误,同时通过在实际投入大规模生产之前拥有一组测试用户来模拟现实世界中可能发生的场景,通过详细和严格的错误分析,这样的问题不太可能发生。
尾注
现在你知道了!在你可以说你的模型已经完全准备好投入生产之前,你必须做五种不同的误差分析。这里有一些其他有用的文章,你可以进一步深入研究,使你的机器学习模型在生产中有效和值得尊敬:
请记住,在测试阶段小心谨慎可能会节省很多精力!
拥抱脸和变形金刚的自然语言处理
NLP 是机器学习的一个分支,旨在帮助计算机和智能系统像人类一样理解文本和口语。
NLP 驱动计算机程序执行各种各样非常有用的任务,如文本翻译、响应口头命令或在眨眼之间总结大量文本。您很有可能以下列形式与 NLP 技术进行过交互:
- 声控全球定位系统
- 智能机器人和数字助理
- 客服聊天机器人
- 基本上,任何涉及使用 STT 和 TTS 技术的数字服务
我们将讨论 NLP 的两个关键技术,但首先是 NLP 的基础——抽象层。
NLP 中的抽象层
从书面文本中提取意义涉及几个抽象层,这些抽象层通常与不同的研究领域相关,但相互之间有很好的协同作用。
这些研究领域包括:
- 形态学 层次,研究词的结构和构词。
- 词汇分析正是着眼于词汇和标记的构成,以及它们各自的词性。
** 句法 分析负责使用词法分析阶段输出的词性标注将单词分组为连贯的短语。* 语义处理然后通过将句法特征与给定的上下文相关联以及消除具有多个定义的单词的歧义来评估所形成的句子的意义和含义。** 最后是 语篇 层面,这里的处理是关于对文本结构和意义的分析,而不仅仅是单个句子,在单词和句子之间建立联系。**
**当前最先进的 NLP 技术将所有这些层结合起来,产生非常类似于人类语音的出色结果。最重要的是,NLP 将人类语言的多种基于规则的建模与统计和深度学习模型相结合。
最近需求量很大的深度学习方法需要大量带注释的数据来学习和识别相关的相关性。像 BERT,GPT2,GPT3 或 RoBERTA 这样的著名模型消耗了大量的训练数据,它们只能由负担得起成本的大规模公司进行训练。例如,训练 GPT-3 据报道花费了 12,000,000 美元…一次训练运行。
变形金刚图书馆
注意力机制
2018 年出现的一个趋势是基于注意力的算法,这是一个由谷歌 R&D 部门研究和开发的概念,并于 2017 年在著名的“注意力是你所需要的全部”论文中首次发布。
注意力是一种模仿我们大脑内部认知结构的技术。它增强并本能地关注数据的特定部分,而淡化其余部分。因此,当面对复杂和大量的数据时,这种机制节省了时间和能量处理。
变形金刚网络大量利用注意力机制来实现高端表现力。因此,变压器在许多领域的 NLP 深度学习模型的架构中被广泛采用。
单词嵌入
在每个 NLP 模型的中心,都有一个预处理阶段,将有意义的单词和句子转换成实数向量。换句话说,嵌入是一种允许具有相似意思的单词具有相似表示的单词表示类型。
它们是文本的分布式表示,也许是深度学习方法在挑战自然语言处理问题上令人印象深刻的表现的关键突破之一。
单词嵌入的根源 分布语义学 理论试图根据单词周围的上下文来表征单词。例如,单词“演员”在句子“演员崩溃”中的意思与在句子“我的演员朋友给我发了这个链接”中的意思不同。共享相似上下文的单词也共享相似的意思。
单词嵌入有几种方法。它们可以追溯到人工智能的早期,并且是基于降维的方法。这些方法(称为“n-gram”或“k-means”)获取文本语料库,并通过在单词共现矩阵中找到聚类来将其缩减到固定的维数。目前最受欢迎的方法是基于 Word2Vec,最初是由谷歌研究人员托马斯·米科洛夫、程凯、格雷格·科拉多和 Quoc Le 在 2013 年推出的。
利用 BERT 进行情感分析
BERT 代表 B 方向En 编码器 R 代表来自 T 变压器。这是谷歌人工智能在 2018 年底开发的一种架构,提供以下功能:
- 设计成深度双向的。从令牌的左右上下文中有效地捕获信息。
- 与前辈相比,在学习速度方面效率极高。
- 它结合了掩码语言模型(MLM)和下一句预测(NSP)。
- 这是一个通用的深度学习模型,可用于分类、问答、翻译、摘要等。
最初,用未标记的数据对 BERT 进行预训练。之后,模型输出输入的特定表示。
再训练过程可以以各种方式完成,或者通过从零开始构建判别或生成模型,或者对公共数据库中的现有模型进行微调。通过利用预先训练的模型,有可能将学习从一个领域转移到另一个领域,而无需花费从头开始学习所需的时间和精力。
注 :我已经简要描述了实际的机制是如何工作的,更多细节我推荐' BERT 解释:NLP 语言模型的现状 '
用 BERT 迁移学习
微调 BERT 以执行特定任务的方法相对简单。虽然 BERT 可用于各种 NLP 应用,但微调过程需要在核心模型中添加一个小层。例如:
分类任务—在变压器模块上使用分类层(情感分析)。
Q & A 相关任务——模型收到一个关于文本序列的问题,并被要求在命题中标出正确答案。伯特被训练学习两个向量,它们标记了答案的开始和结束。例如:班,1.1 版
命名实体识别 NER: 模型被输入一个文本序列,并被要求识别特定的实体(国家、组织、人、动物等)。),并给它们贴上标签。这同样适用于这里,预先训练以识别实体的分类层与变换器块“组装”在一起以适合整个架构。
为什么抱脸?
拥抱脸是一个大型开源社区,它迅速成为预先训练的深度学习模型的诱人中心,主要针对 NLP。他们自然语言处理的核心操作模式围绕着转换器的使用。
用 Python 编写的 Transformers 库公开了一个配置良好的 API,以利用过多的深度学习架构来完成像前面讨论的那些最先进的 NLP 任务。
正如您可能已经猜到的,一个核心的启动价值是可重用性——所有可用的模型都带有一组预先训练好的权重,您可以针对您的特定用途进行微调。
从拥抱脸开始
在官方文档中,您可以找到所有具有相关库结构的组件。
拥抱脸轮毂 Repos
它们有基于 git 的存储库,可以作为存储,并且可以包含项目的所有文件,提供类似 github 的特性,例如:
- 版本控制,
- 提交历史记录和分支差异。
它们还提供了优于常规 Github 回购的重要优势:
- 关于已启动任务、模型训练、指标等的有用元数据,
- 测试推理的浏览器预览,
- 用于生产就绪环境的 API,
- HUB 中有 10 多个框架:Transformers、Asteroid、ESPnet 等等。
查看这里: 抱抱脸库
拥抱面部小工具
一组现成的预训练模型,用于在 web 预览中测试推理。
一些例子:
查看这里: 抱脸小工具
拥抱脸的伯特模型
现在,让我们试着做我们一直在谈论的事情。我们想要微调 BERT 来分析亚马逊上购买商品的一些商业评论,并确定评论的正面、负面、和中立。
亚马逊产品评论数据集
该数据集包括超过 1480 万条来自购买、评级、文本、有用性投票等的产品评论。这些数据将证明对我们的任务非常有用,因为评论是由人们真实地做出的,以反映他们对给定产品的意见。文本倾向于主观性,因此本质上可以分为积极的,消极的和中性的类别。
下载数据集的链接 : 亚马逊商品评论
数据集的示例如下所示:
{
"reviewerID": "A2SUAM1J3GNN3B",
"asin": "0000013714",
"reviewerName": "J. McDonald",
"helpful": [2, 3],
"reviewText": "I bought this for my husband who plays the piano. He is having a wonderful time playing these old hymns. The music is at times hard to read because we think the book was published for singing from more than playing from. Great purchase though!",
"overall": 5.0,
"summary": "Heavenly Highway Hymns",
"unixReviewTime": 1252800000,
"reviewTime": "09 13, 2009"
}
为了确定每个类别,我们将依靠亚马逊评级系统。“总体”键值表示该产品的总体评级。我们可以为每个类别建立一个可测量的范围:
- 正面反馈:4-5 颗星
- 负面反馈:从 0-2 星
- 中性:3 颗星
由于数据涵盖了大量不同的主题和类别,建议缩小范围,只选择其中的一小部分。我选择了这些:
- 汽车的
- 服装、鞋子和珠宝
- 电子学
- 手机和配件
最后,我们将使用小版本的数据集,以避免处理能力过载。
变形金刚图书馆
安装抱脸变形金刚库
- 使用 conda 创建您的虚拟环境:
conda create --name bert_env python=3.6
- 安装支持 cuda 的 Pytorch(如果您有专用的 GPU,或者没有专用的 CPU 版本):
conda install pytorch torchvision torchaudio cudatoolkit=10.2 -c pytorch
- 从 conda 通道安装变压器版本 4.0.0:
conda install -c huggingface transformers
- 安装火炬视觉:
pip install torchvision
- 安装 pytorch-nlp 包中的 Bert 预训练版本:
pip install pytorch-pretrained-bert pytorch-nlp
我们将使用 Pytorch 版本的 BERT uncased,由 Hugging Face 提出。
训练模型
从预处理数据开始
对于训练数据,我们只需要“总体”和“回顾”属性。我们将使用包含 1 (正值)、 2 (负值)和 0 (中性)的“情绪数据”创建一个新列。根据总体得分,每一行都将标有这些数字。
import pandas as pd
review_data = pd.read_json('/content/Dataset_final.json', lines=True)
sentiment_data = []
for i in review_data[['overall']].values:
if i >= 4:
sentiment_data.append(1)
elif i < 3:
sentiment_data.append(2)
else:
sentiment_data.append(0)
sentiment = pd.DataFrame(sentiment_data)
review_data['sentiment'] = sentiment
启动 NSP 进程
将[CLS]和[SEP]标签放在每个复习句子的前面。
sentences = ["[CLS] " + query + " [SEP]" for query in review_data['reviewText']]
BERT 令牌嵌入
在深入这部分代码之前,我们需要解释一下令牌嵌入及其工作原理。嵌入令牌提供了关于文本内容的信息。首先要做的是将我们的文本转换成一个向量。
BERT 使用内部算法将输入的单词分解成记号。BERT 实施的流程包括三个阶段:
- 令牌嵌入
- 嵌入位置
- 嵌入段
PyTorch 的 BertTokenizer 模块将负责内部的所有逻辑。将每个输入句子分成合适的记号,然后将它们编码成数字向量。
from pytorch_pretrained_bert import BertTokenizer
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased', do_lower_case=True)
tokenized_texts = [tokenizer.tokenize(sent) for sent in sentences]
填充输入标记,并使用 BERT 标记器将标记转换为它们在 BERT 词汇表中的索引号:
from keras.preprocessing.sequence import pad_sequences
MAX_LEN = 512
input_ids = pad_sequences([tokenizer.convert_tokens_to_ids(txt) for txt in tokenized_texts],
maxlen=MAX_LEN, dtype="long", truncating="post", padding="post")
input_ids = [tokenizer.convert_tokens_to_ids(x) for x in tokenized_texts]
input_ids = pad_sequences(input_ids, maxlen=MAX_LEN, dtype="long", truncating="post", padding="post")
创建注意掩码,每个标记的掩码为 1,后跟填充的 0:
attention_masks = []
for seq in input_ids:
seq_mask = [float(i>0) for i in seq]
attention_masks.append(seq_mask)
分离数据并为训练做准备
拆分列车并测试拆分:
from sklearn.model_selection import train_test_split
train_inputs, validation_inputs, train_labels, validation_labels = train_test_split(input_ids, labels.values, random_state=2018, test_size=0.2)
train_masks, validation_masks, _, _ = train_test_split(attention_masks, input_ids, random_state=2018, test_size=0.2)
将数据转换为 torch 张量,并使用特定的 batch_size 创建 Dataloader 迭代器:
import torch
from torch.utils.data import TensorDataset, DataLoader, RandomSampler,
SequentialSampler
train_inputs = torch.tensor(train_inputs)
validation_inputs = torch.tensor(validation_inputs)
train_labels = torch.tensor(train_labels)
validation_labels = torch.tensor(validation_labels)
train_masks = torch.tensor(train_masks)
validation_masks = torch.tensor(validation_masks)
batch_size = 8
train_data = TensorDataset(train_inputs, train_masks, train_labels)
train_sampler = RandomSampler(train_data)
train_dataloader = DataLoader(train_data, sampler=train_sampler, batch_size=batch_size)
validation_data = TensorDataset(validation_inputs, validation_masks, validation_labels)
validation_sampler = SequentialSampler(validation_data)
validation_dataloader = DataLoader(validation_data, sampler=validation_sampler, batch_size=batch_size)
实例化模型:
from pytorch_pretrained_bert import BertAdam, BertForSequenceClassification
model = BertForSequenceClassification.from_pretrained("bert-base-uncased", num_labels=3)
model.cuda()
定义优化的超参数:
param_optimizer = list(model.named_parameters())
no_decay = ['bias', 'gamma', 'beta']
optimizer_grouped_parameters = [
{'params': [p for n, p in param_optimizer if not any(nd in n for nd in no_decay)],
'weight_decay_rate': 0.01},
{'params': [p for n, p in param_optimizer if any(nd in n for nd in no_decay)] 'weight_decay_rate': 0.0}
]
optimizer = BertAdam(optimizer_grouped_parameters, lr=2e-5, warmup=.1)
定义训练循环:
train_loss_set = []
epochs = 2
for _ in range(epochs, desc="Epoch"):
model.train()
tr_loss = 0
nb_tr_examples, nb_tr_steps = 0, 0
for step, batch in enumerate(train_dataloader):
batch = tuple(t.to(device) for t in batch)
b_input_ids, b_input_mask, b_labels = batch
optimizer.zero_grad()
loss = model(b_input_ids, token_type_ids=None, attention_mask=b_input_mask, labels=b_labels)
train_loss_set.append(loss.item())
loss.backward()
optimizer.step()
tr_loss += loss.item()
nb_tr_examples += b_input_ids.size(0)
nb_tr_steps += 1
开始跟踪培训损失,看看模型实际上如何改进。
将模型置于评估模式,评估一个批次的预测:
model.eval()
eval_loss, eval_accuracy = 0, 0
nb_eval_steps, nb_eval_examples = 0, 0
for batch in validation_dataloader:
batch = tuple(t.to(device) for t in batch)
b_input_ids, b_input_mask, b_labels = batch
with torch.no_grad():
logits = model(b_input_ids, token_type_ids=None, attention_mask=b_input_mask)
logits = logits.detach().cpu().numpy()
label_ids = b_labels.to('cpu').numpy()
tmp_eval_accuracy = flat_accuracy(logits, label_ids)
eval_accuracy += tmp_eval_accuracy
nb_eval_steps += 1
可以通过绘制 train_loss_set 列表来看一下训练损耗。
import matplotlib.pyplot as plt
plt.figure(figsize=(15,8))
plt.title("Training loss")
plt.xlabel("Batch")
plt.ylabel("Loss")
plt.plot(train_loss_set)
plt.show()
Training loss plot
训练完成后,您可以使用 torch.save()将其保存为检查点。
torch.save(model, '/bert_final_version.pth')
本节的目标是向您展示一个简单的演示,说明如何使用 Hugging Face 提供的预训练版本的 BERT,并使用特定的数据集对其进行微调,以执行所需的任务。
一旦保存了您的检查点,您就可以(例如)在 API 中使用它作为服务来将 tweets 或其他类似的文本内容分为正面、负面或中性类别。
要了解更多,请查看我以前关于对话人工智能的文章,在那里我使用 Django API 作为后端服务来服务模型推理→Nvidia 支持的对话人工智能架构:工具指南
我在下面给你留了 google Colab 笔记本的链接,在那里你会找到运行这个实验的所有代码:情感分析 BERT
结论
我真诚地推荐你检查拥抱脸的工作,他们有优秀的教程和文章来快速自信地让你开始 NLP 和深度学习。
还有,用 Fastai 和 PyTorch 看《程序员深度学习》这本书。他们有关于深度学习 NLP 方法的精彩章节,完全用 Pytorch 和 Fast AI 编码。这很容易,你将很快开始编写你的模型。
一如既往,如有任何问题,请随时通过我的电子邮件联系我:hachcham.ayman@gmail.com
参考**
海王星.新
原文:https://web.archive.org/web/https://neptune.ai/blog/neptune-new
首先,我们很抱歉!在过去的几个月里,我们在产品更新方面非常安静。您已经看到了 web 界面中的一个更新或 Python 客户端库中的一个 bug 修复,但仅此而已。
发生了什么事?
随着时间的推移,我们从您那里获得了大量的反馈。您询问了如何在 spot 实例和管道中使用 Neptune,如何以一种更加层次化的方式组织事物,以及许多其他问题,我们希望做到这一点。但是将这些改进一点一点地添加到当前产品中变得越来越困难(也越来越慢)。不要误解我,我们喜欢迭代,但有时你需要深呼吸,后退一步,重建基础。
简而言之,这就是当时的情况。然而,相信我——等待是值得的🙂
今天,我们很高兴地宣布,一个全新版本的 Neptune 已经为您准备好了,它具有许多新特性和改进的 Python API!
海王星有什么新的?
更好的组织,更大的灵活性,更多的定制
通常,当训练一个只有几个参数的简单模型时,你可以从头开始背诵它们。它们都可以显示在一个屏幕上。
然而,一旦添加了这个太多的参数,问题就出现了。当您除了按字母顺序对复杂的参数配置进行排序之外,还不能轻松地管理它们时,这就成了一种真正的痛苦。
你们对此都有不同的解决方案:
- 明确上传几个参数,其余的上传为 YAML 配置文件,
- 前缀的巧妙运用,
- 还有很多很多其他人。
所有这些都是海王星本身缺乏组织性和灵活性的权宜之计。这改变了!
有了新的 Neptune API,您可以将所有的元数据分层组织到组织整齐的名称空间(文件夹)中。对于所有元数据,我指的是所有元数据,不仅是参数,还包括日志、验证指标、二进制工件等。
你如何用代码做到这一点?新的 Neptune API 依赖于一个类似字典的接口。您可以用一种统一的方式跟踪所有元数据,而不是在那里传递参数,在那里传递属性,以这种方式传递度量,以那种方式传递工件。
import neptune.new as neptune
run = neptune.init()
run['data/version/train'] = md5(train_set.data).hexdigest()
run['data/version/test'] = md5(test_set.data).hexdigest()
run["data/sample"].upload_files("data/sample_images")
PARAMS = {'lr': 0.005, 'momentum': 0.9}
run["model/params"] = PARAMS
run["model/visualization"].upload(File.as_image(model_vis))
for epoch in epochs:
for batch in batches:
[...]
run["batch/accuracy"].log(accuracy)
run["batch/loss"].log(accuracy)
run["test/total_accuracy"] = calculate_test_accuracy()
哦,这也意味着您不再需要担心预先设置参数—您可以在方便的时间和地点更新它们!
支持更多工作流:离线模式、恢复运行和 ML 管道
有时候你运行你的脚本,分析结果,然后继续前进。通常情况下,事情没那么简单:
- 也许你需要多训练几个纪元?
- 也许在第一次分析之后,您需要计算更多的验证指标?
- 也许你的 spot 实例死了,你需要恢复训练?
不要害怕。海王星已经为此做好了准备。更多🙂
使用新的 Python API,您可以恢复对任何现有运行的跟踪。您可以获取所有记录的元数据,更新它并记录新的。更重要的是,它现在是线程安全的,您可以将不同脚本的输出连接成一个。有了这些,你就可以在并行和分布式计算中,使用带有 spot 实例的 Neptune,以及多步 ML 流水线。
最后,如果你在无法永久访问互联网的地方训练你的模型,你会很高兴听到我们增加了离线模式。被跟踪的元数据将被保存在本地,您可以在方便的时候批量上传。如果您的互联网连接有点不稳定或发生意外中断——Neptune 现在会在多次重试后自动切换到离线模式,以确保您的数据始终安全。
更好的 web 界面:文件夹结构、更好的比较和拆分视图
您将注意到的第一件事是,新的 UI 利用了被跟踪元数据的组织的灵活性。以前,您必须在不同的部分之间跳转,才能完全理解生成模型的输入是什么。现在你可以在一个对你最方便的层次结构中组织元数据。
您将注意到的第二件事是,您可以看到所有运行及其元数据的表发生了变化。以前,比较不同运行的选项不仅有点难找到,而且变化意味着来回切换。最后,它只允许同时比较 10 次运行。现在,你可以:
- 比较方式更多次运行(比如 100 次或更多),
- 添加和删除您想要实时显示的内容,
- 在表格视图和比较之间切换或同时保持两者可见。
酷吧?嘶,还有一件事。当您浏览特定跑步的详细信息时,您可能会注意到“添加新仪表板”按钮。现在还有点早,我们将添加更多类型的小部件,但你已经可以构建自己的仪表板,以最适合你的方式可视化元数据。请检查它,并让我们知道你的想法!
跑,跑,跑(再见实验)
从这篇文章开始,我就一直用‘跑’这个词代替‘实验’,这不是巧合。随着我们行业的发展,越来越多的 Neptune 用户关心 ML 模型的可操作性,我们需要与它一起发展。
当然,实验阶段是重要的(并且贴近我们的内心),并且实验跟踪将仍然是 Neptune 的主要用例之一,但是越来越多的人将它用于其他事情,例如:
- 模型注册表
- 监控模型再训练管道
- 监控生产中运行的模型
我们希望更好地服务于您现有的使用案例。我们希望与您用来描述您的作品的命名更加一致。
称它为“实验”已经没有意义了,所以我们把它改成了“运行”。您将看到从实验到在 web 界面和新的 Python API 中运行的变化。
如何开始使用 neptune.new?
等等,我需要修改我的代码吗?
简而言之——不,你现在不需要做任何事情,你的跑步记录会被海王星跟踪,不会有任何问题。
新的 Python API 和改进的用户界面需要改变数据结构。在接下来的几周里,我们将把现有的项目迁移到新的结构,但是你已经可以尝试了,因为所有的新项目都是使用新的结构创建的。
当前的 Python API 将在迁移后继续工作,因此您不需要更改任何一行代码。在后台,我们悄悄地做我们的魔术,并确保事情为你工作。然而,新的 Python API 只与新的数据结构兼容,因此它只在项目迁移后才可用于项目。同样,改进的 web 界面也需要新的数据结构。您已经可以在一个新项目中试用它,并且一旦您的现有项目被迁移,它将可用于它们。
在未来的某个时候,我们计划在客户端库 1.0 版中,将新的 Python API 作为默认 API。然而,我们将在很长一段时间内支持当前的 Python API,这样你就可以在方便的时候进行切换。这是值得的转变,虽然,这是相当可怕的🙂我们准备了一本方便的移民指南来帮助你完成这个过程。
我想用 neptune.new,我现在该怎么做?
这非常简单:
第一步:
创建一个新项目–您会注意到它有一个标记,表明它是用新结构创建的
第二步:
将 Neptune 客户端库至少更新到 0.9 版本。只需在您的环境中运行:
pip install --upgrade neptune-client
第三步:
查看 新文档 。如果你想尝试一下,重新开始——快速入门部分是你最好的朋友。如果您想更新您现有的代码,我们准备了迁移指南来帮助您。
第四步:
享受跟踪元数据的新方式!
我们将在接下来的几周内将现有项目迁移到新的结构中,一旦您的项目被迁移,您也将能够使用新的 Python API。
新来海王星?
首先,你好,欢迎,感谢你读到这里!
如果你想知道到底是怎么回事,你可以:
…或者您可以:
1。创建免费账户
2。安装 Neptune 客户端库
pip install neptune-client
3。将日志添加到您的脚本中
import neptune.new as neptune
run = neptune.init(project="your_workspace/your_project")
run["JIRA"] = "NPT-952"
run["algorithm"] = "ConvNet"
params = {
"batch_size": 64,
"dropout": 0.2,
"learning_rate": 0.001,
"optimizer": "Adam"
}
run["parameters"] = params
for epoch in range(100):
run["train/accuracy"].log(epoch * 0.6)
run["train/loss"].log(epoch * 0.4)
run["f1_score"] = 0.67
4。在海王星看到它
海王星的下一步是什么?
就这样吗?
类似 Dict 的 API,文件夹结构,离线模式,更好的比较,Neptune 团队去海滩喝 pia coladas(当然是通过 Zoom)?
不,我们很快会有更多的东西,这次会更快。
正如我之前提到的,越来越多的 Neptune 用户正在将他们的模型推向生产(恭喜你们!).我们不仅要支持它,而且要让事情变得更简单,就像我们对实验跟踪所做的那样。
在接下来的几个月里:
- 我们将通过对工件版本控制(数据和模型)的支持,使人们使用 Neptune 作为模型注册表的体验变得更好。
- 我们将添加对更多元数据类型的支持,这样您可以在 Neptune 中轻松地记录、显示和比较它;
- 我们将添加与来自 MLOps 生态系统的更多库的集成。
但总的来说,总的来说,我们将努力使 MLOps 工作流中的元数据的存储、显示、组织和查询更加容易。我们将继续为 MLOps 构建一个 元数据存储。
构建自己的神经网络指南[以乳腺癌分类为例]
原文:https://web.archive.org/web/https://neptune.ai/blog/neural-network-guide
这是一个关于为乳腺癌分类建立自己的神经网络的实践指南。我将从基础开始,然后通过实现。
准确识别和分类乳腺癌亚型的任务是一项至关重要的临床任务,训练有素的病理学家可能需要数小时才能完成。因此,我们将尝试通过分析乳腺组织学图像,使用图像分类、PyTorch 和深度学习来自动进行乳腺癌分类。
我的重点将是为新的数据科学家或那些想要修改基础知识的人提供指南,并继续构建自己的神经网络。我们将涵盖:
- 神经网络是如何工作的?
- 卷积神经网络如何工作?
- 从零开始用 CNN 实现乳腺癌分类
什么是神经网络,它们是如何工作的?
为了理解神经网络,我们必须从感知机开始。
感知器或人工神经元是模仿生物神经元的数学模型。像神经元一样,感知器接受几个二进制输入,给出一个二进制输出。简单!
每个输入的重要性可以通过向输入添加权重来表示。神经元的输出,0 或 1,取决于加权和是大于还是小于阈值。从数学上讲,它是:
其中 w 是每个输入的权重, x 是输入。
通过改变权重和阈值,我们可以得到不同的模型。现在,为了简化我们表达感知机的方式,让我们把阈值移到不等式的另一边,用感知机的偏差 b =-阈值来代替。使用偏差代替阈值,感知器规则可以写成:
其中 W 和 x 为向量,其分量分别为权重和输入。
现在,当这些神经元排列在多个层次上时,它被称为神经网络。神经元并不是一个完整的决策模型,但它说明了神经元如何权衡不同种类的证据以做出决策。一个复杂的神经元网络可以做出非常微妙的决定,这似乎是合理的。
激活函数是用来获取神经元输出的函数。有两种类型的激活函数:线性和非线性(上面的函数是线性激活函数)。非线性函数是最常用的,因为它可以使模型更好地概括各种各样的数据——我们将在本文中使用一个。一些最常用的激活功能有:
- Sigmoid 函数
- Tanh 激活函数
- 整流器线性单元或 relu
- 李奇注意到了
Different activation functions and their graphs | Source
这是一个简单的神经网络的样子:
Simple two layer Neural Network | Source
第一层称为输入层,最右边的一层是输出层。这两层之间的层称为隐藏层。在这个网络中,第一层感知器通过权衡输入做出决策。输出被馈送到第二层,依此类推,直到最后一层。
由于每个感知器都是通过权衡来自前一层的输入来做出决策,因此决策的复杂性会随着层的降低而增加。这样,多层感知器网络参与复杂的决策任务。一层的输出用作下一层的输入的神经网络称为前馈网络。
现在,我们知道什么是神经网络,所以让我们讨论它们如何学习给出正确的输出。当我们说网络学习时,这意味着通过计算或遵循一些过程,网络已经找到了正确的权重和偏差集,从而使其损失最小。
损失是目标和我们从 w 和 b 的值得到的预测输出之间的差异。我们的目标是最小化该误差,以获得最精确的 w 和b值。让我们使用均方误差函数来计算我们的误差函数。
计算均方误差有三个步骤:
- 对于给定的 x,找出实际 y 值和预测 y 值之间的差值(y = wx + b)。
- 平方这个差值。
- 求 x 中每个值的平方的平均值。
这里 yᵢ是实际值,ȳᵢ是预测值。让我们代入ȳᵢ:的值
所以我们求误差的平方,然后求平均值。因此得名均方误差。
为什么要引入误差函数?毕竟,我们主要感兴趣的不是网络正确分类的图像数量吗?为什么不尝试直接最大化这个数字,而不是最小化一个像误差函数这样的代理测量?
问题在于,正确分类的图像数量不是网络中权重和偏差的平滑函数。在大多数情况下,对权重和偏差进行小的改变根本不会导致正确分类的训练图像的数量发生任何变化。请进入这个博客进一步阅读。
这使得很难找出如何改变权重和偏差来提高性能。如果我们改为使用平滑的成本函数,如上面定义的误差函数,则很容易找出如何对权重和偏差进行小的改变,以获得成本的改善。这就是为什么我们首先关注最小化误差函数,只有在这之后我们才会检查分类精度。
梯度下降
既然已经定义了损失函数,那就进入有趣的部分——最小化,求 w 和 b. 现在,梯度下降算法是一种求函数最小值的迭代优化算法。这里我们的函数是我们之前定义的误差函数。我将使用标量值解释梯度下降,并在稍后讨论图像分类时跳转到矩阵运算,因为图像基本上是一个矩阵。
让我们尝试对 w 和 b 应用梯度下降,并逐步接近它:
1.最初设 w = 4,b = 0。设 L 为我们的学习率。这控制了每一步 w 的值变化的程度。 L 可以是 0.0001 这样的小值,以获得良好的精度。请记住,权重 w 应始终随机初始化,而不是 1 或 0 [ 更多详情 ]
2.计算损失函数相对于 w 的偏导数,将 x、y、w、b 的当前值代入其中,得到导数值 D 。
现在 Dw 是相对于 w 计算的值。让我们相对于 b 来计算 D,即 Db。
3.现在,我们使用以下等式更新 w 和 b 的当前值:
w = w–L * D[w]
b = b–L * D[b]
4.我们重复这个过程,直到我们的损失函数是一个非常小的值或理想的 0(这意味着 0 误差或 100%的准确性)。我们现在剩下的 w 和 b 的值将是最佳值。现在有了 w 和 b 的最佳值,我们的模型就可以进行预测了!请注意,找到最佳值的“正确集合”至关重要。请查看本文中的以了解数据的过拟合和欠拟合,它们会干扰找到最佳值的“正确集合”。
为了使梯度下降正确工作,我们需要选择一个足够小的学习速率 L ,以便上面的方程是一个很好的近似,但不能太小,否则梯度下降将工作得太慢。
梯度下降通常工作得非常好,在神经网络中,我们会发现这是最小化成本函数和帮助网络学习的一种强有力的方法。
现在,应用梯度下降规则有一个挑战。快速浏览一下误差函数:
告诉我们这是单个训练样本误差的平均值。实际上,为了计算梯度 D ,我们需要为每个训练输入 x 分别计算梯度 D x,然后将它们平均。不幸的是,当训练输入的数量非常大时,这可能需要很长时间,因此学习发生得很慢。
为了处理这个问题,可以使用随机梯度下降。这里,不是计算精确的梯度 D,,而是为随机选择的训练输入的小样本或小批量计算估计的梯度。通过对这个小批量求平均,我们可以很快得到真实梯度的良好估计,这有助于加速梯度下降和学习。
这与神经网络中的学习有什么联系?让 w 和 b 成为我们网络中的权重和偏差。随机梯度下降的工作原理是挑选出一个随机选择的小批训练输入,并用它们进行训练。然后它随机挑选出另一批,用这些来训练。这一直持续到训练输入被耗尽,也就是说完成了一个时期的训练。此时,一个新的训练时代开始了。
有一种计算误差函数梯度的快速算法,称为反向传播。
反向传播是关于改变网络中的权重和偏差如何改变误差函数。反向传播的目标是计算误差函数 E 相对于网络中任何权重 w 或偏差 b 的偏导数 Dw 和 db。
Visual representation of backpropagation | Source
为了计算这些,让我引入一个中间值δ^lT2 j,它将是 l ^第层中第 j 第个神经元的误差。反向传播将给我们一个计算δl(t【9】t 10】j 的过程,然后将与 Dw 和 Db 相关联。)
让我们来理解这个误差是如何影响我们的神经网络的。错误出现在第 l ^(层的第 j 个个神经元上。当神经元的输入进来时,错误扰乱了神经元的操作。它给神经元的加权输入增加了一点变化∏el[j],所以神经元输出的不是 y(e^lj),而是 y(elj+∏elj)。这种变化通过网络中的后续层传播,最终导致总成本变化 D[elj]∏el[j]。)
反向传播基于四个基本方程:
1.输出层错误
其中 E 是误差函数,σ是激活函数。∂e/∂a^lj 测量t5】误差函数作为 j ^(th) 输出激活的函数变化有多快。第二项σ'e ^l [j] ,测量激活函数在 e^lj 的变化速度。为了简化,让我们把 E 看作一个向量,重写上面的表达式(等式 1):
2.误差就下一层的误差而言 (等式 2)
其中(w ^(l+1) ) ^T 是第(l+1)^(层的权重矩阵 w ^(l+1) 的转置。这看起来很复杂,但是让我来分解一下。假设我们知道第(l+1) ^(层的误差δ ^(l+1) 。当我们应用转置权重矩阵时,(w ^(l+1) ) ^T ,我们可以认为这是通过网络将误差向后移动,从而在第 l ^层层的输出端提供某种误差测量。然后我们取点积,O 代表点积。这通过层 l 中的激活函数向后移动误差,给出层 l 的加权输入中的误差δ ^l 。通过组合(等式 1) 和(等式 2) ,我们可以计算网络中任何层的误差δ ^l 。我们首先使用δ ^(L-1) ,然后再次使用(等式 2) 来计算δ ^(L-2) ,以此类推,一直通过网络返回。))
3.误差函数相对于网络中任何偏差的变化率(等式 3)
即误差δ(l[j])正好等于变化率∂E / ∂b ^l [j] 。(eq 1)****(eq 2)已经给了我们δ ^(l [j]) 。我们可以把 (eq 3) 简化为:
**
其中可以理解,δ在与偏差 b. 相同的神经元处被评估
4.误差相对于网络中任何权重的变化率(等式 4)
这显示了如何根据我们已经知道如何计算的量δ ^l 和 al-1 计算偏导数∂e/∂w^lJK。这里 a ^(l-1) 是神经元输入到权值 w 的激活,δ ^l 是神经元输出到权值w的误差通过查看 (eq 4),我们可以说当a ^(l-1) ≈ 0 时,梯度项也会趋于小,这意味着权值学习得慢,或者梯度换句话说,我们可以说(等式 4) 的结果是低激活神经元输出的权重学习缓慢。
总之,现在你已经看到,如果输入神经元是低激活的,或者输出神经元已经饱和,即高或低激活,权重将学习缓慢。
这四个基本方程适用于任何激活函数,不仅仅是标准的 sigmoid 函数或我们在开始讨论的感知器。让我们以伪算法的形式写出来:
- 输入 x : 设置输入层对应的激活 a ¹ 。
- 前馈:对于每个 l = 2,3,…,L 计算 e^L= wLa(L-1)+b^L和 a ^l =σ(e ^l )。
- 输出误差δ ^L : 计算矢量δL=∈[a]EOσ’(eL)。
- 反向传播误差:对于每个 l=L-1,L-2,…,2 计算δL=((w(L+1))Tδ(L+1))oσ'(e^L)。
- 输出:误差函数的梯度由∂e/∂w^lJK= a(l-1)[k]l[j]和∂e/∂bl[j]=δ(^l[j])给出。
检查该算法,您可以看到为什么它被称为 back propagation。我们从最后一层开始,反向计算误差向量δ^L。看起来很奇怪,我们在网络中倒退。但是如果你考虑反向传播的证据,反向传播是成本是网络输出的函数这一事实的结果。为了理解成本如何随着先前的权重和偏差而变化,我们需要重复应用链式法则,通过各层反向工作以获得可用的表达式。如果你不熟悉链式法则,请看看这个由 Josh Starmer 制作的视频。
如果你仍然不清楚反向传播的本质,我建议你看看这个视频和这个视频来了解反向传播演算。
对于博客的其余部分,我将使用 PyTorch 的 loss.backward(),因为它已经过优化。为了使用它,您需要使用 zero_grad()函数清除现有的渐变,否则渐变将会累积。
如何用 Neptune-PyTorch 集成跟踪模型训练元数据?
我们一直专注于前馈神经网络。现在,对于乳腺癌分类的任务,我们来看一个以图像分类闻名的神经网络。
什么是卷积神经网络?它们是如何工作的?
MNIST Data flow in CNN | Source
先说为什么我们需要卷积神经网络(ConvNets,CNN)而不是前馈神经网络。
考虑一个小图像,大小为 100100。对于前馈神经网络,第二层中的每个神经元有 10000 个权重。这使得网络容易过拟合数据。还有,把图像扁平化,缩小到 10000 权重,就失去了图像的本质。
CNN 是前馈神经网络(全连接神经网络)的正则化版本。常规的正则化方法包括随着损失函数的最小化而改变权重,同时随机调整连通性。
CNN 利用图像数据中的分层模式;在每一层中,它们捕捉小的局部特征(相对于前一层),但是随着深度的增加,这些特征相对于输入图像的复杂性增加。因此,这种局部过滤器(在一个小区域上局部连接的神经元)的堆叠使 CNN 能够捕捉复杂和空间不变的特征,如狗、猫、汽车等。与完全连接的网络相比,具有较少数量的可训练参数。我们可以说,它们在从图像中捕捉相关特征方面比完全连接的网络更有效。要了解更多关于 CNN 在图像分类中的重要性,请看这个由计算机爱好者制作的视频。
卷积神经网络是一种特殊类型的神经网络,它在至少一层中使用卷积(滤波器/内核与输入图像卷积以生成激活)而不是常规的矩阵乘法。CNN 的架构类似于全连接神经网络的架构。有一个输入层,隐藏层和最终输出层。
这里,隐藏层执行卷积。接下来是执行其他功能的其他层,如汇集层、全连接层和标准化层。让我们详细看看这些部分。
卷积层
正如我前面提到的,卷积发生在隐藏层中。准确地说,核心或者我们这里称之为滤波器,移动到图像中的不同位置,改变图像上卷积的步幅。对于过滤器的每个位置,计算过滤器和过滤器下的图像像素之间的点积,这导致输出图像中的单个像素。
因此,在整个输入图像上移动滤波器会产生新的图像。这些图像被称为特征地图。在第一卷积层中生成的特征图被下采样。这些特征图然后通过第二卷积层。这里,对于这些新生成的图像中的每一个,需要滤波器权重。结果图像被进一步下采样。如果你有兴趣深入了解卷积如何作用于图像,可以参考这篇关于执行卷积运算的博客。
汇集层
现在,除了通过改变卷积的步幅来进行下采样,还有其他可靠的方法来对图像进行下采样,如使用池层。池层通过将一层的神经元簇的输出合并到下一层的单个神经元中来减少数据维度。本地池合并小型集群,通常为 2 x 2。这进一步降低了分辨率。有两种类型的池:
- 最大池化–为每个特征图选取前一层的每个神经元簇的最大值
- 平均池化–为每个特征图选取每个神经元集群的平均值
Difference between max pooling and average pooling | Source
最大池通常是首选,因为它执行去噪和降维。
汇集有助于提取位置不变的主要特征。此外,维度的减少降低了处理数据所需的计算能力。
完全连接的层
A three layer fully connected multilayer perceptron structure that is identical to a fully connected layer in convolutional neural networks with only difference being the input layer | Source
最后一层是一个完全连接的层,它对我们的图像进行分类。卷积网络的输出然后被展平成列向量,并被馈送到完全连接的神经网络;反向传播应用于训练的每次迭代。
在一系列时期内,该模型能够区分图像中的主要和低级特征,并使用 softmax 分类技术对其进行分类。我不会详细介绍 softmax,但用几句话来说,softmax 分类器给出了每个类别的概率。要了解更多关于 softmax 分类的信息,请浏览 Adrian Rosebrock 的博客,他在博客中精彩地解释了 softmax 分类。
CNN 代码
现在,我们已经完成了基本知识,让我们构建自己的 CNN,看看它在 MNIST 数据集上的表现如何,在 Colab 中使用 Pytorch,使用 GPU。
首先,导入库。
import torch
import torchvision
import torchvision.transforms as transforms
import torch.nn as nn
import torch.nn.functional as F
下载培训和测试数据集。
transform = transforms.Compose(
[transforms.ToTensor(),
transforms.Normalize((0.5,), (0.5,))]
)
trainset = torchvision.datasets.MNIST(
root='./data', train=True, download=True, transform=transform)
trainloader = torch.utils.data.DataLoader(trainset, batch_size=64,
shuffle=True, num_workers=2)
testset = torchvision.datasets.MNIST(
root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=20,
shuffle=False, num_workers=2)
让我们想象一下我们将要用作输入的训练图像。
import matplotlib.pyplot as plt
import numpy as np
def imshow(img):
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()
dataiter = iter(trainloader)
images, labels = dataiter.next()
imshow(torchvision.utils.make_grid(images[:6], nrow=3))
device = torch.device('cuda' if torch.cuda.is_available() else "cpu")
现在,是时候建立我们的 cnn 了。
class NumClassifyNet(nn.Module):
def __init__(self):
super(NumClassifyNet, self).__init__()
self.conv1 = nn.Conv2d(1, 16, kernel_size=5)
self.conv2 = nn.Conv2d(16, 32, kernel_size=5)
self.pool = nn.MaxPool2d(2, 2)
self.fc1 = nn.Linear(512, 120)
self.fc2 = nn.Linear(120, 10)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = x.view(-1, self.flat_features(x))
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x
def flat_features(self, x):
size = x.size()[1:]
num_features = 1
for s in size:
num_features *= s
return num_features
net = NumClassifyNet()
net = net.to(device)
import torch.optim as optim
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr = 0.001)
是时候让模型接受训练了!
test_data_iter = iter(testloader)
test_images, test_labels = test_data_iter.next()
for epoch in range(10):
running_loss = 0
for i, data in enumerate(trainloader, 0):
input_imgs, labels = data
optimizer.zero_grad()
input_imgs = input_imgs.to(device)
labels = labels.to(device)
outputs = net(input_imgs)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 1000 == 0:
print('epoch', epoch+1, 'loss', running_loss/1000)
imshow(torchvision.utils.make_grid(test_images[0].detach()))
test_out = net(test_images.to(device))
_, predicted_out = torch.max(test_out, 1)
print('Predicted : ', ' '.join('%5s' % predicted_out[0]))
print('Training finished')
我们上一个巴赫的输出是:
损失少,预测准确,现在可以停止训练,用这个模型做预测了。
整个测试集达到的精度为:
使用 CNN 的乳腺癌分类
关于数据集的信息:乳腺组织病理学图像
乳腺组织病理学图片可以从 Kaggle 的网站下载。图像数据由 1,77,010 个 50×50 像素的小块组成,提取自以 40°扫描的乳腺癌样本的 162 个完整载片图像。数据包含阴性和阳性样本的图像。
让我们把数据从 kaggle 下载到我们的硬盘上,这样我们就可以使用它了。我发现文档含糊不清,所以我将用自己的话来解释如何做。希望有帮助。这是一次性设置:
1.设置 Kaggle API 访问:收集您的 Kaggle API 访问令牌。导航到您的 Kaggle 个人资料“帐户”页面。找到“创建您的 API 令牌”。下载包含用户名和密钥的 JSON 文件形式的令牌。
2.在 Drive 中保存 API 令牌:在你的 Google Drive 中为 Kaggle 创建一个文件夹。将 API 令牌的副本作为私有文件保存在该文件夹中,以便于访问。
3.将 Google Drive 安装到 Colab :这将确保您不必在每次重启运行时下载数据。
from google.colab import drive
drive.mount('/content/gdrive')
4.使用操作系统配置“Kaggle 环境”:这将把 API 键和值存储为操作系统环境对象t/变量。当您运行 Kaggle 终端命令时(在下一步中),您的机器将通过您的 API 令牌链接到您的帐户。链接到驱动器中的私有目录可以确保您的令牌信息保持隐藏。
import os
os.environ['KAGGLE_CONFIG_DIR'] = "/content/gdrive/MyDrive/kaggle"
5.下载数据
os.chdir('../content/gdrive/MyDrive/kaggle')
!kaggle datasets download -d paultimothymooney/breast-histopathology-images
现在我们有了数据集,让我们开始构建我们的网络吧!
import torch
import torchvision
from torchvision import transforms
from torchvision.datasets import ImageFolder
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import random_split
import torch.optim as optim
from collections import Counter
import matplotlib.pyplot as plt
import numpy as np
将图像转换为张量。
data_dir = "/content/gdrive/MyDrive"
folder_name = "kaggle"
image_folders = os.path.join(data_dir, folder_name)
transform = transforms.Compose([transforms.Resize((50, 50)), transforms.ToTensor()])
images = []
for file in os.listdir(image_folders):
try:
images.append(ImageFolder(os.path.join(image_folders, file), transform=transform))
except:
print(file)
datasets = torch.utils.data.ConcatDataset(images)
检查数据集,找出每个类中的样本数。
i=0
for dataset in datasets.datasets:
if i==0:
result = Counter(dataset.targets)
i += 1
else:
result += Counter(dataset.targets)
result = dict(result)
print("""Total Number of Images for each Class:
Class 0 (No Breast Cancer): {}
Class 1 (Breast Cancer present): {}""".format(result[0], result[1]))
输出:
现在,将数据集分成 75%的训练集和 25%的测试集。
random_seed = 42
torch.manual_seed(random_seed)
test_size = int(0.25*(result[0]+result[1]))
print(test_size)
train_size = len(datasets) - test_size
train_dataset, test_dataset = random_split(datasets, [train_size, test_size])
trainloader = torch.utils.data.DataLoader(train_dataset, batch_size=128,
shuffle=True, num_workers=2)
testloader = torch.utils.data.DataLoader(test_dataset, batch_size=64,
shuffle=False, num_workers=2)
现在,看看我们的数据集。
def imshow(img):
npimg = img.numpy()
plt.imshow(np.transpose(npimg, (1, 2, 0)))
plt.show()
dataiter = iter(trainloader)
images, labels = dataiter.next()
imshow(torchvision.utils.make_grid(images[:6], nrow=3))
labels[:6]
输出:
使用 GPU。
device = torch.device('cuda' if torch.cuda.is_available() else "cpu")
建立乳腺癌分类神经网络。
class BreastCancerClassifyNet(nn.Module):
def __init__(self):
super(BreastCancerClassifyNet, self).__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=3)
self.conv2 = nn.Conv2d(64, 128, kernel_size=3)
self.conv3 = nn.Conv2d(128, 256, kernel_size=3)
self.pool = nn.MaxPool2d(2, 2)
self.fc1 = nn.Linear(4096, 1024)
self.fc2 = nn.Linear(1024, 512)
self.fc3 = nn.Linear(512, 1)
def forward(self, x):
x = self.pool(F.relu(self.conv1(x)))
x = self.pool(F.relu(self.conv2(x)))
x = self.pool(F.relu(self.conv3(x)))
x = x.view(-1, self.flat_features(x))
x = F.relu(self.fc1(x))
x = F.relu(self.fc2(x))
x = self.fc3(x)
x = F.log_softmax(x)
return x
def flat_features(self, x):
size = x.size()[1:]
num_features = 1
for s in size:
num_features *= s
return num_features
net = BreastCancerClassifyNet()
net = net.to(device)
使用二元交叉熵损失,就像我们做二元分类一样。
criterion = nn.BCELoss()
optimizer = optim.SGD(net.parameters(), lr = 0.001)
该训练了!
test_data_iter = iter(testloader)
test_images, test_labels = test_data_iter.next()
for epoch in range(20):
running_loss = 0
for i, data in enumerate(trainloader, 0):
input_imgs, labels = data
input_imgs = input_imgs.to(device)
labels = labels.to(device)
optimizer.zero_grad()
outputs = net(input_imgs)
labels = labels.unsqueeze(1).float()
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
if i % 10000 == 0:
print('epoch', epoch+1, 'loss', running_loss/10000)
imshow(torchvision.utils.make_grid(test_images[0].detach()))
test_out = net(test_images.to(device))
_, predicted_out = torch.max(test_out, 1)
print('Predicted : ', ' '.join('%5s' % predicted_out[0]))
print('Training finished')
最后,在所有数据集上测试我们训练的模型并计算准确性。
correct = 0
total = 0
with torch.no_grad():
for data in testloader:
test_images, test_labels = data
test_out = net(test_images.to(device))
_, predicted = torch.max(test_out.data, 1)
total += test_labels.size(0)
for _id, out_pred in enumerate(predicted):
if int(out_pred) == int(test_labels[_id]):
correct += 1
print('Accuracy of the network on the 44252 test images: %d %%' % (
100 * correct / total))
输出:
现在,这个精度似乎比我们之前达到的要低,但是请注意,我们使用了一个更复杂的数据集,并且我们从头开始构建了这个模型。尽管如此,我们仍然达到了 20 个时期的良好精度。
为了实现更高的准确性,您可以使用在数百万数据集上训练的预训练网络作为基础,并在此基础上构建您的分类模型,即通过应用迁移学习。
结论
我们从定义神经网络发展到建立自己的乳腺癌分类神经网络。让我们回顾一下我们所学的内容:
- 我们首先研究了神经网络的定义。神经元代表什么,它们是如何形成网络的?
- 然后转到他们是如何工作的。简要了解激活函数后,我们进入误差函数,以及梯度下降如何帮助减少误差。
- 我们进一步研究了反向传播,我对它的数学做了简单的解释。
- 然后我们转向 CNN 及其每一层,然后从头开始构建我们自己的 CNN 来对 MNIST 数据集进行分类。
- 凭借我们对神经网络的集体知识,我们为乳腺癌分类建立了自己的神经网络。
资源
我向您展示了如何构建自己的乳腺癌分类网络,但我希望这篇博客将有助于为任何数据集构建自己的分类神经网络。
我希望你喜欢这次旅行!感谢阅读。**
对象检测算法和库
原文:https://web.archive.org/web/https://neptune.ai/blog/object-detection-algorithms-and-libraries
对象检测在图像中找到并识别事物,这是深度学习和图像处理的最大成就之一。为对象创建本地化的一种常用方法是借助边界框。您可以训练一个对象检测模型来识别和检测多个特定对象,因此它是通用的。
物体检测模型通常被训练来检测特定物体的存在。所构建的模型可用于图像、视频或实时操作。即使在深度学习方法和现代图像处理技术之前,对象检测也有很高的兴趣范围。某些方法(如 SIFT 和 HOG 及其特征和边缘提取技术)在对象检测方面取得了成功,该领域的其他竞争者相对较少。
随着卷积神经网络(CNN)的引入和计算机视觉技术的适应,对象检测在当前一代变得更加普遍。具有深度学习方法的对象检测的新浪潮打开了看似无限的可能性。
对象检测利用每个类的特殊和唯一属性来识别所需的对象。在寻找正方形形状时,对象检测模型可以寻找将导致正方形形状的垂直角,每个边具有相同的长度。在寻找圆形对象时,对象检测模型将寻找中心点,从这些中心点可以创建特定的圆形实体。这种识别技术用于面部识别或物体跟踪。
在这篇文章中,我们将探索不同的对象检测算法和库,但首先,一些基础知识。
物体检测用在哪里?
在我们的日常生活中,物体检测已经无处不在。比如你的智能手机用人脸检测解锁的时候。或者在商店或仓库的视频监控中,它可以识别可疑活动。
以下是物体检测的几个主要应用:
- 车牌识别–使用物体检测和光学字符识别(OCR)技术来识别车辆上的字母数字字符。您可以使用对象检测来捕捉图像并检测特定图像中的车辆。一旦模型检测到车牌,OCR 技术就会将二维数据转换成机器编码的文本。
- 人脸检测和识别——如前所述,物体检测的主要应用之一是人脸检测和识别。在现代算法的帮助下,我们可以检测图像或视频中的人脸。由于一次性学习方法,现在甚至可以只用一张经过训练的图像来识别人脸。
- 物体追踪——观看棒球或板球比赛时,球可能会打到很远的地方。在这些情况下,跟踪球的运动以及它所经过的距离是很好的。为此,目标跟踪可以确保我们获得关于球运动方向的连续信息。
- 自动驾驶汽车——对于自动驾驶汽车来说,在驾驶时研究汽车周围的不同元素至关重要。在多个类别上训练以识别不同实体的对象检测模型对于自主车辆的良好性能变得至关重要。
- 机器人–许多任务,如提升重物、取放操作以及其他实时工作都由机器人完成。物体检测对于机器人检测事物和自动化任务是必不可少的。
目标检测算法
自从深度学习在 2010 年代早期普及以来,用于解决对象检测的算法的质量一直在不断进步和提高。我们将探索最流行的算法,同时了解它们的工作原理、优点以及它们在特定场景中的缺陷。
1.方向梯度直方图(HOG)
→简介
方向梯度直方图是最古老的物体检测方法之一。它于 1986 年首次推出。尽管在接下来的十年中有一些发展,但这种方法直到 2005 年才开始在许多与计算机视觉相关的任务中使用。HOG 使用特征提取器来识别图像中的对象。
HOG 中使用的特征描述符是图像的一部分的表示,我们只提取最必要的信息,而忽略其他任何东西。特征描述符的功能是将图像的整体大小转换成数组或特征向量的形式。在 HOG 中,我们使用梯度方向过程来定位图像的最关键部分。
→架构概述
HOG – Object Detection Algorithm | Source
在我们理解 HOG 的整体架构之前,先来看看它是如何工作的。对于图像中的特定像素,通过考虑垂直和水平值来计算梯度的直方图,以获得特征向量。借助于梯度幅度和梯度角度,我们可以通过探索水平和垂直环境中的其他实体来获得当前像素的明确值。
如上图所示,我们将考虑一个特定大小的图像片段。第一步是通过将图像的整个计算分成 8×8 个单元的梯度表示来找到梯度。在获得的 64 个梯度向量的帮助下,我们可以将每个单元分割成角度箱,并计算特定区域的直方图。该过程将 64 个向量的大小减少到 9 个值的较小大小。
一旦我们获得每个单元的 9 点直方图值(仓)的大小,我们就可以选择为单元块创建重叠。最后的步骤是形成特征块,归一化获得的特征向量,并收集所有的特征向量以获得整体 HOG 特征。查看以下链接了解更多信息:【1】和【2】。
HOG 的成就
- 创建对执行对象检测有用的特征描述符。
- 能够与支持向量机(SVMs)相结合,实现高精度的物体检测。
- 为每个位置的计算创建滑动窗口效果。
→需要考虑的要点
- 限制–虽然梯度方向直方图(HOG)在物体检测的初始阶段具有革命性,但这种方法存在许多问题。对于图像中复杂的像素计算来说,这是非常耗时的,并且在某些空间较紧的对象检测场景中是无效的。
- 什么时候用 HOG?–HOG 应经常被用作对象检测的第一种方法,以测试其他算法及其各自的性能。无论如何,HOG 在大多数对象检测和面部标志识别中具有相当高的准确度。
- 示例用例–HOG 最受欢迎的用例之一是行人检测,因为它边缘平滑。其他一般应用包括特定对象的对象检测。更多信息,请参考下面的链接。
2.基于区域的卷积神经网络
→简介
基于区域的卷积神经网络是对之前 HOG 和 SIFT 方法的对象检测过程的改进。在 R-CNN 模型中,我们试图通过使用选择性特征来提取最基本的特征(通常大约 2000 个特征)。选择最重要的提取的过程可以在选择性搜索算法的帮助下计算,该算法可以实现这些更重要的区域提议。
→R-CNN 的工作过程
R-CNN – Object Detection Algorithm | Source
用于选择最重要的区域建议的选择性搜索算法的工作程序是确保您在特定图像上生成多个子分割,并为您的任务选择候选条目。然后,可以利用贪婪算法来相应地组合有效条目,用于循环过程,以将较小的片段组合成合适的较大片段。
一旦选择性搜索算法成功完成,我们接下来的任务就是提取特征并做出适当的预测。然后,我们可以做出最终的候选提议,并且卷积神经网络可以用于创建 n 维(2048 或 4096)特征向量作为输出。在预先训练好的卷积神经网络的帮助下,我们可以轻松地完成特征提取的任务。
R-CNN 的最后一步是对图像进行适当的预测,并相应地标记相应的边界框。为了获得每个任务的最佳结果,通过计算每个任务的分类模型来进行预测,同时使用回归模型来校正提议区域的边界框分类。有关该主题的更多阅读和信息,请参考以下链接。
→R-CNN 的问题
1.尽管利用预先训练的 CNN 模型产生了有效的特征提取结果,但是利用当前算法提取所有区域提议以及最终最佳区域的整体过程极其缓慢。
2。R-CNN 模型的另一个主要缺点不仅是训练速度慢,而且预测时间长。该解决方案需要使用大量的计算资源,增加了该过程的整体可行性。因此,整体架构可以认为是相当昂贵的。
3。有时,由于在这一特定步骤中缺乏改进,在初始步骤中可能会出现糟糕的候选人选择。这可能会导致训练模型中的许多问题。
→需要考虑的要点
- 何时使用 R-CNN?–与 HOG 物体检测方法类似的 R-CNN 必须用作测试物体检测模型性能的第一基线。预测图像和物体所花费的时间可能比预期的要长一点,所以通常更现代版本的 R-CNN 更受欢迎。
- 示例用例–R-CNN 有几种应用,用于解决与对象检测相关的不同类型的任务。例如,从无人机安装的摄像头跟踪对象,在图像中定位文本,以及在谷歌镜头中启用对象检测。查看以下链接了解更多信息。
3.更快的 R-CNN
→简介
虽然 R-CNN 模型能够执行对象检测的计算并获得期望的结果,但是有一些主要的不足之处,尤其是模型的速度。因此,必须引入更快的方法来解决这些问题,以克服 R-CNN 中存在的问题。首先,快速 R-CNN 被引入以对抗 R-CNN 的一些预先存在的问题。
在快速 R-CNN 方法中,整个图像通过预先训练的卷积神经网络,而不是考虑所有的子片段。感兴趣区域(RoI)池是一种特殊的方法,它采用预训练模型和选择性搜索算法的两个输入来提供一个具有输出的全连接图层。在本节中,我们将了解更快的 R-CNN 网络,它是对快速 R-CNN 模型的改进。
→了解更快的 R-CNN
Faster R-CNN – Object Detection Algorithm | Source
更快的 R-CNN 模型是 R-CNN 家族中最好的版本之一,与它的前辈相比极大地提高了性能速度。虽然 R-CNN 和快速 R-CNN 模型利用选择性搜索算法来计算区域提议,但是更快的 R-CNN 方法用更好的区域提议网络来代替这种现有方法。区域提议网络(RPN)计算来自大范围和不同尺度的图像,以产生有效的输出。
区域建议网络减少了边缘计算时间,通常每幅图像 10 ms。这个网络由卷积层组成,从中我们可以获得每个像素的基本特征图。对于每个特征地图,我们有多个锚定框,它们具有不同的比例、不同的大小和纵横比。对于每个锚定框,我们对特定的二进制类进行预测,并为其生成一个边界框。
来自非最大抑制的输出通过感兴趣的区域,并且其余的过程和计算类似于快速 R-CNN 的工作。
→需要考虑的要点
- 限制–更快的 R-CNN 方法的主要限制之一是不同对象的命题中的时间延迟量。有时,速度取决于所用系统的类型。
- 什么时候用更快的 R-CNN?–与其他 CNN 方法相比,预测时间更快。虽然 R-CNN 通常需要大约 40-50 秒来预测图像中的对象,但快速 R-CNN 需要大约 2 秒,但更快的 R-CNN 只需大约 0.2 秒即可返回最佳结果。
- 用例示例–更快 R-CNN 的用例示例与 R-CNN 方法中描述的相似。然而,有了更快的 R-CNN,我们可以更好地执行这些任务,更有效地取得成果。
4.单发探测器(SSD)
→简介
用于多框预测的单次检测器是实现物体检测任务实时计算的最快方法之一。虽然更快的 R-CNN 方法可以实现高精度的预测,但是整个过程非常耗时,并且需要实时任务以大约每秒 7 帧的速度运行,这是远远不理想的。
单镜头检测器(SSD)通过将每秒帧数提高到比更快的 R-CNN 模型快近五倍来解决这个问题。它不再使用区域建议网络,而是使用多尺度特征和默认框。
→架构概述
SSD – Object Detection Algorithm | Source
单次触发多盒探测器架构可分为三个主要部分。单次检测器的第一阶段是特征提取步骤,选择所有关键的特征图。这个架构区域仅由完全卷积层组成,没有其他层。提取完所有的本质特征图后,接下来就是检测人头的过程。这一步也包括完全卷积神经网络。
然而,在探测头的第二阶段,任务不是找到图像的语义。相反,主要目标是为所有特征图创建最合适的边界图。一旦我们计算了两个基本阶段,最后一个阶段是使其通过非最大抑制层,以减少由重复的边界框引起的错误率。
→固态硬盘的局限性
- SSD 虽然显著提升了性能,但会降低图像的分辨率,从而降低图像质量。
- 对于小规模对象,SSD 架构的性能通常比更快的 R-CNN 差。
→需要考虑的要点
- 什么时候用 SSD?–单次检测器通常是首选方法。使用单次检测器的主要原因是因为我们更喜欢对图像进行更快的预测,以检测更大的对象,在这种情况下精度不是非常重要的问题。然而,为了更准确地预测更小和更精确的物体,必须考虑其他方法。
- 示例用例–单次检测器可以在多种数据集上进行训练和实验,如 PASCAL VOC、COCO 和 ILSVRC 数据集。它们可以很好地执行较大的对象检测,如人、桌子、椅子和其他类似实体的检测。
5.YOLO(你只看一眼)
→简介
你只看一次( YOLO )是物体检测最流行的模型架构和算法之一。通常,在谷歌上搜索物体检测算法的第一个概念是 YOLO 架构。YOLO 有几个版本,我们将在接下来的章节中讨论。YOLO 模型使用最好的神经网络原型之一来产生高精度和整体处理速度。这种速度和准确性是其受欢迎的主要原因。
→YOLO 的工作过程
YOLO – Object Detection Algorithm | Source
YOLO 体系结构利用三个主要术语来实现其目标检测。理解这三种技术对于了解为什么与其他对象检测算法相比,该模型执行得如此快速和准确是非常重要的。YOLO 模型中的第一个概念是残差块。在第一个建筑设计中,他们使用 7×7 的剩余块在特定的图像中创建网格。
这些网格中的每一个充当中心点,并且相应地对这些网格中的每一个做出特定的预测。在第二种技术中,考虑特定预测的每个中心点来创建边界框。虽然分类任务对每个格网都很有效,但是为每个预测分离边界框会更复杂。第三种也是最后一种技术是使用并集的交集(IOU)来计算特定对象检测任务的最佳边界框。
→YOLO 的优势
- YOLO 的计算和处理速度是相当高的,特别是与大多数其他训练方法和目标检测算法相比实时性更好。
- 除了快速的计算速度之外,YOLO 算法还设法提供整体的高精度,同时减少了在其他方法中看到的背景误差。
- YOLO 的建筑允许模型更有效地学习和发展对众多物体的理解。
→YOLO 的局限性
- 由于召回率较低,无法检测图像或视频中的较小对象。
- 由于边界框的限制,无法检测两个彼此非常接近的对象。
→YOLO 的版本
YOLO 架构是最有影响力和最成功的对象检测算法之一。随着 2016 年 YOLO 架构的推出,他们的连续版本 YOLO v2 和 YOLO v3 于 2017 年和 2018 年问世。虽然 2019 年没有新版本,但 2020 年有三个快速版本:YOLO v4、YOLO v5 和 PP-YOLO。YOLO 的每一个新版本都比前一个版本稍有改进。微小的 YOLO 也被发布,以确保嵌入式设备可以支持对象检测。
→需要考虑的要点
- 什么时候使用 YOLO?–虽然之前讨论的所有方法在图像和视频目标检测分析中表现都很好,但 YOLO 架构是实时目标检测的首选方法之一。它在大多数实时处理任务上实现了很高的准确性,具有相当快的速度和每秒帧数,具体取决于运行该程序的设备。
- 示例用例–除了对众多对象进行对象检测之外,YOLO 架构的一些流行用例还包括车辆检测、动物检测和人员检测。更多信息,请参考以下链接。
6.RetinaNet
→简介
2017 年推出的 RetinaNet 模型成为这段时间内单次物体检测能力能够超越其他流行物体检测算法的最佳模型之一。当 RetinaNet 架构发布时,对象检测能力超过了 Yolo v2 和 SSD 模型。在保持与这些型号相同的速度的同时,它还能够在准确性方面与 R-CNN 家族竞争。由于这些原因,RetinaNet 模型在通过卫星图像探测物体方面有很高的使用率。
→架构概述
RetineNet – Object Detection Algorithm | Source
RetinaNet 架构的构建方式使得以前的单次检测器问题得到某种程度的平衡,从而产生更有效和高效的结果。在这种模型架构中,以前模型中的交叉熵损失被焦点损失代替。焦点损耗处理 YOLO 和 SSD 等架构中存在的类不平衡问题。RetinaNet 模型是三个主要实体的组合。
RetinaNet 使用三个因素构建,即 ResNet 模型(特别是 ResNet-101)、特征金字塔网络(FPN)和焦点损失。特征金字塔网络是克服先前架构的大部分缺点的最佳方法之一。它有助于将低分辨率图像的语义丰富的特征与高分辨率图像的语义较弱的特征相结合。
在最终输出中,我们可以创建分类和回归模型,类似于前面讨论的其他对象检测方法。分类网络用于适当的多类预测,而回归网络被构建来预测分类实体的适当边界框。关于这个主题的更多信息和阅读,请分别从以下链接查看文章或视频指南,【1】和【2】。
→需要考虑的要点
- 何时使用 RetinaNet?–retina net 是目前众多不同任务中物体检测的最佳方法之一。它可以作为单次检测器的替代品,用于多种任务,以获得快速准确的图像结果。
- 示例用例–re Tina net 对象检测算法可用于多种应用。RetinaNet 的一个高级应用程序用于航空和卫星图像中的物体检测。
对象检测库
1.ImageAI
→简介
ImageAI 库旨在为开发人员提供大量的计算机视觉算法和深度学习方法,以完成与对象检测和图像处理相关的任务。ImageAI 库的主要目标是提供一种用几行代码编写对象检测项目的有效方法。
关于这个主题的更多信息,请务必通过下面的链接访问 ImageAI 库的官方文档。大多数可用的代码块都是在 Python 编程语言和流行的深度学习框架 Tensorflow 的帮助下编写的。截至 2021 年 6 月,该库使用 PyTorch 后端来计算图像处理任务。
→概述
ImageAI 库支持大量与对象检测相关的操作,即图像识别、图像对象检测、视频对象检测、视频检测分析、自定义图像识别训练和推理以及自定义对象检测训练和推理。图像识别功能可以识别特定图像中多达 1000 个不同的对象。
图像和视频对象检测任务将有助于检测日常生活中最常见的 80 个对象。视频检测分析将有助于计算在视频中或实时检测到的任何特定对象的及时分析。也可以引入自定义图像来训练该库中的样本。在更新的图像和数据集的帮助下,您可以为对象检测任务训练更多的对象。
→ GitHub 参考
有关 ImageAI 库的更多信息和阅读,请参考以下 GitHub 参考。
2.格鲁恩科夫
→简介
GluonCV 是最好的库框架之一,拥有各种计算机视觉应用的深度学习算法的大多数最先进的实现。这个库的主要目标是帮助这个领域的爱好者在更短的时间内获得富有成效的结果。它拥有一些最好的特性,包括大量的训练数据集、实现技术和精心设计的 API。
→概述
GluonCV 库框架支持您可以用它完成的大量任务。这些项目包括图像分类任务、图像、视频或实时中的对象检测任务、语义分割和实例分割、用于确定特定身体姿势的姿势估计,以及用于检测正在执行的人类活动类型的动作识别。这些特性使这个库成为最好的对象检测库之一,可以更快地获得结果。
这个框架提供了执行前面提到的任务所需的所有最新技术。它支持 MXNet 和 PyTorch,并且有大量的教程和额外的支持,您可以从中开始探索许多概念。它包含大量的训练模型,您可以从中探索和创建您选择的特定机器学习模型来执行特定的任务。
在虚拟环境中安装了 MXNet 或 PyTorch 之后,您可以通过这个链接开始简单安装这个对象检测库。您可以选择库的特定设置。它还允许您访问模型动物园,这是轻松部署机器学习模型的最佳平台之一。所有这些特性使得 GluonCV 成为一个伟大的对象检测库。
→ GitHub 参考
关于这个库的更多信息和阅读,请查看下面的 GitHub 参考资料。
3.检测器 2
→简介
由脸书人工智能研究(FAIR)团队开发的 Detectron2 框架被认为是下一代库,支持大多数最先进的检测技术、对象检测方法和分割算法。 Detectron2 库是一个基于 PyTorch 的对象检测框架。该库具有高度的灵活性和可扩展性,为用户提供了多种高质量的实现算法和技术。它还支持脸书上的许多应用和生产项目。
→概述
FaceBook 在 PyTorch 上开发的 Detectron2 库有着巨大的应用,可以在单个或多个 GPU 上进行训练,以产生快速有效的结果。在这个库的帮助下,您可以实现几种高质量的对象检测算法,以达到最佳效果。该库支持的这些最先进的技术和对象检测算法包括
DensePose、panoptic 功能金字塔网络,以及开创性的 Mask R-CNN 模型系列的许多其他变体。【1】
Detectron2 库还允许用户轻松训练自定义模型和数据集。以下内容的安装过程非常简单。您需要的唯一依赖项是 PyTorch 和 COCO API。一旦您满足了以下要求,您就可以开始安装 Detectron2 模型,并轻松训练多个模型。要了解更多并理解如何使用下面的库,您可以使用下面的指南。
→ GitHub 参考
关于这个库的更多信息和阅读,请查看下面的 GitHub 参考资料。
4. YOLOv3_TensorFlow
→简介
YOLO v3 车型是 2018 年发布的 YOLO 系列的成功实现之一。YOLO 的第三个版本是对以前型号的改进。这个模型的性能在速度和准确性方面都优于它的前辈。与其他架构不同,它还可以在较小的对象上以良好的精度运行。与其他主要算法相比,唯一主要关注的是速度和准确性之间的权衡。
→概述
YOLOv3_TensorFlow 库是用于对象检测处理和计算的 YOLO 体系结构的最早实现之一。它提供了极快的 GPU 计算,有效的结果和数据管道,重量转换,更快的训练时间,等等。虽然可以从下一节提供的链接中获得该库,但对该框架的支持已经停止(与大多数其他框架类似),现在由 PyTorch 支持。
→ GitHub 参考
有关 YOLO 的更多信息和阅读,请参考下面的 GitHub 参考。
5.暗流
→简介
Darkflow 的灵感来自于 darknet 框架,基本上是一个翻译,以适应 Python 编程语言和 TensorFlow,使其可以被更广泛的受众访问。Darknet 是一个用 C 和 CUDA 实现的对象检测库的早期实现。这个库的安装和工作过程非常简单,易于执行。该框架还支持对象检测任务的 CPU 和 GPU 计算,以在任一场景中获得最佳结果。
→概述
暗流框架的实现需要一些基本的必需品。这些基本需求包括 Python3、TensorFlow、Numpy 和 Opencv。有了这些依赖,您可以轻松地开始与对象检测相关的计算任务。有了暗流库,可以实现很多任务。暗流框架可以访问 YOLO 模型,您可以下载各种模型的自定义权重。
darkflow 库帮助您完成的一些任务包括解析注释、根据特定配置设计网络、绘制流图、训练新模型、训练自定义数据集、创建实时或视频文件、为其他类似应用程序使用 Darkflow 框架,最后,它还允许您将这些模型保存在 protobuf(.pb)格式。
→ GitHub 参考
有关更多信息和阅读,请参考以下 GitHub 参考。
结论
物体检测仍然是迄今为止最重要的深度学习和计算机视觉应用之一。我们已经看到了物体检测方法的许多改进和进步。
它始于像梯度方向直方图这样的算法,这种算法早在 1986 年就被引入,用于以相当高的精度对图像进行简单的对象检测。现在,我们有了现代架构,如更快的 R-CNN、Mask R-CNN、YOLO 和 RetinaNet。
对象检测的限制不限于图像,因为它们可以在视频和实时镜头上以高精度有效地执行。在未来,更多成功的物体检测算法和库仍在等待着我们。
YOLO 物体检测:实践教程
原文:https://web.archive.org/web/https://neptune.ai/blog/object-detection-with-yolo-hands-on-tutorial
Object detection in action.
Source: Supercharge your Computer Vision models with the TensorFlow Object Detection API,
Jonathan Huang, Research Scientist and Vivek Rathod, Software Engineer,
Google AI Blog
作为计算机视觉任务的目标检测
我们生活中每天都会遇到物体。环顾四周,你会发现多个物体围绕着你。作为一个人,你可以很容易地发现和识别你看到的每一个物体。这很自然,不需要太多努力。
然而,对于计算机来说,检测物体是一项需要复杂解决方案的任务。对计算机来说,“检测物体”意味着处理输入图像(或视频中的单个帧),并以图像上的物体及其位置的信息做出响应。用计算机视觉的术语来说,我们把这两个任务叫做分类和定位。我们希望计算机能说出给定图像上呈现的是哪种物体,以及它们的确切位置。
已经开发了多种解决方案来帮助计算机检测物体。今天,我们将探索一种叫做 YOLO 的最先进的算法,它能以实时速度实现高精度。特别是,我们将学习如何在 TensorFlow / Keras 中的自定义数据集上训练该算法。
首先,让我们看看 YOLO 到底是什么,它以什么而闻名。
作为实时物体探测器的 YOLO
什么是 YOLO?
YOLO 是“你只看一次”的首字母缩写(不要和《辛普森一家》中的“你只活一次”混淆)。顾名思义,单个“外观”就足以找到图像上的所有对象并识别它们。
用机器学习的术语来说,我们可以说所有的物体都是通过单次算法运行检测到的。这是通过将图像划分为网格并预测网格中每个单元的边界框和分类概率来实现的。如果我们想使用 YOLO 进行汽车检测,下面是网格和预测边界框的样子:
Grid that YOLO builds (black cells).
Bounding box that YOLO predicts for the first car is in red.
Bounding box that YOLO predicts for the second car is yellow.
Source of the image.
上面的图像只包含过滤后得到的最后一组盒子。值得注意的是,YOLO 的原始输出包含同一个对象的许多边界框。这些盒子的形状和大小不同。正如您在下图中所看到的,一些盒子在捕捉目标对象方面表现得更好,而算法提供的其他盒子则表现不佳。
All bounding boxes in red are predicted by YOLO to capture the first car.
All yellow boxes are for the second car.
The bold red and yellow boxes are the best for car detection.
Source of the image.
为了选择给定对象的最佳边界框,应用了非最大抑制(NMS) 算法。
Non-maximum suppression will handle the multiple bounding
boxes predicted for the cars to keep only those that best capture objects.
Source of the image.
YOLO 预测的所有盒子都有与之相关联的置信度。NMS 使用这些置信度值来去除预测可信度低的框。通常,这些都是预测置信度低于 0.5 的框。
Each bounding box is predicted with a confidence level.
You can see the confidence scores in the top-left corner of each box, next to the object name.
Source of the image.
当所有不确定的边界框都被移除时,只留下具有高置信度的框。为了从表现最好的候选中选出最好的一个,NMS 选择了可信度最高的盒子,并计算它与周围其他盒子的交集。如果一个交点高于特定的阈值水平,则具有较低置信度的边界框被移除。如果 NMS 比较两个具有低于选定阈值的交集的框,则两个框都保留在最终预测中。
YOLO 与其他探测器相比
虽然卷积神经网络(CNN)在 YOLO 的引擎盖下使用,但它仍然能够实时检测对象。这是可能的,因为 YOLO 有能力用一步到位的方法同时进行预测。
其他较慢的对象检测算法(如更快的 R-CNN )通常使用两阶段方法:
- 在第一阶段,选择感兴趣的图像区域。这些是图像中可能包含任何对象的部分;
- 在第二阶段,使用卷积神经网络对这些区域中的每一个进行分类。
通常,在一幅图像上有许多带有物体的区域。所有这些区域都被送去分类。分类是一项耗时的操作,这就是两阶段对象检测方法比一阶段检测方法执行速度慢的原因。
YOLO 不会选择图像中有趣的部分,这是没有必要的。取而代之的是,它在一次正向网络传递中预测整个图像的边界框和类。
下面你可以看到与其他流行的探测器相比,YOLO 的速度有多快。
Frames per second (FPS) is a metric that lets us compare the speed of different object detectors.
SSD and YOLO are one stage object detectors whereas Faster-RCNN
and R-FCN are two-stage object detectors.
Source of the image.
YOLO 的版本
2015 年,Joseph Redmon 在其名为“你只看一次:统一、实时的物体检测”的研究论文中首次介绍了 YOLO。
自那以后,YOLO 发生了很大的变化。2016 年,Joseph Redmon 在《YOLO9000:更好、更快、更强》中描述了第二个 YOLO 版本。
大约在第二次 YOLO 升级两年后,Joseph 提出了另一个网络升级。他的论文名为“ YOLOv3:增量改进”,引起了许多计算机工程师的注意,并在机器学习社区中流行起来。
2020 年,Joseph Redmon 决定停止研究计算机视觉,但这并没有阻止 YOLO 被其他人开发。同年,一个由三名工程师组成的团队(阿列克谢·博奇科夫斯基、钱和廖宏远)设计了第四版的 YOLO,比以前更快更精确。他们在 2020 年 4 月 23 日发表的“ YOLOv4:物体探测的最佳速度和精度”论文中描述了他们的发现。
YOLOv4 compared to other detectors, including YOLOv3.
AP on the Y-axis is a metric called “average precision”. It describes the accuracy of the net.
FPS (frames per second) on the X-axis is a metric that describes speed.
Source of the image.
第四版发布两个月后,独立开发者 Glenn Jocher 发布了 YOLO 的第五版。这一次,没有发表研究论文。这个网络作为 PyTorch 实现出现在 Jocher 的 GitHub 页面上。第五版的精确度和第四版差不多,但速度更快。
最后,在 2020 年 7 月,我们得到了另一个大的 YOLO 更新。在一篇名为“ PP-YOLO:物体探测器的有效和高效实现”的论文中,项龙和他的团队提出了一个新版本的 YOLO。YOLO 的这一迭代是基于第三个模型版本,并超过了 YOLO v4 的性能。
PP-YOLO compared to other detectors, including YOLOv4.
The mAP on the Y-axis is a metric called “ mean average precision”. It describes the accuracy of the net.
FPS (frames per second) on the X-axis is a metric that describes speed.
Source of the image.
在本教程中,我们将仔细研究 YOLOv4 及其实现。为什么是 YOLOv4?三个原因:
- 它在机器学习社区得到了广泛的认可;
- 这个版本已经在广泛的探测任务中证明了它的高性能;
- YOLOv4 已经在多个流行的框架中实现,包括我们将要合作的 TensorFlow 和 Keras。
YOLO 应用示例
在我们进入本文的实际部分,实现我们自定义的基于 YOLO 的对象检测器之前,我想向您展示几个很酷的 YOLOv4 实现,然后我们将进行我们的实现。
注意预测有多快多准!
这是 YOLOv4 可以做的第一个令人印象深刻的例子,从不同的游戏和电影场景中检测多个物体。
或者,您可以从现实生活的摄像机视角查看这个物体检测演示。
YOLO 作为 TensorFlow & Keras 中的对象检测器
机器学习中的 TensorFlow 和 Keras 框架
TensorFlow & Keras logos.
Source of the image.
框架在每个信息技术领域都是必不可少的。机器学习也不例外。在 ML 市场上有几个成熟的玩家帮助我们简化整体的编程体验。PyTorch、scikit-learn、TensorFlow、Keras、MXNet 和 Caffe 只是值得一提的几个。
今天,我们将与 TensorFlow/Keras 密切合作。毫不奇怪,这两个是机器学习领域中最受欢迎的框架。这主要是因为 TensorFlow 和 Keras 都提供了丰富的开发能力。这两个框架非常相似。无需深究细节,需要记住的关键事情是 Keras 只是 TensorFlow 框架的一个包装器。
TensorFlow & Keras 中的 YOLO 实现
在撰写本文时,有 808 个存储库在 TensorFlow / Keras 后端实现了 YOLO。YOLO 版本 4 是我们将要实现的。将搜索限制在 YOLO v4,我得到了 55 个存储库。
仔细浏览所有这些,我发现是一个有趣的候选人继续下去。
Repo with the YOLO implementation that we’re going to work with.
Source of the image.
这个实现是由 taipingeric 和 jimmyaspire 开发的。如果你以前使用过 TensorFlow 和 Keras,这非常简单和直观。
要开始使用这个实现,只需将 repo 克隆到您的本地机器上。接下来,我将向您展示如何使用 YOLO 开箱即用,以及如何训练您自己的自定义对象检测器。
如何开箱即用地运行预先培训的 YOLO 并获得结果
查看回购的“快速启动”部分,您可以看到,要启动并运行一个模型,我们只需导入 YOLO 作为一个类对象,并加载模型权重:
from models import Yolov4
model = Yolov4(weight_path='yolov4.weights',
class_name_path='class_names/coco_classes.txt')
请注意,您需要提前手动下载模型权重。YOLO 附带的模型权重文件来自 COCO 数据集,可以在 GitHub 的 AlexeyAB 官方 darknet 项目页面获得。
紧接着,模型完全准备好在推理模式下处理图像。只需对您选择的图像使用 predict()方法。该方法是 TensorFlow 和 Keras 框架的标准。
pred = model.predict('input.jpg')
例如,对于此输入图像:
我得到了以下模型输出:
Prediction made by pre-trained YOLOv4
模型做出的预测以熊猫数据框的形式方便地返回。我们得到每个检测到的对象的类名、盒子大小和坐标:
DataFrame returned as a result of prediction.
Lots of useful information about the detected objects
predict()方法中有多个参数,让我们指定是否要用预测的边界框、每个对象的文本名称等来绘制图像。查看 predict()方法附带的 docstring,以熟悉我们可以使用的内容:
Parameters available within the predict method
您应该预料到您的模型将只能检测严格限于 COCO 数据集的对象类型。要了解预训练的 YOLO 模型能够检测哪些对象类型,请查看…/yolo-v4-tf.kers/class_names/中的 coco_classes.txt 文件。那里有 80 种对象类型。
如何训练您的自定义 YOLO 对象检测模型
任务陈述
要设计一个对象检测模型,你需要知道你想要检测什么对象类型。这应该是您想要为其创建检测器的有限数量的对象类型。当我们转移到实际的模型开发时,准备一个对象类型的列表是很好的。
理想情况下,您还应该有一个包含您感兴趣的对象的带注释的数据集。该数据集将用于训练检测器并对其进行验证。如果您还没有数据集或注释,不要担心,我将向您展示在哪里以及如何获得它。
数据集和注释
从哪里获取数据
如果你有一个带注释的数据集,跳过这一部分,进入下一章。但是,如果您的项目需要数据集,我们现在将探索您可以获取数据的在线资源。
你在哪个领域工作并不重要,很有可能已经有一个开源数据集可以用于你的项目。
我推荐的第一个资源是由 Abhishek Annamraju 撰写的“来自不同行业领域的 50 多个对象检测数据集”文章,他收集了时尚、零售、体育、医药等行业的精彩注释数据集。
Example of an annotated dataset for the driving car systems.
Source of the image.
另外两个寻找数据的好地方是paperswithcode.com和roboflow.com,这两个地方提供高质量的对象检测数据集。
查看以上资产,收集您需要的数据或丰富您已经拥有的数据集。
如何为 YOLO 标注数据
如果您的图像数据集不带注释,您必须自己完成注释工作。这个手动操作是相当耗时的,一定要保证自己有足够的时间去做。
作为一个注释工具,你可以考虑多个选项。我个人会推荐使用LabelImg。这是一个轻量级和易于使用的图像注释工具,可以直接输出 YOLO 模型的注释。
Annotation work in LabeIIimg shown.
Source of the image.
如何将数据从其他格式转换到 YOLO
YOLO 的注释是 txt 文件的形式。YOLO 的 txt 文件中的每一行必须具有以下格式:
image1.jpg 10,15,345,284,0
image2.jpg 100,94,613,814,0 31,420,220,540,1
我们可以分解 txt 文件中的每一行,看看它由什么组成:
-
一行的第一部分指定了图像的基名:image1.jpg,【image2.jpg】T2
-
线的第二部分定义边界框坐标和类标签。例如, 10,15,345,284,0 表示 xmin,ymin,xmax,ymax,class_id
-
如果一个给定的图像上有多个对象,那么在图像基本名称旁边会有多个框和类标签,用空格分隔。
边界框坐标是一个清晰的概念,但是指定类标签的 class_id 数字呢?每个 class_id 都与另一个 txt 文件中的特定类相链接。例如,预先训练好的 YOLO 带有 coco_classes.txt 文件,看起来像这样:
person
bicycle
car
motorbike
aeroplane
bus
...
类文件中的行数必须与您的检测器将要检测的类数相匹配。编号从零开始,这意味着 classes 文件中第一个类的 class_id 号将为 0。位于类 txt 文件第二行的类的编号为 1。
现在你知道 YOLO 的注释是什么样子了。要继续创建自定义对象检测器,我建议您现在做两件事:
-
创建一个 classes txt 文件,在其中存放您希望检测器检测的类。记住上课顺序很重要。
-
创建带注释的 txt 文件。如果你已经有了注释,但是是 VOC 格式的。XMLs),你可以用这个文件把 XML 转换成 YOLO。
将数据分割成子集
和往常一样,我们希望将数据集分成两个子集:用于训练和验证。这可以简单地做到:
from utils import read_annotation_lines
train_lines, val_lines = read_annotation_lines('../path2annotations/annot.txt', test_size=0.1)
创建数据生成器
当数据被分割时,我们可以进行数据生成器初始化。我们将为每个数据文件准备一个数据生成器。在我们的例子中,我们将有一个用于训练子集和验证子集的生成器。
以下是数据生成器的创建方式:
from utils import DataGenerator
FOLDER_PATH = '../dataset/img'
class_name_path = '../class_names/bccd_classes.txt'
data_gen_train = DataGenerator(train_lines, class_name_path, FOLDER_PATH)
data_gen_val = DataGenerator(val_lines, class_name_path, FOLDER_PATH)
总而言之,下面是数据分割和生成器创建的完整代码:
from utils import read_annotation_lines, DataGenerator
train_lines, val_lines = read_annotation_lines('../path2annotations/annot.txt', test_size=0.1)
FOLDER_PATH = '../dataset/img'
class_name_path = '../class_names/bccd_classes.txt'
data_gen_train = DataGenerator(train_lines, class_name_path, FOLDER_PATH)
data_gen_val = DataGenerator(val_lines, class_name_path, FOLDER_PATH)
模型培训所需的安装和设置
让我们来谈谈创建您自己的对象检测器所必需的先决条件:
-
如果你的计算机有一个支持 CUDA 的 GPU(NVIDIA 制造的 GPU),那么需要一些相关的库来支持基于 GPU 的训练。如果你需要启用 GPU 支持,请查看 NVIDIA 网站上的指南。您的目标是为您的操作系统安装 CUDA 工具包和 cuDNN 的最新版本;
-
你可能想组织一个独立的虚拟环境来工作。此项目需要安装 TensorFlow 2。所有其他的库将在后面介绍;
-
至于我,我在 Jupyter 笔记本开发环境中构建和训练我的 YOLOv4 模型。尽管 Jupyter Notebook 似乎是一个合理的选择,但是如果您愿意,可以考虑在您选择的 IDE 中进行开发。
模特培训
先决条件
到目前为止,您应该已经:
-
数据集的拆分;
-
初始化两个数据生成器;
-
包含类的 txt 文件。
模型对象初始化
要为培训作业做好准备,请初始化 YOLOv4 模型对象。确保使用 None 作为 weight_path 参数的值。在这一步,您还应该提供类 txt 文件的路径。以下是我在项目中使用的初始化代码:
class_name_path = 'path2project_folder/model_data/scans_file.txt'
model = Yolov4(weight_path=None,
class_name_path=class_name_path)
上述模型初始化导致创建具有默认参数集的模型对象。考虑通过将字典作为值传递给 config 模型参数来更改模型的配置。
Model object initialization parameter displayed.
Config 指定 YOLOv4 模型的一组参数。
默认模型配置是一个很好的起点,但是您可能想要尝试其他配置以获得更好的模型质量。
我特别强烈推荐尝试主播和 img_size 。锚点指定将用于捕捉对象的锚点的几何图形。锚点的形状越符合对象的形状,模型的性能就越高。
增加 img_size 在某些情况下也是有用的。请记住,图像越高,模型进行推理的时间就越长。
如果您想使用 Neptune 作为跟踪工具,您还应该初始化一次实验运行,如下所示:
import neptune.new as neptune
run = neptune.init(project='projects/my_project',
api_token=my_token)
定义回调
TensorFlow & Keras 让我们使用回调来监控训练进度、设置检查点和管理训练参数(例如学习率)。
在拟合您的模型之前,定义对您的目的有用的回调。确保指定存储模型检查点和相关日志的路径。以下是我在我的一个项目中是如何做到的:
dir4saving = 'path2checkpoint/checkpoints'
os.makedirs(dir4saving, exist_ok = True)
logdir = 'path4logdir/logs'
os.makedirs(logdir, exist_ok = True)
name4saving = 'epoch_{epoch:02d}-val_loss-{val_loss:.4f}.hdf5'
filepath = os.path.join(dir4saving, name4saving)
rLrCallBack = keras.callbacks.ReduceLROnPlateau(monitor = 'val_loss',
factor = 0.1,
patience = 5,
verbose = 1)
tbCallBack = keras.callbacks.TensorBoard(log_dir = logdir,
histogram_freq = 0,
write_graph = False,
write_images = False)
mcCallBack_loss = keras.callbacks.ModelCheckpoint(filepath,
monitor = 'val_loss',
verbose = 1,
save_best_only = True,
save_weights_only = False,
mode = 'auto',
period = 1)
esCallBack = keras.callbacks.EarlyStopping(monitor = 'val_loss',
mode = 'min',
verbose = 1,
patience = 10)
你可能已经注意到,在上面的回调中,set TensorBoard 被用作跟踪工具。考虑使用海王星作为一个更先进的实验跟踪工具。如果是这样的话,不要忘记初始化另一个回调来支持与 Neptune 的集成:
from neptune.new.integrations.tensorflow_keras import NeptuneCallback
neptune_cbk = NeptuneCallback(run=run, base_namespace='metrics')
拟合模型
要开始训练工作,只需使用 TensorFlow / Keras 中的标准 fit() 方法来拟合模型对象。我是这样开始训练我的模型的:
model.fit(data_gen_train,
initial_epoch=0,
epochs=10000,
val_data_gen=data_gen_val,
callbacks=[rLrCallBack,
tbCallBack,
mcCallBack_loss,
esCallBack,
neptune_cbk]
)
当培训开始时,您会看到一个标准的进度条。
训练过程将在每个时期结束时评估模型。如果您使用一组类似于我在拟合时初始化并传入的回调,那些显示模型在较低损失方面有所改进的检查点将被保存到指定的目录中。
如果没有错误发生并且训练过程顺利进行,则训练作业将会停止,这或者是因为训练时期数结束,或者是因为早期停止回调没有检测到进一步的模型改进并停止整个过程。
在任何情况下,您都应该有多个模型检查点。我们希望从所有可用的选项中选择最好的一个,并使用它进行推理。
推理模式下的定型自定义模型
在推理模式下运行已训练模型类似于开箱即用地运行预训练模型。
您初始化一个模型对象,传递到最佳检查点的路径以及带有类的 txt 文件的路径。下面是我的项目的模型初始化的样子:
from models import Yolov4
model = Yolov4(weight_path='path2checkpoint/checkpoints/epoch_48-val_loss-0.061.hdf5',
class_name_path='path2classes_file/my_yolo_classes.txt')
当模型初始化后,只需对您选择的图像使用 predict()方法来获得预测。概括地说,该模型所做的检测以熊猫数据帧的便利形式返回。我们得到每个检测到的对象的类名、盒子大小和坐标。
结论
您刚刚学习了如何创建一个定制的 YOLOv4 对象检测器。我们已经讨论了端到端的过程,从数据收集、注释和转换开始。你对第四代 YOLO 探测器及其与其他探测器的不同已经有了足够的了解。
现在没有什么能阻止你在 TensorFlow 和 Keras 中训练自己的模型。你知道从哪里得到一个预训练的模型,以及如何开始训练工作。
在我即将发表的文章中,我将向您展示一些有助于提高最终模型质量的最佳实践和生活窍门。和我们在一起!
优化部署和推理模型
原文:https://web.archive.org/web/https://neptune.ai/blog/optimizing-models-for-deployment-and-inference
人工智能和机器学习的发展是迅速的,也是出乎意料的。这些先进的模型描绘了你家后院的梵高风格的画,抓取了你在高中毕业舞会上听到的熟悉曲调的名字,并为你的客户完成了你精心措辞的电子邮件。它们无处不在,各公司都在拼命调整自己的商业模式,以迎合不断增长的需求,挖掘潜在的机会。
诸如此类的重大而仓促的转变往往会导致微小的差距,而这种差距只会在规模扩大后进一步扩大;当部署到大规模场景时,模型缺乏鲁棒性/推理时间慢是在温室环境中使用合成和高度监督数据集进行培训时经常被忽视的主要问题之一。
虽然具有挑战性,但有一些方法几乎可以保证有助于缩小这些训练和推理时间的差距。这篇文章深入探讨了管理和优化部署和推理模型的六种方法。具体来说,我们重点关注神经网络——这是一种最难管理的架构,因为它需要大量的参数和内存。每种方法都附有例子/教程,告诉你如何把它应用到你自己的问题中。
本文假设理解深度学习和神经网络的先决条件,以及使用 PyTorch 等框架实现它们的能力。
知识升华下的记忆管理
记忆一直是深度学习模型的主要缺点。在训练期间,每个要更新的参数必须保留用于反向传播计算的梯度。虽然由于不再需要梯度,该问题在推断过程中略有缓解,但是大量的参数仍然存在,并且如果计算不够强大,在推断过程中仍然可能是一个问题。知识提炼是解决这一问题的直接方法。
从本质上讲,知识提炼的目的是将复杂模型中学习到的知识转移到空间容量小得多的模型中。由于有数百万个参数,神经网络经常表现出过度参数化的现象,这意味着许多中间神经元/权重实际上对最终预测是无用的;这样的问题使得采用具有更少数量的层/每层神经元的网络并且仍然捕获原始网络的大部分成为可能。
一种知识提炼方法,包括教师网络和学生网络。教师网络通常是一个更复杂的模型,使用整个训练数据集进行训练。网络中的大量参数使得收敛相对简单。之后,应用知识转移模块提取教师学到的知识到学生网络中。
如何应用知识转移?
根据要转移的知识类型的不同,知识转移有多种方式。我们介绍两种比较常见的知识及其相应的迁移方法。
- 基于响应的知识:基于响应的知识侧重于网络的最终输出。换句话说,目标是让学生学会输出与教师网络相似的预测。因此,执行这种知识转移的典型方式是通过基于教师和学生的预测计算损失,而不是基于学生和原始事实之间的比较。优化鼓励学生权重更新到与教师相似的空间,实现知识转移的目标。来自老师的这种软概率通常允许学生比实际使用基础真理学得更好。
Example of response-based knowledge | Source: Author
- 基于特征的知识:基于特征的知识强调教师和学生之间中间表征的差异,而不是输出的相似性。因此,传递要素需要在中间表示相似性过程中计算损失,而不是在最终输出中计算。这确保了学生的处理/提取方法也与教师的相似。
Example of feature-based Knowledge | Source: Author
使用模型量化和层融合加速推理
深而宽的体系结构固有地需要大量的矩阵运算。乘法可以在 GPU 的帮助下以并行方式计算,但在模型加载时以及需要同时进行大量推理时,它仍然会相当慢。为此,模型量化是解决这个问题的一个很好的工具。
什么是模型量化?
由 PyTorch 等流行库构建的传统模型通常具有较高的浮点精度,这有助于在训练期间获得尽可能高的精度。量化是以较低位宽度计算和存储参数的技术,以减少推断时间并提高效率。因此,在这种设置下,矩阵计算可以更加紧凑和高效。
PTQ 诉沙特
量化方法大致有两种:
- 1 训练后量化(PTQ),精度下降仅发生在模型训练之后。
- 2 量化感知训练(QAT),其中训练将量化考虑在内。
对于 PTQ,我们可以进一步将其分为 PTQ-动态和 PTQ-静态。PTQ 动态是最容易实现的,因为所有的模型权重被预先量化,并且只有激活在推理过程中被动态量化。如果在模型推理过程中加载权重比矩阵乘法本身要花费大量时间,那么 PTQ 动态法就是一个不错的选择。PTQ 静态,另一方面,使用一个代表性的数据集来寻找最佳的方法来量化权重和激活。
PTD-Q 实施
model_fp32 = M()
model_int8 = torch.quantization.quantize_dynamic(
model_fp32,
{torch.nn.Linear},
dtype=torch.qint8)
通过上面这个简单的方法,你可以在训练后直接创建一个量化的模型。为了展示量化的能力,我们可以用下面的代码来测量之前和之后的模型大小。
def print_size_of_model(model, label=""):
torch.save(model.state_dict(), "m.p")
size=os.path.getsize("m.p")
print("model: ",label,' \t','Size (KB):', size/1e3)
os.remove('temp.p')
return size
f=print_size_of_model(model_fp32,"fp32")
q=print_size_of_model(model_int8,"int8")
print("The model is {0:.2f} times smaller".format(f/q))
例如,1024 个输入和 256 个输出声道的线性层在量化后将比小 3.97 倍。你可以通过测量随机 torch 张量需要多长时间来推断时间,你也会看到量子化的显著改善。
欲了解更多信息,请访问 Pytorch 文档。
量化的权衡
简而言之,PTQ(尤其是 PTQ 动态)更容易用当前的库来实现,因为您可以以完美的精度正常地训练模型,然后选择在之后进行量化。缺点也是显而易见的:随着 PTQs 的增加,模型的精度可能会降低,因为随着顺序的矩阵乘法,网络变得相当不准确。
qat 在一定程度上改善了前述的准确性问题,但在训练中直接应用量化更具挑战性,并且很难确定原始模型的真实潜力。假设计算是允许的,并且硬件相当先进,建议暂停量化,直到您了解模型的全部潜力,然后通过实现折衷对模型应用足够的量化。
层融合
另一种提高模型效率的成熟技术是通过层融合来压缩网络。执行层融合的方法可以有很大的不同,但我们提供了一个简单的示例层融合算法如何工作的概述。
本质上,给定一组神经网络,您可以通过某个距离度量找到层之间的成对相似性。这个距离度量可以简单到两组权重的余弦相似性。然后,选择前 k 个相似层,对于每个层,只需冻结一组权重和权重梯度。如果许多层彼此相似,这将允许模型的效率增加,而不会损害太多的准确性。
检查参考伪算法。
使用 ONNX 库
在决定任何形式的部署之前,优化模型的一个关键步骤是使用 ONNX 库。
ONNX ,开放神经网络交换的简称,是一个开源的生态系统,希望将复杂多样的机器学习库整合在一起。如今,人们可以在各种深度学习框架上编写复杂的网络——最著名的是 Tensorflow 和 PyTorch 。虽然它们在语法上很相似,但实际上却大相径庭,不能互换。
ONNX 是一个增加互操作性的库——来自不同库的每个模型都可以转换为 ONNX 格式,这可以很容易地针对不同的硬件进行优化。根据不同的部署目标(例如 CPU、GPU),ONNX 可以相应地帮助优化它。
当你的机器学习模型是从一个公司内的多个团队开发出来的时候,这一点特别有帮助。每个团队可以根据他们自己的偏好试验模型和库,并且仍然可以无缝地将模型组合在一起,最终用于生产。
欲了解更多信息,请查看关于 ONNX 图书馆的优势的文章。
确定部署模式
在完成了前面几点之后,现在是时候在实际用例的压力下对您的模型进行测试了。这一步相当棘手,因为模型的不同用例可能需要不同类型的部署。我们列出了几种常见的部署模式及其主要区别。
单样本推理部署
也许机器学习模型最常见的用例是将它作为服务(通过 API 或 direct UI)为客户端请求打开,一次一个样本(例如,使用 Google API 对特定图像执行图像分割)。在这种情况下,需要对单个样本进行推断以进行实时响应。因此,如果模型仅在客户端请求时初始化,模型将导致运行时间变慢,过多的模型共存,并超出机器的内存容量。
避免这种情况的标准方法是将模型部署为 web 服务,并将其配置为持续待机模式。像 Flask 这样的库允许这样的部署,可以很容易地集成到 PyTorch 管道中。简而言之,您应该在 web 服务器上预先加载现有的模型和权重,以便从客户端接收到的任何请求都被发送到已经加载的模型进行推理。
*请注意,在大量请求和大量数据传输的情况下,此管道仍然可能遇到瓶颈。因此,在设计 Flask 或其他基于服务器的模型时,有两个主要细节需要考虑:
- 避免向服务器端发送不必要的数据。以图像识别为例:如果模型接受的图像大小为(224,224),则在终端机器上执行图像预处理比以全分辨率发送图像更可行。对于检测等任务,将预测作为边界框坐标发送,而不是直接发回图像。
- 同时打开多个模型。这将避免交通高峰期的拥挤。然而,根据公司的计算能力,太多的模型同时驻留在 GPU 中也可能导致总体推理时间变慢和内存错误。
批量部署
另一方面,如果客户端需要同时分析批量数据,更可行的替代方法是部署模型,使其在处理之前接受批量数据。例如,一家制造公司在生产线上执行异常检测。成批的产品图像可以同时用于预测,因此顺序推断每个图像实际上会减慢时间线。
今天,神经网络体系结构被设计成能够同时接受成批的输入,以加速矩阵乘法过程。因此,您的网络应该接受多个数据条目,并在将它们输入网络之前成批收集它们。像 Flask 这样的 Web 服务部署仍然是可行的,但是当从潜在的多个客户端收集条目时,应该暂停模型。
将模型部署到边缘设备上
与基于网络服务的模型相反,在基于网络服务的模型中,客户端必须将数据传输到中央服务器以获得反馈,在边缘设备(例如,个人移动电话)上部署相同的模型也是一种可能的替代方案。这种部署方法将允许推断时间更快,特别是对于大量数据(传输瓶颈)。然而,精确的模型,尤其是基于深度学习的模型,通常需要非常繁重的计算,而手机或其他边缘设备无法执行。对于这种部署模式,必须牺牲更多的精华/更轻的架构,甚至牺牲精度。
优化模型中的模型修剪
另一个需要考虑的重要步骤是模型修剪,这将极大地提高模型投入生产时的效率。
网络剪枝实质上是在网络权重上覆盖二进制掩码,以便使用较少的权重进行预测。根据修剪方法的不同,屏蔽的具体方式会有所不同,但最常见的方式是简单地修剪具有最小幅度(即,对结果的影响最小)的权重。修剪会导致以下影响:
- 1 减少延迟和推理成本
- 2 增加内存空间,降低功耗。
PyTorch 中的修剪
对于 PyTorch 之类的库,修剪可以非常简单,例如:
import torch.nn.utils.prune as prune
现在,给定一个模型,您可以简单地调用任何您想要的修剪函数,例如:
prune.random_unstructured(module, name="weight", amount=0.3)
Tensorflow 中的修剪
如果你是 Tensorflow 而不是 PyTorch 的粉丝,还有一个为你指定的优化库,称为 TensorFlow 优化工具包。该工具包介绍了一种减少网络权重和增加网络负载的重要方法——剪枝。
更多详情请参考张量流模型优化。
用于模型优化的在线深度学习
数据特征经常随着时间而变化:时间序列数据的分析不再适用于黑天鹅事件;一个物体的照片随着更好的照相机而发展。因此,优化模型以进行部署的主要工作是在通过不断的监控和改进部署模型之后开始的。
虽然通过合并新收集的数据进行简单的重新训练解决了这个问题,但是从头开始重新训练的计算最终是昂贵的,并且通常是耗时的(在 ImageNet-22k 上训练模型可能需要几天,即使使用高级 GPU 也是如此)。本节介绍了从头再培训的替代方案:在线深度学习。
什么是在线深度学习?
传统的深度学习是通过优化方法来执行的,例如对整个数据集进行随机梯度下降。在线深度学习旨在解决只有新来的数据可用的限制,并对当前训练的模型执行在线梯度下降(OGD ),以适应学习的新特征。在 OGD 的前提下,还引入了其他方法,如对冲反向传播,以通过确定模型的适当深度来进一步改进在线深度学习方法。
数据隐私问题
然而,使用新检索的数据仍然会导致隐私问题。您的服务的客户可能不希望他们的数据被发送回中央服务器以进行进一步的模型优化。为此,引入了学习算法的一个分支,即联邦学习。
联合学习旨在在边缘设备(或客户端)上执行训练,并使用该训练来更新中心模型。一种常见的方法如下所示:
Model optimization | Source: Author
Federated learning aims to perform the training on the edge devices (or customer end) and use that to update the central model. A common approach is illustrated as the following:
1 中央服务器端模型将模型复制到边缘设备。
- 2 边缘设备模型使用在线学习算法和给定数据进行优化。
- 3 模型被发送回服务器以优化中央模型。
- 3 The models are sent back to the server to optimise the central model.
关于如何执行这种联合学习算法,存在多种变体,但是总而言之,它们防止了机密数据的传输,并且仍然相应地改进了中央模型。
尾注
本文作为一个端到端的指南,帮助您将机器学习模型连接到部署和推理的最佳状态。我们首先通过引入知识提炼和量化来提高网络的内存和速度容量,以及 ONNX 来优化网络以适应不同的硬件。
之后,我们介绍了要考虑的不同部署模式,并简要介绍了 Tensorflow 的修剪功能。最后,我们介绍了将模型投入生产时的错误检测方法,以及在线学习和联合学习机制,以继续优化您的模型,使其尽可能达到最佳性能。每个场景都是不同的,但希望这篇文章可以使优化深度学习模型以进行部署的艰巨过程稍微顺利一些。
参考
https://neptune.ai/blog/must-do-error-analysis
- https://www.tensorflow.org/model_optimization
- https://pytorch.org/docs/stable/quantization.html
- https://py torch . org/tutorials/intermediate/flask _ rest _ API _ tutorial . html
- https://medium . com/true face-ai/two-benefits-of-the-onnx-library-for-ml-models-4 B3 e 417 df 52e
- https://medium.com/trueface-ai/two-benefits-of-the-onnx-library-for-ml-models-4b3e417df52e*
Optuna 指南:如何监控超参数优化运行
超参数搜索几乎是每个机器学习和深度学习项目的一部分。当您选择一个候选模型时,您要确保它以最好的方式概括您的测试数据。
如果是线性回归这样的简单模型,手动选择最佳超参数很容易。对于像神经网络这样的复杂模型,手工调整是很困难的。
例如,如果我们训练一个只有线性层的神经网络,下面是一组潜在的超参数:
- 层数
- 每层单位
- 正则化强度
- 激活功能
- 学习率
- 优化器参数(2-3 个变量)
- 丢失保持概率
即使这 8 个变量中的每一个都有 2 个候选值,你最终会得到 2^8 = 256 个实验。对于更大的网络和更多的候选值,这个数字变得难以承受。
在本文中,我们将探索如何使用流行的框架 Optuna 为复杂模型设置超参数。
如何进行超参数选择
我们需要考虑寻找最佳超参数值的有效策略。
一种简单的超参数搜索方法是网格搜索,如上例所示:我们为每个超参数手动设置候选值,并对每个超参数值组合进行模型训练和评估。
对于具有 m1,m2,…,mk 个候选值的 k 个超参数,
实验次数= m1m2 … mk*
这种方法的主要缺点是:
- 资源密集型——执行大量实验将需要大量计算资源。
- 非最优–即使该策略穷尽了所有可能的组合,候选值也是由我们设定的。最佳值可能完全不在此候选池中。
- 耗时——在深度学习中,一个实验需要几个小时才能完成,这种策略效率不高。
另一种传统方法是随机搜索。在这里,您在一个定义的值范围内随机选择一个变量。这种方法比网格搜索更具探索性,限制更少,而且与网格搜索相比,您还可以测试更大范围的候选值。
这些方法都不能满足我们收敛到最佳超参数值集的需要。我们需要更有效的算法,以更少的试验来估计最佳超参数。
一些算法使用贝叶斯优化来实现这一点。这个想法是对搜索过程进行概率建模。该模型使用通过使用某些超参数组合集获得的度量值来选择下一个组合,使得度量的改进最大化。
在 Python 中有许多框架可以用来实现这些算法——HyperOpt、Scikit-Optimize、Optuna 等等。
我们将重点讨论 Optuna——可以说是所有选项中最简单的一个。
Optuna 的最佳功能
由运行定义范例
据 Optuna 的作者称,Optuna 的三个特征使其脱颖而出(来源:论文)
- 通过运行定义程序,允许用户动态构建搜索空间。
- 高效的采样算法和剪枝算法,允许一些用户定制。
- 易于设置的多功能架构,可部署用于各种类型的任务。
Optuna 很容易安装。考虑论文中描述的情况:
import optuna
import ...
def objective (trial):
n layers = trial. suggest int (’n layers ’, 1, 4)
layers = []
for i in range( n layers ):
layers.append(trial. suggest int (’n units l {} ’.
format(i), 1, 128))
clf = MLPClassifier (tuple(layers))
mnist = fetch mldata (’MNIST original’)
x train , x test , y train , y test = train test split (
mnist.data , mnist.target)
clf.fit( x train , y train )
return 1.0 − clf.score( x test , y test )
study = optuna. create study ()
study.optimize(objective , n trials =100)
目的是通过优化隐层和每层中单元的数量来搜索最佳的神经网络结构。我们定义一个函数,在本例中是 目标 ,它接受一个名为 的对象进行试验 。
这个 试验 对象用于在目标函数内部构建一个模型。在这种情况下,我们使用 trial 的 suggest_int 方法选择层数和每层中的单元数。此方法选择 1 到 4 之间的一个值。有许多类型的 suggest_ 方法可用,涵盖不同的场景。 试验 对象负责建议提供最佳结果的超参数值。
目标函数返回需要最小化或最大化的单个数字——准确度、损失、f1 分数。然后,创建一个研究对象,并传递两个参数——目标函数和希望研究持续的实验次数。就是这样。
请注意,我们根本没有预定义模型架构。它是完全动态构建的。在另一个称为 远视 的框架中考虑同样的任务:
import hyperopt
import ...
space = {
’n_units_l1 ’: hp.randint(’n_units_l1 ’, 128) ,
’l2’: hp.choice(’l2’, [{
’has_l2 ’: True ,
’n_units_l2 ’: hp.randint(’n_units_l2 ’, 128) ,
’l3’: hp.choice(’l3’, [{
’has_l3 ’: True ,
’n_units_l3 ’: hp.randint(’n_units_l3 ’, 128) ,
’l4’: hp.choice(’l4’, [{
’has_l4 ’: True ,
’n_units_l4 ’: hp.randint(’n_units_l4 ’, 128) ,
}, {’has_l4 ’: False }]) ,
}, {’has_l3 ’: False }]) ,
}, {’has_l2 ’: False }]) ,
}
def objective (space):
layers = [space[’n_units_l1 ’] + 1]
for i in range(2, 5):
space = space[’l{} ’.format(i)]
if not space[’has_l {} ’.format(i)]:
break
layers.append(space[’n_units_l {} ’.format(i)] +
1)
clf = MLPClassifier (tuple(layers))
mnist = fetch mldata (’MNIST original’)
x_train , x_ test , y_train , y_test = train test split (mnist.data , mnist.target)
clf.fit(x_train , y_train)
return 1.0 − clf.score(x_test , y_test )
hyperopt.fmin(fn=objective , space=space , max_evals =100 ,
algo=hyperopt .tpe.suggest)
一开始,你看到一个叫做 空间 的大嵌套字典。用英语来说应该是这样的:
决定是否包含第一层。如果是,建议隐藏单元的数量。决定是否包含第二层。如果是,建议隐藏单元的数量。决定第三个…
不是很有活力。这不像 Optuna 的运行定义特性,我们在运行中定义模型。Hyoperopt 更明确和运行。
高效采样
树 Parzen 估计器(TPE)
默认情况下,Optuna 使用一种称为 Tree-Parzen estimator 的技术,根据实验历史选择下一步要尝试的超参数集。考虑一个简单的例子,其中历史包括 100 次试验,列表如下:
我们将该表的行分成 2 部分,一部分损失< 0.03(好结果表),其余部分(不太好结果表)。在我们用 X 轴作为参数值,Y 轴作为损耗来绘制这两个分布的函数之后,我们得到这样的图(为了便于解释而过度简化):
上面的图是使用好的结果(带有损失< 0.03). We call it g(x) 构建的,其中 x 是参数值。下图显示了不太好的结果。我们称之为 l(x)。
对于一个新的实验,这个超参数的一个新值是使用:
协方差矩阵自适应进化策略(CMA-ES)
Optuna 还提供了另一种采样策略,CMA-ES。它通过更新超参数的均值和方差来动态构建搜索空间。
对于 k 超参数,在 N 次实验之后,我们使用最好的,比如说,25%的实验(这里的最好是根据感兴趣的度量——精确度,f1 来决定的)。我们计算了这些超参数联合分布的均值和协方差矩阵。
这里的一个巧妙之处是,在估计协方差矩阵时,使用上一代(一组试验)的平均值,而不是使用以前的试验为这一代估计的平均值。像这样:
计算下一代(g+1)的均值。来源:Otoro.net
正如您在上面的等式中看到的,下一代( g+1 )的方差和协方差值是使用当前一代 g 的平均值来估计的。
一旦我们有了这个更新的分布,我们就可以通过从这个超参数值的分布中取样来进行实验。查看这篇文章了解更多详情。
修剪
Optuna 通过修剪节省您的时间。简单地说,如果一个实验基于损失或验证度量的中间值看起来没有希望,那么这个实验就被中止。
Optuna 使用之前实验的信息来做出决定。它问在这个时期中间损失的值是多少,在同一阶段以前的实验的损失是多少。
例如,中位数普鲁纳将特定步骤的当前实验与同一步骤的先前实验进行比较。如果表现好于之前实验的中间值,试验将继续,如果不是,试验将中止。
在代码中使用 Optuna(案例研究)
代码
让我们深入研究代码。我们将使用来自 sklearn.datasets 的数字数据集。它有 8*8 大小的图像存储为一维数组。有 10 个标签。
导入相关包
打开一个 jupyter 笔记本,导入这些包和函数。确保在 python 环境中安装这些包。
import sklearn
from sklearn import datasets
from sklearn.model_selection import train_test_split
import numpy as np
import optuna
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
from collections import Counter
import time
加载数据
如上所述,我们加载数字数据集。Sklearn 会自动给你下载。我们将数据分成训练集和验证集。
data = datasets.load_digits()
X = data.data
y = data.target
X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, shuffle=True)
print("Train data shape: ", X_train.shape)
print("Validation data shape: ", X_val.shape)
输出:
Train data shape: (1437, 64)
Validation data shape: (360, 64)
检查标签:
Counter(y_train)
输出:
Counter({6: 142,
4: 147,
7: 143,
8: 141,
1: 151,
3: 147,
9: 145,
2: 142,
0: 134,
5: 145})
我们选择准确性作为感兴趣的衡量标准,因为不存在等级不平衡:
def model_performance(model, X=X_val, y=y_val):
"""
Get accuracy score on validation/test data from a trained model
"""
y_pred = model.predict(X)
return round(accuracy_score(y_pred, y),3)
model_performance 只是我们前面使用的一个辅助函数。
在进行任何超参数搜索之前,让我们考虑一个简单的决策树,看看它在未调优时的性能。
model = DecisionTreeClassifier()
model.fit(X_train, y_train)
print("Validation accuracy: ", model_performance(model))
输出:
Validation accuracy: 0.861
我们将记住这个分数,以了解我们通过使用 Optuna 获得了多少改进。
创建超参数优化过程
我们最终开始创建我们的目标函数并研究:
def create_model(trial):
model_type = trial.suggest_categorical('model_type', ['logistic-regression', 'decision-tree', 'svm'])
if model_type == 'svm':
kernel = trial.suggest_categorical('kernel', ['linear', 'poly', 'rbf', 'sigmoid'])
regularization = trial.suggest_uniform('svm-regularization', 0.01, 10)
degree = trial.suggest_discrete_uniform('degree', 1, 5, 1)
model = SVC(kernel=kernel, C=regularization, degree=degree)
if model_type == 'logistic-regression':
penalty = trial.suggest_categorical('penalty', ['l2', 'l1'])
if penalty == 'l1':
solver = 'saga'
else:
solver = 'lbfgs'
regularization = trial.suggest_uniform('logistic-regularization', 0.01, 10)
model = LogisticRegression(penalty=penalty, C=regularization, solver=solver)
if model_type == 'decision-tree':
max_depth = trial.suggest_int('max_depth', 5, X_train.shape[1])
min_samples_split = trial.suggest_int('min_samples_split', 2, 20)
min_samples_leaf = trial.suggest_int('min_samples_leaf', 2, 20)
model = DecisionTreeClassifier(
max_depth=max_depth, min_samples_split=min_samples_split, min_samples_leaf=min_samples_leaf
)
if trial.should_prune():
raise optuna.TrialPruned()
return model
def objective(trial):
model = create_model(trial)
model.fit(X_train, y_train)
return model_performance(model)
create_model 是一个助手函数,它接受一个试验对象并返回一个模型。我们在搜索领域使用了三种不同的模型——逻辑回归、决策树和 SVM。试用对象使用建议分类方法从这三个中选择一个。根据模型的类型,进一步选择超参数。
在目标函数中,我们使用 create_model 来生成一个模型,并将其拟合到我们的训练数据上。我们返回模型精度:
study = optuna.create_study(direction='maximize', study_name="starter-experiment", storage='sqlite:///starter.db')
此时,我很快在 neptune.ai 上创建了一个名为 blog-optuna 的项目,继续使用代码,您可以在笔记本上创建一个关于 neptune 的实验。我的实验名称是 optuna guide 。请注意,使用 neptune 运行 optuna 研究并不是必需的。如果您希望稍后尝试 neptune,只需注释前面代码中提到的代码行。
在 neptune.ai 上注册即可获得 neptune API 令牌(只需一分钟)。
- 导入 neptune 并创建跑步记录
import neptune.new as neptune
run = neptune.init(
project=”<YOUR_PROJECT_NAME>”
api_token = "<YOUR_API TOKEN>"
)
- 导入并初始化 NeptuneCallback
import neptune.new.integrations.optuna as optuna_utils
neptune_callback = optuna_utils.NeptuneCallback(run)
使用 Neptune-Optuna 集成,Neptune 将自动记录所有有价值的信息,并为我们创建可视化效果。
study = optuna.create_study(direction='maximize', study_name="starter-experiment", storage='sqlite:///starter.db')
因为我们想要最大化目标函数的返回值,方向参数被设置为最大化。我们可以使用 study_name 参数为我们的研究命名。
如果我们希望将实验存储在 sql-lite 数据库中,我们可以将存储参数值设置为类似于“sqlite:/// <path to="" your="" .db="" file="">”的值。
最后,我们可以将 neptune_callback 传递给 study.optimize() callbacks 参数,并开始超参数优化过程。我已经设置了 300 次试验。
study.optimize(objective, n_trials=300, callbacks=[neptune_callback])
输出:
[I 2020-12-12 16:06:18,599] A new study created in RDB with name: starter-experiment
[I 2020-12-12 16:06:18,699] Trial 0 finished with value: 0.828 and parameters: {'model_type': 'decision-tree', 'max_depth': 12, 'min_samples_split': 16, 'min_samples_leaf': 19}. Best is trial 0 with value: 0.828.
[I 2020-12-12 16:06:20,161] Trial 1 finished with value: 0.983 and parameters: {'model_type': 'svm', 'kernel': 'rbf', 'svm-regularization': 6.744450268290869, 'degree': 5.0}. Best is trial 1 with value: 0.983.
[I 2020-12-12 16:06:20,333] Trial 2 finished with value: 0.964 and parameters: {'model_type': 'logistic-regression', 'penalty': 'l2', 'logistic-regularization': 7.0357613534815595}. Best is trial 1 with value: 0.983.
[I 2020-12-12 16:06:20,437] Trial 3 finished with value: 0.983 and parameters: {'model_type': 'svm', 'kernel': 'poly', 'svm-regularization': 9.24945497106145, 'degree': 3.0}. Best is trial 1 with value: 0.983.
.
.
.
最后,为了获得最佳模型:
best_model = create_model(study.best_trial)
best_model.fit(X_train, y_train)
print("Performance: ", model_performance(best_model))
输出:
Performance: 0.989
用海王星来观察这个过程
我们用一行代码集成了 Neptune 和 Optuna。让我们看看我们生成了什么。要获得这些图,请在 neptune.ai 上进行实验,并在工件选项卡下下载图表。如果你没有在你的代码中使用 neptune,请随意浏览我的项目这里。
Link to the charts – here
上面的图显示了我们的目标度量在 300 次试验中的进展。我们看到在最初的 120 次试验中达到了最佳值。
在下面的切片图中,我们可以看到各个参数的哪些值有助于实现最佳性能:
Link to the charts – here
还有一些——等高线图和平行坐标。这些可视化使得搜索过程不再是一个黑箱。
即使您必须运行新的研究,了解这些图表也有助于您确定哪些超参数对感兴趣的指标不重要,以及为了更好、更快地收敛,应该考虑哪些值的范围。
高级选项
为了使您的项目工作更简单,您可以使用 Optuna 提供的这些高级配置:
- 使用 RDB 后端恢复研究–如果您创建了一个具有某个名称和某个数据库后端的研究,您可以在任何时间点恢复它。例子(链接):
import optuna
study_name = 'example-study'
study = optuna.create_study(study_name=study_name, storage='sqlite:///example.db')
要加载该研究:
study = optuna.create_study(study_name='example-study', storage='sqlite:///example.db', load_if_exists=True)
study.optimize(objective, n_trials=3)
- 分布式优化【T1—对于大规模实验,分布式优化可以让你的收敛时间减少几个数量级。最重要的是,使用它非常简单。当您使用终端运行脚本时(如下所示)😗***
$ python foo.py
只需打开另一个终端,并在这个新窗口中运行脚本。这两个流程共享试验历史记录。创建病历报告时,确保您使用的是 sqlite 存储器。(参考
- 使用 CLI 的 Optuna-使用 Optuna 中的 CLI 选项,您可以避免大量的 boiler-plate 代码。考虑这个例子(链接):
您的 python 脚本应该定义一个目标函数。
def objective(trial):
x = trial.suggest_uniform('x', -10, 10)
return (x - 2) ** 2
在您的 CLI 中:
$ STUDY_NAME=`optuna create-study --storage sqlite:///example.db`
$ optuna study optimize foo.py objective --n-trials=100 --storage sqlite:///example.db --study-name $STUDY_NAME
就是这样。
- 多目标研究–在我们的示例中,目标函数返回一个数字,我们选择将其最小化或最大化。然而,我们也可以返回多个值。我们只需要为它们中的每一个指定方向。考虑下面的例子(链接):
import optuna
def objective(trial):
x = trial.suggest_float("x", 0, 5)
y = trial.suggest_float("y", 0, 3)
v0 = 4 * x ** 2 + 4 * y ** 2
v1 = (x - 5) ** 2 + (y - 5) ** 2
return v0, v1
study = optuna.multi_objective.create_study(["minimize", "minimize"])
study.optimize(objective, n_trials=3)
如您所见,我们返回两个值,而不是 optuna.create_study,而是使用 optuna . multi _ objective . create _ study。此外,方向是一个字符串列表,而不仅仅是一个字符串。
结论和结束语
数据科学项目有许多活动的部分。它们会很快变得很乱。
您可以通过使用干净的方法选择最佳的模型超参数来减少这种混乱。
对于大多数类型的 ML/DL 建模,Optuna 是最简单的框架之一。将它与 Neptune 集成,您可以跟踪所有的扫描和可视化,并轻松地将您的结果传达给您的团队。
试试看你是否喜欢它,我知道我肯定会使用 Optuna 一段时间。**
Optuna vs Hyperopt:应该选择哪个超参数优化库?
原文:https://web.archive.org/web/https://neptune.ai/blog/optuna-vs-hyperopt
思考应该选择哪个库进行超参数优化?
使用远视有一段时间了,想改变一下吗?
刚刚听说了 Optuna,你想看看它是如何工作的吗?
很好!
在本文中,我将:
- 向您展示一个在实际问题中使用 Optuna 和 Hyperopt 的示例,
- 在 API、文档、功能等方面比较 Optuna 和 Hyperopt,
- 给你我的综合评分和你应该使用哪个超参数优化库的建议。
让我们开始吧。
评定标准
易用性和 API
在这一节中,我想看看如何为这两个库运行一个基本的超参数调优脚本,看看它有多自然和易用,以及什么是 API。
optina
您在一个函数中定义了您的搜索空间和目标。
此外,您从试验对象中抽取超参数。因此,参数空间是在执行时定义的。对于那些因为这种命令式方法而喜欢 Pytorch 的人来说, Optuna 会感觉很自然。
def objective(trial):
params = {'learning_rate': trial.suggest_loguniform('learning_rate', 0.01, 0.5),
'max_depth': trial.suggest_int('max_depth', 1, 30),
'num_leaves': trial.suggest_int('num_leaves', 2, 100),
'min_data_in_leaf': trial.suggest_int('min_data_in_leaf', 10, 1000),
'feature_fraction': trial.suggest_uniform('feature_fraction', 0.1, 1.0),
'subsample': trial.suggest_uniform('subsample', 0.1, 1.0)}
return train_evaluate(params)
然后,创建研究对象并对其进行优化。最棒的是你可以选择是否要最大化或最小化你的目标。这在优化 AUC 等指标时非常有用,因为您不必在训练前改变目标的符号,然后在训练后转换最佳结果以获得正分数。
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=100)
就是这样。
您可能想知道的关于优化的一切都可以在研究对象中找到。
我喜欢 Optuna 的一点是,我可以定义如何动态地对我的搜索空间进行采样,这给了我很大的灵活性。选择优化方向的能力也很不错。
如果你想看完整的代码示例,你可以向下滚动到示例脚本。
10 / 10
远视
首先定义参数搜索空间:
SPACE = {'learning_rate':
hp.loguniform('learning_rate',np.log(0.01),np.log(0.5)),
'max_depth':
hp.choice('max_depth', range(1, 30, 1)),
'num_leaves':
hp.choice('num_leaves', range(2, 100, 1)),
'subsample':
hp.uniform('subsample', 0.1, 1.0)}
然后,创建一个想要最小化的目标函数。这意味着你将不得不翻转你的目标的符号,以获得更高更好的指标,如 AUC。
def objective(params):
return -1.0 * train_evaluate(params)
最后,实例化 Trials() 对象,并在参数搜索空间最小化目标。
trials = Trials()
_ = fmin(objective, SPACE, trials=trials, algo=tpe.suggest, max_evals=100)
…完成了!
关于被测试的超参数和相应分数的所有信息都保存在试验对象中。
我不喜欢的是,即使在最简单的情况下,我也需要实例化 Trials() 。我宁愿让 fmin 返回试用版并默认进行实例化。
9 / 10
这两个库在这里都做得很好,但是我觉得 Optuna 稍微好一点,因为它具有灵活性、对采样参数的命令式方法以及较少的样板文件。
易用性和 API
>远视
选项、方法和超级(超级参数)
在现实生活中,运行超参数优化需要远离黄金路径的许多额外选项。我特别感兴趣的领域有:
搜索空间
- 优化方法/算法
- 回收
- 持续和重新开始参数扫描
- 修剪没有希望的运行
- 处理异常
- 在这一节中,我将比较 Optuna 和 Hyperopt。
搜索空间
在本节中,我想比较搜索空间的定义、定义复杂空间的灵活性以及每个参数类型(浮点型、整数型、分类型)的采样选项。
optina
您可以找到所有超参数类型的采样选项:
对于分类参数,您可以使用trials . suggest _ categorial
- 对于整数有 trials.suggest_int
- 对于浮点参数,您有个试验.建议 _ 统一、个试验.建议 _ 统一甚至更奇特的个试验.建议 _ 离散 _ 统一
- 特别是对于整数参数,您可能希望有更多的选项,但它处理的是大多数用例。这个库的最大特点是,你可以从参数空间中动态采样,你可以随心所欲。您可以使用 if 语句,可以更改搜索间隔,可以使用来自 trial 对象的信息来指导您的搜索。
太棒了,你可以做任何事情!
def objective(trial):
classifier_name = trial.suggest_categorical('classifier', ['SVC', 'RandomForest'])
if classifier_name == 'SVC':
svc_c = trial.suggest_loguniform('svc_c', 1e-10, 1e10)
classifier_obj = sklearn.svm.SVC(C=svc_c)
else:
rf_max_depth = int(trial.suggest_loguniform('rf_max_depth', 2, 32))
classifier_obj = sklearn.ensemble.RandomForestClassifier(max_depth=rf_max_depth)
...
10 / 10
远视
搜索空间是 Hyperopt 真正为您提供大量采样选项的地方:
对于分类参数,您有 hp.choice
- 对于整数,你得到 hp.randit , hp.quniform , hp.qloguniform 和 hp.qlognormal
- 对于浮动,我们有 hp.normal , hp.uniform , hp.lognormal 和 hp.loguniform
- 据我所知,这是目前最广泛的采样功能。
您可以在运行优化之前定义您的搜索空间,但是您可以创建非常复杂的参数空间:
通过将 hp.choice 与其他采样方法相结合,我们可以拥有条件空间。当你在为涉及预处理、特征工程和模型训练的机器学习管道优化超参数时,这是有用的。
SPACE = hp.choice('classifier_type', [
{
'type': 'naive_bayes',
},
{
'type': 'svm',
'C': hp.lognormal('svm_C', 0, 1),
'kernel': hp.choice('svm_kernel', [
{'ktype': 'linear'},
{'ktype': 'RBF', 'width': hp.lognormal('svm_rbf_width', 0, 1)},
]),
},
{
'type': 'dtree',
'criterion': hp.choice('dtree_criterion', ['gini', 'entropy']),
'max_depth': hp.choice('dtree_max_depth',
[None, hp.qlognormal('dtree_max_depth_int', 3, 1, 1)]),
'min_samples_split': hp.qlognormal('dtree_min_samples_split', 2, 1, 1),
},
])
10 / 10
不得不说他们俩我都喜欢。我可以很容易地定义嵌套搜索空间,并且我有很多针对所有参数类型的采样选项。 Optuna 有命令式的参数定义,提供了更多的灵活性,而hyperpt 有更多的参数采样选项。
搜索空间
Optuna =远视
优化方法
Optuna 和 Hyperopt 都使用相同的优化方法。他们有:
rand.suggest 【远视】samplers . random sampler【Optuna】
你对参数的标准随机搜索。
tpe.suggest (远视)和samplers . TPE . sampler . TPE sampler(Optuna)
Parzen 估计树(TPE)。这种方法背后的想法类似于之前关于 Scikit Optimize 的博文中所解释的。我们使用一个便宜的代理模型来估计昂贵的目标函数在一组参数上的性能。
Scikit Optimize 和 Parzen Tree Estimators(TPE)中使用的方法之间的区别在于,我们要估计尾部的密度,而不是估计实际性能(点估计)。我们希望能够判断跑步是好的(右尾)还是坏的(左尾)。
我喜欢 AutoML.org 弗莱堡的的了不起的人们从 AutoML_Book 中摘录的以下解释。
树 Parzen 估计器对密度函数 p(λ|y < α)和 p(λ|y ≥ α)进行建模,而不是对给定配置λ的观测值 y 的概率 p(y|λ)进行建模。给定百分位数α(通常设置为 15%),观察值分为好的观察值和坏的观察值,简单的一维 Parzen 窗口用于模拟这两种分布。
通过使用 p(λ|y < α)和 p(λ|y ≥ α),您可以估计参数配置相对于以前最佳配置的预期改进。
有趣的是,对于 Optuna 和 Hyperopt 来说,在优化器中都没有指定 α 参数的选项。
optina
一体化。
Optuna 允许您使用来自 Scikit-Optimize (skopt)的采样器。
Skopt 提供了许多基于树的方法作为代理模型的选择。
为了使用它们,您需要:
创建一个 SkoptSampler 实例,在 skopt_kwargs 参数中指定代理模型和获取函数的参数,
- 将采样器实例传递给 optuna.create_study 方法
- 梅干。成功 halvingpruner
from optuna.integration import SkoptSampler
sampler = SkoptSampler(skopt_kwargs={'base_estimator':'RF',
'n_random_starts':10,
'base_estimator':'ET',
'acq_func':'EI',
'acq_func_kwargs': {'xi':0.02})
study = optuna.create_study(sampler=sampler)
study.optimize(objective, n_trials=100)
你也可以使用多臂 bandit 方法之一,称为异步连续减半算法(ASHA)。如果你对细节感兴趣,请阅读论文,但大意是:
运行一段时间的参数配置
- 每隔一段时间删除(一半)最没有希望的运行
- 多运行一些参数配置
- 每隔一段时间删除(一半)最没有希望的运行
- 当只剩下一个配置时停止
- 通过这样做,搜索可以集中在更有希望的运行上。然而,配置预算的静态分配在实践中是一个问题(一种叫做 HyperBand 的新方法解决了这个问题)。
在 Optuna 中使用 ASHA 非常容易。只需将一个成功的 HalvingPruner 传递给。create_study() 一切就绪:
简单明了。
from optuna.pruners import SuccessiveHalvingPruner
optuna.create_study(pruner=SuccessiveHalvingPruner())
study.optimize(objective, n_trials=100)
如果你想了解更多,你可以看看我的关于 Scikit Optimize 的文章。
总的来说,现在优化函数有很多选择。然而,有一些重要的,如超级乐队或 BOHB 失踪。
8 / 10
远视
**## 最近添加的自适应 TPE 是由 ElectricBrain 发明的,它实际上是他们在 TPE 基础上实验的一系列(不那么)小的改进。
作者在这篇引人入胜的博文中彻底解释了他们对 TPE 的方法和修改。
超级好用。代替 tpe.suggest 你需要将 atpe.suggest 传递给你的 fmin 函数。
我真的很喜欢这种在库中包含新优化算法的努力,特别是因为这是一种新的原创方法,而不仅仅是与现有算法的集成。
希望在未来的多臂 bandid 方法,如 Hyperband,BOHB,或基于树的方法,如 SMAC3 也将包括在内。
from hyperopt import fmin, atpe
best = fmin(objective, SPACE,
max_evals=100,
algo=atpe.suggest)
8 / 10
优化方法
Optuna =远视** *** * *
复试
在这一节中,我想看看在每次迭代之后定义回调来监控/快照/修改训练有多容易。这是有用的,尤其是当你的训练是长期的和/或分散的。
optina
用户回调在的回调参数下得到了很好的支持。优化()方法。只需传递一个将研究和试验作为输入的可调用列表,您就可以开始了。
因为您可以访问研究和试验,所以您可以灵活地检查、提前停止或修改未来的搜索。
10 / 10
def neptune_monitor(study, trial):
neptune.log_metric('run_score', trial.value)
neptune.log_text('run_parameters', str(trial.params))
...
study.optimize(objective, n_trials=100, callbacks=[neptune_monitor])
远视
本质上没有回调,但是你可以把你的回调函数放在目标中,它将在每次调用目标时被执行。
我不喜欢它,但我想我可以忍受。
2010 年 6 月
def monitor_callback(params, score):
neptune.send_metric('run_score', score)
neptune.send_text('run_parameters', str(params))
def objective(params):
score = -1.0 * train_evaluate(params)
monitor_callback(params, score)
return score
Optuna 让回调参数变得非常简单,而在 Hyperopt 中,你必须修改目标。
回调
>远视
注意:
opt . utils . Neptune _ monitor:记录运行分数和运行参数,并绘制迄今为止的分数
opt_utils.log_study :记录最佳结果、最佳参数和研究对象本身
- 只需将此添加到您的脚本中:
- 持续和重新启动
保存和加载您的超参数搜索可以节省您的时间和金钱,并有助于获得更好的结果。让我们比较一下这两个框架。
import neptune
import neptunecontrib.monitoring.optuna as opt_utils
neptune.init('jakub-czakon/blog-hpo')
neptune.create_experiment(name='optuna sweep')
monitor = opt_utils.NeptuneMonitor()
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=100, callbacks=[monitor])
opt_utils.log_study(study)
optina
简单地使用 joblib.dump 来腌制试验对象。
…您可以稍后使用 joblib.load 加载它以重新开始搜索。
就是这样。
study.optimize(objective, n_trials=100)
joblib.dump(study, 'artifacts/study.pkl')
对于分布式设置,您可以使用研究的名称,以及数据库的 URL,在此您将分布式研究用于实例化新研究。例如:
study = joblib.load('../artifacts/study.pkl')
study.optimize(objective, n_trials=200)
很好很容易。
关于在速度和并行化部分使用 Optuna 运行分布式超参数优化的更多信息。
study = optuna.create_study(
study_name='example-study',
storage='sqlite:///example.db',
load_if_exists=True)
10 / 10
远视
与 Optuna 类似,使用 joblib.dump 来处理试验对象。
…用 joblib.load 加载并重启。
简单和工程没有问题。
trials = Trials()
_ = fmin(objective, SPACE, trials=trials,
algo=tpe.suggest, max_evals=100)
joblib.dump(trials, 'artifacts/hyperopt_trials.pkl')
如果您正在以一种分布式方式优化超参数,您可以加载连接到 MongoDB 的 MongoTrials() 对象。在速度和并行化一节中有更多关于使用 Hyperopt 运行分布式超参数优化的信息。
trials = joblib.load('artifacts/hyperopt_trials.pkl')
_ = fmin(objective, SPACE, trials=trials,
algo=tpe.suggest, max_evals=200)
10 / 10
两者都使工作变得容易并完成。
持续并重启
Optuna =远视
运行修剪
并非所有的超参数配置都是相同的。对于他们中的一些人,你可以很快看出他们不会得到高分。理想情况下,您希望尽快停止这些运行,而是尝试不同的参数。
Optuna 为您提供了一个通过修剪回调的选项。支持多种机器学习框架:
KerasPruningCallback, TFKerasPruningCallback
TensorFlowPruningHook
pytorchchinitelusingandler,pytorchlineninginingcallback
- FastAIPruningCallback
- light gbmpunigcallback
- XGBoostPruningCallback
- 还有更
- 你可以在文档中读到它们。
- 例如,在 lightGBM 训练的情况下,您可以将这个回调传递给 lgb.train 函数。
- 只有 Optuna 给你这个选择,所以这是一个明显的胜利。
运行修剪
>远视
def train_evaluate(X, y, params, pruning_callback=None):
X_train, X_valid, y_train, y_valid = train_test_split(X, y, test_size=0.2, random_state=1234)
train_data = lgb.Dataset(X_train, label=y_train)
valid_data = lgb.Dataset(X_valid, label=y_valid, reference=train_data)
callbacks = [pruning_callback] if pruning_callback is not None else None
model = lgb.train(params, train_data,
num_boost_round=NUM_BOOST_ROUND,
early_stopping_rounds=EARLY_STOPPING_ROUNDS,
valid_sets=[valid_data],
valid_names=['valid'],
callbacks=callbacks)
score = model.best_score['valid']['auc']
return score
def objective(trial):
params = {'learning_rate': trial.suggest_loguniform('learning_rate', 0.01, 0.5),
'max_depth': trial.suggest_int('max_depth', 1, 30),
'num_leaves': trial.suggest_int('num_leaves', 2, 100),
'min_data_in_leaf': trial.suggest_int('min_data_in_leaf', 10, 1000),
'feature_fraction': trial.suggest_uniform('feature_fraction', 0.1, 1.0),
'subsample': trial.suggest_uniform('subsample', 0.1, 1.0)}
pruning_callback = LightGBMPruningCallback(trial, 'auc', 'valid')
return train_evaluate(params, pruning_callback)
处理异常
如果由于错误的参数组合、随机训练错误或其他问题导致您的一次运行失败,您可能会丢失到目前为止在研究中评估的所有parameter _ configuration:score对。
您可以在每次迭代后使用回调来保存这些信息,或者使用 DB 来存储这些信息,如速度和并行化一节中所述。
但是,即使出现例外情况,您也可能希望让这项研究继续进行。为了使之成为可能,Optuna 允许您将允许的异常传递给。optimize() 方法。
还是那句话,只有 Optuna 支持这个。
处理异常
>远视
def objective(trial):
params = {'learning_rate': trial.suggest_loguniform('learning_rate', 0.01, 0.5),
'max_depth': trial.suggest_int('max_depth', 1, 30),
'num_leaves': trial.suggest_int('num_leaves', 2, 100)}
print(non_existent_variable)
return train_evaluate(params)
study = optuna.create_study(direction='maximize')
study.optimize(objective, n_trials=100, catch=(NameError,))
证明文件
当你是一个库或框架的用户时,在你需要的时候找到你需要的信息是绝对重要的。这就是文档/支持渠道发挥作用的地方,它们可以创建或破坏一个库。
让我们看看 Optuna 和 Hyperopt 在这方面的比较。
optina
是真的好。
有一个适当的网页解释了所有的基本概念,并告诉你在哪里可以找到更多的信息。
此外,有一个完整的和非常容易理解的文档。
它包含:
包含简单和高级示例的教程
API 参考与所有的函数包含美丽的文件字符串。为了给你一个概念,想象一下在你的 docstrings 中有图表,这样你可以更好地理解在你的函数中发生了什么。如果你不相信我,请查看一下 BaseSampler 。
还有一点很重要,那就是来自 Preferred Networks 的支持团队非常关心这个项目。他们对 Github 的问题做出回应,社区也围绕着 Github 不断成长,有很多很棒的功能想法和 pr 出现。查看 Github 项目问题版块,看看那里发生了什么。
- 10 / 10
- 远视
它最近更新了,现在已经很好了。
这里可以找到。
您可以轻松找到以下信息:
如何开始
如何定义简单和高级搜索空间
如何运行安装
- 如何通过 MongoDB 或 Spark 并行运行 Hyperopt
- 不幸的是,有些事情我不喜欢:
- 文档字符串中缺少 API 引用所有函数/方法
- 大多数方法/函数都缺少 docstrings 本身,这迫使您阅读实现(这里有一些积极的副作用:)
没有使用自适应 TPE 的例子。我不确定我是否正确使用了它,我是否应该指定一些额外的(超级)超级参数。缺少 docstrings 在这里对我也没有帮助。
- 文档里有一些 404 的链接。
- 总的来说,最近有了很大的进步,但我有时还是会有点迷失。我希望随着时间的推移,它会变得更好,所以请保持关注。
- 好的是,有很多关于它的博文。其中一些我认为有用的是:
- 文档不是这个项目最强的方面,但是因为它是经典的,所以有很多资源。
2010 年 6 月
文档
>远视
### 形象化 *** * *
可视化超参数搜索非常有用。您可以获得参数之间交互的信息,并了解下一步应该在哪里搜索。
这就是为什么我想比较 Optuna 和 Hyperopt 提供的可视化套装。
optina
在optuna . visualization模块中有一些很棒的可视化效果:
plot_contour: 在交互图表上绘制参数交互。您可以选择想要探索的超参数。
plot _ optimization _ history:显示所有试验的分数,以及到目前为止每个点的最佳分数。
plot _ parallel _ coordinate:交互可视化超参数和分数
- plot_slice: 展示了搜索的演变。你可以看到在超参数空间中你的搜索去了哪里,以及空间的哪些部分被探索得更多。****
plot_contour(study, params=['learning_rate',
'max_depth',
'num_leaves',
'min_data_in_leaf',
'feature_fraction',
'subsample'])
- 总的来说,Optuna 中的可视化是不可思议的!
plot_optimization_history(study)
- 它们允许您放大超参数交互,并帮助您决定如何运行下一次参数扫描。了不起的工作。
plot_parallel_coordinate(study)
- 10 / 10
plot_slice(study)
Optuna 中可用的可视化给我留下了非常深刻的印象。有用、互动、美观。
可视化
>远视
**注意:
如果你想玩这些可视化,你可以使用我为每个实验保存为“study.pkl”的 研究 对象。
速度和并行化
当谈到超参数优化时,能够在您的机器或许多机器(集群)上分布您的训练可能是至关重要的。
这就是为什么,我检查了 Optuna 和 Hyperopt 的分布式训练选项。
optina
您可以在一台机器或一群机器上运行分布式超参数优化,这实际上非常简单。
对于一台机器,你只需改变你的中的 n_jobs 参数。优化()方法。
要在集群上运行它,您需要创建一个驻留在数据库中的研究(您可以在许多关系数据库中进行选择)。
有两种选择可以做到这一点。您可以通过命令行界面来完成:
您也可以在优化脚本中创建一个研究。
通过使用 load_if_exists=True 你可以以同样的方式对待你的主脚本和工作脚本,这简化了很多事情!
最后,您可以从多台机器上运行您的工作脚本,它们都将使用来自研究数据库的相同信息。
容易和工作像一个魅力!
study.optimize(objective, n_trials=100, n_jobs=12)
10 / 10
远视
optuna create-study \
--study-name "distributed-example" \
--storage "sqlite:///example.db"
你可以将你的计算分布在一群机器上。很好,一步一步的指导可以在 Tanay Agrawal 的博客文章中找到,但是简单来说,你需要:
启动一个装有 MongoDB 的服务器,它将从您的工人培训脚本中获取结果,并发送下一个参数集进行尝试,
study = optuna.create_study(
study_name='distributed-example',
storage='sqlite:///example.db',
load_if_exists=True)
study.optimize(objective, n_trials=100)
在您的训练脚本中,创建一个指向您在上一步中启动的数据库服务器的 MongoTrials() 对象,而不是 Trials() ,
terminal-1$ python run_worker.py
terminal-25$ python run_worker.py
将你的目标函数移动到一个单独的目标. py 脚本中,并将其重命名为函数,
编译您的 Python 训练脚本,
跑 远视-蒙哥-工
虽然它完成了任务,但感觉并不完美。您需要围绕目标函数做一些杂耍,在 CLI 中启动 MongoDB 可能会使事情变得更容易。
- 值得一提的是,通过 SparkTrials 对象与 Spark 的集成是最近才添加的。有一个逐步指南来帮助你开始,你甚至可以使用 spark-installation 脚本来使事情变得更容易。
- 完全按照您期望的方式工作。
- 简单又好看!
- 9 / 10
- 两个库都支持分布式培训,这很好。然而,Optuna 在更简单、更友好的界面方面做得更好。
速度和并行化
>远视
best = hyperopt.fmin(fn = objective,
space = search_space,
algo = hyperopt.tpe.suggest,
max_evals = 64,
trials = hyperopt.SparkTrials())
实验结果*
*需要明确的是,这些是针对一个示例问题和的结果,每个库/配置运行一次,它们不保证通用性。要运行一个合适的基准测试,您需要在不同的数据集上运行多次。
也就是说,作为一名从业者,我希望看到对每个问题的随机搜索有所改进。否则,为什么要去 HPO 图书馆呢?** 好的,作为一个例子,让我们在一个表格,二元分类**问题上调整 lightGBM 模型的超参数。如果您想像我一样使用相同的数据集,您应该:
为了让训练更快,我将的助推轮数固定为 300,并提前 30 轮停止。
所有的训练和评估逻辑都放在 train_evaluate 函数中。我们可以将其视为一个黑盒,它获取数据和超参数集并生成 AUC 评估分数。
注意:
您实际上可以将每个以参数作为输入并输出分数的脚本转换成这样的 train_evaluate。完成后,您可以将其视为黑盒并调整您的参数。
要根据一组参数训练模型,您需要运行如下内容:
对于这项研究,我试图在 100 运行预算内找到最佳参数。
我做了 6 个实验:
import lightgbm as lgb
from sklearn.model_selection import train_test_split
NUM_BOOST_ROUND = 300
EARLY_STOPPING_ROUNDS = 30
def train_evaluate(X, y, params):
X_train, X_valid, y_train, y_valid = train_test_split(X, y,
test_size=0.2,
random_state=1234)
train_data = lgb.Dataset(X_train, label=y_train)
valid_data = lgb.Dataset(X_valid, label=y_valid, reference=train_data)
model = lgb.train(params, train_data,
num_boost_round=NUM_BOOST_ROUND,
early_stopping_rounds=EARLY_STOPPING_ROUNDS,
valid_sets=[valid_data],
valid_names=['valid'])
score = model.best_score['valid']['auc']
return score
随机搜索(来自 hyperopt)作为参考
Optuna 和 Hyperopt 的 Parzen 估计量搜索策略树
来自 Hyperopt 的自适应 TPE
来自 Optuna 的 TPE,带有修剪回调,用于更多运行,但在相同的时间范围内。结果是,有修剪的 400 次运行与没有修剪的 100 次运行花费的时间一样多。
import pandas as pd
N_ROWS=10000
TRAIN_PATH = '/mnt/ml-team/minerva/open-solutions/santander/data/train.csv'
data = pd.read_csv(TRAIN_PATH, nrows=N_ROWS)
X = data.drop(['ID_code', 'target'], axis=1)
y = data['target']
MODEL_PARAMS = {'boosting': 'gbdt',
'objective':'binary',
'metric': 'auc',
'num_threads': 12,
'learning_rate': 0.3,
}
score = train_evaluate(X, y, MODEL_PARAMS)
print('Validation AUC: {}'.format(score))
基于 skopt 的 Optuna 随机森林替代模型。取样器
参见超参数优化脚本示例。
- 如果你想更详细地探索所有这些实验,你可以简单地进入实验仪表板。
- Optuna 和 Hyperopt 都比随机搜索有所改进,这很好。
- 来自 Optuna 的 TPE 实现略好于 Hyperopt 的自适应 TPE,但好不了多少。另一方面,当运行超参数优化时,这些小的改进正是您想要的。
- 有趣的是,HPO 和 Optuna 的 TPE 实现在这个问题上给出了非常不同的结果。也许好的和坏的参数配置 λ 之间的分界点选择不同,或者采样方法的默认值更适合这个特定的问题。
- 此外,使用修剪减少了 4 倍的训练时间。我可以在不修剪的情况下运行 100 次搜索的时间内运行 400 次搜索。另一方面,使用修剪得到了较低的分数。您的问题可能不同,但在决定是否使用修剪时,考虑这一点很重要。
对于这一部分,我根据对随机搜索策略的改进来打分。
Experiments for Optuna and Hyperopt in different configurations
远视得到(0.850–0.844)* 100 =6
Optunagot(0.854–0.844)* 100 =10
实验结果
>远视
**结论
- 让我们来看看总体得分:
- 即使你大方地看待它,只考虑两个库共有的特性, Optuna 也是一个更好的框架。
在所有标准上,它都达到或略好于标准,并且:
它有更好的文档
它有更好可视化套件
它有一些 hyperopt 不支持的特性,比如修剪、回调和异常处理
在做了所有这些研究之后,我确信 Optuna 是一个很棒的超参数优化库。
此外,我认为如果你在过去使用超远眼镜,你应该强烈考虑更换。
雅各布·查肯
- 大部分是 ML 的人。构建 MLOps 工具,编写技术资料,在 Neptune 进行想法实验。
- 阅读下一篇
- 如何跟踪机器学习模型的超参数?
卡米尔·卡什马雷克|发布于 2020 年 7 月 1 日
Moreover, I think that you should strongly consider switching from Hyperopt if you were using that in the past.
机器学习算法可通过称为超参数的多个量规进行调整。最近的深度学习模型可以通过数十个超参数进行调整,这些超参数与数据扩充参数和训练程序参数一起创建了非常复杂的空间。在强化学习领域,您还应该计算环境参数。
数据科学家要控制好 超参数 空间,才能使 进步。
在这里,我们将向您展示最近的 实践,提示&技巧,和工具以最小的开销高效地跟踪超参数。你会发现自己掌控了最复杂的深度学习实验!
为什么我应该跟踪我的超参数?也就是为什么这很重要?
几乎每一个深度学习实验指南,像这本深度学习书籍,都建议你如何调整超参数,使模型按预期工作。在实验-分析-学习循环中,数据科学家必须控制正在进行的更改,以便循环的“学习”部分正常工作。
哦,忘了说随机种子也是一个超参数(特别是在 RL 领域:例如检查这个 Reddit )。
超参数跟踪的当前实践是什么?
让我们逐一回顾一下管理超参数的常见做法。我们关注于如何构建、保存和传递超参数给你的 ML 脚本。
Here, we will show you recent practices, tips & tricks, and tools to track hyperparameters efficiently and with minimal overhead. You will find yourself in control of most complex deep learning experiments!
Why should I track my hyperparameters? a.k.a. Why is that important?
Almost every deep learning experimentation guideline, like this deep learning book, advises you on how to tune hyperparameters to make models work as expected. In the experiment-analyze-learn loop, data scientists must control what changes are being made, so that the “learn” part of the loop is working.
Oh, forgot to say that random seed is a hyperparameter as well (especially in the RL domain: check this Reddit for example).
What is current practice in the hyperparameters tracking?
Let’s review one-by-one common practices for managing hyperparameters. We focus on how to build, keep and pass hyperparameters to your ML scripts.
机器学习中的过拟合与欠拟合:你需要知道的一切
原文:https://web.archive.org/web/https://neptune.ai/blog/overfitting-vs-underfitting-in-machine-learning
在我们生活的世界里,数据支配着我们的许多活动。有人说数据是新燃料。数据不仅仅告诉我们过去。如果我们用精确的方法仔细建模,那么我们可以找到模式和相关性来预测股票市场,生成蛋白质序列,探索病毒等生物结构,等等。
像这样手动对大量数据建模是一项乏味的工作。为了实现这一点,我们转向了机器学习算法,这些算法可以帮助我们从数据中提取信息。ML 和 DL 算法的需求量很大,它们可以解决复杂的问题,这些问题是不切实际的,甚至是不可能手工完成的,并且可以学习分布、模式和相关性,揭示数据中的知识。
算法通过探索数据集并创建该数据分布的近似模型来做到这一点,这样当我们提供新的和未知的数据时,它将产生良好的结果。
机器学习中的一个问题是,我们希望我们的算法在处理训练数据(即,输入到算法中用于建模的数据)以及新数据时表现良好。这就是所谓的。我们希望我们的算法善于泛化。
**然而,仍然存在一些问题:
- 理解一个算法真正在做什么是相当具有挑战性的。
- 假设我们已经生产了一个模型,但是它没有产生好的结果——理解哪里出了问题以及如何修复它是一个挑战。
机器学习中的一个普遍问题是,当算法在训练数据集上表现良好,但在测试数据或新数据上表现不佳,并且无法对给定的分布进行建模。
这是为什么呢?
关于算法的性能,可能有很多原因。决定机器学习算法性能的因素是它的以下能力:
- 使训练误差尽可能小。
- 使训练误差和测试误差之间的差距变小。–(深度学习书,伊恩·古德菲勒;2014)
这两个因素对应了机器学习中的两个核心挑战:欠拟合和过拟合。欠拟合是训练误差高的时候。过拟合是指测试误差比训练误差高,或者两者差距大。
虽然理解大而复杂的 ML 和 DL 模型的工作方式具有挑战性,但我们可以从理解小而简单的模型的工作方式开始,并逐步增加复杂性。
注:本文所有题目的代码都在这个 colab 笔记本 里。
模型基础
机器学习算法,或深度学习算法,是一种数学模型,它使用数学概念从数据集中识别或学习某种类型的模式或相关性。我们所说的学习是什么意思?
让我们考虑方程 y = mx + b,其中 m 和 b 是参数,x 是输入。
在机器学习中,学习指的是一个优化过程,其中模型的参数在训练的每次迭代中使用损失函数来更新,使得方程完美地或近似地符合分布。见下图。
一些模型试图通过函数找到输入和输出之间的关系,而另一些模型试图将相似的数据组合在一起,或者找到相关的模式。第一种是监督学习,第二种被称为非监督学习。
在监督和非监督学习中,模型需要学习重要的特征,它可以利用这些特征产生好的结果。有几个因素可以帮助 it 实现这一目标:容量和体系结构。
模型容量和架构
从概念上讲,容量表示机器学习算法可以选择作为最优解的函数(线性或非线性)的数量。机器学习算法的性能取决于其容量。一个好的经验法则是,模型的容量应该与其任务的复杂性和训练数据集的输入成比例。
在解决复杂任务时,低容量的机器学习模型毫无用处。他们倾向于欠配。同样,容量(比需要的)更高的模型最有可能过度配置。
本质上,模型容量代表了一种度量,通过这种度量,我们可以估计模型是倾向于欠拟合还是过拟合。
让我们用一些代码来理解这一点:
import numpy as np
import matplotlib.pyplot as plt
首先,我们将创建一个数据集:
X = np.sort(np.random.rand(100))
然后我们将定义一个真函数。监督学习中的真正函数是已经将输入映射到输出的函数。这将帮助我们评估我们的机器学习算法对分布的建模有多正确。
true_f = lambda X: np.cos(3.5 * np.pi * X)
然后我们定义一个 y,它是真函数的输出:
y = true_f(X) + np.random.randn(100) * 0.1
当我们用 X 对 y 作图时,我们的数据分布看起来像这样:
我们希望我们的机器学习模型尽可能接近真实函数。
现在让我们定义我们的机器学习模型:
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import PolynomialFeatures
from sklearn.linear_model import LinearRegression
为了解决容量问题,我们将使用“度”这个术语。与度数为 15 的模型相比,度数为 1 的模型容量较低。
degrees = [1,15]
在这个循环中,我们将用 1 度和 15 度两个度数来迭代模型。这将向我们展示容量如何帮助我们实现能够产生良好结果的良好模式。
plt.figure(figsize=(15, 10))
for i in range(len(degrees)):
ax = plt.subplot(1, len(degrees), i+1)
plt.setp(ax, xticks=(), yticks=())
polynomial_features = PolynomialFeatures(degree=degrees[i],
include_bias=False)
linear_regression = LinearRegression()
pipeline = Pipeline([("polynomial_features", polynomial_features),
("linear_regression", linear_regression)])
pipeline.fit(X[:, np.newaxis], y)
X_test = np.linspace(0, 1, 100)
yhat = pipeline.predict(X_test[:, np.newaxis])
plt.plot(X_test, yhat,label="Model")
plt.plot(X_test, true_fun(X_test), label="True function")
plt.scatter(X, y, label="Samples")
plt.xlabel("x")
plt.ylabel("y")
plt.xlim((0, 1))
plt.ylim((-2, 2))
plt.legend(loc="best")
plt.title("Degree %d" % degrees[i])
plt.show()
从上图我们可以看出,能力对于建立一个好的机器学习模型有着重要的作用。左边的第一个图像不符合,而右边的图像完全符合分布。
请记住,如果模型的容量高于数据的复杂性,那么模型可能过拟合。
架构是对给定的一组数据分布进行建模的多级非线性函数的组合。不同的模型有不同的架构,这取决于您正在处理的数据。尤其是当你在开发深度学习模型,或者使用非参数模型,如 random forest 或 XGBoost 时。
当这些架构无法学习或捕捉模式时,可能会出现过拟合或欠拟合。
资料组
在典型的机器学习场景中,我们从用于分离和创建训练和测试数据集的初始数据集开始。传统上,我们使用 80%的数据集来训练模型,并保留 20%来测试它。
在训练阶段,我们的模型肯定会偏离训练数据。这通常被称为训练误差。同样,测试阶段产生的偏差称为测试误差。作为机器学习实践者,我们的工作应该是:
- 减少训练误差——训练不足。
- 减少训练和测试误差之间的差距——过度拟合。
记住这一点,我们考虑两个对数据集非常重要的概念:
- 方差和偏差
- 数据泄露
让我们来详细探讨一下。
方差和偏差
方差和偏差是我们大多数人忘记考虑的一些概念。它们是什么意思?
偏差通常指模型的刚性。考虑一个具有非线性属性的数据集(我们在开始时见过)。为了捕捉模式,我们需要应用足够灵活的机器学习算法来捕捉非线性属性。如果我们应用一个线性方程,那么我们说机器学习模型具有高偏差和低方差。简而言之,高偏差模型难以捕捉数据的复杂本质。
让我们定义一个非线性函数和一个简单的线性模型,该函数捕捉数据的真实特征或表示。
non_linear_func = lambda X: np.cos(3.5 * np.pi * X)
Simple_Model = 2**(X)
从上图可以看出,这个简单的模型是:
- 太死板,太简单,无法捕捉非线性表示。
- 高偏差和低方差。
- 在训练集上产生高错误-欠拟合。
方差,另一方面,当算法在训练期间试图精确地模拟分布时,它捕获每个数据点的位置。结果,这个模式就是太灵活而太复杂。在这种情况下,模型具有高方差和低偏差。
如上图所示,复杂模型具有:
- 倾向于从数据集中捕捉噪声。
- 高方差和低偏差。
- 测试集的高误差–过度拟合。
当涉及到过度拟合时,决策树算法非常容易出现这种情况。
什么是数据泄漏,它会影响模型性能吗?
导致过拟合的问题之一是数据泄漏。
当训练集的信息转移到测试集时,就会发生这种情况。在测试集的最终评估中,该模型表现良好。在部署模型之前,这种对模型的高估可能会产生很大的误导。它有可能表现不佳。
为了避免数据泄漏,在进行任何特征工程之前,最好将训练数据集和测试数据集分开。这样,信息不会转移到测试数据集中,模型的真实性能可以在测试过程中进行测量。
如何克服你的 ML 模型中的过拟合和欠拟合?
我们将讨论避免过拟合和欠拟合的六种方法:
- 引入验证集,
- 方差-偏差权衡,
- 交叉验证,
- 超参数调谐,
- 正规化,
- 提前停车。
验证集
验证数据集用于在训练数据集上训练模型后提供无偏见的评估。这在架构的设计迭代或模型的超参数调整期间很有帮助。在这两种情况下,它在部署之前提高了模型的性能,并确保模型在测试数据上具有良好的通用性。
重要的是要记住,在训练期间使用训练和验证数据来检查过拟合和欠拟合。测试数据用于确保模型具有良好的泛化能力。
一个好的实践是从整个数据中创建一个训练集和测试集,然后从先前分离的训练集中创建一个训练集和验证集。
方差-偏差权衡
我们已经知道什么是方差和偏差。它们可以在建立良好的机器学习模型,甚至是产生良好结果的深度学习模型方面发挥重要作用。从本质上讲,我们不能同时拥有极高数量的方差和偏差。我们都有限量版。
“改善过度拟合模型的一种方法是给它喂更多的训练数据,直到验证误差达到训练误差”——与 Scikit-Learn 和 TensorFlow 一起动手进行机器学习,aurélien géRon;2019)
方差-偏差权衡基本上是在偏差和方差之间找到一个最佳平衡点。我们知道偏差反映了模型对数据的严格性,而方差反映了数据的复杂性。高偏差导致刚性模型。当我们增加容量时,模型倾向于通过降低刚性来增加其灵活性。本质上,我们正在通过增加容量,将一个不充分拟合的模型转变为一个统计上良好拟合的模型。
一个好的做法是检查训练错误和验证错误。因为误差=偏差+方差。如果两个误差都较小且彼此接近,则该模型具有良好的拟合性。
左侧图像显示高偏差和欠拟合,中间图像显示良好拟合模型,右侧图像显示高方差和过拟合。
交叉验证
交叉验证通过在训练期间在各种验证数据集上评估 ML 模型来帮助我们避免过度拟合。这是通过将训练数据分成子集来完成的。那么交叉验证对模型有什么帮助呢?
嗯,我们希望模型在训练中学习重要的特征和模式。交叉验证分割数据,使得验证数据代表训练和来自真实世界场景的数据。这有助于模型很好地概括并产生良好的结果。
Source: Approaching (Almost) Any Machine Learning Problem (2020), Abhishek Thakur
让我们看一个例子。
首先,我们将构建四个决策树。每个决定将有不同的最大深度。接下来,我们将训练他们:
from sklearn.tree import DecisionTreeRegressor
tree_reg1 = DecisionTreeRegressor(random_state=42, max_depth=2)
tree_reg2 = DecisionTreeRegressor(random_state=42, max_depth=3)
tree_reg3 = DecisionTreeRegressor(random_state=42, max_depth=5)
tree_reg4 = DecisionTreeRegressor(random_state=42, max_depth=12)
tree_reg1.fit(X_train, y_train)
tree_reg2.fit(X_train, y_train)
tree_reg3.fit(X_train, y_train)
tree_reg4.fit(X_train, y_train)
现在,让我们看看所有四个模型在训练和测试数据集上的准确性:
The training and testing scores of model 1: 0.7732058844148597 and 0.770360248173112,
The training and testing scores of model 2: 0.8523996532650688 and 0.8476275950133408,
The training and testing scores of model 3: 0.8964495771468475 and 0.8907512124389504,
The training and testing scores of model 4: 0.9254890162488267 and 0.8895815575629907
我们可以观察到两件事:
- 随着最大深度的增加,训练精度也增加。
- 随着最大深度的增加,训练精度和测试精度之间的差异也会增加——过度拟合。
为了解决这个问题,我们将使用 k-fold 交叉验证从训练集中创建子集。k 折叠交叉验证将数据集分成“k”个折叠,然后使用“k”个折叠中的一个作为验证集,其他 k-1 个折叠作为训练集。
这个过程重复 k 次,使得 k 个折叠中的每一个被用作测试集一次。然后将从这 k 次训练和测试中获得的分数进行平均,以获得最终分数。
for index, (train, test) in enumerate(fold.split(X_train,y_train)):
X_train_folds = X_train[train]
y_train_folds = y_train[train]
X_test_folds = X_train[test]
y_test_folds = y_train[test]
tree_reg1.fit(X_train_folds, y_train_folds)
tree_reg2.fit(X_train_folds, y_train_folds)
tree_reg3.fit(X_train_folds, y_train_folds)
tree_reg4.fit(X_train_folds, y_train_folds)
k-fold 的目的是帮助模型很好地对测试数据进行概括。
Fold 1
Accuracy Comparison on model 1 : 0.7664370565884211 0.7801300087611103
Accuracy Comparison on model 2 : 0.8485031490397249 0.8586081582213081
Accuracy Comparison on model 3 : 0.8950440772346971 0.9007301852045746
Accuracy Comparison on model 4 : 0.9268552462895857 0.8978944174232537
Fold 2
Accuracy Comparison on model 1 : 0.7671249512433342 0.7687678014811595
Accuracy Comparison on model 2 : 0.8497676129534959 0.8515991797911563
Accuracy Comparison on model 3 : 0.8970919853597747 0.8931467178250443
Accuracy Comparison on model 4 : 0.9283195789947759 0.8911095249603449
Fold 3
Accuracy Comparison on model 1 : 0.7735518731532391 0.7684962516765577
Accuracy Comparison on model 2 : 0.8535462998699248 0.8470155912448611
Accuracy Comparison on model 3 : 0.8969106026960184 0.8898887269256492
Accuracy Comparison on model 4 : 0.9288963915724866 0.8884304629263801
Fold 4
Accuracy Comparison on model 1 : 0.7738322196681096 0.7753768159905526
Accuracy Comparison on model 2 : 0.8536239983149718 0.8512559589603865
Accuracy Comparison on model 3 : 0.8968186364805686 0.8931328656292392
Accuracy Comparison on model 4 : 0.9280796541851367 0.891684128138715
Fold 5
Accuracy Comparison on model 1 : 0.7733590419579685 0.750509982451151
Accuracy Comparison on model 2 : 0.8518211510105747 0.8362310647486868
Accuracy Comparison on model 3 : 0.8977214861124465 0.8890623271523825
Accuracy Comparison on model 4 : 0.9290267746532016 0.8859361597163452
正如我们所看到的,过度拟合在一定程度上减少了。到目前为止,一切顺利。
但是,我们必须记住,交叉验证纯粹基于我们如何为培训和评估阶段创建一个好的子集。它给了我们一个起点,但是我们还必须学习其他方法来优化我们的模型。
让我们发现其他方法来进一步减少过度拟合,同时提高模型性能。
超参数调谐
当创建一个(好的)ML 或 DL 模型时,您必须仔细决定和选择哪种架构最适合您的应用程序——在这种情况下,就是数据分布。当然,这将主要是一种试错法,除非我们找到可以准确模拟分布的最佳算法架构。为此,我们需要探索一系列的可能性。
在寻找最佳模型架构时,我们可以要求机器学习算法执行搜索,以便为我们的数据分布提供参数或架构的良好组合。此外,定义模型架构的参数被称为超参数,搜索这些参数的过程被称为超参数调整。
设计模型时,您可能会问的一些问题是:
- 线性模型的多项式特征的次数应该是多少?
- 决策树或随机森林允许的最大深度应该是多少?
- 我应该在我的随机森林中包含多少棵树?
- 梯度下降的学习率应该是多少?
在这个例子中,我们将看到如何使用网格搜索为我们的随机森林算法找到最佳参数,以减少过度拟合:
from sklearn.metrics import make_scorer
from sklearn.model_selection import GridSearchCV
from sklearn.metrics import r2_score
def performance_metric(y_true, y_predict):
""" Calculates and returns the performance score between
true and predicted values based on the metric chosen. """
score = r2_score(y_true,y_predict)
return score
为了进行完美的网格搜索,我们需要确保在字典中定义了所有的参数(我们想要更改的参数):
params = {'max_depth':np.arange(1,11),
'n_estimators' : [10, 50, 100, 200],
'oob_score' : [False, True],
'max_features': ['auto', 'sqrt']}
scoring_fnc = make_scorer(performance_metric)
regressor_tree = RandomForestRegressor(random_state=42, n_jobs = -1)
grid = GridSearchCV(estimator=regressor_tree,param_grid=params,cv=5,scoring=scoring_fnc)
让我们拟合模型,并检查训练和测试数据集的准确性:
grid.fit(X_train, y_train)
grid.score(X_train, y_train), grid.score(X_test, y_test)
(0.9597848908613165, 0.9481551892881535)
如您所见,网格搜索帮助您找到可以显著减少过度拟合的参数。
要知道网格搜索为数据分布找到了什么参数或架构组合,只需运行 grid.best_estimator_
集成方法
集成方法结合一组预测模型来获得平均预测。这是一个非常成功的方法,不仅因为它减少了过度拟合,还因为它可以解决极其复杂的问题。一个很好的例子是 HydraNet ,特斯拉用于其自动驾驶汽车。
由于汽车使用八个不同的摄像头来获得周围环境的全景,它需要一个可以模拟所有输入的算法。HydraNet 通过一套 CNN 架构实现了这一点。
不管怎样,到目前为止,我们已经看到了如何避免过度拟合的技术,如:引入验证数据集、交叉验证和通过网格搜索进行超参数调整。但是,我们的准确率仍然低于 90%,尽管过度拟合已经大大减少。
让我们使用集成方法来提高准确性,同时在数据分布上保持良好的统计拟合。我们还将使用到目前为止学到的所有技术。
这次,我们将使用一个随机森林算法。随机森林是决策树的组合,其中参数 n_estimators 定义了我们在模型中需要的树的数量。默认情况下,它设置为 100。
from sklearn.ensemble import RandomForestRegressor
regressor_for = RandomForestRegressor(random_state=42, n_jobs=-1)
params = {'max_depth':np.arange(1,6),
'max_features':['auto', 'sqrt', 'log2'],
'n_estimators': [10, 100, 200]
}
scoring_fnc = make_scorer(performance_metric)
grid = GridSearchCV(estimator=regressor_for,param_grid=params,cv=5,scoring=scoring_fnc)
grid.fit(X_train, y_train)
print('The training and testing scores of model 1: {} and {}'.format(grid.score(X_train, y_train), grid.score(X_test, y_test)))
在用随机森林对数据建模之后,我们在训练和测试上都得到了如下分数:0.9098966600896439 和 0.80966665 它不仅提高了模型的准确性,而且保持了非常低的过拟合分数——足够好了。
正规化
到目前为止,在我们的示例中,我们主要使用的是非参数模型,这些模型不会对任何参数进行操作,这使它们比参数模型更有优势——它们具有更大的容量。
“在观察到任何数据之前,参数模型学习由大小有限且固定的参数向量描述的函数”——深度学习书籍,Ian Goodfellow。
参数模型和非参数模型都可能过拟合,并且它们可以被正则化。
正则化是通过使复杂的模型变得简单和不太灵活来约束它。这样可以避免过拟合。
注:调整被称为收缩。
让我们看一个例子。
首先,我们将在数据分布中引入岭回归算法:
岭回归是线性回归的正则化版本:
from sklearn.linear_model import Ridge, LinearRegression
线性回归中的一个简单关系如下所示:
其中 y 是输入变量 x 和系数或参数之间的关系。
在训练阶段,通过优化过程更新系数来最小化损失函数。这个损失函数被称为残差平方和,或 RSS:
RSS 会根据您的训练数据调整系数。如果训练数据中有噪声,估计的系数将不能很好地推广到看不见的数据。在系数过于偏离真实函数的情况下引入正则化有助于系数收缩,或者将这些学习到的估计正则化为零。
在上面的等式中,RSS 用正则化量来修改,其中是正则化强度。
蓝线表示正则化强度为 0 的模型。请注意,当正则化强度大于 0 时,模型开始降低其容量或灵活性,从而减少过度拟合。
提前停止
在迭代算法中,如深度神经网络,甚至在浅层迭代算法中,如随机梯度回归器,您可以通过尽早停止训练来正则化模型-只要验证误差达到最小值。这是提前停止。
Source: Hands-on machine learning with scikit-learn, keras and tensorflow, Aurélien Geron, 2019
结论
在本文中,我们探讨了什么是过度拟合和欠拟合。我们总结一下:
-
过度拟合是指:
- 学习算法可以很好地模拟训练数据,但无法模拟测试数据。
- 模型复杂度高于数据复杂度。
- 数据有太多噪音或差异。
-
欠拟合是指:
- 学习算法无法对训练数据建模。
- 模型简单而死板,无法捕捉数据点。
- 模型具有高偏差。
-
在以下情况下可以识别过度拟合:
- 训练精度高于测试精度。
- 训练误差高于测试误差。
-
当模型的精度非常低时,可以识别出欠拟合,并且欠拟合在多次迭代之后增加。
Source: Deep Learning Book, Ian Goodfellow
要解决拟合不足的问题,请增加模型的容量。这将增加复杂性并降低偏差。
要解决过度拟合问题,请降低模型的容量。这将增加偏差,使模型不那么复杂。使用以下技术:
- 引入验证集,
- 方差-偏差权衡,
- 交叉验证,
- 超参数调谐,
- 正规化,
- 提前停车。
这篇文章的笔记本在这个链接中提供。请随意尝试!**
打包 ML 模型:Web 框架和 MLOps
原文:https://web.archive.org/web/https://neptune.ai/blog/packaging-ml-models
在本文中,我们将了解顶级打包工具——基于网络的框架和 MLOps——数据科学和 ML 项目的内容、原因和方式。数据科学家和机器学习工程师需要特定的工具来端到端地构建、部署和监控这些项目。
我们将详细介绍几种工具,以及它们的关键组件和特性。不需要介绍,我们走吧!
可能有用
找到最适合您的使用情形的 MLOps 工具👉 MLOps 工具景观
机器学习开发生命周期
我们处理的所有 ML 项目都有许多迭代步骤,需要同步执行才能获得最佳结果。当 ML 模型和数据不断增长时,数据科学团队手动管理这些步骤变得很乏味。
这就产生了操作整个机器学习开发生命周期的想法。但是最好的方法是什么呢?理想情况下,我们需要在关键利益相关者之间划分 ML 项目工作,并且每个团队成员需要以高度协作的方式工作,以使项目成功。
机器学习和数据科学生命周期的利益相关者
为了了解如何以迭代和自动化的方式处理任何机器学习项目,我们需要首先了解平均机器学习和数据科学生命周期的所有利益相关者。中小企业、数据科学家和数据工程师是最受欢迎的角色,但每个利益相关者在 ML 项目的成功中都扮演着重要的角色。让我们看看不同的团队成员通常负责什么。
主题专家(SME)
- 专注于非常重要的业务问题。
- 确保模型性能满足业务需求/目标。
- 分析业务需求和目标。
数据分析师/业务分析师
- 处理数据分析和 EDA。
- 协助开发数据功能。
- 为 ML 流程(ETL)优化和构建数据提取。
数据工程师
- 分析和组织数据。
- 构建重要的数据管道。
- 在项目上与 SME、数据分析师、数据科学家和数据架构师合作。
数据科学家
- 开发模型来回答中小企业提出的问题。
- 应用预测分析和统计。
- 审查模型结果、准确性并重新培训模型。
ML 工程师
- 测试模型,并将它们交付到生产中,以产生商业价值。
- 根据客户要求设计和开发机器学习应用程序。
- 扩展和丰富了用于深度学习和机器学习的现有框架和库
软件工程师
- 开发使用 ML 模型的 API 或应用程序。
- 使用各种工具验证机器学习模型是否正确运行。
- 使用 API 将 ML 应用集成为 Web 应用。
机器学习架构师
- 作为生产部署的一部分,优化机器学习模型的架构。
- 支持在生产中部署模型的扩展。
- 与数据科学团队的每个成员合作,并指导 ML 项目。
开发工程师
- 为所有环境中的模型处理持续集成和持续部署管道。
- 处理支持模型的体系结构的安全性、集成和性能。
BI(商业智能)开发人员
- 开发、部署和维护界面,如数据可视化、查询工具和业务仪表板。
- 将业务需求转化为技术需求。设定 BI 工具的业务需求。
涉众通常被隔离在不同的小组和团队中。有了 ML 打包工具,利益相关者可以作为一个合作团体来计算和避免公司的风险。将模型从开发转移到生产和扩展是伴随 ML 项目的常见挑战。它们会导致实现和部署模型的交付时间延长。
ML 打包工具是为了优化数据科学和 ML 生命周期而创建的。多亏了这些工具,沟通和实施流程得以简化。您可以避免突然有太多的涉众无法跟踪谁做了什么的情况,因为工具可以为您跟踪这一点。请记住,这些角色和职责在不同的公司会有所不同。
数据科学和 ML 项目面临的五大问题
在数据科学项目中,我们可能会遇到以下五个挑战:
1。围绕的大肆宣传带来了很高的期望
-
围绕机器学习的炒作如此之多,人们的期望值通常都定得太高了。数据科学和 ML 需要根据它们的局限性来解释,而不仅仅是潜在的好处。
-
营销人员和媒体往往无法解决这种情况的全部现实,所以他们描绘了一幅强大的技术自动解决问题的美好画面。但是人工智能和人工智能是复杂的技术,任何公司都需要时间来实施和充分利用。他们消耗大量资源来实现投资回报。ML 生命周期中的利益相关者需要从一开始就管理期望。
2。模特不喜欢匆忙的时间线
-
创建一个好的机器学习模型需要大量的工作,数据科学家并不总是能够预见准确的开发和实施时间。数据科学项目不应该有严格的里程碑和截止日期。
-
数据科学团队可能在比预期更短或更长的时间内取得成功。企业需要表现出耐心,并继续为团队提供他们需要的资源。
3。模型应该面向未来,无需维护
- 在数据科学团队在构建和测试模型上投入了如此多的辛勤工作之后,经常会出现这样的问题:他们的模型是否已经了解了他们所需要的一切。
- 机器学习模型需要不断训练和维护,以适应未来。团队和企业应该确保他们在开始一个 ML 项目时考虑到这样做的成本。
4。数据收集消耗一半以上的时间
-
数据在任何数据科学用例中都扮演着至关重要的角色。数据科学团队 60%的工作在于收集数据。对于尝试机器学习的初学者来说,他们可以很容易地找到各种托管公开可用数据的网站。
-
为了实现真实世界的场景,您需要通过 web 抓取、通过 API 收集数据,或者(为了解决业务问题)从客户端收集数据(在这种情况下,数据科学家或 ML 工程师需要与主题专家协调和合作来收集数据)。
-
数据一旦被收集,在数据库中可能具有非结构化的格式。正确格式化数据需要数据工程知识。
5。模型和应用部署
数据科学生命周期遵循构建应用程序的 7 个步骤:
1)数据收集,
2)数据清洗,
3)特征工程,
4)分析模式,
5)模型训练和优化,
6)验证模型,
7)模型测试、部署和维护。
啊,部署!研究人员和开发人员通常可以执行所有的构建步骤,但是有时缺乏部署的技能。由于缺乏实践和依赖性问题,对业务的底层模型理解不足,以及模型不稳定,将他们的应用程序投入生产已经成为最大的挑战之一。这是 DevOps 工程师、ML 工程师可以参与进来将您的模型部署到生产中的地方。
通常,许多开发人员从网站上收集数据,并开始训练他们的模型,但在现实世界中,需要获取动态的数据收集源。离线学习或批量学习不能用于这种类型的可变数据。该系统经过培训,然后投入生产,无需学习即可运行。数据和模型可能会漂移,因为它们可能会经常改变。
我们需要一个打包工具,比如基于 web 的框架或 MLOps 工具,来避免或减轻项目涉众所面临的挑战。
将机器学习解决方案构建为一个端到端的系统,并随着时间的推移不断改进,这是在数据科学项目中实现商业价值的主要障碍。打包工具对此有所帮助。
ML 项目中的挑战
ML 项目的两大挑战是:
- 将 ML 模型投入生产,只有 47%的模型完全部署!(来源: Gartner,2019 )
创建的模型数量和实际投入生产的模型数量之间的差距是企业机器学习成功的巨大障碍。一旦组织能够超越这一点,组织将能够从他们的机器学习投资中获得更大的价值。
- 部署机器学习和深度学习模型的时间非常长。(来源: Algorithmia,2020 )
一项调查显示,将 ML & DL 模型投入生产部署——最终开始增加商业价值——平均需要从 8 到 90 天 的时间。更糟糕的是,高达 75%的 ML 项目从未超过实验阶段。
以下是几个使项目难以进入生产的额外挑战:
- 数据和模型的可扩展性问题,
- 开源试点,不是生产级的,
- 难以部署到业务应用程序和流程中,
- 缺乏开发和集成技能,
- 缺乏资金和合适的工具,
- 数据质量和完整性问题,
- 输入和输出的数据治理和安全性。
数据科学中的新兴角色
传统的商业智能和趋势人工智能都在出现,因为它们都使用数据建模(商业智能使用统计技术来分析过去,人工智能进行预测)。
数据科学资源的整体缺乏将导致越来越多的软件开发人员参与创建和管理机器学习模型。( Gartner 首席信息官调查)
同样类型的工作将会出现更多的角色名称和职位名称。为此,我们看到数据科学领域涌现出大量热门职位,例如:
- 机器学习工程师,
- ML 显影剂,
- ML 架构师,
- 数据工程师,
- 深度学习专家,
- NLP 工程师,
- 计算机视觉工程师,
- 机器学习操作(MLOps),
- 人工智能行动。
行业扩张,公司试图将他们自己和他们的才能与众不同。
作为将机器学习模型投入生产的挑战和问题的合理解决方案, MLOps 是伴随着现有的 web 和移动开发框架打包方式而出现的新趋势。
如何打包 ML 项目
重要的是将 ML 项目管道(或数据科学生命周期,如下图所示)打包到一个端到端系统中,以实现良好的 ROI。
有两种方法可以打包 ds 和 ML 项目:
- 基于网络的框架
- MLOps
1.用基于网络的框架打包 ML 项目
基于 web 的框架是一个代码库,它通过为构建可靠、可伸缩和可维护的 web 应用程序提供通用模式,使 web 开发更快、更有效、更容易。大多数时候,专业的 web 开发项目总是使用现有的 web 框架,如 Flask、FastAPI、Django 或 Pyramid。
框架的优势
- 开源的,
- 良好的文档和社区,
- 高效,
- 安全,
- 轻松集成。
为什么基于 web 的框架有用?
基于 Web 的框架使得非常常见的 HTTP 操作的代码可重用性变得容易&构建项目,使得任何具有框架知识的人都可以快速地构建、维护和支持应用程序。
常见的基于 web 的框架的功能
框架提供了执行常见操作的功能,包括:
- 输入表单处理和验证–这个想法是验证数据,然后保存表单,如果它需要一些输入,
- URL 路由–路由机制用于将 URL 直接映射到最终创建网页的代码。
- 使用模板引擎输出格式–使用模板引擎生成任何广泛使用的内容类型,如 HTML、XML 和 JSON。
- 数据库连接–通过对象关系映射(ORM)进行持久数据操作和数据库连接配置。
- Web 安全–框架为 Web 提供安全保护,防止跨站点脚本(XSS)、跨站点请求伪造(CSRF)、SQL 注入和其他恶意攻击。
- 会话存储和检索–无论何时页面会话结束,存储在会话存储器中的数据都会被清除。
全栈框架
全栈框架是一个一体化的地方,其中的库被配置为彼此无缝协作。它可以帮助您构建后端服务、数据库和前端。全栈框架提供了软件开发者构建应用所需的一切。
微观框架
微框架没有全栈框架的大部分功能,比如 web 模板引擎、帐户、授权、认证或输入验证。微框架只提供应用程序所需的组件集。
4 个令人惊叹的 Python 基于 web 的框架
1.烧瓶(微框架)
Flask 是一个著名且广泛使用的 Python web 框架。这是一个第三方 Python 库,用于开发基于 web 的应用程序。Flask 依赖于 Werkzeug WSGI 工具箱和 Jinja2 模板。最终目的是帮助开发一个强大的 web 应用程序基础。
烧瓶的主要特征:
- 内置的开发服务器和快速调试器。
- RESTful 用于分派请求。
- HTTP 的请求处理。
- 集成单元测试支持(代码质量)。
- 即插即用任意对象关系映射(ORM)。
- 使用 Jinja2 模板(标签、过滤器、宏等等)。
- 基于 Unicode。
- 100%符合 WSGI 1.0。
- 社区提供的多个扩展简化了新功能的集成。
- 安全 cookies 支持。
2.FastAPI(微框架)
FastAPI 是一个现代的基于 web 的 API 构建框架,使用 Python 3.6+版本,基于标准 Python 类型,提供高性能。
FastAPI 的主要特性:
- 非常好的性能,接近 NodeJS 和 Go,因为它使用了 Starlette 和 Pydantic。目前最快的 Python 框架之一。
- 健壮:获取生产就绪代码。令人惊讶的交互式文档。
- 代码速度:提高开发特性组件的速度,接近 300%*
- 基于标准:完全兼容 API、OpenAPI 和 JSON 模式的开放标准。
- 较小的错误:减少大约 40%的开发人员引起的错误。*
- 轻松学习使用耗时更少的文档。
- 简短:来自每个参数声明的多个特性。
- 直观:强大的编辑器支持,无处不在的完成,更少的调试时间。
3.Django(全栈框架)
Django 是一个基于 Web 的 Python 框架,它是一个高级的框架,可以快速开发安全且可维护的网站。Django 消除了 web 开发的大部分问题,因此编写应用程序变得非常容易,而不必重新发明轮子。
Django 的主要特点:
- 快得不可思议的–帮助所有开发人员尽可能快地完成他们基于网络的应用程序的构思。
- 满载的–开箱即可处理内容管理、用户认证、站点地图、RSS 订阅源以及更多任务。
- 极度可伸缩性–Django 快速灵活扩展的能力是一个了不起的特性。
- 为了避免许多常见的安全错误,Django 认真对待安全性并帮助开发人员。
- 不可思议的多功能——公司和政府已经使用 Django 建立了各种各样的东西,从内容管理系统,通过社交网络,到科学计算网站。
- 帮助你在应用程序中定义 URL 的模式。
- 最终内置的认证系统。
- 简单而强大的 URL 系统和路由。
- 缓存框架、模板引擎、数据库模式迁移和 ORM。
4.金字塔(介于全栈和微框架之间)
金字塔 是一个开源的轻量级 Python web 框架,专注于将小应用程序变成大应用程序。金字塔基于模型-视图-控制器(MVC)架构模式,这是一个 WSGI web 框架。Pyramid 有一个座右铭——从小处开始,大处结束,坚持完成构建的框架在全栈和微框架之间架起了一座桥梁。
金字塔的主要特征:
- 包罗万象的模板和资产细节。
- 能够很好地运行小型和大型应用。
- 认证和批准的灵活性。
- 2 种不同的方式–web helpers 和 URL dispatch 可用于基于路由配置的 URL 映射。
- 测试、支持和综合数据文档。
- HTML 结构的验证和生成。
基于 web 的框架之间的差异
- 从烧瓶转移到 FastAPI:https://testdriven.io/blog/moving-from-flask-to-fastapi
- 姜戈 vs 弗拉斯克 vs 金字塔:https://www.airpair.com/python/posts/django-flask-pyramid
- Django 的 ORM 无法在非关系(NoSQL)数据库(如 MongoDB 或 Cassandra)上工作,而 Django 的 ORM 层允许开发人员用 Python 代码编写关系数据库读、写、查询和删除操作,而不是用 SQL。
- Web 框架,如 Pyramid & Flask,通过使用少量 Python 库,更容易与非关系数据库一起使用。
现在,进入第二种打包 ML 项目的方法——mlop。
2.用 MLOps(机器学习操作)打包 ML 项目
“人工智能运营是三个不同但合作的领域的交汇点——机器学习,DevOps &数据工程,用于操作你的人工智能模型。”
MLOps 是人工智能模型交付的学科。MLOps 使您和您的公司能够在生产环境中扩展生产能力,以提供更快、更高效的结果,产生巨大的价值。
DataOps 通过将 DevOps 的概念扩展到数据世界,提供了一种令人惊叹的方法来运营您的数据和 AI 平台。作为 DevOps 的扩展,DataOps 构建在一个相当简单的 CI/CD 框架上:持续集成、持续交付和持续部署。
当数据科学和机器学习项目缺乏坚实的框架和架构来支持模型构建、部署、治理和监控时,它们就会失败。为了取得成功,您需要数据科学团队成员(如数据科学家、DevOps 工程师、数据分析师、数据架构师和数据工程师)之间的协作,将 ML 算法产品化,并将其大规模交付到生产中。当您将这个简单但有效的框架进一步扩展到数据市场时,您会得到一个坚实的框架,这就是 MLOps。
MLOps 的 4 个核心原则
- 持续集成(CI)–代码、数据和模型的持续测试和验证。
- 连续交付(CD)–交付自动部署另一个 ML 模型预测服务的 ML 培训管道。
- 连续训练(CT)–自动重新训练 ML 模型以进行重新部署。
- 持续监控(CM)–监控生产数据和模型性能指标。
MLOps 的优势以及我们为什么需要它?
1。加速实现价值的时间
务实地优化 ML 模式的部署,以缩短从培训到生产的时间——从几个月到几分钟。因此,它会不断改进和优化,以便高效地扩展。
2。优化团队的生产力
与现有框架、工作流和工具集成,以提供透明的角色并优化瓶颈。定期监控和报告所有项目,以便做出适当的决策。
3。管理基础设施
系统地控制模型上的计算资源,以符合业务成果和性价比要求,从而大幅降低价格。部署在您想要的任何地方,本地、云或混合环境。
4。保护您的业务
跨用户、数据、ML 模型和资源建立企业级基于角色的访问和安全控制,以确保您的业务通过持续交付而发展。
MLOps 解决什么问题?
数据必须始终有一个主要的业务焦点。可操作化有助于在获得洞察力和将有价值的洞察力转化为可操作的价值之间形成闭环。简单的想法,然而执行起来一点也不简单。
建立一个机器学习运营战略可以在很多方面让你的公司或团队受益:
-
复杂的黑盒 ML 算法带来的障碍减少了,运营和数据团队的专业知识和协作得到了更好的分配。
-
随着机器学习成为主流,运营的监管前沿是一项关键职能。ML Operations 将您的运营团队置于新规则和最佳实践的前沿。他们可以掌控监管流程,而您的数据团队则专注于部署令人惊叹的模型。
-
您的运营团队拥有行业知识,而您的 DS 团队了解数据。MLOps 结合了双方的专业知识,实现了利用双方经验的有效 ML。
每个 MLOps 工具的特定功能的比较表
MLOps 功能
MLFlow
Google Kubeflow
TensorFlow Lite & TensorFlow Extended
Azure 机器学习
aws pagemaker
数据和管道版本控制
TensorFlow Lite & TensorFlow Extended:
是
Azure Machine Learning:
是
TensorFlow Lite & TensorFlow Extended:
是
Azure Machine Learning:
是
模型和实验版本化
TensorFlow Lite & TensorFlow Extended:
使用机器学习元数据(MLMD)
Azure Machine Learning:
是
超参数调整/优化
TensorFlow Lite & TensorFlow Extended:
是
Azure Machine Learning:
是
TensorFlow Lite & TensorFlow Extended:
是
Azure Machine Learning:
有限的
生产/实验跟踪中的模型部署和监控
TensorFlow Lite & TensorFlow Extended:
是
Azure Machine Learning:
是
MLOps 功能
MLFlow
Google Kubeflow
TensorFlow Lite & TensorFlow Extended
Azure 机器学习
aws pagemaker
开放源码
开放源码
Google Kubeflow:
云
TensorFlow Lite & TensorFlow Extended:
是
Azure Machine Learning:
不
TensorFlow Lite & TensorFlow Extended:
当地的
Azure Machine Learning:
云
TensorFlow Lite & TensorFlow Extended:
是
Azure Machine Learning:
是
TensorFlow Lite & TensorFlow Extended:
可扩展用于大量实验
Azure Machine Learning:
不
是
TensorFlow Lite & TensorFlow Extended:
是
Azure Machine Learning:
是
TensorFlow Lite & TensorFlow Extended:
Yes
Azure Machine Learning:
5 MLOps 工具
1.MLflow
Databricks 的 MLflow 是一个开源的 ML 生命周期管理平台。它拥有在训练和运行过程中监控 ML 模型的工具,以及存储模型、在生产代码中加载模型和构建管道的能力。MLflow 适合个人和各种规模的团队。这个神奇的工具是库不可知的。你可以把它和任何你想要的 ML 库和编程语言一起使用。
关键部件:
ml flow Tracking—记录和查询实验:数据、配置、代码&结果。对于查询,它提供了一个 web 界面。
MLflow 项目—将 ML 代码捆绑成一种格式,以便在任何平台上重现运行。它总是以一种可重用和可复制的方式提供一种打包 DS 代码的格式。除此之外,API 和命令行工具包含在项目组件中,用于运行 ML 项目,这使得将项目链接到工作流中成为一种可取的方式。
- MLflow 模型–在几种辅助环境中,可以部署 ML 模型。对于包装机器学习模型,它使用一种标准格式,可以在下游工具的混合中使用。例如,通过 Apache Spark 或 REST API 上的批处理推理进行实时服务。该格式定义了一个协议,允许您以各种“风格”保存机器学习模型,这些风格可以被各种下游工具理解。
- 模型注册–在一个中央存储库中,您可以存储、发现、管理&注释 ML 模型。
- 2. TensorFlow Lite & Tensorflow Extended
- TensorFlow Lite 是一个基于深度学习的框架,应用于设备上的推理。这是一个开源框架,提供了一套工具来实现设备上的 ML,并帮助开发人员在移动、物联网&嵌入式设备上运行他们的模型。
tensor flow Lite 的主要特性:
****设备上的 ML 优化**–处理五个重要约束:隐私、功耗、连接性、尺寸和延迟。
支持多种平台–Android&iOS 设备、微控制器、嵌入式 Linux。
- 支持多种语言–Python、Objective-C、Java、C++和 Swift。
- 性能 造高——靠硬件加速&优化机型。
- 说明性的例子是端到端的——几乎所有常见的人工智能任务,如各种平台上的问答、物体检测、姿态估计、图像分类&文本分类。
- 【tensor flow Extended(TFX)是一个端到端的机器学习平台,用于在生产中部署模型和数据管道,由 Google 实现。它是通用的,由 TensorFlow 演化而来。要将您的模型从研究阶段转移到生产阶段,您可以使用 TFX 轻松创建和管理 ML 生产管道。
- 关键部件:
TensorFlow 数据验证—探索&验证用于机器学习的数据。
TensorFlow 变换–创建变换图,这些图在训练和对可用数据进行全通分析阶段的过程中始终如一地应用。
- TensorFlow 模型分析—在海量数据集上计算全通&切片模型指标,并使用库和可视化元素进行分析。
- TensorFlow 服务—TF 服务专为生产环境而设计。这是一个灵活、高性能的机器学习模型服务系统。
- 3.Azure ML 和 Azure 管道
- Azure ML 提供以下 MLOps 功能:
帮助创建可复制的 ML 管道。 ML 管道允许您为数据准备定义可重复使用的&可重复步骤,轻松培训&模型评估技术。
创建可重用的软件环境用于训练&部署机器学习模型。
- 您可以从任何地方注册、打包和部署模型。您还可以遵循使用 ML 模型所需的关联元数据。
- 治理数据 可以被 捕获为端到端的 ML 生命周期。记录的信息包括为什么进行了更改,当 ML 模型被用于生产时,谁最终发布了模型&。
- 通知机器学习生命周期中的事件完成。示例:模型注册、数据漂移检测、模型部署&实验完成。
- 可以对机器学习应用进行监控以发现与 ML 相关的&操作问题,例如通过监控来提供关于您的 ML 基础架构指标的警报&。
- 使用 Azure ML & Azure Pipelines 等工具自动化数据科学和机器学习生命周期。使用管道有助于您定期更新机器学习模型,测试新模型,并与您的其他应用程序服务一起不断推出新模型&。
- 4. Kubeflow
- Kubeflow 是一个终极的 ML 平台,旨在使用 ML 管道来编排在 Kubernetes 上运行的复杂工作流。Kubeflow 最初是基于谷歌内部部署 TensorFlow 模型的方式,名为(TFX)TensorFlow Extended。
Kubeflow 项目致力于使机器学习工作流在 Kubernetes 上的部署变得简单、可扩展和可移植。他们的目标是提供一种简单的方法,将机器学习开源的最佳系统部署到不同的基础设施中。
kube flow 的主要特性:
为了管理和跟踪实验、运行和作业,Kubeflow 提供了一个良好的用户界面。
多框架集成& SDK 使用笔记本电脑与系统进行交互。
- 为了快速构建端到端解决方案,您可以重用所有提供的组件和管道。
- Kubeflow 中的管道既可以是 Kubeflow 的核心组件,也可以是独立安装。
- 完美适合每一个 Kubernetes 用户。无论你在哪里运行 Kubernetes,你都可以运行 Kubeflow。
- 5.AWS Sagemaker
- 亚马逊 SageMaker 是一个完整的 MLOps 生态系统,支持数据科学团队快速构建、培训、&部署任意规模的 ML 和 DL 模型。AWS SageMaker 整合了一些模块,这些模块可以共同或独立地用于训练、构建&部署您的 AI & ML 模型。它有一个工作室环境,将 Jupyter 笔记本与实验跟踪&管理、批量转换、模型监视器、具有弹性推理的部署、针对天真用户的 Auto ML 的“自动驾驶仪”以及模型调试器混合在一起。
AWS Sagemaker 的主要亮点:
亚马逊网络服务(AWS)是 2021 年 Gartner 魔力象限中的一个远见者。在评估 AWS 产品时,对大多数支持 AWS 组件&的服务进行了仔细分析。其中包括亚马逊 EMR(包括 S3)、AWS Glue、AWS CloudWatch、SageMaker Ground Truth、Amazon Clarify、Data Wrangler、SageMaker Studio IDE、SageMaker Pipelines、AWS CloudTrail、SageMaker Neo &等等。
AWS 基于地理位置而多样化,其客户群横跨多个行业和业务部门。
-
亚马逊 SageMaker 仍然是市场牵引力中的一个强大参与者,拥有可观的资源和强大的生态系统。
-
实验跟踪——如何让模型包装更顺畅
-
在一个中心位置跟踪你的机器学习实验(使用像 Neptune 这样的工具)很有帮助。Neptune 是 MLOps 的一个元数据库,为研究和生产团队开发,用于运行大量的实验(以百万计)。它为记录、存储、组织、显示、查询和比较整个 ML 生命周期中生成的所有元数据提供了一个主要位置。
用于 MLOps 的 Neptune 元数据存储=客户端库+元数据数据库+仪表板/UI(用于过滤、排序和比较实验)。
Neptune 提供了一个开源的 Python 库,允许用户记录任何实验。该工具旨在提供一种易于使用和快速学习的方法来保持所有实验的跟踪。它还集成了近 30 个针对 ML、DL 和 RL 的 Python 库。
海王星存在的 3 种主要元素:
数据版本化——有了助手,数据位置和数据散列可以记录到 Neptune。
实验跟踪——比较实验和模型(优化、经典 ML、深度学习、强化学习等),完全不需要额外的努力。
- 模型注册——跟踪模型血统和版本。
- 这三个主要元素使海王星成为 MLOps 生命周期几个部分之间的桥梁。
- 结论
就是这样——现在就在您的项目中挑选和使用的 10 ML 打包工具。在选择适合您特定需求的平台时,请确保寻找组件、功能和相关因素。这样你就能从工作中获得最大收益。
在生产中开发和部署机器学习模型一直是数据科学和 ML 生命周期的重要元素。在过去,它需要所有 ML 生命周期利益相关者的大量努力,正如我们在本文开头所看到的。打包工具有限,而且该过程是手动的,非常耗时。多亏了这些打包工具,这种情况再也不会发生了。
希望这篇文章能帮助你为你的项目选择合适的 ML 打包工具,这将使你的工作更加愉快和高效。快乐探索和学习!
参考
Vetrivel PS
他是机器学习顾问,也是 AI 领域的获奖博主。Kaggle 专家,热衷于参加黑客马拉松比赛,撰写技术笔记和博客。他喜欢分享知识&帮助初学者和数据科学爱好者成功过渡到数据科学和机器学习这一有趣的领域。
阅读下一篇
机器学习模型管理:它是什么,为什么你应该关心,以及如何实现它
13 分钟阅读|作者卡努马王子| 2021 年 7 月 13 日更新
Machine Learning Model Management: What It Is, Why You Should Care, and How to Implement It
机器学习正在兴起。因此,新的问题不断涌现,ML 开发者和技术公司一起不断构建新的工具来解决这些问题。
如果我们以一种非常基本的方式来看待 ML,我们可以说 ML 在概念上是一种增加了一点智能的软件,但与传统软件不同,ML 本质上是实验性的。与传统的软件开发相比,它有一些新的组成部分,例如:健壮的数据、模型架构、模型代码、超参数、特性等等。因此,自然地,工具和开发周期也不同。软件有 DevOps,机器学习有 MLOps。
如果听起来不熟悉,下面是 DevOps 和 MLOps 的简短概述:
DevOps 是一套开发、测试、部署和操作大规模软件系统的实践。有了 DevOps,开发周期变得更短,部署速度加快,系统发布变得可审计和可靠。
MLOps 是数据科学家和运营专业人员之间进行协作和沟通的一套实践。应用这些实践可以提高最终质量,简化管理流程,并在大规模生产环境中自动部署机器学习和深度学习模型。这使得模型更容易与业务需求和法规要求保持一致。
MLOps 的关键阶段是:
数据采集
数据分析
- 数据转换/准备
- 模型开发
- 模特培训
- 模型验证
- 模型服务
- 模型监控
- 模型再训练
- 我们将深入研究这一过程,所以拿起一杯你最喜欢的饮料,我们走吧!
- Model re-training
We’re going to do a deep dive into this process, so grab a cup of your favorite drink and let’s go!
熊猫情节:深入到直接与熊猫密谋
数据可视化是任何数据科学管道中必不可少的一步。可视化地探索数据会让你对许多其他方式看不到的东西有所了解。
使用 Python 进行可视化有几个有用的库,比如 matplotlib 或 seaborn。这些库直观且易于使用。还有 熊猫 ,主要是一个数据分析工具,但也为可视化提供了多种选择。
用熊猫来策划相当简单。在本文中,我们将了解如何使用 pandas 来探索和可视化您的数据,然后我们将更深入地研究 pandas 的一些高级可视化功能。
和熊猫一起策划
熊猫对象配备了它们的绘图功能。这些绘图函数本质上是围绕 matplotlib 库的包装器。把 matplotlib 想象成熊猫图的后端。
Pandas Plot 是一组方法,可用于 Pandas 数据帧或系列,从该数据帧中的数据绘制各种图形。Pandas Plot 简化了图形和绘图的创建,因此您不需要了解使用 matplotlib 的详细信息。
pandas 内置的可视化功能在帮助快速简单地绘制系列和数据帧方面大放异彩。
检查这个海王星-熊猫集成让你记录熊猫数据帧到海王星。
导入数据集和库
我们将使用 NIFTY-50 数据集。NIFTY 50 指数是印度 T2 国家证券交易所的印度股票市场基准。NIFTY 50 代表国家指数 50,代表 17 个行业中 50 家印度公司股票的加权平均值。该数据集在 Kaggle 上公开提供,但我们将使用仅包含四个行业股票价值的数据子集——银行、制药、IT 和快速消费品。
你可以从 这里 下载样本数据集。
让我们导入可视化所需的必要库和提取的数据集:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
nifty_bank = pd.read_csv('NIFTY BANK.csv',parse_dates=["Date"])
nifty_fmcg = pd.read_csv('NIFTY FMCG.csv',parse_dates=["Date"])
nifty_IT = pd.read_csv('NIFTY IT.csv',parse_dates=["Date"])
nifty_pharma = pd.read_csv('NIFTY PHARMA.csv',parse_dates=["Date"])
%matplotlib inline 可确保单元格运行时,所绘制的图形在笔记本中正确显示。
先来看看俏皮 50 的数据
让我们根据股票在某一天的“收盘”价格,将不同的 CSV 文件组合在一个数据框架中,并筛选出 2020 年之前的数据。
接下来让我们看看数据集的前几列:
nifty_bank_2019 = nifty_bank[nifty_bank['Date'] > '2019-12-31']
nifty_fmcg_2019 = nifty_fmcg[nifty_fmcg['Date'] > '2019-12-31']
nifty_IT_2019 = nifty_IT[nifty_IT['Date'] > '2019-12-31']
nifty_pharma_2019 = nifty_pharma[nifty_pharma['Date'] > '2019-12-31']
d = {
'NIFTY Bank index': nifty_bank_2019['Close'].values,
'NIFTY FMCG index': nifty_fmcg_2019['Close'].values,
'NIFTY IT index': nifty_IT_2019['Close'].values,
'NIFTY Pharma index': nifty_pharma_2019['Close'].values,
}
df = pd.DataFrame(data=d)
df.index=nifty_bank_2019['Date']
df.head()
Combined dataframe consisting of NIFTY indices of the bank, pharma, IT, and FMCG sectors
第一个熊猫图:线形图
现在让我们使用 pandas 来探索和可视化这些数据。首先,看看漂亮的银行指数今年的表现会很有趣。
要使用熊猫绘制图形,可以调用。dataframe 上的 plot()方法。plot 方法只是 matplotlib 的 plt.plot() 的一个简单包装。您还需要指定作为 x 和 y 轴参考的 x 和 y 坐标。因为日期已经是索引列,所以它将被配置为 X 轴。
df.plot(y='NIFTY Bank index')
Line plot showing the NIFTY Bank index performance in the year 2020
正如您在上面看到的,调用。dataframe 上的 plot()方法默认返回一个线图。在 pandas 中绘图很简单,只需要很少的设置。但是,如果需要的话,在某些参数的帮助下,有一些方法可以改变输出。
绘图参数
除了 x 和 y 之外,plot 方法还有几个参数,可以调整这些参数来改变绘图。
-
x 和 y 参数指定你想要的 x 和 y 列的值。在上面的例子中,这些是日期和漂亮的银行索引列。
-
figsize 指定图形对象的大小。
-
标题用于情节。
-
图例待放置轴上支线剧情。
-
Style :每列的 matplotlib 线条样式。
-
X 和 y 标签:用于 X 轴和 y 轴标签的名称。
-
支线剧情:为每一列制作单独的支线剧情。
-
种类:要产生的剧情种类。我们将在接下来的章节中详细讨论这个参数。
现在让我们用更多的参数绘制相同的数据帧,比如指定 figsize 和标签:
df.plot(y='NIFTY Bank index',figsize=(10,6),title='Nifty Bank Index values in 2020',ylabel = 'Value');
Notice this cool Jupyter Notebook trick: adding a semicolon to the end of the plotting call suppresses unwanted output.
《熊猫》不同的情节风格
熊猫打印方法可用于打印除默认线形打印之外的样式。这些方法都可以作为“类”关键字参数提供给****【剧情】。可用选项有:
**
Different plot styles in pandas
你是如何创造这些情节的?有两种选择:
- 使用种类参数。此参数接受字符串值,并决定您将创建哪种绘图。你可以这样做:
Dataframe.plot(kind='<kind of the desired plot e.g bar, area etc>', x,y)
- 创建绘图的另一种方法是使用“DataFrame.plot.
”方法,而不是提供 kind 关键字参数。这使得发现绘图方法及其使用的特定参数变得更加容易:
Dataframe.plot.<kind of the desired plot e.g bar, area, etc>()
Creating pandas plots by using the method DataFrame.plot.<kind>
好吧,你知道如何创建一个线图。我们现在来看看《熊猫》中的其他情节。请注意,您可以使用上面显示的任何一种方法来创建它们。
条形图
条形图是用矩形条表示分类数据的图。条形的长度与它们所代表的值成正比。
为了创建漂亮数据的条形图,您需要在月末对数据进行重新采样/汇总。pandas 的库有一个 resample()函数,它对时间序列数据进行重采样。pandas 中的重采样方法与其 groupby 方法类似,因为它本质上是根据特定的时间跨度进行分组。resample()函数如下所示:
df_sample = df.resample(rule = 'M').mean()[:5]
df_sample
Data resampled by month-end
总结一下上面发生的事情:
- data.resample()用于对股票数据进行重采样。
- “M”代表月末频率,表示您想要对数据进行重新采样的偏移值。
- mean()表示这一时期的平均股价。
现在,让我们创建如下条形图:
df_sample.plot(kind='bar',figsize=(10,6))
*Barplot showing performance of various NIFTY indices *
如上所述,您也可以在不提供“kind”参数的情况下创建相同的情节:
df_sample.plot.bar()
Barplot without providing the ‘kind’ argument.
方法的选择完全取决于你。
条形图的类型
条形图有两种类型,即:
- 水平条形图
当你想水平而不是垂直的时候。通过将“条形图”指定为图表类型,可以创建水平条形图。
df_sample.plot(kind='barh',figsize=(10,6))
Horizontal bar charts in pandas
2。堆积条形图
要生成堆积条形图,请传递 stacked=True:
df_sample.plot(kind='bar',stacked=True)
df_sample.plot(kind='barh',stacked=True)
Stacked bar plots in pandas
直方图
一个直方图是数据分布的表示。让我们只为漂亮的快速消费品索引和漂亮的银行索引创建直方图。
df[['NIFTY FMCG index','NIFTY Bank index']].plot(kind='hist',bins=30,alpha=0.5)
这里 alpha 表示透明度因子,而 bin 指的是数据被分割的范围。默认 bin 值为 10。可以使用“媒体夹”关键字更改媒体夹的大小。
Histograms in pandas
直方图可以使用 stacked=True 进行堆叠。
Stacked histogram in pandas
KDE plots
熊猫可以使用高斯核生成一个【KDE】核密度估计图。一个核密度估计图显示了单个变量的分布,可以认为是一个平滑的直方图。
df[['NIFTY FMCG index','NIFTY Bank index']].plot(kind='kde');
KDE plot in pandas
箱线图
箱线图用于通过其四分位数描绘数据。单个箱线图可以传达大量信息,包括关于四分位距、中位数和异常值的详细信息。让我们首先为我们的数据框架创建盒状图,然后你将看到如何解释它们。
df.plot(kind='box',figsize=(10,6))
Boxplots in pandas
以下是你如何解读一个方框图。
任何在异常点之外的都是那些超过胡须末端的点。您可以看到 NiFTY FMCG 比其他产品有更高的异常点。与条形图一样,也可以通过指定 vert=False 来创建水平箱线图。
df.plot(kind='box',figsize=(10,6),vert=False)
Horizontal boxplots in pandas
面积图
一个面积图直观显示定量数据。
df.plot(kind='area',figsize=(10,6));
Stacked area plot in pandas
默认情况下,pandas 创建一个堆叠面积图,可以通过传递 stacked= False 的值来取消堆叠。
df.plot(kind='area',stacked=False,figsize=(10,6));
Unstacked area plot in pandas
散点图
散点图用于绘制两个变量之间的相关性。这些相关性以不同颜色和大小的标记形式绘制。如果你要绘制一个散点图,显示 NIFTY IT 指数和 NIFTY FMCG 之间的关系,你可以这样做:
df.plot(kind='scatter',x='NIFTY FMCG index', y='NIFTY Bank index',figsize=(10,6),color='Red');
Scatter plot in pandas
六边形面元图
六边形 bin 图,也称为 hexbin 图,可用作散点图的替代图。当数据点数量巨大,并且每个点不能单独绘制时,这种绘图特别有用。
df.plot(kind='hexbin',x='NIFTY FMCG index', y='NIFTY Bank index',gridsize=20,figsize=(10,6));
Hexbin plot in pandas
饼状图
饼图是一列中数字数据的比例表示。让我们以 NIFTY 银行指数的月末重采样数据为例,看看它是如何逐月分布的。
df_sample.index=['jan','feb','march','Apr','may']
df_sample['NIFTY Bank index'].plot.pie(legend=False, autopct='%.f');
熊猫的饼状图
参数 autopct 用于使用 Python 字符串格式显示百分比值。默认情况下启用的图例可以通过指定 legend=False 来禁用。此外,如果指定了 subplots=True,则每列的饼图将绘制为 subplots。
df_sample.plot.pie(subplots=True, figsize=(16, 10),legend=False);
Pie plots for each column are drawn as subplots
Pandas 还有一个名为 pandas.plotting 的绘图模块。该模块由几个绘图函数组成,并接受一个 系列 或 数据帧 作为参数。pandas 绘图模块包含以下功能。以下描述摘自熊猫官方文件。
让我们来看看其中的几个。
散点图矩阵图
您已经看到了如何使用熊猫创建散点图。散点图矩阵,顾名思义,在 pandas 中使用 scatter_matrix 方法创建散点图矩阵。绘图:
from pandas.plotting import scatter_matrix
scatter_matrix(df, alpha=0.5, figsize=(10, 6), diagonal='kde');
A scatter matrix in pandas
自举图
Bootstrap plots 直观评估统计的不确定性,如平均值、中间值、中间值等。Bootstrapping 涉及通过多次从相同的数据中随机采样来计算统计数据,然后对每个样本的单独结果进行平均。然后将从每个随机样本中获得的结果值绘制成线图和条形图。
pd.plotting.bootstrap_plot(df['NIFTY Bank index'])
A bootstrap plot in Pandas
结论
在本文中,我们研究了 pandas 作为绘图库的功能。我们讲述了如何在 pandas 中绘制一些基本的图,并涉及了一些高级的图,如 bootstrap 和散点图。
的。plot()函数是一个非常强大的工具,可以立即帮助您开始数据可视化过程——只需很少的代码行。如果您想了解更多关于 pandas 作为绘图库的功能,以及设计和定制您的绘图,pandas DataFrame 文档的绘图部分是一个很好的起点。**
机器学习中的性能指标[完整指南]
性能指标是每个机器学习管道的一部分。他们会告诉你是否有进步,并给你一个数字。所有的机器学习模型,无论是线性回归,还是像伯特这样的 SOTA 技术,都需要一个衡量标准来判断性能。
每个机器学习任务都可以分解为回归或分类,就像性能指标一样。这两个问题有几十个度量标准,但是我们将讨论流行的标准以及它们提供的关于模型性能的信息。了解你的模型如何看待你的数据很重要!
如果你曾经参加过 Kaggle 比赛,你可能会注意到评估部分。通常情况下,他们有一个衡量你表现的标准。
指标不同于损失函数。损失函数显示了模型性能的度量。它们用于训练机器学习模型(使用某种优化,如梯度下降),它们通常在模型的参数中是可微分的。
度量用于监控和测量模型的性能(在训练和测试期间),并且不需要可区分。
然而,如果对于某些任务,性能度量是可微分的,那么它也可以用作损失函数(可能添加了一些正则化),例如 MSE。
如果你正在寻找一种自动化的方法来监控你的模型的性能指标,请查看 neptune.ai 。这里是解释跟踪度量如何工作的文档(有例子)。
回归度量
回归模型有连续的输出。因此,我们需要一个基于计算预测和实际情况之间某种距离的度量。
为了评估回归模型,我们将详细讨论这些指标:
- 平均绝对误差(MAE),
- 均方误差(MSE),
- 均方根误差(RMSE),
- R (R 的平方)。
注意:我们将使用波士顿住宅数据集来实现回归指标。你可以在这里找到笔记本,里面包含了本博客使用的所有代码。
均方误差
均方差可能是回归问题中最常用的度量。它实际上是找到目标值和回归模型预测值之间的平均平方差。
其中:
- y_j:地面真实值
- y_hat:回归模型的预测值
- n:基准数
与 MSE 相关的几个要点:
- 它是可微的,所以可以更好地优化。
- 它通过平方它们来惩罚甚至很小的错误,这实质上导致了对模型有多差的高估。
- 误差解释必须考虑平方因子(标度)。例如,在我们的波士顿住房回归问题中,我们得到 MSE=21.89,它主要对应于(价格)。
- 由于平方因子,它比其他指标更容易出现异常值。
这可以简单地用 Python 中的 NumPy 数组来实现。
mse = (y-y_hat)**2
print(f"MSE: {mse.mean():0.2f} (+/- {mse.std():0.2f})")
平均绝对误差
平均绝对误差是实际值和预测值之间差值的平均值。数学上,它表示为:
其中:
- y_j:地面真实值
- y_hat:回归模型的预测值
- n:基准数
MAE 的几个关键点
- 对于异常值,它比 MAE 更健壮,因为它没有夸大错误。
- 它为我们提供了预测与实际产出之间的差距。然而,由于 MAE 使用残差的绝对值,它不能给我们一个误差方向的概念,即我们是否低估或高估了数据。
- 错误解释不需要第二个想法,因为它完全符合变量的原始程度。
- MAE 是不可微的,而 MSE 是可微的。
与 MSE 类似,这个指标也很容易实现。
mae = np.abs(y-y_hat)
print(f"MAE: {mae.mean():0.2f} (+/- {mae.std():0.2f})")
均方根误差(RMSE)
均方根误差对应于目标值和回归模型预测值之间的平方差的平均值的平方根。基本上就是 sqrt(MSE)。数学上它可以表示为:
它解决了 MSE 的一些缺点。
与 RMSE 相关的几个要点:
- 它保留了 MSE 的可微性。
- 它通过平方根处理 MSE 产生的较小错误的惩罚。
- 误差解释可以顺利完成,因为规模现在是相同的随机变量。
- 因为比例因子本质上是标准化的,所以在异常值的情况下不太容易挣扎。
实现类似于 MSE:
mse = (y-y_hat)**2
rmse = np.sqrt(mse.mean())
print(f"RMSE: {rmse:0.2f}")
决定系数
r 决定系数实际上是一个后指标,这意味着它是一个使用其他指标计算的指标。
甚至计算这个系数的意义在于回答问题“Y(目标)的总变化有多少(什么%)是由 X(回归线)的变化解释的”
这是使用误差平方和计算的。让我们通过公式来更好地理解它。
Y 的总变化(Y 的方差):
描述回归线的变化百分比:
随后,变异百分比描述了回归线:
最后,我们有决定系数的公式,它可以告诉我们回归线的拟合程度有多好或多差:
这个系数可以简单地用 Python 中的 NumPy 数组实现。
SE_line = sum((y-y_hat)**2)
SE_mean = sum((y-y.mean())**2)
r2 = 1-(SE_line/SE_mean)
print(f"R^2 coefficient of determination: {r2*100:0.2f}%")
与 R 结果相关的直觉很少:
- 如果回归线的误差平方和很小=> R 将接近 1(理想值),这意味着回归能够捕获目标变量中 100%的方差。
- 相反,如果回归线的误差平方和很高=> R 将接近于 0,这意味着回归不能捕捉目标变量的任何方差。
- 你可能认为 R 的范围是(0,1),但实际上是(-∞,1),因为如果回归线的平方误差太高(>平均值的平方误差),回归线和平均值的平方误差之比可以超过值 1。
调整后 R
香草 R 方法有一些缺点,比如误导研究者相信当分数增加时模型在改进,但实际上,学习并没有发生。当模型过度拟合数据时会发生这种情况,在这种情况下,解释的方差将是 100%,但学习尚未发生。为了纠正这一点,R 根据独立变量的数量进行调整。
调整后的 R 始终低于 R,因为它针对增加的预测因子进行了调整,并且只有在确实有改善的情况下才显示出改善。
其中:
- n =观察次数
- k =独立变量的数量
- Ra =调整后的 R
分类指标
分类问题是世界上研究最广泛的领域之一。用例存在于几乎所有的生产和工业环境中。语音识别、人脸识别、文本分类——不胜枚举。
分类模型有离散的输出,所以我们需要一个以某种形式比较离散类的度量。分类度量标准评估一个模型的性能,并告诉你分类的好坏,但它们中的每一个都以不同的方式评估它。
因此,为了评估分类模型,我们将详细讨论这些指标:
- 准确(性)
- 混淆矩阵(不是一个度量标准,但对其他人来说是基本的)
- 精确度和召回率
- f1-分数
- 奥-罗克
注意:我们将使用 UCI 乳腺癌数据集来实现分类指标。你可以在这里找到笔记本,里面包含了本博客使用的所有代码。
准确(性)
分类准确度可能是使用和实现最简单的度量,定义为正确预测的数除以预测总数乘以 100 。
我们可以通过在一个循环中比较实际值和预测值来实现这一点,或者简单地利用 scikit-learn 模块来为我们完成繁重的工作(在本例中没有那么重)。
从从度量类导入 accuracy_score 函数开始。
from sklearn.metrics import accuracy_score
然后,只需传递基本事实和预测值,就可以确定模型的准确性:
print(f'Accuracy Score is {accuracy_score(y_test,y_hat)}')
混淆矩阵
混淆矩阵是地面实况标签与模型预测的可视化表格。混淆矩阵的每一行代表预测类中的实例,每一列代表实际类中的实例。混淆矩阵不完全是一个性能指标,而是一种其他指标评估结果的基础。
为了理解混淆矩阵,我们需要为作为假设的零假设设置一些值。例如,从我们的乳腺癌数据中,让我们假设我们的零假设 H⁰ 是“该个体患有癌症”。
Confusion Matrix for H⁰
混淆矩阵中的每个单元代表一个评估因子。让我们逐一了解这些因素:
- 真阳性(TP) 表示您的模型正确预测了多少阳性类别样本。
- True Negative(TN) 表示您的模型正确预测了多少个负类样本。
- 假阳性(FP) 表示您的模型错误预测了多少个阴性类别样本。这个因子代表统计术语中的I 型误差。混淆矩阵中的错误定位取决于零假设的选择。
- 假阴性(FN) 表示您的模型错误预测了多少阳性类别样本。该因子代表统计术语中的II 型误差。混淆矩阵中的错误定位也取决于零假设的选择。
我们可以使用下面的代码计算单元格的值:
def find_TP(y, y_hat):
return sum((y == 1) & (y_hat == 1))
def find_FN(y, y_hat):
return sum((y == 1) & (y_hat == 0))
def find_FP(y, y_hat):
return sum((y == 0) & (y_hat == 1))
def find_TN(y, y_hat):
return sum((y == 0) & (y_hat == 0))
我们将使用逻辑回归分类器中的两组超参数来查看两种不同状态下的混淆矩阵。
from sklearn.linear_model import LogisticRegression
clf_1 = LogisticRegression(C=1.0, class_weight={0:100,1:0.2}, dual=False, fit_intercept=True,
intercept_scaling=1, l1_ratio=None, max_iter=100,
multi_class='auto', n_jobs=None, penalty='l2',
random_state=None, solver='lbfgs', tol=0.0001, verbose=0,
warm_start=False)
clf_2 = LogisticRegression(C=1.0, class_weight={0:0.001,1:900}, dual=False, fit_intercept=True,
intercept_scaling=1, l1_ratio=None, max_iter=100,
multi_class='auto', n_jobs=None, penalty='l2',
random_state=None, solver='lbfgs', tol=0.0001, verbose=0,
warm_start=False)
精确
精度是预测的真阳性和总阳性的比率:
0
精度度量关注于类型 I 误差 (FP)。当我们拒绝一个真正的空 Hypothesis(H⁰时,就会出现一个第一类错误。因此,在这种情况下,第一类错误是错误地将癌症患者标记为非癌症患者。
精度分数接近 1 将意味着您的模型没有遗漏任何真正的阳性,并且能够很好地区分癌症患者的正确和错误标记。它不能测量的是第二类错误的存在,即假阴性,即非癌症患者被识别为癌症患者的情况。
低精度分数(< 0.5)意味着您的分类器有大量的假阳性,这可能是不平衡的类或未调整的模型超参数的结果。在不平衡类问题中,为了抑制 FP/FN,你必须事先准备好数据,包括过采样/欠采样或焦点损失。
对于第一组超参数:
TP = find_TP(y, y_hat)
FN = find_FN(y, y_hat)
FP = find_FP(y, y_hat)
TN = find_TN(y, y_hat)
print('TP:',TP)
print('FN:',FN)
print('FP:',FP)
print('TN:',TN)
precision = TP/(TP+FP)
print('Precision:',precision)
上述代码片段的输出
通过查看混淆矩阵值,您可能已经猜到,FP 为 0,因此对于给定超参数设置的 100%精确模型来说,该条件是完美的。在这种情况下,没有 I 型错误被报告,因此该模型在抑制错误地将癌症患者标记为非癌症患者方面做了大量工作。
对于第二组超参数:
TP = find_TP(y, y_hat)
FN = find_FN(y, y_hat)
FP = find_FP(y, y_hat)
TN = find_TN(y, y_hat)
print('TP:',TP)
print('FN:',FN)
print('FP:',FP)
print('TN:',TN)
precision = TP/(TP+FP)
print('Precision:',precision)
上述代码片段的输出
由于在这种设置中只剩下第一类误差,因此尽管第二类误差为 0,但精度会下降。
我们可以从我们的例子中推断出,只有精度不能告诉你你的模型在各种情况下的性能。
回忆/敏感度/命中率
一个回忆本质上是真实的肯定与地面真相中所有肯定的比率。
0
召回指标侧重于类型二错误 (FN)。当我们接受一个假的空 hypothesis(H⁰) 时,就会出现第二类错误。因此,在这种情况下,第二类错误是错误地将非癌症患者标记为癌症患者。
向 1 回忆将意味着你的模型没有错过任何真正的阳性,并且能够很好地分类正确和错误标记的癌症患者。
它不能测量的是 I 型错误的存在,这是假阳性,即癌症患者被识别为非癌症患者的情况。
低召回分数(< 0.5)意味着您的分类器有大量的假阴性,这可能是不平衡的类或未调整的模型超参数的结果。在不平衡类问题中,为了抑制 FP/FN,你必须事先准备好数据,包括过采样/欠采样或焦点损失。
对于第一组超参数:
TP = find_TP(y, y_hat)
FN = find_FN(y, y_hat)
FP = find_FP(y, y_hat)
TN = find_TN(y, y_hat)
print('TP:',TP)
print('FN:',FN)
print('FP:',FP)
print('TN:',TN)
recall = recall_score(y, y_hat)
print('Recall: %f' % recall)
上述代码片段的输出
从上述混淆矩阵值来看,第一类错误的可能性为 0,而第二类错误的可能性很大。这就是低召回分数背后的原因。它只关注第二类错误。
对于第二组超参数:
TP = find_TP(y, y_hat)
FN = find_FN(y, y_hat)
FP = find_FP(y, y_hat)
TN = find_TN(y, y_hat)
print('TP:',TP)
print('FN:',FN)
print('FP:',FP)
print('TN:',TN)
recall = recall_score(y, y_hat)
print('Recall: %f' % recall)
上述代码片段的输出
这个集合中唯一持久的错误是 I 类错误,没有报告 II 类错误。这意味着这个模型在遏制错误地将非癌症患者标记为癌症方面做了很大的工作。
以上两个度量标准的主要亮点是它们都只能在特定的场景中使用,因为它们都只能识别一组错误。
精确-召回权衡
要改进你的模型,你可以提高精确度或召回率,但不能两者兼得!如果您试图减少非癌症患者被标记为癌症(FN/II 型)的病例,对被标记为非癌症的癌症患者不会产生直接影响。
这里有一个描绘同样权衡的图:
from sklearn.metrics import plot_precision_recall_curve
disp = plot_precision_recall_curve(clf, X, y)
disp.ax_.set_title('2-class Precision-Recall curve: '
'AP={0:0.2f}'.format(precision))
这种权衡对真实场景有很大的影响,因此我们可以推断,仅仅依靠精确度和召回率并不是很好的衡量标准。这就是为什么你会看到许多公司报告和在线竞赛敦促提交指标是精确度和召回的结合。
f1-分数
F1 得分指标结合了精确度和召回率。其实 F1 的分数就是两者的调和平均值。这两个公式本质上是:
现在,高 F1 分数象征着高精确度和高回忆。它在精确度和召回率之间呈现了良好的平衡,并且在不平衡分类问题上给出了良好的结果。
F1 分数低(几乎)说明不了什么——它只能告诉你在某个阈值时的表现。低召回率意味着我们没有尽力在整个测试集的大部分上做得很好。低精度意味着,在我们识别为阳性的病例中,我们没有正确识别出许多病例。
但是低 F1 并没有说是哪些情况。高 F1 意味着我们可能对决策的大部分具有高精确度和高回忆性(这是信息性的)。F1 低,不清楚是什么问题(低精度还是低召回?),以及模型是否遭受 I 型或 II 型误差。
那么,F1 只是一个噱头吗?不完全是,它被广泛使用,并被认为是收敛到决策的一个很好的度量,但也有一些调整。将 FPR(假阳性率)与 F1 一起使用将有助于抑制 I 型错误,并且您将了解 F1 分数低背后的元凶。
对于第一组超参数:
f1_score = 2*((precision*recall)/(precision+recall))
print('F1 score: %f' % f1_score)
如果你还记得我们在 set-I 参数中的得分,P=1,R=0.49。因此,通过使用这两个指标,我们得到了 0.66 的分数,这并没有给你什么类型的错误是显著的信息,但在推断模型的性能时仍然是有用的。
对于第二组超参数:
f1_score = 2*((precision*recall)/(precision+recall))
print('F1 score: %f' % f1_score)
对于第二组,参数为 P=0.35,R=1。因此,F1 分数在某种程度上总结了 P 和 r 之间的界限。尽管如此,低 F1 并不能告诉你发生了哪个错误。
F1 无疑是判断模型性能最流行的指标之一。它实际上是被称为 F 分数的更广泛指标的子集。
输入β= 1 将得到 F1 的分数。
受试者工作特性曲线下面积
更好地称为 AUC-ROC 评分/曲线。它利用真阳性率(TPR)和假阳性率(FPR)。
- 直觉上 TPR/recall 对应于相对于所有正数据点被正确认为是正的正数据点的比例。换句话说,TPR 越高,我们错过的正面数据点就越少。
- 直觉上FPR/辐射对应于相对于所有负数据点而言被错误地认为是正的负数据点的比例。换句话说,FPR 越高,我们错误分类的负面数据点就越多。
为了将 FPR 和 TPR 组合成一个单一指标,我们首先使用许多不同的逻辑回归阈值来计算前两个指标,然后将它们绘制在一个图表上。得到的曲线称为 ROC 曲线,我们考虑的度量是这条曲线下的面积,我们称之为 AUROC。
from sklearn.metrics import roc_curve
from sklearn.metrics import roc_auc_score
from matplotlib import pyplot
ns_probs = [0 for _ in range(len(y))]
lr_probs = clf_1.predict_proba(X)
lr_probs = lr_probs[:, 1]
ns_auc = roc_auc_score(y, ns_probs)
lr_auc = roc_auc_score(y, lr_probs)
print('No Skill: ROC AUC=%.3f' % (ns_auc))
print('Logistic: ROC AUC=%.3f' % (lr_auc))
ns_fpr, ns_tpr, _ = roc_curve(y, ns_probs)
lr_fpr, lr_tpr, _ = roc_curve(y, lr_probs)
pyplot.plot(ns_fpr, ns_tpr, linestyle='--', label='No Skill')
pyplot.plot(lr_fpr, lr_tpr, marker='.', label='Logistic')
pyplot.xlabel('False Positive Rate')
pyplot.ylabel('True Positive Rate')
pyplot.legend()
pyplot.show()
No Skill: ROC AUC=0.500
Logistic: ROC AUC=0.996
无技能分类器是一种不能区分类别的分类器,在所有情况下都会预测随机类别或固定类别。无技能线的变化是基于积极类和消极类的分布。它是一条水平线,带有数据集中阳性病例的比率值。对于平衡数据集,它是 0.5。
该面积等于随机选择的正面例子排名在随机选择的负面例子之上的概率(被认为正面的概率高于负面的概率)。
因此,高 ROC 仅仅意味着随机选择的正例的概率确实是正的。高 ROC 也意味着你的算法在排列测试数据方面做得很好,大部分负面情况在一个范围的一端,而正面情况在另一端。
当你的问题存在巨大的阶级不平衡时,ROC 曲线不是一个好的选择。其中的原因并不简单,但可以通过公式直观地看出,你可以在这里了解更多信息。在处理不平衡集或使用焦点损失技术后,您仍然可以在这种情况下使用它们。
除了学术研究和比较不同的分类器之外,AUROC 指标没有其他用途。
结论
我希望您现在理解了性能度量在模型评估中的重要性,并且知道一些古怪的小技巧来理解您的模型的灵魂。
需要注意的一件非常重要的事情是,您可以调整这些指标来迎合您的特定用例。
举个例子,拿一个加权 F1 分。它计算每个标签的指标,并根据支持度(每个标签的真实实例数)找到它们的平均权重。
另一个例子可以是加权精度,或者用技术术语来说:平衡精度。二元和多类分类问题中的平衡精度用于处理不平衡数据集。它被定义为每节课的平均回忆。就像我们提到的,【迎合特定用例】,就像不平衡的类。
你可以在这里找到包含本博客中使用的所有代码的笔记本。
继续实验!
就这些了,感谢您的阅读,敬请期待更多内容!再见!
参考
必不可少的 Pil(枕头)图像教程(针对机器学习的人)
原文:https://web.archive.org/web/https://neptune.ai/blog/pil-image-tutorial-for-machine-learning
PIL 代表 Python 图像库。在本文中,我们将看看它的分叉:枕头。PIL 从 2011 年起就没有更新过,所以枕头的情况很明显。
该库支持各种图像格式,包括流行的 JPEG 和 PNG 格式。你会考虑使用枕头的另一个原因是,它很容易使用,而且很受皮托尼斯塔的欢迎。该软件包是大多数处理图像的数据科学家的常用工具。
它还提供了各种图像处理方法,我们将在本文中看到。这些技术非常有用,尤其是在增加计算机视觉问题的训练数据方面。
以下是您可以期望了解到的内容:
- 如何安装
- 枕头的基本概念
- 枕头图像类
- 用 PIL/枕头阅读和书写图像
- 枕头图像操作,例如裁剪和旋转图像
- 使用枕形滤波器增强图像,例如提高图像质量的滤波器
- 在 PIL 处理图像序列(gif)
我们走吧!
安装注意事项
枕头可以通过 pip 安装。
pip install Pillow
需要注意的是,枕头和 PIL 包不能在同一环境中共存。因此,确保在安装枕头时没有安装 PIL。
现在拿起你的枕头,我们开始吧。
PIL 形象的基本概念
我们将从理解几个关键的 PIL 形象概念开始。
为了看到这些概念的实际应用,让我们从使用 Pillow 加载这个图像开始。第一步是从 PIL 进口Image
级。我们将在下一部分详细讨论Image
类。
注意:
我们从 PIL 而不是枕头导入图像类,因为枕头是 PIL 叉子。因此,展望未来,你应该期待从 PIL 进口,而不是枕头。
from PIL import Image
im = Image.open("peacock.png")
加载完图像后,让我们开始讨论那些图像概念。
波段
每个图像都有一个或多个条带。使用 Pillow,我们可以在图像中存储一个或几个波段。例如,一幅彩色图像通常分别有红色、蓝色和绿色的“R”、“G”和“B”波段。
下面是我们如何为上面导入的图像获取波段。
im.getbands()
('R', 'G', 'B')
模式
模式是指图像中像素的类型和深度。目前支持的一些模式有:
- l 代表黑色和白色
- 真彩色的 RGB
- 带透明遮罩的真彩色 RGBA
- 彩色视频格式的 YCbCr
下面是我们如何获取上面加载的图像的模式:
im.mode
'RGB'
尺寸
我们还可以通过图像属性获得图像的尺寸。
注意:
上面加载的图像非常大,所以我缩小了尺寸,以便在本文后面的部分更容易看到。
im.size
(400, 600)
坐标系
枕包使用笛卡尔像素坐标系。在本文的后面部分,我们将使用这个概念,所以理解它是至关重要的。在这个系统中:
- (0,0)是左上角
- 坐标作为元组以(x,y)的形式传递
- 矩形被表示为 4 个元组,首先提供左上角。
了解图像类
正如我们前面提到的,在读入我们的映像之前,我们必须从 PIL 导入Image
类。这个类包含的函数使我们能够加载图像文件以及创建新的图像。接下来,我们将使用的函数已经作为导入Image
的结果被导入,除非另有说明。
加载并保存图像
我们已经看到,我们可以使用Image.open("peacock.jpg")
加载图像,其中peacock.jpg
是图像位置的路径。
从字符串中读取
为了演示如何使用 Pillow 读入图像字符串,我们将首先通过 base64 将图像转换为字符串。
import base64
with open("peacock.jpg", "rb") as image:
image_string = base64.b64encode(image.read())
我们现在可以解码图像字符串,并使用 PIL 的Image
类将其作为图像加载。
import io
image = io.BytesIO(base64.b64decode(image_string))
Image.open(image)
转换成 JPEG
现在让我们举一个例子,看看如何将一幅图像转换成 JPEG 格式。
PIL 保存图像
图像转换是通过读入图像并以新格式保存来实现的。这里是我们如何将孔雀 PNG 图像转换为 JPEG 格式。
im.save('peacock.jpg')
创建 JPEG 缩略图
在某些情况下,我们会对缩小图像的尺寸感兴趣。
例如,为了获得图像的缩略图,可以缩小图像的尺寸。这可以通过定义缩略图的大小并将其传递给thumbnail
图像函数来实现。
size = 128, 128
im.thumbnail(size)
im.save('thumb.png')
图像处理
我们已经看到,我们可以操纵图像的各个方面,如大小。让我们更深入一点,看看其他方面,如图像旋转和颜色转换-仅举几个例子。
裁剪图像
为了裁剪一个图像,我们首先定义一个框来指定我们想要裁剪的图像区域。接下来,我们将这个盒子传递给Image
类的“crop”函数。
im = Image.open('peacock.jpg')
box = (100, 150, 300, 300)
cropped_image = im.crop(box)
cropped_image
旋转图像
旋转图像是通过Image
类的rotate
函数完成的。
rotated = im.rotate(180)
rotated
合并图像
该软件包还允许我们合并两个图像。让我们通过将一个徽标合并到孔雀图像中来说明这一点。我们从进口开始。
logo = Image.open('logo.png')
现在让我们定义标志的位置,并合并两个图像。
position = (38, 469)
im.paste(logo, position)
im.save('merged.jpg')
此操作将取代原始图像。所以,如果想保留原图,可以做一个拷贝。
image_copy = image.copy()
现在,如果您使用 PNG 图像,您可以利用 Pillow 的遮罩功能来消除黑色背景。
im = Image.open("peacock.jpg")
image_copy = im.copy()
position = ((image_copy.width - logo.width), (image_copy.height - logo.height))
image_copy.paste(logo, position,logo)
image_copy
翻转图像
现在让我们看看如何翻转上面的图像。这是使用“翻转”方法完成的。一些翻转选项是FLIP_TOP_BOTTOM
和FLIP_LEFT_RIGHT
。
im.transpose(Image.FLIP_TOP_BOTTOM)
PIL 图像到 NumPy 数组
Pillow 还允许我们将图像转换成 NumPy 数组。将图像转换为 NumPy 数组后,我们可以使用 PIL 读取它。
import numpy as np
im_array = np.array(im)
随着图像的转换,我们现在可以使用枕头加载它。这是使用 Pillow 的 Image 类的fromarray
函数完成的。最后,我们使用 PIL show
图像功能保存并显示图像。
img = Image.fromarray(im_array, 'RGB')
img.save('image.png')
img.show()
颜色变换
我们可以将彩色图像转换成黑白图像,反之亦然。这是通过 convert 函数并传递首选颜色格式来完成的。
im.convert('L')
可以用类似的方式转换成彩色。
im.convert('RGBA')
在图像上绘图
我们马上就要结束了,在此之前让我们再看几个项目,包括图片上的画。Pillow 允许通过ImageDraw
模块来完成,因此,我们从导入它开始。
from PIL import ImageDraw
我们将从定义一个大小为 400×400 的空白彩色图像开始。然后我们使用ImageDraw
来绘制图像。
image = Image.new('RGB', (400, 400))
img_draw = ImageDraw.Draw(image)
现在我们可以使用ImageDraw
对象在图像上绘制一个矩形。我们用白色填充它,给它一个红色的轮廓。使用相同的对象,我们可以在图像上写一些文字,如图所示。
img_draw.rectangle((100, 30, 300, 200), outline='red', fill='white')
img_draw.text((150, 100), 'Neptune AI', fill='red')
image.save('drawing.jpg')
图像增强
Pillow 还附带了使我们能够执行图像增强的功能。这是一个提高图像原始质量的过程。
我们从导入提供这些功能的模块开始。
from PIL import ImageEnhance
例如,我们可以调整图像的锐度:
from PIL import ImageEnhance
enhancer = ImageEnhance.Sharpness(im)
enhancer.enhance(10.0)
让我们再举一个例子,我们把图像的亮度加倍。
enhancer = ImageEnhance.Contrast(im)
enhancer.enhance(2)
过滤器
我们可以用 Pillow 做的另一件超级酷的事情是给图像添加滤镜。第一步是导入ImageFilter
模块。
from PIL import ImageFilter
例如,我们可以像这样模糊图像:
from PIL import ImageFilter
im = Image.open("peacock.jpg")
im.filter(ImageFilter.BLUR)
其他可用的过滤器包括:
im.filter(ImageFilter.CONTOUR)
im.filter(ImageFilter.DETAIL)
im.filter(ImageFilter.EDGE_ENHANCE)
im.filter(ImageFilter.EMBOSS)
im.filter(ImageFilter.FIND_EDGES)
在 PIL 处理图像序列(gif)
我们也可以加载图像序列,如 GIF 图像。先来导入图像序列模块。
from PIL import ImageSequence
接下来,我们将加载一个 GIF 文件,并将前两帧保存为 PNG 文件。因为帧太多,我们中断了循环。
im = Image.open("embeddings.GIF")
frame_num = 1
for frame in ImageSequence.Iterator(im):
frame.save("frame%d.png" % frame_num)
frame_num = frame_num + 1
if frame_num == 3:
break
让我们来看一个已经保存为 PNG 文件的帧。
最后的想法
希望这篇文章能让你对如何在图像处理管道中应用 Pillow 有所了解。
这种用例的一个例子是在图像分割问题中使用的图像增强序列。这将帮助您创建更多的图像实例,最终提高图像分割模型的性能。
现在,让我们回顾一下我们讲述的一些内容:
- 安装 PIL/枕头的过程
- 枕头的基本概念
- 使用 PIL/Pillow 中的图像类
- 在 PIL/枕头上阅读和书写图像
- 在 Pillow 中处理图像
- 使用枕头提高图像质量
- 给图像添加滤镜
- 读取图像序列(gif)
- 将枕头图像转换为数字图像
你可以马上开始应用你在这篇文章中学到的技巧。一个很好的应用示例是深度学习模型的图像增强。综合增加训练数据的数量是提高模型性能的最佳(也是最简单)方法之一。
试试吧!
德里克·姆维蒂
Derrick Mwiti 是一名数据科学家,他对分享知识充满热情。他是数据科学社区的热心贡献者,例如 Heartbeat、Towards Data Science、Datacamp、Neptune AI、KDnuggets 等博客。他的内容在网上被浏览了超过一百万次。德里克也是一名作家和在线教师。他还培训各种机构并与之合作,以实施数据科学解决方案并提升其员工的技能。你可能想看看他在 Python 课程中完整的数据科学和机器学习训练营。
阅读下一篇
Python 中的图像处理:你应该知道的算法、工具和方法
9 分钟阅读|作者 Neetika Khandelwal |更新于 2021 年 5 月 27 日
图像定义了世界,每张图像都有自己的故事,它包含了许多在许多方面都有用的重要信息。这些信息可以借助于被称为图像处理的技术来获得。
它是计算机视觉的核心部分,在机器人、自动驾驶汽车和物体检测等许多现实世界的例子中起着至关重要的作用。图像处理允许我们一次转换和操作数千幅图像,并从中提取有用的见解。它在几乎每个领域都有广泛的应用。
Python 是为此目的广泛使用的编程语言之一。它惊人的库和工具有助于非常有效地完成图像处理任务。
通过本文,您将了解处理图像并获得所需输出的经典算法、技术和工具。
让我们开始吧!
Pix2pix:关键模型架构决策
原文:https://web.archive.org/web/https://neptune.ai/blog/pix2pix-key-model-architecture-decisions
生成对抗网络或 GANs 是一种属于无监督学习类的神经网络。它用于深度生成建模的任务。
在深度生成建模中,深度神经网络学习一组给定数据点上的概率分布,并生成相似的数据点。由于这是一个无人监督的学习任务,它在学习过程中不使用任何标签。
自 2014 年发布以来,深度学习社区一直在积极开发新的 gan,以改善生成建模领域。本文旨在提供关于 GAN 的信息,特别是 Pix2Pix GAN,它是最常用的生成模型之一。
甘是什么?
GANs 由 Ian Goodfellow 在 2014 年设计。GANs 的主要意图是生成不模糊且具有丰富特征表示的样本。判别模型在这方面做得很好,因为它们能够在不同的类别之间进行分类。另一方面,深度生成模型的效率要低得多,因为在自动编码器中,很难近似许多棘手的概率计算。
自动编码器及其变体是显式似然模型,这意味着它们显式计算给定分布的概率密度函数。gan 及其变体是隐式似然模型,这意味着它们不计算概率密度函数,而是学习潜在的分布。
gan 通过将整个问题作为一个二进制分类问题来处理,来学习底层分布。在这种方法中,问题模型由两个模型表示:生成器和鉴别器。生成器的工作是生成新的样本,鉴别器的工作是分类或鉴别生成器生成的样本是真是假。
这两个模型在零和游戏中一起训练,直到生成器可以产生与真实样本相似的样本。或者换句话说,他们被训练到生成器可以骗过鉴别器。
香草甘的架构
先简单了解一下 GANs 的架构。从这一节开始,大多数主题将使用代码进行解释。首先,让我们定义所有需要的依赖项。
import torch
import torch.nn as nn
import torch.optim as optim
from torch.autograd import Variable
import matplotlib.pyplot as plt
import torchvision
import torchvision.datasets as datasets
from torch.utils.data import DataLoader
import torchvision.transforms as transforms
发电机
生成器是 GAN 中的一个组件,它接收定义为高斯分布的噪声,并产生与原始数据集相似的样本。随着 GANs 多年来的发展,他们已经采用了在计算机视觉任务中非常突出的 CNN。但是为了简单起见,我们将使用 Pytorch 用线性函数来定义它。
class Generator(nn.Module):
def __init__(self, z_dim, img_dim):
super().__init__()
self.gen = nn.Sequential(
nn.Linear(z_dim, 256),
nn.LeakyReLU(0.01),
nn.Linear(256, img_dim),
nn.Tanh(),
)
def forward(self, x):
return self.gen(x)
鉴别器
鉴别器只是一个分类器,它对生成器生成的数据是真是假进行分类。它通过从真实数据中学习原始分布,然后在两者之间进行评估来实现这一点。我们将保持简单,使用线性函数定义鉴别器。
class Discriminator(nn.Module):
def __init__(self, in_features):
super().__init__()
self.disc = nn.Sequential(
nn.Linear(in_features, 128),
nn.LeakyReLU(0.01),
nn.Linear(128, 1),
nn.Sigmoid(),
)
def forward(self, x):
return self.disc(x)
生成器和鉴别器的关键区别是最后一层。前者产生与图像相同的形状,而后者只产生一个输出,0 或 1。
损失函数和训练
损失函数是任何深度学习算法中最重要的组件之一。例如,如果我们设计一个 CNN 来最小化真实情况和预测结果之间的欧几里德距离,它将倾向于产生模糊的结果。这是因为欧几里德距离通过平均所有可能的输出而最小化,这导致了模糊。
以上这一点很重要,我们必须记住。也就是说,我们将用于普通 GAN 的损失函数将是二进制交叉熵损失或 BCELoss,因为我们正在执行二进制分类。
criterion = nn.BCELoss()
现在我们来定义一下优化方法以及其他相关参数。
opt_disc = optim.Adam(disc.parameters(), lr=lr)
opt_gen = optim.Adam(gen.parameters(), lr=lr)
device = "cuda" if torch.cuda.is_available() else "cpu"
lr = 3e-4
z_dim = 64
image_dim = 28 * 28 * 1
batch_size = 32
num_epochs = 100
dataset = datasets.MNIST(root="dataset/", transform=transforms, download=True)
loader = DataLoader(dataset, batch_size=batch_size, shuffle=True)
writer_fake = SummaryWriter(f"logs/fake")
writer_real = SummaryWriter(f"logs/real")
step = 0
我们来理解一下训练循环。甘的训练循环开始于:
- 使用高斯分布从生成器生成样本
- 使用生成器产生的真实数据和虚假数据训练鉴别器
- 更新鉴别器
- 更新生成器
下面是训练循环的样子:
for epoch in range(num_epochs):
for batch_idx, (real, _) in enumerate(loader):
real = real.view(-1, 784).to(device)
batch_size = real.shape[0]
noise = torch.randn(batch_size, z_dim).to(device)
fake = gen(noise)
disc_real = disc(real).view(-1)
lossD_real = criterion(disc_real, torch.ones_like(disc_real))
disc_fake = disc(fake).view(-1)
lossD_fake = criterion(disc_fake, torch.zeros_like(disc_fake))
lossD = (lossD_real + lossD_fake) / 2
disc.zero_grad()
lossD.backward(retain_graph=True)
opt_disc.step()
output = disc(fake).view(-1)
lossG = criterion(output, torch.ones_like(output))
gen.zero_grad()
lossG.backward()
opt_gen.step()
if batch_idx == 0:
print(
f"Epoch [{epoch}/{num_epochs}] Batch {batch_idx}/{len(loader)}
Loss D: {lossD:.4f}, loss G: {lossG:.4f}"
)
with torch.no_grad():
fake = gen(fixed_noise).reshape(-1, 1, 28, 28)
data = real.reshape(-1, 1, 28, 28)
img_grid_fake = torchvision.utils.make_grid(fake, normalize=True)
img_grid_real = torchvision.utils.make_grid(data, normalize=True)
writer_fake.add_image(
"Mnist Fake Images", img_grid_fake, global_step=step
)
writer_real.add_image(
"Mnist Real Images", img_grid_real, global_step=step
)
step += 1
以上循环的要点:
- 鉴别器的损失函数计算两次:一次用于真实图像,另一次用于虚假图像。
- 对于实像,地面真实被转换成使用 torch.ones_like 函数的真实,该函数返回定义形状的一个矩阵。
- 对于假图像,使用 torch.zeros_like 函数将地面真实转换为一,该函数返回定义形状的零矩阵。
- 发电机的损失函数只计算一次。如果你仔细观察,鉴别器使用相同的损失函数来计算假图像的损失。唯一的区别是不使用 torch.zeros_like 函数,而是使用 torch.ones_like 函数。标签从 0 到 1 的互换使得生成器能够学习将产生真实图像的表示,因此欺骗了鉴别器。
数学上,我们可以将整个过程定义为:
其中 Z 是噪声,x 是真实数据,G 是发生器,D 是鉴频器。
GANs 的应用
gan 广泛用于:
- 生成训练样本: GANs 通常用于生成特定任务的样本,如恶性和良性癌细胞的分类,特别是在数据较少的情况下训练分类器。
- 人工智能艺术或生成艺术:人工智能或生成艺术是 GANs 被广泛使用的另一个新领域。自从引入不可替代的代币以来,全世界的艺术家都在以非正统的方式创作艺术,即数字化和生成性。像 DeepDaze,BigSleep,BigGAN,CLIP,VQGAN 等 GAN 是创作者最常用的。
AI Art or Generative Art | Source: Author
- 图像到图像的翻译:图像到图像的翻译再次被数字创作者使用。这里的想法是将某种类型的图像转换成目标域中的图像。例如,将日光图像转换为夜间图像,或将冬季图像转换为夏季图像(见下图)。像 pix2pix、cycleGAN、styleGAN 这样的 GAN 是少数几个最受欢迎的 GAN。
Image-to-image translation | Source
- 文本到图像的翻译:文本到图像的翻译就是将文本或给定的字符串转换成图像。这是一个非常热门的领域,而且是一个不断发展的社区。如前所述,来自 OpenAI 的 DeepDaze、BigSleep 和 DALL E 等 GANs 在这方面非常受欢迎。
*Text-to-image translation | Source *
甘的问题
虽然 GANs 可以从随机高斯分布中产生与真实图像相似的图像,但这个过程在大多数时候并不完美。原因如下:
- 模式崩溃:模式崩溃是指生成器能够通过从整体数据中学习较少的数据样本来欺骗鉴别器的问题。由于模式崩溃,GAN 不能学习多种分布,并且仍然局限于少数几种。
- 递减梯度:递减或消失梯度下降发生在网络的导数非常小时,以至于对原始权重的更新几乎可以忽略不计。为了克服这个问题,建议使用 WGANs。
- 不收敛:它发生在网络无法收敛到全局最小值的时候。这是不稳定训练的结果。这个问题可以通过光谱归一化来解决。你可以在这里阅读光谱归一化。
GAN 的变体
自从第一个 GAN 发布以来,已经出现了许多 GAN 的变体。以下是一些最受欢迎的 GANs:
- CycleGAN
- StyleGAN
- 像素网络
- 文本 2 图像
- 迪斯科根
- 伊斯甘
本文只关注 Pix2Pix GAN 。在下一节中,我们将了解一些关键组件,如架构、损失函数等。
Pix2Pix GAN 是什么?
Pix2Pix GAN 是由 Phillip Isola 等人开发的有条件 GAN ( cGAN ),与只使用真实数据和噪声来学习和生成图像的 vanilla GAN 不同,cGAN 使用真实数据、噪声以及标签来生成图像。
本质上,生成器从真实数据以及噪声中学习映射。
类似地,鉴别器也从标签和真实数据中学习表示。
此设置使 cGAN 适用于图像到图像的转换任务,其中生成器根据输入图像生成相应的输出图像。换句话说,生成器使用条件分布(或数据)如指导或蓝图来生成目标图像(见下图)。
Pix2Pix is a conditional GAN | Source: Author
Application of Pix2Pix | Source
Pix2Pix 的想法依赖于为训练提供的数据集。将图像翻译与训练样本{x,y}配对是一对,它们之间具有对应关系。
Pix2Pix 网络架构
pix2pix 有两个重要的架构,一个用于生成器,另一个用于鉴别器,即 U-net 和 patchGAN。让我们更详细地探讨一下这两个问题。
u 网生成器
如前所述,pix2pix 使用的架构称为 U-net。U-net 最初是由 Ronneberger 等人为生物医学图像分割而开发的。艾尔。2015 年。
UNet 由两个主要部分组成:
- 由卷积层(左侧)组成的收缩路径,在提取信息的同时对数据进行下采样。
- 由上转置卷积层(右侧)组成的扩展路径对信息进行上采样。
假设我们的下采样有三个卷积层 C_l(1,2,3),那么我们必须确保我们的上采样有三个转置卷积层 C_u(1,2,3)。这是因为我们想要使用跳过连接来连接相同大小的相应块。
向下采样
Skip connection | Source: Author
在下采样期间,每个卷积块提取空间信息,并将该信息传递给下一个卷积块以提取更多信息,直到它到达被称为瓶颈的中间部分。上采样从瓶颈开始。
上采样
在上采样期间,每个转置卷积块扩展来自前一块的信息,同时连接来自相应下采样块的信息。通过连接信息,网络可以学习根据这些信息组合更精确的输出。
这种架构能够定位,即,它能够逐个像素地找到感兴趣的对象。此外,UNet 还允许网络将上下文信息从较低分辨率层传播到较高分辨率层。这允许网络产生高分辨率样本。
马尔可夫鉴别器
鉴频器采用贴片 GAN 架构。该架构包含多个转置卷积模块。它取图像的一个 NxN 部分,并试图发现它是真的还是假的。n 可以是任意大小。它可以比原始图像小,但仍然能够产生高质量的结果。鉴别器在整个图像上卷积应用。此外,因为鉴别器更小,即与发生器相比它具有更少的参数,所以它实际上更快。
PatchGAN 可以有效地将图像建模为马尔可夫随机场,其中 NxN 被视为独立的面片。所以 PatchGAN 可以理解为一种质感/风格的丧失。
损失函数
损失函数是:
上面的等式有两个部分:一个用于鉴别器,另一个用于发生器。让我们一个一个的了解他们两个。
在任何 GAN 中,在每次迭代中首先训练鉴别器,以便它可以识别真实和虚假数据,从而可以在它们之间进行鉴别或分类。本质上,
D(x,y) = 1 即实数和,
D(x,G(z)) = 0 即伪。
值得注意的是,G(z)也将产生假样本,因此其值将更接近于零。理论上,鉴别器应该总是只将 G(z)分类为零。因此鉴别器应该在每次迭代中保持真实和虚假之间的最大距离,即 1 和 0。换句话说,鉴别器应该最大化损失函数。
在鉴别器之后,发生器被训练。生成器,即 G(z)应该学习产生更接近真实样本的样本。为了学习原始分布,它从鉴别器获得帮助,即,我们将 D(x,G(z)) = 1 而不是 D(x,G(z)) = 0。
随着标记的改变,发生器现在根据属于具有基本事实标记的鉴别器的参数来优化其参数。该步骤确保发生器现在可以产生接近真实数据的样本,即 1。
损失函数也与 L1 损失混合,使得发生器不仅欺骗鉴别器,而且产生接近地面真实的图像。本质上,损耗函数对发电机有一个额外的 L1 损耗。
因此,最终损失函数为:
值得注意的是,L1 损失能够保留图像中的低频细节,但它将无法捕捉高频细节。因此,它仍然会产生模糊的图像。为了解决这个问题,使用了 PatchGAN。
最佳化
优化和训练过程类似于香草甘。但是训练本身是一个困难的过程,因为 GAN 的目标函数更多地是凹-凹的而不是凸-凹的。正因为如此,很难找到一个鞍点,这就是为什么训练和优化 GANs 很困难。
正如我们之前看到的,生成器不是直接训练的,而是通过鉴别器训练的。这实质上限制了发电机的优化。如果鉴别器未能捕获高维空间,那么可以肯定的是,生成器将不能产生好的样本。另一方面,如果我们能够以一种更加优化的方式训练鉴别器,那么我们就可以保证生成器也将得到优化的训练。
在训练的早期阶段,G 未经训练,产生好样本的能力较弱。这使得鉴别器非常强大。因此,不是将 log(1D(G(z))最小化,而是将发生器训练为将 log D(G(z))最大化。这在训练的早期阶段创造了某种稳定性。
解决不稳定性的其他方法有:
在模型的每一层使用光谱归一化
- 使用 Wasserstein 损失计算真实或虚假图像的平均分数。
- Pix2Pix 动手示例
让我们用 PyTorch 对 Pix2Pix 进行编码,直观地了解它的工作原理及其背后的各种组件。本节将让您清楚地了解 Pix2Pix 是如何工作的。
让我们从下载数据开始。以下代码可用于下载数据。
数据可视化
!wget http://efrosgans.eecs.berkeley.edu/pix2pix/datasets/facades.tar.gz
!tar -xvf facades.tar.gz
一旦下载了数据,我们就可以将它们可视化,以了解根据需求格式化数据所需的必要步骤。
我们将导入以下库进行数据可视化。
从上面的图像中,我们可以看到数据有两个图像连接在一起。如果我们看到上面的图像的形状,我们发现宽度是 512,这意味着图像可以很容易地分成两部分。
import matplotlib.pyplot as plt
import cv2
import os
import numpy as np
path = '/content/facades/train/'
plt.imshow(cv2.imread(f'{path}91.jpg'))
Source: Author
> >图像的形状:(256,512,3)
print('Shape of the image: ',cv2.imread(f'{path}91.jpg').shape)
为了分离图像,我们将使用以下命令:
左边的图像将是我们的基础真理,而右边的图像将是我们的条件图像。我们将它们分别称为 y 和 x。
image = cv2.imread(f'{path}91.jpg')
w = image.shape[1]//2
image_real = image[:, :w, :]
image_cond = image[:, w:, :]
fig, axes = plt.subplots(1,2, figsize=(18,6))
axes[0].imshow(image_real, label='Real')
axes[1].imshow(image_cond, label='Condition')
plt.show()
Source: Author
创建数据加载器
Dataloader 是一个允许我们按照 PyTorch 要求格式化数据的功能。这将包括两个步骤:
1.格式化数据,即从源中读取数据,裁剪数据,然后将其转换为 Pytorch 张量。
2.在将数据输入神经网络之前,使用 Pytorch 的 DataLoader 函数加载数据以创建批处理。
class data(Dataset):
def __init__(self, path='/content/facades/train/'):
self.filenames = glob(path+'*.jpg')
def __len__(self):
return len(self.filenames)
def __getitem__(self, idx):
filename = self.filenames[idx]
image = cv2.imread(filename)
image_width = image.shape[1]
image_width = image_width // 2
real = image[:, :image_width, :]
condition = image[:, image_width:, :]
real = transforms.functional.to_tensor(real)
condition = transforms.functional.to_tensor(condition)
return real, condition
请记住,我们将为培训和验证创建一个数据加载器。
train_dataset = data()
train_loader = DataLoader(train_dataset, batch_size=4, shuffle=True)
val_dataset = data(path='/content/facades/val/')
val_loader = DataLoader(train_dataset, batch_size=4, shuffle=True)
Utils
在本节中,我们将创建用于构建生成器和鉴别器的组件。我们将创建的组件是用于下采样的卷积函数和用于上采样的转置卷积函数,分别称为 cnn_block 和 tcnn_block。
发电机
def cnn_block(in_channels,out_channels,kernel_size,stride=1,padding=0, first_layer = False):
if first_layer:
return nn.Conv2d(in_channels,out_channels,kernel_size,stride=stride,padding=padding)
else:
return nn.Sequential(
nn.Conv2d(in_channels,out_channels,kernel_size,stride=stride,padding=padding),
nn.BatchNorm2d(out_channels,momentum=0.1,eps=1e-5),
)
def tcnn_block(in_channels,out_channels,kernel_size,stride=1,padding=0,output_padding=0, first_layer = False):
if first_layer:
return nn.ConvTranspose2d(in_channels,out_channels,kernel_size,stride=stride,padding=padding,output_padding=output_padding)
else:
return nn.Sequential(
nn.ConvTranspose2d(in_channels,out_channels,kernel_size,stride=stride,padding=padding,output_padding=output_padding),
nn.BatchNorm2d(out_channels,momentum=0.1,eps=1e-5),
)
现在,让我们定义生成器。我们将使用这两个组件来定义相同的。
鉴别器
class Generator(nn.Module):
def __init__(self,instance_norm=False):
super(Generator,self).__init__()
self.e1 = cnn_block(c_dim,gf_dim,4,2,1, first_layer = True)
self.e2 = cnn_block(gf_dim,gf_dim*2,4,2,1,)
self.e3 = cnn_block(gf_dim*2,gf_dim*4,4,2,1,)
self.e4 = cnn_block(gf_dim*4,gf_dim*8,4,2,1,)
self.e5 = cnn_block(gf_dim*8,gf_dim*8,4,2,1,)
self.e6 = cnn_block(gf_dim*8,gf_dim*8,4,2,1,)
self.e7 = cnn_block(gf_dim*8,gf_dim*8,4,2,1,)
self.e8 = cnn_block(gf_dim*8,gf_dim*8,4,2,1, first_layer=True)
self.d1 = tcnn_block(gf_dim*8,gf_dim*8,4,2,1)
self.d2 = tcnn_block(gf_dim*8*2,gf_dim*8,4,2,1)
self.d3 = tcnn_block(gf_dim*8*2,gf_dim*8,4,2,1)
self.d4 = tcnn_block(gf_dim*8*2,gf_dim*8,4,2,1)
self.d5 = tcnn_block(gf_dim*8*2,gf_dim*4,4,2,1)
self.d6 = tcnn_block(gf_dim*4*2,gf_dim*2,4,2,1)
self.d7 = tcnn_block(gf_dim*2*2,gf_dim*1,4,2,1)
self.d8 = tcnn_block(gf_dim*1*2,c_dim,4,2,1, first_layer = True)
self.tanh = nn.Tanh()
def forward(self,x):
e1 = self.e1(x)
e2 = self.e2(F.leaky_relu(e1,0.2))
e3 = self.e3(F.leaky_relu(e2,0.2))
e4 = self.e4(F.leaky_relu(e3,0.2))
e5 = self.e5(F.leaky_relu(e4,0.2))
e6 = self.e6(F.leaky_relu(e5,0.2))
e7 = self.e7(F.leaky_relu(e6,0.2))
e8 = self.e8(F.leaky_relu(e7,0.2))
d1 = torch.cat([F.dropout(self.d1(F.relu(e8)),0.5,training=True),e7],1)
d2 = torch.cat([F.dropout(self.d2(F.relu(d1)),0.5,training=True),e6],1)
d3 = torch.cat([F.dropout(self.d3(F.relu(d2)),0.5,training=True),e5],1)
d4 = torch.cat([self.d4(F.relu(d3)),e4],1)
d5 = torch.cat([self.d5(F.relu(d4)),e3],1)
d6 = torch.cat([self.d6(F.relu(d5)),e2],1)
d7 = torch.cat([self.d7(F.relu(d6)),e1],1)
d8 = self.d8(F.relu(d7))
return self.tanh(d8)
让我们使用下采样函数来定义鉴别器。
定义参数
class Discriminator(nn.Module):
def __init__(self,instance_norm=False):
super(Discriminator,self).__init__()
self.conv1 = cnn_block(c_dim*2,df_dim,4,2,1, first_layer=True)
self.conv2 = cnn_block(df_dim,df_dim*2,4,2,1)
self.conv3 = cnn_block(df_dim*2,df_dim*4,4,2,1)
self.conv4 = cnn_block(df_dim*4,df_dim*8,4,1,1)
self.conv5 = cnn_block(df_dim*8,1,4,1,1, first_layer=True)
self.sigmoid = nn.Sigmoid()
def forward(self, x, y):
O = torch.cat([x,y],dim=1)
O = F.leaky_relu(self.conv1(O),0.2)
O = F.leaky_relu(self.conv2(O),0.2)
O = F.leaky_relu(self.conv3(O),0.2)
O = F.leaky_relu(self.conv4(O),0.2)
O = self.conv5(O)
return self.sigmoid(O)
在本节中,我们将定义参数。这些参数将帮助我们训练神经网络。
初始化模型
batch_size = 4
workers = 2
epochs = 30
gf_dim = 64
df_dim = 64
L1_lambda = 100.0
in_w = in_h = 256
c_dim = 3
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
让我们初始化这两个模型,并启用 CUDA 进行更快的训练。
我们还将定义优化器和损失函数。
G = Generator().to(device)
D = Discriminator().to(device)
培养
G_optimizer = optim.Adam(G.parameters(), lr=2e-4,betas=(0.5,0.999))
D_optimizer = optim.Adam(D.parameters(), lr=2e-4,betas=(0.5,0.999))
bce_criterion = nn.BCELoss()
L1_criterion = nn.L1Loss()
一旦定义了所有重要的函数,我们将初始化训练循环。
监控我们的模型
for ep in range(epochs):
for i, data in enumerate(train_loader):
y, x = data
x = x.to(device)
y = y.to(device)
b_size = x.shape[0]
real_class = torch.ones(b_size,1,30,30).to(device)
fake_class = torch.zeros(b_size,1,30,30).to(device)
D.zero_grad()
real_patch = D(y,x)
real_gan_loss=bce_criterion(real_patch,real_class)
fake=G(x)
fake_patch = D(fake.detach(),x)
fake_gan_loss=bce_criterion(fake_patch,fake_class)
D_loss = real_gan_loss + fake_gan_loss
D_loss.backward()
D_optimizer.step()
G.zero_grad()
fake_patch = D(fake,x)
fake_gan_loss=bce_criterion(fake_patch,real_class)
L1_loss = L1_criterion(fake,y)
G_loss = fake_gan_loss + L1_lambda*L1_loss
G_loss.backward()
G_optimizer.step()
run["Gen Loss"].log(G_loss.item())
run["Dis Loss"].log(D_loss.item())
run['L1 Loss'].log(L1_loss.item())
run['Gen GAN Loss'].log(fake_gan_loss.item())
torch.save(G.state_dict(), 'PIX2PIX.ckpt')
run['model_checkpoints'].upload('PIX2PIX.ckpt')
if (i+1)%5 == 0 :
print('Epoch [{}/{}], Step [{}/{}], d_loss: {:.4f}, g_loss: {:.4f},D(real): {:.2f}, D(fake):{:.2f},g_loss_gan:{:.4f},g_loss_L1:{:.4f}'
.format(ep, epochs, i+1, len(train_loader), D_loss.item(), G_loss.item(),real_patch.mean(), fake_patch.mean(),fake_gan_loss.item(),L1_loss.item()))
G_losses.append(G_loss.item())
D_losses.append(D_loss.item())
G_GAN_losses.append(fake_gan_loss.item())
G_L1_losses.append(L1_loss.item())
with torch.no_grad():
G.eval()
fake = G(fixed_x).detach().cpu()
G.train()
figs=plt.figure(figsize=(10,10))
plt.subplot(1,3,1)
plt.axis("off")
plt.title("conditional image (x)")
plt.imshow(np.transpose(vutils.make_grid(fixed_x, nrow=1,padding=5, normalize=True).cpu(),(1,2,0)))
plt.subplot(1,3,2)
plt.axis("off")
plt.title("fake image")
plt.imshow(np.transpose(vutils.make_grid(fake, nrow=1,padding=5, normalize=True).cpu(),(1,2,0)))
plt.subplot(1,3,3)
plt.axis("off")
plt.title("ground truth (y)")
plt.imshow(np.transpose(vutils.make_grid(fixed_y, nrow=1,padding=5, normalize=True).cpu(),(1,2,0)))
plt.savefig(os.path.join('./','pix2pix'+"-"+str(ep) +".png"))
run['Results'].log(File(f'pix2pix-{str(ep)}.png'))
plt.close()
img_list.append(figs)
训练模型不是最后一步。您需要监控和跟踪培训,以分析绩效并在必要时实施更改。考虑到监控有太多损失、图和指标要处理的 GAN 的性能是多么费力,我们将在这一步使用 Neptune。
Neptune 允许用户:
1 监控模特的现场表演
2 监控硬件的性能
- 3 存储和比较不同运行的不同元数据(如指标、参数、性能、数据等。)
- 与他人分享工作
- 要开始,只需遵循以下步骤:
- 1.在本地系统上使用
pip install neptune-client
或conda install -c conda-forge neptune-client
安装 neptune-client。
2.创建账号,登录 Neptune.ai 。
3.登录后,创建一个新项目 。
!pip install neptune-client
4.现在,您可以将不同的元数据记录到 Neptune。点击了解更多信息。
对于这个项目,我们将把我们的参数记录到 Neptune 仪表板中。要将参数或任何信息记录到仪表板中,请创建字典。
一旦创建了字典,我们将使用以下命令记录它们:
请记住,损耗、生成的图像和模型的权重都是使用“run”命令记录到 Neptune 仪表盘中的。
PARAMS = {'Epoch': epochs,
'Batch Size': batch_size,
'Input Channels': c_dim,
'Workers': workers,
'Optimizer': 'Adam',
'Learning Rate': 2e-4,
'Metrics': ['Binary Cross Entropy', 'L1 Loss'],
'Activation': ['Leaky Relu', 'Tanh', 'Sigmoid' ],
'Device': device}
例如,在上面的培训中,您会发现以下命令:
run['parameters'] = PARAMS
这些基本上是用来记录数据到海王星仪表板。
培训初始化后,所有记录的信息将自动记录到仪表板中。Neptune 从训练中获取实时信息,允许实时监控整个过程。
run["Gen Loss"].log(G_loss.item())
run["Dis Loss"].log(D_loss.item())
run['L1 Loss'].log(L1_loss.item())
run['Gen GAN Loss'].log(fake_gan_loss.item())
以下是监控过程截图。
您还可以访问所有元数据并查看生成的样本。
最后,您可以比较不同运行的元数据。这是很有用的,例如,当您想要查看在调整一些参数后,您的模型是否比前一个模型执行得更好。
Monitoring the performance of the model | Source
Monitoring the performance of the hardware | Source
关键要点
Access to all metadata | Source
Access to the generated samples | Source
Pix2Pix 是一个有条件的 GAN,它使用图像和标签来生成图像。
Comparing metadata from different runs | Source
它使用两种架构:
- 发电机的 u 形网
- 鉴别器的 PatchGAN
- PatchGAN 在生成的图像中使用 NxN 大小的较小补丁来区分真假,而不是一次性区分整个图像。
- Pix2Pix 有一个专门针对生成器的额外损耗,以便它可以生成更接近地面真实情况的图像。
- Pix2Pix 是一种成对图像翻译算法。
- 您可以探索的其他 gan 包括:
- CycleGAN:它类似于 Pix2Pix,因为除了数据部分,大部分方法都是相同的。它不是成对图像翻译,而是不成对图像翻译。学习和探索 CycleGAN 会容易得多,因为它是由相同的作者开发的。
如果您对文本到图像的翻译感兴趣,那么您应该探索:
- 您可能想尝试的其他有趣的 GANs 项目:
- StyleGAN
- 阿尼梅根
- 比根
- 年龄-cGAN
- starman 参考资料
- 使用条件对抗网络的图像到图像翻译
- 深度学习书籍:Ian Goodfellow
生成性对抗网络:古德菲勒等人
- 生成性对抗网络和一些 GAN 应用——你需要知道的一切
- 生成性对抗性网络损失函数的温和介绍。
- Generative Adversarial Networks: Goodfellow et al.
- Generative Adversarial Networks and Some of GAN Applications – Everything You Need to Know
- A Gentle Introduction to Generative Adversarial Network Loss Functions.
面向机器学习专家的 Plotly Python 教程
Plotly 是一个开源的 Python 图形库,非常适合构建漂亮的交互式可视化。在深入研究机器学习建模之前,它是发现数据集中模式的一个非常棒的工具。在本文中,我们将看看如何以示例驱动的方式使用它。
您可能会看到的一些可视化效果包括:
- 线形图,
- 散点图,
- 条形图,
- 误差线,
- 箱线图,
- 直方图,
- 热图,
- 支线剧情,
- 和气泡图。
为什么你会选择 Plotly
现在,事实是你仍然可以使用 Matplotlib、Seaborn 或者 T2 的 Bokeh 来获得这些可视化效果。有几个原因可以解释为什么你会选择 Plotly:
- 可视化是交互式的,不像 Seaborn 和 Matplotlib
- 使用 Plotly 的高级 Express API 生成复杂的视觉效果相当简单;
- Plotly 还提供了一个名为 Plotly Dash 的框架,你可以用它来托管你的可视化以及机器学习项目;
- 你可以为你的可视化生成 HTML 代码,如果你喜欢,你可以把它嵌入到你的网站上。
也就是说,生成可视化效果需要清理数据集。这是一个至关重要的部分,否则,你会有视觉传达错误的信息。在本文中,我们跳过清理和预处理部分,将重点放在可视化上。我们将在教程结束时提供整个笔记本。
创建可视化效果时,记住最佳实践也很重要,例如:
- 使用对眼睛友好的颜色
- 确保数字相加,例如在饼图中,百分比总和应为 100%
- 使用正确的色标,这样观众就能清楚地看到哪种颜色代表较高的数字,哪种颜色代表较低的数字
- 不要在同一个视图中放置太多的数据,例如,可以分组并绘制最上面的项目,而不是绘制数据集中的所有内容
- 保证剧情不要太忙
- 总是添加你的数据的来源,即使你是收集它的人。它建立信誉。
我们可以通过两种方式与 Plotly API 进行交互;
在这篇文章中,我们将交替使用它们。
Plotly 直方图
直方图是数字数据分布的表示,数据被分组到多个条块中。然后显示每个箱的计数。在 Plotly 中,可以使用 sum 或 average 等聚合函数来聚合数据。在绘图中,要入库的数据也可以是分类的。这里有一个例子:
Plotly 条形图
import plotly.express as px
fig = px.histogram(views, x="views")
fig.show()
当您想要显示分类列和数字列时,条形图是一种很好的可视化工具。它显示了每个类别中某个数字列的数量。Plotly Express 使绘制一个非常容易。
你不仅仅局限于垂直条形图,你也可以使用水平条形图。这是通过定义“方向”来实现的。
Plotly 饼图
fig = px.bar(views_top, x='event', y='views')
fig.show()
饼图是显示每个类别中项目数量的另一种可视化类型。这种类型使用户能够快速确定特定项或值在整个数据集中所占的份额。这次让我们展示一下如何使用 Plotly 的 Graph 对象来绘制。
fig = px.bar(views_top, x='views', y='event',orientation='h')
fig.show()
Plotly 圆环图
您可以通过指定hole
参数将上面的视觉效果更改为圆环图。这是您希望环形图上的孔的大小。
Plotly 散点图
import plotly.graph_objects as go
fig = go.Figure(
data=[
go.Pie(labels=labels, values=values)
])
fig.show()
散点图对于确定两个数值变量之间是否存在关系或相关性非常有用。
Plotly 线图
折线图主要用于显示某一数值如何随时间或某一区间变化。
fig = go.Figure(
data=[
go.Pie(labels=labels, values=values, hole=0.2)
])
fig.show()
Plotly 注释
在 Plotly 中添加文本标签和注释非常简单。在散点图中,这可以通过指定text
参数来实现。
Plotly 3D 散点图
fig = px.scatter(df,x='comments',y='views')
fig.show()
在 Plotly 中,可以通过传递 x、y 和 z 参数来创建 3D 散点图。
Plotly 写入 HTML
Plotly 还允许您将任何可视化保存到 HTML 文件中。这非常容易做到。
fig = px.line(talks, x="published_year", y="number_of_events")
fig.show()
Plotly 3D 曲面
现在让我们看看如何在 Plotly 中绘制 3D 曲面。类似于 3D 散点图,我们必须传递 x、y 和 z 参数。
Plotly 气泡图
fig = px.scatter(df,x='comments',y='views',color='duration',text="published_day")
fig.show()
绘制气泡图非常类似于散点图。事实上,它是根据散点图构建的。我们增加的唯一一项是气泡的大小。
绘图表
Plotly 还可用于将数据框可视化为表格。我们可以使用 Plotly Graph Objects Table
来实现这一点。我们将标题和单元格传递给表格。我们还可以指定如下所示的样式:
fig = px.scatter_3d(df,x='comments',y='views',z='duration',color='views')
fig.show()
打印热图
我们可以用密度热图来形象化一个聚集函数的 2D 分布。聚合函数应用于 z 轴上的变量。该函数可以是总和、平均值甚至是计数。
情节动画
fig.write_html("3d.html")
Plotly 动画可用于制作特定值随时间变化的动画。为了实现这一点,我们必须定义animation_frame
。在这种情况下,是年份。
箱形图
箱线图显示了数据通过其四分位数的表示。落在第四个四分位数之外的值表示数据集中的异常值。
fig = go.Figure(data=[go.Surface(z=df[['duration','views','comments']].values)])
fig.update_layout(title='3D Surface', autosize=False,
width=500, height=500,
margin=dict(l=65, r=50, b=65, t=90))
fig.show()
Plotly 地图
为了在 Plotly 中使用地图,你需要前往地图框并获取你的地图框 API 密钥。有了手头的,您可以在地图上直观地显示您的数据。这是在传递纬度和经度时使用scatter_mapbox
完成的。
情节复杂的次要情节
fig = px.scatter(df,x='comments',y='views',size='duration',color='num_speaker', log_x=True, size_max=60)
fig.show()
使用 Plotly,我们还可以在同一个图形上可视化多个图。这是用情节主线完成的。通过定义一个facet_col
来创建图形。图表将被分解成尽可能多的来自facet_col
列的唯一值。
Plotly 误差线
误差线用于显示可视化数据的可变性。一般来说,它们有助于显示估计误差或某一测量的精确度。误差线的长度揭示了不确定性的水平。误差线越长,表明数据点越分散,因此不确定性越大。它们可以应用于图表,如折线图、条形图和散点图。
fig = go.Figure(data=[go.Table(header=dict(values=views_top.columns,
fill_color='yellow',
),
cells=dict(values=[views_top['event'],views_top['views']],
fill_color='paleturquoise',
))
])
fig.show()
最后的想法
希望这篇文章向您展示了如何在下一个机器学习工作流程中使用 Plotly。你甚至可以用它来可视化你的机器学习模型的性能指标。与其他工具不同,它的视觉效果既吸引眼球又具有互动性。
交互性使您能够放大和缩小图表中的特定部分。这样,你可以看得更深一点,更详细地分析你的图表。具体来说,我们已经看到了如何在 Plotly 中使用流行的图表,如直方图、条形图和散点图。我们还看到,我们可以在同一个图形上构建多个图,并在地图上可视化数据。
fig = px.density_heatmap(df, x="published_year", y="views",z="comments")
fig.show()
使用的笔记本可以在这里找到。
快乐策划——没有双关语!
Plotly Animations can be used to animate the changes in certain values over time. In order to achieve that, one has to define the animation_frame
. In this case, it’s the year.
px.scatter(df, x="duration", y="comments",animation_frame="published_year", size="duration", color="published_day")
Plotly box plot
A box plot shows the representation of data through their quartiles. Values falling outside the fourth quartile represent the outliers in your dataset.
fig = px.box(df, x="published_day", y="duration")
fig.show()
Plotly maps
In order to work with maps in Plotly, you will need to head over to Mapbox and grab your Mapbox API key. With the at hand, you can visualize your data on a map in Plotly. This is done using the scatter_mapbox
while passing the latitude and the longitude.
px.set_mapbox_access_token('YOURTOKEN')
fig = px.scatter_mapbox(df, lat="lat", lon="lon",
color="region",
size="views",
color_continuous_scale=
px.colors.cyclical.IceFire, size_max=15)
fig.show()
Plotly subplots
With Plotly, we can also visualize multiple plots on the same graph. This is done using Plotly Subplots. The plots are created by defining a facet_col
. The graphs will be broken into as many unique values as available from the facet_col
column.
px.scatter(df, x="duration", y="comments",
animation_frame="published_month", animation_group="event",
facet_col="published_day",width=1500, height=500,
size="views", color="published_day",
)
Plotly error bars
Error bars are used to show the variability of data in a visualization. Generally, they help in showing the estimated error or the preciseness of a certain measure. The length of the error bar reveals the level of uncertainty. Longer error bars indicate that the data points are more spread out hence more uncertain. They can be applied to graphs such as line charts, bar graphs, and scatterplots.
fig = go.Figure(
data=[
go.Bar(
x=views_top['event'], y=views_top['views'],
error_y=dict(type='data', array=views_top['error'].values)
)
])
fig.show()
Final thoughts
Hopefully, this piece has shown you how you can use Plotly in your next machine learning workflow. You can even use it to visualize the performance metrics of your machine learning models. Unlike other tools, its visuals are eye-catching as well as interactive.
The interactivity enables you to zoom in and out of specific parts in the graph. In this way, you can look a little deeper to analyze your graph in more detail. Specifically, we have seen how you can use popular graphs such as histograms, bar charts, and scatter plots in Plotly. We have also seen that we can build multiple plots on the same graph as well as visualize data on the map.
The Notebook used can be found here.
Happy plotting – no pun intended!
使用机器学习预测股票价格
原文:https://web.archive.org/web/https://neptune.ai/blog/predicting-stock-prices-using-machine-learning
众所周知,股票市场是不稳定的,动态的,非线性的。由于多种(宏观和微观)因素,如政治、全球经济状况、意外事件、公司财务表现等,准确的股价预测极具挑战性。
但是,所有这些也意味着有大量的数据可以从中发现模式。因此,金融分析师、研究人员和数据科学家不断探索分析技术,以检测股市趋势。这就产生了算法交易的概念,它使用自动化、预编程的交易策略来执行订单。
在本文中,我们将使用传统的量化金融方法和机器学习算法来预测股票走势。我们将讨论以下主题:
- 股票分析:基本面与技术面分析
- 作为时间序列数据的股票价格及相关概念
- 用移动平均技术预测股票价格
- LSTMs 简介
- 用 LSTM 模型预测股票价格
- 对新方法的最终想法,如 ESN
免责声明:本项目/文章无意提供金融、交易和投资建议。不保证模型的准确性。在使用本文介绍的方法或准则做出任何投资决定之前,受众应进行尽职调查。
股票分析:基本面分析与技术面分析
说到股票,基本面分析和技术分析是市场分析的两个极端。
- 基本面分析(你可以在这里阅读更多信息):
- 通过检查公司的内在价值来评估公司的股票,包括但不限于有形资产、财务报表、管理有效性、战略计划和消费者行为;基本上是一个公司的所有基本要素。
- 作为长期投资的相关指标,基本面分析依赖于历史和当前数据来衡量收入、资产、成本、负债等。
- 一般来说,基本面分析的结果不会随着短期消息而改变。
- 技术分析(你可以在这里了解更多信息):
在我们的练习中,我们将只看技术分析,重点是简单的移动平均线和指数移动平均线技术来预测股票价格。此外,我们将利用 LSTM(长短期记忆),一个时间序列的深度学习框架,来建立一个预测模型,并将其性能与我们的技术分析进行比较。
如免责声明所述,股票交易策略不在本文讨论范围之内。我使用交易/投资术语只是为了帮助你更好地理解分析,但这不是财务建议。我们将使用这样的术语:
作为时间序列数据的股票价格
尽管存在波动,股票价格并不只是随机产生的数字。因此,它们可以被分析为一系列离散时间数据;换句话说,在连续时间点(通常是每天)进行的时间序列观察。时间序列预测(根据历史值预测未来值)非常适用于股票预测。
由于时间序列数据的序列性质,我们需要一种方法来聚合这种信息序列。在所有潜在的技术中,最直观的是马,他能够消除短期波动。我们将在下一节讨论更多的细节。
数据集分析
在这个演示练习中,我们将使用过去 21 年(1999 年 11 月 1 日至 2021 年 7 月 9 日)苹果股票(股票代码 AAPL)的收盘价。分析数据将从 Alpha Vantage 加载,它为历史和实时股市数据提供了一个免费的 API。
要从 Alpha Vantage 获取数据,需要一个免费的 API 键;可以在这里找到的演练教程。不想创建 API?别担心,我的 Github repo 里也有分析数据。如果你想探索其他股票,下载数据的代码也可以在这个 Github repo 中找到。一旦有了 API,您所需要的就是特定股票的股票代码。
对于模型训练,我们将使用最老的 80%的数据,并将最近的 20%保存为保留测试集。
test_ratio = 0.2
training_ratio = 1 - test_ratio
train_size = int(training_ratio * len(stockprices))
test_size = int(test_ratio * len(stockprices))
print("train_size: " + str(train_size))
print("test_size: " + str(test_size))
train = stockprices[:train_size][['Date', 'Close']]
test = stockprices[train_size:][['Date', 'Close']]
创建海王星项目
关于模型训练和性能比较,Neptune 使用户可以方便地跟踪与模型相关的一切,包括超参数规范和评估图。本完整指南提供了如何用 Python 设置和配置 Neptune 项目的分步说明。
现在,让我们为这个特定的练习创建一个项目,并将其命名为“ StockPrediction ”。
评估指标和助手功能
由于股票价格预测本质上是一个回归问题,因此 RMSE(均方根误差)和 MAPE(平均绝对百分比误差%) 将是我们当前的模型评估指标。两者都是预测准确性的有用衡量标准。
,其中 N =时间点个数,At =实际/真实股价,Ft =预测/预测值。
RMSE 给出了预测值和真实值之间的差异,而 MAPE (%)测量了相对于真实值的这种差异。例如,12%的 MAPE 值表示预测股价和实际股价之间的平均差异为 12%。
接下来,让我们为当前的练习创建几个辅助函数。
- 将股票价格数据分成训练序列 X 和下一个输出值 Y,
def extract_seqX_outcomeY(data, N, offset):
"""
Split time-series into training sequence X and outcome value Y
Args:
data - dataset
N - window size, e.g., 50 for 50 days of historical stock prices
offset - position to start the split
"""
X, y = [], []
for i in range(offset, len(data)):
X.append(data[i-N:i])
y.append(data[i])
return np.array(X), np.array(y)
- 计算 RMSE 和 MAPE (%),
def calculate_rmse(y_true, y_pred):
"""
Calculate the Root Mean Squared Error (RMSE)
"""
rmse = np.sqrt(np.mean((y_true-y_pred)**2))
return rmse
def calculate_mape(y_true, y_pred):
"""
Calculate the Mean Absolute Percentage Error (MAPE) %
"""
y_pred, y_true = np.array(y_pred), np.array(y_true)
mape = np.mean(np.abs((y_true-y_pred) / y_true))*100
return mape
- 计算技术分析的评估指标并登录到 Neptune(带 arg。logNeptune = True),
def calculate_perf_metrics(var, logNeptune=True, logmodelName='Simple MA'):
rmse = calculate_rmse(np.array(stockprices[train_size:]['Close']), np.array(stockprices[train_size:][var]))
mape = calculate_mape(np.array(stockprices[train_size:]['Close']), np.array(stockprices[train_size:][var]))
if logNeptune:
npt_exp['RMSE'].log(rmse)
npt_exp['MAPE (%)'].log(mape)
return rmse, mape
- 绘制股票价格的趋势,并将该图记录到 Neptune(带参数。带参数。logNeptune = True),
def plot_stock_trend(var, cur_title, stockprices=stockprices, logNeptune=True, logmodelName='Simple MA'):
ax = stockprices[['Close', var,'200day']].plot(figsize=(20, 10))
plt.grid(False)
plt.title(cur_title)
plt.axis('tight')
plt.ylabel('Stock Price ($)')
if logNeptune:
npt_exp[f'Plot of Stock Predictions with {logmodelName}'].upload(neptune.types.File.as_image(ax.get_figure()))
用移动平均技术预测股票价格
MA 是一种在股票市场消除随机波动的流行方法。类似于滑动窗口,均线是沿时间尺度/周期移动的平均值;随着新数据点的增加,旧数据点会被丢弃。
短期、中期和长期投资常用的周期分别是 20 天、50 天和 200 天 MA 。
金融分析师最喜欢两种移动平均线:简单移动平均线和指数移动平均线。
简单的人
SMA 是简单移动平均线的缩写,它计算一系列股票(收盘)价格在该范围内特定时间段的平均值。SMA 的公式为:
,其中 PN= N 个时间点的股价,N =时间点的个数。
在这个构建 SMA 模型的练习中,我们将使用下面的 Python 代码来计算 50 天的 SMA。为了更好的衡量,我们还会添加一个 200 天的均线。
window_size = 50
npt_exp = neptune.init(
api_token=os.getenv('NEPTUNE_API_TOKEN'),
project=myProject,
name='SMA',
description='stock-prediction-machine-learning',
tags=['stockprediction', 'MA_Simple', 'neptune'])
window_var = str(window_size) + 'day'
stockprices[window_var] = stockprices['Close'].rolling(window_size).mean()
stockprices['200day'] = stockprices['Close'].rolling(200).mean()
plot_stock_trend(var=window_var, cur_title='Simple Moving Averages', logmodelName='Simple MA')
rmse_sma, mape_sma = calculate_perf_metrics(var=window_var, logmodelName='Simple MA')
npt_exp.stop()
在我们的 Neptune 项目中,我们将在测试集上看到性能指标;RMSE = 43.79,MAPE = 12.53%。
此外,下面的趋势图显示了 50 天,200 天的 SMA 预测与真实的股票收盘价的比较。
不足为奇的是,从中期趋势来看,50 日均线是比 200 日均线更好的趋势指标。尽管如此,这两个指标给出的预测似乎比实际值要小。
指数毫安
与对所有历史数据点分配相同权重的 SMA 不同,EMA(指数移动平均线的缩写)对最近的价格应用较高的权重,即在我们的示例中 50 天 MA 的尾部数据点。加权因子的大小取决于时间段的数量。计算 EMA 的公式是:
,
其中 P t =时间点 t 的价格,
均线 t-1 点**= t-1 点均线,
N = EMA 中的时间点数,
和加权因子 k = 2/(N+1)。
均线优于均线的一个优点是,均线对价格变化更敏感,这使得它对短线交易很有用。下面是 EMA 的 Python 实现:
npt_exp = neptune.init(
api_token=os.getenv('NEPTUNE_API_TOKEN'),
project=myProject,
name='EMA',
description='stock-prediction-machine-learning',
tags=['stockprediction', 'MA_Exponential', 'neptune'])
window_ema_var = window_var+'_EMA'
stockprices[window_ema_var] = stockprices['Close'].ewm(span=window_size, adjust=False).mean()
stockprices['200day'] = stockprices['Close'].rolling(200).mean()
plot_stock_trend(var=window_ema_var, cur_title='Exponential Moving Averages', logmodelName='Exp MA')
rmse_ema, mape_ema = calculate_perf_metrics(var=window_ema_var, logmodelName='Exp MA')
npt_exp.stop()
检查 Neptune 中跟踪的性能指标,我们得到 RMSE = 36.68,MAPE = 10.71%,这比 RMSE 和 MAPE 的 SMA 分别为 43.79 和 12.53%有所提高。
从这个均线模型生成的趋势图也暗示了它的表现优于均线。
SMA 和 EMA 预测性能的比较
下面的剪辑显示了 SMA 和 EMA 在 Neptune 中并排的比较;蓝色和粉色的线分别是 SMA 和 EMA。
时间序列数据的 LSTMs 简介
现在,让我们继续讨论 LSTM 模型。LSTM 是长短期记忆的缩写,是一种非常强大的时间序列算法。它可以捕捉历史趋势模式,并以高精度预测未来值。
简而言之,理解 LSTM 模型的关键组件是细胞状态( C t ),它代表了细胞内部的短期和长期记忆。
为了控制和管理单元状态,LSTM 模型包含三个门/层。值得一提的是,这里的“门”可以被视为让信息进来(被记住)或出去(被忘记)的过滤器。
顾名思义,遗忘门决定从当前单元状态中丢弃哪些信息。数学上,它应用一个 sigmoid 函数来输出/返回来自前一个单元格状态的每个值的[0,1]之间的值(Ct-1);这里“1”表示“完全通过”,而“0”表示“完全过滤掉”
它用于选择在当前单元格状态中添加和存储哪些新信息。在这一层中,实现一个 sigmoid 函数来减少输入向量中的值( i t ),然后一个 tanh 函数挤压[-1,1]之间的每个值( C t )。 i t 和 C t 的逐元素矩阵乘法表示需要添加到当前单元状态的新信息。
输出门用于控制流向下一个单元状态的输出。与输入门类似,输出门先应用一个 sigmoid 函数,然后应用一个 tanh 函数来过滤掉不想要的信息,只保留我们决定让其通过的信息。
为了更详细地了解 LSTM,你可以查看这个文档。
了解了 LSTM 理论,你一定想知道它是如何预测现实世界的股票价格的。我们将在下一节找到答案,通过建立一个 LSTM 模型,并将其性能与两个技术分析模型进行比较:SMA 和 EMA。
用 LSTM 模型预测股票价格
首先,我们需要创建一个专用于 LSTM 的海王星实验,其中包括指定的超参数。
layer_units, optimizer = 50, 'adam'
cur_epochs = 15
cur_batch_size = 20
cur_LSTM_pars = {'units': layer_units,
'optimizer': optimizer,
'batch_size': cur_batch_size,
'epochs': cur_epochs
}
npt_exp = neptune.init(
api_token=os.getenv('NEPTUNE_API_TOKEN'),
project=myProject,
name='LSTM',
description='stock-prediction-machine-learning',
tags=['stockprediction', 'LSTM','neptune'])
npt_exp['LSTMPars'] = cur_LSTM_pars
接下来,我们缩放 LSTM 模型规则的输入数据,并将其分成训练集和测试集。
scaler = StandardScaler()
scaled_data = scaler.fit_transform(stockprices[['Close']])
scaled_data_train = scaled_data[:train.shape[0]]
X_train, y_train = extract_seqX_outcomeY(scaled_data_train, window_size, window_size)
几个注意事项:
- 我们使用标准定标器,而不是你之前可能见过的最小最大定标器。原因是股票价格是不断变化的,没有真正的最小值或最大值。使用 MinMaxScaler 是没有意义的,虽然这种选择最终很可能不会导致灾难性的结果;
- 原始格式的股票价格数据不能直接用于 LSTM 模型;我们需要使用我们预定义的
*extract_seqX_outcomeY
* 函数来转换它。例如,为了预测第 51 个价格,该函数预先创建 50 个数据点的输入向量,并使用第 51 个价格作为结果值。
继续,让我们开始 LSTM 建模过程。具体来说,我们正在构建一个具有两个隐藏层的 LSTM,以及一个基于输出的“线性”激活函数。还有,这个模型登录的是海王星。
def Run_LSTM(X_train, layer_units=50, logNeptune=True, NeptuneProject=None):
inp = Input(shape=(X_train.shape[1], 1))
x = LSTM(units=layer_units, return_sequences=True)(inp)
x = LSTM(units=layer_units)(x)
out = Dense(1, activation='linear')(x)
model = Model(inp, out)
model.compile(loss = 'mean_squared_error', optimizer = 'adam')
if logNeptune:
model.summary(print_fn=lambda x: NeptuneProject['model_summary'].log(x))
return model
model = Run_LSTM(X_train, layer_units=layer_units, logNeptune=True, NeptuneProject=npt_exp)
history = model.fit(X_train, y_train, epochs=cur_epochs, batch_size=cur_batch_size,
verbose=1, validation_split=0.1, shuffle=True)
模型超参数和概要已经登录到海王星。
一旦培训完成,我们将根据我们的坚持集测试模型。
def preprocess_testdat(data=stockprices, scaler=scaler, window_size=window_size, test=test):
raw = data['Close'][len(data) - len(test) - window_size:].values
raw = raw.reshape(-1,1)
raw = scaler.transform(raw)
X_test = []
for i in range(window_size, raw.shape[0]):
X_test.append(raw[i-window_size:i, 0])
X_test = np.array(X_test)
X_test = np.reshape(X_test, (X_test.shape[0], X_test.shape[1], 1))
return X_test
X_test = preprocess_testdat()
predicted_price_ = model.predict(X_test)
predicted_price = scaler.inverse_transform(predicted_price_)
test['Predictions_lstm'] = predicted_price
是时候计算性能指标并将其记录到 Neptune 了。
rmse_lstm = calculate_rmse(np.array(test['Close']), np.array(test['Predictions_lstm']))
mape_lstm = calculate_mape(np.array(test['Close']), np.array(test['Predictions_lstm']))
npt_exp['RMSE'].log(rmse_lstm)
npt_exp['MAPE (%)'].log(mape_lstm)
def plot_stock_trend_lstm(train, test, logNeptune=True):
fig = plt.figure(figsize = (20,10))
plt.plot(train['Date'], train['Close'], label = 'Train Closing Price')
plt.plot(test['Date'], test['Close'], label = 'Test Closing Price')
plt.plot(test['Date'], test['Predictions_lstm'], label = 'Predicted Closing Price')
plt.title('LSTM Model')
plt.xlabel('Date')
plt.ylabel('Stock Price ($)')
plt.legend(loc="upper left")
if logNeptune:
npt_exp['Plot of Stock Predictions with LSTM'].upload(neptune.types.File.as_image(fig))
plot_stock_trend_lstm(train, test)
npt_exp.stop()
在海王星,很神奇的看到我们的 LSTM 模型取得了 RMSE = 12.63,MAPE = 2.37%的成绩;这是对 SMA 和 EMA 模型的巨大改进!
趋势图显示了我们测试集的预测收盘价和实际收盘价近乎完美的叠加。
SMA、EMA 和 LSTM 模型的比较
LSTM 会占用大量的计算和内存资源吗?毕竟,这是一个比 SMA 或 EMA 等传统技术分析模型更复杂的算法。如果 LSTM 模式确实需要更多的资源来运行,那么扩大规模将是一个挑战,对吗?
幸运的是,海王星自动为我们监控这些信息。
正如我们所看到的,这三种型号的 CPU 和内存使用量相当接近;LSTM 模式并不比并购模式消耗更多的资源。
关于新方法的最后想法
在预测苹果股票价格的例子中,我们已经看到了 LSTMs 相对于传统 MA 模型的优势。对其他股票进行归纳时要小心,因为与其他平稳的时间序列不同,股票市场数据几乎没有季节性,而且更加混乱。
在我们的例子中,苹果作为最大的科技巨头之一,不仅建立了成熟的商业模式和管理,其销售数字也受益于创新产品或服务的发布。这两个因素都有助于降低苹果股票的隐含波动率,使得 LSTM 模型的预测相对容易,而不同的高波动率股票则相反。
为了解释股票市场的混乱动态,回声状态网络(ESN)被提出。作为 RNN(递归神经网络)家族中的一项新发明,ESN 利用了一个隐藏层,该隐藏层具有几个流动且松散互连的神经元;这个隐藏层被称为“储层”,用于捕获输入数据的非线性历史信息。
在高层次上,ESN 接受时间序列输入向量,并将其映射到高维特征空间,即动态库(神经元不像网络那样连接,而是像一个库)。然后,在输出层,应用线性激活函数来计算最终预测。
如果你有兴趣了解更多关于这种方法的知识,请查阅耶格和哈斯的原创论文。
此外,在新闻和社交媒体上结合关于股票市场以及感兴趣的给定股票的情绪分析也是令人感兴趣的。另一种更好的股票价格预测方法是混合模型,我们将 MA 预测作为输入向量添加到 LSTM 模型中。你可能也想探索不同的方法。
希望你喜欢读这篇文章,就像我喜欢写它一样!完整的代码/脚本可以在我的 Github repo 这里找到,我们目前的 Neptune 项目可以在这里找到供你参考。
最流行的编程语言&为什么它们在机器学习中有用
原文:https://web.archive.org/web/https://neptune.ai/blog/programming-languages-machine-learning
在线论坛和数据科学博客有很多建议:学习那种语言,跟上那个框架,你看过那个库吗?很难跟上所有最新的技术,尤其是在机器学习领域,这个领域几乎每天都在变化。
在本文中,我们将带它回到基础,并讨论对机器学习最有用的编程语言。除了简要概述这些语言如何工作,我们还将涵盖机器学习的基础知识、数据科学家的流行趋势、有用的库、用例以及范例。让我们开始吧!
构建机器学习模型的基本概述
在了解为什么某些编程语言更适合 ML 之前,理解构建 ML 模型的基础是很重要的。
机器学习是最接近模仿人脑的东西。ML 算法在大量数据(图像、数字或单词)中搜索模式,以便做出预测。在搜索引擎和内容推荐系统的引擎盖下,是这些强大的机器学习算法。
构建机器学习模型有 4 个基本步骤:
步骤 1:整合数据集
数据集必须反映模型将做出的真实生活预测。训练数据可以分类;该模型将挑选出不同类别之间的不同特征和模式,以学习如何区分它们。例如,如果您训练一个模型对斑马和长颈鹿进行分类,数据集将包含这两种动物的图像,并进行适当的标记。
您希望准备一个包含一切的数据集,这样模型的预测就不会不准确或有偏差。数据集应该是随机的、经过重复数据删除的、全面的,并分成训练集和测试集。
您使用训练集来训练模型,使用测试集来确定模型的准确性,并确定潜在的警告和改进。训练集和测试集不应该有重叠的数据。
Example of an image dataset that could be used for object detection | Source
步骤 2:选择合适的算法
根据手头的任务、训练数据量以及数据是否有标签,可以使用特定的算法。
标记数据的常见算法包括:
- 回归算法
- 决策树
- 基于实例的算法
无标签数据的常见算法包括:
A neural network acts as a human brain in order to recognize relationships within huge amounts of data. | Source
步骤 3:在数据集上训练算法
该模型在数据集上反复训练,根据不正确的输出调整权重和偏差。例如,如果我们有一条直线的方程:y = mx + b,训练的可调值是“m”和“b”,或者我们的权重和偏差。我们无法影响输入(y)或输出(x ),因此我们必须在训练过程中调整 m(斜率)和 b (y 截距),随机值被分配给 m 和 b,直到线的位置受到影响,从而获得最正确的预测。随着不断迭代,模型的精度不断提高。
步骤 4:测试+改进模型
您可以通过对以前从未用于训练的新数据进行测试或评估来检查模型的准确性。这将帮助你理解你的 ML 模型在现实世界中的表现。评估后,您可以微调我们在训练过程中最初假设的超参数;根据数据集、模型和训练过程的具体情况,调整这些超参数在某种程度上可以成为一个不断变化的实验过程。
机器学习的应用
既然我们已经学习了构建简单机器学习模型背后的理论,让我们来探索现实世界中的各种应用。一旦你学会了机器学习,这就是你将能够建立的!
推荐引擎
几乎各大平台都有推荐系统。他们收集用户数据来推荐产品、服务或信息。推荐系统可能会跟踪数据,如用户的观看历史、用户观看某个内容的时间、他们对该内容的反应等。
社会化媒体
社交媒体平台使用各种各样的 ML 工具来保持它们的使用。例如,脸书分析你喜欢什么内容,以便提供相关的广告。Instagram 通过图像处理识别视觉效果。Snapchat 跟踪你的面部运动,同时使用计算机视觉对其进行过滤。
无人驾驶汽车
为了避开附近的物体,如行人和其他汽车,自动驾驶汽车通过传感器和摄像头收集周围的数据。使用 SIFT(尺度不变特征变换)等 ML 算法,汽车可以表现得好像有人真的在方向盘后面一样。
教育
ML 可用于识别苦苦挣扎的学生或教育平台中的差距。Anki 和 Quizlet 等抽认卡工具使用算法来跟踪记忆和保持率。
医学+健康
ML 技术正在成为医疗保健行业的重要组成部分。ML 算法可用于确定最佳治疗过程,帮助进行更准确的诊断和药物开发,等等。医疗保健管理系统使用 ML 来绘制和治疗传染病,并为患者提供个性化护理。
人物检测
人物检测让您可以通过摄像机或视频来识别和跟踪人物。这项技术用于安全设备,最近正在亚马逊 Go 杂货店实施,该技术在顾客购物时跟踪他们,所以他们不必结账。
ML 编程语言
您现在已经对 ML 及其现实世界的应用程序有了基本的了解,但是可能很难知道从哪里或者如何开始。最重要的第一步是了解至少一种用于机器学习的主要编程语言。
在我们深入讨论之前,我们先来谈谈数据科学家的受欢迎程度。Stack Overflow 在 2018 年进行的开发者调查显示,Python 是最受欢迎的编程语言,其次是 Java 和 Javascript。
Python 拥有无可争议的受欢迎程度。Python 的创造者 Guido Van Rossum 说:“我当然没有打算创造一种面向大众消费的语言。”可以肯定地说,他做了相反的事情,因为 Python 为那些回避编码的人带来了编码的前沿——过于复杂的语法早已成为过去。
这个描述流行 Python 用例的图表是开发者调查的另一个成果。最初,web 开发似乎是 Python 最受欢迎的用途,约占 26%。然而,数据分析和机器学习的结合揭示了惊人的 27%。那么为什么对 ML 来说 Python 这么受欢迎呢?
在我们深入研究之前,我们必须了解人工智能项目在技术栈和所需技能方面不同于传统的软件项目。因此,选择一种稳定、灵活、拥有多样化工具的编程语言是非常重要的。Python 满足了所有这些。
除了简单性和一致性,它还有一个很棒的社区,可以帮助构建各种 ML 框架和库。这些是预先编写的 Python 代码包,可以帮助机器学习工程师快速解决常见任务,并更快地开发产品。
大众图书馆 | 特定用途 | 利益 |
---|---|---|
支持多个后端神经计算引擎
|
用户友好,易于学习和建立模型,广泛采用
|
| |
大型数值计算/多层神经网络
|
漂亮的计算图,库管理,调试,可扩展性,流水线
|
| |
ML 和统计建模工具
|
进行各种任务,包括预处理、聚类、模型选择等。大量的功能,以及为各种目的而建造的
T3 |
| |
从事线性代数、傅立叶变换和矩阵领域的工作
|
减少存储数据的内存使用量
|
| |
构建在 NumPy 扩展之上,让用户操作和可视化数据
|
为了可视化和操纵数据的高级命令和类
|
| |
用于数据分析、清理、探索、转换、可视化
|
多种功能,处理大数据,精简数据表现形式
|
| |
建立在 Matplotlib 的基础上,创建漂亮而丰富的统计图形
|
美学与内置剧情
|
正如您所看到的,Python 为 ML 提供了一种其他语言无法提供的简单体验:您不必重新发明轮子。
Python 比其他编程语言更直观,因为它的语法非常简单,是团队实现的最佳选择。开发人员可以专注于手头的 ML 任务,如复杂的算法或通用的工作流,而不是语言的细节。看一下这个简单的例子:
C:
Java:
main()
{
printf("Hello World");
}
Python 还具有难以置信的灵活性和平台无关性,因为它不需要 Python 解释器就能得到 Linux、Windows 和 macOS 的支持。这也使得在使用自己的 GPU 时,训练变得更加便宜和简单。57%的机器学习工程师报告使用 Python,其中 33%的人更喜欢将其用于开发。
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World");
}
}
然而,对于任何事情,我们也必须考虑 Python 的缺点:
几乎没有统计模型包
- 由于全局解释器锁(GIL ), Python 中的线程化很成问题,多线程 CPU 绑定的应用程序比单线程运行得慢。
- 稀有
现在让我们来看看 R。R 是为高级统计和数据可视化而构建的。对于任何想要理解机器学习或统计中涉及的数学计算的人来说,这是适合你的语言。
在数据分析和可视化方面,Python 中的 R beats。它允许快速原型和数据集工作,以建立您的 ML 模型。例如,如果你想将大段文字分解成单词或短语来寻找模式,R 会击败 Python。
r 还附带了一个令人印象深刻的库和工具集,以帮助您的机器学习追求。这些高级数据分析包涵盖了建模前和建模后阶段,是为模型验证或数据可视化等特定任务而设计的。
有用的包和库包括:
大众图书馆
特定用途 | 利益 | |
---|---|---|
用来“整理”你的数据并使其易于与
一起工作的集合 | 用于“整理”您的数据并使其易于使用的集合 | 更高效的代码、有组织的数据 |
|
Tidyr 的一部分,将图形分解成语义组件的数据可视化包
| Tidyr 的一部分,数据可视化包,将图形分解成语义组件 | 更轻松地浏览数据,同时创建复杂的可视化效果 |
|
Tidyr 的一部分,帮助挑战
| Tidyr 的一部分,帮助应对数据操作挑战 | 快速,直接连接到外部数据库,链函数,以减少混乱和编码,语法简单 |
|
用于业务和财务分析
| 用于业务和财务分析 | 模型和规模财务分析 |
除了一个活跃而有用的开源社区,R 还可以免费下载并附带 GNU 包,这使它跻身于 SAS 和 Matlab 等昂贵的替代软件之列。R Studio 是一个 IDE,它允许开发人员创建 ML 算法的统计可视化。r 附带了一个控制台、语法高亮编辑器和其他有用的工具,比如绘图、历史、调试、工作空间管理。
要开始使用 R 并下载 R studio,请查看其网站。
Screenshot of R Studio | Source
现在我们来谈谈不那么有趣的部分。R 的缺点包括:
陡峭的学习曲线: R 是一门难学的语言,这可能会增加为一个项目或团队寻找专家的难度。您使用的任何新包都需要学习,并且没有完整的 r 文档。
- r 可能不一致,因为它的算法来自第三方。
- 说到 ML,最大的问题往往是 R 或 Python。两者各有优缺点,但 Python 更适合数据操作和重复性任务。如果你想构建某种使用 ML 的产品,那就用 Python 吧。如果你需要一些深入的分析,R 是你最好的选择。
朱莉娅
我们已经相当深入地讨论了 ML 的两种巨型语言。但是 Julia 是一个真正的失败者:虽然不像 Python 和 R 那样受欢迎,但它的功能与 Python、MATLAB 和 R 相当,并且具有 C++和 Java 的执行速度。现在这个理由足够让你记住它了!Java 有两个巨大的优势:速度+为并行而设计。因为它感觉像一种脚本语言,所以转换起来也不困难,所以 Python / R 开发人员可以很容易地掌握它。
在 AI 方面,Julia 最适合深度学习(仅次于 Python),并且非常适合快速执行基础数学和科学。Julia 专注于科学计算领域,非常适合这个领域。由于这些计算能力,Julia 具有可伸缩性,并且比 Python 和 r 更快。
其强大的本地工具包括:
大众图书馆
特定用途 | 利益 | |
---|---|---|
轻量级的 ML 库,有用的工具,帮助你使用朱莉娅的全部力量
| 轻量级 ML 库,有用的工具,帮助您使用朱莉娅的全部权力 | 用 Julia 编写,具有与 Tensorflow 相同的功能 |
|
深度学习框架,在 Julia
中使用模型的动态计算图支持 GPU 运算和自动微分 | 深度学习框架,使用 Julia 中的模型的动态计算图支持 GPU 操作和自动微分 | 用朱莉娅写的,活跃社区 |
|
可用于数据处理&操纵、性能评估、交叉验证、模型调整等。
| 可用于数据处理和操作、性能评估、交叉验证、模型调整等。 | |
|
Julia 版 Tensorflow
| 张量流的 Julia 版本 | 用 Julia 编写,提供了将计算表示为数据流图的灵活性 |
|
茱莉亚版 Scikit 学
| 朱莉娅版 Scikit Learn | 用 Julia 写的,让你进行预处理,聚类,模型选择等。:多种用途 |
Julia 还可以调用 Python、C 和 Fortran 库,并带有交互式命令行和全功能调试器。
然而,与 Python 相比,Julia 在面向对象编程、可伸缩性、社区和各种库方面有所欠缺。它还处于初级阶段。大多数 ML 专家都使用两者:Julia 用于后端深度学习,在那里它实现了最佳的性能比率,Python 用于前端。
Java Script 语言
当您想到 ML 时,JavaScript 肯定不是第一个想到的。虽然 JavaScript 主要用于 web 开发,但它已经用 TensorFlow.js 滑入了机器学习,TensorFlow.js 是 Google 创建的开源库,它使用 JavaScript 在浏览器中构建机器学习模型,或者在 Node.js 中,JavaScript。对于那些只熟悉 web 开发的人来说,TensorFlow.js 是进入 ML 的绝佳入口。TensorFlow.js 支持 WebGL,所以你的 ML 模型可以在有 GPU 的情况下运行;例如,如果用户在手机上打开网页,该模型可以利用感官数据。Tensorflow.js 允许您导入现有的预训练模型,重新训练导入的模型,并在浏览器中创建模型。我们来看看 TensorFlow.js 的利弊
An example of what you can do with TensorFlow.js | Source
赞成的意见
| 骗局 |
具有很高的计算性能
|
| --- | --- |
| 具有很高的计算性能 | 数据限制:无法访问浏览器,这意味着数据资源有限 |
| 高度安全,设备在运行应用程序时可抵御外部威胁 | 对硬件加速的有限支持 |
| 几个用例:浏览器中的 Javascript 应用程序、Node.js 环境中的服务器、桌面、移动设备等。 | 单线程,这会限制性能 |
许多开发人员将 ML 从后端服务器带到前端应用程序。TensorFlow.js 允许开发人员在没有复杂后端系统的情况下,用纯 HTML 创建和运行 ML 模型。这种简单性让您可以轻松地创建伟大的项目。这里有几个例子:
自动图片处理:通过卷积神经网络生成艺术
- 使用人工智能的游戏
- 内容推荐引擎
- 了解本地网络/设备使用模式的活动监控
- 对象检测,例如识别照片中的许可证
- 斯卡拉
Scala 比 Python 快得多,并且将面向对象和函数式编程的精华带到了一种高级语言中。它最初是为 Java 虚拟机(JVM)构建的,非常容易与 Java 代码交互。开发人员可以轻松构建高性能系统,同时通过 Scala 使用静态类型来避免错误。
Scala 有几个用于线性代数、随机数生成、科学计算等的库。:
大众图书馆
特定用途 | 利益 | |
---|---|---|
用于通过数组支持、2D 数据结构等进行数据操作。
| 用于通过阵列支持、2D 数据结构等进行数据操作。 | 构建在阵列支持的数据结构之上 |
|
一个快速 GPU 和 CPU 加速库
| 快速 GPU 和 CPU 加速库 | |
|
主要科学计算库,最好来自 MATLAB 的数据结构和来自 Python 的 Numpy 类
| 主要的科学计算库,最好来自 MATLAB 的数据结构和 Python 的 Numpy 类 | 对数据阵列进行快速高效的操作 |
|
Scala 版 MATLAB 计算功能
| MATLAB 计算功能的 Scala 版本 | 附带 Scala 的可伸缩性和强大功能 |
|
用于自然语言处理
| 用于自然语言处理 | 由于高速和 GPU 的使用,可以解析成千上万的句子 |
从性能、学习曲线和易用性来看,Scala 也是 Apache Spark 的绝佳选择(Apache Spark 是一个数据处理框架,用于在巨型数据集上处理任务,并将数据处理任务分布到多台计算机上)。
现在我们来比较一下 Scala 的优缺点:
赞成的意见
| 骗局 |
允许利用 JVM 库,常用于企业代码
|
| --- | --- |
| 允许利用 JVM 库,经常在企业代码中使用 | 陡峭的学习曲线结合了函数式编程和面向对象编程 |
| 几个可读的语法特性 | 有限的开发人员社区、资源 |
| 功能特性,如字符串比较、模式匹配等。 | C/C++ |
C/C++和机器学习是一对困难的组合。从一开始,Python 似乎就比 C/C++有许多优势:
Python 更灵活,语法简单,也更容易学习
使用 Python 可以让你专注于 ML 的细微差别,而不是语言
- 大量的库和包
- 您可以通过 Python 解释器,仅通过命令行与数据交互工作
- 用 C/C++调试 ML 算法要困难得多
- 然而,使用 C/C++也有一些优点:
- C/C++是最有效的语言之一,机器学习算法需要很快。
使用 C/C++可以让你控制从内存、CPU 等开始的单个资源。
- 很多 ML 框架比如 TensorFlow,caffe,vowpal,wabbit,libsvm 等等。实际上是用 C++实现的
- 你一定会在招聘人员和公司面前脱颖而出
- 作为最古老的编程语言之一,C 和 C++在机器学习方面是一个利基。C 可以用来补充现有的机器学习项目,计算机硬件工程师更喜欢 C,因为它的速度和控制水平-你可以使用 C/C++从头实现算法。
- 通常,在以下情况下使用 C/C++:
速度极其重要
没有适合您的用例的 Python 库
-
您希望控制内存的使用,因为您将达到系统的极限
-
大众图书馆
特定用途
| 利益 | |
大型数值计算/多层神经网络
|
| --- | --- | --- |
| 大型数值计算/多层神经网络 |
漂亮的计算图,库管理,调试,可扩展性,流水线
|
微软认知工具包
|
|
深度学习工具包,使用有向图描绘神经网络一系列计算步骤
|
开源,让你使用庞大的数据集
| |
| 深度学习框架,让您可以使用富有表现力的架构、可扩展的代码等。 | |
让你更快的实现 ML 算法
|
| 让您更快地实现 ML 算法 |
强调扩展性和速度,易于使用
|
【DyNet】
|
|
支持 NLP、图结构、强化学习等的神经网络库。
|
高性能,在 CPU 或 GPU 上高效运行
| |
| 有各种各样的 ML 方法,如多种数据表示,算法类,通用工具等。 |
开源,各种工具
| Java 语言(一种计算机语言,尤用于创建网站) |
许多公司的基础设施、软件、应用程序等。都是用 Java 构建的,这意味着集成和兼容性问题被最小化了
许多流行的数据科学框架,如 Fink、Hadoop、Hive 和 Spark 都是用 Java 编写的
Screenshot of the Weka Machine Learning Workbench | Source
Java 可用于数据科学中的各种过程,如清理数据、数据导入和导出、统计分析、深度学习、NLP 和数据可视化
-
Java 虚拟机允许开发人员编写跨多个平台的相同代码,并且可以更快地构建工具
-
用 Java 构建的应用程序易于扩展
-
Java 像 C/C++一样运行迅速,这就是为什么 Linkedin、脸书和 Twitter 使用 Java 来满足他们的一些 ML 需求
-
Java 是一种强类型编程语言,这意味着开发人员必须对变量和数据类型有明确而具体的了解
-
生产代码库通常用 Java 编写
-
Java 也为 ML 配备了各种工具和库:
-
大众图书馆
特定用途
利益
| |
用于通用机器学习:算法、数据挖掘、数据分析、预测建模
| 用于通用机器学习:算法、数据挖掘、数据分析、预测建模 |
| --- | --- | --- |
|
开源,各种工具
| 开源,各种各样的工具 |
用于创建可扩展的机器学习算法
|
|
可扩展的、现成的大型数据挖掘任务框架
| 适用于大型数据挖掘任务的可扩展、即用型框架 |
开源软件,用于实时对数据流进行数据挖掘
|
| | | 广泛支持深度学习算法的框架 |
|
开源,提供高处理能力
| 开源,提供高处理能力 |
专门用于自然语言处理的工具包,可以用于主题建模、文档分类、聚类、信息抽取
|
|
建立在 Java 之上,让你用 ML 来处理文本文档
| 构建于 Java 之上,允许您使用 ML 来处理文本文档 | 所有编程语言的能源数据 |
正如所料,在我们今天讨论的所有语言中,C 语言被证明是最快和最节能的。
所有编程语言的比较
让我们最后看一下这些语言提供的各种特性:
Comparison of all the programming languages
计算机编程语言
稀有
朱莉娅 | java 描述语言 | 斯卡拉 | C/C++ | Java 语言(一种计算机语言,尤用于创建网站) | 面向对象、命令式、函数式、面向方面、反射式 | 面向对象和函数式编程的混合,命令式,反射式 | |
---|---|---|---|---|---|---|---|
多重调度,因此易于表达面向对象和函数式编程模式 | 命令式、面向对象、功能性、反思性 | 面向对象、功能性、通用性 | 祈使句 | 命令式、面向对象、通用、反射式 | 否,因为语言参考包含在每个版本的文档中 | 否 | |
是 | 是 | 是 | 是 | 强 | 强 | ||
强 | 虚弱 | 强 | 虚弱 | 强 | 安全 | 安全 | |
安全 | 安全 | 不安全 | 安全 | 隐含的 | 隐含的 | ||
隐含的 | 隐含的 | 部分隐式 | 显式 | 显式 | 鸭子,结构 | ||
主格结构 | 主格 | 主格 | 动态 | 动态 | |||
动态 | 动态 | 静态 | 静态 | 静态 | 按值 | 所需值 | |
“路过共享” | 按值 | 按值+名称 | 通过值/指针 | 按值 | 是 | 是 | |
是 | 是 | 是 | Optional | 是 | ML,网络开发。,游戏开发。,软件开发。 | 统计计算与图形、数值计算、可视化 | |
并行性,//r//n//r//n“我们想要像 Python 一样可用于一般编程,像 R 一样易于统计,像 Perl 一样自然地处理字符串,像 Matlab 一样强大地处理线性代数,像 shell 一样善于将程序粘在一起。”出处
| 并行性,//r//n//r//n“我们想要像 Python 一样适用于一般编程,像 R 一样易于统计,像 Perl 一样自然地处理字符串,像 Matlab 一样强大地处理线性代数,像 shell 一样善于将程序粘合在一起。”来源 | Web 脚本、Web +移动开发、Web 服务器+游戏开发。 | 通用语言、并行计算、DSL 和计算 | 应用程序、服务器端、后端开发、Android 开发。 | | 生产力、代码可读性、简单性、模块化 | 交互式、全面的数据集分析,高级数据分析 |
| 通用、全面的数据集分析、强大且快速 | Web 开发。 | Java 的更好替代方案,简洁、类型安全、可伸缩、平台独立 | 低级别访问 | 简单、安全、分布式、面向对象、健壮、可移植的“一次编写,随处运行” |
人气:
【按优先级排列】
| 人气:
【优先顺位】 | 57% |
| 31% | 28% | 不适用 | 43% | 41% | | 33% | 5% |
| 不适用 | 7% | 不适用 | 19% | 16% | | 情感分析、NLP/chatots、网络挖掘 | 情感分析、生物工程/生物信息学、欺诈检测 |
| 科学计算 | 搜索引擎,网络开发。 | 大数据 | 游戏中的人工智能、机器人移动、网络安全+网络攻击检测 | 客户支持管理、网络安全+网络攻击检测+欺诈检测 |
进入 ML 前的专业背景*
| 进入 ML 前的专业背景* | 数据科学 |
| 数据分析师/统计师 | 前端 web 开发人员 | 不适用 | 嵌入式计算硬件,电子工程师 | 前端桌面应用开发者 | | 对 ML 好奇 | 数据科学 |
| | 增加获得工作的机会 | | 将机器学习添加到现有应用中 | 公司 | | Keras, Tensorflow, Scikit learn, NumPy, SciPy, Pandas, Seaborn | Tidyr,Ggplot2,Dplyr,tidy quat |
| 流动、膝、MLBase.jl、tensorflow . jl、ScikitLearn.jl | TensorFlow.js | 鞍座、气雾、微风、标量、NLP | Tensorflow,微软认知工具包,Caffe,MLpack,DyNet,幕府将军 | Weka,Apache mahout,海量在线分析,Deeplearning4j,Mallet |
资源/文档/社区
| 资源/文档/社区 | 伟大的 |
| 伟大的 | 可能对 ML 更好 | 可能更大 | 好的 | 好的 | Could be bigger | Good | Good |
生产的概念证明
原文:https://web.archive.org/web/https://neptune.ai/blog/proof-of-concept-to-production
概念验证(POC) 基本上就是一个实验。它以一个项目、系统、程序或产品的形式出现,虽然没有 100%完成,但已经准备好在现实世界中进行尝试。
简单来说,概念证明是一种验证你的想法或理论能够进入现实世界的演示。它还证明了服务或产品是有成本效益的,值得投资金钱和资源来开发它。在大多数情况下,POC 用于有效的研究目的,并用于投资者确定产品/服务是否有足够的潜力来表明您的产品可以盈利。POCs 是开发的一个重要部分,因为它可以发现工作流中的差距以及解决问题的方法。概念验证就像项目的演示版本,通过给定的参数,系统如何实现或吞吐量如何实现。
在本文中,我们将讨论:
什么是概念证明?
您的项目有可能有独特的需求,甚至不清楚是否有可能将它变成现实。概念验证是测试这些独特需求的战略性方法,以确保您不会将预算浪费在一个不可能的产品上。
因此,POC 不是一个生产就绪的系统,它更像是一个测试您的系统是否能在生产中实际工作的过程,以及您是否应该继续投资于它。
人工智能和机器学习中的概念验证是在简单的算法和少量数据上开发和测试的,以了解进一步开发它们是否有意义。从概念验证到生产的过程并不简单。如果 POC 成功,那么项目将进入生产阶段。除了告诉您一个项目是否值得追求,POCs 还可以帮助您回答其他问题,例如:
- 您的工作流程设置是否正确?
- 发展中会面临哪些问题?
- 功能是否满足项目需求?
如果项目想法很简单,大多数人会认为它是可行的,并跳过概念验证。这种方法通常是可行的,但有时它可能会变成一个代价高昂的错误。
为什么概念证明很重要?
概念验证说明了您的产品/服务的功能,并告诉您如何正确规划项目。人工智能和 ML 中的错误代价高昂,而概念验证可以是一种很好的方式节省资金,向项目利益相关者展示您的计划,并表明您的产品是否值得信赖。
但这还不是全部。以下是人工智能中的概念证明是一种良好实践的更多原因:
POC 帮助您在早期阶段计算风险。无需投入大量的金钱和精力,您就可以测试您的项目是否值得开发,并确切地了解它的风险有多大。假设您计划将您的应用程序迁移到某个平台上,您不确定它是否可行。因此,概念验证将帮助您确定它是否有效,以及您能否继续推进它。
在进行 POC 时,您会发现许多意想不到的问题。有了这个问题,您可以考虑在进入生产阶段之前添加一个解决方案。概念验证会产生许多见解,或者与您产品数据的预测价值相关,或者与您面临的某些特定问题相关。这些见解在 POC 阶段期间和之后都很有帮助。
测试、增强和改进。从长远来看,在 POC 阶段获得的信息有助于公司,并创造了改进工作流或模型结构的机会,即使是在部署到生产之后。
让我们看一个场景,POC 在初始阶段发现问题。在进行 POC 时,它给我们额外的时间回去解决问题,并在展示它之前运行多个测试。概念验证可以改变生产的方式。如果您的 POC 具有良好的潜力,您可以在部署阶段对其进行调整和改进。通过概念验证,你可以向利益相关者和投资者展示你的产品有很大的盈利潜力。
Created by author with Canva
概念验证的方法
无论软件的领域或类型如何,有几个广泛的步骤适用于任何 POC。根据您的产品需求,您将需要大量的时间和资源来部署到生产环境中。
您必须专注于数据建模部分,以使模型更加准确。当您接近生产阶段时,从数据角度来看,事情会变得更加复杂。
我们需要定义我们的需求,或者我们客户的需求,并确定满足他们的最佳方式。一旦你准备好这个概念,你就可以将点映射到解决方案。你可以收集用户/客户对你的概念的反馈,从客户的角度询问可以改进的地方。特别是,您需要用以下内容结束此阶段:
- 问题定义:问题定义就是定义需求并进行分析。有时 POC 失败是因为它们缺乏清晰的问题定义。它填补了产品的当前状态和期望状态之间的空白。
- 资料收集 & 准备:一旦一切都定义好了,就该开始准备资料了。探索和试验数据集,选择合适的数据集,看看他们是否遗漏了任何关键的数据点。通过排序、结构化、处理和添加缺失的数据点来准备数据。监视数据如何生成输出。一旦数据准备阶段完成,就是开发和测试的时候了。
一旦你为你的产品做了所有的研究,是时候为你的产品制作原型并进行测试了。你必须为关键功能创建一个用户界面/UX ,并开发一个原型产品。在内部测试,或者甚至与一组特殊的外部用户一起测试。原型设计有三个关键要素:
- 建模:添加自定义或预定义的机器学习算法。你可以尝试不同的机器学习实验,创建一个 ML 模型。用算法在一组数据上训练你的模型。
- 协作:团队之间高效的信息交流让工作变得更加容易。
- 测试:一旦训练完成,就该用不同的数据来测试你的模型了,包括它从未见过的数据。该流程允许数据科学家监控模型的运行情况、需要改进的地方以及哪里出了问题。通过测试,你检查你的算法已经学习的逻辑步骤,并且看它是否与产品解决方案匹配。
一旦您的 POC 启动并运行,您就可以创建一个 MVP (最小可行产品),并向更多的用户群展示该产品。到目前为止,您已经收集了大量关于产品及其内部运作的信息。反馈、测试结果、原型等等。所以,现在利用这些信息设计一个路线图,将你的产品/服务部署到现实世界中。
- 验证:这是 POC 的最后一个阶段,每个信息、结果和问题都呈现给团队和利益相关者。您将讨论部署路线图、数据收集、监控路线图等等。
评估概念验证
一旦你完成了概念验证,你需要根据最初的目标和假设来评估你的产品或服务的结果。如果您的 POC 符合您之前的假设,甚至超过了它们,这意味着您的思路是正确的。
通过 POC 过程,您可能会学到一些关于如何改进产品的知识,并准确地意识到生产中可能会出现的问题。您可能会发现有些特性超出了范围,需要大量的改进。
一旦您对您的概念验证做出积极评价,就该衡量您的概念验证了。为了将您的 ML 模型投入生产,您现在还必须处理一些非关键的特性。此外,您还必须在更大的客户群和更大的基础设施上监控模型性能。
POC 对生产的挑战
事情并不总是像你想的那样发展。在 POC 到生产阶段期间和之后,您将面临许多问题。公司在从 POC 转向生产时会面临许多问题:
- 数据问题,
- 管理不当,
- 不适当的 ML 工具和框架,
- 团队中没有足够的专业知识。
组织应该有合适的架构来支持你的 AI/ML 集成。组织必须进行大规模研究,开发多功能团队,并使用不同的硬件和软件参数测试产品。
将机器学习或人工智能投入生产需要大量的耐心、努力和资源。这需要大量的研究、熟练的团队、硬件和软件资源以及专家的咨询。由于这些挑战,一个好的和潜在的想法在这个阶段被抛弃。以下是公司在 POC 到生产阶段面临的几大挑战。
Created by author with Canva
您可能有最好的模型,但是如果您的组织不了解它的潜力,它就不会投入生产。有时组织不提供对整个机器学习环境的访问。如果模型或特性出了问题,可能没有人会承担责任。机器学习和基于人工智能的产品/服务价格昂贵,因此有时组织只是为了省钱而减少员工和资源需求。当公司看到运行 POC 的成本时,通常会后退一步。但是随着人员和软件需求的减少,这可能会导致延迟和重大问题
处于生产水平。由于组织中管理不当、法律等各种问题,模型无法存活并被丢弃。
模型不能进入生产,主要是因为组织没有足够的工具和最佳实践知识。组织经常削减硬件和软件资源以节省资金。这导致许多问题,并最终对 POC 产生影响。组织经常使事情变得复杂,并且无法达到他们最初想到的目标,导致模型生存的延迟和挑战。
有许多与数据相关的问题,如数据收集、质量和数量。数据收集是团队花费大部分时间的地方。收集正确的数据和所需的数据格式是一个具有挑战性的部分,数据有不同的格式和文件。如果数据没有被正确地组织和清理,模型可能会有很多问题。
概念验证中使用的数据可能与训练数据集存在一些差距和问题。生产需要格式良好的数据。查看指标并填补数据集中的空白。
当从 POC 转移到生产时,数据量不足以检测任何变化和训练模型。你需要大量的数据来增加你的模型的预测。假设您的模型是关于检测一些水果,但用于训练模型的数据集是在冬天拍摄的。模型精度可能是正确的,但它无法检测未成熟的水果。数据不够大,无法提供准确的结果。最好使用真实世界的数据来获得更好的结果。
当您从概念验证转向生产时,数据及其条件可能会发生变化。该模型开始失去其预测能力。这会影响模型的性能。这可能是因为在 POC 期间和生产期间收集的数据有不同的收集方法。在投入生产之前,您可能需要重新考虑几个步骤。
为了正确地管理和操作您的模型,您需要一个良好的基础设施。它有助于您更轻松地监控和处理每个流程。您需要一个合适的环境来处理和提供数据。拥有一个数据就绪模型有助于您在生产阶段降低成本和复杂性。要在生产中运行模型,您需要一个适当的管理和监控系统。您需要测试、版本化和监控您的模型。
Created by author with Canva
概念验证后需要考虑的事项
你的产品/服务可能已经开始运行,但这并不是你工作的结束。你必须继续致力于生产架构。您将填补数据集中的空白,监控工作流程,并定期更新系统。一旦你所有的实验都在生产阶段完成,你可能需要考虑一些事情。
在数据准备和训练阶段使用可重复、可重用的程序可以使事情变得健壮和易于扩展。笔记本通常不容易管理,但使用 Python 文件可能是一个好的选择,因为它将提高工作质量。开发可重复管道的关键是将机器学习环境视为代码。这样,您的整个端到端管道可以在重大事件发生时执行。
- 数据存储和监控
对于您的 ML 实验的连续过程,您必须关注数据和环境。如果输入数据发生变化,您可能会发现模型准确性的问题。因此,监控数据并以正确的格式实现数据也很重要,因为有时实现的数据和连接的标签可能已经改变。
当你从 POC 进入生产时,从事产品/服务的开发人员和数据科学家的数量需要增加,因为这将有助于分配工作并使交付更快。如果在生产中没有适当的治理,会出现许多问题。你必须创建一个中心,让团队的每个成员都可以联系在一起,并且可以访问必要的东西。这使得事情变得非常顺利,易于维护。管理和组织你的机器学习实验本身就是一项任务。
结论
概念验证是将你的想法运用到现实世界中的一个重要部分。这个过程帮助你评估你的产品需求和你在生产中可能面临的困难。这有助于你专注于构思你的想法。
POC 为您提供了关于您的产品/服务的详细见解以及改进方法。它可以帮助您发现某个特定的特性在实际部署中是好是坏。甚至在投入生产之前,您就可以发现问题并解决它们。值得!
额外研究和推荐阅读
哈希尔·帕特尔
Android 开发者和机器学习爱好者。我热衷于开发移动应用程序、制造创新产品和帮助用户。
阅读下一篇
机器学习模型管理:它是什么,为什么你应该关心,以及如何实现它
13 分钟阅读|作者卡努马王子| 2021 年 7 月 13 日更新
13 mins read | Author Prince Canuma | Updated July 13th, 2021
机器学习正在兴起。因此,新的问题不断涌现,ML 开发者和技术公司一起不断构建新的工具来解决这些问题。
如果我们以一种非常基本的方式来看待 ML,我们可以说 ML 在概念上是一种增加了一点智能的软件,但与传统软件不同,ML 本质上是实验性的。与传统的软件开发相比,它有一些新的组成部分,例如:健壮的数据、模型架构、模型代码、超参数、特性等等。因此,自然地,工具和开发周期也不同。软件有 DevOps,机器学习有 MLOps。
如果听起来不熟悉,下面是 DevOps 和 MLOps 的简短概述:
DevOps 是一套开发、测试、部署和操作大规模软件系统的实践。有了 DevOps,开发周期变得更短,部署速度加快,系统发布变得可审计和可靠。
MLOps 是数据科学家和运营专业人员之间进行协作和沟通的一套实践。应用这些实践可以提高最终质量,简化管理流程,并在大规模生产环境中自动部署机器学习和深度学习模型。这使得模型更容易与业务需求和法规要求保持一致。
MLOps 的关键阶段是:
数据采集
- 数据分析
- 数据转换/准备
- 模型开发
- 模特培训
- 模型验证
- 模型服务
- 模型监控
- 模型再训练
- 我们将深入研究这一过程,所以拿起一杯你最喜欢的饮料,我们走吧!
We’re going to do a deep dive into this process, so grab a cup of your favorite drink and let’s go!
pyLDAvis:每个 NLP 数据科学家都应该知道的主题建模探索工具
你有没有想过根据新闻、论文或推文的主题对它们进行分类?知道如何做到这一点可以帮助你过滤掉不相关的文档,并且通过只阅读你感兴趣的内容来节省时间。
这就是文本分类的目的——允许您训练您的模型识别主题。这种技术允许您使用数据标签来训练您的模型,并且它是监督学习。
在现实生活中,您可能没有用于文本分类的数据标签。你可以检查每一个文档来标记它们,或者雇佣其他人来做这件事,但是这需要很多时间和金钱,尤其是当你有超过 1000 个数据点的时候。
没有训练数据,你能找到你的文档的主题吗?可以,可以用主题建模来做。
什么是主题建模?
使用主题建模,可以对一组文档进行单词聚类。这是无监督的学习,因为它自动将单词分组,而没有预定义的标签列表。
如果你输入模型数据,它会给你不同的单词集合,每一个单词集合都描述了主题。
(0, '0.024*"ban" + 0.017*"order" + 0.015*"refugee" + 0.015*"law" + 0.013*"trump" '
'+ 0.011*"kill" + 0.011*"country" + 0.010*"attack" + 0.009*"state" + '
'0.009*"immigration"')
(1, '0.020*"student" + 0.020*"work" + 0.019*"great" + 0.017*"learn" + '
'0.017*"school" + 0.015*"talk" + 0.014*"support" + 0.012*"community" + '
'0.010*"share" + 0.009*"event")
当你看到第一组单词的时候,你会猜测这个话题是军事和政治。看第二组单词,你可能会猜测话题是公共事件或学校。
这个挺有用的。你的文本被自动分类,不需要给它们贴标签!
用 pyLDAvis 可视化主题建模
主题建模是有用的,但是仅仅看上面的单词和数字的组合是很难理解的。
理解数据最有效的方法之一是通过可视化。有没有一种方法可以将 LDA 的结果可视化?是的,我们可以用皮戴维斯。
PyLDAvis 允许我们解释如下主题模型中的主题:
很酷,不是吗?现在我们将学习如何使用主题建模和 pyLDAvis 对推文进行分类并可视化结果。我们将分析包含 6000 条推文的真实 Twitter 数据集 。
看看能找到什么话题。
如何开始使用 pyLDAvis 以及如何使用它
将 pyLDAvis 安装在:
pip install pyldavis
接下来,让我们导入相关的库:
import gensim
import gensim.corpora as corpora
from gensim.corpora import Dictionary
from gensim.models.coherencemodel import CoherenceModel
from gensim.models.ldamodel import LdaModel
from pprint import pprint
import spacy
import pickle
import re
import pyLDAvis
import pyLDAvis.gensim
import matplotlib.pyplot as plt
import pandas as pd
如果您想访问上面的数据并阅读本文,请下载数据并将数据放在当前目录中,然后运行:
tweets = pd.read_csv('dp-export-8940.csv')
tweets = tweets.Tweets.values.tolist()
tweets = [t.split(',') for t in tweets]
如何使用 LDA 模型
主题建模包括计算单词和对相似的单词模式进行分组,以描述数据中的主题。如果模型知道词频,以及哪些词经常出现在同一文档中,它将发现可以将不同的词组合在一起的模式。
我们首先将一个单词集合转换成一个单词包,单词包是一个元组列表(word_id,word_frequency)。gensim . corpora . dictionary是一个很好的工具:
id2word = Dictionary(tweets)
corpus = [id2word.doc2bow(text) for text in tweets]
print(corpus[:1])
[[(0, 1), (1, 1), (2, 1), (3, 3), (4, 1), (5, 2), (6, 2), (7, 1), (8, 1), (9, 1), (10, 1), (11, 2), (12, 2), (13, 1), (14, 1), (15, 1), (16, 2), (17, 1), (18, 1), (19, 1), (20, 2), (21, 1), (22, 1), (23, 1), (24, 1), (25, 2), (26, 1), (27, 1), (28, 1), (29, 1), (30, 1), (31, 1), (32, 1), ... , (347, 1), (348, 1), (349, 2), (350, 1), (351, 1), (352, 1), (353, 1), (354, 1), (355, 1), (356, 1), (357, 1), (358, 1), (359, 1), (360, 1), (361, 1), (362, 2), (363, 1), (364, 4), (365, 1), (366, 1), (367, 3), (368, 1), (369, 8), (370, 1), (371, 1), (372, 1), (373, 4)]]
这些元组是什么意思?让我们将它们转换成人类可读的格式来理解:
[[(id2word[i], freq) for i, freq in doc] for doc in corpus[:1]]
[[("'d", 1),
('-', 1),
('absolutely', 1),
('aca', 3),
('act', 1),
('action', 2),
('add', 2),
('administrative', 1),
('affordable', 1),
('allow', 1),
('amazing', 1),
...
('way', 4),
('week', 1),
('well', 1),
('will', 3),
('wonder', 1),
('work', 8),
('world', 1),
('writing', 1),
('wrong', 1),
('year', 4)]]
现在让我们构建一个 LDA 主题模型。为此,我们将使用gensim . models . LDA model . LDA model:
lda_model = LdaModel(corpus=corpus,
id2word=id2word,
num_topics=10,
random_state=0,
chunksize=100,
alpha='auto',
per_word_topics=True)
pprint(lda_model.print_topics())
doc_lda = lda_model[corpus]
这里好像有一些模式。第一个话题可能是政治,第二个话题可能是体育,但模式不清楚。
[(0,
'0.017*"go" + 0.013*"think" + 0.013*"know" + 0.010*"time" + 0.010*"people" + '
'0.008*"good" + 0.008*"thing" + 0.007*"feel" + 0.007*"need" + 0.007*"get"'),
(1,
'0.020*"game" + 0.019*"play" + 0.019*"good" + 0.013*"win" + 0.012*"go" + '
'0.010*"look" + 0.010*"great" + 0.010*"team" + 0.010*"time" + 0.009*"year"'),
(2,
'0.029*"video" + 0.026*"new" + 0.021*"like" + 0.020*"day" + 0.019*"today" + '
'0.015*"check" + 0.014*"photo" + 0.009*"post" + 0.009*"morning" + '
'0.009*"year"'),
(3,
'0.186*"more" + 0.058*"today" + 0.021*"pisce" + 0.016*"capricorn" + '
'0.015*"cancer" + 0.015*"aquarius" + 0.013*"arie" + 0.008*"feel" + '
'0.008*"gemini" + 0.006*"idea"'),
(4,
'0.017*"great" + 0.011*"new" + 0.010*"thank" + 0.010*"work" + 0.008*"good" + '
'0.008*"look" + 0.007*"how" + 0.006*"learn" + 0.005*"need" + 0.005*"year"'),
(5,
'0.028*"thank" + 0.026*"love" + 0.017*"good" + 0.013*"day" + 0.010*"year" + '
'0.010*"look" + 0.010*"happy" + 0.010*"great" + 0.010*"time" + 0.009*"go"')]
让我们使用 pyLDAvis 来可视化这些主题:
点击此处亲自与可视化互动。
-
每个气泡代表一个主题。气泡越大,语料库中关于该主题的推文数量的百分比越高。
-
蓝色条代表语料库中每个单词的总频率。如果没有选择主题,将显示最常用单词的蓝色条。
-
红色条给出了给定主题产生给定术语的估计次数。从下面的图片中可以看到,单词“go”大约有 22,000 个,在主题 1 中使用了大约 10,000 次。红色条最长的单词是属于该主题的推文使用最多的单词。
-
气泡之间的距离越远,它们之间的差异就越大。例如,很难区分主题 1 和主题 2。它们看起来都是关于社会生活的,但是区分话题 1 和话题 3 要容易得多。我们可以看出话题 3 是关于政治的。
一个好的主题模型会有分散在整个图表中的大而不重叠的气泡。从图中我们可以看到,气泡聚集在一个地方。我们能做得比这更好吗?
是的,因为幸运的是,有一个更好的主题建模模型叫做 LDA Mallet。
如何使用 LDA Mallet 模型
如果一个主题中的单词相似,我们的模型会更好,所以我们将使用主题连贯性来评估我们的模型。主题一致性通过测量主题中高分单词之间的语义相似度来评估单个主题。好的模型会产生话题连贯性分数高的话题。
coherence_model_lda = CoherenceModel(model=lda_model, texts=tweets, dictionary=id2word, coherence='c_v')
coherence_lda = coherence_model_lda.get_coherence()
print('\\nCoherence Score: ', coherence_lda)
Coherence Score: 0.3536443343685833
这是我们的基线。我们刚刚使用了 Gensim 的内置版本的 LDA 算法,但是有一个 LDA 模型提供了更好的主题质量,称为 LDA Mallet 模型 。
让我们看看是否可以用 LDA Mallet 做得更好。
mallet_path = 'patt/to/mallet-2.0.8/bin/mallet'
ldamallet = gensim.models.wrappers.LdaMallet(mallet_path, corpus=corpus, num_topics=20, id2word=id2word)
pprint(ldamallet.show_topics(formatted=False))
coherence_model_ldamallet = CoherenceModel(model=ldamallet, texts=tweets, dictionary=id2word, coherence='c_v')
coherence_ldamallet = coherence_model_ldamallet.get_coherence()
print('\\nCoherence Score: ', coherence_ldamallet)
Coherence Score: 0.38780981858635866
连贯性评分更好!如果我们增加或减少题目数量,分数会更好吗?让我们通过微调模型来找出答案。本教程很好地解释了如何调整 LDA 模型。下面是文章中的源代码:
def compute_coherence_values(dictionary, corpus, texts, limit, start=2, step=3):
"""
Compute c_v coherence for various number of topics
Parameters:
----------
dictionary : Gensim dictionary
corpus : Gensim corpus
texts : List of input texts
limit : Max num of topics
Returns:
-------
model_list : List of LDA topic models
coherence_values : Coherence values corresponding to the LDA model with respective number of topics
"""
coherence_values = []
model_list = []
for num_topics in range(start, limit, step):
model = gensim.models.wrappers.LdaMallet(mallet_path, corpus=corpus, num_topics=num_topics, id2word=id2word)
model_list.append(model)
coherencemodel = CoherenceModel(model=model, texts=texts, dictionary=dictionary, coherence='c_v')
coherence_values.append(coherencemodel.get_coherence())
return model_list, coherence_values
model_list, coherence_values = compute_coherence_values(dictionary=id2word, corpus=corpus, texts=tweets, start=2, limit=40, step=4)
limit=40; start=2; step=4;
x = range(start, limit, step)
plt.plot(x, coherence_values)
plt.xlabel("Num Topics")
plt.ylabel("Coherence score")
plt.legend(("coherence_values"), loc='best')
plt.show()
看起来的连贯性分数随着话题数量的增加而增加。我们将使用具有最高一致性分数的模型:
best_result_index = coherence_values.index(max(coherence_values))
optimal_model = model_list[best_result_index]
model_topics = optimal_model.show_topics(formatted=False)
print(f'''The {x[best_result_index]} topics gives the highest coherence score \\
of {coherence_values[best_result_index]}''')
这 34 个话题的连贯得分最高,为 0.3912。
厉害!我们得到更好的连贯性分数。让我们看看如何使用 pyLDAVis 对单词进行聚类。
为了使用 pyLDAVis 可视化我们的模型,我们需要将 LDA Mallet 模型转换成 LDA 模型。
def convertldaGenToldaMallet(mallet_model):
model_gensim = LdaModel(
id2word=mallet_model.id2word, num_topics=mallet_model.num_topics,
alpha=mallet_model.alpha, eta=0,
)
model_gensim.state.sstats[...] = mallet_model.wordtopics
model_gensim.sync_state()
return model_gensim
optimal_model = convertldaGenToldaMallet(optimal_model)
您可以在这里 访问调好的型号 。然后用 pyLDAvis 进行可视化:
pyLDAvis.enable_notebook()
p = pyLDAvis.gensim.prepare(optimal_model, corpus, id2word)
p
点击这里来想象你自己。现在区分不同的话题更容易了。
- 第一个泡沫似乎是关于个人关系的
- 第二个泡沫似乎与政治有关
- 第五个泡沫似乎是关于积极的社会事件
- 第六个泡泡似乎是关于足球的
- 第七个泡沫似乎是关于家庭的
- 第 27 个泡沫似乎是关于体育的
还有很多。对于这些泡沫的话题,大家有不同的猜测吗?
结论
感谢阅读。希望您已经了解了主题建模是什么,以及如何用 pyLDAvis 可视化您的模型的结果。
虽然主题建模不如文本分类准确,但如果你没有足够的时间和资源给你的数据贴标签,这是值得的。为什么不先尝试一个更简单的解决方案,然后再想出更复杂、更耗时的方法呢?
可以在这里玩转本文中的代码。我鼓励您将这些代码应用到您自己的数据中,看看您会得到什么。
坤延川
Python 评估开发人员和数据科学家,喜欢尝试新的数据科学方法并为开源做出贡献。她目前每天都在 Data Science Simplified 上通过文章和日常数据科学技巧分享一点点美好的事物。
阅读下一篇
自然语言处理的探索性数据分析:Python 工具完全指南
11 分钟阅读|作者 Shahul ES |年 7 月 14 日更新
探索性数据分析是任何机器学习工作流中最重要的部分之一,自然语言处理也不例外。但是你应该选择哪些工具来高效地探索和可视化文本数据呢?
在这篇文章中,我们将讨论和实现几乎所有的主要技术,你可以用它们来理解你的文本数据,并给你一个完成工作的 Python 工具的完整之旅。
开始之前:数据集和依赖项
在本文中,我们将使用来自 Kaggle 的百万新闻标题数据集。如果您想一步一步地进行分析,您可能需要安装以下库:
pip install \
pandas matplotlib numpy \
nltk seaborn sklearn gensim pyldavis \
wordcloud textblob spacy textstat
现在,我们可以看看数据。
news= pd.read_csv('data/abcnews-date-text.csv',nrows=10000)
news.head(3)
数据集只包含两列,发布日期和新闻标题。
为了简单起见,我将探索这个数据集中的前 10000 行。因为标题是按发布日期排序的,所以实际上从 2003 年 2 月 19 日到 2003 年 4 月 7 日有两个月。
好了,我想我们已经准备好开始我们的数据探索了!
如何跟踪海王星的 PyTorch 闪电实验
原文:https://web.archive.org/web/https://neptune.ai/blog/pytorch-lightning-neptune-integration
使用 PyTorch Lightning 并想知道您应该选择哪个记录器来跟踪您的实验?
想要找到保存超参数、指标和其他建模元数据的好方法吗?
考虑使用 PyTorch Lightning 来构建您的深度学习代码,并且不介意了解它的日志记录功能?
不知道闪电有一个相当可怕的海王星积分?
这篇文章(很可能)适合你。
为什么是 PyTorch 闪电和海王星?
如果你从未听说过,PyTorch Lightning 是 PyTorch 之上的一个非常轻量级的包装器,它更像是一个编码标准而不是框架。这种格式可以让你摆脱大量的样板代码,同时保持简单易懂。
其结果是一个框架,为研究人员、学生和生产团队提供了尝试疯狂想法的终极灵活性,而不必学习另一个框架,同时自动化掉所有的工程细节。
您可以获得的一些出色功能包括:
- 在不改变代码的情况下,在 CPU、GPU 或 TPUs 上进行训练,
- 琐碎的多 GPU 和多节点训练
- 微不足道的 16 位精度支持
- 内置性能分析器(训练器(profile=True))
以及一大堆其他伟大的功能。
但是,伴随着这种轻松运行实验的强大功能和随意调整的灵活性,出现了一个问题。
如何跟踪所有变化,例如:
- 损失和指标,
- 超参数
- 模型二进制
- 验证预测
和其他能帮助你组织实验过程的东西?
PyTorch 闪电记录器
幸运的是,PyTorch Lightning 为您提供了一个将记录器轻松连接到 pl 的选项。训练器和一个支持的记录器可以跟踪之前提到的所有东西(和许多其他东西)是 NeptuneLogger,它保存你的实验在…你猜对了,海王星。
海王星不仅跟踪你的实验文物,而且:
最好的部分是,这种集成使用起来真的很简单。
让我给你看看它是什么样子的。
你也可以看看这个 colab 笔记本,玩玩我们将要谈到的你自己的例子。
PyTorch 闪电日志:基本集成(保存超参数、指标等)
在最简单的情况下,您只需创建NeptuneLogger
:
from pytorch_lightning.loggers import NeptuneLogger
neptune_logger = NeptuneLogger(
api_key="ANONYMOUS",
project_name="shared/pytorch-lightning-integration")
并将其传递给Trainer
的 logger 参数,以符合您的模型。
from pytorch_lightning import Trainer
trainer = Trainer(logger=neptune_logger)
trainer.fit(model)
通过这样做,您可以自动:
- 记录指标和损失(并创建图表),
- 记录并保存超参数(如果通过 lightning hparams 定义),
- 记录硬件利用率
- 记录 Git 信息和执行脚本
看看这个实验。
你可以监控你的实验,比较它们,并与他人分享。
对一辆四缸车来说还不错。
但是只要多一点努力,你就能得到更多。
PyTorch 闪电测井:高级选项
Neptune 为您提供了许多定制选项,您可以简单地记录更多特定于实验的内容,如图像预测、模型权重、性能图表等等。
所有这些功能对 Lightning 用户都是可用的,在下一节中,我将向您展示如何充分利用 Neptune。
创建 NeptuneLogger 时记录额外信息
创建记录器时,您可以记录其他有用的信息:
- 代码:快照脚本、jupyter 笔记本、配置文件等等,
- 超参数:记录学习率、历元数和其他东西(如果你正在使用 lightning 的 lightning
hparams
对象,它将被自动记录) - 属性:日志数据位置、数据版本或其他
- 标签:添加“resnet50”或“无增强”等标签来组织您的跑步。
只需将这些信息传递给你的记录器:
neptune_logger = NeptuneLogger(
api_key="ANONYMOUS",
project="shared/pytorch-lightning-integration",
tags=["pytorch-lightning", "mlp"],
)
用 PyTorch Lightning 记录训练中的额外事情
训练中可以记录很多有趣的信息。
您可能对监控以下内容感兴趣:
- 每个时期后的模型预测(考虑预测遮罩或覆盖的边界框)
- 诊断图表,如 ROC AUC 曲线或混淆矩阵
- 模型检查点,或其他对象
这真的很简单。只需转到您的LightningModule
并调用作为self.logger.experiment
可用的 Neptune 实验的方法。
例如,我们可以记录每个时期后的损失直方图:
class CoolSystem(pl.LightningModule):
def validation_epoch_end(self, outputs):
avg_loss = torch.stack([x['val_loss'] for x in outputs]).mean()
fig = plt.figure()
losses = np.stack([x['val_loss'].numpy() for x in outputs])
plt.hist(losses)
neptune_logger.experiments['loss_histograms'].log(File.as_image(fig))
plt.close(fig)
return {'avg_val_loss': avg_loss}
neptune_logger.experiment["your/metadata/metric"].log(metric)
#记录自定义指标neptune_logger.experiment["your/metadata/text"].log(text)
#日志文本值neptune_logger.experiment["your/metadata/file"].upload(artifact)
#日志文件neptune_logger.experiment["your/metadata/figure"].upload(File.as_image(artifact))
#日志图片、图表neptune_logger.experiment["properties/key"] = value
#添加键值对neptune_logger.experiment["sys/tags"].add(['tag1', 'tag2'])
#为组织添加标签
很酷吧?
但是…这不是你能做的全部!
PyTorch 闪电训练结束后记录东西
跟踪你的实验不一定要在你做完后才结束。安装循环末端。
您可能想要跟踪trainer.test(model)
的指标,或者计算一些额外的验证指标并记录下来。
要做到这一点,你只需要告诉NeptuneLogger
不要在安装后关闭:
neptune_logger = NeptuneLogger(
api_key="ANONYMOUS",
project_name="shared/pytorch-lightning-integration",
...
)
…您可以继续记录🙂
测试指标:
trainer.test(model)
其他(外部)指标:
from sklearn.metrics import accuracy_score
...
accuracy = accuracy_score(y_true, y_pred)
neptune_logger.experiment['test/accuracy'].log(accuracy)
测试集上的性能图表:
from scikitplot.metrics import plot_confusion_matrix
import matplotlib.pyplot as plt
...
fig, ax = plt.subplots(figsize=(16, 12))
plot_confusion_matrix(y_true, y_pred, ax=ax)
neptune_logger.experiment['test/confusion_matrix'].upload(File.as_image(fig))
整个模型检查点目录:
neptune_logger.experiment('checkpoints').upload('my/checkpoints')
转到本实验查看这些对象是如何被记录的:
但是…还有更多!
海王星让你在训练后获取实验。
让我告诉你怎么做。
把你的 PyTorch 闪电实验信息直接拿到笔记本上
您可以在实验完成后获取实验,分析结果,并更新度量、工件或其他东西。
例如,让我们将实验仪表板提取到熊猫数据帧:
import neptune.new as neptune
project = neptune.init('shared/pytorch-lightning-integration')
project.fetch_runs_table().to_pandas()
或者获取一个单独的实验并用训练后计算的一些外部度量来更新它:
exp = neptune.init(project='shared/pytorch-lightning-integration', id='PYTOR-63')
exp['some_external_metric'].log(0.92)
或者获取一个单独的实验并用训练后计算的一些外部度量来更新它:
exp = project.get_experiments(id='PYTOR-63')[0]
exp.log_metric('some_external_metric', 0.92)
如你所见,你可以从 Pytorch Lightning 将很多东西记录到 Neptune。
如果你想深入了解这个问题:
最后的想法
Pytorch Lightning 是一个很棒的库,可以帮助您:
- 组织你的深度学习代码,让其他人容易理解,
- 将开发样板外包给经验丰富的工程师团队,
- 访问大量最先进的功能,几乎不需要修改您的代码
借助 Neptune integration,您可以免费获得一些额外的东西:
- 你可以监控和跟踪你的深度学习实验
- 你可以很容易地与其他人分享你的研究
- 您和您的团队可以访问实验元数据并更有效地协作。
希望有了这种力量,你将确切地知道你(和其他人)尝试了什么,你的深度学习研究将以闪电般的速度前进
完整的 PyTorch 闪电追踪脚本
pip install --upgrade torch pytorch-lightning>=1.5.0
neptune-client
matplotlib scikit-plot
import os
import numpy as np
import neptune.new as neptune
import torch
from torch.nn import functional as F
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
from torchvision import transforms
import matplotlib.pyplot as plt
import pytorch_lightning as pl
MAX_EPOCHS=15
LR=0.02
BATCHSIZE=32
CHECKPOINTS_DIR = 'my_models/checkpoints'
class CoolSystem(pl.LightningModule):
def __init__(self):
super(CoolSystem, self).__init__()
self.l1 = torch.nn.Linear(28 * 28, 10)
def forward(self, x):
return torch.relu(self.l1(x.view(x.size(0), -1)))
def training_step(self, batch, batch_idx):
x, y = batch
y_hat = self.forward(x)
loss = F.cross_entropy(y_hat, y)
self.log('train/loss', loss)
return {'loss': loss}
def validation_step(self, batch, batch_idx):
x, y = batch
y_hat = self.forward(x)
loss = F.cross_entropy(y_hat, y)
self.log('val/loss', loss)
return {'val_loss': loss}
def validation_epoch_end(self, outputs):
avg_loss = torch.stack([x['val_loss'] for x in outputs]).mean()
fig = plt.figure()
losses = np.stack([x['val_loss'].numpy() for x in outputs])
plt.hist(losses)
neptune_logger.experiment['imgs/loss_histograms'].upload(neptune.types.File.as_image(fig))
return {'avg_val_loss': avg_loss}
def test_step(self, batch, batch_idx):
x, y = batch
y_hat = self.forward(x)
loss = F.cross_entropy(y_hat, y)
self.log('test/loss', loss)
return {'test_loss': loss}
def test_end(self, outputs):
avg_loss = torch.stack([x['test_loss'] for x in outputs]).mean()
return {'avg_test_loss': avg_loss}
def configure_optimizers(self):
return torch.optim.Adam(self.parameters(), lr=LR)
def train_dataloader(self):
return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=BATCHSIZE)
def val_dataloader(self):
return DataLoader(MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor()), batch_size=BATCHSIZE)
def test_dataloader(self):
return DataLoader(MNIST(os.getcwd(), train=False, download=True, transform=transforms.ToTensor()), batch_size=BATCHSIZE)
from pytorch_lightning.loggers.neptune import NeptuneLogger
neptune_logger = NeptuneLogger(
api_key="ANONYMOUS",
project_name="shared/pytorch-lightning-integration",
tags=["pytorch-lightning", "mlp"],
)
model_checkpoint = pl.callbacks.ModelCheckpoint(filepath=CHECKPOINTS_DIR)
from pytorch_lightning import Trainer
model = CoolSystem()
trainer = Trainer(max_epochs=MAX_EPOCHS,
logger=neptune_logger,
checkpoint_callback=model_checkpoint,
)
trainer.fit(model)
trainer.test(model)
import numpy as np
model.freeze()
test_loader = DataLoader(MNIST(os.getcwd(), train=False, download=True, transform=transforms.ToTensor()), batch_size=256)
y_true, y_pred = [],[]
for i, (x, y) in enumerate(test_loader):
y_hat = model.forward(x).argmax(axis=1).cpu().detach().numpy()
y = y.cpu().detach().numpy()
y_true.append(y)
y_pred.append(y_hat)
if i == len(test_loader):
break
y_true = np.hstack(y_true)
y_pred = np.hstack(y_pred)
from sklearn.metrics import accuracy_score
accuracy = accuracy_score(y_true, y_pred)
neptune_logger.experiment['test/accuracy'].log(accuracy)
from scikitplot.metrics import plot_confusion_matrix
import matplotlib.pyplot as plt
fig, ax = plt.subplots(figsize=(16, 12))
plot_confusion_matrix(y_true, y_pred, ax=ax)
neptune_logger.experiment['confusion_matrix'].log(File.as_image(fig))
neptune_logger.experiment('checkpoints').upload(CHECKPOINTS_DIR)
neptune_logger.experiment.stop()
PyTorch 闪电 vs 点燃:有什么区别?
原文:https://web.archive.org/web/https://neptune.ai/blog/pytorch-lightning-vs-ignite-differences
Pytorch 是使用最广泛的深度学习库之一,仅次于 Keras。它为任何在开发和研究中使用深度学习方法的人提供了敏捷性、速度和良好的社区支持。
Pytorch 比 Tensorflow 有一定优势。作为一名人工智能工程师,我非常喜欢的两个关键特性是:
- Pytorch 有动态图(Tensorflow 有静态图),这使得 Pytorch 实现更快,并增加了 pythonic 的感觉。
- Pytorch 很容易学,而 Tensorflow 有点难,主要是因为它的图形结构。
我在 Pytorch 上遇到的唯一问题是,当模型按比例放大时,它缺少结构。随着算法中引入越来越多的函数,模型变得复杂,很难跟踪细节。类似 Keras 的东西将有利于提供一个具有简单调用功能的高级接口。
今天,Pytorch 社区已经相当大了,不同的群体已经创建了解决相同问题的高级库。在本文中,我们将探索两个库: Pytorch Lighting 和 Pytorch Ignite ,它们为您的深度学习代码提供了灵活性和结构。
对比:Pytorch 照明与 Pytorch 点火
闪电 | 燃烧 | |
---|---|---|
TensorBoard,海王星,MLflow,Wandb,
彗星, |
TensorBoard,Neptune,MLflow,Wandb,Polyaxon
|
| | | |
| | | |
| | | |
|
制作
样书
| | |
| |
功能指标和模块指标界面
|
如果不定义指标,则根据任务选择。在本文中,我们将其定义为(autosklearn . metrics . roc _ AUC)
|
Pytorch 闪电是什么?
Lightning 是构建在 Pytorch 之上的高级 python 框架。它是威廉·法尔孔在攻读博士学位时发明的。它是为研究人员创建的,专门用于尝试新的深度学习模型,其中涉及研究规模、多 GPU 训练、16 位精度和 TPU。
为什么是闪电?
创建 Lightning 的目的是通过消除低级代码,同时保持代码的可读性、逻辑性和易于执行,来扩展和加速研究过程。
Lightning 为 pytorch 函数提供了一种结构,在这种结构中,函数的排列方式可以防止模型训练过程中的错误,这种错误通常发生在模型放大时。
关键特征
Pytorch Lightning 附带了许多功能,可以为专业人员以及研究领域的新手提供价值。
在任何硬件上训练模型:CPU、GPU 或 TPU,无需更改源代码
- 16 位精度支持:通过将内存使用减半来加快训练模型的速度
- 可读性:减少不想要的或样板代码,把重点放在代码的研究方面
- 删除不需要的或样板代码
- 界面:简洁、整洁、易于导航
- 更容易复制
- 可扩展:你可以使用多个数学函数(优化器、激活函数、损失函数等等)
- 可重用性
- 与可视化框架集成,如 Neptune.ai、Tensorboard、MLFlow、Comet.ml、Wandb
- 使用 PyTorch Lightning 的好处
闪电 API
Lightning API 提供了与原始 Pytorch 相同的功能,只是更加结构化。在定义模型的时候,你不用修改任何代码,完全一样,你需要做的就是继承 LightningModule 而不是 nn.module 。LightningModule 负责建模深度学习网络的所有重要方面,例如:
定义模型的架构( init
- 定义训练、验证和测试循环(分别为训练 _ 步骤、验证 _ 步骤和测试 _ 步骤)
- 定义优化器(configure _ optimizer
- Lightning 自带lightning data module;您可以创建自己的培训、验证和测试数据集,然后将其传递给培训师模块。
- 让我们看看在 Lightning 中定义模型是什么样子的。
如您所见,LightningModule 很简单,类似于 Pytorch。它负责所有需要定义的重要方法,比如:
class MNISTModel(pl.LightningModule):
def __init__(self):
super(MNISTModel, self).__init__()
self.l1 = torch.nn.Linear(28 * 28, 10)
def forward(self, x):
return torch.relu(self.l1(x.view(x.size(0), -1)))
def training_step(self, batch, batch_nb):
x, y = batch
loss = F.cross_entropy(self(x), y)
return loss
def configure_optimizers(self):
return torch.optim.Adam(self.parameters(), lr=0.02)
init 负责模型和相关权重
- forward :与 Pytorch Forward 相同,连接架构的所有不同组件,并向前传递
- 训练 _ 步骤:定义训练循环及其功能
- 配置优化器:定义优化器
- 还有其他功能:
测试 _ 步骤
- 测试 _ 结束
- 配置优化器
- 验证 _ 步骤
- 验证 _ 结束
- 训练器方法负责配置训练标准(时期数、训练硬件:CPU、GPU 和 TPU、GPU 数量等)。培训师的主要工作是将工程代码从研究代码中分离出来。
最后,你需要做的就是调用。从训练器实例中拟合方法,传递定义好的模型和数据加载器,并执行。
韵律学
mnist_model = MNISTModel()
train_ds = MNIST(os.getcwd(), train=True, download=True, transform=transforms.ToTensor())
train_loader = DataLoader(train_ds, batch_size=32)
trainer = pl.Trainer(gpus=1, max_epochs=3, progress_bar_refresh_rate=20)
trainer.fit(mnist_model, train_loader)
指标的目的是允许用户使用某种数学标准来监控和测量训练过程,如:准确性、AUC、RMSE 等。它不同于损失函数;损失函数测量预测值和实际值之间的差异,并同时使用参数更新权重,而指标则用于监控模型在训练集和验证测试中的表现。这为模型的性能提供了有洞察力的行为。
Lightning 有两种指标:
功能度量
- 模块度量接口
- 功能指标
功能性指标允许您根据自己的需求创建自己的指标作为功能。Pytorch 为您提供了一个 tensor_metric decorator,它主要负责将所有输入和输出转换为张量,以便在所有 DDP 节点上同步度量的输出(如果 DDP 已初始化)。
Pytorch 还提供:
import torch
from pytorch_lightning.metrics import tensor_metric
@tensor_metric()
def rmse(pred: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
return torch.sqrt(torch.mean(torch.pow(pred-target, 2.0)))
numpy_metric:用 numpy 实现的度量函数的包装器
- tensor_collection_metric:其输出不能转换为 torch 的度量的包装器。张量完全
- 模块指标接口
模块指标接口允许您为指标提供模块化接口。它负责张量转换,并处理 DDP 同步和 i/o 转换。
使用模块度量接口的另一种方法是使用普通 pytorch 创建一个度量函数,并从 lightning 基类派生一个类,然后在 forward 中调用您的度量:
import torch
from pytorch_lightning.metrics import TensorMetric
class RMSE(TensorMetric):
def forward(self, x, y):
return torch.sqrt(torch.mean(torch.pow(x-y, 2.0)))
钩住
import torch
from pytorch_lightning.metrics import TensorMetric
def rmse(pred: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
return torch.sqrt(torch.mean(torch.pow(pred-target, 2.0)))
class RMSE(TensorMetric):
def forward(pred: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
return rmse(pred, target)
Lightning 也有被称为钩子的处理程序。挂钩帮助用户在训练期间与教练互动。基本上,它让用户在训练中采取某种行动。
例如:
on_epoch_start :这是在 epoch 最开始的训练循环中调用的:
为了启用挂钩,请确保您覆盖了您的 LightningModule 中的方法,并定义了需要在期间完成的操作或任务,培训师将在正确的时间调用它。
def on_epoch_start(self):
on_epoch_end :这是在 epoch 结束时的训练循环中调用的:
要了解更多关于钩子的信息,请点击链接。
def on_epoch_end(self):
分布式培训
Lightning 提供多 GPU 培训和 5 种分布式后端培训:
数据并行' dp '
- 分布式数据并行' ddp '
- 分布式数据并行-2 'ddp2 '
- 分布式数据并行分片' dpp_sharded '
- 极速'极速'
- 这些设置可以在调用。拟合方法。
注意,为了使用分片发行版,您需要从 plugins 参数中调用它。
Trainer = Trainer(distributed_backend = None)
Trainer = Trainer(distributed_backend ='dp')
Trainer = Trainer(distributed_backend ='ddp')
trainer = Trainer(gpus=4, plugins='ddp_sharded')
查看这篇文章以更深入地了解分片发行版。
deepspeed 也是如此:
要了解更多关于 deepspeed 的信息,请查看这篇文章。
trainer = Trainer(gpus=4, plugins='deepspeed', precision=16)
再现性
这样,再现性变得非常容易。为了一次又一次地重现相同的结果,你需要做的就是设置伪随机发生器的种子值,并确保训练器中的确定性参数为真。
有了上面的配置,您现在可以放大模型,甚至不用担心模型的工程方面。请放心,一切都由闪电模块负责。
from pytorch_lightning import Trainer, seed_everything
seed_everything(23)
model=Model()
Trainer = Trainer(deterministic = True)
它规范了代码。
你所需要做的就是关注研究方面,包括操纵数学函数,增加一层神经元,甚至改变训练硬件。
它将工程与研究分离开来。
与海王星整合
Lightning 提供了与 Neptune 的无缝集成。你需要做的就是调用 NeptuneLogger 模块:
如上所示设置所有需要的参数,然后将其作为一个参数传递给 trainer 函数,您就可以通过 Neptune 仪表盘监视您的模型了。
from pytorch_lightning.loggers.neptune import NeptuneLogger
neptune_logger = NeptuneLogger(
api_key="ANONYMOUS",
project_name="shared/pytorch-lightning-integration",
close_after_fit=False,
experiment_name="train-on-MNIST",
params=ALL_PARAMS,
tags=['1.x', 'advanced'],
)
生产
trainer = pl.Trainer(logger=neptune_logger,
checkpoint_callback=model_checkpoint,
callbacks=[lr_logger],
**Trainer_Params)
将 lightning 模型部署到生产环境中也非常简单,就像使用。to_torchscript,。to_onnx 并且有三种方法可以保存用于生产的模型:
将模型保存为 PyTorch 检查点
- 将模型转换为 ONNX
- 将模型导出到 Torchscript
- 要获得关于模型部署和生产的更深入的知识,请查看这篇文章。
社区
闪电社区正在成长。几乎有 390 名贡献者、11 名研究科学家组成的核心团队、博士生,以及超过 17k 的活跃用户。因为社区正在快速发展,文档非常重要。
如果你发现自己有什么问题,可以在 Lightning 的 Slack 或者 Github 上寻求帮助。
Lightning 的文档非常简洁、易读、易懂。还包括视频解释。
何时使用 PyTorch 闪电
研究和创造新的建筑。
- 寻找分布式并行培训。
- 寻找 CPU,GPU 和 TPU 培训。在 PyTorch 中,您可以轻松地从训练器本身更改硬件。
- 它提供了 SOTA 架构,因此您可以根据自己的需要调整它的设置。
- 何时不使用 PyTorch 闪电
如果你不知道 PyTorch,那就先学 PyTorch 再用闪电。可以去看看闪电。
- 代码对比:Pytorch vs 闪电
从上面的例子中,您可以看到,Lightning 为每个操作提供了更专用的功能:构建模型、加载数据、配置优化器等等,此外,它还负责样板代码,如配置训练循环。它更侧重于研究方面,而不是工程方面。
什么是 Ignite?
Ignite 是在 PyTorch 基础上开发的另一个高级库。它有助于神经网络训练。和闪电一样,它也是为研究人员创造的。它需要更少的纯 PyTorch 代码,这增加了界面的灵活性和简单性。
为什么点燃?
Ignite 为用户提供了一个界面,将架构、标准和损耗整合到一个函数中,用于培训和评估(可选)。这个特性使 Ignite 基于 Pytorch 的基础,,同时也使用户意识到从工程术语中分离出来的高级抽象(可以稍后在培训之前配置)。这给了用户很大的灵活性。
关键特征
Ignite 提供了三个高级功能:
引擎:这允许用户构造不同的配置用于训练和评估;
- 现成的指标:允许用户轻松评估模型;
- 内置处理程序:这允许用户创建训练管道,记录,或者简单地说——与引擎交互。**
** 使用 PyTorch Ignite 的好处*
*## 点燃 API
引擎:引擎让用户在每一批数据集上运行给定的抽象,在它经历时期、日志记录等时发出事件。
让我们看看发动机是如何工作的:
正如你所看到的,用于训练深度学习模型的抽象或基础被包含在函数 update_model 中,然后被传递到引擎中。这只是包含反向传播的训练函数。没有定义额外的参数或事件。
def update_model(engine, batch):
inputs, targets = batch
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, targets)
loss.backward()
optimizer.step()
return loss.item()
trainer = Engine(update_model)
要开始训练,您只需调用。从训练器运行方法,根据要求定义 max_epochs 。
trainer.run(data_loader, max_epochs=5)
事件和处理程序
事件和处理程序帮助用户在训练期间与引擎进行交互。基本上,它让用户监控模型。我们将看到两种与模型互动的方式:借助装饰者、和的帮助。添加事件处理程序。
下面的函数使用@trainer.on decorator 打印评估器在训练数据集上运行的结果。
如您所见,函数中的主要元素是 train_evaluator,它主要对训练数据执行评估并返回指标。可以使用相同的度量来发现准确性、损失等。您所要做的就是给出一个打印件或一个 return 语句,以便获得值。
@trainer.on(Events.EPOCH_COMPLETED)
def log_training_results(trainer):
train_evaluator.run(train_loader)
metrics = train_evaluator.state.metrics
accuracy = metrics['accuracy']*100
loss = metrics['nll']
last_epoch.append(0)
training_history['accuracy'].append(accuracy)
training_history['loss'].append(loss)
print("Training Results - Epoch: {} Avg accuracy: {:.2f} Avg loss: {:.2f}"
.format(trainer.state.epoch, accuracy, loss))
另一种方法是使用。训练器的 add_event_handler 。****
上面的代码使用验证数据集来操作指标。这个和上一个一模一样。唯一的区别是我们在中传递这个函数。训练器、的 add_event_handler 方法,它将像前面的函数一样工作。
def log_validation_results(trainer):
val_evaluator.run(val_loader)
metrics = val_evaluator.state.metrics
accuracy = metrics['accuracy']*100
loss = metrics['nll']
validation_history['accuracy'].append(accuracy)
validation_history['loss'].append(loss)
print("Validation Results - Epoch: {} Avg accuracy: {:.2f} Avg loss: {:.2f}"
.format(trainer.state.epoch, accuracy, loss))
trainer.add_event_handler(Events.EPOCH_COMPLETED, log_validation_results)
有相当多的内置事件可以让你在训练期间或训练结束后与教练互动。
例如,事件。EPOCH_COMPLETED 会在 EPOCH 完成后执行某个功能。事件。另一方面,完成的将在训练完成后执行。
韵律学
Ignite 提供准确度、精确度、召回率或混淆矩阵等指标,以计算各种质量。
例如,下面我们计算训练数据集的准确度。
从上面的代码中,您可以看到用户必须将度量实例连接到引擎。然后使用引擎的 process_function 的输出来计算度量值。
from ignite.metrics import Accuracy
def predict_on_batch(engine, batch)
model.eval()
with torch.no_grad():
x, y = prepare_batch(batch, device=device, non_blocking=non_blocking)
y_pred = model(x)
return y_pred, y
evaluator = Engine(predict_on_batch)
Accuracy().attach(evaluator, "val_acc")
evaluator.run(val_dataloader)
Ignite 还允许用户通过算术运算创建自己的指标。
分布式培训
Ignite 支持分布式培训,但用户必须对其进行相应的配置,这可能需要很大的努力。用户需要正确设置分布式过程组、分布式采样器等。如果你不熟悉如何设置它,它会非常乏味。
再现性
Ignite 的可再现性在于:
Ignite 自动处理随机状态的能力,这可以确保批处理在不同的运行时间具有相同的数据分布。
- Ignite 不仅允许集成 Neptune,还允许集成 MLflow、Polyaxon、TensorBoard 等等。
- 与海王星整合
这个海王星整合非常容易。你所需要做的就是 pip 安装 neptune-client 库,然后你只需从ignite . contrib . handlers . Neptune _ logger中调用 NeptuneLogger 。
有趣的是,您可以附加许多事件处理程序,这样所有数据都将显示在 Neptune 仪表盘中,这将有助于您监控训练。
from ignite.contrib.handlers.neptune_logger import *
npt_logger = NeptuneLogger(api_token="ANONYMOUS",
project_name='shared/pytorch-ignite-integration',
name='ignite-mnist-example',
params={'train_batch_size': train_batch_size,
'val_batch_size': val_batch_size,
'epochs': epochs,
'lr': lr,
'momentum': momentum})
下面你会发现一些例子,说明如何用 Neptune 附加事件处理程序。
社区
npt_logger.attach(trainer,
log_handler=OutputHandler(tag="training",
output_transform=lambda loss: {'batchloss': loss},
metric_names='all'),
event_name=Events.ITERATION_COMPLETED(every=100))
npt_logger.attach(train_evaluator,
log_handler=OutputHandler(tag="training",
metric_names=["loss", "accuracy"],
another_engine=trainer),
event_name=Events.EPOCH_COMPLETED)
npt_logger.attach(validation_evaluator,
log_handler=OutputHandler(tag="validation",
metric_names=["loss", "accuracy"],
another_engine=trainer),
event_name=Events.EPOCH_COMPLETED)
Ignite 社区正在成长;在撰写本文时,几乎有 124 个贡献者和超过 391 个活跃用户。
何时使用 PyTorch Ignite
具有优秀界面的高级库,具有根据需求定制 Ignite API 的附加属性。
-
当您想分解代码,但不想牺牲灵活性来支持复杂的训练策略时
-
提供了一个丰富的实用工具支持环境,如指标、处理程序和记录器,可用于轻松地评估/调试您的模型,它们可以单独配置。
-
何时不使用 PyTorch 点火
如果你不熟悉 Pytorch。
-
如果你不精通分布式培训,只是想轻松使用它。
-
如果你不想花很多时间去学习一个新的库。
-
代码比较:Pytorch 与 Ignite
纯 PyTorch
PyTorch-Ignite
model = Net()
train_loader, val_loader = get_data_loaders(train_batch_size, val_batch_size)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.8)
criterion = torch.nn.NLLLoss()
max_epochs = 10
validate_every = 100
checkpoint_every = 100
def validate(model, val_loader):
model = model.eval()
num_correct = 0
num_examples = 0
for batch in val_loader:
input, target = batch
output = model(input)
correct = torch.eq(torch.round(output).type(target.type()), target).view(-1)
num_correct += torch.sum(correct).item()
num_examples += correct.shape[0]
return num_correct / num_examples
def checkpoint(model, optimizer, checkpoint_dir):
filepath = "{}/{}".format(checkpoint_dir, "checkpoint.pt")
obj = {"model": model.state_dict(), "optimizer":optimizer.state_dict()}
torch.save(obj, filepath)
iteration = 0
for epoch in range(max_epochs):
for batch in train_loader:
model = model.train()
optimizer.zero_grad()
input, target = batch
output = model(input)
loss = criterion(output, target)
loss.backward()
optimizer.step()
if iteration % validate_every == 0:
binary_accuracy = validate(model, val_loader)
print("After {} iterations, binary accuracy = {:.2f}"
.format(iteration, binary_accuracy))
if iteration % checkpoint_every == 0:
checkpoint(model, optimizer, checkpoint_dir)
iteration += 1
model = Net()
train_loader, val_loader = get_data_loaders(train_batch_size, val_batch_size)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.8)
criterion = torch.nn.NLLLoss()
max_epochs = 10
validate_every = 100
checkpoint_every = 100
trainer = create_supervised_trainer(model, optimizer, criterion)
evaluator = create_supervised_evaluator(model, metrics={'accuracy': Accuracy()})
@trainer.on(Events.ITERATION_COMPLETED(every=validate_every))
def validate(trainer):
evaluator.run(val_loader)
metrics = evaluator.state.metrics
print("After {} iterations, binary accuracy = {:.2f}"
.format(trainer.state.iteration, metrics['accuracy']))
checkpointer = ModelCheckpoint(checkpoint_dir, n_saved=3, create_dir=True)
trainer.add_event_handler(Events.ITERATION_COMPLETED(every=checkpoint_every),
checkpointer, {'mymodel': model})
trainer.run(train_loader, max_epochs=max_epochs)
如您所见,Ignite 压缩了 pytorch 代码,使您在研究领域更加高效,您可以在跟踪和操作工程方面(即模型训练)的同时练习不同的技术。
结论
Lightning 和 Ignite 各有各的好处。如果您正在寻找灵活性,那么 Ignite 是不错的选择,因为您可以使用传统的 Pytorch 来设计您的架构、优化器和整体实验。Ignite 将帮助您组装特定功能的不同组件。
如果你正在为一个新的设计寻找快速原型,或者研究最先进的 ML 方法,那么就用闪电吧。这将有助于你专注于研究方面,并有助于你更快地扩大模型,从而减少误差。此外,它还提供 TPU 和并行分布。
我希望你喜欢这篇文章。如果您想尝试一些实际的例子,请访问 Lightning 和 Ignite 的笔记本链接(在本文开头的比较表中)。
感谢阅读!
资源
闪电文件
- 点燃文档
- Neptune 记录器文档
- 8 位创作者和核心贡献者谈论他们来自 PyTorch 生态系统的模型训练库
- 8 Creators and Core Contributors Talk About Their Model Training Libraries From PyTorch Ecosystem*
PyTorch 损失函数:最终指南
原文:https://web.archive.org/web/https://neptune.ai/blog/pytorch-loss-functions
你的神经网络可以完成很多不同的任务。无论是对数据进行分类,如将动物图片分为猫和狗,回归任务,如预测月收入,还是其他任何事情。每个任务都有不同的输出,需要不同类型的损失函数。
您配置损失函数的方式可以决定算法的性能。通过正确配置损失函数,你可以确保你的模型按照你想要的方式工作。
幸运的是,我们可以使用损失函数来充分利用机器学习任务。
在本文中,我们将讨论 PyTorch 中流行的损失函数,以及如何构建自定义损失函数。一旦你读完了,你应该知道为你的项目选择哪一个。
检查如何通过 Neptune + PyTorch 集成来监控您的 PyTorch 模型训练并跟踪所有模型构建元数据。
损失函数有哪些?
在我们进入 PyTorch 细节之前,让我们回忆一下损失函数是什么。
损失函数用于测量预测输出和提供的目标值之间的误差。损失函数告诉我们算法模型离实现预期结果有多远。“损失”一词意味着模型因未能产生预期结果而受到的惩罚。
例如,损失函数(姑且称之为 J )可以采用以下两个参数:
- 预测产量( y_pred
- 目标值( y )
Illustration of a neural network loss
此函数将通过比较模型的预测输出和预期输出来确定模型的性能。如果 y_pred 和 y 之间的偏差很大,损失值会很高。
如果偏差很小或者值几乎相同,它将输出一个非常低的损耗值。因此,当模型在所提供的数据集上进行训练时,您需要使用一个损失函数来适当地惩罚模型。
损失函数根据算法试图解决的问题陈述而变化。
如何添加 PyTorch 损失函数?
PyTorch 的 torch.nn 模块有多个标准损失函数,你可以在你的项目中使用。
要添加它们,您需要首先导入库:
import torch
import torch.nn as nn
接下来,定义您想要使用的损失类型。以下是定义平均绝对误差损失函数的方法:
loss = nn.L1Loss()
添加函数后,您可以使用它来完成您的特定任务。
PyTorch 中有哪些损失函数?
广义来说,PyTorch 中的损失函数分为两大类:回归损失和分类损失。
回归损失函数在模型预测连续值时使用,如人的年龄。
分类损失函数在模型预测离散值时使用,例如电子邮件是否为垃圾邮件。
排名损失函数在模型预测输入之间的相对距离时使用,例如根据电子商务搜索页面上的相关性对产品进行排名。
现在我们将探索 PyTorch 中不同类型的损失函数,以及如何使用它们:
1.PyTorch 平均绝对误差(L1 损失函数)
torch.nn.L1Loss
平均绝对误差 (MAE),也称为 L1 损失,计算实际值和预测值之间的绝对差的和的平均值。
它检查一组预测值的误差大小,而不关心它们的正负方向。如果不使用误差的绝对值,那么负值会抵消正值。
Pytorch L1 损失表示为:
x 代表实际值, y 代表预测值。
什么时候可以使用?
- 回归问题,特别是当目标变量的分布有异常值时,如与平均值相差很大的小值或大值。它被认为对异常值更稳健。
例子
import torch
import torch.nn as nn
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
mae_loss = nn.L1Loss()
output = mae_loss(input, target)
output.backward()
print('input: ', input)
print('target: ', target)
print('output: ', output)
###################### OUTPUT ######################
input: tensor([[ 0.2423, 2.0117, -0.0648, -0.0672, -0.1567],
[-0.2198, -1.4090, 1.3972, -0.7907, -1.0242],
[ 0.6674, -0.2657, -0.9298, 1.0873, 1.6587]], requires_grad=True)
target: tensor([[-0.7271, -0.6048, 1.7069, -1.5939, 0.1023],
[-0.7733, -0.7241, 0.3062, 0.9830, 0.4515],
[-0.4787, 1.3675, -0.7110, 2.0257, -0.9578]])
output: tensor(1.2850, grad_fn=<L1LossBackward>)
2.PyTorch 均方误差损失函数
torch.nn.MSELoss
均方误差(MSE) ,也称为 L2 损失,计算实际值和预测值之间的平方差的平均值。
Pytorch MSE Loss 总是输出正的结果,不管实际值和预测值的符号如何。为了提高模型的准确性,您应该尝试减少 L2 损失-一个完美的值是 0.0。
平方意味着较大的错误比较小的错误产生更大的误差。如果分类器偏离 100,则误差为 10,000。如果相差 0.1,误差为 0.01。这个惩罚犯大错的模特,鼓励小错。
Pytorch L2 损失表示为:
x 代表实际值, y 代表预测值。
什么时候可以使用?
- MSE 是大多数 Pytorch 回归问题的默认损失函数。
例子
import torch
import torch.nn as nn
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
mse_loss = nn.MSELoss()
output = mse_loss(input, target)
output.backward()
print('input: ', input)
print('target: ', target)
print('output: ', output)
###################### OUTPUT ######################
input: tensor([[ 0.3177, 1.1312, -0.8966, -0.0772, 2.2488],
[ 0.2391, 0.1840, -1.2232, 0.2017, 0.9083],
[-0.0057, -3.0228, 0.0529, 0.4084, -0.0084]], requires_grad=True)
target: tensor([[ 0.2767, 0.0823, 1.0074, 0.6112, -0.1848],
[ 2.6384, -1.4199, 1.2608, 1.8084, 0.6511],
[ 0.2333, -0.9921, 1.5340, 0.3703, -0.5324]])
output: tensor(2.3280, grad_fn=<MseLossBackward>)
3.PyTorch 负对数似然损失函数
torch.nn.NLLLoss
负对数似然损失函数 (NLL)仅适用于将 softmax 函数作为输出激活层的模型。 Softmax 指的是计算层中每个单元的归一化指数函数的激活函数。
Softmax 函数表示为:
该函数获取一个大小为 N 、的输入向量,然后修改这些值,使每个值都在 0 和 1 之间。此外,它对输出进行归一化,使得向量的 N 值之和等于 1。
NLL 使用否定的含义,因为概率(或可能性)在 0 和 1 之间变化,并且这个范围内的值的对数是负的。最终,损失值变为正值。
在 NLL 中,最小化损失函数有助于我们获得更好的输出。负对数似然是从近似最大似然估计(MLE)中检索的。这意味着我们试图最大化模型的对数似然,结果,最小化 NLL 。
在 NLL 中,模型因以较小的概率做出正确预测而受到惩罚,因以较高的概率做出预测而受到鼓励。对数做惩罚。
NLL 不仅关心预测是否正确,还关心模型是否确定预测得分高。
Pytorch NLL 损失表示为:
其中 x 是输入,y 是目标,w 是重量,N 是批量。
什么时候可以使用?
- 多类分类问题
例子
import torch
import torch.nn as nn
input = torch.randn(3, 5, requires_grad=True)
target = torch.tensor([1, 0, 4])
m = nn.LogSoftmax(dim=1)
nll_loss = nn.NLLLoss()
output = nll_loss(m(input), target)
output.backward()
print('input: ', input)
print('target: ', target)
print('output: ', output)
input: tensor([[ 1.6430, -1.1819, 0.8667, -0.5352, 0.2585],
[ 0.8617, -0.1880, -0.3865, 0.7368, -0.5482],
[-0.9189, -0.1265, 1.1291, 0.0155, -2.6702]], requires_grad=True)
target: tensor([1, 0, 4])
output: tensor(2.9472, grad_fn=<NllLossBackward>)
4.PyTorch 交叉熵损失函数
torch.nn.CrossEntropyLoss
该损失函数计算一组给定事件或随机变量的两个概率分布之间的差异。
它用于计算一个分数,该分数总结了预测值和实际值之间的平均差异。为了增强模型的准确性,您应该尝试最小化得分—交叉熵得分在 0 到 1 之间,一个完美的值是 0。
其他损失函数,如平方损失,惩罚不正确的预测。 交叉熵 对非常自信和错误的人大加惩罚。
与负对数似然损失不同,负对数似然损失不会基于预测置信度进行惩罚,交叉熵会惩罚不正确但有把握的预测,以及正确但不太有把握的预测。
交叉熵函数有很多种变体,其中最常见的类型是二元交叉熵(BCE) 。BCE 损失主要用于二元分类模型;即只有两个类别的模型。
Pytorch 交叉熵损失表示为:
其中 x 是输入,y 是目标,w 是重量,C 是类别数,N 是小批量维度。
什么时候可以使用?
- 二进制分类任务,这是 Pytorch 中的默认损失函数。
- 创建有信心的模型-预测将是准确的,并且具有更高的概率。
例子
import torch
import torch.nn as nn
input = torch.randn(3, 5, requires_grad=True)
target = torch.empty(3, dtype=torch.long).random_(5)
cross_entropy_loss = nn.CrossEntropyLoss()
output = cross_entropy_loss(input, target)
output.backward()
print('input: ', input)
print('target: ', target)
print('output: ', output)
input: tensor([[ 0.1639, -1.2095, 0.0496, 1.1746, 0.9474],
[ 1.0429, 1.3255, -1.2967, 0.2183, 0.3562],
[-0.1680, 0.2891, 1.9272, 2.2542, 0.1844]], requires_grad=True)
target: tensor([4, 0, 3])
output: tensor(1.0393, grad_fn=<NllLossBackward>)
5.PyTorch 铰链嵌入损失函数
torch.nn.HingeEmbeddingLoss
铰链嵌入损失用于计算存在输入张量 x 和标签张量 y 时的损失。目标值介于{1,-1}之间,这有利于二进制分类任务。
使用铰链损失函数,只要实际类值和预测类值之间的符号存在差异,就可以给出更大的误差。这激励例子有正确的标志。
铰链嵌入损耗表示为:
什么时候可以使用?
- 分类问题,尤其是在确定两个输入是相似还是不相似时。
- 学习非线性嵌入或半监督学习任务。
例子
import torch
import torch.nn as nn
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
hinge_loss = nn.HingeEmbeddingLoss()
output = hinge_loss(input, target)
output.backward()
print('input: ', input)
print('target: ', target)
print('output: ', output)
###################### OUTPUT ######################
input: tensor([[ 0.1054, -0.4323, -0.0156, 0.8425, 0.1335],
[ 1.0882, -0.9221, 1.9434, 1.8930, -1.9206],
[ 1.5480, -1.9243, -0.8666, 0.1467, 1.8022]], requires_grad=True)
target: tensor([[-1.0748, 0.1622, -0.4852, -0.7273, 0.4342],
[-1.0646, -0.7334, 1.9260, -0.6870, -1.5155],
[-0.3828, -0.4476, -0.3003, 0.6489, -2.7488]])
output: tensor(1.2183, grad_fn=<MeanBackward0>)
6.PyTorch 边际排序损失函数
torch.nn.MarginRankingLoss
边际排名损失计算一个标准来预测输入之间的相对距离。这不同于其他损失函数,如 MSE 或交叉熵,它们学习从给定的输入集直接预测。
利用边际排序损失,只要有输入 x1 、 x2 ,以及标签张量 y (包含 1 或-1),就可以计算损失。
当 y == 1 时,第一次输入将被假定为一个较大的值。它的排名会高于第二个输入。如果 y == -1,则第二个输入的排名会更高。
Pytorch 利润排名损失表示为:
什么时候可以使用?
例子
import torch
import torch.nn as nn
input_one = torch.randn(3, requires_grad=True)
input_two = torch.randn(3, requires_grad=True)
target = torch.randn(3).sign()
ranking_loss = nn.MarginRankingLoss()
output = ranking_loss(input_one, input_two, target)
output.backward()
print('input one: ', input_one)
print('input two: ', input_two)
print('target: ', target)
print('output: ', output)
input one: tensor([1.7669, 0.5297, 1.6898], requires_grad=True)
input two: tensor([ 0.1008, -0.2517, 0.1402], requires_grad=True)
target: tensor([-1., -1., -1.])
output: tensor(1.3324, grad_fn=<MeanBackward0>)
7.PyTorch 三重边界损失函数
torch.nn.TripletMarginLoss
三重余量损失计算模型中测量三重损失的标准。通过这个损失函数,可以计算出有输入张量、 x1 、 x2 、 x3 以及大于零的裕量时的损失。
一个三联体由 a (主播) p (正例) n (反例)组成。
Pytorch 三线态余量损失表示为:
什么时候可以使用?
例子
import torch
import torch.nn as nn
anchor = torch.randn(100, 128, requires_grad=True)
positive = torch.randn(100, 128, requires_grad=True)
negative = torch.randn(100, 128, requires_grad=True)
triplet_margin_loss = nn.TripletMarginLoss(margin=1.0, p=2)
output = triplet_margin_loss(anchor, positive, negative)
output.backward()
print('anchor: ', anchor)
print('positive: ', positive)
print('negative: ', negative)
print('output: ', output)
anchor: tensor([[ 0.6152, -0.2224, 2.2029, ..., -0.6894, 0.1641, 1.7254],
[ 1.3034, -1.0999, 0.1705, ..., 0.4506, -0.2095, -0.8019],
[-0.1638, -0.2643, 1.5279, ..., -0.3873, 0.9648, -0.2975],
...,
[-1.5240, 0.4353, 0.3575, ..., 0.3086, -0.8936, 1.7542],
[-1.8443, -2.0940, -0.1264, ..., -0.6701, -1.7227, 0.6539],
[-3.3725, -0.4695, -0.2689, ..., 2.6315, -1.3222, -0.9542]],
requires_grad=True)
positive: tensor([[-0.4267, -0.1484, -0.9081, ..., 0.3615, 0.6648, 0.3271],
[-0.0404, 1.2644, -1.0385, ..., -0.1272, 0.8937, 1.9377],
[-1.2159, -0.7165, -0.0301, ..., -0.3568, -0.9472, 0.0750],
...,
[ 0.2893, 1.7894, -0.0040, ..., 2.0052, -3.3667, 0.5894],
[-1.5308, 0.5288, 0.5351, ..., 0.8661, -0.9393, -0.5939],
[ 0.0709, -0.4492, -0.9036, ..., 0.2101, -0.8306, -0.6935]],
requires_grad=True)
negative: tensor([[-1.8089, -1.3162, -1.7045, ..., 1.7220, 1.6008, 0.5585],
[-0.4567, 0.3363, -1.2184, ..., -2.3124, 0.7193, 0.2762],
[-0.8471, 0.7779, 0.1627, ..., -0.8704, 1.4201, 1.2366],
...,
[-1.9165, 1.7768, -1.9975, ..., -0.2091, -0.7073, 2.4570],
[-1.7506, 0.4662, 0.9482, ..., 0.0916, -0.2020, -0.5102],
[-0.7463, -1.9737, 1.3279, ..., 0.1629, -0.3693, -0.6008]],
requires_grad=True)
output: tensor(1.0755, grad_fn=<MeanBackward0>)
8.PyTorch Kullback-Leibler 散度损失函数
torch.nn.KLDivLoss
kull back-lei bler 散度,简称 KL 散度,计算两个概率分布之间的差异。
使用此损失函数,您可以计算在预测概率分布用于估计预期目标概率分布的情况下损失的信息量(以位表示)。
它的输出告诉你两个概率分布的接近度。如果预测的概率分布与真实的概率分布相差甚远,就会导致巨大的损失。如果 KL 散度的值为零,则意味着概率分布是相同的。
KL 散度的表现就像交叉熵损失一样,在如何处理预测和实际概率方面有一个关键的区别。交叉熵根据预测的置信度惩罚模型,而 KL 散度不会。KL 散度仅评估概率分布预测如何不同于基本事实的分布。
KL 发散损失表示为:
x 代表真实标签的概率, y 代表预测标签的概率。
什么时候可以使用?
- 逼近复杂函数
- 多类分类任务
- 如果您希望确保预测的分布类似于定型数据的分布
例子
import torch
import torch.nn as nn
input = torch.randn(2, 3, requires_grad=True)
target = torch.randn(2, 3)
kl_loss = nn.KLDivLoss(reduction = 'batchmean')
output = kl_loss(input, target)
output.backward()
print('input: ', input)
print('target: ', target)
print('output: ', output)
###################### OUTPUT ######################
input: tensor([[ 1.4676, -1.5014, -1.5201],
[ 1.8420, -0.8228, -0.3931]], requires_grad=True)
target: tensor([[ 0.0300, -1.7714, 0.8712],
[-1.7118, 0.9312, -1.9843]])
output: tensor(0.8774, grad_fn=<DivBackward0>)
如何在 PyTorch 中创建自定义损失函数?
PyTorch 允许您创建自己的自定义损失函数,并在项目中实现。
以下是你如何创建自己简单的交叉熵损失函数。
将自定义损失函数创建为 python 函数
def myCustomLoss(my_outputs, my_labels):
my_batch_size = my_outputs.size()[0]
my_outputs = F.log_softmax(my_outputs, dim=1)
my_outputs = my_outputs[range(my_batch_size), my_labels]
return -torch.sum(my_outputs)/number_examples
还可以创建其他高级 PyTorch 自定义损耗函数。
使用类定义创建自定义损失函数
让我们修改计算两个样本之间相似性的 Dice 系数,作为二元分类问题的损失函数:
class DiceLoss(nn.Module):
def __init__(self, weight=None, size_average=True):
super(DiceLoss, self).__init__()
def forward(self, inputs, targets, smooth=1):
inputs = F.sigmoid(inputs)
inputs = inputs.view(-1)
targets = targets.view(-1)
intersection = (inputs * targets).sum()
dice = (2.*intersection + smooth)/(inputs.sum() + targets.sum() + smooth)
return 1 - dice
如何监控 PyTorch 损失函数?
很明显,在训练模型时,需要关注损失函数值,以跟踪模型的性能。随着损失值不断降低,模型不断变好。我们有很多方法可以做到这一点。让我们来看看它们。
为此,我们将训练一个在 PyTorch 中创建的简单神经网络,该网络将对著名的虹膜数据集执行分类。
为获取数据集进行必要的导入。
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
正在加载数据集。
iris = load_iris()
X = iris['data']
y = iris['target']
names = iris['target_names']
feature_names = iris['feature_names']
对数据集进行缩放,使均值=0,方差=1,可以快速收敛模型。
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
将数据集以 80:20 的比例分成训练和测试。
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=2)
为我们的神经网络及其训练做必要的导入。
import torch
import torch.nn.functional as F
import torch.nn as nn
import matplotlib.pyplot as plt
import numpy as np
plt.style.use('ggplot')
定义我们的网络。
class PyTorch_NN(nn.Module):
def __init__(self, input_dim, output_dim):
super(PyTorch_NN, self).__init__()
self.input_layer = nn.Linear(input_dim, 128)
self.hidden_layer = nn.Linear(128, 64)
self.output_layer = nn.Linear(64, output_dim)
def forward(self, x):
x = F.relu(self.input_layer(x))
x = F.relu(self.hidden_layer(x))
x = F.softmax(self.output_layer(x), dim=1)
return x
定义用于获得精确度和训练网络的函数。
def get_accuracy(pred_arr,original_arr):
pred_arr = pred_arr.detach().numpy()
original_arr = original_arr.numpy()
final_pred= []
for i in range(len(pred_arr)):
final_pred.append(np.argmax(pred_arr[i]))
final_pred = np.array(final_pred)
count = 0
for i in range(len(original_arr)):
if final_pred[i] == original_arr[i]:
count+=1
return count/len(final_pred)*100
def train_network(model, optimizer, criterion, X_train, y_train, X_test, y_test, num_epochs):
train_loss=[]
train_accuracy=[]
test_accuracy=[]
for epoch in range(num_epochs):
output_train = model(X_train)
train_accuracy.append(get_accuracy(output_train, y_train))
loss = criterion(output_train, y_train)
train_loss.append(loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
with torch.no_grad():
output_test = model(X_test)
test_accuracy.append(get_accuracy(output_test, y_test))
if (epoch + 1) % 5 == 0:
print(f"Epoch {epoch+1}/{num_epochs}, Train Loss: {loss.item():.4f}, Train Accuracy: {sum(train_accuracy)/len(train_accuracy):.2f}, Test Accuracy: {sum(test_accuracy)/len(test_accuracy):.2f}")
return train_loss, train_accuracy, test_accuracy
创建模型、优化器和损失函数对象。
input_dim = 4
output_dim = 3
learning_rate = 0.01
model = PyTorch_NN(input_dim, output_dim)
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)
1.监视笔记本电脑中 PyTorch 的丢失
现在,您一定注意到了 train_network 函数中的打印语句,用于监控损失和准确性。这是做这件事的一种方法。
X_train = torch.FloatTensor(X_train)
X_test = torch.FloatTensor(X_test)
y_train = torch.LongTensor(y_train)
y_test = torch.LongTensor(y_test)
train_loss, train_accuracy, test_accuracy = train_network(model=model, optimizer=optimizer, criterion=criterion, X_train=X_train, y_train=y_train, X_test=X_test, y_test=y_test, num_epochs=100)
我们得到这样的输出。
如果需要,我们也可以使用 Matplotlib 绘制这些值。
fig, (ax1, ax2, ax3) = plt.subplots(3, figsize=(12, 6), sharex=True)
ax1.plot(train_accuracy)
ax1.set_ylabel("training accuracy")
ax2.plot(train_loss)
ax2.set_ylabel("training loss")
ax3.plot(test_accuracy)
ax3.set_ylabel("test accuracy")
ax3.set_xlabel("epochs")
我们会看到这样一个图表,表明损失和准确性之间的相关性。
这个方法不错,而且行之有效。但是我们必须记住,我们的问题陈述和模型越复杂,就需要越复杂的监控技术。
2.使用 neptune.ai 监控 PyTorch 损失
监控度量标准的一个更简单的方法是将它们记录在一个类似 Neptune 的服务中,并专注于更重要的任务,比如构建和训练模型。
为此,我们只需要遵循几个小步骤。
注:最新的代码示例请参考 Neptune-PyTorch 集成文档。
首先,让我们安装需要的东西。
pip install neptune-client
现在让我们初始化一次海王星运行。
import neptune.new as neptune
run = neptune.init_run()
我们还可以分配配置变量,例如:
run["config/model"] = type(model).__name__
run["config/criterion"] = type(criterion).__name__
run["config/optimizer"] = type(optimizer).__name__
这是它在用户界面上的样子。
最后,我们可以通过在 train_network 函数中添加几行来记录我们的损失。请注意与“运行”相关的行。
def train_network(model, optimizer, criterion, X_train, y_train, X_test, y_test, num_epochs):
train_loss=[]
train_accuracy=[]
test_accuracy=[]
for epoch in range(num_epochs):
output_train = model(X_train)
acc = get_accuracy(output_train, y_train)
train_accuracy.append(acc)
run["training/epoch/accuracy"].log(acc)
loss = criterion(output_train, y_train)
run["training/epoch/loss"].log(loss)
train_loss.append(loss.item())
optimizer.zero_grad()
loss.backward()
optimizer.step()
with torch.no_grad():
output_test = model(X_test)
test_acc = get_accuracy(output_test, y_test)
test_accuracy.append(test_acc)
run["test/epoch/accuracy"].log(test_acc)
if (epoch + 1) % 5 == 0:
print(f"Epoch {epoch+1}/{num_epochs}, Train Loss: {loss.item():.4f}, Train Accuracy: {sum(train_accuracy)/len(train_accuracy):.2f}, Test Accuracy: {sum(test_accuracy)/len(test_accuracy):.2f}")
return train_loss, train_accuracy, test_accuracy
这是我们在仪表盘上看到的。绝对无缝。
你可以在 Neptune 应用程序中查看这次运行。不用说,你可以用任何损失函数做到这一点。
注:最新的代码示例请参考 Neptune-PyTorch 集成文档。
最后的想法
我们研究了 PyTorch 中最常见的损失函数。您可以选择适合您项目的任何函数,或者创建您自己的自定义函数。
希望这篇文章可以作为你在机器学习任务中使用 PyTorch 损失函数的快速入门指南。
如果你想更深入地了解这个主题或了解其他损失函数,可以访问 PyTorch 官方文档。
随机森林回归:何时失败,为什么?
在本文中,我们将关注使用随机森林进行回归的一个主要问题,即外推。
我们将讨论以下项目:
- 随机森林回归与线性回归
- 随机森林回归外推问题
- 潜在的解决方案
- 应该使用随机森林进行回归吗?
让我们开始吧。
随机森林回归与线性回归
随机森林回归是一个相当健壮的算法,然而,问题是你应该把它用于回归?
为什么不用线性回归代替呢?线性回归中的函数可以很容易地写成 y=mx + c,而复杂随机森林回归中的函数看起来就像一个黑盒,不能很容易地用函数来表示。
一般来说,随机森林会产生更好的结果,适用于大型数据集,并且能够通过为缺失数据创建估计值来处理缺失数据。然而,他们提出了一个主要的挑战,那就是他们不能在看不见的数据之外进行推断。我们稍后将深入探讨这些挑战
决策树回归
决策树对于获取输入特征和目标变量之间的非线性关系非常有用。
决策树的内部工作可以被认为是一堆 if-else 条件。
它从最顶端的一个节点开始。然后,该节点分为左右两个节点,即决策节点。这些节点然后分裂成它们各自的左右节点。
在叶节点的末端,计算该区域内发生的观测值的平均值。最底层的节点被称为叶节点或终端节点。
树叶中的值通常是该特定区域内观测值的平均值。例如,在下面最右边的叶节点中,552.889 是 5 个样本的平均值。
这种分裂的程度就是我们所知的树的深度。这是可以调整的超参数之一。指定树的最大深度是为了防止树变得太深——导致过度拟合的情况。
随机森林回归
随机森林是决策树的集合。这就是说,许多树以某种“随机”的方式构成了一个随机森林。
- 每棵树都是从不同的行样本中创建的,并且在每个节点处,选择不同的要素样本进行分割。
- 每棵树都有自己的预测。
- 然后对这些预测进行平均以产生一个结果。
平均使得随机森林比单个决策树更好,因此提高了其准确性并减少了过度拟合。
来自随机森林回归变量的预测是森林中的树木产生的预测的平均值。
训练线性回归和随机森林的示例
为了进一步深入,让我们看一个线性回归和随机森林回归的例子。为此,我们将对同一数据集应用线性回归和随机森林回归,并比较结果。
让我们以这个数据集为例,您应该根据克拉、深度、表、x、y 和 z 等其他特征来预测钻石的价格。如果我们看下面的价格分布:
我们可以看到价格从 326 到 18823 不等。
让我们训练线性回归模型,并在验证集上运行预测。
预测价格的分布如下:
预测价格明显在训练数据集中显示的“价格”值范围之外。
线性回归模型,顾名思义,就是在数据上创建一个线性模型。一种简单的思考方式是采用 y = mx+C 的形式。因此,由于它符合线性模型,因此能够在预测过程中获得定型集以外的值。它能够根据数据进行推断。
现在让我们看看使用相同数据集从随机森林回归器获得的结果。
这些值显然在 326 和 18823 的范围内——就像我们的训练集一样。没有超出该范围的值。随机森林不能举一反三。****
正如您在上面看到的,当使用随机森林回归时,预测值永远不会超出目标变量的训练集值。
如果您查看预测值,它们将如下所示:
Hengl, Tomislav et. al “Random forest as a generic framework for predictive modeling of spatial and spatio-temporal variables”. PeerJ. 6. e5518. 10.7717/peerj.5518. | Source
想知道为什么吗?
让我们在这里探索这一现象。上面使用的数据有以下几列克拉,深度,表,x,y,z 预测价格。
下图显示了随机森林回归器中的一个决策树。
让我们放大到这棵树的一小部分。例如,有 4 个深度为<= 62.75, x <= 5.545, carat <= 0.905, and z <= 3.915. The price being predicted for these is 2775.75. This figure represents the mean of all these four samples. Therefore, 的样本,测试集中落在该叶子中的任何值都将被预测为 2775.75。
也就是说,当随机森林回归器承担预测以前未见过的值的任务时,它将总是预测以前见过的值的平均值。显然,样本的平均值不能超出样本中的最高值和最低值。
随机森林回归器无法发现使其能够外推超出训练集的值的趋势。当面对这种情况时,回归器假设预测将接近训练集中的最大值。上面的图 1 说明了这一点。
潜在的解决方案
好,那么你如何处理这个外推问题呢?
有几个选项:
- 使用线性模型,如 SVM 回归、线性回归等
- 构建深度学习模型,因为神经网络能够进行外推(它们基本上是类固醇上的堆叠线性回归模型)
- 使用堆叠组合预测值。例如,您可以使用线性模型和随机森林回归量来创建堆叠回归量。
- 使用随机森林的修改版本
其中一个扩展是回归增强随机森林 (RERFs)。本文作者提出了一种借鉴惩罚参数回归优点的技术,以在外推问题中给出更好的结果。
具体来说,该过程有两个步骤:
- 在随机森林前跑套索,
- 根据 Lasso 的残差训练一个随机森林。
由于随机森林是一个完全非参数的预测算法,它可能不能有效地结合反应和预测之间的已知关系。响应值是观察值 Y1,.。。,Yn 来自训练数据。RERFs 能够整合响应和预测之间的已知关系,这是使用回归增强随机森林解决回归问题的另一个好处。
Haozhe Zhang et. al 2019 “Regression-Enhanced Random Forests” | Source
最后的想法
在这一点上,我相信您可能想知道是否应该使用随机森林来解决回归问题。
让我们看看那个。
何时使用随机森林?
- 当数据具有非线性趋势时,训练数据之外的外推并不重要。
什么时候不用随机森林?
- 当您的数据是时间序列形式时。时间序列问题需要确定一个增长或下降的趋势,而这是一个随机的森林回归方程所不能表达的。
希望这篇文章能给你一些随机森林回归内部工作的背景知识。
随机连线神经网络:你真正需要知道的
原文:https://web.archive.org/web/https://neptune.ai/blog/randomly-wired-neural-networks
神经网络的创新布线是神经网络架构成功的一大部分,如 ResNets 和 DenseNets 。通过神经架构搜索(NAS) ,研究人员探索接线和操作类型的联合优化。
在来自脸书人工智能研究所的论文“探索用于图像识别的随机连线神经网络”中,作者通过随机连线神经网络的镜头研究了连接模式。随机网络生成器负责整个网络生成过程。
使用三种传统的随机图模型生成随机有线网络。根据作者的说法,这些网络在 ImageNet 基准上具有竞争性的准确性。
让我们探索一下随机有线网络,看看它们都是些什么。
Full computation graphs of three randomly wired network samples | Source
从网络生成器的角度研究神经结构
设计神经网络的自动化过程被称为神经架构搜索 (NAS)。NAS 可以用来寻找神经网络的最佳布线模式。NAS 网络生成器定义了一组理想的布线模式。网络从这个集合中取样,服从一个可学习的概率分布。
因为 NAS 网络生成器是手工设计的,所以可用的布线模式仅限于一小部分可能的图形。这篇论文的作者介绍了新颖的网络生成器。随机连线的神经网络是从随机网络生成器中采样的。这一代是由人类设计的随机过程定义的。
作者在图论中使用三个现有的随机图模型家族来避免他们自己的偏见。完整的网络定义是通过将随机图转换为有向无环图(DAG) ,并应用从节点到其功能角色的简单映射来完成的。
随机有线网络的体系结构
让我们来看看随机有线网络架构的基本概念。
网络发电机
网络生成器被定义为从参数空间到神经网络结构空间的映射。生成器决定如何连接计算图形。生成器执行确定性映射——给定相同的参数,它总是返回相同的网络架构。
如果引入一个伪随机数的种子,就导致了一个网络家族的构建。这些生成器被称为随机网络生成器。
随机连线神经网络
生成随机有线网络涉及以下概念:
- 生成一般图形
- 边缘操作
- 节点操作
- 输入和输出节点
- 阶段
生成一般图形
首先,网络生成器创建一组节点和连接这些节点的边。图形与神经网络的相似程度没有限制。
获得图形后,它被映射到计算神经网络。这种映射是人为设计的。简单的映射用于关注图形连接模式。
边缘操作
边缘用于数据流。定向边将数据从一个节点发送到另一个节点。
节点操作
图中的节点可以有输入边和输出边。一些节点操作包括:
- 聚合-通过加权和合并来自边缘的输入数据。在砝码上应用一个 s 形确保它们是正的。这种聚合保持了与输入通道相同数量的输出通道,从而防止卷积的计算量变大。
- 转换–使用 ReLU-卷积-BN 三元组 4 转换聚合数据。相同类型的卷积应用于所有节点。在这种情况下,它是一个 3×3 深度方向卷积,后跟一个 1×1 卷积,其间没有非线性。转换应该具有相同数量的输入和输出通道,以便转换后的数据可以与来自任何其他节点的数据合并。修复通道计数后,每个节点的参数计数和浮点运算保持不变。
- 分发–由节点的输出边发出转换数据的相同副本。
输入和输出节点
在图像分类问题中,你需要单一的输入和输出。由于没有输入边的多个输入节点,迄今获得的图将不是有效的神经网络。它还包含多个输出节点。
通过简单的后处理步骤,您可以生成有效的网络。创建一个连接到所有原始输入节点的额外节点。使用唯一输入节点向所有原始输入节点发送输入数据的相同副本。类似地,将一个输出节点连接到所有原始输出节点。该节点计算所有原始输出节点的未加权平均值。讨论中的两个节点不执行卷积。
阶段
独特的输入和输出节点导致有效的神经网络。然而,在图像分类的例子中,网络并不始终保持完整的图像分辨率。将网络划分为对要素地图进行下采样的阶段非常重要。
生成的图形代表一个阶段。该图通过其独特的输入和输出节点连接到前一级和后一级。连接到输入节点的节点的变换被改变为步长为 2。当从一个阶段过渡到另一个阶段时,随机图中的通道数增加 2 倍。
下表总结了随机连线神经网络,称为 RandWire。
随机图模型
使用的经典图模型都是无向的。一个简单的试探法被用来引导他们。三个经典随机
使用的图形模型有:
Comparison on random graph generators | Source
设计和优化
人类设计师通过线或网格搜索来优化网络的参数空间。也可以通过随机搜索扫描随机种子来进行优化。
然而,在这种情况下不会这样做(尽管这是可能的),因为对于不同的种子,精度变化可以忽略不计。而是报告多个网络实例的平均精度。
随机连线神经网络性能
这些网络中的实验是在 ImageNet 1000 类分类任务上进行的。对大约 120 万幅图像进行了训练,并对 5 万幅验证图像进行了测试。网络被训练 100 个历元,具有半周期余弦形状的学习速率衰减。标签平滑正则化的系数为 0.1。
Visualization of the random graphs generated by ER, BA, and WS. | Source
MobileNet 、 ResNet 和 ShuffleNet 是用于实验的一些架构。实验中使用的所有网络实例都收敛并实现了 73%以上的平均准确率。网络之间的差异也很小。下图显示了在 ImageNet 上的性能结果。
网络也可以被修改用于对象检测。在这种情况下,具有 FPN 的更快的 R-CNN 被用作对象检测器。
以下是对 COCO 物体探测的结果。
最后的想法
我们探索了受图论中随机图模型启发的随机连线神经网络。所获得的结果接近由人类设计的网络获得的结果和由基于神经结构搜索的模型获得的结果。这就是网络生成器的概念。
资源
推荐系统:构建和部署的经验
如果你看一下推荐系统的论文,你会发现大量的论文来自于行业而不是学术界。这是因为 RecSys 实际上是一个实际问题。电子商务的 RecSys 可能与社交媒体的 RecSys 有很大不同,因为它们的业务目标不同。此外,每一个新颖的想法都需要在现实世界中接受检验,才能获得可信度。因此,了解 RecSys 的实用性就像了解新颖的架构一样重要。
Structure of a recommender system | Source
本文讨论了构建推荐系统时的实际考虑事项。具体来说,我们将从以下几个方面谈谈我对推荐系统的认识:
- 数据集创建
- 目标设计
- 模特培训
- 模型评估
- 离线评估
- 检测和减轻偏见
- 检查模型正确性的清单
- RecSys 架构
- 在线营销
- A/B 测试
注:文中所有观点均为作者个人观点,不代表作者现任或前任雇主。
推荐系统:数据集创建
RecSys 的这一步不像文本或图像分类那样简单。例如,假设我们正在创建一个 RecSys,它可以预测电子商务网站的点击量。如果我们有少量的用户和项目,我们可以在所有数据上训练我们的模型。
然而,如果我们在亚马逊或沃尔玛的规模上工作,我们有数百万的每日活跃用户和目录中的商品。在整个历史交互上训练一个简单的协作过滤模型将花费我们很多成本——从数据仓库读取数据(如果不是 PBs,则以 TB 为单位),旋转一个高容量的 VM(将运行数周)。我们必须质疑这样做是否值得,以及正确的做法是什么。
如果我们的数据库中有十亿用户,每天有几百万活跃用户,那么我们必须只为这些活跃用户训练,因为不活跃的用户出现的机会更少。用户可以通过设置最近 N 天的活动阈值来选择这个用户子集,例如选择在最近 10 天内点击了> =10 个项目的用户。如果我们没有包括在培训中的一些用户出现,我们可以退回到一个定制的逻辑,比如基于内容或基于流行度的检索。由于 RecSys 模型会定期接受训练,因此这部分用户会不断变化。一旦我们选择了这个用户子集,我们就可以在与这些用户的交互上训练我们的模型。
下一个问题是,多少数据才够?如果我们有五年的数据,我们不需要全部。是的,模型受益于更多的数据。但在 RecSys 中,主要思想是最好地抓住用户的兴趣,这种兴趣会随着时间而变化。所以有新鲜的训练数据更有意义。此外,简单的协同过滤模型不能捕获太多的复杂性。人们可以通过绘制一个度量与训练步骤数的关系图来验证这一点,这很可能会显示收益递减。
接下来,在你的数据集中检测重复是有帮助的,就像相同的视频/物品用不同的 id 发布两次。此外, NLP 和 CV 模型可以帮助删除数据集的 NSFW、有害和非法内容。
遵循这些步骤可以大大减少数据集的大小。这将帮助我们以最小的质量损失节省成本。
推荐系统:设计最优目标
RecSys 的最终目标是给人们想要的东西。尽管这是一个宽泛且颇具哲理性的问题,但我们必须将其缩小到模型必须优化的特定信号——预测点击、喜欢、分享等。当我们训练一个模型来预测点击并使用它来提供推荐时,我们的基本假设是,如果你点击了一个项目,它就与你相关。通常情况下,这并不完全正确。
为了更好地理解这一点,让我们用一个不同的例子。假设你正在为 YouTube 构建一个 RecSys,它可以预测用户是否会点击某个特定的视频。该模型用于基于点击概率提供推荐。然而,这种模式减少了用户在平台上花费的时间。原因是点击不等同于关联。大多数 clickbait 视频的点击率都很高,但观众在几秒钟后就会停止观看。一个 100%准确的模型将提供大量被点击但未被观看的视频。
从上面的学习中,您决定训练一个模型来预测用户是否会观看至少 75%的视频。因此,训练示例将包括(用户、视频、标签)三元组,其中如果> =75%的视频被观看,则标签=1,否则为 0。这比点击模型更好,因为现在我们认为用户所做的不仅仅是点击一个视频。然而,即使这样也有一个大问题。
考虑两个视频,A 和 B,A 是娱乐性的 20 秒长的视频,B 是 60 分钟的教程视频。要看 75%,需要看 15 秒的 A,45 秒的 b。
自然地,A 将比 B 具有更高的该标签的肯定率。然而,观看 15 秒的 A 可能意味着用户不喜欢 A(因为 15 秒对于决定你是否更喜欢该内容来说太短了),观看 30 分钟(50%)的 B 很可能意味着 B 与用户相关。即使是高度精确的模型最终也会提供不成比例的大量较短持续时间的视频,这不是最优的。
关键是一个信号很少定义完全的相关性。每个信号都有自己的偏差。在多个信号上训练多个模型,结合它们各自的分数(例如,加权相加),并创建最终分数,这是一个很好的做法。
推荐系统:模型训练
大型 NLP 或视觉模型有数十亿个分布在线性、卷积、递归或注意力层中的参数。这些参数中的每一个都涉及到输出的计算。然而,在推荐模型中,模型大小比大多数 NLP 或 CV 模型大得多。
考虑矩阵分解,其中模型学习一个用户和一个项目嵌入(在协同过滤的情况下)。如果嵌入维度是 100,你有 1 亿个用户,1000 万个商品。总嵌入数为 1.1 亿。每个嵌入有 100 个可学习的参数。因此,该模型有 110*1 亿或约 110 亿个参数。然而,要计算一个用户的分数,你一次只需要访问 1 亿个用户嵌入中的一个。这个特定的用户嵌入与所有的项目嵌入一起使用来对所有的项目评分。因此,推荐模型占用大量内存,但计算量较小。
这是一个不同的挑战,因为现在你不能也不需要为一批数据在 GPU/TPU 上加载整个嵌入表。然而,在传统框架如 TensorFlow 或 PyTorch 上编写这样的模型很难,因为它们的默认行为是在 GPU/TPUs 上加载整个模型。幸运的是,许多框架都为此构建了功能。
Tensorflow 构建了一个名为tensor flow _ re commenders的框架,并带有一个名为tpuemleding的特殊嵌入表。此外,它还实现了 RecSys 中许多常见任务的版本,如检索和排序以及流行的架构,如 DCN 。
**近日,PyTorch 公布了 torchrec 。据该小组称:
“TorchRec 是一个 PyTorch 域库,旨在提供大规模推荐系统(RecSys)所需的通用稀疏度&并行原语。它允许作者使用分布在许多 GPU 上的大型嵌入表来训练模型。”
NVIDIA 也有 梅林 ,它可以自动化 RecSys 中的常见流程,以实现更快的生产级系统。它支持 Tensorflow 和 PyTorch,构建在 cuDF(相当于熊猫的 GPU)、RAPIDS(基于 GPU 的分析和数据操作库)和 Triton(高性能推理服务器)之上。
推荐系统:模型评估
离线评估
典型的分类任务针对准确性、精确度、召回率或 F1 分数等指标进行优化。使用这些指标评估 RecSys 具有欺骗性。在 RecSys,我们对客观概率不感兴趣。我们对排名更感兴趣。例如,如果视频 A 和 B 的预测得分是 0.9 和 0.8,我们将在服务时首先显示视频 A,然后显示视频 B。即使 A 和 B 的概率是 0.5,0.4,或者 0.3,0.2,结果仍然是一样的。重要的是顺序,而不是绝对数字。因此,ROC-AUC、PR-AUC、NDCG、recall@K 和 precision@K 等指标更适合。
然而,即使这样,这种评价也是可遇不可求的。推荐系统因对某些主题、人口统计或受欢迎程度的复合偏见而臭名昭著。推荐系统在自己生成的日志上进行训练。如果受欢迎的内容被系统提升得更多,那么所生成的增量日志将具有更多针对该受欢迎的内容的三元组。在这些新日志上训练的模型的下一个版本将会看到一个偏斜的分布,并且将会知道推荐流行的项目是一个安全的选择。这就是所谓的流行偏见。
建议计算不同级别的指标,如年龄、性别、位置等用户属性。这有助于我们了解该模型对于特定的一组用户是否表现更好,而对于其他用户是否表现不佳。像 reclist 这样的工具提供了一个简单的界面来深入你的推荐模型。
另一个有用的工具可能是 Neptune ,因为它提供了简单的日志 API 来进行更有组织性、协作性和综合性的分析。人们可以创建定制的仪表板通过交互式可视化来可视化日志。如上所述,我们感兴趣的是基于人口统计和位置等属性的多重切割的度量。我们可以在这里绘制 ROC/PR AUC、损失曲线和对数排名指标,并轻松比较和确定该模型是否真正稳健。
Example dashboard in Neptune | Source
检测和减轻偏见
如前所述,如果不加以注意,像受欢迎程度偏差这样的偏差很容易在系统中传播。但是我们如何在减轻偏见之前衡量它呢?
A loop of detecting and mitigating bias| Source
一个简单的测量受欢迎程度偏差的方法是检查有多少独特的项目占 10%,20%,50%,..百分之百的推荐。在理想的情况下,项目的数量应该随着推荐量的增加而增加。但是,对于有偏差的模型,项目数量会在某个百分比(通常在较低端)后饱和。这是因为该模型仅依赖可推荐项目的某个子集来进行预测。
但是这种方法没有考虑用户的偏好。例如,如果用户 U1 与三个项目 A、B 和 C 交互;并且喜欢项目 A 和 B 但不喜欢项目 C。类似地,用户 U2 与 A、B 和 C 交互;只喜欢 A。我们知道 A 是受欢迎的商品,而 B 和 C 不是。
答(受欢迎) | b(不流行) | c(不流行) | |
---|---|---|---|
0 | |||
0 | 0 |
简单有偏模型的例子
对 U1 来说,如果模型对 A 的评分高于 B,那么它可能是有偏见的。因为用户对它们的反应都是积极的。即使模型始终支持更受欢迎的项目,我们也有一个有偏见的模型。然而,对于 U2 来说,将受欢迎的项目排名更高是有意义的,因为 U2 不喜欢另外两个不受欢迎的项目。虽然我们使用的例子非常简单,但有统计奇偶校验这样的方法可以帮助你衡量这一点。
有一些简单的方法可以减轻偏见。一种方法是引入阴性样本。考虑一个电子商务平台,用户在这个平台上与数百件商品中的几件互动。我们只知道用户交互了哪些项目(正面的例子)。然而,我们不知道其他物品发生了什么。为了平衡这个数据集,我们通过为一个用户随机抽样一个项目并给它分配一个负标签(=0)来引入负样本。假设用户不会喜欢随机挑选的商品。由于这种假设很可能是正确的,所以添加负样本实际上会将缺失的信息添加到数据集中。
测试推荐系统模型正确性的清单
像任何软件一样,人们应该通过编写单元测试来确保模型的正确性。不幸的是,编写 ML 代码单元测试并不常见,也很棘手。但是,对于 RecSys 来说,让我们关注一个简单的 CF(协同过滤)模型。众所周知,该模型本质上是用户嵌入和项目嵌入的集合。您可以对该模型进行以下测试:
- 正确评分–消耗用户和项目嵌入的评分操作应产生介于 0 和 1 之间的分数。
- 正确的版本控制–由于嵌入会定期重新训练,因此正确地对它们进行版本控制以保持分数一致是非常重要的。
- 正确的特征–一些模型,如双塔模型,使用诸如最近 X 小时的用户活动的特征。我们需要确保模型使用的特性管道不会产生泄漏的特性。
- 正确的训练数据集–数据集不应有重复的用户-项目对,标签应正确,训练-测试-分割应是随机的。
RecSys 架构
推荐系统必须从数百万个项目中为用户挑选最好的一组。然而,这必须在严格的延迟要求内完成。因此,我们训练的模型越复杂,处理一个请求所需的时间就越多。因此,RecSys 采用多级架构。你可以把它想象成一个漏斗,从一百万个项目开始,到少数几个推荐结束。
这个想法是在这个漏斗的顶端使用一个简单、轻量级的模型,就像一个简单的协作过滤模型。该模型应该能够挑选出几千个最相关的项目,可能没有最好的排名,即相关项目应该出现在这几千个项目中,如果它们不在顶部也没关系。因此,该模型优化了召回率和速度。这个模型也被称为候选生成器。即使在简单的协同过滤模型中,也要确保嵌入维度不要太大。使用 100 维可能会使您的回忆略有增加,但会影响您的延迟。
然后,这数以千计的物品被送到另一个名为 light ranker 的模型中。顾名思义,这个模型的任务就是寻找最佳排名。模型经过高精度训练,比候选发电机更复杂(例如双塔模型)。它还使用了更多基于用户活动、项目元数据等的功能。这个模型的结果是一个包含数百个项目的排序列表。
最后,这数百件物品被送到重 ranker。这个等级与轻等级有着相似的目标,除了它比轻等级更重并且使用更多的特性。因为它只对数百个项目进行操作,所以这种复杂体系结构所涉及的延迟是可管理的。
Recommender systems architecture | Source
用于推荐系统的在线 MLOps
与分类或回归模型相比,推荐模型的一个好处是我们可以获得实时反馈或“标签”。因此,我们可以建立一个全面的 ML Ops 管道来密切监控您的模型性能。
我们可以监控许多指标。
-
1 在平台上花费的时间
-
2 订婚
-
3 次点击
-
4 采购
-
5 用户流失
模型在参与度等指标上的表现很容易在离线实验中衡量。然而,你不能在一个离线实验中测量像流失这样的东西。在现实世界的 RecSys 中发现这种差异是很常见的。通常,我们会分析哪些在线指标(如花费的时间、参与度、点击量)与客户流失正相关。这减少了在离线实验中改进一组可预测指标的问题。
除了模型质量和性能,我们还应该监控平均值、第 95 个百分点、和第 99 个百分点的延迟、CPU、非 200 状态代码率、和内存使用情况。这并不奇怪,但是提高这些指标也可以减少花费的时间并减少流失。像 Grafana 这样的工具有助于建立全面的观察仪表板。
再培训管道也可能因为与代码错误无关的问题而中断,比如 Kubernetes 集群中没有足够的 pods 可用,或者没有足够的 GPU 资源可用。如果您在 Airflow 上使用 DAGs,它可以选择在 Slack 上设置故障警报。或者,调整重试次数和超时参数,以便提高自动恢复的机会。
推荐系统:A/B 测试
改进推荐系统是一个持续的过程。然而,这种改进不应该恶化用户体验。如果你的团队提出了一个新颖的模型,在离线评估中显示出惊人的收益,那么向所有用户推广这个模型并不明显。这就是 A/B 测试发挥作用的地方。
任何新的目标模型都必须对照控制(现有生产)模型进行评估。在 A/B 测试中,您将随机选择一小部分用户,并使用目标模型为他们服务,而其余的用户像以前一样从控制模型接收建议。几天/几周后,看看哪个模型表现更好,并使用假设检验对其进行量化。如果测试的结论是新的模型比控制的模型更好,那么您就向所有用户推出新的模型。
然而,一个好的做法是只向 98-99%的用户推广新模型,而让其余 1-2%的用户使用控制模型。这 1-2%的用户被称为维持组。这里的想法是看看,在某个时候,新模型是否开始退化,是由于影响所有模型的一些变化,还是仅仅这个新模型有问题?在 RecSys 中,当服务于一小组用户时,目标模型仍然在主要由控制模型生成的日志上被训练。然而,有可能当新模型成为控制时,它开始从主要由它自己生成的日志中学习并退化。
结论
RecSys 有许多移动部件,这些部件中的每一个都是一个旋钮,可以通过调节来使系统变得更好。就我个人而言,这是 RecSys 让我真正感兴趣的地方。我希望这篇文章能够提供新的思考方向。每个主题都有不同数量的文献供你探索。下面我链接了一些参考。一定要检查他们!
参考
[1] TwHIN:嵌入 Twitter 异构信息网络进行个性化推荐
[2] 协同过滤中的流行度-机会偏差
[3] 在 Twitter 上解决基于模型的候选人生成中数据集偏差的经验教训**
推荐系统:机器学习度量和商业度量
原文:https://web.archive.org/web/https://neptune.ai/blog/recommender-systems-metrics
通常,围绕如何评估一个推荐系统或者我们应该关注什么 KPIs】存在争议?推荐系统可以通过多种方式使用多个度量组进行评估。每个指标组都有自己的用途。在本文中,我们将看看它们是什么,以及如何将它们结合起来,使业务团队和 ML 工程师都感到满意。
- 我们将从讨论什么是推荐系统以及它们的应用和好处开始。
- 我们还将比较为推荐系统建立机器学习模型的主要技术,并了解度量和业务评估技术。
- 最后,我们将了解如何为所需的评估选择这些指标。
推荐系统简介
什么是推荐系统?
推荐系统旨在向用户推荐他们可能喜欢或购买的相关内容或产品。它有助于找到用户正在寻找的商品——直到推荐显示出来,他们才意识到这一点。对于不同的客户,必须采用不同的策略,这些策略是由现有数据决定的。由于 RS 必须是一种数据驱动的方法,它可以由机器学习算法来驱动。
提出建议有两个主要阶段:
- 1 候选生成–创建用户可能喜欢的产品子集。
- 2 评分——根据向用户显示的项目对候选列表进行缩减和排序。
这些技术和相关的评估指标将在本文中进一步描述。
产品推荐的力量
为了充分利用 RS 并改善用户体验,我们应该了解并深入研究以下各项之间的关系:
- 用户和产品–当用户对特定产品有偏好时。例如,一个网飞用户可能喜欢恐怖片,而另一个用户可能喜欢喜剧片。
- 产品和产品–当物品相似时。例如,相同流派的音乐或电影。
- 用户和用户——当用户对某一特定商品有相同或不同的喜好时。例如,青少年可能在他们消费的内容方面不同于成年人。
在设计 RS 时记住这些关系会给用户带来愉快的体验,从而提高他们对这些产品的参与度。让我们想象一下 YouTube 没有你喜欢的推荐视频。我们大多数人在那里花了很多时间,只是因为推荐是如此准确!
推荐系统背后的策略
要为这样的系统选择最佳策略,我们必须首先评估可用的用户和产品数据量。以下是一些流行的策略,按照所需数据量的升序排列:
- 1 全球——为用户提供最常购买、最流行或最受欢迎的产品。它们可能与任何用户相关。
- 2 上下文-依靠产品属性和一起购买的物品,它们可以与地理位置等基本用户属性相结合,并可用于针对某个群体。
- 3 个性化——不仅需要情境数据,还需要用户行为,如购买历史、点击等。
这些策略应该相互结合,以增强 RS 的性能。例如,在线购物平台应该了解产品的背景以及用户的购买历史。虽然“一起查看”策略只适用于新用户,但对于老客户来说,“一起购买”策略更合适。
如何衡量一个推荐人的成功?
这里有一个重要的问题:如何衡量一个推荐人的成功?已经知道应该以某种方式组合的可能关系和策略,答案需要很大的努力。由于要涵盖多个组件和指标,因此很难衡量一个推荐引擎对于一个业务问题有多好。
然而,对于这样的任务,我们可以使用一些度量标准。由于它们的具体选择取决于算法,下一节将专门概述可能的候选生成技术,这是推荐系统的第一步。
候选生成技术
候选生成的目标是预测某个用户对产品的评价,并根据该评价选择他们可能喜欢的项目子集。
Candidate generation | Source: Author
有两种主要的技术需要描述:基于内容的过滤和协同过滤。
1.基于内容的过滤
基于内容的过滤意味着 RS 将向喜欢或购买的项目推荐相似的项目(上下文策略)。举个例子,如果用户 A 看了两部恐怖电影,会向他推荐另一部恐怖电影。这种技术可以以用户或项目为中心。
以项目为中心
以项目为中心的基于内容的过滤意味着 RS 仅基于与先前项目的相似性来推荐新项目(隐式反馈)。
Item-centred content-based filtering | Source
以用户为中心
在以用户为中心的基于内容的过滤的情况下,例如通过问卷形式(明确的反馈)收集关于用户偏好的信息。这种知识导致推荐与喜欢的项目具有相似特征的项目。
User-centered content-based filtering | Source
如何开始?
基于内容的系统的基本部分是选择相似性度量。首先,我们需要定义一个基于隐式或显式数据描述每个用户的特征空间。下一步是建立一个系统,根据选择的相似性度量对每个候选项目进行评分。适合基于内容的过滤任务的相似性度量将在本文后面讨论。
2.协同过滤
它通过同时使用用户和项目之间的相似性来解决基于内容的过滤的一些限制。它允许我们基于相似用户 b 购买的商品向用户 A 推荐一个商品。此外,CF 模型的主要优点是它们自动学习用户的嵌入,而不需要手工设计。这意味着它们比基于内容的方法受到的限制更少。协同过滤系统可以分为基于记忆和基于模型的方法。
Collaborative filtering | Source
基于记忆的
基于记忆的 CF 系统处理来自项目-项目或用户-用户交互的记录值,假设没有模型。搜索是基于相似性和最近邻算法完成的。例如,找到与用户 A 最接近的用户,并推荐他们购买的商品。
基于模型的
基于模型的方法假设生成模型解释用户-项目交互并做出新的预测。他们利用矩阵分解算法将稀疏的用户-项目矩阵分解成两个矩阵的乘积:用户因子和项目因子。近年来,在基于模型的遥感领域,人们研究了很多方法。例如关联规则、聚类算法、深度神经网络等。
混合物
混合推荐系统是基于内容和协同过滤方法的结合。这些系统有助于克服这两种类型的推荐器所面临的问题。它可以通过多种方式实现:
- 这两个组件可以单独开发,也可以组合开发。
- 也可以基于关于可用用户数据量的条件来分层设计。如已经提到的,“一起查看”策略可以应用于新用户和基于内容的以项目为中心的过滤。这有助于克服冷启动问题。然而,当有更多的数据可用于过去的购买者时,我们可以为他们实施协同过滤方法。
在我们继续之前,让我们来看看下表中这两种技术的优缺点:
模型
基于内容
合作的
Content-based:
如果用户喜欢喜剧,推荐另一部喜剧
Collaborative:
如果用户 A 和用户 B 相似,用户 B 喜欢某个视频,那么这个视频就推荐给用户 A
Content-based:
- 不需要任何关于其他用户的数据
- 可以推荐小众单品
Collaborative:
- 不需要领域知识
- 帮助用户发现新的兴趣
Content-based:
- 需要大量的领域知识
- 仅基于用户的现有兴趣进行推荐
Collaborative:
- 无法处理新鲜物品(冷启动)
- 很难包含查询之外的功能
基于内容和协作技术的比较|来源:作者
推荐系统的评价
当谈到指标时,各种类型的推荐系统之间的区别是什么?评估模型有几个指标。在基于内容的过滤方面,我们应该从相似性度量中进行选择,而对于协作方法——预测和分类度量取决于我们是预测得分还是二进制输出。
在我们评估候选生成模型之后,我们可能希望根据业务价值评估整个系统,并涵盖更多非准确性相关的指标以进行评分。所有这些都将是本节的主题。
相似性度量
当我们有一个项目的元数据可用时,我们可以很容易地向用户推荐新的项目。例如,如果我们在网飞上观看了电影 A,我们可以根据其他电影的大量元数据标签推荐另一部电影,并计算它们与电影 A 之间的距离。另一种方法是使用 Tf-Idf 等 NLP 技术,并将电影描述表示为向量。我们只需要选择一个相似性度量。
最常见的有余弦相似度、雅克卡相似度、欧氏距离和皮尔逊系数。所有这些都可以在“sklearn.metrics”模块中找到。
余弦相似性
对于一个以商品为中心的系统,要计算已购买商品和新商品之间的相似性,我们只需取代表这些商品的两个向量之间的余弦值。如果有很多高维特征,余弦相似度是最佳匹配,尤其是在文本挖掘中。
雅克卡相似性
Jaccard 相似性是交集的大小除以两组项目的并集的大小。
与本文中其他相似性度量的不同之处在于,Jaccard 相似性将集合或二进制向量作为输入。如果向量包含排名或评级,则不适用。在电影推荐的情况下,假设我们有 3 部带有 3 个热门标签的电影。
- 电影 A 标签=(冒险、浪漫、动作)
- 电影 B 标签=(冒险、太空、动作)
- 电影 C 标签=(浪漫、喜剧、友情)
基于这些数据,我们可以说电影 A 更像电影 B 而不是电影 C。这是因为 A 和 B 共享 2 个标签(冒险、动作),而 A 和 C 共享一个标签(浪漫)。
欧几里得距离
它是以用户为中心的系统中两个用户之间的距离,是连接他们的线段的长度。偏好空间是可用项目,轴是由用户评级的项目。基于用户评级,我们搜索具有相似品味的用户喜欢的项目。两个人之间的距离越小,他们喜欢相似物品的可能性就越大。
这种度量的潜在缺点是,当人 A 倾向于给出比人 B 更高的分数(整体排名分布更高)时,欧几里德相似性将会很大,而不考虑人 A 和人 B 之间的相关性
皮尔逊相关系数
PCC 是代表用户评级的两个向量之间的关系的线的斜率的度量。它的范围从-1 到 1,0 表示没有线性相关性。
例如,让我们考虑用户 A 和用户 B 给出的评级:
- 用户 A 的评分= [5,6,8,5,7]
- 用户 B 的评级= [5,8,6,5,5]
最佳拟合线具有正斜率,这意味着用户 A 和用户 B 之间的正相关性(下图):
Correlation between ratings of two users | Source: Author
通过使用这种方法,我们可以预测人 A 会如何评价一个还没有被评价的产品。为此,我们简单地取其他用户(包括用户 B)的评级的加权平均值,其中权重是使用 PCC 相似性来计算的。
预测指标
预测性测量解决了推荐系统的评级与用户评级有多接近的问题。对于非二进制任务,它们是一个很好的选择。平均绝对误差(MAE)和均方根误差(RMSE)是最流行和最容易解释的预测指标。
平均绝对误差
MAE 是推荐和相关评级之间差异的平均幅度,非常容易解释。
MAE formula, R – predicted Ratings matrix | Source
请注意,它不会惩罚大的错误或异常值,并对这些情况进行与其他情况相同的加权。这意味着 MAE 对评级准确性给出了一个相当全面的观点,而不是惩罚大的错误。
均方根误差
RMSE 是一个二次评分指标,也衡量平均幅度,但平方根有所不同。
RMSE formula, R – predicted Ratings matrix | Source
RMSE 对大错误给予很大的权重。这意味着当离群值不受欢迎时,这更有用。
在实践中,RMSE 和 MAE 通常在 K-fold 交叉验证数据集上被检查用于协同推荐模型。然而,从业务角度来看,重要的不仅是最高的 RMSE 或 MAE,还有用于评分的非准确性指标,这将在后面的部分中描述。现在,让我们继续讨论二值化推荐任务的指标。
分类指标
分类度量评估推荐系统的决策能力。对于识别与用户相关或不相关的产品这样的任务,它们是一个很好的选择。对于决策支持度量,精确的评级被忽略,而对于基于排名的方法,它通过排名具有隐含的影响。
决策支持度量
基于所有用户的所有推荐项目,可以计算传统精度和召回率。在测试数据集中可用或接收到高交互值的推荐项目可以被认为是准确的预测,反之亦然。这些指标需要来自用户的注释,将我们的问题转化为二进制文件,并设置被考虑的顶级推荐的数量(Top-N)。然后,通过使用‘sk learn . metrics’模块,我们可以构建混淆矩阵并定义度量如下:
Relevant:
真阳性(TP)
Not relevant:
假阳性
Relevant:
假阴性(FN)
Not relevant:
真阴性(TN)
推荐结果混淆矩阵|来源:作者
精确
Precision@k 是与用户相关的前 k 个推荐项目的一部分
P =(相关的前 k 个推荐的数量)/(被推荐的项目的数量)
让我们来看看这个例子:
召回率@k 或命中率@k
Calculation of precision@k | Source: Author
Recall@k 或 HitRatio@k 是与用户相关的一组项目中的前 k 个推荐项目的一部分。请注意,k 越大,命中率越高,因为推荐中包含正确答案的可能性越大。
R =(相关的前 k 个建议的数量)/(所有相关项目的数量)
在我们的例子中它看起来像什么?
F1@k
Calculation of recall@k | Source: Author
F1@k 是 precision@k 和 recall@k 调和平均值,有助于将它们简化为单一指标。以上所有指标都可以基于混淆矩阵进行计算。确切的公式如下所示:
正如我们所见,F1 系数不考虑真负值。那些是推荐系统没有推荐与用户无关的项目的情况。这意味着,我们可以把任何值放入真负值,它不会影响 F1 的分数。一个有趣且完全对称的替代方法是马修斯相关系数(MCC)。
Precision, recall, F1 formulas | Source
马修斯相关系数
马修斯相关系数是观察到的和预测的二元分类之间的相关系数:
当分类器是完美的(FP = FN = 0)时,MCC 的值是 1,表示完美的正相关。相反,当分类器总是错误分类(TP = TN = 0)时,我们得到的值为-1,代表完全负相关。
基于排名的指标
如果我们有一个候选生成算法,它返回项目的排序,并且列表中更靠下的项目不太可能被使用或看到,那么应该考虑以下度量。
平均精度
precision@k (P(k))只考虑从排名 1 到 k 的推荐子集,而 average precision 奖励我们将正确的推荐放在列表的顶部。先说定义。如果我们被要求推荐 N 个项目,并且在项目的整个空间中相关项目的数量是 m,那么:
例如,让我们考虑 AP@5 的示例输出,同时我们向添加了 m = 5 产品的用户推荐商品。
在第一组建议中,我们可以看到只有第五项建议是相关的。它表示 precision @ 1 = precision @ 2 = precision @ 3 = precision @ 4 = 0,因为前四位没有相关项。精度@5 等于⅕,因为第 5 项是相关的。一旦我们计算了所有的 precision@k 值,我们将它们相加并将结果除以 5,即得到 AP@5 值的产品数。
Calculation of AP, example 1 | Source: Author
根据上面的例子,我们应该注意到,AP 会因为正确的推荐排名靠前而奖励我们。这是因为第 k 个子集的精度越高,我们对 k 点的猜测就越正确。这可以在下面的例子中看到。
Based on the above example we should notice that AP rewards us for top ranking the correct recommendations. That happens because the precision of the kth subset is higher the more correct guesses we have up to the point k. This can be seen in the below example.
当 precision@5 不变时,AP@5 随着推荐项目的等级而降低。需要注意的一件非常重要的事情是,AP 不会因为我们在列表中加入了额外的推荐而惩罚我们。在使用它时,我们应该确保我们只推荐最好的项目。
Calculation of AP, example 2 | Source: Author
平均精度
AP 适用于单个数据点,相当于单个用户,而 MAP 是所有 Q 个用户的 AP 指标的平均值。
平均倒数命中等级(ARHR)或平均倒数等级(MRR)
MAP formula | Source: Author
MRR 是用户倒数排名(RR)的平均值。倒数排名是第一个正确项目排名的“乘法倒数”。在两种情况下,MRR 是一个合适的选择:
MRR is the average of reciprocal rank (RR) over users. The reciprocal rank is the “multiplicative inverse” of the rank of the first correct item. MRR is an appropriate choice in two cases:
1 只有一个相关项。
- 2 在用例中,只有第一个推荐的项目是必不可少的。
- 这意味着如果结果列表中有多个正确答案,则 MRR 不适用。如果你的系统返回 10 个条目,并且在第三高的位置有一个相关条目,这就是 MRR 所关心的。它不会检查其他相关项目是否出现在等级 4 和等级 10 之间。
MRR 的示例计算如下所示:
贴现累计收益(DCG)
MRR calculation | Source: Author
DCG 是衡量排名质量的一个标准。要描述它,我们应该从累积收益开始。CG 是列表中所有结果的分级相关性值的总和。这意味着我们需要计算我们的推荐的相关性分数。
DCG is a measure of ranking quality. To describe it, we should start with Cumulative Gain. CG is the sum of graded relevance values of all results in the list. That means that we need relevance scores of our recommendations to calculate it.
累积增益计算|来源:作者
正如我们所看到的,假设高度相关的文档在搜索结果列表中出现得越早就越有用,那么上述两个相关性得分列表获得相同的得分并不完全正确。
为了解决这个问题,应该引入 DCG。它通过减少与结果位置成对数比例的分级值来惩罚在搜索中出现较低的高度相关的文档。参见下面的等式。
基于我们的示例,让我们计算 Python 中“scoresA”的 DCG,将“scoresB”视为真实输出。
正如我们所见,DCG 分数大约是 3.6,而不是 6。DCG 的问题是很难比较不同查询的性能,因为它们不在 0 到 1 的范围内。这也是 nDCG 更常用的原因。它可以通过计算理想 DCG (IDCG)来获得。IDCG 是按降序排序的 DCG,起着归一化因子的作用。
Computing DCG in Python | Source: Author
在我们的例子中:
nDCG 评分的局限性在于它不惩罚假阳性。例如,[3]和[3,0,0]产生相同的 nDCG,但在第二个输出中,有 2 个不相关的建议。它也可能不适合具有几个同样好的结果的推荐系统。
Computing nDCG in Python | Source: Author
不仅仅准确性很重要
我们必须记住,建议不是预测。评估候选生成模型是一回事,把模型纳入整个 RS 系统,给最感兴趣的项目打最高分是另一回事。客户评估系统的方式不仅受到准确性的影响,还受到公司商业策略的影响。例如,对于新闻聚合网站来说,目标是增加人们在平台上花费的时间,而对于电子商务来说,RS 性能的决定因素是销售额的增加。
以推荐为中心的指标
以推荐为中心的指标是独立于用户的概念,不需要用户信息。他们评估系统的领域,而不是用户的评级或他们的历史。它们包括本文前面定义的准确性和度量标准。让我们来看看其中的一些。
多样性
当协作推荐系统只关注准确性时,我们可能会遇到图示的问题。在这个例子中,用户购买了几张披头士的专辑。结果,向他们提供了该乐队的其他专辑的列表。尽管用户可能喜欢它,但是这种本地化的推荐不是很有用。为其他波段留出更多空间会更有用。
When the collaborative recommender system is focused on accuracy only, we may experience the illustrated problem. In this example, the user bought a couple of Beatles’ albums. As a result, they are provided with a list of other albums of this band. Although the user might probably like it, such localised recommendations are not very useful. It would be more useful to have more space for other bands.
这就是多样性的含义,它是结果集中所有项目对之间的平均差异。当然,它高度依赖于可用的元数据以及我们选择的相似性度量。正如我们在下图中所看到的,虽然准确度在 40-100 个最佳推荐之间保持不变,但多样性仍然随着所显示的推荐项目的数量而增加。这意味着值得考虑多样性度量来对推荐项目重新排序。
Not so useful recommendation | Source
新闻报道
覆盖率是推荐系统向用户推荐一个训练集中的所有项目的能力。让我们考虑像在抽奖中那样选择物品的随机推荐器。这种推荐器具有接近 100%的覆盖率,因为它具有推荐每个可用项目的能力。另一方面,基于流行度的推荐器将只推荐前 k 个项目。在这种情况下,覆盖率接近 0%。
Evaluation of Top-K item recommendation where K ranges from 5 to 100 on the ItemKNN algorithm for the MovieLens dataset. For diversity, Shanon entropy has been used | Source
覆盖率不评估用户是否喜欢推荐,而是根据它给用户带来意想不到的能力来衡量 RS。覆盖率低会导致用户不满意。
以用户为中心的指标
以用户为中心的指标通过询问用户、自动记录交互和观察他的行为(在线)来收集。尽管这种实证测试困难、昂贵且需要大量资源,但这是真正衡量客户满意度的唯一方法。我们来讨论一下。
新奇
它是衡量 RS 向用户介绍长尾项目的能力。电子商务平台可以从排名靠前的个性化小众商品中受益。例如,亚马逊通过销售传统书店没有的书籍,而不是畅销书,取得了巨大的成功。
新奇可以被定义为用户喜欢的所有项目中未知项目的一部分。衡量它的理想方式是客户调查,但在大多数情况下,我们无法确定用户之前是否知道该商品。有了关于用户行为的隐含数据,我们就可以衡量推荐之间的差异,这种差异有时可以替代新奇分数。我们还必须记住,太多新奇的东西会导致用户缺乏信任。找到新颖性和可信赖性之间的平衡至关重要。
可信赖
Long-tail is full of niche content that users may like | Source
这是一个衡量用户是否信任与他们互动的推荐系统的指标。一个改进的方法是增加一个解释,解释为什么推荐一个特定的项目。
流失和响应
用户评价新项目后,流失衡量推荐变化的频率。响应是这种变化的速度。应该考虑这两个指标,但与新颖性相似,它们会导致低可信度。
现在我们知道,准确性不足以衡量 RS 的性能,我们还应该将注意力放在覆盖率和新颖性等指标上。
业务指标
不幸的是,上面描述的所有指标都没有向我们展示真正的客户对公司商业战略方面产生的建议的反应。衡量它的唯一方法是 A/B 测试。A/B 测试花费更多的资源和时间,但是它允许我们测量下图中显示的指标,我们将在本节中定义这些指标。
点击率
CTR 衡量的是推荐获得的点击量。假设点击率越高,推荐就越相关。它在新闻推荐领域非常受欢迎,并被 Google News 或 Forbes 等网络平台所使用。与基于流行度的系统相比,个性化的建议给他们带来了大约 38%的点击量增长。
Business metrics for recommender systems | Source
采用和转换
虽然 CTR 告诉我们用户是否点击了某个商品,但它不能确定这个点击是否转化为购买。YouTube 和网飞已经考虑了替代收养措施。只有当用户观看了特定比例的视频(“长点击率”)时,他们的 YouTube 点击才会被计算在内。同样,网飞统计电影或连续剧被推荐后被观看的次数(“收视率”)。
当一个项目无法查看时,必须定义其他特定于领域的度量。例如,在 LinkedIn 的情况下,它将是在工作机会推荐之后与雇主联系的次数。
销售和收入
在确定引入的算法在识别后来的观看或购买方面是成功的方面,CTR 和采用度量是好的。然而,销售的变化通常是最重要的。然而,确定遥感的商业价值方面的改进仍然是困难的。无论如何,用户可能已经购买了一件商品,而推荐可能是不相关的。
对销售分布的影响
与之前相比,衡量引入 RS 后的销售变化是一种非常直接的方法。然而,这需要了解销售分布变化的影响。例如,我们可以观察到个体水平上多样性的减少,并通过进一步的努力来克服这种影响。
用户行为和参与度
几个真实的 RS 测试发现,有一个推荐通常会增加用户的活跃度。通常,在不同的领域(例如,在 Spotify),客户参与度和保持度之间存在对应关系。当流失率较低时,可能很难衡量。
如何为一个推荐系统选择指标?
由于我们已经熟悉了推荐系统评估指标的多个指标,我们现在可能会怀疑从哪里开始。如果我们问自己以下问题,可能会有所帮助。
Summary of business metrics | Source
使用哪种候选生成技术?
对于基于内容的过滤,应考虑相似性度量来评估模型性能,如余弦或 Jaccard 相似性。对于协作方法,应选择预测性和准确性指标。
有带注释的数据吗?
我们有从用户或企业收集的明确数据吗?如果是,我们可以将其用作测试集,并使用与准确性相关的度量标准执行监督模型构建。如果不是,我们不得不把隐含数据当作基本事实。这意味着与准确性相关的指标信息会更少,因为我们不知道用户会如何反应,例如,一个利基推荐项目。我们必须关注覆盖面和多样性。
推荐物品有顺序吗?
如果用户打算以特定的顺序考虑多个推荐,与准确性相关的度量(例如 precision@k,recall@k)是不够的,因为它们忽略了排序,并且同等地加权具有较低和较高等级的项目。地图、MRR 或 DCG 可能是更好的选择。
物品是用数字还是二进制来评分的?
在协作系统的情况下,二元尺度表示分类任务和准确性度量,而等级表示回归任务和预测性度量。对于基于内容的系统,二进制尺度允许我们使用 Jaccard 相似性度量。
用户对排名较低的项目的兴趣衰减有多快?
地图、MRR 和 DCG 等指标反映了热门建议的顺序。当我们希望不仅包括排名,还包括顶级项目的评级时,最佳选择是 DCG。它包含了某些项目比其他项目更相关的知识。
是否只显示排名靠前的项目?
如果是,整体预测或排名准确率都不是很好的匹配。确切的评级与用户无关,因为他们已经看到了非常有限的项目列表。在这种情况下,命中率和 CTR 就更合适了。
可以进行在线 A/B 测试吗?
唯一正确的答案是肯定的。A/B 测试允许我们测量 RS 的商业价值,例如 CTR 和销售额的变化。此外,我们可以从用户的可信度、流失率和新奇度方面收集反馈。
摘要
很难衡量一个推荐引擎对于一个商业问题有多好。二进制或等级感知准确性相关的度量将是通过所选 ML 方法生成一组候选项目的良好起点。不幸的是,准确性与对客户满意度至关重要的多样性或新颖性等指标并不一致。
最后,依靠最大似然度量来确定推荐系统的性能是不够的。就商业价值而言,只有用户反馈才能带来有价值的产出。这就是为什么总是要进行 A/B 测试的原因。它让我们能够衡量点击率、销售额及其衍生产品的改善情况。只有这样,商业策略和机器学习模型才会和谐地工作。
参考
祖赞娜·德国人
热衷于数据故事的高级机器学习工程师。在业务和数据科学团队之间搭建桥梁。人工智能专业应用数学硕士。在与 NLP、推荐系统和时间序列相关的任务的深度学习方面经验丰富。她的兴趣包括交互式 Tableau 仪表板开发。
阅读下一篇
ML 模型测试:4 个团队分享他们如何测试他们的模型
10 分钟阅读|作者斯蒂芬·奥拉德勒| 2022 年 3 月 1 日更新
ML Model Testing: 4 Teams Share How They Test Their Models
尽管机器学习行业在开发帮助数据团队和从业者操作他们的机器学习模型的解决方案方面取得了进展,但测试这些模型以确保它们按预期工作仍然是将它们投入生产的最具挑战性的方面之一。
大多数用于测试生产用途的 ML 模型的过程是传统软件应用程序的原生过程,而不是机器学习应用程序。当开始一个机器学习项目时,标准的做法是对业务、技术和数据集要求进行严格的记录。尽管如此,团队经常忽略稍后的测试需求,直到他们准备好部署或者完全跳过部署前的测试。
团队如何测试机器学习模型?
对于 ML 测试,你在问这样的问题:“我如何知道我的模型是否有效?”本质上,您希望确保您学习到的模型行为一致,并产生您期望的结果。
与传统的软件应用程序不同,建立测试 ML 应用程序的标准并不简单,因为测试不仅依赖于软件,还依赖于业务环境、问题领域、使用的数据集和选择的模型。
虽然大多数团队在部署模型之前都习惯于使用模型评估度量来量化模型的性能,但是这些度量通常不足以确保您的模型已经准备好投入生产。您还需要对您的模型进行彻底的测试,以确保它们在现实世界中足够健壮。
这篇文章将教你不同的团队如何对不同的场景进行测试。同时,值得注意的是,这篇文章不应该被用作模板(因为 ML 测试是与问题相关的),而应该是一个指南,指导你根据你的用例,为你的应用尝试什么类型的测试套件。
While most teams are comfortable with using the model evaluation metrics to quantify a model’s performance before deploying it, these metrics are mostly not enough to ensure your models are ready for production. You also need to perform thorough testing of your models to ensure they are robust enough for real-world encounters.
This article will teach you how various teams perform testing for different scenarios. At the same time, it’s worth noting that this article should not be used as a template (because ML testing is problem-dependent) but rather a guide to what types of test suite you might want to try out for your application based on your use case.
递归神经网络指南:RNN 的深度探索
原文:https://web.archive.org/web/https://neptune.ai/blog/recurrent-neural-network-guide
序列建模是对序列数据进行建模的任务。建模序列数据是指创建一个数学概念来理解和研究序列数据,并使用这些理解来为特定应用程序生成、预测或分类序列数据。
顺序数据有三个属性:
- 序列中的元素可以重复
- 它遵循顺序(上下文安排)
- 数据长度变化(可能是无限的)
顺序数据例子有:
- 文本和句子
- 音频(如语音和音乐)
- 电影或视频
- 时间序列数据(如股票市场数据)
- DNA 序列,蛋白质结构
- 材料成分
- 决策
序列数据因其属性而难以建模,需要不同的方法。例如,如果顺序数据通过前馈网络输入,它可能无法很好地建模,因为顺序数据具有可变长度。前馈网络对于固定大小的输入工作良好,并且没有很好地考虑结构。
另一方面,卷积神经网络是为了处理结构或数据网格(如图像)而创建的。他们可以处理长的数据序列,但是受限于他们不能正确排序序列。
那么,我们如何建立可以对序列数据建模的深度学习模型呢?对顺序数据建模并不是一件容易的事情。
例如,当对监督学习任务建模时,我们的方法是向神经网络提供一对输入(x)和输出(y)。在训练期间,模型通过逼近一个更接近原始值的值来学习将输入与输出进行映射。
和【f】θ
在每次迭代期间,该模型试图通过损失函数来校正近似输出,即,通过获取原始或基本真实值与预测值的差,并同时通过优化过程来更新模型的参数。这样,可以确保它们之间的差异减小,近似值尽可能接近原始值。
当我们处理序列数据时,我们试图对输入序列进行建模。与监督学习任务不同,在监督学习任务中,我们将输入与输出进行映射,在序列建模中,我们尝试对序列的概率进行建模。
这使得机器学习或深度学习模型能够生成令人喜欢的序列,或者能够估计序列的可能性。计算损失函数和优化的其余过程保持不变。
如何对序列建模
让我们用一个例子来理解如何对序列建模。
在下面的例子中,我们将使用英语单词(句子)序列进行建模,因为它们继承了我们前面讨论过的相同属性。
建模 p(x)
假设一个句子中的单词相互独立,我们可以使用一个语料库来告诉我们每个单词在英语中出现的概率。
一旦我们知道了每个单词的概率(从语料库中),我们就可以通过将单个单词彼此相乘来找到整个句子的概率。
例如,如果我们对句子“加密货币是下一件大事”进行建模,那么它看起来会像这样:
p(" 加密货币 ")p(" 是 ")p(" 的 ")p(" 下一个 ")p(" 大的 ")p(" 事")
上述模型可以用一个公式来描述:
每个单词都有一个时间戳:t,t-1,t-2,t-n,它描述了单个单词的位置。
但是,事实证明,上述模型并没有真正捕捉到序列的结构。为什么?
因为任何特定单词的概率都可能高于单词的其余部分。在我们的示例中,单词“**”的概率比任何其他单词都高,因此得到的序列将是“The The The The "。
*### 建模 p(x |上下文)
虽然我们仍然可以通过引入 条件概率 来修改相同的模型,但假设每个单词现在都依赖于其他每个单词,而不是独立的,我们现在可以按照以下方式对序列建模:p(x[T])= p(x[T]| x[1]…。,x [T-1] )。
同一句话“加密货币是下一个大 _ _ _ _ _ _ _ _”现在可以有一系列选项可供选择。例如:
本质上,条件概率描述的是下一个词会是什么。
但是上面的例子可以一次预测一个单词;为了预测单词序列,我们需要根据条件句计算联合概率。
举个例子,
p(x|context):
p(x3|x2,x1)
加密货币是下一个的****
p(x|context):
p(x4|x3,x2,x1)
加密货币是下一个大
p(x|context):
p(x5|x4,x3,x2,x1)
加密货币是下一个大的东西
p(x|context):
p(x6|x5,x4,x3,x2,x1)
*预测的单词以粗体书写
*the predicted words are written in bold
到目前为止,我们了解了如何使用单词语料库(包含概率值)对句子序列进行建模,然后计算句子中每个单词的联合和条件概率,我们可以从语料库中选择适当的单词,并预测句子中的下一个单词。
这种类型的方法很适合一些句子,并且很好地捕捉了数据的结构。但是当我们处理段落时,我们必须处理可伸缩性。当这种模型被引入大句时,处理能力增加,效率降低。
N-grams
为了应对可扩展性问题,NLP(自然语言处理)研究人员引入了 N 元语法 的概念,其中考虑了“N”个单词的条件和联合概率。例如,如果 n 等于 2,那么只有句子的前两个单词将用于计算联合概率,而不是整个句子。
目标
p(x |上下文)和 n=2
p(x1)
p(x2|x1)
p(x|context) and n=2:
p(x3|x2,x1)
p(x|context) and n=2:
加密货币就是下一个的****
p(x|context) and n=2:
p(x4|x3,x2)
加密货币是下一个大
p(x|context) and n=2:
p(x5|x4,x3)
加密货币是下一个大的东西
p(x|context) and n=2:
p(x6|x5,x4)
*预测的单词以粗体书写
p(x|context) and n=2:
p(x6|x5,x4)
这种方法减少了可伸缩性问题,但不是完全减少。
N 元语法的缺点是:
如果句子很长,句子的上下文就会丢失。
小规模减少可伸缩性问题
上下文矢量化
- 上下文矢量化是一种方法,其中输入序列被概括为向量,使得该向量然后被用于预测下一个单词可能是什么。
- f h
f [θ] 这样总结 h 中的上下文:
p(x [t] |x [1] ,…,x[t-1])≈p(x[t]| h)
一旦我们找到上下文向量 h ,我们就可以使用第二函数 g,它产生概率分布。
h g[θ]
上下文矢量化的优点是:
秩序得以维持
可以在可变长度的序列中操作
它可以学习微分(反向传播)
- 上下文保存在短句或序列中。
- 到目前为止,我们已经了解了什么是顺序数据以及如何对其建模。在下一节中,我们将了解 rnn 以及它们如何使用上下文矢量化来预测下一个单词。
- 什么是递归神经网络?
- 递归神经网络用于用时间步长索引 t 对序列数据建模,并结合了上下文矢量化技术。
上下文矢量化充当“存储器”,它捕获关于到目前为止已经计算的信息,并使 rnn 能够记住过去的信息,其中它们能够保存长的和可变的序列的信息。因此,RNNs 可以接受一个或多个输入向量,并产生一个或多个输出向量。
通过设计,rnn 类似于深度神经网络。它们有输入向量、权重向量、隐藏状态和输出向量。隐藏状态将序列的模式或上下文捕获到一个摘要向量中。输出不仅受应用于输入的权重(如常规神经网络)的影响,还受表示基于先前输入的上下文信息的“隐藏”状态向量的影响,使得相同的输入可以根据序列中输入的上下文产生不同的输出。
RNN 是如何工作的?
如上所述,rnn 有四个主要组成部分:
投入
隐藏状态
重量或参数
- 输出
- 为了更好地理解 RNN,我们需要看看多层感知器如何处理序列数据。
- 多层感知器
- 在多层感知器(MLP) 中,我们有一个输入层、一个隐藏层和一个输出层。输入层接收输入,通过应用激活的隐藏层传递输入,然后返回输出。
当存在多个隐藏层时,激活被应用到第一个隐藏层的每个节点,然后被发送到下一个隐藏层,依此类推,直到它到达最后一个层以产生输出。每个隐藏层都有自己的权重和偏差,使它们相互独立。
但是这两者之间的关系是无法建立的,除非我们把这些隐藏的层结合在一起,因为我们处理的是序列。如果隐藏层相互独立,那么结构和顺序将会丢失。因此,为了将这些隐藏层组合在一起,我们应该为每个隐藏层设置相同的权重和偏差。
为了实现输入和输出之间的这种连续和结构化的关系,我们需要将输入句子一个字一个字地输入到序列中的所有隐藏层,同时将前一个神经元的输出输入到下一个神经元。
这种方法使整个过程结构化和有关联。
这是递归神经网络的开端,其中先前的输入与当前的输入相结合,从而保持当前输入(x2)与先前输入(x1)的某种关系。
本质上,rnn 是 MLP 的一个修改版本,其中数据被输入到每个隐藏层。
递归神经网络
在 RNNs 中,x(t)在时间步长 t 时作为网络的输入。RNN 中的时间步长 t 表示单词在句子或序列中出现的顺序。隐藏状态 h(t)表示在时间 t 的上下文向量,并且充当网络的存储器。基于当前输入和前一时间步的隐藏状态计算上下文向量 h(t)。
例如,以句子“加密货币是下一件大事”为例。在时间 T1“加密货币”将被馈送到网络中,在时间 t2“是”被馈送到网络中,在时间 t3“是”被馈送到网络中,等等。
我们用这个公式来表示隐藏状态:
h[t]= tanh(W[h]h[t-1]+W[x]x[t])
当 t = 1 时,
h[1]= tanh(W[h]h[0]+W[x]x[1]),其中 x [1] 为“加密货币”,h0 初始化为零
当 t = 2 时,
h[2]= tanh(W[h]h[1]+W[x]x[2]),其中 x [1] 为‘是’。
当 t = 3 时,
h[3]= tanh(W[h]h[2]+W[x]x[3]),其中 x [2] 为‘the’。
隐藏状态和输入的权重参数都是可学习的,这意味着在训练期间,它将使用反向传播来更新自身。
如果你注意到上面的公式,你会发现参数={Wh,Wx,Wy}在每个输入中都保持不变。这被称为参数共享。参数共享使 RNNs 能够构建和保留上下文信息,即使句子的长度是可变的。当我们想要对一个数据经常重复出现的序列建模时,这种共享是很重要的。rnn 在几个时间步长上共享相同的权重。
rnn 预测来自最后一个隐藏状态的输出以及输出参数 Wy。预测更像是一项分类任务,其中使用了一个 softmax 函数来确保英语句子中所有可能单词的概率。
培训注册护士
计算梯度:通过时间反向传播
到目前为止,我们已经了解了前馈在 RNNs 中的工作原理,即输入进入网络并向前移动,同时在每个时间步长内共享相同的参数。在反向传播过程中,它必须返回时间步长以更新参数。
那么它是如何发生的呢?
如前所述,预测 RNN 的产量是一项分类任务,因此我们使用交叉熵来计算损失。
L [θ] (y,y’)[t]=-y[t]logy[t]’
其中 θ={W [h] ,W [x] ,W [y] }
我们知道参数是可共享的,正是 RNNs 的这种能力使网络变得不同;很难区分。为了解决这个问题,网络需要扩展,或者说展开,这样参数就可以根据时间步长在整个网络中进行区分——这就是术语“时间反向传播”(BPTT)。
从上图中,你可以看到一个展开的循环网络是什么样子。
由于神经网络一次只处理一个单词,因此损失是基于每个单词计算的。整个过程如下所示:
你可以看到公式是如何展开的。
对于 Wy 的区分,程序应该如下所示:
所以,让我们总结一下反向传播:
使用当前输出计算损耗,使用交叉熵损耗计算实际输出
网络是展开的或扩展的,因此反向传播可以通过隐藏层和时间发生
为递归神经元(即隐藏状态)和密集层更新权重参数
- 渐变的问题
- 在顺序数据的反向传播期间出现的两个常见问题是消失和爆炸梯度。
- 消失渐变
当微分向量以指数方式快速变为零时,这反过来使网络难以学习一些长周期相关性,问题是消失梯度。
回到 RNNs 中的反向传播,我们看到网络中的每一个神经元都参与了关于成本函数的输出计算。正因为如此,我们必须确保每个神经元的参数都得到更新,以最小化误差,并且这可以及时返回到所有神经元。所以,你必须通过时间一路传播回这些神经元。
我们还知道,上下文向量,或隐藏状态 参数,在整个网络中共享,以保持顺序和连续性。在初始化期间,参数被赋予一个接近于零的随机数,当隐藏状态在时间上向前移动时
在不同的时间步长上相乘,使得梯度 Wh 越来越小,基本上为零,直到消失。
梯度越低,网络越难更新权重,如果梯度为零,则权重不会更新。
爆炸渐变
当由于不稳定的过程而累积大的梯度时,会发生爆炸梯度,并导致参数的非常大的更新。
在 RNNs 中,爆炸梯度可能发生在反向传播期间,并导致非常大的梯度,实质上对网络参数进行大的更新。在极端情况下,权重值可能会变得很大,以至于变成 NaN 值。
克服梯度问题
rnn 中的梯度问题可以通过以下方法解决:
渐变剪辑
门控网络
渐变剪辑
- 渐变裁剪是一种用于避免渐变爆炸的技术。假设 rnn 以近似线性方式运行是合理的,这使得梯度不稳定。
- 为了控制渐变,它被修剪或整形为较小的值。裁剪渐变有两种方法:
就在参数更新之前,从小批量中裁剪渐变
使用测量范数||g||的超参数 C,其中 g 是梯度。如果||g|| > C 那么 gg。C/||g||
^(阅读) 了解渐变裁剪(以及如何修复爆炸渐变问题)
- 门控网络
- 为了解决渐变消失的问题,您可以使用具有门控机制的新架构。像长短期记忆和门控循环网络这样的结构已经被证明可以解决消失梯度。我们将在下一节深入探讨它们。
RNN 摘要(至今):
序列的顺序被保留
能够映射:
将变量序列输入到固定大小的向量中
- 将固定大小的向量序列输入到序列中
- 输入序列转换为相同长度的输出序列。
- 它是差分的(所以它可以学习)
- 由于梯度问题,当处理长序列时,序列的上下文丢失
- RNN 的类型
- 到目前为止,我们已经了解了:
- 序列建模
这是什么?
我们如何对序列建模?
- 上下文矢量化
- 递归神经网络
- 它们是什么?
- 它们是如何工作的?
- 穿越时间的反向传播
- 教师强迫
- 训练时的 RNNs 问题
- 克服梯度问题
- 现在,我们将继续讨论不同类型的 rnn,同时阐明普通 rnn 的局限性。我们将讨论五种类型的 RNN:
- 双向 RNN
- 编码器-解码器序列到序列架构
LSTM
- 苏军总参谋部情报总局
- 卷积递归神经网络
- 双向 RNN
- 在序列建模中,到目前为止,我们假设我们的目标是给定一个特定的句子序列,对下一个输出进行建模。在 NLP 任务中,可能会出现上下文依赖于未来句子的情况。
- 例如:
我是 __。
我饿了。
我饿了,我能吃掉整个馅饼。
- 在上面的例子中,答案可以分别是‘饿’,‘不’,‘非常’。但是为了理解上下文,特别是当整体上下文依赖于未来单词时,我们需要设计一个将未来单词考虑在内的模型。
- RNNs 的一个缺点是它们及时考虑了过去和现在的单词,而不是未来的单词。这使得 RNNs 成为一个单向顺序网络,其中信息单向流动,通常是正向流动。
- 为了解决这个问题,我们必须引入一种机制,在这种机制中:
序列的信息反向传播
神经网络考虑了过去、现在和未来这三个时间步,并在此基础上预测输出。
双向 RNN 是解决这个问题的一种网络。这是一种将两个独立的 rnn 放在一起的架构。一个以传统方式工作,即向前工作,另一个向后工作。
- 从上图可以看出,两个网络在每个时间步都根据过去-现在(正向 RNNs)信息和未来-现在(反向 RNNs)信息输出各自的输出。
- 编码器-解码器序列到序列架构
在顺序建模中使用 RNNs 的优势在于它可以:
将输入序列映射到固定大小的向量
将固定大小向量映射到序列
将输入序列映射到相同长度的输出序列。
- 但是假设我们想训练一个 RNN 来映射一个输入序列到一个输出序列,不一定是相同的长度。特别是当我们想把一种语言翻译成另一种语言时,这种情况就会出现。
- 编码器-解码器序列到序列是一种处理这类问题的架构。顾名思义,它有两种类型的架构:编码器和解码器。
- 编码器 RNN 接收可变长度的输入序列,并对其进行处理以返回一个向量或向量序列,称为“上下文”向量 C 。
解码器 RNN 以固定长度的向量为条件来产生输出序列。同样,编码器的最后隐藏状态是解码器的初始隐藏状态。
长短期记忆(LSTM)
建立长短期记忆是为了保存 RNN 缺乏的序列的长期上下文信息。
LSTM 的核心思想是确保梯度长时间流动,不会消失或爆炸。
正如我们前面看到的,RNNs 有一个标准的体系结构,其中隐藏状态形成了某种循环机制来保存和共享每个时间步长的信息。嗯,LSTM 也有一个循环机制。不是只有一个神经网络层,而是有四个神经网络,以某种方式相互作用,以保存和共享长的上下文信息。
让我们一步步了解 LSTM 网络的工作原理:
细胞状态:长时记忆通常称为细胞状态,用 Ct-1 表示,自然界中有递归。小区状态允许以前的信息存储在 LSTM 网络中。它由内部门调制,即:遗忘门和输入门。
遗忘门:单元格状态与遗忘门相连,遗忘门指示哪些信息要保留,哪些信息要遗忘。它通过一个 sigmoid 函数来实现这一点。它查看 ht-1 和 xt 的初始状态,并为每个单元状态 Ct-1 输出一个介于 0 和 1 之间的数字。如果遗忘门返回的信息为 1,则存储该信息,如果返回 0,则删除该信息。
输入门:输入门从相同的初始状态 ht-1 取相同的输入 XT,并通过两个非线性激活函数:sigmoid(返回 0 和 1 之间的值)和 tanh(返回-1 和 1 之间的值),分别是输入门it 和候选存储器C`****t。这有助于单元状态保存新信息,同时将单元状态从 Ct-1 更新为 Ct。输入门的想法是在单元状态中存储新的信息,以及从遗忘门删除的记忆。
-
输出门:输出将基于单元状态 Ct、初始隐藏状态 ht-1 和输入 xt。隐藏状态和输入将通过一个 sigmoid 传递,因此值在 0 和 1 之间。同时,我们通过 tanh 传递单元状态 CT 以获得 1 和-1 之间的值,并将其乘以 sigmoid 门的输出,以便我们只输出与上下文相关的内容。
-
总而言之:
-
第一个 sigmoid 激活功能是遗忘门,它确保应该从先前的单元状态(Ct-1)中遗忘什么信息。
-
第二个 sigmoid 和第一个 tanh 激活函数用于输入门,确保什么信息应该与先前修剪的信息一起保存到单元状态。
最后一个 sigmoid 是单元的输出门和 tanh,它突出显示哪些信息应该进入下一个隐藏状态。
- 门控循环单元(GRU)
- GRU 是新一代的递归神经网络,它是 LSTM 的修改版,但复杂度更低。gru 使用隐藏状态而不是单元状态来传递信息。它也只有两个门,一个复位门和更新门。
- 更新门:更新门选择需要添加和/或忽略的信息。它类似于 LSTM 输入门。
重置门:重置门用于决定忘记多少过去的信息。
由于 gru 的运行规模较小,因此比 LSTM 网络更快。LSTMs 和 gru 成功的原因是因为它们的门控机制:
保留上下文信息和长期序列。
避免梯度问题。
选通函数允许网络调整梯度消失的程度,因为它被复制了四次,所以在每个时间步长取不同的值。它们采用的值是当前输入和隐藏状态的学习函数。
- 卷积递归神经网络
- 卷积递归神经网络是两种神经网络的组合:卷积神经网络和递归神经网络。两者都有自己独特的属性,这有助于他们在工作中脱颖而出。
由于类似网格的操作,CNN 非常善于从任何给定的数据中提取特征和表示。另一方面,rnn 非常适合顺序数据建模,这反过来又保留了顺序、结构和上下文。
CRNN 架构通常用于产生更好/最佳的音频信号处理结果。由于像音乐这样的音频信号非常复杂(大量噪声聚集在一起),提取低维模式和表示变得相当困难。为什么我们需要低维模式?
因为高维模式不能提供对数据结构的更好理解。使用 CNN,我们可以更深入地挖掘高维序列结构,这样它就给我们低维表示,然后可以馈入 RNN,甚至 LSTM,这可以用来生成/预测另一个序列。
CRNN 也用于图像序列应用示例图像字幕,也可用于从句子生成图像,也称为序列到图像。
RNN 在 Keras / Tensorflow 和 Python 中的实现
让我们看看如何用 keras 为字符文本预测实现 RNN。
我们将使用两个库:numpy 和 tensorflow-keras。
你可以在这里下载数据集。
数据预处理
数据预处理是必要的,因为数据包含 ASCII 字符,这可能会干扰我们的建模过程并给出不正确的结果。
import numpy as np
from tensorflow.keras.layers.recurrent import SimpleRNN
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Activation
清理完数据后,我们可以创建一个查找表。查找表基本上从数据中创建唯一字符的表。该表将把文本中的字符转换成数字,然后将数字输入到 RNNs 中。
INPUT_FILE = "data/wonderland.txt"
现在,我们将创建输入和标签。重要的是要理解,在序列建模中,输入将从索引 0 开始,而标签将从索引 1 开始。
例如,如果我们输入“加密货币是下一件大事”,那么:
print("Extracting text from input")
file = open(INPUT_FILE, 'rb')
lines = []
for line in file:
line = line.strip().lower()
line = line.decode("ascii", "ignore")
if len(line) == 0:
continue
lines.append(line)
file.close()
text = " ".join(lines)
After the data is cleaned, we can create a look-up table. The look-up table basically creates a table of unique characters from the data. This table will convert the characters in the text to numbers, which will then be fed into the RNNs.
chars = set([c for c in text])
nb_chars = len(chars)
char2index = dict((c, i) for i, c in enumerate(chars))
index2char = dict((i, c) for i, c in enumerate(chars))
print(index2char)
{0: '!',
1: 's',
2: '7',
3: 'p',
4: 'x',
5: '.',
6: ']',
7: '3',
8: 'a',
9: 'z',
10: '9',
11: '5',
12: '6',
13: 'h',
14: ',',
15: 'c',
16: 'r',
17: '@',
18: 'k',
19: 'w',
20: 'd',
21: '(',
22: 'o',
23: 'f',.....}
Now, we’ll create inputs and labels. It’s important to understand that in sequence modeling, the input will start from index 0, where the label will start from index 1.
- 值得一提的是,这是一个角色级别的 RNN,所以你将与角色一起工作,而不是文字
一次热编码
将序列转换为一位热编码向量。
模拟 RNN
定义模型:
print("Creating input and label")
SEQ_LEN = 10
STEP = 1
print("The table is ready")
input_chars = []
label_chars = []
for i in range(0, len(text) - SEQ_LEN, STEP):
input_chars.append(text[i:i + SEQ_LEN])
label_chars.append(text[i + SEQ_LEN])
print(input_chars)
['project gu',
'roject gut',
'oject gute',
'ject guten',
'ect gutenb',
'ct gutenbe',
't gutenber',
' gutenberg',
'gutenbergs',...]
RNN 将包含 128 个隐藏的州
永远记住,密集层应该等于文本中唯一字符的数量
print("Vectorizing input and label text...")
X = np.zeros((len(input_chars), SEQ_LEN, nb_chars), dtype=np.bool)
y = np.zeros((len(input_chars), nb_chars), dtype=np.bool)
for i, input_char in enumerate(input_chars):
for j, ch in enumerate(input_char):
X[i, j, char2index[ch]] = 1
y[i, char2index[label_chars[i]]] = 1
训练模型
结论
- 在本文中,我们讨论了:
- 如何有效地模拟序列以捕捉结构和上下文。
HIDDEN_SIZE = 128
BATCH_SIZE = 128
NUM_ITERATIONS = 25
NUM_EPOCHS_PER_ITERATION = 1
NUM_PREDS_PER_EPOCH = 100
model = Sequential()
model.add(SimpleRNN(HIDDEN_SIZE, return_sequences=False,
input_shape=(SEQ_LEN, nb_chars),
unroll=True))
model.add(Dense(nb_chars))
model.add(Activation("softmax"))
model.compile(loss="categorical_crossentropy", optimizer="rmsprop")
上下文向量如何提供一种有效的方法来概括一个序列
for iteration in range(NUM_ITERATIONS):
print("=" * 50)
print("Iteration #: %d" % (iteration))
model.fit(X, y, batch_size=BATCH_SIZE, epochs=NUM_EPOCHS_PER_ITERATION)
test_idx = np.random.randint(len(input_chars))
test_chars = input_chars[test_idx]
print("Generating from seed: %s" % (test_chars))
print(test_chars, end="")
for i in range(NUM_PREDS_PER_EPOCH):
Xtest = np.zeros((1, SEQ_LEN, nb_chars))
for i, ch in enumerate(test_chars):
Xtest[0, i, char2index[ch]] = 1
pred = model.predict(Xtest, verbose=0)[0]
ypred = index2char[np.argmax(pred)]
print(ypred, end="")
test_chars = test_chars[1:] + ypred
print()
如何将多层感知器转换为 RNN,方法是在给定的时间步长将输入直接顺序输入隐藏层。
参数共享如何将一个独立的神经网络转化为一个连续的神经网络,该神经网络可以被微分并保持序列的完整性。
- 梯度的问题以及如何纠正。
- 不同类型的无线网络:
- 双向 RNNs:它考虑了基于上下文的学习的未来顺序。
- 编码器-解码器 RNNs:它使用两种架构来将输入序列映射到可变长度的输出序列,这是普通的 RNN 无法做到的。
- LSTMs:它通过引入门控机制纠正了消失梯度的问题,并且还保留了长期依赖性或长期上下文。
- GRU:和 LSTM 一样,但建筑更简单。
- CRNN:使用 CNN 和 RNN 的组合架构,更好地将高维特征提取为低维特征,并分别对提取的低维进行序列建模。
- 内容很多,所以如果你能坚持到最后——感谢你的阅读!我希望这个指南是有帮助的。
- 资源:
- 尼尔什·巴拉
- 我是最近一家初创公司 perceptronai.net 的创始人,该公司旨在通过我们的深度学习算法提供医疗和材料科学方面的解决方案。我也阅读和思考了很多。有时我把它们以绘画或音乐的形式表现出来。当我需要喘口气时,我会去跑步。
阅读下一篇
如何组织深度学习项目——最佳实践范例
13 分钟阅读|作者 Nilesh Barla |年 5 月 31 日更新
I am the founder of a recent startup perceptronai.net which aims to provide solutions in medical and material science through our deep learning algorithms. I also read and think a lot. And sometimes I put them in a form of a painting or a piece of music. And when I need to catch a breath I go for a run.
一个成功的深度学习项目,你需要很多迭代,很多时间,很多努力。为了让这个过程不那么痛苦,你应该尽量利用你的资源。
一个好的循序渐进的工作流程将帮助你做到这一点。有了它,你的项目变得高效、可复制、和可理解。
在本文中,您将看到如何构建深度学习项目的工作——从开始到部署,监控部署的模型,以及中间的一切。
在这个过程中,我们将使用 Neptune 来运行、监控和分析您的实验。Neptune 是提高 ML 项目生产率的一个很酷的工具。
在本文中,您将了解到:
关于项目的生命周期。
定义项目目标的重要性。
根据项目需求收集数据。
模型训练和结果探索,包括:
- 为更好的结果建立基线。
- 采用现有的开源最新模型研究论文和代码库中的技术和方法。
- 实验跟踪和管理
- 避免欠拟合和过拟合的模型优化技术,例如:
- 控制超参数
- 规范化
- 修剪
- 在部署之前测试和评估您的项目。
- 模型部署
- 项目维护
- Pruning
- Testing and evaluating your project before deployment.
- Model deployment
- Project maintenance
满怀期望地减少管道债务
原文:https://web.archive.org/web/https://neptune.ai/blog/reducing-pipeline-debt-great-expectations
你是一家产品公司数据科学团队的一员。你的团队有很多机器学习模型。他们的输出指导着关键的业务决策,以及一些显示重要 KPI 的仪表板,这些 KPI 由您的主管日夜密切关注。
在那致命的一天,你刚刚为自己泡了一杯咖啡,正要开始一天的工作,这时宇宙塌了。公司的每个人都疯了。业务指标仪表板显示的似乎是随机数字(除了每隔一个小时,KPI 在短时间内看起来没问题),模型预测该公司即将破产。更糟糕的是,每一次解决这种疯狂的尝试都导致您的数据工程和研究团队报告新的不完善的服务和模型。
那天是讨债日,未付的债务是最糟糕的一种:管道债务。是怎么积累起来的?让我们回到几个月前。
什么是管道债务?
你正要开始一个新的令人兴奋的机器学习项目。您已经找到了分散在公司数据库、功能商店和电子表格中的一些有用数据。为了使数据可用,您构建了一个数据管道:一组接收、处理、清理和组合所有这些数据的作业和 Python 函数。最后,您的管道将数据输入到机器学习模型中。我们可以把整个过程示意性地描述如下。
Simple data pipelines are manageable | Source: Author
你的数据管道工作得很好:它不断用数据填充下游的机器学习模型,模型将这些数据转化为准确的预测。然而,在云中作为服务部署的模型不太可行。为了使它更有用,您构建了一组仪表板,用于向业务涉众呈现模型的输出以及重要的 KPI,从而深化了您的管道。
Existing pipelines are likely to be extended | Source: Author
一天,你在午餐时和研究团队的一位同事谈论你的项目。他们非常兴奋,并决定对他们的数据做一些类似的事情,使公司的数据管道更宽,跨团队边界。
The more pipelines there are, the more complex the system gets | Source: Author
几周后,你们俩又聊了起来。当你们了解了研究团队的工作时,你们都注意到如果你们的两个团队使用彼此的数据为各自的模型和分析提供支持,这将是多么有用和有价值。在实现这个想法时,公司的数据管道是这样的。
If many pipelines exist, they will inevitably blend | Source: Author
上面的图片应该已经敲响了警钟——它们显示的是管道债务的积累。
Pi peline 债务是数据管道中的技术债务。当您的数据管道为三 U 型时,就会出现这种情况:
- 1 无证
- 2 未经测试
- 3 不稳定
它有多种口味,但都有一些共同的特点。这个系统是纠缠不清的,这意味着一个地方的变化可能会破坏其他地方的不同进程。这使得代码重构和调试异常困难。
对于软件工程师来说,这听起来像是一个已经解决的问题,这个解决方案叫做自动化测试。然而,测试软件在两个主要方面与测试数据非常不同:
- 首先,虽然你可以完全控制你的代码,并且可以在它不工作的时候修改它,但是你不能总是修改你的数据;在许多情况下,你仅仅是一个观察者,看着一些真实世界的过程产生的数据。
- 第二,软件代码总是有对有错:要么它做了它被设计去做的事情,要么它没有。数据从来没有对错。它只能适合或不适合某个特定的目的。这就是为什么当涉及到数据时,自动化测试需要一种特殊的方法。
自动化测试:拯救的期望
为数据管道量身定制的自动化测试是 Great Expectations 的前提,Great Expectations 是一个广泛使用的用于数据验证的开源 Python 包。
Always know what to expect from your data | Source: Author
由超导公司开发并于 2018 年首次发布的《远大前程》的口号是“永远知道从你的数据中可以期待什么”,这正是它所提供的。
这个包是围绕期望的概念构建的。期望可以被认为是对数据的单元测试。它是一个声明性语句,描述数据集的属性,并以简单、人类可读的语言进行描述。
例如,要断言某个表中“num_complaints”列的值在 1 到 5 之间,您可以编写:
expect_column_values_to_be_between(
column="num_complaints",
min_value=1,
max_value=5,
)
该语句将验证您的数据,并返回成功或失败的结果。
正如我们已经提到的,你并不总是控制你的数据,而是被动地观察它的流动。通常情况下,一个非典型的值会不时地出现在您的数据中,但不一定是令人苦恼的原因。伟大的期望通过“mostly”关键字来适应这一点,该关键字允许描述期望应该多久匹配一次。
expect_column_values_to_be_between(
column="num_complaints",
min_value=1,
max_value=5,
mostly=0.95,
)
如果至少 95%的“num_complaints”值在 1 到 5 之间,上述语句将返回成功。
为了更好地理解数据,关键是要有一些关于为什么我们期望从数据中得到某些属性的背景。我们可以简单地添加它,方法是将“meta”参数传递给带有任何相关信息的期望。我们的同事甚至我们未来的自己都会为此感谢我们。
expect_column_values_to_be_between(
column="num_complaints",
min_value=1,
max_value=5,
mostly=0.95,
meta={
“created_by”: “Michal”,
“craeted_on”: “28.03.2022”,
“notes”: “number of client complaints; more than 5 is unusual”
“and likely means something broke”,
}
)
这些元数据注释也将构成数据文档的基础,这些数据文档是远大前程可以凭空产生的,但稍后会有更多内容!
该包包含几十个现成可用的预期,它们都有冗长的、人类可读的名称,如“expect _ column _ distinct _ values _ to _ be _ in _ set”、“expect _ column _ sum _ to _ be _ between”或“expect _ column _ KL _ divergence _ to _ be _ less _ than”。这种语法允许人们清楚地陈述对数据的期望以及原因。
有些期望适用于列值,有些则适用于它们的集合函数或整个密度分布。当然,该软件包还可以轻松地为何时需要定制的解决方案创建定制的期望。
《远大前程》有很多不同的后台。您可以在 Pandas 数据框架上本地评估您的期望,就像在 SQL 数据库(通过 SQLAlchemy)或 Apache Spark 集群上一样容易。
那么,这些预期如何有助于减少管道债务呢?这个问题的答案是多方面的。
- 首先,制定预期的过程迫使我们坐下来思考我们的数据:它的性质,来源,以及它可能出错的地方。这有助于加深理解,并改善团队内部与数据相关的沟通。
- 第二,通过清楚地陈述我们对数据的预期,我们可以及早发现任何异常情况,如系统中断。
- 第三,通过对照一组预先存在的预期来验证新数据,我们可以确保我们不会给我们的机器学习模型输入垃圾。
- 4 接下来,定义期望使我们非常接近拥有维护良好的数据文档。这个清单还在继续。
我们将很快讨论了解一个人的期望的所有上述好处,但首先,让我们设置 GE 包!
满怀期望地开始
在本文的剩余部分,我们将介绍 GE 最有用的特性,以及这个包的几个巧妙的用例。为了保持实用性,这些例子使用了真实的数据集,所以在我们深入研究 Great Expectations 功能之前,让我们花一点时间来讨论问题设置和数据集,以及如何在您的机器上安装和设置 GE。
问题设置
我们将查看芝加哥市的出租车出行数据集。这些数据包含向市政当局报告的每次出租车行程的信息,例如行程的开始和结束时间、出租车 ID、行程的距离、费用、上下车地点等等。原始数据非常庞大(从 2013 年到现在每月更新一次),因此为了演示的目的,我们将它限制在两天内:2022 年 2 月 27 日和 2 月 28 日。这相当于 13,000 多次旅行。
我们将把 2 月 27 日的数据视为我们公司的现有数据,我们将自动对其进行分析,以制作预期套件。然后,我们会将 2 月 28 日的数据视为新的传入数据,我们将根据我们的预期对其进行验证,以确保那里没有任何古怪的事情发生,并且我们可以安全地将这些新数据添加到我们公司的数据库中,并利用它们来训练机器学习模型,例如。
树立远大的期望
让我们从安装包开始。远大前程需要 Python 3,可以用 pip 安装。
pip install great_expectations
上面的命令不仅安装了 Python 包本身,还安装了附带的 CLI(命令行界面),它提供了从终端可用的便利实用程序。我们现在将使用其中的一个命令 init 来建立远大前程项目。
great_expectations init
运行此命令后,您应该会在终端窗口中看到以下提示:
键入 enter 继续,一个名为“great_expectations”的目录将出现在您的项目目录中,其中包含上面截图中显示的所有内容。
所有这些都被包的作者称为数据上下文。数据上下文包含了 Great Expectations 为您的项目提供服务所需的所有文件。它包含各种配置和元数据,并提供对数据源、期望和其他 GE 对象的访问。不需要太担心;现在,我们可以相信设置向导已经正确初始化了数据上下文,然后继续连接一些数据。
连接数据
要将新的数据源连接到我们的数据上下文,我们只需在终端中运行以下命令。
great_expectations datasource new
这将生成三个提示。首先,系统会询问我们是想连接到文件系统还是数据库。由于我们在本地将出租车出行数据保存为 CSV 文件,因此我们选择前者。第二个问题是关于我们希望使用的处理引擎:pandas 还是 spark。我们喜欢熊猫。最后,我们需要输入数据文件的路径。
提供所有必要的输入导致 Jupyter 笔记本被打开。名为“datasource_new”的笔记本提供了一些用于配置数据源的样板 Python 代码。默认设置很好,所以我们不需要改变任何东西,也许除了第二个代码单元中的数据源名称。我把我的旅行叫做“旅行”。
更改名称后,我们需要运行所有的笔记本单元,这将有效地创建我们的数据源。最后一个单元格的打印输出应该确认我们的“trips”数据源存在。现在,随着数据源的创建,我们可以安全地关闭和删除笔记本了。
随着软件包的设置和数据的连接,我们可以深入了解远大前程的关键特性!
《远大前程》的主要特点
远大前程提供了三个非常有用的特性:
- 1 自动化数据分析,根据手头的数据创建期望套件。
- 2 自动生成数据文档。
- 最后,对新数据进行验证,以防止令人讨厌的新数据进入我们的数据库和机器学习模型。
让我们一个一个地看。
自动化数据分析
期望从何而来?您可以根据您对数据和任何相关领域知识的熟悉程度,逐个手动起草它们。然而,更常用的方法是让 GE 通过分析现有数据来自动创建它们。这是产生一套基本期望的快速方法,我们可以在以后扩展和建立这些期望。
自动分析器考虑数据的几个基本属性:列的类型、聚合统计信息(如最小值、最大值或平均值)、非重复值计数和缺失值的数量等等。
为了运行自动化概要分析,我们需要导航到终端中数据上下文所在的目录,并运行以下命令。
great_expectations suite new
系统会弹出提示,要求我们选择期望的创建方式。我们选择最后一个选项,自动分析器。
通用电气然后询问要分析哪些数据。它在我们的数据上下文中检测到可用的 CSV 文件。如前所述,我们选择 2 月 27 日的数据进行分析。
接下来,我们又得到了两个提示。首先,我们需要键入期望套件的名称,然后确认到目前为止所做的所有选择。正如你可能已经猜到的,这将打开一个充满样板代码的 jupyter 笔记本,允许我们定制我们的期望。
在笔记本的第二个代码单元中,我们可以看到一个名为“ignored_columns”的变量,它被定义为数据中所有列的列表。这里我们需要做的是注释掉我们真正想要分析的列。让我们评论一下行程时间,距离和费用。
然后,我们只需要运行整个笔记本来创建期望套件。我们的期望套件已经作为一个 JSON 文件保存在我们的数据上下文中的期望目录中。虽然我们可以浏览这个可读性很强的 JSON 文件,但是查看数据文档要方便得多,因为数据文档应该在我们运行笔记本时就已经在浏览器中打开了。这就给我们带来了《远大前程》的第二大特点。
数据文档
这个包自动将一个 expect suite 呈现到一个 HTML 页面中,这个页面可以作为数据文档:一个关于有什么数据以及数据应该是什么样子的真实来源。
Screenshot from Data Docs | Source: Author
数据文档以数据的汇总统计数据和基于它们创建的期望为特色。左侧 Action 面板中的黄色按钮指导我们编辑预期,以便我们可以修复可能错误生成的预期或添加全新的预期。随意点击,探索这个仙境!一旦你回来,我们将继续新数据的验证。
新数据的验证
为了防止管道债务累积,渴望进入你的数据库、分析和模型的每一部分新数据都应该得到验证。这意味着我们希望确保新数据满足我们基于现有数据和/或领域知识产生的所有期望。为了用 GE 做到这一点,我们需要建立一个用软件包的行话来说叫做检查点的东西。
一个检查点针对一批数据运行一个期望套件。我们可以通过将“checkpoint new”关键字传递给 great_expectations,后跟所选的检查点名称来实例化它。在这里,我将我的称为“2 月 28 日检查点”。
great_expectations checkpoint new feb_28_checkpoint
这将打开另一个配置笔记本。对我们来说唯一重要的单元格是定义“yaml_config”变量的第二个代码单元格。在那里,我们可以选择应该验证哪个数据集(“data_asset_name”)以及应该评估哪个期望套件(“expectation_suite_name”)。这一次,我们可以保留所有的默认值——GE 推断,因为我们只有两个数据文件,其中一个用于概要分析,所以我们可能希望验证另一个。
为了运行我们的检查点,也就是评估我们对新数据的期望,我们只需要取消笔记本最后“运行您的检查点”部分的最后两行代码的注释,然后运行它。这将再次打开数据文档,这次向我们显示验证结果。
对于我们的出租车出行数据,许多期望都落空了。其中一些失败是可以预料到的:例如,基于 2 月 27 日的数据,我们已经创建了一个预期,表明中值票价应该大于或等于 21 英镑,而对于 2 月 28 日的数据,中值票价是 15 英镑。看到不同日子的中间价格不同并不奇怪。
Some expectations have failed | Source: Author
这个例子强调了仔细分析和起草期望套件的重要性。自动化分析器生成的值应该被视为一个起点,而不是一个现成的套件。
手动处理期望值
在前面的章节中,我们借助 Jupyter 笔记本使用了 CLI。但是,可以手动创建和编辑预期。
如前所述,expectation suite 仅仅是一个 JSON 文件,包含我们在本文开头看到的格式的期望,例如:
{
"expectation_type": "expect_column_values_to_not_be_null",
"kwargs": {
"column": "Trip Seconds",
"mostly": 0.99
},
"meta": {}
},
我们可以使用任何文本编辑器来修改这些期望或添加新的期望。这种与 GE 交互的方式非常方便,尤其是当您有一个大型的期望套件或其中的几个时。
远大期望的用例
在前面的章节中,我们已经经历了一个非常标准的建立数据验证过程的工作流程。让我们稍后再来看看:
- 1 我们使用自动化数据分析器根据现有数据创建预期套件。
- 我们仔细分析预期,根据需要修正和添加更多内容(我们在本教程中并没有真的这样做,因为这是一个非常数据和领域特定的过程,但它是实践中至关重要的一步!).在这一步,我们可能会在数据中发现一些有趣或危险的属性。现在是澄清这些问题的时候了。
- 我们根据我们的期望套件运行每一批新的输入数据,只有当它通过验证时,才允许它进一步进入我们的数据管道。如果失败了,我们会试着去理解为什么以及是否是新的数据出现了偏差,或者可能是我们的预期没有适应某些极端情况。
现在我们知道了如何带着巨大的期望来验证数据,让我们来讨论几个具体的用例,在这些用例中,在 GE 上投入时间会得到很大的回报。
检测数据漂移
部署在生产中的机器学习模型的一个臭名昭著的危险是数据漂移。数据漂移是指模型输入的分布发生变化的情况。发生这种情况有多种原因:数据收集设备容易损坏或需要更新软件,这会影响数据的记录方式。如果数据是由人类产生的,那么随着时尚和人口统计的快速发展,数据会更加不稳定。
数据漂移构成了机器学习模型的严重问题。它可以使算法学习到的决策边界对于新状态数据无效,这对模型的性能有不利影响。
输入数据验证。
在数据漂移可能令人担忧的情况下,只需对模型输入要素建立预期,以验证其长期趋势、平均值或历史范围和波动性。一旦世界发生变化,你的输入数据开始变得不一样,通用电气将会通过抛出一系列失败的测试来提醒你!
防止异常值扭曲模型输出
对部署在生产中的模型的另一个威胁,与数据漂移有点类似,是离群值。当一个模型得到一个不寻常的值作为输入,通常很高或很低,那么它的输出会发生什么?如果模型在训练期间没有看到这样的极值,诚实的回答应该是:我不知道预测应该是什么!
不幸的是,机器学习模型没有这么诚实。恰恰相反:模型可能会产生一些非常不可靠的输出,没有任何警告。
幸运的是,一个人可以很容易地通过适当的期望套件来防止它!只需根据模型在训练中看到的内容为模型的输入要素设置允许的范围,以确保您不会根据异常值进行预测。
防止管道故障蔓延
数据管道有时确实会失败。你可能错过了一个关键案例。或者您的服务器机房可能暂时断电了。不管是什么原因,一个期待新文件出现在某个地方的数据处理作业突然发现什么也没有。
如果这会导致代码失败,那也不一定是坏事。但通常不会:作业成功了,并高兴地向下游系统宣布您的网站在前一天的访问量为 0。这些数据点随后显示在 KPI 仪表盘上,甚至更糟的是,被输入到自动重新训练的模型中。如何防止这种情况发生?
当然是带着期望。简单地期望最近的数据——例如,带有足够新的时间戳——在那里。
检测有害的偏见
机器学习模型中的偏见是一个最近越来越受到关注和兴趣的话题。考虑到这些模型对人们生活的深远影响,这一点至关重要。公开的问题是如何检测和防止这些偏见做魅力。
虽然它们不能提供最终的答案,但远大的期望至少可以帮助我们发现危险的偏见。机器学习中的公平是一个庞大而复杂的话题,所以让我们专注于大图的两个小部分:进入模型的训练数据,以及它对不同测试输入产生的预测。
当涉及到训练数据时,我们希望它是公平和无偏见的,无论这在我们的特定情况下意味着什么。例如,如果数据是关于用户的,您可能希望以适当的比例包括来自不同地理位置的用户,以匹配他们的全球人口。在数据被允许用于训练之前,可以通过对照适当的期望套件验证每批训练数据来检查是否是这种情况。
至于模型的输出,例如,如果男女的其余特征相同,我们可能希望它对男女产生相同的预测。为了确保这一点,只需在一个保留测试集上测试模型,并根据一套预先设计好的预期运行结果。
改善团队沟通和数据理解
最后但同样重要的是,让我给你举一个非常有创意的使用远大前程的例子,这是我从软件包的作者之一 James Campbell 那里听到的,他在数据工程播客中接受了采访。
也就是说,您可以从创建一个空的期望套件开始,也就是:列出所有的列,但是不要对它们的值进行任何检查。然后,召集与数据或业务流程相关的人,问他们:令人担忧的最大月流失率是多少?网站粘性要降到多低才会触发警报?这样的对话可以改善团队之间与数据相关的交流,以及公司内部对数据本身的理解。
额外资源
感谢阅读!要了解关于 Great Expectations 包的更多信息,包括如何将它与 Apache Spark 或关系数据库一起使用,或者如何编写自定义期望,请查看该包的官方文档。写得真的很好,读起来也很愉快。你可能也喜欢听已经提到的对通用电气的一位作者的采访,如果你正在寻找一个更短的资源,看看这个来自超导公司产品负责人的演讲,该公司是《远大前程》的幕后推手。最后,我希望你总是知道从你的数据中期待什么!
如何理解强化学习代理?在培训和调试过程中,我记录了什么,为什么要记录
原文:https://web.archive.org/web/https://neptune.ai/blog/reinforcement-learning-agents-training-debug
基于简单地观察一个代理在环境中的行为,很难说出它为什么这样做以及它在内部是如何工作的。这就是为什么建立指标来说明为什么代理以某种方式执行是至关重要的。
这很有挑战性,尤其是当代理不按照我们希望的方式运行的时候……就像总是。每个人工智能从业者都知道,无论我们做什么,大多数时候都不会简单地开箱即用(否则他们不会给我们这么多钱)。
在这篇博文中,你将学习如何跟踪检查/调试你的代理学习轨迹。我假设你已经熟悉强化学习(RL)代理环境设置(见图 1),并且你至少听说过一些最常见的 RL 算法和环境。
然而,如果你刚刚开始你的 RL 之旅,不要担心。我试着不太依赖读者的先验知识,在不能省略某些细节的地方,我会引用有用的资料。
Figure 1: The Reinforcement Learning framework (Sutton & Barto, 2018).
我将从讨论有用的指标开始,这些指标让我们对代理的培训和决策过程有所了解。
然后,我们将重点关注这些指标的汇总统计数据,如 average,这将帮助我们分析代理在整个培训过程中播放的许多剧集。这些将有助于解决代理出现的任何问题。
在每一步,我都会根据自己在 RL 研究中的经验提出建议。让我们直接开始吧!
我用来检查 RL 代理培训的指标
有多种类型的指标可以遵循,每一种都为您提供了关于模型性能的不同信息。因此,研究人员可以获得有关…的信息
…代理表现如何
在这里,我们将进一步了解诊断代理整体性能的三个指标。
剧集回归
这是我们最关心的。整个代理培训都是为了达到可能的最高预期回报(见图 2)。如果这一指标在整个培训过程中不断上升,这是一个好迹象。
图二:RL 问题。找一个使目标 J 最大化的政策π,目标 J 是环境动态 p 下的期望收益 E[R],τ是代理人(或其政策π)所玩的轨迹。
然而,当我们知道期望什么样的回报,或者什么是好的分数时,它对我们更有用。
这就是为什么你应该总是寻找基线,别人的结果在你工作的环境中,把你的结果和他们比较。
随机代理基线通常是一个良好的开端,它允许您重新校准,感受环境中什么是真正的“零”分,即您只需简单地使用控制器即可获得的最小回报(见图 3)。
Figure 3. Table 3 from the SimPLe paper with their results on Atari environments compared to many baselines alongside the random agent and human scores.
剧集长度
这是一个结合剧集回归进行分析的有用指标。它告诉我们,如果我们的代理人能够生存一段时间前终止。在 MuJoCo 环境中,不同的生物学习走路(见图 4),它会告诉你,例如,你的代理人是否在翻转和重置到剧集开始之前做了一些动作。
求解速率
又一个分析剧集回归的指标。如果你的环境有一个被解决的概念,那么检查它能解决多少集是有用的。例如,在推箱子游戏中(见图 5 ),将一个箱子推到目标上可以获得部分奖励。也就是说,只有当所有箱子都在目标上时,房间才被解决。
图 5。推箱子是一个运输难题,玩家必须将房间中的所有箱子推到存储目标上。
因此,代理有可能有一个积极的情节回报,但仍然没有完成要求它解决的任务。
另一个例子是谷歌研究足球(见图 6)及其学院。朝着对手的目标移动会有一些部分奖励,但学院插曲(例如在较小的小组中练习反击情况)只有在代理人的团队进球时才被视为“解决”。
…训练进度
有多种方法来表示“时间”的概念,以及用什么来衡量 RL 中的进度。以下是前四名。
总环境步骤
这个简单的指标告诉您在环境步骤或时间步骤方面,代理已经收集了多少经验。这通常比休息时间更能说明训练进度(步数),休息时间在很大程度上取决于您的机器模拟环境和在神经网络上进行计算的速度(见图 6)。
Figure 7. DDPG training on the MuJoCo Ant environment. Both runs took 24h, but on different machines. One did ~5M steps and the other ~9.5M. For the latter, it was enough time to converge. For the former not and it scored worse.
此外,我们还报告了最终的代理分数,以及训练它需要多少环境步骤(通常称为样本)。分数越高,样本越少,代表样本效率越高。
训练步骤
我们用随机梯度下降(SGD)算法训练神经网络(参见深度学习书籍)。
训练步骤指标告诉我们对网络进行了多少次批量更新。当从非策略重放缓冲区进行训练时,我们可以将其与总的环境步骤进行匹配,以便更好地理解平均来说,来自环境的每个样本被显示给网络多少次以从中学习:
批量规模培训步骤/总环境步骤=批量规模/首次展示长度*
其中 rollout length 是我们在训练步骤之间的数据收集阶段(当数据收集和训练按顺序运行时)平均收集的新时间步数。
上述比率,有时称为训练强度,不应该低于 1 ,因为这将意味着一些样本甚至一次也没有显示给网络!其实应该远高于 1,比如 256(比如 DDPG 的 RLlib 实现中设置的,找“训练强度”)。
墙壁时间
这只是告诉我们实验运行了多长时间。
在计划未来我们需要多少时间来完成每个实验时,这是很有用的:
- 2-3 个小时?
- 通宵吗??
- 或者几天???
- 整整一周?!?!?!
是的,有些实验可能需要在你的电脑上花上整整一周的时间来完全收敛或训练到你所使用的方法能达到的最大单集回报率。
令人欣慰的是,在开发阶段,较短的实验(几个小时,最多 24 小时)在大多数情况下足以简单地判断代理是否有效,或者测试一些改进想法。
注意,你总是想以这样一种方式来计划你的工作,当你在做其他事情时,比如编码、阅读、写作、思考等,一些实验在后台运行。
这就是为什么一些只用于运行实验的专用工作站可能是有用的。
每秒步数
代理每秒执行多少环境步骤。这个值的平均值允许您计算运行一些环境步骤需要多少时间。
…代理在想什么/做什么
最后,让我们看看代理人的大脑内部。在我的研究中——根据项目的不同——我使用价值函数和政策熵来了解正在发生的事情。
状态/动作值功能
Q-learning 和 actor-critic 方法利用了价值函数 (VFs)。
查看他们预测的值来检测一些异常是有用的,并查看代理如何评估其在环境中的可能性。
在最简单的情况下,我在每集的时间步长记录网络状态值估计,然后在整个剧集中对它们进行平均(下一节将详细介绍)。随着更多的训练,这一指标应开始与记录的发作返回相匹配(见图 7 ),或更经常地,与用于训练 VF 的打折发作返回相匹配。如果没有,那就是一个不好的迹象。
Figure 8. An experiment on the Google Research Football environment. With time, as the agent trains, the agent’s value function matches the episode return mean.
此外,在 VF 值图表上,我们可以看到是否需要一些额外的数据处理。
例如,在 Cart Pole 环境中,一个代理在它倒下并死去之前,每一个时间步长都会得到 1 的奖励。剧集回归很快就到了几十上百的量级。VF 网络的初始化方式是在训练开始时输出 0 附近的小值,很难捕捉到这个范围的值(见图 8)。
这就是为什么在用它训练之前需要一些额外的返回标准化。最简单的方法是简单地除以可能的最大回报,但不知何故我们可能不知道什么是最大回报,或者根本没有最大回报(例如,参见穆泽罗论文中的 Q 值归一化,附录 B–备份)。
Figure 9. An experiment on the Cart Pole environment. The value function target isn’t normalized and it has a hard time catching up with it.
我将在下一节讨论一个例子,当这个特殊的度量结合极端聚合帮助我检测代码中的一个 bug 时。
政策熵
因为一些 RL 方法利用了随机策略,所以我们可以计算它们的熵:它们有多随机。即使使用确定性策略,我们也经常使用ε-贪婪探索策略,我们仍然可以计算它的熵。
策略熵 H 的等式,其中 a 是动作,p(a)是动作概率。
最大熵值等于 ln(N),其中 N 是动作的个数,表示策略随机统一选择动作。最小熵值等于 0,这意味着总是只有一个动作是可能的(有 100%的概率)。
如果您观察到代理策略的熵快速下降,这是一个不好的迹象。这意味着你的代理很快停止探索。如果你使用随机策略,你应该考虑一些熵正则化方法(例如软演员评论家)。如果您使用确定性策略和ε-贪婪探索性策略,可能您对ε衰变使用了过于激进的调度。
…训练进展如何
最后,但同样重要的是,我们有一些更标准的深度学习指标。
KL 发散
像Vanilla PolIcy Gradient(VPG)这样的基于策略的方法在从当前策略中采样的一批经验上训练(它们不使用任何带有经验的重放缓冲器来训练)。
这意味着我们所做的对我们所学的有很大的影响。如果你把学习率设置得太高,那么近似梯度更新可能会在某些看似有希望的方向上迈出太大的步伐,这可能会把代理推入状态空间的更差区域。
因此,代理将比更新前做得更差(参见图 9)!这就是为什么我们需要监控新旧政策之间的差异。它可以帮助我们,例如设定学习率。
图 10。VPG 在车杆环境下的训练。在 y 轴上,我们有一集的长度(在这个环境中它等于一集的回报)。橙色线是分数的滑动窗口平均值。左图,学习率太大,训练不稳定。右图中,学习率被适当微调(我用手找到的)。
KL 散度是两个分布之间距离的度量。在我们的例子中,这些是动作分布(策略)。我们不希望我们的政策在更新前后有太大差异。还有像 PP O 这样的方法,对 KL 散度进行约束,根本不允许太大的更新!
网络权重/梯度/激活直方图
记录每层的激活、梯度和权重直方图可以帮助您监控人工神经网络训练动态。您应该寻找以下迹象:
- 垂死的 ReLU:
如果一个 ReLU 神经元在正向传递中被箝位到零,那么它在反向传递中就不会得到梯度信号。甚至可能发生的情况是,由于不恰当的初始化或训练期间的过大更新,一些神经元对于任何输入都不会兴奋(返回非零输出)。
“有时,你可以通过一个训练过的网络转发整个训练集<,即 RL >中的重放缓冲区,然后发现你的神经元中有很大一部分(例如 40%)一直为零。”~ 是的,你应该了解安德烈·卡帕西的背景 - 消失或爆炸渐变:
渐变更新的非常大的值可以指示爆炸渐变。渐变剪辑可能会有所帮助。
另一方面,梯度更新的非常低的值可以指示消失的梯度。使用 ReLU 激活和 Glorot 统一初始化器(又名 Xavier 统一初始化器)应该有所帮助。 - 消失或爆炸激活:
激活的良好标准偏差在 0.5 到 2.0 的数量级。明显超出此范围可能表明消失或激活爆炸,这反过来可能导致梯度问题。尝试分层/批量标准化,以控制您的激活分布。
一般来说,层权重(和激活)的分布接近正态分布(没有太多异常值的零附近的值)是健康训练的标志。
以上提示应该有助于您通过培训保持网络健康。
政策/价值/质量/…头损失
即使我们优化了一些损失函数来训练一个代理,你也应该知道这不是一个典型意义上的损失函数。具体来说,它不同于监督学习中使用的损失函数。
我们优化了图 2 中的目标。为此,在策略梯度方法中,您推导出该目标的梯度(称为策略梯度)。然而,因为 TensorFlow 和其他 DL 框架是围绕自动梯度构建的,所以您定义了一个 s u rrogate 损失函数,在其上运行自动梯度后,产生的梯度等于策略梯度。
请注意,数据分布取决于策略,并随着训练而变化。这意味着损失函数不必为了训练继续进行而单调减少。当代理发现状态空间的一些新区域时,它有时会增加(参见图 10)。
Figure 11. SAC training on the MuJoCo Humanoid environment. When the episode return starts to go up (our agent learns successfully), the Q-function loss goes up too! It starts to go down again after some time.
而且,它并不能衡量代理人的表现!经纪人的真实表现是一集回归。记录损失作为健全检查是有用的。但是,不要把你对训练进度的判断建立在这上面。
汇总统计数据
当然,对于一些度量标准(比如状态/行动值),为每个实验的每个环境时间步长记录它们是不可行的。通常,你会计算每一集或几集的统计数据。
对于其他指标,我们处理随机性(例如,当环境和/或政策是随机的时,事件返回)。因此,我们必须使用抽样来估计预期的度量值(样本=事件返回案例中的一个代理事件)。
在任何一种情况下,聚合统计都是解决方案!
平均值和标准偏差
当您处理随机环境(例如,《吃豆人》中的幽灵随机行动)和/或您的策略随机采取行动(例如 VPG 的随机策略)时,您应该:
- 播放多集(10-20 集应该可以),
- 他们的平均指标,
- 记录这个平均值和标准偏差。
与简单的一集相比,平均值将更好地估计真实的预期回报,标准差为您提供了播放多集时指标变化的提示。
方差太大,你应该取更多的样本进行平均(播放更多的剧集)或者使用平滑技术,如指数移动平均。
最小/最大值
在寻找 bug 时检查极端情况真的很有用。我用例子来讨论一下。
我和我的代理在 Google Research Football 上进行实验,使用当前时间步长的随机展开来计算动作质量,我注意到这些动作质量的一些奇怪的最小值。
平均统计值是有意义的,但是具有最小值的东西是不好的。它们低于合理的最小值(低于负 1,见图 11)。
Figure 12. The mean qualities are all above zero. The minimum qualities are very often below minus one, which is lower than should be possible.
经过一番挖掘,我发现我使用了 np.empty 来创建一个动作质量数组。
np.empty 是实现 np.zeros 的一种奇特方式,它分配内存,但并不初始化 NumPy 数组。
因此,有时一些操作会更新来自未被擦除的已分配内存位置的分数(覆盖数组中的初始值)!
我把 np.empty 改成了 np.zeros ,问题就解决了。
中位数
同样的想法,我们用平均随机事件,可以适用于整个培训!
我们知道,深度学习使用的算法叫做随机梯度下降。它是随机的,因为我们随机抽取训练样本,然后分批打包。这意味着多次进行一项训练会产生不同的结果。
你应该总是用不同的种子(伪随机数发生器初始化)运行你的训练多次,并且报告这些运行的中间值,以确保分数不是那么高或那么低,仅仅是偶然的。
Figure 13. SAC training on the MuJoCo Ant environment. All runs have the same hyper-parameters, only different seeds. Three runs, three results.
深度强化学习还没有起作用所以你的代理可能无法训练任何东西,即使你的实现是正确的。它可能只是偶然失败,例如,由于不幸的初始化(见图 12)。
结论
现在您知道了您应该记录的内容和原因,以便全面了解代理培训流程。此外,您知道在这些日志中要寻找什么,甚至知道如何处理常见问题。
在我们结束之前,请再看一下图 12。我们看到,训练曲线虽然不同,但遵循相似的路径,甚至三分之二收敛到相似的结果。知道这意味着什么吗?
敬请关注以后的帖子!
强化学习的 10 个现实应用
原文:https://web.archive.org/web/https://neptune.ai/blog/reinforcement-learning-applications
在强化学习(RL) 中,智能体按照奖励和惩罚机制接受训练。代理人因正确的移动而得到奖励,因错误的移动而受到惩罚。在这样做的时候,代理人试图最小化错误的移动,最大化正确的移动。
在本文中,我们将看看强化学习在现实世界中的一些应用。
自动驾驶汽车中的应用
各种论文提出了深度强化学习用于自动驾驶。在自动驾驶汽车中,有各种各样的方面需要考虑,例如各个地方的速度限制,可驾驶区,避免碰撞——仅举几例。
一些可以应用强化学习的自动驾驶任务包括轨迹优化、运动规划、动态路径、控制器优化和基于场景的高速公路学习策略。
比如,可以通过学习自动泊车政策来实现泊车。使用 Q-Learning 可以实现变道,而超车可以通过学习超车策略来实现,同时避免碰撞并在其后保持稳定的速度。
AWS DeepRacer 是一款自主赛车,旨在在物理赛道上测试 RL。它使用摄像头来可视化跑道,并使用强化学习模型来控制油门和方向。
Wayve.ai 已经成功地将强化学习应用于训练汽车如何在一天内驾驶。他们使用深度强化学习算法来处理车道跟随任务。他们的网络架构是一个具有 4 个卷积层和 3 个全连接层的深度网络。以下示例显示了车道跟踪任务。中间的图像代表驾驶员的视角。
具有强化学习的工业自动化
在工业强化中,基于学习的机器人被用来执行各种任务。除了这些机器人比人更有效率这一事实之外,它们还能完成对人来说很危险的任务。
一个很好的例子是 Deepmind 使用人工智能代理来冷却谷歌数据中心。这导致能源支出减少了 40%。这些中心现在完全由人工智能系统控制,无需人工干预。显然仍然有来自数据中心专家的监督。该系统的工作方式如下:
- 每五分钟从数据中心获取数据快照,并将其输入深度神经网络
- 然后,它预测不同的组合将如何影响未来的能源消耗
- 确定在维持安全标准的同时将导致最小功耗的行动
- 在数据中心发送和实施这些操作
这些动作由本地控制系统验证。
强化学习在交易和金融中的应用
有监督的时间序列 模型可以用于预测未来的销售以及预测股票价格。然而,这些模型并不能决定在特定的股票价格下应该采取的行动。进入强化学习(RL)。RL 代理可以决定这样的任务;是持有、买入还是卖出。RL 模型使用市场基准标准进行评估,以确保其性能最佳。
这种自动化为流程带来了一致性,不像以前的方法,分析师必须做出每一个决策。例如,IBM 有一个复杂的基于强化学习的平台,能够进行金融交易。它根据每笔金融交易的盈亏来计算回报函数。
自然语言处理中的强化学习
在 NLP 中,RL 可以用于文本摘要、问答、和机器翻译等等。
这篇论文的作者 Eunsol Choi、Daniel Hewlett 和 Jakob Uszkoreit 提出了一种基于强化学习的方法来回答给定的长文本问题。他们的方法是首先从文档中选择一些与回答问题相关的句子。然后用慢速 RNN 来回答所选的句子。
在本文中,监督学习和强化学习的组合被用于抽象文本摘要。该报由罗曼·保卢斯、蔡明·熊&理查德·索歇署名。他们的目标是在较长的文档中使用注意力的、基于 RNN 的编码器-解码器模型时,解决在摘要中面临的问题。本文的作者提出了一种具有新型内部注意力的神经网络,该网络关注输入并分别连续产生输出。他们的训练方法是标准监督单词预测和强化学习的结合。
在机器翻译方面,来自科罗拉多大学和马里兰大学的作者提出了一种基于强化学习的同步 T2 机器翻译方法。这项工作有趣的地方在于,它有能力学习何时信任预测的单词,并使用 RL 来确定何时等待更多输入。
来自斯坦福大学、俄亥俄州立大学和微软研究院的研究人员已经将 Deep RL 用于对话生成。深度 RL 可以用于在聊天机器人对话中模拟未来的奖励。使用两个虚拟代理模拟对话。策略梯度方法用于奖励包含重要对话属性的序列,如连贯性、信息性和易于回答。
强化学习在医疗保健中的应用
在医疗保健领域,患者可以根据从 RL 系统学习到的政策接受治疗。RL 能够使用先前的经验找到最优策略,而不需要关于生物系统的数学模型的先前信息。这使得这种方法比医疗保健中其他基于控制的系统更适用。
医疗保健中的 RL 被归类为慢性病或重症护理、自动医疗诊断和其他一般领域中的动态治疗方案(DTRs) 。
在 DTRs 中,输入是一组对患者的临床观察和评估。输出是每个阶段的治疗方案。这些类似于 RL 中的状态。在 DTRs 中应用 RL 是有利的,因为它能够确定依赖于时间的决定,以便在特定时间对患者进行最佳治疗。
RL 在医疗保健中的使用也通过考虑治疗的延迟效应而改善了长期结果。
RL 还被用于发现和产生用于慢性疾病的最佳 DTR。
您可以通过浏览这篇文章来深入了解医疗保健领域的 RL 应用。
强化学习在工程中的应用
在工程前沿,脸书开发了开源强化学习平台——地平线。该平台使用强化学习来优化大规模生产系统。脸书在内部使用了 Horizon:
- 个性化建议
- 向用户发送更有意义的通知
- 优化视频流质量。
Horizon 还包含以下工作流:
- 模拟环境
- 分布式数据预处理平台
- 在生产中培训和导出模型。
视频显示中强化学习的一个经典示例是根据视频缓冲区的状态和来自其他机器学习系统的估计,为用户提供低比特率或高比特率的视频。
Horizon 能够处理类似生产的问题,例如:
- 大规模部署
- 特征标准化
- 分布学习
- 提供和处理包含高维数据和数千种要素类型的数据集。
新闻推荐中的强化学习
用户偏好可能经常改变,因此基于评论和喜欢向用户推荐新闻的可能会很快过时。通过强化学习,RL 系统可以跟踪读者的返回行为。
**构建这样的系统将涉及获取新闻特征、读者特征、上下文特征和读者新闻特征。新闻特写包括但不限于内容、标题和出版商。阅读器功能指的是阅读器如何与内容互动,例如点击和分享。上下文特征包括新闻方面,例如新闻的时间和新鲜度。然后根据这些用户行为定义奖励。
游戏中的强化学习
让我们来看看游戏前沿的一个应用,具体来说就是 AlphaGo Zero 。使用强化学习,AlphaGo Zero 能够从零开始学习围棋。它通过与自己对抗来学习。经过 40 天的自我训练,Alpha Go Zero 能够超越被称为大师的 Alpha Go 版本,该版本击败了世界排名第一的柯洁。它只使用棋盘上的黑白棋子作为输入特征和一个单一的神经网络。依赖于单个神经网络的简单树搜索用于评估位置移动和样本移动,而不使用任何蒙特卡罗展开。
实时竞价——强化学习在营销和广告中的应用
在这篇论文中,作者提出了具有多智能体强化学习的实时竞价。使用聚类方法和给每个聚类分配一个策略投标代理来处理大量广告客户的处理。为了平衡广告商之间的竞争与合作,提出了一种分布式协调多代理竞价(DCMAB)。
在市场营销中,准确定位个人的能力至关重要。这是因为正确的目标显然会带来高投资回报。本文的研究基于中国最大的电子商务平台淘宝。所提出的方法优于最先进的单代理强化学习方法。
机器人操作中的强化学习
深度学习和强化学习的使用可以训练机器人,这些机器人有能力抓住各种物体——甚至是那些在训练中看不见的物体。例如,这可以用于在装配线上制造产品。
这是通过结合大规模分布式优化和一种叫做 QT-Opt 的深度 Q 学习来实现的。QT-Opt 对连续动作空间的支持使其适用于机器人问题。首先离线训练一个模型,然后在真实的机器人上进行部署和微调。
谷歌人工智能将这种方法应用于机器人抓取,其中 7 个真实世界的机器人在 4 个月的时间内运行了 800 个机器人小时。
在这个实验中,QT-Opt 方法在 700 次抓取之前看不到的物体的尝试中,有 96%的抓取成功。Google AI 之前的方法有 78%的成功率。
最后的想法
虽然强化学习仍然是一个非常活跃的研究领域,但在推进该领域并将其应用于现实生活方面已经取得了重大进展。
在本文中,就强化学习的应用领域而言,我们仅仅触及了皮毛。希望这能激发你的好奇心,让你更深入地探索这个领域。如果你想了解更多,看看这个棒极了的回购——没有双关语,还有这个。**
示例强化学习基础(马尔可夫链和树搜索)
你有没有在电子游戏中与电脑对战过,并且想知道它怎么会变得这么好?很大一部分是强化学习。
强化学习(RL)是一个机器学习领域,专注于构建自我完善的系统,在交互式环境中学习自己的行为和经验。在 RL 中,系统(学习者)会根据奖励来学习做什么和怎么做。与其他机器学习算法不同,我们不会告诉系统该做什么。它自主探索和发现哪种行为可以产生最多的回报。强化问题被认为是一个闭环系统,因为系统现在的行为会影响它以后的输入。
“在机器学习和人工智能的背景下,强化学习是一种动态编程,它使用奖励和惩罚系统来训练算法。”–Techopedia
在本文中,我们将通过一些实际例子来深入探讨强化学习。
强化学习是如何工作的?
强化学习问题可以用一系列不同的元素来表述,这取决于你使用的技术。一个基本的强化学习过程包括一个代理,一个代理在交互环境中采取的行动,以及基于该行动的奖励。
- 代理人–根据之前获得的奖励做出决策的学习者。
- 行动—代理为获得奖励而采取的措施。
- 环境—一个任务,代理需要探索这个任务才能获得奖励。
- 状态—在一个环境中,状态是一个代理所处的位置。当前状态包含有关代理先前状态的信息,这有助于他们进行下一步操作。
- 奖励–代理人因其所做的行为而获得奖励或惩罚。
在上图中,下标 t 和 t+1 表示时间步长。代理以时间步长与环境交互,时间步长随着代理进入新状态而增加:
s [t] =s [0] 到 s[t+1]= s[0+1]= s[1]
强化学习没有训练阶段,学习者或代理人根据自己的经验进行改进,并分别对积极和消极行为进行奖励或惩罚。这整个经历被一个接一个发生的国家-行动对所捕获。这一过程的最终目标是在学习最佳行动或举措的同时最大化整体回报。
虽然目标是明确的,但强化学习仍然需要一些参数来实现更好的性能。
- 折扣系数–有助于随着时间的推移调整奖励的重要性。它会成倍地降低以后奖励的价值,因此代理人不会采取任何没有长期影响的行动。
- 策略—表示状态到动作的映射。目标是找到一个最优策略,指定每个州的行动,承诺最高的回报。
- Value–确定状态-行动对的好坏,即该功能试图找到一个有助于最大化回报的策略。
- Q 值—将状态-行动对映射到奖励。这是指在某个州的政策下采取的行动的长期影响。
这些函数中的一些是所有 RL 算法的基础,一些是少数算法所特有的。在下一节中,我们将介绍 RL 算法,并详细解释这些函数。
强化学习算法是面向目标的,学习如何实现一个复杂的目标。基本算法对于更大的状态-动作空间可能不是有效的,除非它们与神经网络结合。
神经网络由互连的节点组成,这些节点按层排列,它们之间的每个连接都将被分配一些权重。目标是通过训练数据的向后和向前传播的几次迭代来了解正确的权重。有人可能会问,这怎么能应用于强化学习算法。
在强化学习中,状态和动作可能有 N 种组合,记录所有这些组合可能有点困难。可以对一些状态-动作样本训练神经网络,并学习预测每个状态可能的最佳动作。
现在我们对强化学习有了基本的了解,让我们来回顾一些算法和技术。
强化学习算法
我们将只讨论一些精选的算法来帮助你开始强化学习,因为它们有很多,而且新的算法还在不断被发现。
RL 算法可以分为:
- 基于模型的 RL,
- 无模型 RL。
无模型 RL 可以进一步分为基于策略和基于价值的 RL。
- 基于模型–这些 RL 算法使用模型,根据之前观察到的转换来学习转换分布。建模容易有偏差,同样的情况也会发生在基于模型的 RL 中。在数据不足的情况下,政策优化或找到正确的状态-行为对以获得高回报可能会面临偏差。
- 基于策略–在基于策略的算法中,重点是为状态-动作对开发最佳策略。有两种类型的策略,确定性的和随机的。
- 基于价值—基于价值的算法从当前状态开始,确定最佳策略,以最大化任何和所有连续步骤的预期奖励值。
让我们来看看一些最流行的 RL 算法。
q 学习
Q 学习是一种无模型的基于值的强化算法。重点是学习一个动作在特定状态下的价值。两个主要组件有助于找到给定状态的正确操作:
**1. Q-Table–这是查找表的一个别出心裁的名字。该表包含 Q 分数,即代理在采取特定行动时将获得的最大预期未来回报。每一行表示环境中的一个特定状态,每一列专用于操作。
表格值将随着改进的动作/分数而迭代更新。这些值可以使用 Q 函数来计算。
- Q 函数—Q 函数使用贝尔曼方程。 贝尔曼方程 ,以理查德·e·贝尔曼命名,是与被称为动态规划的数学优化方法相关的最优性的必要条件。”
q 函数使用贝尔曼方程的基本概念。它通过使用先前状态的值来计算特定点的决策问题的值。
Q(s[t],a[t])= r(s,a)+max Q(s[t],a
在上面的等式中,
Q(s[t],a[t]**)=特定状态下给定动作的 Q 值
r(s,a) =在给定状态下采取行动的奖励
= 折扣系数
max q (s [t] ,a [t] ) = 给定状态下的最大期望报酬以及该状态下所有可能的行为
等式中的 q 代表每个状态下动作的质量,这就是为什么在这个算法中使用了一对状态和动作。q 值有助于识别在一种状态下哪些动作比其他动作更合适。这就是贝尔曼发挥作用的地方,因为我们可以利用贝尔曼的理论来确定完美的 Q 值。
最初,在 Q-learning 中,我们探索环境并更新 Q-table,直到它准备好并包含每个状态的更好行动的信息,以最大化奖励。
DQN-深度 Q 网络
在上面的介绍部分,我们提到了将神经网络与 RL 相结合。DQN 就是一个完美的例子。DQN 是由 DeepMind 在 2015 年利用 Q 学习和神经网络开发的。
在 Q-learning 中,我们处理离散数量的状态,定义和更新 Q-table 更容易。在一个大的状态空间环境中,这可能是具有挑战性的。在 DQN,不是定义一个 Q 表,而是用神经网络来近似每个状态-动作对的 Q 值。在强化学习中应用神经网络有几个挑战,因为大多数其他深度学习应用程序使用大量的手动标记训练,这在奖励数据稀疏且有噪声的 RL 情况下不稳定。
当代理发现特定状态的新动作时,RL 数据也保持变化。使用只对固定数据分布起作用的神经网络方法对 RL 没有帮助。这就是 DeepMind 的 DQN 算法建议使用 Q 学习方法和经验回放功能的变体的地方。
可以通过最小化损失函数 L 来训练 Q 网络,如下所示:
损失函数将在每次迭代 I 时改变。在上面的 DQN 等式中,y[I]是迭代 I 的目标/回报计算,ρ(s,a)是序列 s 和动作 a 的概率分布,称为行为分布。
在 RL 中使用连续的样本来训练用于学习目的的代理是没有用的,因为样本会有很强的相关性。但是,使用经验回放,DQN 随机化抽样并减少方差。在每次迭代中,我们计算小批量的损失,这提供了更好的数据效率,并有助于做出公正的决策。
A3C–异步优势行动者-批评家
DQN 使用经验重放,但也使用更多的内存和需要更多的计算。因此,A3C 建议在环境的多个实例上并行使用多个代理,而不是体验重放。这种技术提供了更稳定的过程,因为并行性也有助于处理相关的数据样本。
在基于值的无模型算法中,基于 Q 值更新状态-动作对的值,这使得学习过程缓慢。通过 A3C,我们可以克服 DQN 的挑战。它由三个主要部分组成——
- 异步
在 DQN,单个神经网络与单个环境进行交互,而在 A3C 中,并行演员学习者使用多个代理。每个代理都有自己的网络和环境,并与之交互。随着全球网络的出现,代理将拥有更加多样化的数据,这最终收获了整体学习。
- 演员评论家
A3C 结合了基于价值和基于政策的优点,因此它能够预测价值和政策功能。代理使用使用值函数预测的值来寻找最优策略函数。因此,价值函数充当批评家,政策充当演员。
- 优势
这是一个有助于理解回报比预期好多少的指标。这改进了代理在环境中的学习过程。
A = Q(s,A)–V(s)
这种方法优于许多其他 RL 算法,但这并不意味着其他算法没有用。但是,在许多情况下,将这些结合在一起有助于实现更高的效率。
SARSA–国家-行动-奖励-国家-行动
它由 Rummery 和 Niranjan 提出,被称为修正的连接主义 Q-Learning(MCQ-L),但被 Rich Sutton 命名为 SARSA。该名称反映了我们在 SARSA 中遵循的流程。该算法的目的是找到 Q 值,该 Q 值取决于代理的当前状态和在该状态下的动作。这是一种基于策略的算法,它根据所采取的措施来估计策略的价值。
Qt+1(St,At) = Qt(St,At) + αRt+1 + γQt(St+1,At+1)—Qt(St,At)
这里我们考虑从状态-动作对到状态-动作对的转换,并了解状态-动作对的价值。每次从非终止状态 St 转换后都会进行更新。如果 St+1 为终端,那么 Qt(St+1,At+1 )被定义为零。这个规则使用事件五元组的每个元素, (St,At,Rt+1 , St+1,At+1 ) ,它们构成了从一个状态-动作对到下一个状态-动作对的转换。–RL-第 6.4 章
MBMF——基于模型的免费模型
神经科学的证据表明,人类同时使用 MF 和 MB 方法来学习新技能,并在学习过程中在两者之间切换。–MBMF RL
MF 算法在学习复杂的策略方面是有效的,但是它需要许多尝试并且可能是耗时的,其中模型对于 MB 来说必须是精确的以实现泛化。MB 和 MF 都有其局限性。通过结合它们,我们可以利用它们的优势。基于模型的 RL 将使用神经网络模型来创建将在无模型 RL 中使用的样本,以实现高回报。基于模型的算法可以提供策略的监督初始化,可以使用无模型算法对其进行微调。
应用和使用案例
强化学习有着广泛的应用。RL 已经成功地解决了序列决策问题。研究人员利用 RL 技术解决一些非顺序问题;RL 广泛应用于游戏、医疗保健、供应链管理等领域。
RL 以其主流算法被用于解决几个具有超人性能的游戏而闻名。AlphaGo 是一个设计用来下围棋的计算机程序。它轻而易举地打败了人类围棋高手。它结合了蒙特卡罗树搜索算法和深度神经网络。RL 被用在很多其他游戏中,还有视频游戏,尤其是所有的雅达利游戏。具有一般智能的代理已经为吃豆人,太空入侵者,和更多建立。
"强化学习不仅仅是一个学术游戏。通过使计算机能够在没有提示和建议的情况下自我学习,机器可以创新地行动,并克服普遍的人类偏见。”–deep sense . ai
机器人系统并不新鲜,它们通常在受控的环境中执行重复的动作。只有一定数量的步骤需要以专注的方式来遵循。
设计必须观察周围环境并采取最佳行动路线的机器人可能具有挑战性,但深度学习和 RL 有助于使其成为可能。机器人系统的一个很好的例子就是你家里的机器人吸尘器。起初,它不知道你的房间,慢慢地它会了解这个区域。如今,许多这样的应用程序都结合了 RL 来使机器人变得更好。
- 自主控制学习
大多数人都听说过自动驾驶,比如特斯拉汽车。该领域需要复杂的控制架构,并且参数调整非常困难。但是,一旦部署了这些系统,它们大多是自学的。
在用 RL 创建自治系统时,必须考虑许多事情。正如你在上面的图表中看到的,系统/智能体应该能够检测物体,规划运动,最重要的是知道什么时候移动,什么时候停止。
每天都会产生大量的新闻内容,但并不是每条新闻都与每个用户相关。有许多参数需要考虑。传统的推荐方法涵盖了所有的参数,如位置、时间、简档等。,但倾向于推荐类似的商品。这减少了阅读选择和用户满意度。
“使用 RL 的推荐框架可以通过将用户回报模式视为点击/不点击标签的补充来显式地对未来回报建模,以便捕捉更多的用户反馈信息。此外,还融入了有效的探索策略,为用户寻找新的有吸引力的新闻。”–DRN——宾夕法尼亚州立大学
学习模型–实践
马尔可夫决策过程
大多数强化学习任务都可以被框定为 MDP。MDP 用于描述每个事件依赖于前一个事件的任务,这种属性被称为马尔可夫属性。这假设一个过程的未来事件仅仅基于该过程的当前状态或该过程的整个历史。
通常,马尔可夫过程包括:
- 将执行动作的代理,
- 一组可能的路线或状态,
- 决策环境,
- 代理必须实现的一个目标——奖励。
我们已经在上面的章节中详细介绍了这些组件。因此,在这里我们将着重于从头创建一个 MDP 环境,并尝试以这种方式模拟一个复杂的现实世界的问题。
对于 MDP 环境,我们使用将问题分解成子问题的动态编程概念,并将这些子问题的解决方案存储起来,以便以后解决主问题。为了将主要问题分成多个子问题,我们将创建一个网格形式的环境,其中每个网格都有不同的奖励或惩罚。
让我们举一个小例子来理解我们在这里所说的。说你在开车,想回家,但是你平时走的路今天很忙。还有一条路不太拥挤,也许能让你准时回家。让我们看看使用 RL 的代理如何决定走哪条路。
首先,我们以网格形式定义问题及其状态。
TRAFFIC = "T"
AGENT = "A"
HOME = "H"
EMPTY = "E"
mdp_grid = [
[HOME, EMPTY],
[TRAFFIC, AGENT]
]
for row in mdp_grid:
print('|'+'|'.join(row) + '|')
|H|E|
|T|A|
代理只能向左、向右、向上和向下移动,这意味着他只能执行以下操作:
UP = 0
DOWN = 1
LEFT = 2
RIGHT = 3
ACTIONS = [UP, DOWN, LEFT, RIGHT]
既然知道了状态和动作,就该计算每个状态-动作对的奖励,并确认目标是否已经实现。对于每次迭代,它将状态和动作作为输入,并返回新的状态、动作和奖励。
def path(state, action):
def new_pos(state, action):
p = deepcopy(state.agent_pos)
if action == UP:
p[0] = max(0, p[0] - 1)
elif action == DOWN:
p[0] = min(len(state.grid) - 1, p[0] + 1)
elif action == LEFT:
p[1] = max(0, p[1] - 1)
elif action == RIGHT:
p[1] = min(len(state.grid[0]) - 1, p[1] + 1)
else:
raise ValueError(f"Unknown action {action}")
return p
p = new_pos(state, action)
grid_item = state.grid[p[0]][p[1]]
new_grid = deepcopy(state.grid)
if grid_item == TRAFFIC:
reward = -10
is_done = True
new_grid[p[0]][p[1]] += AGENT
elif grid_item == HOME:
reward = 100
is_done = True
new_grid[p[0]][p[1]] += AGENT
elif grid_item == EMPTY:
reward = -1
is_done = False
old = state.agent_pos
new_grid[old[0]][old[1]] = EMPTY
new_grid[p[0]][p[1]] = AGENT
elif grid_item == AGENT:
reward = -1
is_done = False
else:
raise ValueError(f"Unknown grid item {grid_item}")
return State(grid=new_grid, agent_pos=p), reward, is_done
但是我们将如何调用这个函数,我们将如何决定我们已经到达了家?首先,我们将随机选择每个状态中的动作。然后,我们将尝试使用状态-动作对来确定选择的路径是否正确。对于每一个状态-动作对,我们将计算 q 值,看看哪个动作准确到达家,然后重复这个过程,直到我们到家。
这里,我们定义了一些常数,稍后我们将使用贝尔曼公式来计算 Q 值。
N_STATES = 4
N_EPISODES = 10
MAX_EPISODE_STEPS = 10
MIN_ALPHA = 0.02
alphas = np.linspace(1.0, MIN_ALPHA, N_EPISODES)
gamma = 1.0
eps = 0.2
start_state = State(grid=grid, car_pos=[1, 1])
q_table = dict()
为了创建 q_table,我们需要状态-动作和相应的 q 值。
def q(state, action=None):
if state not in q_table:
q_table[state] = np.zeros(len(ACTIONS))
if action is None:
return q_table[state]
return q_table[state][action]
我们还需要决定什么是最好的行动。
def choose_action(state):
if random.uniform(0, 1) < eps:
return random.choice(ACTIONS)
else:
return np.argmax(q(state))
让我们播放几集,看看代理人需要多长时间来决定回家的最佳方式。
for e in range(N_EPISODES):
state = start_state
total_reward = 0
alpha = alphas[e]
for _ in range(MAX_EPISODE_STEPS):
action = choose_action(state)
next_state, reward, done = path(state, action)
total_reward += reward
q(state)[action] = q(state, action) +
alpha * (reward + gamma * np.max(q(next_state)) - q(state, action))
state = next_state
if done:
break
print(f"Episode {e + 1}: total reward -> {total_reward}")
现在我们的 Q 表已经准备好了,代理现在知道了每个状态下可能的最佳行动,让我们检查他如何一步一步到达家。
如果你记得我们之前做的网格,代理在位置(1,1)。我们将从 1,1 开始旅程,看看代理接下来会去哪里——他会走繁忙的道路还是没有交通的道路?
r = q(start_state)
print(f"up={r[UP]}, down={r[DOWN]}, left={r[LEFT]}, right={r[RIGHT]}")
up=98.13421151608904, down=42.67994031503147, left=-10.0, right=42.25406377182159
因此,可以看到 UP 具有最高的 Q 值,即当代理开始时,他选择了没有交通流量的道路。让我们看看他下一步会做什么。
new_state, reward, done = path(start_state, UP)
r = q(new_state)
print(f"up={r[UP]}, down={r[DOWN]}, left={r[LEFT]}, right={r[RIGHT]}")
up=-1.0, down=0.9519170608828851, left=99.92190645654732, right=0.0
这一次,代理向左转,这意味着他成功地到达了家,这样,我们就创建了我们的第一个 RL 解决方案。这里,我们从头开始创建了一个简单的马尔可夫决策过程。如果我们加上时间、距离等其他因素,这个问题就更难了。更多类似的例子,你可以查看 OpenAI github 页面。
蒙特卡罗树搜索
蒙特卡罗树搜索是经典树搜索和强化学习原理的结合。这种模型在组合游戏中很有用,在这种游戏中,在采取任何行动之前都需要计划。在国际象棋比赛中,在你移动任何一个棋子之前,你会先想两步或更多步,在你的脑海中运行未来的场景,并思考你的对手可以进一步采取什么行动。该模型能够组合不同的场景,并对其进行归纳,以找到最佳解决方案。
一种基本的 MCTS 方法是在模拟播出后逐节点建立的简单搜索树。这个过程有 4 个主要步骤:
- 选择
使用特定的策略,MCTS 算法从根节点 R 开始遍历树,递归地找到最佳子节点,并且(一旦到达叶节点)移动到下一步。MCST 使用 UCB(置信上限)公式,这有助于在勘探和开采之间保持平衡。
这里,S[I]是节点 I 的值,在选择过程中遍历时,无论哪个子节点返回最大值,都将被选中。
*2. 膨胀
这是向树中添加新的子节点的过程。这个新节点将被添加到以前选择的节点中。
- 模拟
扩展后,该算法在选定的节点上执行模拟。在这个过程中,它会查看游戏中的所有场景,直到达到一个结果/目标。
- 反向传播
反向传播是这样一个步骤,其中所有以前访问过的节点——从当前节点到根节点——都将用奖励值和访问次数进行更新。
现在您已经对什么是 MCTS 及其主要步骤有了基本的了解,让我们使用 Python 从头开始构建一个树搜索算法。在这个例子中,我们将创建一个井字游戏,并尝试一步一步地分析。
创建一个 3 x 3 的井字游戏板,起初,它是空的。
def play_game():
tree = MCTS()
board = new_tic_tac_toe_board()
print(board.to_pretty_string())
while True:
row_col = input("enter row,col: ")
row, col = map(int, row_col.split(","))
index = 3 * (row - 1) + (col - 1)
if board.tup[index] is not None:
raise RuntimeError("Invalid move")
board = board.make_move(index)
print(board.to_pretty_string())
if board.terminal:
break
for _ in range(50):
tree.do_rollout(board)
board = tree.choose(board)
print(board.to_pretty_string())
if board.terminal:
break
def new_tic_tac_toe_board():
return TicTacToeBoard(tup=(None,) * 9, turn=True, winner=None, terminal=False)
if __name__ == "__main__":
play_game()
enter row,col: 3,1
一旦你进入行列,你的棋盘看起来就像这样。
现在是时候让电脑下他的棋了。它将首先进行 50 次滚转,然后移动。
def do_rollout(self, node):
"Make the tree one layer better. (Train for one iteration.)"
path = self._select(node)
leaf = path[-1]
self._expand(leaf)
reward = self._simulate(leaf)
self._backpropagate(path, reward)
def _select(self, node):
"Find an unexplored descendent of `node`"
path = []
while True:
path.append(node)
if node not in self.children or not self.children[node]:
return path
unexplored = self.children[node] - self.children.keys()
if unexplored:
n = unexplored.pop()
path.append(n)
return path
node = self._uct_select(node)
def _expand(self, node):
"Update the `children` dict with the children of `node`"
if node in self.children:
return
self.children[node] = node.find_children()
def _simulate(self, node):
"Returns the reward for a random simulation (to completion) of `node`"
invert_reward = True
while True:
if node.is_terminal():
reward = node.reward()
return 1 - reward if invert_reward else reward
node = node.find_random_child()
invert_reward = not invert_reward
def _backpropagate(self, path, reward):
"Send the reward back up to the ancestors of the leaf"
for node in reversed(path):
self.N[node] += 1
self.Q[node] += reward
reward = 1 - reward
def _uct_select(self, node):
"Select a child of node, balancing exploration & exploitation"
assert all(n in self.children for n in self.children[node])
log_N_vertex = math.log(self.N[node])
def uct(n):
"Upper confidence bound for trees"
return self.Q[n] / self.N[n] + self.exploration_weight * math.sqrt(
log_N_vertex / self.N[n]
)
return max(self.children[node], key=uct)
你可以在 do_rollout()函数中看到,它调用了 MCTS 的所有四个主要组件。现在,对手将轮到他出牌,棋盘看起来像这样。
同样的过程将会重复,直到其中一个玩家赢得游戏。如果你对通过增加维度来扩展游戏感兴趣,这里有的基本代码供你参考。
这种算法在许多回合制游戏中使用:井字游戏、国际象棋、跳棋等。它不仅限于游戏应用,它实际上可以扩展并用于决策过程。
RL 的优势和挑战
技术是这样一个领域,无论发生多少突破,总会有发展的空间。虽然 RL 是机器学习中的新兴领域之一,但它比其他算法和技术有一些好处,也有一些独特的挑战。
利益
- 它不需要用于训练目的的标记数据,获得标记的训练数据集不涉及任何成本。
- 它是面向目标的,可用于一系列步骤的问题,不像其他 ML 算法是基于输入和输出的。
- 在 RL 中,探索和剥削同时发生,这意味着 RL 不需要再培训。在测试寻找新解决方案的新方法的同时,它还利用了迄今为止最好的解决方案。
- RL 侧重于实现其他算法难以实现的长期结果。
- RL 系统是人类自我技能的反映,因此这些系统几乎不需要任何中断,并且有达到完美的范围。
挑战
- RL 不适用于较简单的问题。
- 这可能导致国家负担过重,从而削弱成果。
- 在大多数现实世界的问题中,没有具体的奖励,但大多数 RL 算法都是基于寻找一个特定目标的概念。
- 虽然这都是关于 RL 中的试错,但不可能在所有场景中都是一样的。比如在自动驾驶汽车中,它不能多次撞车后才能决定走哪条路。
- 每个算法中都有环境参数,从定义的角度来看,我们似乎可以控制这些元素。在现实世界中,事情可能会频繁变化,RL 系统的准确性将始终令人怀疑。
RL 则不同——有人监督和无人监督
RL 不同于监督和非监督学习,因为它不需要训练数据,并且单独与环境一起工作以实现一个定义的目标。以下是其他一些不同之处:
比较标准 | 监督学习 | 无监督学习 | 强化学习 |
---|---|---|---|
未标记的数据用于训练
|
与环境互动并遵循试错过程
|
| |
回归分类
| | |
| | | | |
| |
预测、身份检测等。
|
欺诈检测、推荐系统等。
|
自动驾驶、游戏应用、医疗保健等。
|
结论
在整篇文章中,我们收集了一些关于强化学习的基础知识,从定义到基本算法。我们做了一些动手练习,用 Python 从头开始创建马尔可夫决策过程和蒙特卡罗树搜索。
在写这篇文章和阅读大量研究论文的时候,我觉得在这个领域有太多东西需要探索,有太多东西需要实验。看到未来会带来什么是令人兴奋的。
感谢阅读!
Thanks for reading!***
使用 Autoencoder 了解表征学习
原文:https://web.archive.org/web/https://neptune.ai/blog/representation-learning-with-autoencoder
机器学习是人工智能的一个子领域,我们试图建立具有大脑功能和行为的智能系统。通过人工智能,我们试图建造能够计算、提取模式、自动化日常任务、诊断生物异常以及证明科学理论和假设的机器。
因为机器学习是 AI 的子集,它不依赖于硬编码的算法来找到通往核心解决方案的道路,而是用它可以从给定信息中提取知识的思想来加强 AI,并且在没有硬编码的情况下找到通往核心思想的道路。
随着机器学习的出现,我们现在可以设计能够“处理涉及真实世界知识的问题并做出看起来主观的决定”的算法。
(伊恩·古德费勒《深度学习》)
在所有机器学习问题中,数据都起着关键作用。
为什么这么重要?
数据是信息的离散排列,提供一系列连续的事件。在这种安排中,所有的表现形式都被隐藏起来了。如果机器可以提取代表特定事件的模式,我们可以说机器已经学习了这些信息,如果新的数据或信息被输入其中,那么它可以提供适当的解决方案和预测。
表征学习
想象一下,一名工程师设计了一种基于大脑扫描预测恶性细胞的 ML 算法。为了设计算法,工程师必须严重依赖患者数据,因为所有答案都在那里。
数据中的每个观察或特征描述了患者的属性。预测结果的机器学习算法必须学习每个特征如何与不同的结果相关联:良性或恶性。
因此,如果数据中有任何噪声或差异,结果可能完全不同,这是大多数机器学习算法的问题。大多数机器学习算法对数据的理解都很肤浅。
那么解决办法是什么呢?
向机器提供更抽象的数据表示。
对于许多任务,不可能知道应该提取什么特征。艾伦·图灵和他破译恩尼格玛密码的同事观察到了信息中有规律出现的模式。这就是代表学习的想法真正进入视野的地方。
在表示学习中,机器被提供数据,并且它自己学习表示。这是一种寻找数据表示(特征、距离函数、相似性函数)的方法,它决定了预测模型的性能。
表征学习的工作原理是将高维数据简化为低维数据,从而更容易发现模式和异常,并让我们更好地理解数据的行为。
它还降低了数据的复杂性,因此减少了异常和噪声。这种噪声的减少对于监督学习算法非常有用。
不变性和解纠缠
表征学习的问题在于,很难获得能够解决给定问题的表征。幸运的是,深度学习和深度神经网络开始证明非常面向目标和有效。
深度神经网络可以从简单的概念中构建复杂的概念,这一想法是深度学习的核心[Ian Goodfellow,“深度学习”]。
那么,表征学习的理念在哪里呢?
人们试图理解深度学习的成功。两个主要结论是 表征学习 和优化。
深度学习通常被视为一个黑盒,其中有限数量的函数被用来寻找产生良好泛化能力的参数。这是通过优化来实现的,在优化中,算法试图通过用实际情况评估模型输出来自我校正。
这个过程一直进行到优化函数达到称为全局最小值的最小值点。大多数深度学习网络都严重过度参数化,并表明它们可能过度拟合——即算法在训练数据上表现良好,但在新数据上表现不佳。最近的工作表明,这与损失景观的性质有关,也与随机梯度下降(SGD)执行的隐式正则化有关,但总体输出仍有噪声[Zhang 等人,2017]。
另一方面,表征学习专注于网络各层(激活)学习的表征的属性,同时在很大程度上保持对所使用的特定优化过程的不可知[深层表征中不变性和解缠结的出现,2018]。
通常出现在任何数据分布中的两个主要因素是方差和纠缠。需要消除这两个因素,以便从数据中获得良好的表示。数据中的方差也可以被认为是敏感性,而这些敏感性可以将结果颠倒过来。我们建立的任何模型都必须对方差具有鲁棒性,也就是说,它必须是不变的,因为这会极大地损害深度学习模型的结果。
纠缠是数据中的向量与数据中的其他向量连接或关联的方式。这些联系使得数据非常复杂,难以破译。我们应该做的是寻找关系简单的变量。这是一种将高维数据转换为低维数据的简单方法,或者以一种可以轻松分离的方式来转换高维数据。
从上一节中,我们了解到表征学习的能力是它学习对数据有意义的抽象模式,而深度学习通常被认为是深度网络学习表征的能力,这些表征对诸如平移、旋转、遮挡以及“解开缠结”或分离高维数据空间中的因素等干扰不变(不敏感)[Bengio,2009]。但是,学习通过创建不变的和不混乱的模型来简化复杂的数据排列仍然很重要。
“如果架构和损失函数都没有明确地实施不变性和解纠缠,这些属性如何能够在通过简单的一般优化训练的深度网络中一致地出现?”
事实证明,我们可以通过展示两样东西来回答这个问题:
使用统计决策和信息论的经典概念,我们表明深度神经网络中的不变性等价于它计算的最小表示,并且可以通过在现实和经验验证的假设下堆叠层并在计算中注入噪声来实现。
- 使用经验损失的信息分解,我们表明过拟合可以通过限制存储在权重中的信息内容来减少。【深度表征中不变性与解纠缠的出现,2018】。
信息瓶颈
信息瓶颈是由 Tishby 等人(1999)提出的。它是在一个假设下推出的,即它可以通过压缩可以在整个网络中传输的信息量来提取相关信息,从而强制对输入数据进行有记忆的压缩。
这种压缩的表示方式不仅降低了维度,还降低了数据的复杂性【深度学习和信息瓶颈原理,Tishby 2015】。这个想法是,一个网络就像通过一个瓶颈挤压信息一样,去除了噪音输入数据中无关的细节,只留下与一般概念最相关的特征。
Tishby 的发现让人工智能社区议论纷纷。“我相信信息瓶颈的想法在未来的深度神经网络研究中可能非常重要”,谷歌研究院的 Alex Alemi 说,他已经开发了新的近似方法,用于将信息瓶颈分析应用于大型深度神经网络。Alemi 说,瓶颈不仅可以作为理解为什么我们的神经网络像目前一样工作的理论工具,也可以作为构建网络新目标和架构的工具。
潜在变量
潜在变量是无法直接观察到的随机变量,但它为数据如何分布奠定了基础。潜变量也给了我们高维数据的低层表示。它们为我们提供了数据分布的抽象表示。
那么我们为什么需要潜在变量呢?
所有的机器学习都有一个明确的学习复杂概率分布的问题 p(x) 。而这些分布是约束,只有有限的一组高维数据点 x 从这个分布中抽取。
例如,为了了解猫的图像的概率分布,我们需要定义一个分布,这个分布可以模拟构成每幅图像的所有像素之间的复杂相关性。直接对这种分布建模是一项乏味且具有挑战性的任务,甚至是不可行的无限时间。我们可以引入一个(未观察到的)潜在变量 z,并为数据定义一个条件分布 p(x | z) ,而不是直接对 p(x) 建模,这被称为可能性。用概率术语来说, z 可以解释为一个连续的随机变量。对于猫图像的例子,z 可以包含猫的类型、颜色或形状的隐藏表示。
有了 z,我们可以在潜变量上进一步引入一个先验分布 p(z )来计算观察变量和潜变量的联合分布 p(x,z) = p(x|z)p(z) 。
为了获得数据分布 p(x) 我们需要忽略潜在变量。
在此之前,我们可以使用贝叶斯定理计算后验分布。
后验分布允许我们推断给定观测值的潜在变量。
请注意,边缘化方程中的积分对于我们处理的大多数数据没有解析解,我们必须应用某种方法来推断后验概率。本质上,具有潜在变量的模型可用于执行生成数据的生成过程。这就是所谓的生成模型。
这意味着如果我们想要生成一个新的数据点,我们首先需要得到一个样本 z~ p(z) ,然后用它从条件分布 p(x|z) 中采样一个新的观测值 x 。在这样做的同时,我们还可以评估该模型是否为数据分布 p(x) 提供了良好的近似。
根据定义,包含潜在变量的数学模型是潜在变量模型。这些潜在变量的维数比观察到的输入向量低得多。这产生了数据的压缩表示。
潜在变量基本都是在信息瓶颈处发现的。最终,在这个信息瓶颈中,我们可以找到给定高维输入的抽象表示。流形假设陈述高维数据位于低维流形上。
既然我们知道了潜在变量是什么,在哪里可以找到它们,我们现在可以转向使用表征学习的各种框架。
各种学习框架中的表征学习
当前的机器和深度学习模型仍然容易与给定数据发生差异和纠缠(如前所述)。为了提高模型的准确性和性能,我们需要使用表示学习,以便模型能够产生不变性和不纠缠的结果。
在本节中,我们将看到表示学习如何在三种学习框架中提高模型的性能——监督学习、非监督学习和强化学习。
监督学习
监督学习是指 ML 或 DL 模型将输入 X 映射到输出 y。监督学习背后的思想是,学习算法通过优化来学习从输入到输出的映射,其中算法试图通过使用基本事实评估模型输出来校正自身。这个过程一直进行到优化函数达到称为全局最小值的最小点。
但有时,即使优化函数达到了全局最小值,它在新数据上仍然表现不佳,导致过度拟合。事实证明,监督学习模型不需要大量的数据来学习从输入到输出的映射,但它实际上需要学习到的特征。当学习到的特征被传递到监督学习算法中时,它可以将预测精度提高 17%。【利用无监督学习的有效特征学习来改进大规模开放在线课程中的预测模型】。
无监督学习
无监督学习是一种 ML,我们不关心标签,只关心观察本身。无监督学习不用于分类和回归,它通常用于发现潜在模式、聚类、去噪、离群点检测、数据分解等。
当处理数据 x 时,我们必须非常小心地选择什么特征 z ,以便提取的模式反映真实的数据。据观察,更多的数据不一定能为您提供良好的表示。我们需要小心地设计一个既灵活又有表现力的模型,这样提取的特征才能提供重要的信息。
当我们有了正确的特征之后,就可以更有把握地执行诸如聚类、分解或异常检测之类的任务。
强化学习
强化学习是另一种类型的 ML,涉及开发算法,这些算法应该在环境中采取行动,以最大化成功的机会。
监督学习和强化学习都使用输入和输出之间的映射。在监督学习中,提供给代理的反馈是执行任务的正确动作集,强化学习使用奖励和惩罚作为积极和消极行为的信号。重点是在探索(未知领域)和开发(现有知识)之间找到平衡。
体系结构
在这一部分,我们将探索深度学习模型——特别是,如何在给定类型的神经网络中提取表示。
多层感知器或 MLP
感知器[Rosenblatt,1958,1962]是最简单的神经单元,它由一系列与权重相结合的输入组成,然后与基本事实进行比较。
MLP,或多层感知器,是一种通过堆叠多层感知器单元构建的前馈神经网络。MLP 由三层节点组成——输入层、隐藏层和输出层。MLP 作为一个非常基本的人工神经网络,有时也被称为香草神经网络。
隐藏节点使用一系列非线性激活函数,使网络能够区分和分离不可线性分离的数据。这就是人工神经网络或 MLP 的力量发挥作用的地方,因为通用逼近定理指出“神经网络在给予适当的权重时可以代表各种各样有趣的功能。另一方面,它们没有提供配重的构造,而仅仅是说明这种构造是可能的"。
这个概念是表征学习和潜在变量的基础。该定理的核心是我们的目标,即找到能够代表整个数据基本分布的变量或所需权重,这样,当我们将这些变量或所需权重插入看不见的数据时,我们就能获得与原始数据中相似的接近结果。
简而言之,人工神经网络帮助我们从给定的数据集中提取有用的模式。
CNN
卷积神经网络或 CNN 是应用最广泛的神经网络之一,尤其是在图像处理和计算机视觉方面。卷积神经网络是一种使用卷积运算的网络,卷积运算是一种特殊的线性运算,它至少在一层中取代了一般的矩阵乘法[Ian Goodfellow,Deep learning]。CNN 是多层感知器的正则化版本——一种用于控制过度拟合的模型。图像或自然图像具有有限数量的对于平移不变的统计特性。
CNN 通过以下方式实现平移、旋转和失真不变性:
局部利用空间特征,
共享重量,
等变表示。
- 他们还采取了不同的方法来实现正则化:他们利用数据中的层次模式,并使用更小更简单的模式来组装更复杂的模式。 CNN 通过跨网络同时共享信息来考虑这些属性,因为它们能够考虑特征的 位置 。
- 构建 CNN 是为了利用输入数据的空间特征——它们的联合概率分布、空间分布等等————T3,通过在相邻层的神经元之间实施局部连接模式。因此,该架构确保所学习的特征返回对空间局部输入模式的适当响应。
- 堆叠许多这样的层会产生越来越全球化或在整个网络中共享的非线性滤波器。这些过滤器可以处理更大的向量空间,这样网络首先创建输入的小部分的表示,通过非线性过滤器的帮助将它们分离,然后从它们组装更大区域的表示。但是请记住,并不是所有的表示都很重要;我们必须利用信息瓶颈来修剪它们。
我们还必须记住,通过参数共享,CNN 已经能够非常显著地减少独特的模型参数,同时能够增加模型大小。这种参数共享使图层具有一种称为等变表示的属性,这意味着如果输入发生变化,输出也会以同样的方式发生变化。这样我们可以防止模型过度参数化和过度拟合。
CNN 为我们提供了准确的工具来提取有用的信息,更具体地说是空间信息或特征,以后可以根据您的需要进行删减和定制。因此,使用 CNN 成为构建自动编码器和生成模型的常见做法。
Autoencoders
观察到由深度网络学习的表示对数据的复杂噪声或差异不敏感。这在一定程度上可以归因于架构。例如,卷积层和最大池的使用可以显示出对变换的不敏感性。
因此,自动编码器是一种神经网络,可以被训练来完成表征学习的任务。自动编码器试图通过编码器和解码器的组合将其输入复制到输出。通常,使用再循环(Hilton 和麦克莱兰,1988)来训练自动编码器,这是一种基于比较输入网络的激活和重构输入的激活的学习算法(Ian Goodfellow,Deep learning)。
传统上,这些被用于降维或特征学习的任务[LeCun,1987;布尔兰和坎普,1988 年;Hilton 和 Zemel,1994],但最近人们认识到,自动编码器和潜在变量模型(利用先验和后验分布概念的模型,如变分自动编码器)可用于构建生成模型,即可以生成新数据的模型。它通过压缩信息瓶颈中的信息来实现这一点,以便从整个数据集中仅提取重要的特征,并且这些提取的特征或表示可用于生成新数据。
简而言之,编码器是一种将输入减少为不同表示形式的功能,而解码器也是一种功能,可以将从编码器获得的表示形式转换回原始格式。
我们将讨论四种类型的自动编码器:
在完全自动编码器下
正则化自动编码器
稀疏自动编码器
降噪自动编码器
- 不完整的自动编码器
- 如果数据很简单,将输入复制到输出可能会很好,但是如果数据非常复杂呢?在这种情况下,我们的自动编码器将会不合适。我们感兴趣的是保存有用的信息。模型应该学习有用的特性。
- 为了获得这样的功能,我们的模型应该是浅层网络的组合——用于编码和解码——瓶颈是比原始输入更小维度的约束。
- 尺寸小于输入尺寸的自动编码器被称为欠完整自动编码器。通过根据重构误差来惩罚网络,模型可以学习和捕获最显著的特征。
我们知道神经网络能够学习非线性函数,像这样的自动编码器可以被认为是非线性 PCA。
规则化自动编码器
当瓶颈被限制为具有比原始输入更小的维度时,欠完整自动编码器可以学习显著特征。但是我们必须知道编码器和解码器模型的容量。据观察,如果编码器和解码器都被赋予太多的容量,这些自动编码器将无法学习到任何有用的东西。
过完备自动编码器面临着与欠完备自动编码器相同的问题。如果瓶颈与输入具有相同甚至更大的维度,他们什么也学不到。在过完备自动编码器的情况下,也容易将输入复制到输出,而不是学习重要的特性。
理想情况下,我们可以成功地训练任何结构的自动编码器,根据分布的复杂性选择瓶颈维数和编码器和解码器的容量。
规范化的自动编码器给了我们这样做的能力。他们使用损失函数,使该模型能够学习有用的特征,包括:
表示的稀疏性,
表示的导数很小,
对噪声或缺失输入的鲁棒性。
正则化自动编码器的一个特殊特性是,它们可以是非线性的和过完备的,但仍然可以了解一些关于数据分布的有用信息。
- 稀疏自动编码器
- 已经观察到,当以鼓励稀疏性的方式学习表示时,在分类任务上获得改进的性能。这些方法包括激活函数、采样步骤和不同种类的惩罚的组合。
- 稀疏自动编码器是一种已经被正则化以响应独特统计特征的模型。欠完整自动编码器将对每个观测使用整个网络。稀疏自动编码器将被迫根据输入数据选择性地激活网络区域。这消除了网络从输入数据中记忆特征的能力,并且由于一些区域被激活而其他区域没有被激活,因此网络学习有用的信息和特征。
本质上,有两种方法可以施加这种稀疏约束。这些术语是:
L1 正规化
KL-散度
两者都涉及测量每个训练批次的隐藏层激活,并在损失函数中增加一项以惩罚过度激活。
去噪自动编码器
- 开发通用自动编码器的另一种方法是创建一个新的数据集,比如说从 X;其中 x’是 x 的损坏版本。通过这种方法,我们构建了一个模型,该模型能够从轻微损坏的输入数据中进行归纳,但仍将未损坏的数据作为我们的目标输出。
- 本质上,我们的模型不能简单地开发一个记忆训练数据的映射,因为我们的输入和目标输出不再相同。相反,该模型学习用于将输入数据映射到低维流形的矢量场。如果这个流形准确地描述了自然数据,我们就有效地“抵消”了增加的噪声。
生成模型
根据定义,生成建模是机器学习中的一项无监督学习任务,它涉及自动发现和学习输入数据中的表示或模式,以这种方式,该模型可用于生成新示例。所有这些模型都以某种方式表示多个变量的概率分布。创成式模型生成的分布是高维的。例如,在分类和回归等经典深度学习方法中,我们对一维输出进行建模,而在生成模型中,我们对高维输出进行建模。
本质上,我们对数据的联合分布进行建模,并且我们没有任何标签。
创成式模型的一些用途包括:
密度估计和异常值检测
数据压缩
从一个域映射到另一个域
语言翻译,文本到语音
基于模型的强化学习中的规划
- 表征学习
- 理解数据
- 生成模型的类型:
- 自回归模型
- RNN 和变形金刚语言模型,NADE,PixelCNN,WaveNet
- 潜在变量模型
- 易处理:例如可逆/基于流动的模型(RealNVP、Glow 等。)
棘手的问题:例如变化的自动编码器
- 隐式模型
- 生成对抗网络及其变体
-
- 玻尔兹曼机器
- 玻尔兹曼机器是由对称连接的节点组成的神经网络,它们自己决定是激活还是保持空闲。玻尔兹曼机器最初是作为学习二元向量上的任意概率分布的一般方法而引入的[Fahlman 等人,1983;阿克利等人,1985 年;辛顿等人,1984 年;辛顿和塞伊诺夫斯基,1986]。
- 玻尔兹曼机器使用一种简单的随机学习算法来寻找代表输入数据中复杂模式的特征。它们只有输入(可见)和隐藏节点。该模型中没有输出节点,这使得该模型具有不确定性——它不依赖于任何类型的输出。
- 该图显示了十个节点,它们都是相互连接的。它们通常被称为状态。红色的代表隐藏的节点(h),蓝色的代表可见的节点(v)。
玻尔兹曼机器的输入是相连的,这是它们根本不同的地方。所有这些节点相互交换信息,并自生成后续数据,因此称为生成式深度模型。
在这里,可见节点是我们测量的,隐藏节点是我们不测量的。这使他们能够在自己之间共享信息,并自行生成后续数据。当我们输入数据时,这些节点学习所有的参数、它们的模式以及数据之间的相关性。然后,这个模型准备好根据它所学到的东西来监控和研究异常行为。
虽然该程序在具有大量特征检测层的网络中非常慢,但在具有单层特征检测器的网络中却很快,这种检测器被称为受限玻尔兹曼机器。
RBMs 是一个具有生成能力的两层人工神经网络。他们有能力学习一组输入的概率分布。RBM 是 Geoffrey Hinton 发明的,可用于降维、分类、回归、协同过滤、特征学习和主题建模。
RBM 是一类特殊的玻尔兹曼机器,它们受限于可见单元和隐藏单元之间的联系。与玻尔兹曼机器相比,这使得实现它们更容易。
如前所述,它们是一个两层的神经网络(一层是可见层,另一层是隐藏层),这两层由一个完全的二分图连接。这意味着可见层中的每个节点都连接到隐藏层中的每个节点,但同一组中没有两个节点相互连接。这种限制允许比一般玻尔兹曼机器可用的训练算法更有效的训练算法,特别是基于梯度的对比发散算法。
RBM 可以通过梯度下降和反向传播过程进行微调。这样的网络被称为深度信念网络。虽然 RBM 偶尔会被使用,但深度学习社区中的大多数人已经开始用一般的敌对网络或变型自动编码器来取代它们的使用。
可逆模型
可逆模型(也称为规范化流)是一类易处理的生成模型。主要思想是通过使用可逆函数转换先验分布来近似数据分布。可逆模型通过对来自先验的样本应用可逆和可微变换 f [θ] (z) 来生成观测值。
为了解释一个表示或先验,我们需要将意义固定到特征编码的各个部分。也就是说,我们必须将高维特征向量分解成多个多维因素。这种不纠缠的映射应该是双射的,因此不纠缠的特征必须转换回原始表示。
这实质上意味着,对于哪个表示产生了给定的观察结果,没有模糊性,因为函数是易处理的。
这也意味着我们可以通过反转函数来计算潜在变量,并将其应用于观察到的数据,因此我们可以准确地恢复产生潜在变量的原始变量。这使得表象相关和完全确定。
可逆模型的局限性:
潜在空间和观察必须具有相同的维度
潜在变量必须是连续的
观察必须是连续的或量化的
像这样的表达模型需要很多层,所以计算和内存开销都很大
结构僵化:模型设计缺乏灵活性
- 变分推理
- 我们的生成模型必须不仅仅是一个生成样本或做出预测的黑匣子。我们希望找到我们正在处理的数据的意义,一些更内在的和可解释的东西。我们希望以一种捕捉可解释性的方式构建模型,而不仅仅是追溯潜在变量到观察到的数据,以找到它们之间的相关性。我们希望我们的模型能够灵活地适应新的数据。
- 易处理模型的局限性之一是,它是完全确定的,因为潜在变量是易处理的。这也意味着模型是严格刚性的。如果输入的新数据有异常值,它可能表现不好。这是真实世界数据的主要问题。
- 我们需要建立足够灵活的模型来解决这类问题。我们不是要找到精确的易处理的潜在变量,而是要找到处于近似推理分布下的潜在变量。
这类模型属于难处理模型的范畴。
在一个难以处理的模型中,后验概率分布近似为 p(z|x ),或者通过我们在神经网络中喜欢的变分推断,或者通过我们在概率图形模型中经常使用的马尔可夫链蒙特卡罗方法。蒙特卡罗方法被证明是计算昂贵的,因为它试图从整个分布中找到精确的样本,而变分推断试图使用优化技术用易处理的分布来近似后验分布[Ian Goodfellow,Deep learning]。
我们用变分后验 q (z|x)来逼近精确后验 p(z|x)。是变分参数,我们将对其进行优化,以使变分后验符合精确后验。变分后验概率是从均值和标准差分别为 0 和 1 的标准正态分布中采样得到的。样本是随机选取的,因此使得模型难以处理。
变分推理模型由两个重要部分组成:
易处理的组件,它们是可微分的和连续的,使模型具有确定性,
难以处理的组件,这使得模型具有灵活性和概率性。
因此,我们可以定义一种称为重新参数化技巧的技术,建议我们从单位高斯随机采样ε,然后将随机采样的ε移动潜在分布的均值μ,并通过潜在分布的方差σ对其进行缩放。由于和易于处理,我们使用反向传播技术来优化参数,从而找到精确的后验概率。
这种方法使模型更加灵活,我们可以使用任何架构来生成样本。
- KL 发散
- Kullback-Leibler 散度或相对熵是两个分布之间差异的度量。在概率统计中,我们经常会用更简单的近似分布来代替观察数据或复杂的分布。KL 散度帮助我们测量当我们选择一个近似值时,我们损失了多少信息。
VI 的一般思想是从一个易处理的分布族中取一个近似值 q(z) ,然后使这个近似值尽可能地接近真实的后验 p(z|x)。这通常通过最小化两种分布之间的 Kullback-Leibler (KL)散度来实现,定义如下:
这减少了对优化问题的推断[5]。 q(z) 和 p(z|x) 越相似,KL 散度越小。请注意,这个量不是数学意义上的距离,因为如果我们交换分布,它就不是对称的。此外,在我们的例子中,交换分布意味着我们需要得到关于 p(z|x) 的期望,这被认为是难以处理的。
现在,上面的方程在对数的分子中仍然有难以处理的后验概率。
我们知道后验分布的公式:
因此,我们可以重写:
边际可能性 logp(x) 可以从期望值中取出,因为它不依赖于 z 。量 F(q) 就是所谓的证据下界(ELBO)。KL 总是≥ 0,因此它代表证据的下限。ELBO 越接近边际似然,变分近似就越接近真实的后验分布。复杂的推理问题被简化为更简单的优化问题。
变型自动编码器
变分自动编码器,或 VAE[金玛,2013;Rezende 等人,2014],是一个生成模型,它使用学习的近似推理生成连续的潜在变量[Ian Goodfellow,Deep learning]。它是自动编码器的改进版本。
自动编码器的局限性在于,它们学会了生成紧凑的表示并很好地重建它们的输入,但是除了像去噪自动编码器这样的一些应用之外,它们相当有限。
自动编码器的基本问题是,它们将输入转换到的潜在空间以及编码向量所在的位置可能不连续,或者不允许简单的插值。
另一方面,变分自动编码器有一个从根本上区别于普通自动编码器的独特属性,正是这个属性使它们对生成式建模如此有用:它们的潜在空间是设计成连续的,允许简单的随机采样和插值。
它通过使其编码器不输出随机潜在变量,而是输出两个向量来实现这一点:一个均值向量μ和另一个标准差向量σ(这将是模型的优化参数)。因为我们假设先验服从正态分布,我们将输出两个向量来描述潜在状态分布的均值和方差。
直观地说,均值向量控制着输入的编码应该集中在哪里,而标准差控制着“区域”,即编码可以偏离均值多少。
通过构建我们的编码器模型来输出一系列可能的值,我们将从这些值中随机采样以馈入我们的解码器模型,我们本质上是在实施一个连续、平滑的潜在空间表示。对于潜在分布的任何采样,我们期望我们的解码器模型能够准确地重建输入。因此,在潜在空间中彼此接近的值应该对应于非常相似的重构。
我们理想中想要的是编码,所有的编码彼此尽可能接近,同时仍然是不同的,允许平滑插值,并支持新样本的构造。
这个取样过程需要特别注意。
训练模型时,我们需要能够使用反向传播计算网络中每个参数相对于最终输出损耗的关系。我们不能对随机抽样过程这样做。VAE 实现这一点的方法是通过重新参数化技巧。使用这种技术,我们可以优化精确分布的参数,同时仍然保持从该分布中随机采样的能力。
变分自动编码器在生成样本方面取得了一些很好的结果,是生成建模的最新方法之一。它的主要缺点是从模型生成的样本有时会很模糊。原因的最明显结论是最大似然的内在效应,它使 DKL(pdata || pmodel)最小化。这实质上意味着模型将高概率分配给训练集中出现的点,以及可能导致模糊图像的其他点[Ian Goodfellow,Deep learning]。
甘斯
生成对抗网络或 GANs【good fellow 等。,2014]是另一种类型的生成模型,利用了不同的方法。
生成性对抗网络是基于博弈论的,其中两个网络——生成者和对抗者——相互竞争。生成器 Gis 是一个定向潜在变量模型,其确定性地从 z 生成样本 x,鉴别器 D 是一个函数,其工作是从真实数据集和生成器中区分样本。
生成器网络直接产生样本,而它的对手鉴别器网络试图通过返回一个概率值来区分从训练数据中提取的样本和从生成器中提取的样本,该概率值表示该样本是真实的训练样本还是从模型中提取的假样本。
GAN 可以与强化学习进行比较,其中生成器从鉴别器接收奖励信号,让它知道生成的数据是否准确。
在训练期间,生成器试图更好地生成看起来真实的图像,而鉴别器则训练更好地将这些图像分类为假图像。当鉴别器不再能够区分真实图像和赝品时,该过程达到平衡。
生成器模型将固定长度的随机向量作为输入,并生成从高斯分布中随机抽取的样本,该向量用于生成过程的种子。训练后,这个多维向量空间中的点将对应真实数据中的点,形成数据分布的压缩表示作为潜在变量。这个过程是有差别的和连续的。
在核心处,该模型像任何其他生成模型一样发现潜在的特征,然后可以以不同的方式利用这些特征来产生新的图像样本。
在 GANs 的情况下,生成器模型将意义应用于所选潜在空间中的点,使得从潜在空间中提取的新点可以被提供给生成器模型作为输入,并用于生成新的不同的输出示例。
另一方面,鉴别器模型将来自领域的示例作为输入(真实的或生成的),并预测真实或虚假的二进制类别标签(生成的)。真实的例子来自训练数据集。生成的示例由生成器模型输出。
鉴别器是一个正常的分类模型。
在训练期间,鉴别器应该识别真实图像,因此 D(x) 应该接近 1,并且它还应该能够识别来自 z 的伪生成图像,因此 D(G(z)) 应该接近 0。
根据这个等式,我们希望最大化鉴别器函数,同时最小化发生器函数。
如前所述,GAN 是一个微分模型,这意味着发电机模型中的参数可以使用梯度下降进行自我更新。同时,鉴别器模型使用梯度上升最大化损失函数。
在训练过程之后,鉴别器模型被丢弃,因为我们对生成器感兴趣。
{XXX}2vec 型号
到目前为止,我们一直关注非结构化数据以及如何从中提取表示。但是,对结构化数据执行机器学习是复杂的,因为这种数据没有矢量形式。出现了多种方法来构造结构化数据的矢量表示,从核和距离方法到递归、递归和卷积神经网络。其中一个过程被称为嵌入。
嵌入是从输入数据中学习另一组向量值,并通过另一组向量表示原始实际向量的过程。在神经网络的上下文中,嵌入是低维的,学习离散变量的连续向量表示。
神经网络嵌入是有用的,因为它们可以减少分类变量的维度,并在转换的空间中有意义地表示类别。
如前所述,传统的机器学习主要关注如何解决确定性问题的分类或回归等问题,使用手动设计的数据表示 [Bengio 等人,2013]。相比之下,表征学习首先关注的是获得矢量表征的挑战,这样先前的任务就变得容易解决[Bengio 等人,2013]。这种类型的方法有助于处理结构化数据,即序列、树和图,其中矢量表示不立即可用[Hamilton 等人,2017b]。
我想提一下经常使用嵌入的两个领域,一个是语言——自然语言处理——另一个是推荐系统。
嵌入技术包括:
矩阵分解
Word2Vec
xxx2vec
矩阵分解用于去除相似的特征向量。包括项目向量、用户向量、用户偏好向量。它主要用于推荐系统。
word2vec 对于做自然语言处理的人来说自然是再熟悉不过了。顾名思义,word2vec 将单词编码成向量。例如,单词“腹泻”被编码成[0.4442,0.11345]。
Word2Vec 是一种用于从大量文本语料库中以无监督的方式学习语义知识的模型,广泛应用于自然语言处理(NLP)。输入被一次性编码,然后输入到神经网络中,然后它使用这些向量来表征单词的语义信息,通过嵌入空间(潜在空间)学习文本,使语义相似的单词在该空间中非常接近。
- 在 Word2Vec 中,主要有两种模型:Skip-Gram 和连续词袋(CBOW)。从直观的理解来说,Skip-Gram 是一个给定的输入词,用来预测上下文。CBOW 是在给定上下文的情况下预测输入单词。
- 2vec 有许多变体,也称为 xxx2vec:
- Node2vec
Struc2vec
Metapath2vec
这些都是标题为图结构上的表示学习的变体。这些算法被设计成保留向量空间中的信息。邻近关系在邻近向量网络中是重要的。所有信息都被赋予一定的权重,这些权重相互聚集在一起。因此,如果我们能够提取重要的特征或表示,那么我们随后的任务就变得更容易和更准确。
未来进展面临的挑战
- 创成式建模是一种直观的方法,用于在缺少数据的情况下生成样本。大多数情况下,这些场景发生在医学扫描或其他非常隐私的数据中,不应该向公众开放。因此,使用生成模型,我们可以创建数据样本,这些样本可以由各个领域的专家进行评估。由于所有深度学习模型都严重依赖输入数据的表示,我们必须确保:
- 数据应该尽可能的干净。例如,我们必须确保数据由该领域的专家精心管理,以便提取的表示非常有效并生成良好的样本。
- 模型的架构不应过于宏大或平淡无奇。
对于复杂的数据,使用表达模型来避免欠拟合。同样,对于简单数据,使用简单模型以避免过度拟合。
由于生成模型在生成超高清样本方面并不完美,不同的模型应该结合起来,以利用它们的互补优势。
我希望你能从这篇文章中学到一些新东西。感谢您的阅读!
Generative modelling is an intuitive method for generating samples when there is a lack of data to work with. Most of the time these scenarios happen in medical scans, or other data that is very private, and should not be given access to the public. So using generative models we can create samples of data, and those can be evaluated by the experts in the respective fields. Since all deep learning models rely heavily on representation of the input data, we have to make sure that:
- Data should be as clean as it can be. For instance, we must make sure the data is carefully curated by experts in the field, so that representation extracted is highly effective and generates good samples.
- **Architecture of the model should not be overwhelming or underwhelming. **
- For complex data use an expressive model to avoid underfitting. Similarly for simple data use a simple model to avoid overfitting.
- Since generative models are not so perfect in terms of producing ultra high definition samples, different models should be combined to take advantage of their complementary strengths.
I hope you learned something new from this article. Thank you for reading!
部署期间的再培训模型:持续培训和持续测试
培训、测试和部署–就这样,对吗?你的工作完成了吗?不完全是!
数据科学家在机器学习方面犯的最大错误之一是,他们假设他们的模型在部署后将永远保持正常工作。但是那些不可避免会不断变化的数据呢?一个部署在生产环境中并任其发展的模型将无法独自适应数据的变化。
在 2020 年 8 月的一项英国银行调查中,35%的受访银行家表示疫情对 ML 模型的表现有负面影响。像这样不可预测的事件是一个很好的例子,说明了为什么与静态验证和测试技术相比,对生产中的 ML 模型进行持续的训练和监控是非常重要的。
The impact of the pandemic on the performance of banks’ machine learning models | Source
在生产中部署您的模型
一家初创公司最近聘请你作为首席数据科学家,构建一个预测模型,确定某些城市的房价。您的模型性能指标看起来很棒,您的应用可以部署到生产环境中了。
Life cycle of a model deployed in production | Source
您成功部署了您的模型。下一步是什么?三件事:
- 模型服务
- 模型性能监控
- 模型再训练
模型服务
模型服务是模型在生产中被消费的过程。它因不同的业务用例而异。在您构建自动化的模型再培训管道之前,了解您的模型将如何在生产中被消费是很重要的。有几种方法可以将你的机器学习模型生产化,比如 模型即服务、模型即依赖、批量预测(预计算服务) 。
模型性能监控
模型性能监控是基于实时数据跟踪机器学习模型性能的过程,以便识别可能影响业务的潜在问题。一个好的模型监控管道应该监控模型的可用性、实时数据的模型预测和性能,以及 ML 系统的计算性能
模型再训练
在监控和跟踪您的模型性能之后,模型管理的下一步是重新训练您的机器学习模型。目标是确保生产中模型的质量是最新的。
如何持续监控生产中的模型?
现在您意识到部署不是模型管理的最后阶段,它只是开始。就像软件部署一样,您的代码是确定性的,将总是按照编写的那样运行,并且您的团队总是可以在软件上部署新功能。但在机器学习中,开发管道包括 3 个层次的变化:数据、算法(模型)和代码。
那么,当您在生产中部署您的模型时,您需要监视什么呢?
数据有效性
您需要监控您的模型在上游管道中接收的数据,因为“垃圾进,垃圾出”。您的模型对它接收的输入数据很敏感。如果生产数据中的定型数据的统计分布发生变化,模型性能将会显著下降。
要监控的主要数据质量问题:
- 数据模式
在重新训练您的模型之前,您需要验证您的输入数据符合预期的上游模式。这意味着您的下游管道步骤,包括数据处理和模型训练,应该与来自生产数据的模式完全相同。您可以使用 Python 断言方法 来验证您的模式是否符合预期的模式。
如果模式不符合预期的模式,数据科学团队可以更新管道来处理这些更改。这可能意味着从头开始重新训练一个新的模型来适应新的特性,或者仅仅意味着重新命名这些特性。
- 数据漂移
另一个需要注意的数据质量问题是数据漂移。这仅仅意味着数据的统计属性发生了变化。
模型验证
成功验证数据管道后,您还需要验证模型管道。模型管道在部署到生产环境之前经过验证。
模型验证步骤包括:
- 使用采用的指标和选择的阈值测试模型性能。在生产中监控模型性能非常重要。如果低于阈值,可以触发再培训作业。可以测试重新训练的模型。
- 模型元数据和版本控制。监控生产中的有效方式非常重要。在重新训练你的机器学习模型时运行一系列实验后,你需要保存所有的模型元数据,用于再现性。您的再培训管道应该将不同的模型版本和元数据与模型性能度量一起记录到元数据存储中。管理模型元数据的一个非常好的工具是 Neptune AI 。
- 一致的对手。随着机器学习领域的发展,企业开始采用机器学习应用程序作为中央决策者。在生产中监控模型的安全性是很重要的。一些机器学习模型,如信用风险模型,容易受到对抗性攻击。欺诈者总是在寻找不同的方法来欺骗一个准备识别可疑信用卡交易的模型。
- 模型基础设施。在部署到生产环境之前,您还需要监控模型基础设施与预测服务 API 的兼容性和一致性。
让我们来看看一些可用于持续监控的最佳工具。使用这些工具,您可以同时运行模型来测试它们在生产中的性能。
Neptune 是一个模型监控平台,允许您运行大量实验,并为您的 MLOps 工作流存储所有元数据。借助 Neptune,您的团队可以跟踪实验并重现有前途的模型。很容易与任何其他框架集成。使用 Neptune AI,您可以有效地监控您的模型管道。每个模型实验/运行都可以被记录。
Qualdo 是一个很好的工具,用于监控生产中的模型。您可以监控您的上游管道,以识别持续摄取过程中的数据问题。您还可以监控模型在生产中的性能,并从生产数据的预测中获得见解。Qualdo 还允许您设置警报,以在模型性能超过某个阈值时或在上游管道中发现数据漂移时提示您的团队。Qualdo 还允许您在 Tensorflow 中监控模型管线性能。
您可以阅读更多关于用于监控生产模型的最佳工具的信息点击这里。
现在您了解了如何在生产中持续监控您的模型。接下来呢?
什么是持续训练?
持续训练是机器学习操作的一个方面,它自动和持续地重新训练机器学习模型,以在数据被重新部署之前适应数据的变化。数据变更、模型变更或代码变更都可能触发重构。
为什么持续培训很重要?
我们将探讨为什么在花费了这么多时间培训和部署模型之后,您仍然需要在生产中更改模型。
机器学习模型会随着时间变得陈旧
一旦在生产中部署了机器学习模型,模型的性能就会下降。这是因为你的模型对现实世界的变化很敏感,而用户行为会随着时间不断变化。虽然所有的机器学习模型都会衰减,但是衰减的速度是随时间变化的。这主要是由数据漂移、概念漂移或两者共同造成的。
Model performance decays with time
听说过数据漂移吗?让我们探讨一下数据漂移的概念及其业务含义。
什么是数据漂移?
Consumer demand changes suddenly due to stay-at-home policy. | Image by Elena Samuylova Source
数据漂移(协变量移位)是生产数据的统计分布相对于用于训练或构建模型的基线数据的变化。由于以下原因,来自实时服务的数据可能会偏离基线数据:
- 现实世界的变化,
- 训练数据不代表总体,
- 数据质量问题,如数据集中的异常值。
例如,如果您使用从传感器收集的摄氏温度数据建立了一个模型,但单位更改为华氏温度-这意味着您的输入数据发生了变化,因此数据发生了漂移。
如何监控生产中的数据漂移
处理数据漂移的最佳方法是使用高级 MLOps 工具持续监控您的数据,而不是使用传统的基于规则的方法。基于规则的方法,如计算数据范围或比较数据属性以检测异常值,可能非常耗时,并且容易出错。
检测数据漂移可采取的步骤:
- 利用 JS-Divergence 算法识别实时模型输出中的预测漂移,并将其与训练数据进行比较。
- 比较上游和下游数据的数据分布,查看实际差异。
如上所述,你还可以利用 Fiddler AI 平台来监控生产中的数据漂移。
什么是概念漂移?
概念漂移是一种现象,你试图预测的目标变量的统计特性会随着时间的推移而改变。这意味着概念已经改变,但是模型不知道这种改变。
当你的模型对目标类的最初想法改变时,概念漂移就发生了。例如,你建立一个模型来对围绕某些话题的推文的积极和消极情绪进行分类,随着时间的推移,人们对这些话题的情绪会发生变化。属于积极情绪的推文可能会随着时间的推移演变成消极情绪。
简单来说,情感分析的概念已经漂移。不幸的是,你的模型会一直预测积极情绪为消极情绪。
数据漂移与概念漂移
显而易见,世界上每时每刻都在产生数据。随着从多个来源收集数据,数据本身也在发生变化。这种变化可能是由于数据的动态性质,也可能是由现实世界中的变化引起的。
如果输入分布发生变化,但真实标签没有变化(模型输入的概率发生变化,但给定模型输入的概率的目标类的概率没有变化),那么这种变化被认为是数据漂移。
同时,如果模型的标注或目标类发生了变化,这就是在给定输入数据概率的情况下目标类发生变化的概率。这意味着我们正在检测概念漂移的影响。数据漂移和概念漂移都会导致模型衰退,应该分别处理。
定义再培训策略
现在你明白为什么在生产中监控和重新训练你的机器学习模型很重要了。那么,你如何重新训练你的机器学习模型呢?
为了回答这个问题,我们先来看看在设计持续训练策略之前应该问的一些问题。
问题 | 答案 |
---|---|
一个模特应该什么时候再培训?
|
–定期培训 rn–基于绩效的触发器 rn–基于数据变化的触发器 rn–按需再培训
|
|
再训练需要多少数据?
|
–固定窗口 rn–动态窗口 rn–代表性子样本选择
|
|
应该再培训什么?
|
–持续学习 vs 迁移学习 rn–离线(批量)Vs 在线(增量)
|
|
重新训练后什么时候部署你的模型?
| |
这些问题的答案可以分别回答,并有助于确定采取的策略。对于每个问题,我们将提出不同的方法来符合持续交付的原则。
你应该什么时候重新培训一个模型?
在重新训练机器学习模型之前,了解您的业务用例非常重要。一些用例对您需要重新训练您的模型的时间和频率有很高的要求。像欺诈检测和搜索引擎排名算法这样的业务用例需要频繁的再培训。就像根据行为数据训练的机器学习模型一样,因为行为数据是动态的——而根据制造数据训练的机器学习模型需要较少的再训练。
选择再培训计划有四种不同的方法:
- 基于区间的再训练
想知道如何安排您的模型再培训-每周,每月或每年?嗯,定期训练是重新训练你的模型的最直观和直接的方法。通过选择重新训练模型的时间间隔,您可以知道何时触发重新训练管道。这取决于你的训练数据更新的频率。
只有在与您的业务用例一致的情况下,基于时间间隔重新训练您的模型才有意义。否则,随机周期的选择将导致复杂性,甚至可能给你一个比先前模型更差的模型。
- 基于绩效的触发器
在生产中部署您的模型之后,您需要确定您的基线度量分数。在这种方法中,重建的触发是由于生产中模型性能的下降。如果你的模型性能低于你设定的阈值,这是事实,这将自动触发再培训管道。这种方法假设您已经在生产中实现了一个复杂的监控系统。
依赖模型在生产中的表现的缺点是,它需要时间来获得地面真相。在贷款/信贷模型的情况下,可能需要 30-90 天才能获得基本事实。这意味着,你需要等到得到结果后,再启动再培训工作,在大多数情况下,这可能会影响业务。
这种方法非常适合那些不需要很长时间就能获得基本事实的用例。您可以实时监控模型预测
Trigger retraining Machine learning models based on performance | Source
从上面的图像中,你可以看到 9 月份部署的机器学习模型的性能随着时间的推移不断下降。
- 基于数据变化的触发
通过监视生产中的上游数据,您可以确定数据分布的变化。这可能表明您的模型已经过时,或者您处于一个动态的环境中。当您无法从生产中的模型获得快速反馈或基本事实时,这是一个值得考虑的好方法。
您还可以将这种方法与基于性能的触发器结合使用。数据漂移是您的模型性能在生产中下降的一个主要原因,并且在任何情况下都可能导致您的模型性能低于您接受的性能阈值。这将自动触发模型再训练的构建。
Retraining machine learning models based on changes in datas | Image by Vidhi Chugh Source
这是一种手动重新训练模型的方法,通常采用传统的技术来重新训练模型。大多数创业公司在重新训练他们的模型时使用这种技术,这是一种启发式方法,可能会提高你的模型性能,但不是最好的。在生产环境中,您的机器学习操作应该是自动化的。
再培训需要多少数据?
我希望现在你已经清楚什么时候你需要重新培训你的模型,以及为什么要选择一个重新培训计划。了解如何选择正确的数据来重新训练模型,以及是否删除旧数据也很重要。
选择合适的数据大小时需要考虑三件事:
- 您的数据有多大?
- 你的数据在漂移吗?
- 你多久得到一次新数据?
固定窗口大小
这是一种选择定型数据的直接方法,也是一种考虑定型数据是否太大而不适合的方法,并且您也不想在历史数据上定型模型。通过选择 X 个月的数据来重新训练模型,您应该记住重新训练模型的频率。
选择合适的窗口大小是使用这种方法的一个主要缺点,因为如果窗口大小太大,我们可能会在数据中引入噪声。如果太窄,可能会导致不合身。例如,如果您已经决定基于您的业务用例定期重新训练您的模型,那么您应该在重新训练间隔之前选择数据。
总的来说,这种方法是一种简单的启发式方法,在某些情况下效果很好,但在数据不断变化的动态环境中会失败。
动态窗口大小
这是固定窗口大小方法的替代方法。这种方法通过迭代窗口大小来确定要使用的最佳窗口大小,从而帮助确定应该使用多少历史数据来重新训练您的模型。如果您的数据很大,并且您也经常获得新数据,那么这是一种值得考虑的方法。
假设您在 100,000 条记录上训练了您的模型,现在您有 5000 条新记录可用。您可以将这 5000 条新记录作为您的测试数据,旧数据集的一部分或全部可以作为您的训练数据,这取决于在进行网格搜索以选择正确的窗口大小之后测试数据上的最佳模型性能。将来,在与测试数据进行比较之后,可以根据性能选择不同的窗口进行再训练。
Using dynamic window size to select the best training data | Source
虽然动态窗口大小方法消除了从什么窗口大小中选择的挑战,并且更加数据驱动,但是它也像固定窗口大小方法一样给予新数据更多的优先权。它是计算密集型的,并且需要大量时间来达到完美的窗口大小。
代表性子样本选择
这种方法使用与生产数据相似的训练数据,这是重新训练机器学习模型的基本思想。为了实现这一点,您需要首先对您的生产数据进行彻底的分析,并排除表明存在漂移的数据。然后,您可以选择代表总体并且与原始数据的统计分布相似的数据样本。
应该重新培训什么?
例如,您在生产中部署了您的模型,并且还构建了一个监控系统来实时检测模型漂移。在观察到模型性能下降后,您选择了基于您的业务用例的重新训练策略。现在你只剩下应该训练什么了。有不同的方法来重新训练你的模型,最好的方法取决于你的用例。
持续学习与迁移学习
持续学习
持续学习也称为终身学习。这种类型的学习算法试图模仿人类的学习。机器学习算法被应用于数据集以产生模型,而不考虑任何先前学习的知识,并且随着新数据变得可用,连续学习算法随着时间对机器学习模型进行小的一致更新。
为了更好地理解这个概念,让我们考虑一个用例,您正在为 Spotify 构建一个推荐系统,该系统会推荐用户感兴趣的歌曲。为了根据新的兴趣推荐新歌,你需要定期重新训练你的模型,因为用户行为会随着时间不断变化。
迁移学习
迁移学习是一种机器学习技术,它重用现有模型作为重新训练新模型的基础。
“迁移学习是通过从已经学习过的相关任务中迁移知识来提高在新任务中的学习”。— 第十一章:迁移学习 , 《机器学习应用研究手册》 ,2009 年
迁移学习的一个主要优势是模型能够被重新训练,而无需从头开始重建。这是一种优化技术,允许模型进行增量训练。它被广泛应用于深度学习算法中。
进一步阅读如何使用迁移学习-> 开发卷积神经网络模型时如何使用迁移学习
使用迁移学习和继续学习的利弊
迁移学习 | 持续学习 | |
---|---|---|
——知识的传递。该模型可以在新的任务/概念上进行训练——节省再训练时间
|
–培训后保留知识 rn–节省培训时间 rn–使模型自动适应 rn–提高模型性能
|
| |
—易受数据漂移影响——迁移学习仅在初始问题与模型试图解决的新问题相关时有效
|
——易受概念漂移
|
离线学习与在线学习
在线学习
离线学习又称为批量学习。你可能已经熟悉这种学习技巧,但可能不知道它的名字。这是建立机器学习模型的标准方法。基本上,您可以获得一个训练数据集,并立即在该数据集上构建模型。离线学习系统不能进行增量学习。一旦一个模型被部署到生产中,它就会应用它所学到的东西,并且不再需要学习就可以运行。
用离线学习重新训练你的模型意味着用更新的数据从头构建一个新的系统。这种方法简单明了,但是你需要考虑一个再培训策略,而想出一个再培训策略需要对业务目标有一个清晰的理解。
在线学习
也称为增量学习。在在线学习中,您通过顺序传递数据实例来增量地重新训练系统。这意味着当数据进来时,你正在重新训练你的模型。这种类型的学习使得重新训练更加容易,并且不需要假设数据是如何分布的。它没有考虑顾客行为的变化。
它也非常适合持续接收数据的系统,并且非常经济实惠。如果你的数据太大而无法容纳,在线学习是一个可以接受的折衷方案。在线学习帮助你的机器学习模型避免数据漂移。如果您的应用程序使用实时流数据,那么在线学习是一个不错的选择。
如何重新培训 scikit-learn 模型
一些 Sci-kit 学习算法支持在线学习。这些算法可以增量学习,而不必一次加载所有实例。这些估算器有一个叫做 partial_fit API 的方法。这对非核心学习有好处,而且保证了再培训的时间会很短。虽然一些 scikit-learn 模型不支持部分拟合,但一些算法可以允许您通过使用warm _ start参数进行重新训练。
支持增量学习的 scikit-learn 模型的示例可以在这里找到。
在线学习 | 在线学习 | |
---|---|---|
——简单明了的方法。
–如果使用各种窗口选择过程正确选择了训练数据,数据漂移的空间很小或没有
|
–节省大量培训时间 rn–不占用大量计算能力。
——性价比
|
| |
花费大量时间从零开始重新训练模型
|
——易受概念漂移的影响——与离线学习
相比,需要时间收敛到最小值 |
再培训后部署模式
耶!!!快好了。你现在一定很兴奋。您了解为什么您需要在生产中监控您的模型管道,以及何时触发您的再培训管道。现在你已经重新训练了你的机器学习模型,你的老板问“你什么时候部署新的模型更新?”。
您应该在重新培训后立即部署吗?
即使您已经重新训练了您的模型,并且性能指标看起来很好,更新的模型仍然有比以前的模型表现差的很大风险,即使在重新训练之后。
将旧模型留给特定的窗口或者直到模型服务了特定数量的请求,这是一个好的实践。然后你可以为新模型提供同样的数据并得到预测。这样,您可以比较两个模型的预测,以了解哪一个模型的表现更好。
如果你对新型号的性能满意,你可以放心地开始使用它。这是一个典型的 A/B 测试的例子,这将确保您的模型在上游数据上得到验证。
最佳实践是在重新培训后自动部署您的模型。您可以使用 kubernetes 将您的机器学习模型部署到生产环境中。
频繁重新训练模型的缺点
频繁再培训怎么会不好?在考虑重新训练你的模型之前,你应该有一个特定的业务用例和正确的重新训练策略。正确的策略并不总是意味着频繁的再培训。
频繁地重新训练你的模型会导致系统的复杂性或隐藏的成本,并且也容易出错。因此,应该在成本和业务目标之间取得平衡。与重新训练模型相关的一些复杂性或成本包括:
云解决方案的培训模型可能非常昂贵,而且需要大量时间。想象一下,必须每天在云 GPU 上重新训练您的模型,这将产生不必要的成本,因为重新训练模型并不一定意味着“提高模型性能”。
不同的团队参与了机器学习模型开发的生命周期,而不仅仅是数据科学团队。在部署新模型之前,它可能需要业务利益相关者的批准,然后机器学习工程师不得不担心在生产中部署它。
Disadvantages of retraining your models frequently | Source
这会导致延迟或摩擦。如果你没有一个先进的机器学习操作平台,这个特殊的用例是至关重要的。
如果您很少重新训练您的模型,那么很容易使用简单的系统架构。但是如果你频繁地重新训练你的模型,你必须设计一个更复杂的系统。您需要设计一个管道,在没有人工干预的情况下,重新培训、评估和部署您的模型到生产中。
生产中持续培训和持续监控的最佳实践
在建立任何机器学习模型之前,你需要有一个 MLOps 的思维模式。您的端到端管道应遵循四个关键 MLOps 原则:
- 自动化,
- 可重用性,
- 再现性,
- 可管理性。
有了这些原则,您一定可以保护您的模型免受不希望的性能下降,并且您的模型在生产中的质量是最新的。
通过自动化您的 ML 生命周期来构建、培训、部署和监控您的 ML 模型,您可以轻松地交付您的 ML 应用程序和商业价值。
您的端到端 ML 管道由 3 部分组成:
Image modified by the author and adapted from this source.
构建/CI 管道
这是作为代码部署的基础设施。CI 管道基于模板部署资源或依赖项。大多数数据科学家利用 docker 为他们的模型构建 docker 图像。除了构建包和可执行文件,您还可以测试您的代码质量,运行一些单元测试并测量您的模型延迟。如果这些测试是成功的,那么训练/释放管道是精心安排的。
列车/连续油管管道
这是从数据存储中提取数据、转换数据、创建和存储要素的管道。您可以在 CT 管线自动化过程中利用特征库。这是一个集中的地方,可以存储用于训练机器学习模型的精选功能。特征库让您在每次需要训练 ML 模型时重用特征,而不是重建这些特征。
发布/CD 管道
CI/CT 阶段产生的工件被部署到生产环境中。模型工件被打包和部署,以满足生产中的请求。应监控性能结果、数据漂移和数据质量,并建立良好的警报系统。此阶段的输出是一个已部署的模型预测服务。
最后的想法
现在我希望你明白持续培训的含义,以及为什么在生产中重新培训你的模型是重要的。不要在生产中部署您的模型并放弃。一旦您的模型被部署,模型性能就开始下降。
在选择再培训策略之前,您需要了解您的具体用例。然后你就可以考虑你要多长时间重新训练一次,如何重新训练你的模型,重新训练你的模型需要用什么数据,重新训练后什么时候部署你的模型。
您需要持续监控生产中的模型,并确保您的模型是最新的。这是确保长期性能的唯一方法。
参考资料:
- MLOps:机器学习中的连续交付和自动化管道
- 成功持续培训战略的框架
- 为什么您应该关注数据和概念漂移
- 数据漂移入门
- 关于如何监控生产模型的全面指南
- 机器学习(ML)操作加速器
- 概念漂移最佳实践
- 机器学习的连续交付
ML 团队中的角色以及他们如何相互协作
原文:https://web.archive.org/web/https://neptune.ai/blog/roles-in-ml-team-and-how-they-collaborate
开发成功的机器学习项目需要各种专业知识,因此,这是一项极其协作的工作。设计问题陈述需要公司提出关键问题,例如:
- 为什么要建立一个 ML 模型?
- 如何获取所需数据?
- 如何设计系统基础设施?还有更多。
ML 已经存在了一段时间,但是对于职称和随之而来的责任仍然有些混乱。在这篇文章中,我们将讨论一个 ML 项目的发展,角色如何在 ML 团队中分配,以及他们如何合作。
一个 ML 项目进展如何?
ML 团队中的角色与项目的设计非常一致。通常,在基于产品的公司中,情况是这样的:
设计什么功能/组件(需要 ML)?
产品经理,以及来自分析师和其他业务利益相关者的见解,决定可以从机器学习中受益的高影响力功能。
我们如何将业务问题设计成数据科学问题?
任何业务需求都需要转化为数据科学问题。例如,考虑一个在线时尚网站,它看到大量的服装被退回。分析师发现,这是因为他们在订购时倾向于选择较小/较大的尺寸。数据科学方法包括使用用户和产品信息训练模型,并推荐正确的尺寸。
然而,仅仅因为项目有意义,并不意味着公司应该直接追求它。业务团队首先估计运输 ML 模型将产生的节约量。最后,由于公司的人力资源有限,它必须决定与其他项目相比,这个项目在此时的可行性。这些决策基于公司的战略、愿景和计算出的投资回报率。
通常,公司中的高级和首席数据科学家与业务经理一起定义明确的数据科学问题。
我们有所需的数据和管道吗?
很多时候,甚至把一个问题框定为 ML 问题也是不够的。您需要确保您拥有正确的类型—数据的数量和质量,以及接收和存储数据的正确基础架构。这通常需要集成多个云服务、数据库和 API。在上面的例子中,您可能希望记录被退回的产品的详细信息,如年龄、性别、过去的购买情况等用户数据。在一个团队中,数据工程师对几乎所有关于数据存储在哪里以及如何处理的问题都有答案。
数据质量够好吗?
在上面的例子中,如果产品的图像质量和分辨率较低,将它们用作模型中的输入将不是最佳的。类似地,用户的身高、体重和偏好等属性可能会不断变化,或者有时他们会使用自己的帐户为他人点餐。因此,获取相关数据并不像看起来那么简单。分析师和数据科学家通常会检查数据,检查其形式是否正确。
需要什么样的注释和数据获取工作?
虽然在无监督学习和迁移学习方面已经取得了很大的进展,但是许多工业问题都是有监督的,需要大量的标注数据。注释也很棘手。注释猫和狗比注释一条推文的情感更容易,因为不同的注释者在这样做的时候会有自己的偏见。需要频繁注释工作的公司有专门的注释团队,或者他们将它外包给注释公司。
我们有资源(员工、计算、时间)来解决它吗?
随着应用 ML 中不同子领域( NLP 、 CV 、 RL 、Speech)越来越深入,单个数据科学家很难成为其中每一个领域的专家。这就是为什么大公司有多个数据科学团队,每个团队处理产品的一小部分。
如何向用户推出模型?
打电话。fit()和。predict()在笔记本上工作得很好,但是在现实生活中,在部署模型时有很多工程和用户体验方面的问题。例如,当用户打开应用程序时生成推荐可能会增加加载时间。相反,人们可能会选择在大多数用户不在应用程序上时更新推荐,并将其存储在他们的设备上。通常,ML 工程师和开发人员是这些工作的幕后推手。
我们跟踪哪些指标来衡量模型的成功?
也许要决定的最重要的事情是什么指标表明模型在其目标上是成功的。在我们的时装店示例中,我们将记录用户是否订购了我们推荐的尺寸的服装。不管是哪种情况,他都归还物品了吗?如果他接受了建议,但仍然因为尺寸不正确而不得不退货,那么我们的模型就犯了一个错误。同样,如果他/她没有接受我们的建议,也没有回来,我们的模型可能也犯了一个错误。度量标准是在项目一开始就决定的。
ML 团队中的角色
一个人无法回答上述所有问题。因此,成熟的 ML 团队通常由以下人员组成:
- 数据分析师
- 数据工程师
- 数据科学家
- 研究/应用科学家
- ML 工程师
- 开发商
我们将详细讨论这些角色。
数据分析师–他们与产品经理和业务团队密切合作,从用户数据中获得洞察力,然后用于驱动产品路线图。通常,他们使用 SQL、Excel 等工具,以及 Tableau 和 Power BI 等一系列数据可视化工具。他们的核心技能包括使用描述性统计和推断性统计来分析数据。他们的角色是根据他们的职能划分的。例如,营销分析师将分析公司的营销努力和成果,而风险分析师将分析信用卡欺诈模式。
数据工程师–数据工程师确保收集、转换/处理和存储数据的基础设施建设完善。他们管理来自应用程序的数据如何在数据库和其他存储之间接收和传输,他们的关键技能包括使用 Spark 或 Hadoop 等工具来处理大量数据。他们还与云平台合作建立数据仓库。此外,他们还负责 ETL (Extract Transform Load)作业,这实质上意味着从数据源获取数据,对其进行处理,并将其存储在数据仓库中。由于他们处理密集的计算任务,他们通常被期望了解分布式系统的基础知识、数据结构和算法。
数据科学家——这是每个人的最爱,主要是因为它被过度使用了。通常,他们负责分析、处理和解释数据。数据科学家还使用高级统计数据从中获得见解,并将他们的发现传达给业务利益相关者。此外,他们建立 ML 模型,成为产品的一部分。根据工作范围的不同,他们需要了解统计学、SQL、Python/R 和机器学习。
研究科学家——专注于前沿技术的公司通常都有这个角色。一般来说,研究科学家为各种产品相关领域开发新算法。虽然,他们不一定需要将他们的工作转化为生产模型。研究科学家通常在 NLP、计算机视觉、语音或机器人方面有一些专业知识,他们通过博士学位或丰富的研究经验获得这些知识。他们的工作要求他们进行研究,发表论文和解决困难的研究问题。
机器学习工程师(Machine Learning Engineer)——他们的工作与数据工程师的工作有所重叠,但他们主要专注于 ML 模型和相关的基础设施。他们的工作是为最终用户构建更新模型和创建预测界面的工具。他们与数据科学家密切合作,部署他们制作的模型。ML 工程师利用云服务以及 Cortex 或 FastAPI 等开源部署库来创建端点。他们的工作通常跨越多个部署场景,如云、本地、边缘部署。为了处理可伸缩性,他们通常需要了解 Docker 和编排平台,如 Kubernetes。
开发者–你有你的模型,你有你的结果,你有你的基础设施。现在怎么办?拼图的最后一块,可以说是最重要的一块,是将所有东西与主应用程序集成。这就是你需要后端开发者的地方。他们经常设计 API 并将模型预测格式化成用户友好的东西。
初创企业中的 ML 团队
在谷歌或亚马逊这样的成熟公司,找到这些特定的角色是很常见的。然而,如果你在一家较小的创业公司工作,你可能找不到单独的研究科学家或 ML 工程师。在这样的公司中,一个或多个数据科学家被期望处理几乎所有的组件——分析、模型开发和部署。你可以称这样的人为全栈数据科学家。
这样的设置有利有弊。一方面,公司节省了成本,因为给某人多付一点钱比给每个零件雇佣多个员工要便宜。此外,如果你在这样的公司工作,你可以学到广泛的技术技能。此外,在较小的团队中,沟通更容易。另一方面,让不同的人专门负责项目需求的不同部分,可以确保您获得具有最佳实践的高质量工作。
ML 团队如何协作?
我们现在对 ML 项目的进展有了一个清晰的概念。但是他们如何交流和管理他们的工作流程呢?有一些工具是专门为协作而制作的。
像 slite、conception 和 google docs 这样的工具有助于维护项目、范围、需求和责任的文档。与团队合作需要获得共同的真理来源。
通常,软件和 ML 团队创建详细的文档(有时称为业务需求文档或 BRD ),概述特定项目的确切结果和目标。这种做法有助于让所有人达成共识。
例如,如果一家公司想开始更新一个现有的推荐系统,他们需要集思广益整个项目指南。从当前推荐系统的状态、当前指标开始,公司希望在这个新版本中关注哪些问题,以及谁将参与该项目。像 Slite 和 concept 这样的工具允许用户创建表格、看板、清单以及格式良好的标题和段落。一旦每个人都清楚了背景,就分配了角色和职责,项目时间表也就确定了。
如果你是开发者,你一定知道 GitHub。有数以百万计的开源项目,被全世界数以百万计的开发者所使用。任何受欢迎的项目在世界各地都有成百上千的贡献者。想象一下 GitHub 让代码协作变得多么容易。
它不仅帮助您推送代码和提交 PRs,还处理您的 CI/CD 负载,并使您能够就问题和代码相关文档进行协作。
MLOps 元数据存储–Neptune . ai
与开发人员不同,数据科学家不仅需要跟踪他们的代码,还需要跟踪各种 ML 实验、超参数和不同版本数据集的结果。neptune.ai 允许他们使用与流行的 ML 库和超参数调优框架无缝集成的客户端 API(仅使用几行代码)来跟踪所有这些。
此外,Neptune 还提供了对模型、数据集进行版本化和日志记录的功能,并为自动化部署创建了自己的 CI/CD 管道。
该平台为您记录指标、CPU/GPU 利用率、代码和模型文件,以便您将更多精力放在实验上。
了解更多关于海王星的特征。
最后的想法
总之,ML 生态系统已经发展到足以识别 ML 项目中涉及的关键角色和职责。然而,根据公司的类型和规模,每个职位的工作范围会有所不同。如果您正在工作或寻求建立您的团队或提高团队产出,有许多工具和角色结构可供选择,通过允许更容易的团队间和团队内协作,可以使工作流更有效。
参考
如何让你神圣的项目易于分享和协作
原文:https://web.archive.org/web/https://neptune.ai/blog/sacred-projects-easy-to-share-and-collaborate-on
冗长的电子表格详述混乱的人工授精实验的日子已经一去不复返了。有了神圣这样的平台,你就可以安心的记录实验了。神圣为您做了有益的工作:它跟踪您的参数、模型架构、数据集变更、培训工作、工件、度量、元、调试等等。
本质上,Sacred 是一个 Python 模块,允许您配置、组织、记录和再现实验。这样,您可以:
- 轻松管理您的实验参数
- 为你的实验做些设置
- 在 MongoDB 数据库中保存单次运行的配置
- 复制结果
神圣的带有一个强大的命令行界面,在那里你可以改变参数,进行不同的实验和变种。通过它的“观察者”,它可以记录实验的各种细节——如依赖关系、配置、使用的机器或结果。这些信息可以进入数据库或其他实验跟踪工具。
有陷阱吗?好吧,尽管它很有价值,但神圣并没有一个完整的用户界面或关键的实验来追踪功能。
这就是 Omniboard 的用武之地。Omniboard 是神圣的孪生兄弟——你不能缺了一个使用另一个。Omniboard 是一个 NodeJS 服务器,连接到神圣的数据库,并可视化实验+指标/日志。您可以:
- 通过表格或列表视图访问实验管理功能
- 对比实验
- 审查关于实验的详细数据,例如度量图、源文件、工件或 git 散列/版本控制信息。
神圣和全能的结合可能是强大的,但是它们缺乏有价值的功能,而这些功能对于大规模团队来说是至关重要的。例如:
- 详细团队协作的特性
- 显示笔记本版本或笔记本自动快照的用户界面
- 可以保存实验视图或分组实验的用户界面
- 可以扩展到数百万次运行的用户界面
- 专门的用户支持
然而,不要失去希望。你可以很容易地获得所有这些功能,以及你所知道和喜爱的神圣功能。
介绍海王星
Neptune 是一个轻量级的 ML 实验管理工具。它灵活且易于与不同的工作流程集成。您的队友可以使用任何 ML 库和平台,共享结果,并在单个 Neptune 仪表板上进行协作。如果不想在自己的硬件上部署,可以使用他们的 web 平台。
海王星的主要特征是:
- 实验管理:跟踪你团队的所有实验,并对它们进行标记、过滤、分组、排序和比较
- 笔记本版本和区分:比较两个笔记本或同一笔记本中的检查点;与源代码类似,您可以进行并排比较
- 团队协作:添加评论,提及队友,比较实验结果
更多详情请看- > 海王 vs 圣物+全能
海王星+神圣整合
Omniboard 是神圣的流行前端——然而,正如我们上面讨论的,它缺乏许多关键特性,特别是对于协作。另一方面,Neptune 让您继续使用神圣的日志 API,同时提供其圆滑、直观的 UI。这是 Omniboard 更实用的替代品。
在与 Sacred 集成时,Neptune 用自己的 Observer 替换了 MongoDB 后端。这样,您就不必建立数据库。你所有的数据都可以记录到云端或者本地,随你怎么想。
现在我们来看一下如何同步它们:
Neptune 设置(如果您已经有一个 Neptune 帐户,请跳过)
-
先注册一个海王 AI 账号。它对个人和非组织都是免费的,你可以获得 100 GB 的存储空间。
-
通过点击右上角的菜单获取您的 API 令牌。
-
创建一个 NEPTUNE_API_TOKEN 环境变量,并在控制台中运行它。export NEPTUNE _ API _ TOKEN = ' your _ API _ TOKEN '
-
创建一个项目。在您的项目仪表板中,单击“新建项目”并填写以下信息。注意隐私设置!
综合
首先,您需要安装您的 neptune 客户端:
pip install neptune-client
确保创建一个实验:
ex = Experiment('iris_rbf_svm')
然后,传递实验对象作为第一个参数:
from neptunecontrib.monitoring.sacred import NeptuneObserver
ex.observers.append(NeptuneObserver(api_token='ANONYMOUS',
project_name='shared/sacred-integration'))
确保用您自己的 API 令牌替换“ANONYMOUS ”(参见上文!)和项目名称。
在那之后,简单地像平常一样运行你的实验。现在,他们将在海王星训练!
与海王星合作
您的实验元数据现在应该存储在 Neptune 中,您可以在您的实验仪表板中查看它:
您可以通过添加标签和使用自定义过滤器对实验进行分组来自定义仪表板。
Neptune 让你只需发送一个链接就可以分享 ML 实验。它可以是:
Neptune 还带有工作区,一个你可以管理项目、用户和订阅的中心枢纽;有个人和团队工作空间。
在团队工作区中,团队成员可以浏览与其分配的角色相关的内容。您可以在项目和工作区中分配各种角色。在团队工作区中,您可以邀请管理员或成员,每个人都有不同的权限。
可以在顶栏上的工作区名称中更改工作区设置:
在概述、项目、人员和订阅选项卡下,您可以看到工作场所设置:
项目中有三个角色:所有者、贡献者和查看者。根据角色的不同,用户可以运行实验、创建笔记本、修改以前存储的数据等。
更多详情参见- > 用户管理
了解更多关于海王星的信息
如你所见,海王星很好地补充了神圣。您可以轻松替换 Omniboard 并添加 Neptune Observer 来解锁更多功能。海王星可以作为一个中心枢纽来管理你的实验,并与你的团队合作。
如果你想了解更多关于 Neptune 的知识,请查阅官方文档。如果你想尝试一下,创建你的账户,开始用 Neptune 跟踪你的机器学习实验。