在机械进修社区,越来越多的人开始讨论研究的可复现性,但这些讨论大部分局限于学术环境。如何确保消费环境的ML可复现?近日,机械进修开发办事提供商 maiot.io 的 CTO Benedikt Koller 发布一篇博客文章,介绍了他鉴于自身经验归纳的开发可复现消费级机械进修所要注意的 12 个要素。过去二十年来,我们对软件开发的懂得有了大幅提升。其中一大部分原因是 DevOps 概念的出现及其在软件开发行业的广泛应用。领先的软件公司都遵循着同样的模式:首先是在软件开发过程中快速迭代,然后举行继续集成、继续交付、继续布置。每个特性都要经过尝试,看其提供价值的能力如何,而且软件始终要处于就绪的状态,并且通过自动化法子举行布置。机械进修这个领域虽不同于传统的软件开发,但我们也能从软件开发行业汲取很多实用的经验教训。过去几年里,我们一直在开发消费型机械进修项目。我们的目标并不只是概念验证,而是与软件开发一样的可复现能力(reproducibility)。因此,我们建立了一套过程协调器、强大的自动化能力并建立了一套用于实现该目标的工作过程。为什么不直接使用 Jupyter Notebook?从头开始建立一组包含所有处理步骤的笔记需求多长时间?为团队纳入新成员的难易程度如何?你现在可以复现两个月前的结果吗?能以多快的速度复现?你能将今天的结果和历史结果举行对比吗?你能在训练过程中关注到数据的出处吗?如果你的模型过时了又会发生什么?我们遇到过所有这些成绩。现在,我们将这些经验举行了归纳归纳,得到了成功建立消费型机械进修的 12 个要素(类似于软件开发中的十二要素应用/12 factor app)。1. 版本控制对软件工程师来说,版本控制基本上是理所当然需求做的,但是这一法子论还尚未被数据科学家广泛接受。让我引述一下 Gitlab 上一些人的说法:版本控制可促进整个软件开发团队之间的协调、共享和协作。版本控制软件让团队可以在分布式和异步环境中工作、管理代码和文件的修改和版本以及解决合并冲突和相关异常。简单来说,版本控制能让你安全地管理软件开发中会变化的部分。机械进修其实是一种特殊的软件开发,有着自己特定的要求。首先,机械进修中会变化的部分不止一种,而是两种:代码和数据。其次,模型训练的方式是(快速)迭代,并且代码中的差异会很大(比如拆分、预处理、模型)。只要数据发生更改,就需求保存一个版本,这样才能保证能复现结果以及重复执行尝试和训练模型。简单粗暴的版本控制(硬拷贝)具有很大的改进空间,不过尤其是在团队共享的情况下,能够保持不变的版本控制是至关重要的。代码的版本控制还要更加重要。除了上面引述的内容,预处理代码不仅在训练阶段很重要,而且在办事阶段也很重要,需求与模型有保持不变的相关性。为了在数据科学家的工作过程和投入消费的要求之间建立一种中台,一种方便的法子是提供无办事器的功能。归纳:你需求对代码举行版本控制,也需求对数据举行版本控制。2. 明确的特征依赖关系在理想世界中,产生你的输入数据的东西应该总是会产生同样的数据,至少结构上是这样。但这个世界并不是完美的,你从上游办事获取的数据也是由人类建立的,因此可能会发生变化。最终,特征也可能发生改变。最好的情况是你的模型会直接故障报错,但还有最坏的情况:你的模型悄悄继续工作,但得到的结果都是垃圾。明确定义的特征依赖关系能够尽快揭示出失败案例。如果系统设计得好,还能在办事时举行继续训练,然后调整依赖关系并加以适应。归纳:明确代码中的特征依赖关系。3. 描述性的训练和预处理优良的软件都有优良的描述和注释——让人无需阅读每一行代码就能轻松阅读和懂得代码功能。尽管机械进修是一类特殊的软件开发,但它并不鼓励实践者背离已有的代码书写准则。在代码书写标准中,最基本的一条是能让人在短时间内不费力地阅读。预处理和模型的代码都应该遵循 PEP8 规范。代码中应当使用有意义的对象名并包含有助于懂得的注释。遵循 PEP8 规范可提升代码的可读性,降低复杂度并加快调试速度。SOLID 之类的编程范式提供了经过深思熟虑的框架,可让代码在未来用例中的可维护性、可懂得性和灵活性都得到改善。配置应该与代码分离。不要将数据分配比例硬编码到代码之中,而是通过配置方式提供,以便在运转时修改。人们在超参数调节方面已经熟知这一点了:使用分离的配置文件可以显著加快迭代速度,并且让代码库可以重复使用。归纳:提升代码可读性并且将代码和配置分开。4. 训练结果的可复现性如果你不能复现训练结果,那么这个结果就是不可信的。尽管这是本文的主题,但在可复现性方面有一些细节需求说明。不仅是你自己需求能复现训练结果,你的整个团队都要能做到这一点。不管是在 PC 还是在 AWS 虚拟机上,模糊处理 Jupyter Notebook 中的训练结果都与可复现性背道而驰。通过设定训练的工作过程,整个团队都可以透明地访问已执行的尝试和已运转的训练。通过绑定可复用的代码库以及分离的配置文件,每个人都可在任何时间成功重新训练。归纳:使用管道式工作过程和自动化。5. 尝试尝试的形式有很多。举两个例子:1)单元尝试是原子层面上的尝试——鉴于各自的标准单独尝试每个函数和功能。2)集成尝试则相反,是将代码库的所有元素都放到一起举行尝试,同时还会尝试上下游办事的克隆版本或模拟版本。这两种范式都适应于机械进修。预处理代码是预先确定的,直到尝试阶段——这样的转换能在不同的输入下都得到正确结果吗?模型是集成尝试的一个绝佳案例——在消费环境中提供办事时,你的模型的表现是否与评估时相当?归纳:尝试你的代码,尝试你的模型。6. 偏移与继续训练在消费场景中,任务发生偏移是合理存在的成绩。只要数据存在变化的可能性,你就需求考虑偏移的可能性。对于此成绩的风险,有两种可以采取的措施:1)监控消费系统中的数据。建立自动化报告机制,在数据发生变化时通知团队,这种变化甚至可能超过明确定义的特征依赖关系。2)鉴于新输入的数据继续训练。良好自动化的管道化过程可以鉴于新数据重复运转,然后与历史训练结果举行对比,展示性能变化情况以及将训练得到的模型快速投放到消费中,从而让模型表现更好。归纳:如果你的数据会发生变化,那就采用一种继续训练的管道化过程。7. 跟踪结果Excel 并非一种跟踪尝试结果的好法子。而且还不只是 Excel,任何分散的人工跟踪法子得到的信息都是不够权威的,也因此是不可信的。正确的做法是以一种中心化的数据存储方式自动记录训练结果。自动化能够保证可靠地跟踪每次训练,从而方便之后对比每次训练的结果。对结果举行中心化存储,能为团队提供透明,实现继续性分析。归纳:通过自动化法子跟踪结果。8. 尝试模型与消费模型我们需求努力才能懂得数据集。通常来说,我们会通过尝试来实现懂得,尤其是当我们关注的领域具备大量隐含领域知识时。创建一个 Jupyter Notebook,将部分/全部数据导入 Pandas Dataframe,举行几个小时无序研究,训练第一个模型,评估结果——任务完成。但幸运的是,现实并不如此。在机械进修的生命周期中,尝试有自己的目的。这些目的并不是模型,而是懂得。鉴于探索性 Jupyter Notebook 的模型是为了懂得,而不是为消费开发的成品。懂得之后,还需求进一步开发和适应,才能开始打造用于消费的训练过程。不过,所有与领域特定的知识无关的懂得都可以自动化。你可以鉴于你使用的每个数据版本生成统计信息,从而可以跳过那些你在 Jupyter Notebook 中做过的一次性的临时探索工作,然后直达第一个管道式过程。你在过程中尝试举行得越早,你就能越早地在中间结果上举行协作,也就能更早地实现可投入消费的模型。归纳:笔记不能投入消费,因此要在过程中尽早尝试。9. 训练和办事之间的法子差异训练和实际办事之间往往存在法子差异,为了正确地将所有数据预处理过程都纳入到模型办事环境中,需求减少这些差异。这当然是正确的,你也需求坚持这一原则。但是,这只是对这一成绩的部分解读。先来简单看一段古老的 DevOps 历史:2006 年,亚马逊的 CTO Werner Vogels 创造了一个说法「You build it, you run it(你建立的东西你要运转)」。这是一个描述性的短语,意思是开发者的责任不只是写程序,还需求运转它们。机械进修项目也需求类似的机制——懂得上游的数据生成以及下游的模型使用都在数据科学家的职责范围内。你训练用的数据是通过什么体系生成的?它会出成绩吗?该体系的办事级目标(SLO)是什么?这与实际办事的目标一致吗?你的模型的办事方式是怎样的?运转时环境是怎样的?怎样在办事时对函数举行预处理?这些都是数据科学家需求懂得和解答的成绩。归纳:正确地将预处理嵌入到办事之中,确保你懂得数据的上下游。10. 可对比性从为项目引入第二个训练脚本开始,可对比性就成了未来工作的重要组成部分。如果第二个模型的结果无法与第一个模型的结果举行对比,则整个过程就浪费了,其中至少有一个是多余的,甚至可能两个都多余。根据定义,所有试图解决同一成绩的模型训练都需求可以对比,否则它们就不是在解决同一成绩。尽管迭代过程可能导致所要对比的东西发生变化,但是在技术上实现模型训练的可对比性需求一开始就作为首要功能内置于训练架构之中。归纳:建立你自己的管道式过程,以便轻松对比各个过程的训练结果。11. 监控粗略地说,机械进修的目标应该是通过进修数据来解决成绩。为了解决这个成绩,需求分配计算资源。首先是分配给模型的训练,然后是分配给模型的办事。负责在训练期间提供资源的不管是人还是部门,都需求负责将这些资源转移给办事。模型在使用过程中可能出现很多性能下降成绩。数据可以偏移,模型可能成为整体性能的瓶颈,偏差也是一个真实存在的成绩。效果:数据科学家和团队负责监控他们创建的模型。他们并不一定要负责实施监控,尤其是当组织结构很大时,但他们肯定需求负责监控数据的懂得和解释。最低限度上,需求监控的内容包括输入数据、推理次数、资源使用情况(CPU、RAM)和输出数据。归纳:同样,「You build it, you run it(你建立的东西你要运转)」。监控消费过程中的模型是数据科学的部分工作。12. 模型的可布置性从技术层面讲,每个模型训练过程都需求得到可布置到消费环境中的成品。毫无疑问,这些模型结果可能很糟糕,但它需求做成可以布置到消费环境的形态。这是软件开发中的常见模式,也叫做继续交付(Continuous Delivery)。团队需求能够随时布置他们的软件,为了满足这个目标,迭代周期需求足够快。机械进修也需求采用类似的法子。这样才能迫使团队首先考虑现实与期望之间的平衡。所有利益相关者都应当清楚,在模型结果方面,哪些结果是理论上可能的。所有利益相关者都应当在模型的布置方式以及如何与更大的软件架构整合上达成一致。但是,这也可能需求自动化,也需求前文提到的一些要素。归纳:每个训练过程都需求得到可布置的成品,而不「只是」模型。原文链接:https://blog.maiot.io/12-factors-of-ml-in-production/

你的消费型ML复现不了,可能是工作过程出了成绩
在机械进修社区,越来越多的人开始讨论研究的可复现性,但这些讨论大部分局限于学术环境。如何确保消费环境的ML可复现?近日,机械进修开发办事提供商 maiot.io 的 CTO Benedikt Koll