《机器学习工业复现的 12 个要素》

过去二十年来,我们对软件开发的理解有了大幅提升。其中一大部分原因是 DevOps 概念的出现及其在软件开发行业的广泛应用。

领先的软件公司都遵循着同样的模式:首先是在软件开发过程中快速迭代,然后进行持续集成、持续交付、持续部署。每个特性都要经过测试,看其提供价值的能力如何,而且软件始终要处于就绪的状态,并且通过自动化方法进行部署。

机器学习这个领域虽不同于传统的软件开发,但我们也能从软件开发行业汲取很多实用的经验教训。过去几年里,我们一直在开发生产型机器学习项目。我们的目标并不只是概念验证,而是与软件开发一样的可复现能力(reproducibility)。因此,我们构建了一套流程协调器、强大的自动化能力并建立了一套用于实现该目标的工作流程。

为什么不直接使用 Jupyter Notebook?从头开始构建一组包含所有处理步骤的笔记需要多长时间?为团队纳入新成员的难易程度如何?你现在可以复现两个月前的结果吗?能以多快的速度复现?你能将今天的结果和历史结果进行对比吗?你能在训练过程中关注到数据的出处吗?如果你的模型过时了又会发生什么?

我们遇到过所有这些问题。现在,我们将这些经验进行了归纳总结,得到了成功构建生产型机器学习的 12 个要素(类似于软件开发中的十二要素应用/12 factor app)。

版本控制可促进整个软件开发团队之间的协调、共享和协作。版本控制软件让团队可以在分布式和异步环境中工作、管理代码和文件的修改和版本以及解决合并冲突和相关异常。

简单来说,版本控制能让你安全地管理软件开发中会变化的部分。

机器学习其实是一种特殊的软件开发,有着自己特定的要求。首先,机器学习中会变化的部分不止一种,而是两种:代码和数据。其次,模型训练的方式是(快速)迭代,并且代码中的差异会很大(比如拆分、预处理、模型)。

只要数据发生更改,就需要保存一个版本,这样才能保证能复现结果以及重复执行实验和训练模型。简单粗暴的版本控制(硬拷贝)具有很大的改进空间,不过尤其是在团队共享的情况下,能够保持不变的版本控制是至关重要的。

代码的版本控制还要更加重要。除了上面引述的内容,预处理代码不仅在训练阶段很重要,而且在服务阶段也很重要,需要与模型有保持不变的相关性。为了在数据科学家的工作流程和投入生产的要求之间建立一种中台,一种方便的方法是提供无服务器的功能。

总结:你需要对代码进行版本控制,也需要对数据进行版本控制。

在理想世界中,产生你的输入数据的东西应该总是会产生同样的数据,至少结构上是这样。但这个世界并不是完美的,你从上游服务获取的数据也是由人类构建的,因此可能会发生变化。最终,特征也可能发生改变。最好的情况是你的模型会直接故障报错,但还有最坏的情况:你的模型悄悄继续工作,但得到的结果都是垃圾。

明确定义的特征依赖关系能够尽快揭示出失败案例。如果系统设计得好,还能在服务时进行持续训练,然后调整依赖关系并加以适应。

总结:明确代码中的特征依赖关系。

尽管机器学习是一类特殊的软件开发,但它并不鼓励实践者背离已有的代码书写准则。在代码书写标准中,最基本的一条是能让人在短时间内不费力地阅读。

预处理和模型的代码都应该遵循 PEP8 规范。代码中应当使用有意义的对象名并包含有助于理解的注释。遵循 PEP8 规范可提升代码的可读性,降低复杂度并加快调试速度。SOLID 之类的编程范式提供了经过深思熟虑的框架,可让代码在未来用例中的可维护性、可理解性和灵活性都得到改善。

配置应该与代码分离。不要将数据分配比例硬编码到代码之中,而是通过配置方式提供,以便在运行时修改。人们在超参数调节方面已经熟知这一点了:使用分离的配置文件可以显著加快迭代速度,并且让代码库可以重复使用。

总结:提升代码可读性并且将代码和配置分开。

通过设定训练的工作流程,整个团队都可以透明地访问已执行的实验和已运行的训练。通过绑定可复用的代码库以及分离的配置文件,每个人都可在任何时间成功重新训练。

总结:使用管道式工作流程和自动化。

1)单元测试是原子层面上的测试——基于各自的标准单独测试每个函数和功能。

2)集成测试则相反,是将代码库的所有元素都放到一起进行测试,同时还会测试上下游服务的克隆版本或模拟版本。

