作为第四范式·先知平台核心机器学习框架GDBT的设计者,屠维维在大规模分布式机器学习系统架构、机器学习算法设计与应用等方面有较深的积累。屠维维在演讲中表示,越来越多的企业开始利用机器学习技术,将数据转化为智能决策引擎。企业机器学习应用系统中核心模型训练系统的设计和优化有哪些考虑?与教材中的机器学习应用相比,在企业实际的机器学习应用中有哪些容易被忽视的陷阱?涂薇薇就此进行了经验分享,同时给出了一些可供参考的解决方案。业界大规模分布式机器学习计算框架设计经验机器学习的经典定义是利用经验(数据)来提升系统性能。在应用过程中,首先要明确机器学习的目标,即机器学习要做什么。以谷歌增加搜索广告业务收入为例,谷歌首先拆解了增加收入的目标,广告收入=平均单价点击率广告展示量,其中“广告展示量”受到严格控制(考虑政策和法规和用户体验),“每次点击价格”受广告商主动出价的影响。点击率差异较大,谷歌广告平台有自主权控制广告的展示。因此,谷歌要增加搜索广告收入,机器学习最适合优化“广告点击率”。确定机器学习的具体优化目标是广告点击率后,谷歌机器学习系统会循环执行四个系统:数据收集→数据预处理→模型训练→模型服务(模型服务生成的数据将被数据收集系统收集的下一个周期使用)。在这四个系统中,与机器学习算法最相关的是模型训练系统。在涂薇薇看来,在计算框架设计方面,没有通用的框架,只有最适合实际计算问题的框架。一个兼顾开发效率和执行效率的机器学习大规模分布式并行计算框架。在工业应用中,有效数据和特征维度正在迅速增加。在数据量方面,过去一个机器学习任务只有几万条数据,而现在一个业务的数据量可以轻松达到千亿级。在特征维度上,传统机器学习采用“抓大放小”的方法——只使用高频宏观特征,忽略包含大量信息的低频微观特征——进行训练,但随着算法、计算能力和数据收集能力的提升,不断增强,在机器学习训练中加入更多的低频微特征,使得模型的效果更加出色。特征频率分布机器学习技术在工业应用中也不断发展。机器学习最早的工业应用只使用宏观特征和简单模型,后来发展成两个不同的流派:以微软和雅虎为代表,只使用宏观特征,而使用复杂模型流派,以谷歌为代表,使用简单模型但利用微特征类型。时至今日,使用更多微观特征和复杂模型来更精细地描述复杂关系已成为大势所趋。这对模型训练提出了更高的要求。首先,训练系统需要分布式并行。由于功率墙(PowerWall,芯片密度不能完全提高)和延迟墙(LatencyWall,光速极限,芯片尺寸和时钟频率不能完全提高)的限制,摩尔定律慢慢失败。目前,提升计算能力的方法主要依靠并行计算,从早期的降低执行延迟到现阶段的提高吞吐量。在模型训练的高性能计算需求下,单机在IO、存储、计算等方面的能力不足。机器学习模型训练系统需要分布式并行化。当然,我们还需要牢记阿姆达尔定律。PowerWall,功耗随集成电路密度指数增加2倍,训练框架要求开发效率高。在机器学习领域,有一个著名的定理,叫做NoFreeLunch[WolpertandMacready1997],这意味着任何算法(包括随机算法)在所有问题上都具有相同的预期性能。问题,开发不同的机器学习算法。这就要求机器学习计算框架的开发效率非常高。典型的机器学习建模过程的第三部分是训练系统需要高执行效率。面对实际问题时,需要对数据、特征表达、模型、模型参数等进行多次尝试,而每次尝试都需要单独的模型训练。因此,模型训练是整个机器学习建模过程中重复次数最多的模块,执行效率成为重中之重。四是底层框架没有免费的午餐。对于不同的计算问题,各种计算资源的计算模式和要求是不同的,因此没有适合所有问题的完美架构,只有最适合实际问题的架构。基于机器学习任务特点的框架设计可以更有效地解决大规模机器学习模型训练的计算问题。开发效率的优化就提高开发效率而言,这里有两个方面:计算和编程模型的选择,以及编程语言的选择。有两种类型的并行计算范例。一种是基于共享内存的并行计算范式。不同的计算节点共享同一块内存。这里底层需要处理内存访问冲突等问题。这种模式一般用于小型处理器。另一种是基于消息传递的并行计算范式。每个计算节点使用自己的内存,计算节点通过消息传递的方式进行并行计算。在实际的分布式并行系统中,多机之间一般采用消息传递,单机内部一般采用共享内存(有些系统也是基于消息传递)。机器学习的分布式模式分为数据分布和模型分布。数据分发是指将训练数据切割成许多部分,不同的机器处理部分数据。但是对于一些比较大的模型,单台机器可能无法完成整个模型的计算,所以将模型切割成很多部分,不同的机器计算模型的不同部分。在实际应用过程中,根据不同场景的需要,两者一般是并存的。数据分布和模型分布式机器学习模型训练中最常见的分布式并行计算模型是分布式数据流计算模型。数据流模型是一种数据驱动的并行计算执行模型。数据流计算逻辑是基于数据流图来表达的。用户通过描述计算流程图来完成计算,并在计算流程图中定义计算节点。一般情况下,用户不需要指定具体的执行过程。数据流图中不同数据的计算一般都是异步完成的,其中的计算节点只要上游准备好就可以执行计算逻辑。目前主流的ETL(Extract-Transform-Load)数据处理框架如Hadoop、Spark、Flink等都是基于数据流计算模型。然而,机器学习计算任务有一个共享的中间状态,这个中间状态不断被擦除:模型参数,计算过程会不断读写中间状态。数据流的计算模型在执行过程中一般是异步的,因此很难控制共享的中间状态模型参数的一致性。因此,基于数据流计算模型的一致性模型一般都是同步的,保证了数据流内部的强一致性,但是基于同步的系统的执行性能依赖于最慢的计算节点,计算效率相对较低。数据流计算模型中的模型参数混淆另一种常见的分布式并行计算模型是基于参数服务器的分布式计算模型。参数服务器是对机器学习模型训练和计算中共享状态的直观抽象——模型参数管理。模型参数的读写由统一的参数服务器管理。参数服务器本质上是一个支持多种一致性模型的模型。高性能Key-Value存储服务。可以基于参数服务器实现不同的一致性模型。一个极端是BSP(BulkSynchronousParallel,同步并行)。所有计算节点在计算过程中获得一致的模型参数,保证了算法实现的一致性。但代价是同步造成的资源浪费;另一个极端是ASP(AsynchronousParallel,异步并行),所有计算节点在计算过程中对彼此之间的模型参数没有任何一致性保证,计算节点完全异步执行,这种一致性模型的计算效率很高,但模型参数没有一致性保证,不同节点获取不同版本的模型,训练过程不稳定,影响算法效果;CMU的ErixXing教授提出了一种介于BSP和ASP之间的SSP(StaleSynchronousParallel),通过限制最不一致参数版本的数量来控制整体的同步节奏。对收敛性有更好的保证。基于不同的一致性模型,可以很好地在运行速度和算法效果之间进行权衡。实际上,数据流计算模型和参数服务器计算模型描述了机器学习模型训练和计算过程的不同方面。用数据流来描述机器学习样本数据的流动是很自然的,模型训练过程中的中间状态可以用参数服务器来描述。计算模型的自然描述。因此,两者的结合是整体的发展趋势:参数服务器是在数据流中读写的。例如,Intel在Spark上开发了参数服务器。但是,数据流计算模型和参数服务器计算模型的一致性模型是不同的。参数服务器的一致性模型,如BSP或SSP,会打破数据流原有的异步计算逻辑。结合参数服务器和数据流的容灾策略和一致性管理策略需要精心设计才能很好地统一和集成。数据流与参数服务器相结合的架构编程模型及编程语言的选择编程范式可分为命令式和声明式两种。命令式编程是通过显式指定具体的执行过程来编程的。常见的命令式语言有C/C++等;与命令式编程不同,声明式编程不指定具体的执行过程,只定义和描述计算任务目标,具体的执行交给底层计算框架。命令式编程由于对具体执行过程的明确规范而更加灵活,而声明式编程的底层计算框架可以针对执行过程进行更深入的优化,可能效率更高。在实际的机器学习模型训练计算框架中,两者一般并存,如MxNet、Tensorflow等。学习模型训练计算框架一般采用前后端分离的方式:C/C++、Java/Scala等,后端保证系统运行效率,前端使用Python、R等提供更易于使用的编程接口。在后端语言的选择上,主流是Java和C++,两者各有优缺点:在生态方面,Java远好于C++,因为开发方便,很多大数据计算框架基于Java或类Java语言开发;在可移植性方面,Java优于C++,因为JVM屏蔽了许多底层差异;在内存管理方面,基于GC的Java在大数据的情况下效率更高,同步分布式并行的效率远低于经过优化的C++的效率,因为在大数据的情况下,GC的概率会很高,而一旦一台服务器启动GC,其计算能力将受到很大影响,整个集群的计算效率,尤其是同步的情况下,也会降低。会大大降低,当机器数量增加时,某个时刻触发GC的概率也会大大增加;在语言抽象方面,C++的模板机制在编译期得到了扩展,可以做更多的编译优化。除了生成的程序文件较大外,整体执行效率非常高,相应的Java泛型是通过类型擦除实现的。实际运行时做数据类型转换会带来很多额外的开销。使其整体执行效率大受影响。在实际的机器学习模型训练系统设计中,具体选择取决于框架设计者的喜好和实际问题的需要(如系统部署要求、开发成本等)。执行效率的优化在执行效率的优化方面,主要举例分享四个方面的优化:计算、存储、通信、容错。在计算方面,最重要的优化点是均衡。平衡不仅包括不同机器、不同计算线程之间的负载平衡,还包括算术和逻辑运算资源、存储资源、通信资源等各种与计算相关的资源之间的平衡。最终目标是最大化所有计算资源的利用率。在实际优化过程中,需要仔细剖析程序,找出可能存在的性能瓶颈,对性能瓶颈进行优化,解决瓶颈问题。但是此时性能瓶颈可能会发生转移,因此需要不断迭代:Profiling→DiscoveryBottleneck→Solvethebottleneck。典型的计算性能优化周期CPU和GPU架构与分布式计算相比代价高昂,例如序列化成本、网络通信成本等。并非所有任务都需要分布式执行。在某些情况下,一个任务或者任务的某部分,单机就可以很好的执行,不要为了分发而分发。为了获得更好的计算性能,需要将单机和分布式分开优化。CPU、GPU、FPGA等不同硬件各有优势。比如CPU适合复杂指令,有分支预测,缓存大,适合任务并行;粒度数据并行,但不适合复杂指令执行,可用于加速矩阵运算等粗粒度并行计算任务;针对特定的计算任务,比如深度学习预测,FPGA在CPU和GPUPeak之间优化了性能,同时功耗远低于GPU芯片。机器学习任务需要合理的任务调度,以充分发挥不同计算硬件的优势,提高计算硬件的利用率。近年来,CPU、GPU等计算硬件的效率提升远快于主存性能,因此计算与存储之间的性能差距不断扩大,形成了“内存墙”。因此,在众多问题上面,存储优化更为重要。在存储方面,从CPU寄存器到L1、L2等高速缓存,再到CPU本地内存,再到其他CPU内存、外存,存储结构复杂,存储硬件不同,访问效率也参差不齐。震级。不同之处。JeffDean建议程序员牢记不同存储硬件的性能数据。存储层级架构、性能数据、存储墙针对存储层级和各层级存储硬件的性能特点,可以采用数据本地化、内存访问方式等存储优化策略。因为机器学习是迭代的,一些训练数据或者一些中间计算结果都可以放在本地,再次训练时不需要请求远程数据;另外,在单机的情况下,还可以尝试不同的内存分配策略和调整计算方式,加强数据本地化。在内存访问方式优化方面,也可以进行很多优化:数据访问重排序,比如GPU纹理渲染和矩阵乘法运算中常用的Z-order曲线优化;数据布局调整,例如可以使用更紧凑的数据结构来提高顺序内存访问的缓存效率高。同时,在多线程场景下,尽量避免线程间频繁竞争申请内存释放,会竞争同一个锁。另外,冷热数据可以分离,提高缓存效率;例如数据预取,可以使用另一个线程提前预取数据以更快的存储,提高后续计算的内存访问效率。通信是分布式机器学习计算系统的重要组成部分。通信包括点对点通信和组通信(如AllReduce、AllGather等)。可以通过软件优化和硬件优化来提高执行效率。在软件优化方面,可以通过序列化框架优化、通信压缩、应用层优化等方式进行优化:通信依赖于序列化,一般的序列化框架如ProtoBuffer、Thrift等,语言方面的考虑会牺牲一定的效率,并且可以针对特定通信场景设计更简单的序列化框架,提高序列化效率。当带宽成为瓶颈时,可以考虑用CPU来交换带宽,比如使用压缩技术来降低带宽压力。更重要的优化来自于对应用层通信方式的考虑,可以做更多的优化:比如parameterserver的client可以将同一台机器上多个线程的请求结合起来,因为在同一个机器学习训练过程中,不同线程之间大概率会出现多次重复的模型参数请求;或者根据parameterserver的不同一致性模型,做请求缓存,提高查询效率,降低带宽;或者对于不同的网络拓扑结构,可以采用不同的组通信方法来实现。除了软件优化外,通信架构还需要充分利用硬件特性来提高网络吞吐量,降低网络延迟。例如,您可以配置多个网卡建立冗余链路以提高网络吞吐量,或者部署Infiniband以提高网络吞吐量并降低网络延迟。.在容错方面,对于不同的系统,容错策略的核心差异在于选择最合适的Tradeoff。这里的Tradeoff指的是在每次失败后恢复任务的成本和降低这个成本的开销之间的权衡。在选择机器学习模型训练系统的容错策略时,需要考虑机器学习模型训练任务的特点:首先,机器学习模型训练是一个迭代计算任务,有很多中间状态;其次,机器学习模型训练系统中的模型参数是最重要的状态;***,机器学习模型训练不一定要求强一致性。业界对于机器学习训练任务的容灾方案有DataLineage和Checkpointing两种。数据沿袭通过记录数据源简化了数据源的跟踪。一旦数据出错或丢失,可以根据DataLineage找到之前的数据,通过反复计算恢复数据。常见的开源项目Spark就采用了这种容灾方案。DataLineage的粒度可大可小,需要一个相对可靠的DataLineage维护服务。整体开销比较大。对于机器学习模型训练中的共享状态——模型参数不一定是好的容灾方法,因为模型参数是共享的,中间状态很多。每个中间状态依赖于之前版本的模型参数和所有中间数据的计算;与DataLineage不同,机器学习模型训练系统中的Checkpointing策略一般侧重于机器学习模型参数的容灾,由于机器学习是迭代的,所以可以利用这一点。在满足机器学习一致性模型的情况下,可以在单次或多次迭代之间或迭代内调整机器学习模型参数。以及灾难恢复的训练进度,以便在出现故障时,可以从上一次迭代的模型检查点开始,进行下一次迭代。与DataLineage相比,机器学习模型训练系统对模型参数和模型训练进度进行Checkpointing容灾更为自然和合适。因此,目前主流的专为机器学习设计的计算框架,如Tensorflow、Mxnet等,都使用了Checkpointing。灾难恢复策略。除了上述容错方式外,还可以采用传统容灾中常用的冗余系统进行容灾。根据容灾系统的在线状态,可分为冷、温、热备份方式。在实际应用中,可以根据实际的资源和计算性能需求,选择最适合实际问题的冗余容错方法。机器学习实际应用中的常见陷阱在实际的机器学习应用中,往往存在容易被忽视的陷阱。以下是分享一些常见陷阱的示例:一致性、开放世界、依赖管理、可理解性/可调试性。一致性陷阱一致性陷阱是最容易被忽视的陷阱。首先,训练/估计一致性问题是最常见的,包括不一致的特征表达和不一致的目标意义。特征表达不一致比较常见,原因有很多:不同的表达比较常见,比如在训练数据中,0代表男性,1代表女性,但是在估计数据中,1代表女性,0代表男性;trainingandevaluationfeatures在抽取过程中,一方或双方出现逻辑错误,会导致不一致;有一种更微妙的不一致叫做“遍历”,这种不一致在时间序列数据中尤其容易出现。因果逻辑的信息,比如在使用特征时整个训练数据集中正反例的个数/比例,实际上是隐含的使用了样本的标注信息,但是在训练过程中是不可能提前获取到的。估计过程。标记信息(否则无需估计);又比如有些特征使用的是当前样本时间点之后的信息,但这在实际估计中是做不到的,因为目前不可能穿越到未来。另一种不一致是目标含义的不一致。例如,目标是优化搜索结果的用户满意度,但将用户点击作为机器学习的目标。用户点击某个搜索结果并不代表用户对该结果感到满意。另一种经常被忽视的一致性是字段含义随时间变化。在实际应用中,需要注重一致性检验,关注特征的具体物理意义,避免出现特征表达不一致、目标意义不一致、随时间不一致等问题。开放世界陷阱当机器学习系统应用于实际业务时,它面临的是一个开放世界。机器学习系统不再是静态孤立的系统,而是需要与外界打交道。这里有很多陷阱。有一个非常著名的幸存者偏差问题,因为当前模型会影响下一个模型的训练数据。如果没有干预,训练数据就会有偏差。这种偏差***的起源来自于二战。一组科学家研究了如何加强飞机以提高飞机在战场上的生存率。他们在战场上幸存下来的飞机上找到了弹孔并进行了分析。最后,他们得出了一个结论:腹部中弹最多,所以需要在腹部进行加固,以提高存活率。不过,统计学家亚伯拉罕沃尔德指出,他们忽略了那些被击毁的飞机,因为它们被击中机翼和发动机等关键部位,因此保护机翼和发动机等关键部位可能更好,以提高飞机在战场上的生存率。此类问题在推荐系统、搜索引擎等系统中非常常见。用户看到的结果是基于机器学习模型推荐的,这些结果会成为下一次机器学习模型训练的数据,但是这些数据是有模型偏差的。本质上,这是Exploitation和Exploration之间的权衡,需要以长期效果为目标。解决这样的问题,可以参考强化学习中的解决方法。除了幸存者偏差陷阱之外,机器学习系统还可能与实际业务系统中的其他系统进行协作。机器学习系统的输出会随着数据的变化而变化,但是如果与之配合的系统依赖于机器学习系统输出的阈值等参数是固定的,则可能会影响整个系统的效果。在实际应用中,需要监控机器学习系统的输出分布及其对其他系统的影响,可以采用估计分布修正等策略。依赖陷阱粗心的依赖很容易导致非常灾难性的后果,但在实际应用中却常常被忽视。常见的依赖性有:数据依赖性:与传统软件系统不同,机器学习系统的性能依赖于外部数据。数据依赖比代码依赖更可怕,因为很多时候它是隐含的,很难检测或分析。大公司经常发生的是模型之间的依赖。在解决某个业务问题时,建立机器学习模型B。为了快速绘图,它依赖于其他团队模型A的输出,但如果依赖团队升级模型A,对B来说将是灾难性的。除了数据依赖和模型之间的依赖之外,更难检测的是什么是隐式依赖。可能有一些特征字段会被模型本身改变。随着推荐模型的升级而变化。在实际应用中,要密切关注数据依赖,尽量避免模型之间的依赖,避免隐式依赖。可理解性/可调试性陷阱可理解性/可调试性是最容易被忽视的。在实际的业务应用中,为了追求效果可能会使用一个非常复杂的模型,那么这个模型可能很难理解,也很难调试。对于一些业务,比如医疗应用、银行审计等,对模型的可理解性有要求。为了便于理解,一种常见的解决方案是进行模型转换。比如周志华教授提出的TwiceLearning方法,可以通过TwiceLearning将一个非常复杂的应用模型转化为性能相近的决策树。模型,而决策树模型是一个比较通俗易懂的模型。另一种方法是解释模型的预测结果。比如***的作品LIME就借鉴了类似TwiceLearning的思想,在局部用可理解的模型来解释复杂的模型。可调试性对于实际应用来说非常重要,因为模型几乎不可能100%正确,而且为了追求业务效果,很容易使用非常复杂的特征和模型,但在模型复杂的情况下不会出现badcase和特征,或者如果要提高模型的性能,就会难以分析,导致模型难以改进,不利于后续开发。因此,在实际业务中,需要选择适合实际问题和团队能力的特征和模型复杂度。[TwiceLearnig和LIME]总结机器学习使用数据来提高系统性能。它是一种以数据驱动的方式实现人工智能,已广泛应用于各行各业。随着实际业务数据量和数据维度的增长,计算能力的不断提升,以及机器学习算法的不断优化,机器学习在行业应用中正在从早期简单模型的宏观特征向微观特征转变今天的复杂模型。向机器学习训练系统的设计和优化转变带来了新的挑战。机器学习应用的核心系统包括数据采集、数据预处理、模型训练和模型服务。每个系统对计算、存储、通信和一致性都有不同的要求。对于模型训练系统,由于摩尔定律的失效,实际业务的整体数据量和数据维度不断增长,机器学习算法的没有免费的午餐定理,需要在实际建模过程中进行频繁的尝试,和NoFree计算框架。Lunch,实际的机器学习系统需要一个专门为机器学习设计的兼顾开发效率和执行效率的分布式并行计算框架。本次分享首先介绍了解决开发效率中计算和编程模型的选择,以及编程语言的选择。开发者需要根据自己的实际应用场景、开发成本、团队能力等进行取舍和选择。然后通过实例介绍了解决执行效率所涉及的计算、存储、通信和容错等方面的设计和优化。ContinuousProfiling,迭代消除瓶颈,均衡利用好各种计算资源,尽可能地最大化利用各种计算资源,从而提高整体执行效率。当机器学习应用于实际业务时,会出现很多容易被忽视的陷阱。本次分享简单介绍了一致性陷阱的常见类型、机器学习在开放世界中的陷阱、机器学习系统中各种依赖的陷阱,以及容易被忽视的模型可理解性和可调试性。介绍,同时给出了一些可供参考的解决方案。在实际的机器学习应用中,需要尽可能避免踏入这些陷阱。
