机器之心分析师网络
编辑:H4O
一、机器学习和无服务器学习
1.1、机器学习(ML)在应用场景中遇到了什么问题?
近年来,机器学习(MachineLearning,ML)在图像识别、文本和语音处理等领域中广泛应用,改变了人们工作、生活的方式,带来了巨大的便利性。但同时,ML用户也面临着几个巨大的挑战,这些挑战极大地阻碍了ML的生产力和效率。首先,用户通常需要手动配置许多系统级参数,例如工作服务器/参数服务器的数量、内存分配、cpu数量、物理拓扑等。其次,用户需要指定大量与ML相关的参数,如学习率、学习算法、神经网络结构等,这些参数与系统级参数之间还存在各种交互作用。第三,ML工作流通常由多个阶段组成,包括预处理、训练、超参数搜索等等,每个阶段都有ML用户必须考虑的不同计算需求。
由于ML的这些特点,在实际应用中经常会导致两个问题:
一是,ML工作流中不同任务的异构性导致了训练工作流执行过程中资源的严重不平衡。ML用户需要单独考虑每个阶段的异构资源需求,常常会导致资源过度配置(ResourceOverprovisioning)。当前的ML框架通常是基于粗粒度的VM集群的,而这些集群并不具备ML相关工作负载所需的灵活性。CPU总利用率低至20%的情况并不少见[1]。在实践中,开发人员在工作流的不同阶段反复使用不同的ML参数进行实验会进一步加剧资源过度配置的问题;
二是,ML用户需要应对复杂的管理问题,他们面临着为每个ML工作负载提供、配置和管理这些资源的挑战。利用VMs进行机器学习工作负载的系统通常需要用户重复执行一系列繁重的任务,表1中展示了一些任务。这种管理复杂性阻碍了交互和迭代用例,降低了用户生产力和模型的有效性。
在实践中,过度资源调配和显式资源管理负担这两个问题是紧密耦合的:ML用户在遇到工作流不同阶段所需资源精确分配所带来的难度和人工成本的问题时,通常会采用过度资源调配的方式来应对。
那究竟用什么办法应对ML在实践中应用的这些问题呢?在这篇文章中我们一起来探讨一个目前广泛应用且获得了非常好效果的办法:无服务器计算(ServerlessComputing)。
表1.ML用户在使用VM集群时遇到的任务挑战。
1.2、无服务器计算(ServerlessComputing)
无服务器计算是云原生计算模型的一种落地状态。云计算的发展在经历了基础设施即服务(InfrastructureasaService-IaaS)、平台即服务(PlatformasaService-PaaS)、软件即服务(SoftwareasaService-SaaS)几个阶段后,逐渐进入了无服务器计算的阶段。从与之前几个阶段所能提供的服务进行比较的角度分析,无服务器计算可以提供以下一种或两种服务:
1.函数即服务(Functions-as-a-Service-FaaS)。开发人员使用由事件(event)或HTTP请求触发的函数运行和管理应用程序代码,开发人员将这些小的代码单元部署到FaaS中,FaaS按需执行和扩展,开发人员则无需管理服务器或任何其他底层基础设施。
2.后端即服务(Back-as-a-Service-BaaS)。提供第三方的基于API的服务用于替换应用程序中的核心功能子集。对于开发人员来说,这些API是作为一个自动扩缩容和透明操作的服务提供的,所以对于开发人员来说,这种服务方式也是无服务器的。
从技术实现的角度分析,无服务器计算依靠云基础设施而不是用户来自动解决资源调配和管理的挑战。这种方法依赖于一个更受限制的计算单元,例如AWSLambda的无状态Lambda函数(theStatelessLambdaFunction),该计算单元由开发人员提交,并由云基础设施安排执行。因此,用户无需手动配置、部署和管理长期计算单元(例如VM)。无服务器模式的优势促进了数据中心、云提供商和开放源代码平台的快速应用。
无服务器计算所提供的服务包括:一种有时间限制的无状态函数作为执行程序逻辑的服务API,以及,一种管理程序状态的对象存储系统。通过使用服务API,用户可以运行代码函数(也称为操作)并返回每个函数的结果。无服务器计算还提供HTTPS终端,允许开发人员检索函数结果,开发人员可以通过HTTPS终端输入参数后生成相关函数的触发事件(或链接)。对于能够清晰地分离程序状态和逻辑的应用程序设计人员来说,无服务器计算平台提供了对大型计算能力的即时访问,使得程序设计人员无需进行复杂的集群部署。
在无服务器计算平台中,云服务提供商提供了按需执行函数的能力,并对最终用户隐藏了集群配置和管理开销。除了可用性方面的好处外,这种模式还提高了效率:云提供商可以以比传统集群计算更精细的粒度复用资源,并且用户不需要为空闲资源付费。然而,为了有效地管理资源,云服务提供商对每种资源的使用进行了限制。
计算(computation)。无服务器计算平台中提供的计算资源通常仅限于一个CPU核和一个较短的计算窗口。例如,AWSLambda在单个AVX内核上提供900秒的计算时间,可以访问高达3GB的内存和512MB的磁盘存储。用户可以执行许多并行函数,并且这些执行的聚合计算性能几乎呈线性扩展。函数执行中的线性可伸缩性只在单个worker之间没有通信的情况下对并行计算有用。在实际应用中,由于单个worker只是瞬时存在的,他们的启动时间可能是错开的,因此传统的类似MPI的点对点通信模型无法在这种环境中工作。我们可以考虑利用存储作为worker之间的间接通信通道。
存储(Storage)。云服务提供商提供了多种存储选项,从键值存储到关系型数据库。有些服务不完全是弹性的,因为它们需要预先提供资源。然而,像AmazonS3或GoogleCloudStorage这样的分布式对象存储系统提供了无限存储,用户只需按存储的数据量付费。我们可以考虑潜在地将计算期间的中间状态存储在分布式对象存储中,并且仍然可以获得与从其他节点的RAM访问时相同的带宽。
控制面(ControlPlane)。除了存储服务,云服务提供商还提供发布-订阅服务,如AmazonSQS或GoogleTaskQueue。这些服务通常不支持高数据访问带宽,但提供一致性保证,如至少一次传递,并且可以用于“控制平面”状态:所有无服务器函数调用之间共享的任务队列。云服务提供商还提供一致的键值存储(例如DynamoDB),可用于跨无服务器函数调用存储和操作控制平面状态。
由于无服务器计算存在上述约束条件,在实际应用中,无服务器计算也不是“完美无缺”的,应用无服务器计算也面临很多问题。以AWSLambda为例,利用无服务器计算的主要挑战是与Lambda函数相关联的非常小的本地资源约束(内存、cpu、存储、网络),这是无服务器计算的基础,正因为这些细粒度的计算单元实现了可伸缩性和灵活性。具体的,无服务器计算面临着如下问题:
本地内存和存储空间小(Smalllocalmemoryandstorage)。由于存在计算资源限制,阻止了使用任何未使用这些资源设计的计算框架。例如,我们无法在AWSLambda或具有此类资源受限配置的VM上运行Tensorflow或Spark。
低带宽以及缺乏P2P通信(LowbandwidthandlackofP2Pcommunication)。与常规VM相比,Lambda函数的可用带宽有限。我们发现,最大的AWSLambda只能维持60MB/s的带宽,即使在中型VM中,也远远低于1GB/s的可用带宽。此外,无服务器计算对通信拓扑施加了进一步的限制。诸如AWSLambda之类的无服务器计算单元不允许对等通信。因此,传统的用于数据中心ML的通用通信策略,例如树结构或环结构AllReduce通信等等,在这样的环境中都无法有效实现。
短暂且不可预测的加载时间(Short-livedandunpredictablelaunchtimes)。Lambda函数的寿命很短,且启动时间非常多变。例如,AWSLambda在加载后可能需要几分钟的时间来启动。这意味着在训练过程中,Lambda会在不可预知的时间开始,并且有可能在训练中途结束。这就要求Lambda的ML运行时能够容忍worker的频繁离开和到达。
缺乏快速共享存储(Lackoffastsharedstorage)。因为Lambda函数之间不能连接,所以需要使用共享存储。由于ML算法有严格的性能要求,这种共享存储需要低延迟、高吞吐量,并针对ML工作负载中的通信类型进行优化。然而,到目前为止,还没有能够为云提供所有这些属性的快速无服务器存储。
不过,目前已经有不少无服务器计算的落地应用案例。其中,有代表性的公有云无服务器平台有:
AWSLambda。亚马逊的AWSLambda,借助Lambda,几乎可以为任何类型的应用程序或后端服务运行代码,而且完全无需管理。只需上传代码,Lambda会处理运行和扩展高可用性代码所需的一切工作。开发人员可以将代码设置为自动从其他AWS服务触发,或者直接从任何Web或移动应用程序调用。。
MicrosoftAzureFunctions。微软的Azure是一个事件驱动(Event-drive)的无服务器计算平台,可以解决复杂的编排问题。本地构建和调试,无需额外设置,在云中大规模部署和操作,并使用触发器和绑定集成服务。。
GoogleCloudFunctions。Google的CloudFunctions是一种事件驱动的计算服务。它具有自动扩展、运行代码以响应事件的能力,仅在代码运行时付费的能力,并且不需要任何服务器管理。用例包括无服务器应用程序后端,实时数据处理和智能应用程序,如虚拟助手,聊天机器人和情绪分析。
阿里云函数计算(FunctionCompute)。阿里的函数计算是一个事件驱动的全托管无服务器计算服务,无需管理服务器等基础设施,只需编写代码并上传,函数计算会准备好计算资源,并以弹性、可靠的方式运行代码。所有客户,函数计算都将提供每月100万次函数调用、400,000个函数实例资源的免费无服务器算力支持。。
有代表性的私有云无服务器框架有:
Fission。Fission使用Kubernetes构建函数。它允许程序员使用任何编程语言编写函数,并将其与任何事件触发器(如HTTP请求)进行映射。。
Funktion。Funktion是一个开源的容器本地化服务器平台,使用Kubernetes构建函数。它允许程序员用任何编程语言编写函数,可以在任何地方、任何云上或在本地运行。。
Kubeless。是一个kubernets原生的无服务器计算框架。它利用Kubernetes资源提供自动缩放、API路由、监控、故障恢复等功能。。
ApacheOpenWhisk。OpenWhisk使用Docker构建函数,它允许程序员使用Scala语言编写函数,允许在任何规模的事件响应中执行代码。框架响应类似HTTP请求这样的触发事件,然后运行JavaScript或Swift代码片段。。
IronFunctions。Iron使用Docker、Swarm、Kubernetes构建函数,它允许程序员使用Go语言编写函数。。
OpenLambda。OpenLambda是一个Apache许可的无服务器计算项目,用Go编写,基于Linux容器。OpenLambda的主要目标是探索无服务器计算的新方法。。
OpenFaas。OpenFaaS是一个使用Docker构建无服务器(Serverless)功能的框架,它拥有对指标的一级支持。任何流程都可以打包为一个函数,使你能够使用一系列web事件,而无需重复的样板化编码。。
有代表性的无服务器平台的包装框架有:
Chalice(Python,AWS)。Chalice允许开发者快速创建和部署应用,采用AmazonAPI网关和AWSLambda。。
(Node,AWS)。方便快速部署项目到AWSLambda和API网关。它自动化了所有容易出错的部署和配置任务,并按照JavaScript开发人员所期望的开箱即用的方式设置了一切。开发人员可以轻松地开始使用Lambda和API网关,并专注于解决重要的业务问题,而不是处理AWS部署工作流。。
二、引入ML的无服务器计算最新研究情况介绍
由上一节的介绍我们知道,目前已经有很多公有云、私有云无服务器计算平台,也有一些无服务器平台的包装框架。可以说,我们想在日常的应用实践中尝试无服务器化,已经是比较容易的一件事了。不过,具体到机器学习的问题,这些无服务器计算平台在ML应用场景下都或多或少存在一些问题。
由第一章中的介绍我们可以看到,无服务器计算非常适用于离散化数据中心(DisaggregatedDatacenters),但对许多性能关键型应用(Performancecriticalapplications)却不是非常适用,因为无服务器计算方式切断了传统的性能优化途径,例如利用数据局部性进行优化或分层通信等,因此会直接影响性能关键型应用的效果。目前无服务器平台主要用于简单的事件驱动应用程序,如物联网自动化、前端web服务和日志处理等等。
2.1、ACaseforServerlessMachineLearning[2]
本文是来自Berkeley的研究人员发表在NIPS2018中的一篇文章,具体分析了ML工作负载环境下的资源管理问题,探讨了利用无服务器基础设施实现ML工作流资源管理自动化的研究方向。作者提出了一个无服务器机器学习框架,该框架专门用于无服务器基础设施和ML工作流。
本文所讨论的无服务器计算依赖于AmazonS3的无状态Lambda函数,这些函数由开发人员提交,并由云基础设施自动调度。因此,它们避免了开发人员显式配置、部署和管理长期计算单元(例如VM)的需要。与一般的无服务器计算平台不同,无服务器机器学习框架需要满足三个关键目标。首先,它的API需要支持广泛的ML任务:数据预处理、训练和超参数优化。为了简化从现有ML系统的转换所涉及的工作量,应该用Python之类的高级语言开发这样的API。第二,为了为无状态工作者之间的中间数据和消息传递提供存储,它需要提供一个具有丰富接口的低延迟可伸缩数据存储。第三,要在资源受限的Lambda上高效运行,它的Runtime必须是轻量级和高性能的。
为了满足这些条件,作者构建了一个专门用于ML的无服务器框架。
首先,该框架为ML工作流的所有阶段提供了一个API,该API实用且易于更广泛的ML社区使用。(1)API完全包含在Python包中,允许ML开发人员轻松调用。(2)API提供了一个抽象底层系统级资源的高级接口。(3)Python包提供了一个用户界面,开发人员可以通过该界面可视化工作进度。
然后,该框架包含Python前端提供到客户端后端的接口。这个后端负责管理临时计算资源和调度任务。在这个后端中,不同的子模块为ML工作流的每个特定阶段的逻辑(例如预处理)进行编码处理。这些子模块启动Lambda上的worker,跟踪计算进度,并在计算完成后将结果返回到Python前端。客户端后端使用内部低级调度程序,该调度程序封装了与启动、终止和重新生成在无服务器Lambda上运行的任务相关的所有逻辑。这个调度程序还跟踪所有任务的状态。
第三,该框架提供一个轻量级Runtime,它封装了系统支持的不同计算之间共享的所有函数,从而简化了新算法的开发。Workerruntime提供两个接口。首先,它提供了一个智能迭代器来训练存储在S3中的数据集。这个迭代器在Lambda的本地内存中预取和缓冲mini-batch,与worker的计算并行,以减轻访问S3的高延迟(10ms)。它为分布式数据存储提供了一个API。
最后,该框架为workers之间的中间数据和通信提供具有丰富接口的共享存储。此接口有两种类型的API:(1)用于一般消息传递、中间数据存储和数据缩减的键值存储,以及(2)参数服务器接口。为了达到所需的低延迟,将该数据存储部署在云VMs上。为了有效地利用稀缺的网络资源,对数据存储接口进行优化处理,例如:数据压缩、稀疏数据结构、异步通信等。
为了实现简化机器学习工作流执行的目标,理想的系统应该提供一个简单但足够通用的API。这个API需要让用户在一个单一的、集成的框架内执行ML任务,例如:(1)数据集加载,支持常用的数据格式,(2)数据预处理,(3)模型训练,(4)大规模的超参数调整。
图1.API示例。无服务器ML的API应该支持ML开发工作流的不同阶段:(a)预处理,(b)训练,和(c)超参数调优。
为了评估对ML无服务器框架的需求,作者引入两个框架进行性能比对:PyWren[3]和Bosen[4]。PyWren是一个专门用于无服务器架构的Map-reduce框架。PyWren提供了可缩放到数千个workers的map和reduce原语。Bosen是一个分布参数框架,专门用于基于VM的ML算法。为了进行评估,作者在PyWren上实现了一个异步SGD训练算法。在PyWren基线实现的基础上,作者还进行了一组优化。作者使用了来自CriteoKaggle竞赛的Criteo展示广告数据集进行实验。作者在10个最大的AWSLambda(3GB内存)上运行PyWren,在单个VM()中的8个内核上运行Bosen。
作者通过记录随时间变化的测试损失来测量这两个系统的性能(图2)。对于PyWren,作者在实现每个优化之后报告这个值。作者累计实现了以下优化:(1)跨迭代重用Lambda;(2)使用异步SGD进行小批量预取;(3)使用低延迟存储(Redis)代替AmazonS3;(4)使用具有多get操作的稀疏数据传输。我们观察到这些优化显著改善了Pyren在600秒后实现的最终测试损失(从0.61到0.57)。尽管有了这些改进,PyWren仍然比Bosen慢得多。进一步的性能分析表明,PyWren存在一些开销,例如序列化/反序列化数据,以及使用接口不适合ML工作负载的远程存储(例如Redis或S3)。这一结果表明,在设计无服务器计算框架的早期,需要仔细考虑ML工作负载的性能需求。
图2.PyWren和Bosen在Criteo-Kaggle逻辑回归任务中的表现。PyWren基线通过重用Lambda、添加预取、切换到异步计算、用更高性能的Redis存储后端替换S3以及支持在单个RPC上获取多个密钥而得到了增量改进。
此外,作者还构建了本文所提出的框架的原型,包括:(1)具有参数服务器接口的高性能数据存储,(2)mini-batch数据的循环缓冲区预取,(3)逻辑回归SGD训练算法。为了充分验证这种设计的好处,作者在相同的逻辑回归任务中对其进行了评估。作者测量了每个worker的平均SGD迭代时间(见图3)。这个时间是worker性能的一个指标;较低的迭代时间意味着更频繁的模型更新和更快的收敛。作者还将这一次的SGD算法分解为四个主要步骤:(1)从数据存储中获取最新模型,(2)从远程存储(例如S3)中获取一个minibatch,(3)计算SGD梯度,以及(4)将梯度发送到数据存储。作者发现,尽管无服务器计算具有固有的开销,本文所提出的框架原型还是实现了较低的每次迭代时间(500μs)---与Bosen这样的系统不相上下。这种性能源于两种机制:(1)远程mini-batch的有效预取和缓冲,以及(2)尽可能与数据存储通信。首先,minibatch预取机制通过与计算并行进行,有效地掩盖了从S3获取minibatch所需的时间。实际上,对于中型/大型Lambda,在新的minibatch上开始计算所需的时间可以忽略不计,因为大多数情况下,这些数据都是在worker需要之前缓存在内存中的。即使从S3获取一个mini-batch需要10ms也是这样的。其次,作者发现与数据存储的通信是有效的(例如,发送梯度的时间可以忽略不计)。由于能够与数据存储异步通信,进一步提升了该框架的性能。
图3.本文所提出原型每次SGD迭代的时间。具体细分为四个主要步骤:(1)将梯度发送到数据存储,(2)计算梯度,(3)从数据存储获取模型,(4)从S3获取minibatch。
2.2、Cirrus:aServerlessFrameworkfor-to-MLWorkflows[5]
这篇文章也是节2.1中所介绍的Berkeley研究小组的研究成果,是对节2.1中分析的NIPS’18中文章所涉及工作的扩展和延伸。在专门用于无服务器基础设施和ML工作流的无服务器ML框架原型的基础上,将其封装为一个实现端到端管理的分布式ML训练框架Cirrus,可以直接调用使用(),并将相关工作内容发表在发表在SoCC’19中。Cirrus专门用于无服务器云基础设施(如AmazonAWSLambda)中的ML训练。它提供高级原语来支持ML工作流中的一系列任务:数据集预处理、训练和超参数优化。Cirrus结合了无服务器接口的简单性和无服务器基础设施(具体是指AWSLambda和S3)的可伸缩性,以最小化用户的工作。
Cirrus的设计原则是:
自适应的细粒度资源分配。为了避免由于过度配置而造成的资源浪费,Cirrus应该灵活地调整为每个工作流阶段保留的细粒度资源量。
无状态服务器端后端。为了确保无服务器计算资源的健壮和高效管理,Cirrus设计了一个无状态的服务器端后端。有关当前部署的函数以及ML工作流任务和计算单元之间的映射的信息由客户端后端管理。因此,即使所有云端资源变得不可用,ML训练工作流也不会失败,并且可以在资源再次可用时恢复其操作。
端到端无服务器API。模型训练不是ML研究人员的唯一任务,数据集预处理、特征工程和参数调整等对于最终生成一个好的模型同样重要。Cirrus应该提供一个完整的API,允许开发人员以最小的工作量端到端的大规模地运行这些任务。
高可扩展性。ML任务是高度计算密集型的,在没有有效并行化的情况下需要很长时间才能完成。因此,Cirrus应该能够同时运行数千个workers和数百个实验。
与节2.1中所介绍的工作类似,Cirrus利用四个系统模块来实现上述原则。首先,Cirrus为ML开发人员提供了Python前端。这个前端有两个功能:a)为ML训练的所有阶段提供丰富的API;b)在无服务器的基础设施中执行和管理大规模计算。其次,Cirrus提供了一个客户端后端。第三,为了克服低延迟无服务器存储的不足,Cirrus为worker共享的所有中间数据提供了低延迟分布式数据存储。第四,Cirrus提供了一个在无服务器Lambda上运行的worker运行时(runtime)。该运行时提供了访问S3中的训练数据集和分布式数据存储中的中间数据的有效接口。Cirrus的完整结构见图4。
图4.Cirrus系统结构。系统由(有状态的)客户端(左)和(无状态的)服务器端(右)组成。预处理和面向用户的训练包含一个前端的API。客户端后端管理云功能和向函数分配任务。服务器端由LambdaWorker和高性能数据存储组件组成。Lambdaworker将数据迭代器API导出到客户端后端,并包含许多迭代训练算法的有效实现。数据存储用于存储梯度、模型和中间预处理结果。
Cirrus的整体结构与节2.1中是类似的。Cirrus的前端和客户端后端是用Python实现的,方便Cirrus与现有的机器学习方法相结合。为了提高效率,分布式数据存储和workerruntime用C++实现。表2列出了实现的不同组件以及它们的大小和实现语言。Workerruntime代码包括迭代器接口和数据存储客户端实现。workerruntime和数据存储通过TCP连接进行通信。作者实现了一个共享组件库,其中包括线性代数库、通用实用程序和ML算法,这些组件被所有系统组件共享。作者已经公开发布了Apache2开源许可的实现()。
表2.Cirrus组件。
首先,Cirrus为ML工作流的所有阶段提供了一个Python前端API。前端是一个高度灵活的thinPythonAPI,默认情况下,它从开发人员那里抽象出所有的细节,同时提供了通过API的参数覆盖内部配置参数(例如,优化算法)的能力。前端还提供了一个运行在Plotly上的用户界面,供用户监控工作负载的进度和启动/停止任务。CirrusPythonAPI分为三个子模块。每个子模块都打包了与工作流的每个阶段相关的所有函数和类。(1)预处理。预处理子模块允许用户对存储在S3中的训练数据集进行预处理。此子模块允许不同类型的数据集转换:最小-最大缩放、标准化和特征散列。(2)训练。Cirrus的训练子模块支持ML模型,这些模型可以通过随机梯度下降进行训练。目前Cirrus支持稀疏Logistic回归、潜在Dirichlet分配、Softmax和协同过滤。(3)超参数优化。超参数优化子模块允许用户在给定的参数集上运行网格搜索。Cirrus允许用户改变ML训练参数(例如,学习率、正则化率、小批量大小)以及系统参数(例如,Lambda函数大小、并发worker数量、梯度过滤)。
其次,Cirrus的Python前端提供了一个到Cirrus客户端后端的接口。这个后端的功能和能够完成的任务与节2.1中介绍的框架完全相同。客户端后端从前端算法中抽象出Lambda的管理。客户端后台会保存一个当前活动的Lambda列表,以及一个AWSLambdaAPI的连接列表(每个连接用于启动一个Lambda)。在训练期间加载的Lambda在其生存期结束时自动重新加载(每15分钟一次)。由于LambdaAPI的特殊性,从一台服务器上快速加载数百个Lambda是非常困难的。为了解决这个问题,后端保留一个线程池,可用于响应新Lambda任务的请求。
第三,Cirrus提供了分布式存储模块。Cirrus的数据存储用于存储所有workers共享的中间数据。由于现有产品中不允许Lambda之间进行交互通信,因此Lambda需要共享存储。无服务器Lambda的存储需要满足三个条件:首先,它需要低延迟(本文实现低至300μs),以便能够适应延迟敏感的工作负载,例如用于ML训练的工作负载(迭代SGD)。其次,它需要扩展到数百个workers,以利用无服务器基础架构几乎线性的可扩展性。第三,它需要一个丰富的接口来支持不同的ML用例。例如,数据存储必须支持multiget(§6.5)、常规键/值的put/get操作和参数服务器接口。为了实现低延迟,将数据存储部署在云VMs中。它实现了低至300μs的延迟,而AWSS3的延迟约为10ms。此延迟对于训练阶段最大化模型的更新至关重要。作者使用稀疏表示来表征梯度和模型以实现高达100倍的压缩比,以便与存储和批处理请求进行数据交换。为了实现高可伸缩性,Cirrus包括以下机制:(1)分片存储,(2)高度多线程,(3)数据压缩,(4)梯度滤波器和(5)异步通信。Cirrus的分布式数据存储提供了一个接口,支持所有在ML工作流中存储中间数据的用例。该接口支持键值存储接口(set/get)和参数服务器接口(s果然啊dient/getmodel)。
最后,Cirrus提供了一个运行时(Runtime),它封装了系统支持的不同计算之间共享的所有函数。如图5,Cirrus的Runtime为ML计算提供了通用抽象(Generalabstractions)和基本数据类型(Dataprimitives)用于访问训练数据、参数模型和中间结果。这些可用于向Cirrus添加新的ML模型。为了简化新算法的开发,Runtime提供了一组线性代数库。Cirrus的初始版本使用外部线性代数库如Eigen进行梯度计算。为了减少Eigen处理序列化和反序列化数据的时间,作者最终开发了自己的线性代数库。对于数据访问,Runtime提供了一个由本地循环缓冲区支持的基于minibatch的迭代器,允许worker以低延迟访问训练minibatch。此外,它还提供了一个高效的API来与分布式数据存储进行通信。
图5.CirrusRuntime。minibatch是异步预取的,并在每个Lambda的内存中本地缓存(取决于使用的Lambda的大小)。将梯度异步发送至参数服务器,每次迭代模型同步从参数服务器中进行检索。
作者给出了Cirrus在不同阶段的详细工作方式。
(1)数据加载和预处理。Cirrus假设训练数据存储在一个全局存储中,比如S3。因此,使用Cirrus的第一步就是将数据集上传到云端。用户将数据集的路径传递给系统,然后由系统负责解析和上载数据集。在此过程中,Cirrus将数据集从其原始格式(如csv)转换为二进制格式。这种压缩消除了在训练和超参数调优阶段进行反序列化的需要,这有助于减少Lambda工作进程中的计算负载。其次,Cirrus生成数据集大小相似的分区,并将其上传到S3存储桶(S3Bucket)。
Cirrus还可以应用变换(Transformations)来提高模型的性能。例如,对于Cirrus实现的异步SGD优化方法,对数据集中的特征进行规范化处理能够提高训练的效果。对于这些transformations,Cirrus启动了一个大型MapReduce作业:每个输入分区一个worker。在map阶段,每个worker计算其分区的统计信息(例如,平均值和标准差)。在reduce阶段,这些局部统计信息被聚合以计算全局统计信息。在最后的映射阶段,worker转换每个分区样本,给出最终的每列统计信息。对于大型数据集,map和reduce阶段会跨大量worker和列来聚合每列的统计信息。这会造成每秒生成大量新的写操作和读操作,而超出了S3支持的事务吞吐量。基于这个原因,作者使用Cirrus的低延迟分布式数据存储来存储映射的中间结果,并减少了计算量。
(2)模型训练。Cirrus使用分布式SGD算法进行模型训练。在训练期间,worker运行Lambda函数,并迭代计算梯度步长。每个梯度计算需要两个输入:一个minibatch和最新的模型。minibatch是Cirrus的运行时通过迭代器从S3获取的。因为迭代器在工作内存中缓冲minibatch,所以检索minibatch的延迟非常低。使用数据存储API(get_sparse_model_X)从数据存储中同步检索最新的模型。对于每个迭代,每个worker都计算一个新的梯度。然后将此梯度异步发送到数据存储(s_gradient_X)以更新模型。
(3)超参数优化。超参数优化是一种模型参数的搜索方式,该模型参数能够保证生成最佳准确度。典型的做法是在多维参数空间上执行网格搜索。搜索可以是暴力破解(Brute-force)搜索或自适应搜索。常见的做法是让网格搜索完整地运行,然后对结果进行后处理,以找到最佳配置。这是一种代价高昂的资源浪费。Cirrus通过提供超参数搜索仪表板(Hyperparametersearchdashboard),来解决这种超时过度配置问题(over-provisioningovertime)。Cirrus超参数仪表板提供了一个统一的界面,用于监控模型随时间变化的损失收敛情况。它允许用户选择单个损失曲线并终止相应的训练实验。因此,Cirrus提供了:启动超参数搜索的API和执行后端;监控模型精度收敛的仪表板;终止单个调优实验的能力,并节省了过度配置成本。
在文献[2]工作的基础上,Cirrus为ML用户提供了一个轻量级的PythonAPI。作者同样给出了一个例子来展示这个API的功能。如图6所示,这个API与图1中给出的文献[2]中的API几乎相同。区别在于本文已经将Cirrus封装为模块“cirrus”,可直接在python中进行import。
图6.CirrusAPI示例。Cirrus支持ML开发工作流的不同阶段:(a)预处理,(b)训练,和(c)超参数调优。
图7a显示了不同数量的服务器(对于Bosen)和AWSLambda(对于Cirrus)在一段时间内实现的逻辑测试损失。通过对一个包含50K样本的数据集上的训练模型评估以得到损失值。作者发现,Cirrus的收敛速度明显快于Bosen。Bosen的性能因为worker相互竞争共享本地缓存受到影响,该缓存在将梯度发送到参数服务器之前聚合梯度。这种设计最终导致了Bosen收敛速度较慢。在图7b中,作者使用相同的数据集和相同的预处理步骤将Cirrus与TensorFlow进行了比较。同样地,Cirrus性能优于TensorFlow。
图7c中的实验对比的是Cirrus和Spark完成协同过滤任务的性能,该实验中使用的是Netflix数据库[8]。由图7c,Cirrus比Spark收敛得更快,测试损耗更低。此外,作者还观察到Spark的ALS实现受到昂贵的RDD开销的影响,因为Spark需要将整个数据集加载到内存中。这导致Spark花了超过94%的时间来做与训练模型不直接相关的工作。相比之下,Cirrus从S3连续向worker流式传输数据,这使得他们可以立即开始计算。
图7.(a)Bosen和Cirrus之间不同设置的时间损失比较。Bosen达到的最佳损失为0.485,Cirrus达到最佳损失的速度至少快了5倍(200秒vs1000秒)。与最先进的ML训练框架相比,Cirrus可以在一个或两个Lambda的寿命内(300-600秒)更快地收敛,并且损失更低。(b)TensorflowCriteo_tft基准和Cirrus的收敛与时间曲线。Tensorflow是在32核节点上执行的,Cirrus在10个Lambda中运行。(c)运行Netflix数据集时,Spark(ALS)和Cirrus的RMSE随时间变化曲线。Spark在运行Netflix数据集时,前4分钟处理数据,并在ALS的5次迭代中收敛(RMSE=0.85)后终止。Cirrus能够更快收敛到较低的RMSE(0.833)。
图8中的实验验证的是Cirrus的可扩展性(Scalability)。通过设计该系统以实现3个维度的扩展:用S3存储训练数据,用Lambda计算,以及用分布式参数服务器共享内存,来实现扩展性。
存储扩展性:Cirrus通过将S3中的训练数据集分割成中等大小的对象来解决这个问题。作者使用10MB的对象,因为作者发现这个大小可以实现良好的网络利用率,同时对于最小尺寸的Lambda来说也足够小。通过使用大型对象,减少了每秒的请求数量。因此,当每个worker从S3消耗30MB/s的训练数据时,能够将S3的吞吐量线性扩展到1000个Cirrusworkers(图8a)。
计算扩展性:由图8b,没有模型和参数的同步得情况下Cirrus可以通过并行传输输入训练数据和计算梯度来实现线性计算可伸缩性。
参数服务器扩展性:在参数服务器层面,主要挑战来自于每个虚拟机VM有限的网络带宽,以及更新模型和worker请求服务器所需的计算。Cirrus通过1)模型分片,2)稀疏梯度/模型,3)数据压缩,4)异步通信来解决这个问题。Cirrus实现了线性可扩展性,最高可达600个worker(图8c)。
图8.AWS存储(GB/秒)、AWS无服务器计算(梯度/秒)和Cirrus数据存储(样本/秒)的可扩展性。每个worker消耗30MB/s的训练数据。
最后,作者对比了专门的ML系统PyWren与Cirrus。PyWren是一个运行在无服务器Lambda上的map-reduce框架。它提供了可扩展至数千名worker的map和reduce原语。PyWren的Runtime经过优化可以在AWSLambda上运行,AWSLambda也是本文用于Cirrus实验的无服务器平台。作者在实验中对PyWren进行了优化,使其每次模型更新的平均时间提高了700倍(从14秒到0.02),但其模型每秒更新次数仍然远低于Cirrus(图9b),并且收敛速度明显慢于Cirrus(图9a)。
图9.PyWren和Cirrus在10个Lambda上运行时在稀疏逻辑回归工作负载上的性能。由于结合了预取、在模型训练迭代中重复使用Lambda以及通过Cirrus的快速数据存储进行高效的模型共享,Cirrus实现了2个数量级的模型更新数量增长。训练数据预取解决了S3的高访问延迟问题,从而使更新速度增加了10倍/秒。
2.3、DistributedMachineLearningwithaServerlessArchitecture[9]
本文作者介绍了一个完全基于无服务器架构的分布式机器学习新框架:SIREN。SIREN由本地客户端和无服务器云平台(例如AmazonLambda)组成,前者使用深度强化学习(DeepReinforcementLearning,DRL)agent进行资源调度决策,后者根据这些调度决策为ML训练作业加载无状态函数(StatelessFunctions)。SIREN的完整结构框架如图10。
图10.SIREN结构
SIREN采用的是SGD算法,使用mini-batches并在多个Lambda函数上运行。每个Lambda函数的作用就类似于传统参数服务器架构中的worker。SIREN与参数服务器架构的一个主要区别是,在SIREN中不存在参数服务器来处理模型参数更新。相反,数据和模型都存储在一个共同的数据存储中(例如AmazonS3),所有函数都可以访问。每个函数从公共存储中读取当前模型,根据mini-batches训练数据计算梯度,然后直接用新计算的梯度更新公共存储中的模型。因此,整个架构是无服务器的。在SIREN中,作者提出了一种混合同步并行(Hybridsynchronousparallel,HSP)计算模式。如图11所示,在每个epoch内,所有的函数都可以异步更新模型,同时在每个epoch结束时施加一个同步屏障(Synchronizationbarrier),以便完成下一个epoch的资源调度。
已知epoch为t,第k个mini-batch为Ξ_t,k,更新模型为:
在epocht-1结束时的模型ω与ω_t,0相同。HSP在无服务器架构中是高效的,因为加载的函数是同质的,从而导致每个epoch的同步代价都很低。在无服务器云平台中,调用和终止函数也是轻量级的。
图11.无服务器云上的混合同步并行(HSP)处理。
作者使用Python代码实现了SIREN,支持AWSLambda之上的ML模型训练,并全面支持MXNetAPIs。机器学习开发人员可以在SIREN上运行他们的传统MXNet项目,而无需重构现有代码。如图10所示,SIREN包括三个主要部分:(1)封装MXNet机器学习库的代码包;(2)用AWSSDKboto3构建本地客户端,调用并管理AWSLambda中的无状态函数;(3)用TensorFlow实现DRLagent,进行动态资源配置决策。此外,还对AWSLambda进行了一系列约束,以保证无状态函数的轻量级和可移植性。
由于AWSLambda的编程runtime不支持原生的ML训练算法,作者在代码包中引入了一部分MXNetML库。在AWSLambda上,代码包大小限制为250MB,这使得直接将任何现成的ML库(如MXNet、TensorFlow)加载到AWSLambda上都是不可行的。为了缩小MXNet代码包的大小,作者用不同的编译选项组合重新编译了MXNet源代码,并排除了无服务器云中不必要的编译选项。例如,禁用了USE_CUDA、USE_CUDNN和USE_OPENMP等选项。
在AWSLambda上,单个函数的计算能力也受到限制:要求每个Lambda函数最多在300秒内执行完毕,最大内存大小为3GB。但是,由于AWSLambda支持每个AWS账户中多达3000个函数并发执行,因此SIREN通过使用大量Lambda函数并行化ML训练工作负载实现了高度的并行性。
作者考虑在一个有M个样本的数据集上训练ML工作负载,总奖励预算为B。如果达到一定的损失值L或者总奖励预算B用完,则训练终止。在任何一个epocht,调度器将对并行调用的函数数量(用n_t表示)以及每个函数的内存大小m_t做出判断。令f_t,i表示在第t个epoch加载第i个活跃函数,如图11所示。需要注意的是,如果函数i已经到了它的运行寿命,则会调用一个新的函数来代替它,且仍然用f_t,i来表示,所以在epocht中总会有n_t个函数在并发执行。在每一个函数f_t,i中,重复计算一个新的mini-batch数据的聚合梯度,并根据HSP模式下的SGD更新模型参数。
在epocht中,假设函数f_t,i花费一个完整周期(P^F)_t,i来获取mini-batch数据,(P^C)_t,i计算梯度,(P^U)_t,i更新模型参数。函数i在epocht的完整执行时间为:
epocht在HSP的全部持续时间为P_t=max_i(P_t,i)。在epocht结束时,ML任务的损失值更新为l_t。
无服务器云根据函数执行时间和函数内存大小向用户收费。令c表示使用1GB内存执行一个函数一秒钟的单价。一个epocht的总花费为:
而ML任务的总的奖励成本为:
其中,T表示epoch的总数。本文所述任务的目标是最小化作业完成时间,即在一定奖励预算B约束下解决以下优化问题:
在每个epocht开始时,DRLagent决定资源配置计划(n_t,m_t),即DRL任务中的动作action,具体如图12。衡量动作(n_t,m_t)有效性的方法是在每个epocht的结束进行数字reward量化计算。计算的依据是这个epoch持续的时间P_t和任务结束时预算是否透支。
图12.DNN策略表示的DRL。
状态(State):在本文所描述的问题中,epocht的状态表示为:
其中,l_t表示epocht的损失值,(P^F)_t、(P^C)_t、(P^U)_t分别表示获取、平均计算和平均模型参数更新时间,P_t为epoch的执行时间。u_t和ω_t分别表示平均内存和CPU的利用情况,b_t为剩余预算。
动作(Action):在本文所描述的问题中,动作表示为a_t=(n_t,m_t)。n_t表示激活的函数数量,m_t表示每个函数的内存大小。DRLagent根据策略选择操作,策略定义为给定当前状态下整个操作空间的概率分布π(a|s)。作者使用策略梯度方法,通过参数θ的函数来近似策略π(a|s)。因此,策略π可以写成π(a|s,θ),其中θ是要学习的参数。将策略π定义为实值空间的高斯概率密度:
基于条件概率π(a_t|s_t-1,θ)确定动作a_t。然后,在一个大的离散作用空间上学习概率质量函数的问题就转化为在一个二维连续空间中寻找参数(μ(s,θ),σ(s,θ))的问题。
奖励(Reward):在本文所描述的问题中,每个epoch结束时奖励定义为:r_t=-βP_t,其中β为正则化系数。epocht的时间越长,agent得到的奖励就越少。最后一个epochT的奖励为:
换句话说,如果作业成功停止,即在不超出预算B的情况下满足收敛阈值L,则向agent分配正C的奖励。否则,如果作业失败,即在用完预算B之前还没有收敛,则给奖励赋值为负C。在DRL中,agent学习的是累计折扣奖励:
其中,γ∈(0,1]为未来折扣奖励因子。在整个DRL训练过程中,上式中的目标函数引导着agent找到最优的估计值。
作者模拟了一个无服务器的云环境,运行由DRLagent控制的mini-batchSGD算法。作者使用OpenAIGym实现模拟环境(()),OpenAIGym是一个用于评估强化学习算法的开源接口。实验目的是验证与传统的网格搜索(GridSearch)基线方法所找到的最优(静态)策略相比使用SIREN进行调度的优势。作者比较了在AWSLambda上使用SIREN和在EC2集群上使用MXNet训练ML作业的完成时间和成本。具体实验中选择了三种类型的EC2实例来构建测试集群:(2vCPU,8GB内存)、(4vCPU,16GB内存)和(8vCPU,32GB内存),每小时分别收费0.1美元、0.2美元和0.4美元。
图13给出了SIREN与网格搜索最佳函数数量的比较实验。图13(a)比较了通过网格搜索和SIREN实现的训练时间。与网格搜索相比,SIREN在预算为300美元的情况下最多可减少36%的训练时间。如图13(b)所示,网格搜索列举了不同预算下不同数量的函数的总奖励情况。SIREN能够根据经验动态调整函数数量。图13(c)给出了分配给每个epoch的函数数量。在前几个epoch中,SIREN启动了大量的函数以快速降低损失值;在后几个epoch,agent减少了函数数量以节省成本。SIREN的DRLagent通过与模拟的无服务器云的迭代交互进行在线训练。图13(d)中的学习曲线表明,agent通过探索不同数量的函数来学习最大化总奖励。agent的训练在大约200次迭代之后完成。
图13.SIREN与网格搜索最佳函数数量比较。
图14.通过SIREN和EC2上的MXNet对MNIST数据集训练LeNet。
图14的实验对比SIREN和EC2上的MXNet。图14(a)显示了使用12个EC2集群和使用SIREN训练LeNet的完成时间和相应的成本。由于EC2集群的异质性,EC2上的成本与训练完成时间呈非线性关系。例如,×6集群和×6集群几乎在同一时间完成训练,但后者产生的成本是前者的两倍。相比之下,SIREN通过更多的投资缩短了完成时间。图14(b)显示,SIREN动态调整每个训练epoch的函数及其内存。当函数数量减少时,每个函数收到的训练数据分区更大,需要更大的内存来处理数据分区。SIREN中的DRLagent是通过与AWSLambda在线交互进行训练的。从图14(c)中的学习曲线可以看出,经过150次左右的迭代,DRLagent的训练已经完成。
进一步的,作者在的集群上训练LeNet、CNN模型和线性分类模型并确定相应的成本。然后,在成本相同的情况下在×8集群上用SIREN训练同样的模型。图15中的实验数据显示,与相同成本的EC2集群相比,SIREN使用这些模型分别减少了40%、39.4%和44.3%的训练时间。
图15.不同模型相同成本预算下SIREN与EC2的比较。
2.4、ServerlessLinearAlgebra[10]
本文作者构建了NumPyWren:一个基于无服务器编程模型的线性代数系统,以及LAmbdaPACK:一个为高度并行线性代数算法的无服务器执行而设计的领域特定语言。相关工作发表在SoCC’20中。
无服务器计算(例如,AWSLambda、GoogleCloudFunctions、AzureFunctions)是一种编程模型,云提供商在其中管理服务器同时动态管理资源分配。通常,无服务器平台计算会公开一个有时间限制的、无状态的FaaSAPI,以及一个管理程序状态的对象存储系统。对于能够清晰地分离程序状态和逻辑的应用程序设计人员来说,无服务器平台提供了对大型计算能力的即时访问,而无需应对复杂集群部署的开销。
本文所研究的内容:密集线性代数(Denselinearalgebra)极大地受益于现有的以服务器为中心的数据中心。现有的分布式线性代数框架可以通过利用局部性、网络拓扑和单个服务器内的资源紧密集成来完成高性能计算。在这样的背景下作者提出这样一个问题:这些线性代数算法能否成功地移植到一个分散数据中心中?也就是说,我们能否在无服务器编程模型中实现与基于MPI的分布式线性代数框架相当的性能?
本文作者构建了NumPyWren,一个在无服务器架构上完成线性代数任务的系统。NumPyWren执行使用LAmbdaPACK编写的程序,LAmbdaPACK是作者构建的一个高级DSL,可以简洁地表示任意基于分片的线性代数算法。NumPyWren通过无状态函数执行来执行大规模密集线性代数程序。通过对中间语言LAmbdaPACK的分析,作者最终证明了分散式无服务器计算模型(Disaggregatedserverlesscomputingmodel)可以用于具有复杂通信程序的计算密集型程序。
NumPyWren解决的是类似Cholesky分解的线性代数问题。考虑求解线性方程Ax=b的问题,其中a是对称正定矩阵。我们可以先把a分解成两个三角形矩阵a=LL^T,然后解两个相对简单的Ly=b和L^Tx=y得到解x。从这个过程中可以看出,分解是该求解问题中计算代价最高的步骤。Communication-AvoidingCholesky是一个很好的计算Cholesky分解的算法。该算法将矩阵分成若干块,并得出一个计算顺序使总数据传输量最小。具体算法如下:
如图16,在outerloop(j)的每一步中,算法首先计算单个块Ajj的Cholesky分解(图16(a))。这个结果用来更新由Aij下面的列块组成的"面板(panel)"(图16(b))。最后,第j列右边的所有区块都会根据各自的位置,通过索引更新面板(图16(c))。通过向下移动对角线重复这一过程(图16(d))。
图16.并行Cholesky分解的前4个时间步骤:0)对角块Cholesky分解,1)并行列更新,2)并行子矩阵更新,3)(后续)对角块Cholesky分解。
作者针对Algorithm1提出了两点问题。首先,作者认为Algorithm1在执行过程中展现出了动态并行性。外循环(Outerloop)由三个不同的步骤组成,具有不同的并行度,从O(1)、O(K)到O(K2),其中K是每个步骤的封闭子矩阵大小。其次,该算法在这三个步骤之间存在细粒度的依赖关系,无论是在一个迭代内还是在多个迭代之间。由此,作者提出了本文所考虑的工作,即:实现适应可用的并行化,作者通过将程序分解为可并行运行的细粒度执行单元来实现这一点。为了在无状态环境中实现这一点,作者建议以分散的方式执行依赖性分析。将描述程序控制流的全局依赖图分发给每个worker。然后,每个worker根据其在全局任务图中的当前位置,对其下游依赖关系进行本地推理。
首先,我们介绍本文提出的LAmbdaPACK:一种用于实现并行线性代数算法的特定语言。LAmbdaPACK是生成和使用矩阵块(Tiledmatrices)的命令式程序。这些程序可以对标量值执行基本的算术和逻辑运算。它们不能直接读取或写入矩阵值;相反,所有实质性的计算都是通过调用矩阵块上的本机内核来执行的。矩阵块由索引引用,LAmbdaPACK程序的主要作用是对内核调用排序,并计算每个调用的分块索引。LAmbdaPACK包括简单的for循环和if语句,但是没有递归,只有从LAmbdaPACK到内核的一级函数调用。每个矩阵块索引只能写入一次,这是许多函数式语言的共同设计原则。LAmbdaPACK中的原语功能强大,包括TallSkinnyQR(TSQR)、LU、Cholesky和奇异值分解等等。LAmbdaPACK的示例性描述如图17所示。
图17.LAmbdaPACK语言的示例性描述。
关于LAmbdaPACK的算法分析主要包括两个阶段。由于原始未压缩的DAG非常大,其节点数可能会随着Cholesky或QR等算法的输入大小呈立方级增长,因此,第一阶段的任务是分析程序并提取任务的压缩DAG。DAG中的每个任务对应一个数组写入,我们还需提取执行此任务所需的内核计算和数组读取。由于每个数组读取都有一个唯一的上游写入任务,因此此过程是可跟踪处理的。第二个阶段发生在runtime,在执行任务之后,能够动态发现下游任务。使用当前循环变量绑定的信息来查询下游任务的压缩DAG。图18和图19分别给出了LAmbdaPACK的DAG和程序示例。
图18.LAmbdaPACKDAG示例。
图19.LAmbdaPACK程序示例。
LAmbdaPACK中没有并行原语,而是LAmbdaPACKruntime通过静态分析程序来推断底层依赖关系图。为了并行执行程序,作者从程序产生的依赖结构构造了一个内核调用的DAG。作者借用并扩展了循环优化技术(loopoptimization),将LAmbdaPACK程序转换为隐式有向无环图(ImplicitDAG)。将程序DAG中的每个节点N表示为一个元组(line_number,loop_indices)。利用这个信息,可以执行程序迭代空间中的任何语句。
接下来,作者解决推导DAG中特定节点的下游依赖关系问题。作者提出在runtime处理依赖性分析:每当一个存储位置被写入时,确定从同一存储位置读取的N(所有行,所有循环索引)中的表达式。每当一个存储位置被写入时,我们确定从同一存储位置读取N(所有行,所有循环索引)中的表达式。作者将约束建模为一个方程组。假设单个线性代数算法中的行数必然很小,而程序迭代空间通常非常大。当数组仅由循环变量的仿射函数索引时,即形式为ai+b的函数,其中i是循环变量,a和b是编译时已知的常数,则可以使用循环优化来有效地查找特定节点的依赖关系。
如图19中的程序示例,如果在runtime一个worker正在执行程序的第7行,i=0、j=1和k=1,以查找下游依赖项,则分析器将扫描这7行中的每一行,并计算是否存在一组有效的循环索引,以便在程序中的该点读取S[1,1,1]。如果是这样,那么元组(line_number,loop_indices)定义了该任务的下游依赖项,并确定为当前任务的子任务。为了便于访问和开发,作者将LAmbdaPACK嵌入Python中。由于大多数LAmbdaPACK调用优化的BLAS和LAPACK内核,因此使用高级解释语言的性能损失很小。LAmbdaPACK详细流程见Algorithm2。
然后,我们介绍本文提出的NumPyWren框架。NumPyWren框架包括五个独立可扩展的主要组件:runtime状态存储、任务队列、轻量级全局任务调度器、无服务器计算runtime和分布式对象存储。图20展示了NumPyWren框架组件。
图20.NumPyWren执行框架的体系结构,具体为6x6cholesky分解期间的runtime状态。
任务排队(TaskQueue):客户端进程将需要执行的第一个任务排队到任务队列中。任务队列是一个发布-订阅样式的队列,它包含DAG中的所有节点,这些节点的输入依赖关系都已满足并准备好执行。
执行器配置(ExecutorProvisioning):任务队列的长度由配置者(Provisioner)监控,provisioner管理计算资源以匹配执行期间的动态并行性。在第一个任务排队后,provisioner启动一个执行器(executor),并根据任务队列大小维护活动executor的数量。由于provisioner的角色只是轻量级的,所以它也可以作为“无服务器”云函数定期执行。
任务执行(TaskExecution):执行器管理NumPyWren任务的执行和调度。一旦执行器准备就绪,它就轮询任务队列以获取可用的任务,并执行任务中的编码指令。大多数任务涉及从对象存储读取输入和将输出写入对象存储,以及执行BLAS/LAPACK函数等。假定对象存储是一个分布式持久存储系统,它支持单个密钥的先读后写一致性。使用一个带有单一静态赋值语言的持久对象存储,有助于设计容错协议。当执行器接近无服务器系统的runtime限制时(AWSLambda为900),执行器自动终止。如果有必要的话,provisioner将负责雇佣新worker。容错协议能够实现即使工作进程超过runtime限制或是在执行过程中被云提供商杀死,程序仍能在有效状态下运行。
Runtime状态更新(Runtimestateupdate):一旦任务执行完成并且输出被持久化,执行器就会更新runtime状态存储中的任务状态。runtime状态存储跟踪整个执行的控制状态,并且需要支持每个任务的快速更新。如果已完成的任务具有“ready”子任务,则执行器会将该子任务添加到任务队列中。状态存储的原子性保证了每个子任务都能够被调度。这个使用执行器执行调度的过程实现了高效、分散、细粒度的任务调度。由于计算和存储的分离,NumPyWren中的容错非常容易实现。因为对对象存储的所有写入都是持久的,所以在任务完成后都不需要重新计算。
任务租用(TaskLease):在NumPyWren中,所有挂起的和可执行的任务都存储在一个任务队列中。保持一个不变量,即任务只有在完成后才能从队列中删除(例如,runtime状态存储已更新,输出持久化到对象存储)。当一个worker获取一条任务,这个worker就获得了该任务的租约(lease)。在租用期间,该任务被标记为不可见,以防止其他workers获取这条任务。
故障检测和恢复(FailureDetectionandRecovery):在正常操作期间,worker将使用后台线程续订任务租约,直到任务完成。如果任务完成,worker将从队列中删除该任务。如果worker失败,它将无法再续订租约,并且该任务将对任何可用的worker可见。因此,故障检测在租约到期时发生,恢复时间由租约长度决定。
垃圾收集(Garbagecollection):由于NumPyWren将所有中间状态存储到一个持久对象存储区,因此在不再需要时清除状态是非常必要的。但是,由于在对象存储中存储字节的成本极低,与处理TB级中间状态问题的计算成本相比,在程序结束时进行垃圾收集就足够了。使用与程序相关联的唯一id标记对象存储中单个程序执行的所有分配。在程序执行终止后,NumPyWren通过启动一组并行的无服务器任务来异步清理对象存储,以清理与给定程序id关联的所有对象。
自动缩放(Autoscaling):与传统的无服务器计算模型(每个新任务分配一个新容器)不同,NumPyWren中的任务调度和worker管理是解耦的。这种解耦允许自动扩展计算资源,以实现更好的性价比权衡。在NumPyWren中,作者采用了一个简单的自动缩放启发式算法,能够在保持较低作业完成时间的同时获得很好的利用率。
作者对4种线性代数算法:矩阵乘(MatrixMultiply,GEMM)、QR分解(QRDecomposition,QR)、奇异值分解(SingularValueDecomposition,SVD)、Cholesky分解(CholeskyDecomposition,Cholesky)进行了实验评价。对于这四种算法,作者将它们与最先进的MPI实现进行比较。其中Cholesky,GEMM和SVDwe使用ScaLAPACK实现,ScaLAPACK是一个工业级Fortran库,专为高性能、分布式密集线性代数而设计。对于QR分解,则使用了communication-avoidingQR分解算法的优化实现。NumPyWren实现大约有6000行Python代码,作者将其构建在Amazonweb服务(AWS)平台上。对于runtime状态存储,使用的是Redis---一个由ElasticCache提供的键值存储。尽管ElasticCache是一种配置的(而不是“无服务器”)服务,但作者发现使用一个实例就足以满足所有工作负载。此外,作者还发现,可以用托管供应商提供的键值存储(如DynamoDB)来替换Redis,但性能略有下降。作者将Amazon的简单队列服务(SimplequeueService,SQS)用于任务队列,Lambda或EC2,使用AmazonS3作为远程对象存储。
作者对实验进行了一些特殊的设备选择、环境选择或参数选择。首先,由于不能很容易地控制并发Lambda执行的数量或AWS提供的硬件类型,出于实验控制的原因,作者通过模仿EC2上的无服务器runtime来进行大部分评估以便与其他系统进行比较。其次,本文的Lambda模拟基于PyWren框架中的“独立模式”。PyWren使用一个单独的SQS队列来模拟Lambda作业队列,并使用有时间限制的进程来模拟短函数调用。在控制底层硬件(AVX、NIC等)时,使用SQS会导致不确定性。然后,目前Lambda的定价是EC2现货价格的10倍,这使得本文的大规模实验无法在Lambda上进行。作者通过实验对比发现,在EC2上运行模拟的无服务器环境与在AWSLambda上运行的性能差别最小。最后,模拟环境中的实验还允许修改某些在真实无服务器环境中用户无法控制的系统参数,如函数超时等。
表3中给出针对四种密集线性代数方法NumPyWren与MPI的端到端性能比较。作者对比了在完全相同的硬件条件下(8个实例中的256个物理核),处理大小为256k(262144)的方阵时MPI和NumPyWren的性能。我们可以看到无服务器环境施加的限制导致的性能损失在1.4x到1.6x之间(按wall-clocktime计算)。
表3.在具有512个虚拟核的集群上,在N=256K的方阵上运行时,不同算法的MPI与NumPyWren执行时间的比较。
在表4中,作者比较了NumPyWren和MPI使用的总核秒数(core-seconds)。对于MPI,coreseconds是指核的总数乘以wall-clockruntime。对于NumPyWren,作者只计算“活动核(Activecores)”,因为空闲核是可以被其他任务利用的。作者通过在无服务器核启动和冷却计算过程中每个核的总计算时间中添加一个启动延时γ来计算总核秒数。具体的,作者选择γ=20s以对系统进行保守的评估。对于QR和Cholesky这些具有可变并行性的算法,虽然wall-clocktime相当,但作者发现NumPyWren使用的核秒数减少了1.15倍。对于SVD,实验中显示出超过3倍的资源节省效果,不过,产生这种差异一部分是由于使用的SVD算法不同。然而对于具有固定数量的并行性的算法(如GEMM),NumPyWren中过多的通信会导致更高的资源消耗。
表4.在一个256K大小的方阵上运行算法的MPI与NumPyWren总CPU时间(以核秒为单位)比较。
三、文章小结
本文参考引用的文献:
[1]CharlesReiss,AlexeyTumanov,GregoryRGanger,RandyHKatz,:,7.
[2]JoaoCarreira,PedroFonseca,AlexeyTumanov,etal.,ACaseforServerlessMachineLearningNIPS'18
[3]EricJonas,ShivaramVenkataraman,IonStoica,:Distributed
computingforthe99%.CoRR,abs/1702.04024,2017.
[4]JinliangWei,WeiDai,AurickQiao,QirongHo,HenggangCui,GregoryRGanger,PhillipBGibbons,
GarthAGibson,
,pages381–394.ACM,2015.
[5]JoaoCarreira,PedroFonseca,AlexeyTumanov,etal.,Cirrus:aServerlessFrameworkfor-to-MLWorkflows,SoCC’19:ACMSymposiumonCloudComputing,
[6]MartínAbadi,PaulBarham,JianminChen,ZhifengChen,AndyDavis,JeffreyDean,MatthieuDevin,SanjayGhemawat,GeoffreyIrving,MichaelIsard,etal.[].TensorFlow:ASystemforLarge-ScaleMachineLearning
[7]CriteoDataset..
[8]NetflixDataset..
[9]HaoWang,DiNiu,BaochunLi,DistributedMachineLearningwithaServerlessArchitecture,IEEEINFOCOM2019,
[10]VaishaalShankar,etal.,Serverlesslinearalgebra,SoCC'20:ACMSymposiumonCloudComputing,
[11]ServerlessMachineLearningonModernHardwareUsingApacheSpark,
分析师介绍:
仵冀颖,工学博士,毕业于北京交通大学,曾分别于香港中文大学和香港科技大学担任助理研究员和研究助理,现从事电子政务领域信息化新技术研究工作。主要研究方向为模式识别、计算机视觉,爱好科研,希望能保持学习、不断进步。
免责声明:本文章如果文章侵权,请联系我们处理,本站仅提供信息存储空间服务如因作品内容、版权和其他问题请于本站联系