Tensorflow凭“谷歌”“开源”两个标签自2015年底发布以来便名震深度学习圈。而前年底Facebook就打造其专属ML平台FBLearner Flow,大幅提高员工工作效率。今天,FB工程师首次披露该平台细节,公司意欲进一步提高速度、效率,迈向ML自动化。虽然目前仍限内部使用,但不排除FB这款“Flow”未来也将开源。两大巨头的两股“Flow”如何较量?先从了解FBLearner Flow开始。
Facebook 现在在信息推荐、过滤攻击言论、推荐热门话题、搜索结果排名等等已经使用了大量人工智能和深度学习的技术。在Facebook上,还有许多试验能够从机器学习模型中获利,但是目前,对于很多没有深厚机器学习背景的工程师来说,想要利用这些机器学习基础设施,还是有很大的困难。2014年年末Facebook发布FBLearner Flow,决定重新定义自己的机器学习平台,把人工智能与机器学习中最先进的算法以最便利的方式提供给Facebook的工程师。
在早期运用人工智能与机器学习的试验中,Facebook 发现,准确度上最大的提升往往来自快速的试验、功能编程和模式调试,而非从根本上运用不同的算法。此前,在找到成功的新功能,或者一个超参数集时,工程师可能需要进行上千次试验。Facebook对传统的流水线系统进行评估发现,这一系统并没有很好的匹配Facebook的需求,大多数的解决方案并没有提供以不同的输入来重新运行这一流水线的解决方案;也没有提供机制来具体地分析产出和副作用;没有提供对输出的可视化;没有为参数扫描之类的任务提供条件步骤。
为了实现这些点,Facebook想要一个具备以下属性的平台:
- 每一种机器算法都必须以一种可再使用的方式运行过一次。
- 工程师应该能写出一个训练流水线,这些流水线可以在多种机器中平行切换,并被其他工程师再使用。
- 对于具有不同机器学习经验的工程师来说,训练模型应该变得简便,并且,几乎每一步都应该是完全自动化的。
- 人人都应该能够便利地搜索过去的试验和测试结果,并与其他人分享,并在特定的试验中尝试新的变量。
所以Facebook决定建立一个全新的平台——FBLearner Flow。这一平台要能方便地在不同的产品中重复使用多种算法,并可以延伸到成千上万种模拟的定制试验操中,轻松地对实验进行管理。这一平台提供了创新性的功能,比如从流水线定义和对Python 编码进行自动化平行移用中自动生成用户界面(UI)试验。
目前,超过25%的Facebook工程开发团队都在使用FBLearner Flow。创建以来,该平台已经训练了超过100万模型。Facebook的预测服务,已经发展到每秒产生超过600万次预测。
在编码上减少人工劳动,要求进行一系列的试验,允许机器工程师把更多的时间花在功能编码上,这反过来能够让准确度得到更大的提升,进而,工程师能够产生更大范围的影响,现在的workflow写作者有150个左右,他们的工作的影响力已经超越了他们自己和团队。
在近距离地接触这一系统前,有几个关键的概念需要理解:
工作流(Workflow):一个工作流是限于FBLearner Flow中的一个流水线,并且是其所运行的有机器学习任务的入口。每一个Workflow负责的都是一个具体的任务,比如训练和评估具体的模型。Workflows由计算符系统的术语进行定义,可以被移用。
计算符(Operator):计算符是workflows的建造模块。从概念上,你可以把计算符认为是一个程序里面的一种功能。在FBLearner Flow中,计算符是单个机器中运行和执行的最小组件。
通道(Channels):通道代表作输入和输出。输入和输出在工作流和计算符之间的流动。所有的通道都是由Facebook定义的归类系统进行归类。
这一平台由三个核心部件组成:一个定制的分布式工作流的写作和执行环境;一个用户界面试验管理,用于发布试验和检查结果;还有许多事前定义的流水线,用于训练在Facebook最常见的使用机器学习的算法。
FBLearner Flow 中所有的工作流和计算符都被定义为Python中的函数,并使用特殊的修饰器,来与平台进行融合。来看一个简单的场景,假设我们想要根据经典的鸢尾花数据集训练一个决策树,以根据花的花瓣和花萼来预言花的种类。假设我们可用的数据集是在蜂巢(Hive)矩阵中,并且有5列,每一列分贝代表了花瓣宽度、花瓣长度、花萼宽度、花萼长度以及样本种类。在这个Workflow中,我们将会以对数损失(log loss)的方法来评估模型的表现,并且预测一个未加标签数据集的种类。
一个要处理的样本工作流可能会是这样的:
让我们更深入地查看这一工作流,以理解FBLearner Flow是如何工作的。
首先,工作流的修饰器会告诉FBLearner Flow,鸢尾花函数不是一个常见的Python函数,而是一个工作流。
输入图式和返回参数表明了工作流所期待的输入和输出类型。执行框架将自动地在运行时间内核实这些类型,并且强制Workflow接收它所期待的数据。参照下面的例子,输入的带标签数据被标注为一个数据集,并以分四列输入。如果在所提供的数据集中,其中一列缺失,系统会提出输入错误的警告,因为这一数据集与工作流是不相符的。
工作流的架构看起来像一个常规的Python函数,可以调用若干计算符,这些计算符执行的是真正的机器学习工作。虽然看起来很普通,但是FBLearner Flow采用了一个预测系统(system of future),在工作流内实现平行化迁移,让没有共享数据属性的步骤也可以同时运行。
Workflows的运行并不是连续性的,它分为两个部分:1,DAG编译部分;2,计算符执行部分。在DAG编译部分,工作流的计算符并不实际执行任务,而是反馈Futures。Futures指的是代表了计算延时模块的东西。所以在上文的例子中,dt变量其实是一个furure,它代表还没有发生的决策树训练。在DAG编译部分,FB Learner Flow记录了所有操作中的调用,还有一系列在进行操作开始前的futures。
比如,ComputeMetricsOperator和PredictOperator都把dt.model作为输入,这样以来,系统就知道,在操作运行前,nn必须要被计算,所以他们必须等待,直到 TrainDecisionTreeOperator完成。
完成了DAG编译部分后,FB Learner Flow就建立一个DAG 计算符,在这个计算符中,边界代表了数据的依赖性。这一个DAG随后能够被列入执行计划,在这儿,一旦它的父程序完全成功,计算符就能够开始执行。在这个例子中, ComputeMetricsOperator 和 PredictOperator的调用之间,不存在数据依赖性,所以这两个计算符的运行能够平行切换。
在计算符执行部分,每一个计算符在它的依赖计算符完成后,就开始运行。每一个计算符都有自己对CPU、GPU和内存要求,并且,FBLearner Flow将会分配机器的一部分,与计算符对任务的要求相匹配。FBLearner Flow 自动地处理,分配相关编码给机器,在输入和输出之间进行切换。
在Facebook中,有好几百个不同的工作流,在执行无数的机器学习任务。Facebook面临的一个挑战是建立一个通用的UI,能够与Facebook的工程师所使用的一系列工作流共同工作。使用通用的类型系统,可以建立一个UI,能以一个不了解工作流的方式阐释输入和输出,也就是不需要理解每一个工作流实施的细节。对于未来的定制化,FBLearner Flow用户界面提供了一个插件系统,能够被不用的团队尝试定制化体验,并且融入Facebook的系统中。
FBLearner Flow UI提供一些额外的体验:1)发布工作流 2)对结果进行可视化和比较3)管理试验。
此前,Facebook曾发现,每一个工作流都要求一个类型输入图式。工程师发布一个工作流时,UI能够读到这个输入图式,并自动地生成架构表格,并且把具体的输入与工作流进行匹配。这允许机器学习工程师在一行前端代码都不用写的情况下,能够为他们的工作流获得丰富的UI。这将能让UI渲染复杂的输入要素,比如为分类和选择数据集。
在用户界面上,工程师能够检查每一个工作流,观察输出,以修改标签和其它的元数据,并采取行动,比如配置模型,进行生产。Workflow中输入和输出可以进行对比,让工程师根据基线评价试验的表现。Facebook把对输出进行可视化的技术用于渲染输入,也就是用于提供具体类别,对每一个输出进行渲染的分类系统。
Facebook的工程师每天要进行几千次试验,FBLearner Flow UI提供了管理这些试验的工具。所有的workflow都在Elasticsearch中编了索引,所以可以通过多种维度搜到,并且,系统的支持把搜索词条存到更容易被发现的试验中。在进行模式调试时,工程师经常会运行复杂的参数扫描,通过特定的渲染,可以看到哪一个基阵产生了最好的结果。
FBLearner Flow平台的一个核心原则是,它不跟任何的算法进行捆绑。结果便是,平台能够支持大量的机器学习算法,以及结合了这些算法的创意。平台还很容易扩展,任何工程师都能写一个新的工作流来让整个公司的人都可以使用他或她最喜爱的算法。开放资源应用的算法能够便利地在工作流中使用,并融入Facebook 的基础设施中。
Facebook的应用机器学习算法团队在运行那些提供普通使用的算法可以扩展化的Workflow,其中包括:
- 神经网络
- 梯度推进的决策树
- Lambda MART
- 随机梯度递减
- 逻辑回归
有了FB Learner Flow,AI会变成编程团队的一个组成部分,并为Facebook的工程师提供通过简单的API调用,紧跟AI的发展潮流。Facebook一直努力地提升FBLearner Flow,来让工程师变得越来越有生产力,并在越来越多的产品中使用机器学习。这些改进包括:
效率:过去的四月,在一个包含了几千台机器群集里,运行了超过500000 工作流。其中一些试验要求大量的计算资源,需要花掉好几天才能完成。Facebook着眼于提升这些试验的运行效率,来保证平台在把执行延迟最小化的同时,满足不断增长的需求。Facebook正在围绕数据局部性寻找新的解决方案,用来源数据共置计算,并且,Facebook也正在提高对资源要求的理解,来尽可能地让更多的试验在每一个机器中都能进行。
速度:FBLearner Flow是一个每天能吸收万亿数据的系统,每天训练的模型超过几千个,不管是离线还是实时,随后,把这些模型用于生活预测的服务器。工程师和相关团队,即便是没有什么专业知识,也能建立和允许试验,以更熟练前所未有的速度把AI支持的产品部署生产。Facebook正在努力把工作流完成的周期最小化,让产品能从最新的数据中进行学习,允许工程是快速地进行多次试验。
机器学习的自动化:许多机器学习算法都有很多可有优化的超参数。在Facebook,许多模型的准确度1%的提升都能产生许多有意义的影响。所以,有了Flow,Facebook为大规模的参数扫描和其它的自动的机器学习功能建立支持,利用闲置的循环来进一步提高这些模型。在这一领域,Facebook会进行进一步的投资,在Facebook的多种产品中提升Facebook AI和机器学习的专业性。
在接下来的几个月里,Facebook将会对一些特定的系统和应于保持高度关注,这些系统和应用能够利用FBLearner Flow来给工程师提供条件,让他们便利的在产品中使用AI 和深度学习,同时,也可以为Facebook用户提供更加个性化的体验。
Facebook核心机器学习小组的负责人Hussein Mehanna在接受媒体采访时说,Facebook在Flow上除了发表学术论文,可以做的还很多,公司最后会把这一平台开源。
【来源:Facebook,由新智元(微信号:AI_era)编译:胡祥杰】
·氧分子网(http://www.yangfenzi.com)延伸阅读:
本文作者 Mikio Braun 是 Zalando 的推荐和搜索系统的交付带头人,Mikio拥有机器学习的博士学位。本文概述了一个能把数据科学引入生产系统的架构的典型模式。想了解更多的大规模复杂数据分析的内容,可以查看Mikio Braun的培训视频《大规模机器学习》。
在过去的几年间,数据科学这个概念已经被非常多的行业所接受。数据科学(源自于一个科学研究课题)最早是来自于一些试图去理解人类的智能并创造人工智能的科学家,但现在它已经被证明是完全可以带来真正的商业价值。
例如,我所在的公司:Zalando(欧洲最大的时尚品零售店)。在这里,数据科学和其他工具一起被用来提供数据驱动的推荐。推荐本身作为后端服务,被提供给很多地方,包括产品页面、分类目录页面、通讯电邮以及重新定位目标客户等。
数据驱动产生推荐
实际上,有非常多的方法可以由数据驱动产生推荐。例如,在所谓的“协同过滤”里,所有用户的行为(比如浏览商品、对想买商品列表的操作、以及购买行为)都可以被收集起来作为推荐的基础,然后分析发现哪些商品有相似的用户行为模式。这种方法的优美之处在于计算机根本不用知道这些商品是什么。而它的缺点则是商品必须要有足够多的用户行为信息数据才能保证这个方法起作用。
另外一类产生推荐的方法是只看商品的属性。例如,推荐具有相同品牌的或者相同颜色的商品。当然,对这些方法还有非常多的扩展或者组合。
更简单一些的方法就是只通过计数来做推荐。但这种方法在实践里会有非常多的复杂的变形。例如,对个性化推荐,我们曾使用过“学习排序”的方法,即对商品集做个性化的排序。上图里所显示的就是这个方法需要最小化的损失函数。
不过,这里画出这个图的主要目的,还是来展示数据科学可能会引入的复杂度。这个函数自身使用了成对的加权指标,并带有正则化条件。这个函数的数学展现是很简化的,当然也就很抽象。这个方法不仅对于电商的推荐场景有用,还对当物品有足够特征的时候的所有类型的排序问题也有用。
将数据科学方法引入工业界
为了把类似上图的非常复杂的数学算法引入到生产系统中,我们需要做什么?数据科学和软件工程之间的界面应该是什么样?什么样的组织架构和队伍结构才最适合使用这些数据科学的方法?这些都是非常相关和合理的问题。因为这些问题的答案将会决定对于一个数据科学家或者是整个数据科学团队的投资是否能最终得到回报。
在下文里,我会根据我作为一个机器学习的研究人员以及在Zalando带领一个数据科学家和工程师团队的经验,来对这些问题做一些探讨。
理解数据科学(系统)与生产系统的关系
让我首先从了解数据科学系统与后端生产系统的关系开始,看看如果将两者进行集成。
典型的数据科学工作流程(管道)如上图里所示:第一步总是从发现问题和收集一些数据(来自于数据库或者生产系统的日志)开始。取决于机构的数据准备好的程度,这一步有可能就是很困难的。首先,你有可能需要搞清楚谁能让你接触到所需的数据,并搞清楚谁能给你权限去使用这个数据。当数据可用后,它们就可能需要被再次处理,以便提取特征值。你希望这些特征可以为解决问题提供有用的信息。接着,这些特征值被导入学习的算法,并用测试数据对产生的结果模型做评估,以决定这个模型是否能较好地对新数据做预测。
上述的这个分析管道通常都是短期一次性的工作。一般是由数据科学家手工完成所有的步骤。数据科学家可能会用到如Python这样的编程语言,并包括很多的数据分析和可视化的库。取决于数据数量,有时候数据科学家也使用类似Spark和Hadoop这样的计算框架。但一般他们在一开始都只会使用整个数据集的一小部分来做分析。
为什么开始只用一小部分数据
开始只用一小部分数据的主要原因是:整个分析管道过程并不是一锤子买卖,而是非常多次反复迭代的过程。数据科学项目从本质上讲是探索性的,甚至在某种程度上是开放式的命题。虽然项目目标很清楚,但什么数据可用,或可用的数据是否适合分析,这些在项目一开始都不是很清楚。毕竟,选择机器学习作为方法就已经意味着不能仅仅只是通过写代码来解决问题。而是要诉诸于数据驱动的方法。
这些特点都意味着上述的分析管道是迭代的,并需要有多次改进,尝试不同的特征、不同的预处理模式、不同的学习方法,甚至是重回起点并寻找和实验更多的数据来源。
这整个过程本质上就是反复的,而且经常是高度探索性的。当做出的模型的整体的表现不错后,数据科学家就会对真实的数据运用开发的分析管道。到这时,我们就会面临与生成系统的集成问题。
区分生产系统和数据科学系统
生产系统和一个数据科学系统的最主要区别就是生产系统是一个实时地、在持续运行的系统。数据一定要被处理而模型必须是经常更新的。产生的事件也通常会被用来计算关键业务性能指标,比如点击率等。而模型则通常会每隔几个小时就被用新数据再进行训练,然后再导入生产系统中去服务于新来的(例如通过REST接口送入的)数据。
这些生产系统一般都是用如Java这样的编程语言写的,可以支持高性能和高可靠性。
如果你把生产系统和数据科学系统并排放置,那么就会得到一个类似上图的情况。在右上角,是数据科学的部分。其典型特征是使用类似Python的语音或者是Spark的系统,但一般是一次性的手工触发的计算任务,并经过迭代来优化整个系统。它的产出就是一个模型,本质上就是一堆学习到的数字。这个模型随后被导入进生成系统。而生产系统则是一个典型的企业应用系统,用诸如Java语言写成的,并持续运行。
当然,上面的这个图有一些简化了。现实中,模型都是需要被重新训练的,所以一些版本的数据处理管道会和生成系统集成在一起,以便不时地更新生产系统里的模型。
请注意那个在生成系统里运行的A/B测试。它对应于数据科学一侧的评估部分。但这两部分经常并不完全具有可比性。例如不把离线的推荐结果展示给客户,就很难去模拟一个推荐的效果,但有这样做可能会带来性能的提升。
最后,必须要意识到,这个系统并不是在安装部署完成后就“万事大吉了”。就如数据科学侧的人需要迭代多次来优化数据分析管道,整个实时系统也必须随着数据分布漂移来做迭代演进。由此新的数据分析任务就成为可能。对我而言,能正确做好这个“外部迭代”是对生产系统的最大的挑战,同时也是最重要的一步。因为这将决定你能否持续地改善生产系统,并确保你在数据科学上的初期投资取得回报。
数据科学家和程序员:合作的模式
到目前为止,我们主要关注的是生产环境里的系统是什么样。当然对于如何保证生产系统稳定和高效则有很多种方法。有时候,直接部署Python写的模型就足够了,但生产系统和探索分析部分的分离是肯定存在的。
你将会面对的艰巨挑战之一,就是如何协调数据科学家与程序员的合作。“数据科学家”依然是一个新的角色,但他们所做的工作与典型的程序员有着明显差异。由此导致的误解和沟通障碍就不可避免了。
数据科学家的工作通常是探索性的。数据科学项目一般始于一个模糊的目标、哪些数据可用的一些想法、以及可能的算法。但非常常见的情况是,数据科学家必须尝试多种想法,并从数据里获取洞察。数据科学家会写很多的代码,但是大部分都是用于测试想法,并不会被用于最终的解决方案。
与数据科学家相反,程序员通常非常关注于编程。他们的目标是开发一个系统,实现所要求的功能。程序员有时会做一些探索性的工作,比如构建原型、验证概念或是测试性能基准。但他们的工作的主要目标还是写代码。
他们间的不同还明显地体现在代码的变化上。程序员通常会坚持一个非常明确定义的代码开发流程。一般包括创建自己工作流的分支,在开发完成后做评测检查,然后把自己的分支合并进主分支。大家可以并行开发,但必须在协商后才能把他们的分支合并进主分支。然后这个过程再重复进行。这整个过程都是确保主分支会以一个有序的方式演进。
数据科学家也会写很多的代码。但正如我之前所说的,这些代码通常是为了验证想法。所以数据科学家可能是会写出一个版本1,但它并没有实现需求。然后又针对一个新的想法写了版本2,随后是2.1和2.2,直到发现还是不能实现需求而停止。再对更新的想法去写版本3和3.1。也许在这个时候,数据科学家意识到,如果采用2.1版里的某些方法并结合3.1版里的某些方法,就能获得一个更好的解决方案。这就带来了版本3.3和3.4,并可能由此形成了最终解决方案。
一个有意思的事情是,数据科学家实际上可能希望保留所有这些没成功的版本。因为之后的某个时间,也许它们又会被拿来测试新的想法。也许有些部分可以被放入一个“工具箱”里,逐步形成数据科学家自己的私人机器学习库。程序员更希望去删除“无用的代码”(因为他们知道如何快速地找回这些代码),而数据科学家则喜欢保留代码以防万一。
上述的两大不同意味着,在现实中,直接让程序员和数据科学家共同工作可能会出问题。标准的软件工程流程对数据科学家的探索性工作模式并不合适,因为他们的目标是不同的。引入代码评测检查和有序的分支管理、评测、合并分支的工作流对数据科学家而言并不合适,还会减慢他们的工作。同样的,把探索性的模式引入生产系统开发也不会成功。
为此,如何才能构建一个合作模式来保证两边都能高产出的工作?可能第一直觉就是让他们相互分离地工作。例如,完全分开代码库,并让数据科学家独立工作,产出需求文档,再由程序员团队实现。这种方法也行得通,但流程通常会非常得慢,且容易出错。因为重新开发实现一遍就可能会引入错误,尤其是在程序员并不熟悉数据分析算法的情况下。同时能否进行外部迭代来改进系统的表现也依赖于程序员是否有足够的能力来实现数据科学家的需求。
幸运的是,很多数据科学家实际上是希望能成为好的程序员,或是反过来。所以我们已经开始试验一些更直接和更能帮助加快流程的合作模式。
例如,数据科学家和程序员的代码库依然是分离的,但部分生产系统会提供清晰定义的接口来方便数据科学家把他们的方法嵌入进系统。与这些生产系统的接口进行沟通的代码必须严格地依据软件开发实践流程,但这是数据科学家的工作。用这种方式,数据科学团队可以在自己的代码快速地迭代,同时也就是完成了对生产系统的迭代。
这种架构模式的一个具体实现是采用“微服务”方法。即让生产系统去调用数据科学家团队开发的微服务来获取推荐。用这个方式,整个数据科学家使用的离线分析管道还可以被调整用来做A/B测试,甚至是加入生产系统而不用程序员团队重新开发实现。这种模式会要求数据科学家具有更多的软件工程技能,但我们看到越来越多的数据科学家已经具有这样的技能集。事实上,后来我们修改了Zalando的数据科学家的职衔为“研究工程师(数据科学)”来反应这种实际情况。
采用类似这样的方法,数据科学家可以快速实践,对离线数据做迭代研究,并在生产系统环境里迭代开发。整个团队可以持续地把稳定的数据分析方法迁移进生产系统。
持续适应并改进
至此,我概述了一个能把数据科学引入生产系统的架构的典型模式。需要理解的一个关键概念就是这样的系统需要持续地适应并改进(这和几乎所有的针对实际数据的数据驱动项目类似)。能够快速迭代,实验新的方法,使用A/B测试验证结果,这一切都非常重要。
依据我的经验,保持数据科学家团队和程序员团队的分离是不可能达成这些目标的。与此同时,很重要的是,我们也要承认两个团队的工作方式确实是不同的,因为他们的目标不一样(数据科学家的工作更加具有探索性,而程序员更关注于开发软件和系统)。
通过允许各自团队能工作在更适合他们的目标的方式,并定义一些清晰的接口,是有可能集成两个团队,并保证新的方法可以被快速地试错的。这会要求数据科学家团队具有更多的软件工程技能,或是至少能有软件工程师来桥接起两个世界。
作者介绍:Mikio Braun是Zalando的推荐和搜索系统的交付带头人。Zalando是欧洲最大的时尚品平台之一。Mikio拥有机器学习的博士学位,并在投身把研究成果转化成行业应用前进行了多年的研究工作。