这两种范式都适应于机器学习。预处理代码是预先确定的,直到测试阶段——这样的转换能在不同的输入下都得到正确结果吗?模型是集成测试的一个绝佳案例——在生产环境中提供服务时,你的模型的表现是否与评估时相当?

总结:测试你的代码,测试你的模型。

1)监控生产系统中的数据。建立自动化报告机制,在数据发生变化时通知团队,这种变化甚至可能超过明确定义的特征依赖关系。

2)基于新输入的数据持续训练。良好自动化的管道化流程可以基于新数据重复运行,然后与历史训练结果进行比较,展示性能变化情况以及将训练得到的模型快速投放到生产中,从而让模型表现更好。

总结:如果你的数据会发生变化,那就采用一种持续训练的管道化流程。

正确的做法是以一种中心化的数据存储方式自动记录训练结果。自动化能够保证可靠地跟踪每次训练,从而方便之后比较每次训练的结果。对结果进行中心化存储,能为团队提供透明,实现持续性分析。

总结:通过自动化方法跟踪结果。

在机器学习的生命周期中,实验有自己的目的。这些目的并不是模型,而是理解。基于探索性 Jupyter Notebook 的模型是为了理解,而不是为生产开发的成品。理解之后,还需要进一步开发和适应,才能开始打造用于生产的训练流程。

不过,所有与领域特定的知识无关的理解都可以自动化。你可以基于你使用的每个数据版本生成统计信息,从而可以跳过那些你在 Jupyter Notebook 中做过的一次性的临时探索工作,然后直达第一个管道式流程。你在流程中实验进行得越早,你就能越早地在中间结果上进行协作,也就能更早地实现可投入生产的模型。

总结:笔记不能投入生产,因此要在流程中尽早实验。

先来简单看一段古老的 DevOps 历史:2006 年,亚马逊的 CTO Werner Vogels 创造了一个说法「You build it, you run it(你构建的东西你要运行)」。这是一个描述性的短语,意思是开发者的责任不只是写程序,还需要运行它们。

机器学习项目也需要类似的机制——理解上游的数据生成以及下游的模型使用都在数据科学家的职责范围内。你训练用的数据是通过什么体系生成的?它会出问题吗?该体系的服务级目标(SLO)是什么?这与实际服务的目标一致吗?你的模型的服务方式是怎样的?运行时环境是怎样的?怎样在服务时对函数进行预处理?这些都是数据科学家需要理解和解答的问题。

总结:正确地将预处理嵌入到服务之中,确保你理解数据的上下游。

根据定义,所有试图解决同一问题的模型训练都需要可以比较,否则它们就不是在解决同一问题。尽管迭代过程可能导致所要比较的东西发生变化,但是在技术上实现模型训练的可比较性需要一开始就作为首要功能内置于训练架构之中。

总结:构建你自己的管道式流程,以便轻松比较各个流程的训练结果。

效果:数据科学家和团队负责监控他们创建的模型。他们并不一定要负责实施监控,尤其是当组织结构很大时,但他们肯定需要负责监控数据的理解和解释。最低限度上,需要监控的内容包括输入数据、推理次数、资源使用情况(CPU、RAM)和输出数据。

总结:同样,「You build it, you run it(你构建的东西你要运行)」。监控生产过程中的模型是数据科学的部分工作。

这是软件开发中的常见模式,也叫做持续交付(Continuous Delivery)。团队需要能够随时部署他们的软件,为了满足这个目标,迭代周期需要足够快。

机器学习也需要采用类似的方法。这样才能迫使团队首先考虑现实与期望之间的平衡。所有利益相关者都应当清楚,在模型结果方面,哪些结果是理论上可能的。所有利益相关者都应当在模型的部署方式以及如何与更大的软件架构整合上达成一致。但是,这也可能需要自动化,也需要前文提到的一些要素。

总结:每个训练流程都需要得到可部署的成品,而不「只是」模型。

Original: https://www.cnblogs.com/CheeseZH/p/14084509.html
Author: ZH奶酪
Title: 《机器学习工业复现的 12 个要素》

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/9603/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

发表回复

登录后才能评论
免费咨询
免费咨询
扫码关注
扫码关注
联系站长

站长Johngo!

大数据和算法重度研究者!

持续产出大数据、算法、LeetCode干货,以及业界好资源!

2022012703491714

微信来撩,免费咨询:xiaozhu_tec

分享本页
返回顶部