【Google 年度顶级论文】机器学习系统,隐藏多少技术债?
【Google 年度顶级论文】机器学习系统,隐藏多少技术债?
本文作者:D. Sculley, Gary Holt, Daniel Golovin, Eugene Davydov, Todd Phillips,Dietmar Ebner, Vinay Chaudhary, Michael Young, Jean-Franc¸ois Crespo, Dan Dennison。(以上为Google研究人员)
1. 介绍
随着机器学习(ML)社群持续积累了几年对于活跃系统(live systems)的经验,一种让人不舒服的趋势广泛地浮出水面:研发和部署机器学习系统相对来说是既快速又便宜的,但维护它们却很困难,并且成本昂贵。
这种对立可以用“技术债”的框架来理解。1992年WardCunningham引入了这个比喻,用来帮助解释在软件工程领域里因为进展快速而带来的长期成本。就像欠下财政债务一样,欠下技术债务也总是有充分的战略性原因。并不是所有的债务都是不好的,但是,所有的债务都需要付出利息。技术债可能通过:
重构代码(refactoringcode)、改进单元测试(improvingunit tests)、删除无用代码(deletingdead code)、降低依赖(reducing dependencies)、精简应用程序接口(tightening APIs)、以及改进说明(improving documentation)的方式来逐渐偿还。
这些行动的目标并不是为了增加全新的功能,而是为了使未来能够继续改进,减少报错,以及提高维护性。推迟偿还只会带来越来越高昂的成本。因为技术债会高速增长,所以它是非常危险的。
在这篇论文中,我们提出,机器学习系统有其特有的、带来技术债的能力,因为它们不仅有传统代码所有的维护问题,还要额外加上机器学习的一些特有问题。这种债务可能很难被察觉到,因为它存在于系统层面而不是代码层面。鉴于数据会影响机器学习系统的行为表现,传统的抽象化和边界可能悄悄崩溃(corrupted)或是失效(invalidated)。偿还代码层面技术债务的典型方法在系统层面的机器学习特有的技术债面前是不够的。
这篇论文并不提供全新的机器学习算法,而是寻求提高机器学习社群对于机器学习系统技术债的意识;从长远来看,实际操作中这些艰难的权衡必须得到考虑。我们关注于系统层面的交互和接口,因为这是一个可能会快速积累机器学习技术债的领域。在系统层面上,一个机器学习模型可能会严重侵蚀抽象化边界(abstractionboundaries)。多次利用输入信号(re-use)或连锁输入信号(chain)非常吸引人,但可能会无意中将几个系统组合起来(combine),也可能会令组合系统脱节(disjoint)。机器学习可能会被当作是黑匣,导致大量的“胶水代码”(glue code)或是大量校准层(calibration layers)。外部世界的变化可能会在无意中影响系统行为。在设计不够仔细的时候,即使是监控机器学习系统的行为都可能会使一件困难的事情。我们探索了一些机器学习特有的需要在设计系统时考虑到的风险因素。这些包括了:
(1)边界侵蚀(boundary erosion)
(2)纠缠(entanglement)
(3)隐藏反馈循环(hiddenfeedback loops)
(4)未申明的访问者(undeclared consumers)
(5)数据依赖(data dependencies)
(6)配置问题(configuration issues)
(7)外部世界变化(changesin the external world)
(8)系统层面的反面模式(anti-patterns)
2. 复杂模型侵蚀边界
传统的软件设计实践表明,使用封装和模块设计的强抽象化边界有助于创造便于维护的代码,因为这让独立更改和改进变得很简单。给定元素中信息输入输出中,严格的抽象化边界有助于表达不变条件(invariants)以及逻辑一致性。
不幸的是,通过预先设置特殊的行为来迫使机器学习系统拥有严格的抽象化边界是非常困难的。事实上,机器学习恰恰是被应用在相反的情况中:当不依赖于外部数据、期望的行为便无法在软件逻辑里被有效表达时。真实世界并不能被干净整齐地封装起来。在这里,我们检验了一些会导致边界侵蚀、进而使机器学习系统中的技术债显著提高的情况。
纠缠
机器学习系统将信号混在一起,使它们互相纠缠,让独立更新变成一件不可能的事。比如,想象一下一个在模型中使用了特征x1,…xn的系统。如果我们改变了x1中输入值的分布,那么剩下n-1个特征的重要性、权重、或是用法(use)可能都会随之发生变化。增加一个新特征xn+1会导致相似的改变,就像移除其中任何一个特征一样。不存在真正意义上独立的输入。我们在这里称它为CACE法则:改变任何东西都意味着改变一切(ChangingAnything Changes Everything)。CACE不仅适用于输入信号,也适用于超参数(hyper-parameters)、学习情景(learningsettings)、抽样方法(samplingmethods)、收敛阈值(convergencethresholds)、数据选择(dataselection)、以及其他在本质上是微小改动的部分。
一种可能的缓解策略是,将模型分离开、转而提供集成模型。这个方法在分离式多层环境之类的情景下(例如在[14]中)是有用的,因为这样的环境下,这个方法能够让纠缠导致的各种问题都自然而然地消解。然而,在许多例子里,集成模型的效果非常好是因为它的组成模型各自的误差是不相关的。依赖于这样的组合会导致严重的纠缠问题:改进一个组成模型可能实际上让整个系统的准确度变得糟糕了——如果余下的误差与其它组成模型的误差相关性变得更强烈。
第二种可能的策略是,关注预测行为发生的变化。[12]中提出,用一个高维度可视化工具来让研究者们可以快速看到许多维度和切片上的效果。以切片为基础进行操作的矩阵可能也会非常有用。
嵌套修正
经常会出现一种情况:针对问题A的模型ma已经有了,但现在需要一个针对稍有不同的问题A’的模型。在这样的情况下,将ma作为输入信息、并学习一个小改变的模型是非常诱人的,它可以很快地解决问题。
然而,这种修正模型带来了新的对于ma的系统依赖,让未来分析改进这个模型的代价变得更为昂贵。当修正模型多层嵌套——针对问题A’’的模型是基于m’a习得的之类——来适应几个有些许不同的测试分布时,成本会变得更为高昂。一旦存在,嵌套修正模型会让改进陷入僵局,因为改进任何一个单独的组成部分的准确性事实上都会带来系统层面的损害。缓解策略是扩充ma,通过增加辨别特征让ma直接在它所在的模型里习得修正;或者接受为A’单独创造一个模型的成本。
未声明的访问者
许多时候,来自一个机器学习模型ma的预测能被许多程序访问的,或者是在运行时、或者是通过写入文件或是日志来让其他系统可以在之后访问。不对访问进行控制的话,一些访问者可能是未声明的(undeclared),悄无声息地将一个模型的输出结果输入给另一个系统。在更经典的软件工程领域,这个问题被称为可见性债务(visibilitydebt)。
未声明的访问者往好了说会带来昂贵的成本,往坏了说更是危险的,因为它们在模型ma与堆栈其他部分之间创建了一个隐藏的紧耦合。对ma的改变将很有可能也影响到这些其它的部分,也许通过无意的、尚未被理解的、会造成损伤的方式。实际操作中,这种紧耦合会逐渐增加对ma做任何改变的成本和难度,即使这些改变是为了提升性能。不仅如此,未声明的访问者可能会创建隐藏的反馈循环,在第4部分我们会更详细地讨论这个问题。
未声明的访问者可能很难被发现,除非系统在设计时就特意针对这个问题作了防护,比如限制访问或是有严格的服务级别协议(strictservice-level agreements, SLAs)。在缺乏限制的情况下,工程师们自然会使用手头最方便的信号,特别是当需要面对截止时间的压力时。
3. 数据依赖比代码依赖成本更高
在经典的软件工程环境中,依赖债务(dependencydebt)被认为是代码复杂程度和科技债的重要贡献者。我们已经发现,机器学习系统中的数据依赖具有相似的形成债务的能力,但可能更难被察觉到。代码依赖可以通过编译器和链接的静态分析被鉴定出来。由于缺乏相似的工具用来鉴定数据依赖,形成大型的、难以拆解的数据依赖链是一件很容易发生的事情。
依赖于不稳定的数据
为了获得快速进展,将其他系统生成的信号当作输入的特征是非常便利的。然而,一些输入的信号是不稳定的(unstable),这意味着它们的行为随着时间会发生数量上的变化(quantitatively)或是质量上的变化(qualitatively)。这可能发生得非常隐蔽,比如这个输入信号来自于另一个自身会随时间更新的机器学习模型,或者一个依赖于数据的、用来计算TF/IDF分数或是语义映射的查找表(lookuptable)。这也可能发生得非常明显,比如当输入信号的工程所有权(engineeringownership)独立于使用这个输入信号的模型的工程所有权。在这样的情况下,可以在任何时候对输入信号进行更新。这是非常危险的,因为即使是对输入信号的“改进”也可能会对使用这个信号的系统产生不确定的危害作用,要诊断这样的问题需要很高的成本。比如,想象一下这样的情况:一个输入信号之前的校准是错误的(mis-calibrated),使用这个信号的模型很可能拟合这些错误的校准;对信号作了更正以后,整个模型都会突然发生变化。
针对依赖于不稳定数据的问题,一种常见的缓解策略是,对于一个给定信号创建一份标记版本的副本。比如,与其允许一个词汇(words)到主题(topics)的语义映射聚合随时间一直变化,创建这个映射的冻结副本(frozenversion)、一直使用到更新版本被彻底检查确认完毕是更好的选择。然而,创建每个版本的副本会带来它自己的成本,例如可能的冗余以及同一信号随时间而产生的不同版本的维持成本。
依赖于未充分使用的数据
在代码层面,未被充分使用的依赖指的是大部分时候非必要的包(Packages)。相似的,依赖于未充分使用的数据指的是几乎不能为模型提供性能提升的输入信号。这会导致机器学习系统在变化的时候容易出现问题,有时候还会造成灾难,即使这些依赖可以被无损移除。
例如,假如要简化从老编号方案到新编号方案的过渡,那么两种方案都作为特征留在系统里。新的产品只有新的编号,但老的产品会有新、老编号,而模型在某些产品上,会持续依赖于老的编号。一年后,停止将老编号填充进数据库的代码被删除了。这对于机器学习系统的维修者来说不会是一个愉快的日子。
依赖于未充分使用的数据,这个问题可以通过多种方式蔓延进入模型中。
遗留特征:很常见的例子是,特征 F 在早期的开发中存在,但随着开发进行,在新的特征中 F 变成多余了,但并没有被发觉。
捆绑特征:很多时候,一组特征被评估为有用的。但是由于截止期限的压力或其他类似原因,这组特征都被加入到新模型了,其中就很可能包括一些没有价值的特征。
є特征:作为机器学习研究者,总是会想方设法改善模型的精确程度,哪怕这个精确度的提升是非常的小,或者带来的复杂度会很高。
相关特征:有时候两个特征是相关性很高,但其中一个特征有更直接的因果作用。很多机器学习方法很难识别出来区别,而是把这两者等同看待,甚至可能选择了没有因果关系的那个特征。当真实世界的行为改变了特征之间的相关性,结果就会变得很脆弱、不够稳健。
依赖于未充分使用的数据这一问题可以通过完全把一个特征丢弃以评估检测。这项工作需要定期进行,以识别并移除多余的特征。
图1:在真实世界的整个机器学习系统中,只有一小部分是由机器学习的代码组成,图片中用中间的小黑盒来表示。它需要大量并且复杂的周边设施。
对数据依赖作静态分析
在传统的代码中,编译器和编译系统可以用依赖图(dependencygraphs)做静态分析。数据依赖的静态分析工具非常少,但它们对于错误检查、访问者追踪、迁移和更新(migrationand updates)来说都很必要。这类工具其中之一就是自动特征管理系统(automatedfeature management system),它让数据源和特征可以被标注,然后运行自动检查来确保所有的依赖都有恰当的标注,而依赖树(dependencytree)可以被完全解开(fullyresolved)。这类工具在实践中能让迁移和删除操作变得安全得多。
4. 反馈循环
现在机器学习系统的主要特征之一即是,如果系统随时间不断进行更新,这些系统最终会影响它们自身的行为。这就导致了某种形式的分析债,即在一个系统未发布之前很难预测一个给定模型的行为。这些反馈循环可以有不同的形式,但如果所有这些反馈循环是随时间而逐渐发生的话,它们是很难被检测到的,当模型更新不频繁时就是这样。
直接反馈循环
一个模型可能直接影响到它自身未来训练数据的选择。尽管理论上正确的解决方法是赌博机算法,但是采用标准的监督算法已经是一种很普遍的做法。问题是赌博机算法(例如语境赌博机算法)实质上不能很好的地缩放到现实世界中要求的动作空间的尺度大小。因而,可以通过采用一些随机化的操作或者隔离受到给定模型影响的某部分数据等方式来缓解上述的不良影响。
隐藏反馈循环
直接反馈循环分析起来代价是非常昂贵的,但是它们至少提出来了一个机器学习研究者们很自然地会去琢磨的统计挑战。相比之下,更困难的情况是隐藏反馈循环,即两个系统在世界范围内间接地互相影响。
一个例子可能是,如果两个系统单独地决定一个网页的某些方面,例如一个系统对产品进行挑选并展示,另一个系统挑选相关的评论。改进一个系统可能导致另一个系统行为的变化,因为作为对于改变的反应,用户开始更多或更少地点击其他部分。需要注意的是,在两个完全不相交的系统中也可能会存在隐藏反馈循环。可以从来自于两个不同的投资公司的两个股票市场预测模型的案例加以考虑,如果对其中的一个模型做出某些改进(或者,bug),则另一个模型的投标和购买行为相应地也会受到一定程度的影响。
5. 机器学习系统的反面模式
对于学术领域的众多研究者而言,了解到在许多的机器学习系统中仅仅只有一小部分的代码用来进行学习或者预测可能会让他们感到非常惊讶(如图1所示)。在Lin和Rayboy语言中,除了仅有的小部分代码用于学习或者预测,大部分剩余代码被称为“管道工程”。
不幸的是,对于一个融合了机器学习算法并最终债台高筑的系统来说,这很普遍。在这个章节中,我们检测了数个在许多的机器学习系统中显露的反面模式系统设计,以及在有可能的时候哪些应该被避免或重构。
粘合代码
机器学习研究者倾向于开发普遍适用的解决方案作为自给自足的包(packages)。在像mloss.org、in-house code、专有软件包、基于云平台等地方,有许多这种包以开源包的形式存在。
采用通用软件包经常会导致粘合代码的系统设计模式,在这种系统设计模式中,包含了大量支持数据写入通用软件包或者数据从通用软件包中输出的代码。粘合代码的代价从长远来看是很高的,因为这将系统局限于(freeze)一个特定包的特点,如果要测试其他方法,成本就会变得不可避免的昂贵。因此,采用通用包会抑制改进,因为以粘合代码的形式使得利用特定领域的特性或者调整目标函数实现特定领域的目标变得更加困难,。由于一个成熟的机器学习系统可能最终会包含(最多)5%的学习代码和(最少)95%的粘合代码,创建一个干净纯粹的解决方案比重复使用通用软件包成本要更低。
对抗粘合代码的重要策略之一就是,将黑盒包(black-box packages)包装进普通的应用程序接口。这让周边支持的基础设施能被更多地重复利用,降低更换包的成本。
管道丛林
作为粘合代码的一种特殊情况,“管道丛林”(pipeline jungles)现象经常出现在数据预备阶段。随着新信号逐渐被鉴定、新信息资源逐渐被添加,管道丛林也有机地发展起来。一不小心,在机器学习系统友好的格式下,预备数据的结果系统可能会成为一个充满碎片、联结部分以及采样步骤的丛林,经常也会有中间输出文件在其中。管理这些管道、检测错误、以及从失效中修复等全部都是非常困难和代价昂贵的事情。测试这样的管道通畅要求端到端的整合测试。上述所有情况增加了系统的技术债,并且使得未来创新的成本更加昂贵。
只有从整体上考虑数据收集和特征提取的过程,才能够避免“管道丛林”现象的发生。用从头再来的方式消除管道丛林,以及从最底层开始重新进行设计,确实是一项工程上的重大投资,但是其也是一项能够大幅减少持续增的成本并加速未来创新的工程。
粘合代码和“管道丛林”是集成问题表现出来的症状,根源可能在于“研究”和“工程”角色过于分离。当机器学习包是在象牙塔的环境中被开发出来时,对于在实践中部署这些包的团队来说结果可能看上去像一个黑盒。工程师和研究者处于同一个团队的混合研究方法(事实上,很多时候研究者和工程师是同一个人)能够显著地减少源头的摩擦。
失效的实验代码路径
粘合代码或是“管道丛林”的一个常见结果是,在主要的生成代码中,通过执行实验代码路径作为条件分支来演示具有选择性方法的实验过程,从短期看来是极具吸引力的。对于任何单独的改变,以这种方式来进行实验,成本是相对较低的——周边的基础设备无需再返工。然而,随着时间的推移,由于后台兼容性的维护愈加困难以及循环复杂度(cyclomatic complexity)呈指数增长,这些日渐积聚的代码路径将会导致技术债的持续增加。对代码路径间所有可能的交互做测试变得非常困难,或者说不可能。这种危险的一个著名例子就是Knight Capital的系统在45分钟里损失了4.65亿美元,由于从废弃的实验代码路径产生了未被预料到的行为。
和传统软件领域中的“死旗”(dead flags)一样,周期性地重复检查每个实验分支,从而纠察出哪个实验分支可以舍弃的方法是非常有益的。一般仅仅是一小部分分支能够被实际应用到,其它许多实验分支可能被测试一次后就遭到舍弃。
抽象化债务
上述的问题强调了这样的一个事实:明显缺少强抽象来支持机器学习系统。Zheng最近对机器学习抽象状态与数据库技术状态做了令人信服的比较,得到这样的一个结论:机器学习领域的文献中,没有哪一篇将相关数据库(relational database)作为基本抽象(basic abstraction)的论文得到的结果能达到接近成功的地步。什么样的接口才是描述一个数据流、一个模型、或者一个预测的正确接口?
特别是对于分布式学习来说,仍然缺乏被广泛接受的抽象。可能有人会争论,机器学习中Map-Reduce的广泛应用是由于缺乏强分布式学习抽象。事实上,在最近几年,广泛协议的几个领域之一认为Map-Reduce对于迭代的机器学习算法是一个性能很差的抽象。
参数服务器抽象更具有鲁棒性,但这个基本思想有多个相互竞争的规范。标准抽象的缺乏使得不同组成部分之间的界限太容易被模糊化。
常见异味
在软件工程中,系统设计的异味(smell)指的是在一个系统中或者系统中的一个部件中存在的潜在问题。我们鉴别了一些机器学习系统的异味,这些并不是不可违逆的准则,而只是主观判断的指标。
POD类(Plain-Old-Data)异味:机器学习系统采用和生成的丰富数据信息全部是用浮点数、整数等普通的数据类型进行编码的。在一个鲁棒的系统中,一个模型的参数应该明确自己代表的是一个对数赔率系数、还是一个决策阈值,一个预测应该知道关于产生这个预测的模型的各种片段信息以及它将如何被使用。
多语言异味:用一种特定的语言编写系统中的一部分代码是一件非常具有诱惑力的事情,特别是当这种语言对于手头的任务而言有一个便利的库(library)或脚本。然而,用多种语言编写系统经常会增加测试成本,并且会增加将所有权让渡给其他人的难度。
原型异味:通过原型在小范围内测试新的想法是非常方便的。然而,定期地依赖于一个原型环境暗示着系统的脆弱性、难以改变,并能够从改善的抽象性和接口受益。维护一个原型环境需要承担它的代价,并且有个显著的威胁是,时间压力会促使一个原型系统变成了产品解决方案。除此之外,在小范围内发现的结果不能很好地应用在整个范围内。
6. 配置债
另一个令人惊讶的债务积累的区域是机器学习系统的配置。任何大系统都有许多配置选择权,包括哪些特征被采用,数据是怎样选择,许多特定学习算法的设置,潜在的预处理和后处理、验证方法等等。我们已经观察到不论是工程师还是研究者都将系统的配置看作是一个事后的想法。事实上,系统配置的验证和测试可能被看作是不重要的。在一个成熟的系统中,系统的配置占有举足轻重的地位,用于系统配置的行数远远超过了传统代码的行数。每个系统配置行都可能含有潜在的错误。
考虑以下的案例。特征A应该是9/14,但被错误地记录为9/17。在10/7之前,特征B在数据上是不可用的。因为记录格式的改变,要改变用于计算11/1之前和之后数据关于特征C的代码。特征D在产品中是不可用的,所以在实际设置中查询模型,就需要使用替代性的特征 D’和D’’。如果特征Z被采用,由于查找表的原因,训练工作必须给定额外的存储空间,否则他们会无效率地进行训练。因为延迟约束,特征Q排除使用特征R。
这一切的混乱使得配置难以修改正确,并且很难合理解释这种现象。然而。配置的错误代价是昂贵的,它会导致时间的大量损失、计算资源的浪费以及生产问题。这使得我们清楚知道,应根据以下原则进行良好的系统配置。
(1)从以前的系统配置中做出小的改变,应该能很容易地指明。
(2)人为错误、遗漏、或者是疏忽是很难发生的。
(3)在两个不同构造的模型间,应该能很容易看出不同。
(4)能够容易的自动维护和验证配置,例如在这些方面:采用的特征数量、数据依赖关系的传递闭包。
(5)能够很容易地探测无用的或者冗余的设置。
(6)系统配置应进行全码的检查,并且记录到存储空间中。
7. 处理客观世界的变化
让机器学习系统如此令人着迷的一点就是,它们经常与外部世界直接地互动。经验表明,外部世界是不稳定的。这种背景的变化率(backgroundrate of change)导致了机器学习系统持续的维护成本。
动态系统的固定阈值。为给定模型执行某些操作而设定一个阈值是必要的:去预测对或是错,标记某个邮件是否为垃圾邮件,某个给定广告显示与否。为了在某些矩阵中进行权衡,机器学习中一个经典的方法是从一系列可能的阈值中选择一个,例如召回率与准确率。然而,这样的阈值通常是人为设定的。于是如果一个模型的数据更新,那么旧的人为设定的阈值可能就失效了。人工更新很多模型中的很多阈值很浪费时间而且也让模型不够强大。对应这种情况一种缓解策略就是[14],在这篇文章中阈值是通过对有效的留存数据进行简单评估而习得的。
监控和测试。对独立元件的单元测试和对运行系统的端到端测试是很有价值的,但是在快速变化的世界面前,这种测试提供的证据不足以说明系统是按计划运行的。对系统行为的实时综合性监测辅以自动回复机制对于长期系统的可靠性来说是非常重要的。
问题的关键是:监测什么?考虑到许多机器学习系统倾向随着时间不断地自我适应这一情况,可以被测试的不变条件(invariants)并不总是明显的。我们提供了以下几个出发点。
预测偏差(Prediction Bias)。在一个按计划运行的系统中,它应该符合这样的情况:预测标签(predicted labels)的分布与观测标签(observedlabels)的分布是相同的。这不论怎样都不是一个全面的测试,因为一个无视输入的特征而只预测标签出现频率均值的空值模型也能通过这个测试。然而,它作为诊断工具却意外地有用,它在矩阵中发生变化时通常意味着出现了一个值得注意的问题。例如,这种方法能够帮助检测这样的情况,外部世界行为突然改变,使得利用历史数据训练的分布不再反映当前现实。通过分割各维度的预测偏差可以快速分离问题,也能够用于自动报警机制。
处置限制(Action Limits)。在那些用于在现实世界中采取行动的系统中,例如项目投标或者标记垃圾短信,设定处置限制(Action Limits)并将它作为完成性检查(sanitycheck)的项目之一是很有用的。这些限制范围应该设置得足够宽,以防被不合逻辑地触发。如果系统由于某种行为而达到了限制值,自动报警应该启动并触发人工介入或者调查。
上游生产者(Up-Stream Producers)。来自多种多样的上游生产者的数据通常会提供给机器学习系统。这些上游过程应该被彻底地监测、测试,并且要满足服务层面的常规目标:将下游机器学习系统的需求考虑在内。进而任何上游的警报都必须传播到机器学习系统的控制面板中来保证系统的准确性。相似地,任何不能满足既定服务层面目标的机器学习系统也要传播到下游所有的系统中,并且如果可能的话,直接传播到它们的控制面板中。
由于外部变化是实时发生的,回应也应该实时发生。依靠人类介入作为对警报页面的回应是一种策略,但是对于具有时间敏感性的问题是很鸡肋的。创造一个不需要直接人为介入的自动回应系统总是值得投入的。
8. 与机器学习相关的其他领域的技术债
我们现在简短地突出强调一下其他一些领域中与机器学习有关的可能发生的技术债。
数据测试债。如果数据在机器学习系统中取代了代码,并且代码要被测试,那么似乎以下说法就很明晰了,即一定量的输入数据的测试对于得到一个运作良好的系统来说是重要的。基本的完整性测试(sanitychecks)是有用的,监测输入数据分布变化的复杂测试同样也是有用的。
可重复性债。作为科学家,能够重复实验并得到相似结果是很重要的,但是某些条件下,在真实世界里设计一个狭义可重复性系统会变得困难。这些条件包括随机化算法,并行学习固有的不确定性,对初始条件的依赖和与外部世界的互动。
进程管理债。本论文中描述的大部分使用案例讨论了维护一个模型的成本,但是成熟系统可能有几十个或者几百个模型同时运行。这引出了广泛而重要的问题,它包括自动并安全地为相似模型更新各种配置的问题,如何为众多不同业务优先级的模型管理并分配资源问题,还有在一条生产线中如何可视化并检测数据流拥堵问题。开发工具来帮助生产事故的恢复也很重要。常见的需要人工步骤的过程是,避免重要的系统级别异味(smell)。
文化债。机器学习的研究领域和工程领域之间,有时是有明显界限的,但是这可能不利于长期系统健康。创造一种团队文化去鼓励删除特征,减少复杂度,提高可重复性和稳定性,把监督进行到精确率的提高均会被量化的程度。据我们的经验,在两个领域(机器学习研究和工程领域)有优势的异质性团队中最有可能发生这样的情况。
9. 结论:测量并还清技术债
技术债是一个很好的比喻,但是很不幸的是它并没有严格的、可被追踪的度量方式。我们如何测量系统中的技术债,如何评估技术债的全部成本?先要注意到,一个团队仍然在快速进步并不是低技术债或者良好运行的证据,因为技术债的全部成本只会随着时间的推移而慢慢浮出水面。事实上,发展过快经常会引入技术债。一些有用问题在这里列出:
· 一个全新的算法被全面测试的难易程度?
· 所有数据相关性的传递闭包是什么?
· 新改变对系统的影响,能多精确的测量?
· 改善模型或是信号会降低其他模型吗?
· 要花多久才能使团队新成员赶上其他人速度?
我们希望这篇文章能够对可持续机器学习领域(maintainableML)的发展起到一定的促进作用,这里所指的领域包括了更好的抽象、测试方法和设计模式。也许最重要的观点是,技术债是一个既需要工程师也要科学家注意的问题。以大规模增加系统复杂性为代价求取微小的精确性进步的研究性解决方案,很少会被广泛应用。即使是一两个看起来很正常的数据相关性的增加都能够减缓未来的进度。
还清与机器学习有关的技术债需要做出特定的承诺,这种承诺常常只能通过转变团队文化来完成。认识到这一点,优先考虑并奖励这样的行为,对于成功机器学习团队的长期健康来说是很重要的。
鸣谢
这篇文章要特别感谢在创新型研究氛围和强大工程实践的团队文化中一天天学习而得到的重要教训。许多同事帮助形成了这种观点,并且民间智慧的积累而产生的有益影响再怎么强调也不为过。我们想要特别鸣谢以下各位:RobertoBayardo,Luis Cobo,SharatChikkerur, JeffDean,PhilipHenderson,ArnarMar Hrafnkelsson,AnkurJain,Joe Kovac,Jeremy Kubica,H. Brendan McMahan,SatyakiMahalanabis, LanNie,Michael Pohl,Abdul Salem,SajidSiddiqi,Ricky Shan,AlanSkelly,Cory Williams,和Andrew Young。
本篇论文的简短形式曾在2014年加拿大的蒙特利尔SE4ML讨论会中呈现过。
参考论文
[1] R. Ananthanarayanan, V. Basker, S. Das, A. Gupta, H. Jiang, T. Qiu, A. Reznichenko, D. Ryabkov, M. Singh, and S. Venkataraman. Photon: Fault-tolerant and scalable joining of continuous data streams. In SIGMOD ’13: Proceedings of the 2013 international conference on Management of data, pages 577– 588, New York, NY, USA, 2013.
[2] A. Anonymous. Machine learning: The high-interest credit card of technical debt. SE4ML: Software Engineering for Machine Learning (NIPS 2014 Workshop).
[3] L. Bottou, J. Peters, J. Qui ˜nonero Candela, D. X. Charles, D. M. Chickering, E. Portugaly, D. Ray, P. Simard, and E. Snelson. Counterfactual reasoning and learning systems: The example of computational advertising. Journal of Machine Learning Research, 14(Nov), 2013.
[4] W. J. Brown, H. W. McCormick, T. J. Mowbray, and R. C. Malveau. Antipatterns: refactoring software, architectures, and projects in crisis. 1998.
[5] T. M. Chilimbi, Y. Suzue, J. Apacible, and K. Kalyanaraman. Project adam: Building an efficient and scalable deep learning training system. In 11th USENIX Symposium on Operating Systems Design and Implementation, OSDI ’14, Broomfield, CO, USA, October 6-8, 2014., pages 571–582, 2014.
[6] B. Dalessandro, D. Chen, T. Raeder, C. Perlich, M. Han Williams, and F. Provost. Scalable handsfree transfer learning for online advertising. In Proceedings of the 20th ACM SIGKDD international conference on Knowledge discovery and data mining, pages 1573–1582. ACM, 2014.
[7] M. Fowler. Code smells. http://http://martinfowler.com/bliki/CodeSmell.html.
[8] M. Fowler. Refactoring: improving the design of existing code. Pearson Education India, 1999.
[9] J. Langford and T. Zhang. The epoch-greedy algorithm for multi-armed bandits with side information. In Advances in neural information processing systems, pages 817–824, 2008.
[10] M. Li, D. G. Andersen, J. W. Park, A. J. Smola, A. Ahmed, V. Josifovski, J. Long, E. J. Shekita, and B. Su. Scaling distributed machine learning with the parameter server. In 11th USENIX Symposium on Operating Systems Design and Implementation, OSDI ’14, Broomfield, CO, USA, October 6-8, 2014., pages 583–598, 2014.
[11] J. Lin and D. Ryaboy. Scaling big data mining infrastructure: the twitter experience. ACM SIGKDD Explorations Newsletter, 14(2):6–19, 2013.
[12] H. B. McMahan, G. Holt, D. Sculley, M. Young, D. Ebner, J. Grady, L. Nie, T. Phillips, E. Davydov, D. Golovin, S. Chikkerur, D. Liu, M.Wattenberg, A. M. Hrafnkelsson, T. Boulos, and J. Kubica. Ad click prediction: a view from the trenches. In The 19th ACM SIGKDD International Conference on Knowledge Discovery and Data Mining, KDD 2013, Chicago, IL, USA, August 11-14, 2013, 2013.
[13] J. D. Morgenthaler, M. Gridnev, R. Sauciuc, and S. Bhansali. Searching for build debt: Experiences managing technical debt at google. In Proceedings of the Third International Workshop on Managing Technical Debt, 2012.
[14] D. Sculley, M. E. Otey, M. Pohl, B. Spitznagel, J. Hainsworth, and Y. Zhou. Detecting adversarial advertisements in the wild. In Proceedings of the 17th ACM SIGKDD International Conference on Knowledge Discovery and Data Mining, San Diego, CA, USA, August 21-24, 2011, 2011.
[15] Securities and E. Commission. SEC Charges Knight CapitalWith Violations ofMarket Access Rule, 2013.
[16] A. Spector, P. Norvig, and S. Petrov. Google’s hybrid approach to research. Communications of the ACM, 55 Issue 7, 2012.
[17] A. Zheng. The challenges of building machine learning tools for the masses. SE4ML: Software Engineer- ing for Machine Learning (NIPS 2014 Workshop)
论文下载
论文原文 Hidden Technical Debt in Machine Learning Systems,