
本文最初发布于 Uber 工程博客,由 InfoQ 中文站翻译并分享。python

Fiber:Uber 的开源分布式机器学习平台,图片由 Flat UI Kit 提供,项目地址:https://github.com/uber/fibergit
在过去的几年中,计算机不断加强的处理能力推进了机器学习的进步。算法愈来愈多地利用并行性,并依赖分布式训练来处理大量数据。然而,随之而来的是增长数据和训练的需求,这对管理和利用大规模计算资源的软件提出了巨大的挑战。github
在 Uber,咱们开发了 POET、Go-Explore 和 GTN 等算法,这些算法利用大量的计算来训练神经网络模型。为了使将来几代相似算法的大规模计算成为可能,咱们开发了一种新的分布式计算库 Fiber,它能够帮助用户轻松地将本地计算方法扩展到成百上千台机器上。Fiber 可使使用 Python 的大规模计算项目变得快速、简单和资源高效,从而简化 ML 模型训练过程,并得到更优的结果。算法
在理想状况下,将运行在一台机器上的应用程序扩展为运行在一批机器上的应用程序应该很容易,只需更改命令行参数便可。然而,在现实世界中,这并不容易。编程
咱们天天都与许多运行大规模分布式计算任务的人一块儿工做,咱们发现,如今很难利用分布式计算的缘由有如下几个:后端
在笔记本或台式机本地运行代码与在生产集群上运行代码之间存在着巨大的差距。 你可让 MPI 在本地运行,但在计算机集群上运行它是彻底不一样的过程。微信
不能动态扩展。若是你启动了一个须要大量资源的做业,那么你极可能须要等待,直到全部资源都分配好了才能够运行该做业。这个等待下降了扩展的效率。网络
错误处理缺失。在运行时,有些做业可能会失败。你可能不得不还原部分结果或整个地放弃本次运行。架构
学习成本很高。每一个系统都有不一样的 API 和编程约定。要使用新系统启动做业,用户必须学习一套全新的约定。app
新的 Fiber 平台专门解决了这些问题。它为更普遍的用户群体提供了无缝使用大规模分布式计算的可能。
Fiber 是一个用于现代计算机集群的基于 Python 的分布式计算库。用户能够利用这个系统针对整个计算机集群进行编程,而不是只针对单个台式机或笔记本电脑。它最初是为了支持像 POET 这样的大规模并行科学计算项目而开发的,Uber 也已经用它来支持相似的项目。Fiber 的功能很是强大,这样主要是由于:
易于使用。Fiber 容许用户编写在计算机集群上运行的程序,而不须要深刻研究计算机集群的细节。
易于学习。Fiber 提供了与 Python 标准 多处理 库相同的 API。知道如何使用多处理库的工程师能够很容易地用 Fiber 编写计算机集群程序。
快速可靠。Fiber 的通讯中枢基于 Nanomsg 构建,这是一个高性能异步消息传递库,能够提供快速、可靠的通讯。
不须要部署。Fiber 在计算机集群上的运行方式与普通应用程序相同。它会自动为用户处理资源分配和通讯。
提供了可靠的计算。Fiber 内置的错误处理功能让用户能够专一于编写实际的应用程序代码,而不是处理崩溃问题。当运行一个工做进程池时,这尤为有价值。
除了这些好处以外,Fiber 还能够在特别关注性能的领域与其余专用框架搭配使用。例如,对于 随机梯度降低(SGD),Fiber 的 Ring 特性 能够帮助咱们在计算机集群上创建分布式训练做业,并容许它与 Horovod 或 torch.distributed 协同。

图 1:Fiber 启动许多不一样的做业支持(job-backed)进程,而后在其中运行不一样的 Fiber 组件和用户进程。Fiber Master 是管理全部其余进程的主进程。有些进程(如 Ring Node)保持成员之间的通讯。
Fiber 能够帮助从事大规模分布式计算的用户减小从产生想法到在计算集群上实际运行分布式做业的时间。它还能够帮助用户屏蔽配置和资源分配任务的繁琐细节,而且能够缩短调试周期,简化从本地开发到集群开发的转换。
Fiber 让咱们能够灵活地为经典的多处理 API 选择能够在不一样集群管理系统上运行的后端。为了实现这种集成,Fiber 被分为三个不一样的层:API 层、后端层和集群层。API 层为 Fiber 提供了进程、队列、池和管理器等基本构建块。它们具备与多处理相同的语义,可是咱们对它们进行扩展了,使它们能够在分布式环境中工做。后端层处理在不一样集群管理器上建立或终止做业的任务。当用户新增一个后端时,全部其余 Fiber 组件(队列、池等)都不须要更改。最后,集群层由不一样的集群管理器组成。尽管它们不是 Fiber 自己的一部分,可是它们帮助 Fiber 管理资源并跟踪不一样的做业,减小了 Fiber 所须要跟踪的项的数量。图 2 是整体架构图:

图 2:Fiber 的架构包括 API 层、后端层和集群层,这让它能够在不一样的集群管理系统上运行。
Fiber 引入了一个新的概念,称为 做业支持过程(也称为 Fiber 进程)。这些进程与 Python 多处理库中的进程相似,可是更灵活:多处理库中的进程只在本地机器上运行,但 Fiber 进程能够在不一样的机器上远程运行,也能够在同一机器上本地运行。当新的 Fiber 进程启动时,Fiber 会在当前计算机集群上建立一个具备适当 Fiber 后端的新做业。

图 3:Fiber 中的每一个做业支持进程都是在计算机集群上运行的一个容器化做业。每一个做业支持进程也有本身的 CPU、GPU 和其余计算资源。在容器内运行的代码是自包含的。
Fiber 使用容器来封装当前进程的运行环境(如上图 3 所示),其中包括全部必需的文件、输入数据和其余依赖的程序包,并且要保证每一个元素都是自包含的。全部子进程都以与父进程相同的容器镜像启动,以确保运行环境的一致性。由于每一个进程都是一个集群做业,因此它的生命周期与集群上的任何做业相同。为了方便用户,Fiber 被设计成直接与计算机集群管理器交互。所以,不像 Apache Spark 或 ipyparallel,Fiber 不须要在多台机器上设置,也不须要经过任何其余机制引导。它只须要做为一个普通的 Python pip 包安装在一台机器上。
Fiber 基于 Fiber 进程实现了大多数多处理 API,包括管道、队列、池和管理器。
Fiber 中队列和管道的行为方式与多处理相同。不一样之处在于,Fiber 中的队列和管道由运行在不一样机器上的多个进程共享。两个进程能够从同一个管道读取和写入数据。此外,队列能够在不一样机器上的多个进程之间共享,每一个进程能够同时向同一队列发送或从同一队列接收信息。Fiber 队列是用高性能异步消息队列系统 Nanomsg 实现的。

图 4:Fiber 能够在不一样的 Fiber 进程之间共享队列。在本例中,一个 Fiber 进程与队列位于同一台机器上,另外两个进程位于另外一台机器上。一个进程写入队列,另外两个进程读取队列。
Fiber 也支持 池,以下图 5 所示。它们让用户能够管理工做进程池。Fiber 使用 做业支持进程 扩展池,以便每一个池能够管理数千个(远程)工做进程。用户还能够同时建立多个池。

图 5:在具备三个工做进程的池中,如本例所示,两个工做进程位于一台机器上,另外一个位于另外一台机器上。它们共同处理提交到主进程中任务队列的任务,并将结果发送到结果队列。
管理器 和 代理对象 使 Fiber 可以支持共享存储,这在分布式系统中相当重要。一般,这个功能由计算机集群外部存储系统如 Cassandra 和 Redis 提供。相反,Fiber 为应用程序提供了内置的内存存储。该接口与多处理系统中的管理器类型接口相同。
Ring 是对多处理 API 的扩展,能够用于分布式计算设置。在 Fiber 中,Ring 指的是一组共同工做的、相对平等的进程。与池不一样,Ring 没有主进程和辅助进程的概念。Ring 内的全部成员承担大体相同的责任。Fiber 的 Ring 模型拓扑(以下图 6 所示)在机器学习分布式 SGD 中很是常见,torch.distributed 和 Horovod 就是例子。通常来讲,在一个计算机集群上启动这种工做负载是很是具备挑战性的;Fiber 提供 Ring 特性就是为了帮助创建这样的拓扑。

图 6:在一个有四个节点的 Fiber Ring 中,Ring 节点 0 和 Ring 节点 3 运行在同一台机器上,但在两个不一样的容器中。Ring 节点 1 和节点 2 都在单独的机器上运行。全部这些进程共同运行同一函数的副本,并在运行期间相互通讯。
借助上述灵活的组件,咱们如今可使用 Fiber 构建应用程序了。在这一节中,咱们将展现两种使用 Fiber 帮助用户构建分布式应用程序的方式。
在下面的例子中,咱们将展现工程师如何运用 Fiber 来实现大规模分布式计算。这个例子演示的是一个 强化学习(RL)算法。一般,分布式 RL 的通讯模式涉及在机器之间发送不一样类型的数据,包括动做、神经网络参数、梯度、per-step/episode 观察及奖励。
Fiber 实现了管道和池来传输这些数据。在底层,池是普通的 Unix 套接字,为使用 Fiber 的应用程序提供接近线路速度的通讯。现代计算机网络的带宽一般高达每秒几百千兆。经过网络传输少许数据 一般速度很快。
此外,若是有许多不一样的进程向一个进程发送数据,进程间通讯延迟也不会增长太多,由于数据传输能够并行进行。事实证实,Fiber 池能够做为许多 RL 算法的基础,由于模拟器能够在各个池工做进程中运行,而且结果能够并行回传。
下面的示例显示了使用 Fiber 实现的简化 RL 代码:
# fiber.BaseManager is a manager that runs remotely
class RemoteEnvManager(fiber.managers.AsyncManager):
pass
class Env(gym.env):
# gym env
pass
RemoteEnvManager.register(‘Env’, Env)
def build_model():
# create a new policy model
return model
def update_model(model, observations):
# update model with observed data
return new_model
def train():
model = build_model()
manager = RemoteEnvManager()
num_envs = 10
envs = [manager.Env() for i in range(num_envs)]
handles = [envs[i].reset() for i in num_envs]
obs = [handle.get() for handle in handles]
for i in range(1000):
actions = model(obs)
handles = [env.step() for action in actions]
obs = [handle.get() for handle in handles]
model = update_model(model, obs)
许多 Python 用户利用了多处理。Fiber 为此类应用程序提供了更多的机会,经过这种系统,只需更改几行代码,就能够在相似于 Kubernetes 的计算机集群上的分布式设置中运行。
例如,OpenAI Baselines 是一个很是流行的 RL 库,它有许多参考算法,好比 DQN 和 PPO。它的缺点是只能在一台机器上工做。若是但愿大规模地训练 PPO,就必须建立本身的基于 MPI 的系统并手动设置集群。
相比之下,有了 Fiber,事情就简单多了。它能够无缝地扩展像 PPO 这样的 RL 算法,从而利用分布式环境的数百个工做进程。Fiber 提供了与多处理相同的 API,OpenAI Baselines 就是使用这些 API 在本地获取多核 CPU 的处理能力。要让 OpenAI Baselines 使用 Fiber,只须要修改 一行代码:
修改完这行代码,OpenAI Baselines 就能够在 Kubernetes 上运行了。咱们在 这里 提供了在 Kubernetes 上运行 OpenAI Baselines 的完整指南。
Fiber 实现了基于池的错误处理。在建立新池时,还将建立关联的任务队列、结果队列和挂起表。而后,用户能够将新建立的任务添加到任务队列中。该任务队列由主进程和工做进程共享。每一个工做进程从任务队列中获取一个任务,而后在该任务中运行任务函数。每当用户从任务队列中删除一个任务时,Fiber 就会在挂起表中添加一个条目。工做进程完成该任务后会将结果放入结果队列中。而后,Fiber 从挂起表中删除与该任务相关的条目。

图 7:上图是一个包含四个工做进程的普通 Fiber 池。在下图,Worker 3 出现故障,所以 Fiber 启动一个新的工做进程(Worker 5),而后准备将其添加到池中。
若是池里有一个工做进程在处理过程当中失败,如上图 7 所示,父池做为全部工做进程的进程管理器将会检测到该失败。而后,若是这个失败的进程有挂起任务,则父池会将挂起表中的挂起任务放回到任务队列中。接下来,它启动一个新的工做进程来替换以前失败的进程,并将新建立的工做进程绑定到任务队列和结果队列。
Fiber 最重要的应用之一是扩展计算算法(如 RL) 和基于群体的方法(如 ES)。在这些应用程序中,延迟很是关键。RL 和基于群体的方法常常应用于须要与模拟器(如 ALE、Gym 和 Mujoco)频繁交互以评估策略和收集经验的设置中。等待模拟器结果所带来的延迟严重影响了总体的训练性能。
为了测试 Fiber,咱们将其性能与其余框架进行了比较。咱们还在框架开销测试中增长了 Ray,以提供一些初步结果,并但愿在未来添加更详细的结果。
一般有两种方法能够减小 RL 算法和基于群体的方法的延迟。要么咱们能够减小须要传输的数据量,要么咱们能够提高不一样进程之间通讯通道的速度。为了加快通讯处理,Fiber 使用 Nanomsg 实现了管道和池。此外,用户还可使用 speedus 这样的库进一步提升性能。
一般,框架中的组件会影响计算资源,所以,咱们测试了 Fiber 的开销。咱们比较了 Fiber、Python 多处理库、Apache Spark、Ray 和 ipyparallel。在测试过程当中,咱们建立了一批工做负载,完成这些任务所需的总时间是固定的。每一个任务的持续时间从 1 秒到 1 毫秒不等。
对于每一个框架,咱们在本地运行了 5 个工做进程,并经过调整批次的大小来确保每一个框架的总耗时大约为 1 秒(即 1 毫秒的任务,咱们运行了 5000 个)。咱们假设,Fiber 的性能应该和多处理差很少,由于 Fiber 和多处理都不依赖于复杂的调度机制。相反,咱们认为 Apache Spark、Ray 和 ipyparallel 会比 Fiber 慢,由于它们中间依赖于调度器。

图 8:在测试 Fiber、Python 多处理库、Apache Spark 和 ipyprallel 的框架开销时,咱们在本地运行了 5 个工做进程,并调整批次大小,使每一个框架在大约 1 秒钟内完成任务。
当任务持续时间为 100 毫秒或更多时,Fiber 几乎没有表现出任何差别,当任务持续时间降至 10 毫秒或 1 毫秒时,它比其余框架更接近多处理库。
咱们以多处理做为参考,由于它很是轻量级,除了建立新进程和并行运行任务外没有实现任何其余特性。此外,它还利用了仅在本地可用的通讯机制(例如共享内存、Unix 域套接字等)。这使得支持分布式资源管理系统的其余框架难以超越多处理,由于这些系统没法利用相似的机制。

图 9:咱们的开销测试显示,Fiber 的执行状况与 Python 多处理库相似,在 1 毫秒处,ipyparallel 和 Apache Spark 处理任务的耗时更长。最佳完成时间为 1 秒。
与 Fiber 相比,ipyparallel 和 Apache Spark 在每一个任务持续时间上都落后不少。当任务持续时间为 1 毫秒时,ipyparallel 花费的时间几乎是 Fiber 的 24 倍,Apache Spark 花费的时间是后者的 38 倍。显然,当任务持续时间较短时,ipyparallel 和 Apache Spark 都引入了至关大的开销,并且,对于 RL 和基于群体的方法,它们不如 Fiber 合适,后者使用了模拟器,响应时间只有几毫秒。咱们还能够看到,在运行 1 毫秒的任务时,Ray 花费的时间大约是 Fiber 的 2.5 倍。
为了探究 Fiber 的可伸缩性和效率,咱们将其与 ipyparallel 进行了比较,因为以前的性能测试结果,咱们没有考虑 Apache Spark。咱们也排除了 Python 多处理库,由于它不能扩展到一台机器以外。咱们运行了 50 次 进化策略迭代(ES),根据它们的耗时对比了 Fiber 和 ipyparallel 的可伸缩性和效率。
在工做负载相同的状况下,咱们预计 Fiber 能够完成得更快,由于前面已测试过,它的开销比 ipyparallel 小得多。对于 Fiber 和 ipyparallel,咱们使用的群体大小为 2048,所以,不管工做进程的数量多少,总计算量都是固定的。咱们还在二者中实现了相同的 共享噪音表,每八个工做进程共享一个噪音表。这项工做的实验域是 OpenAI Gym Bipedal Walker Hardcore 环境的一个修改版本,这里 对修改进行了描述。

图 10:当 ES 迭代 50 次以上时,使用不一样数量的工做进程运行 ES,Fiber 的扩展性均优于 ipyparallel。每一个工做进程在单个 CPU 上运行。
主要结果是,Fiber 的扩展性比 ipyparallel 更好,而且完成每次测试的速度明显更快。随着工做进程数从 32 增长到 1024,Fiber 的运行时间逐渐缩短。相比之下,当工做进程数从从 256 增长到 512 时,ipyparallel 的运行时间逐渐变长。在使用 1024 个工做进程时,因为进程之间的通讯错误,ipyparallel 未能完成运行。这个失败削弱了 ipyparallel 运行大规模并行计算的能力。根据 Amdahl 定律,咱们看到,当工做进程数增长到 512 以上时,Fiber 的收益会减小。在这种状况下,主进程处理数据的速度就会成为瓶颈。
总的来讲,在全部工做进程数的测试中,Fiber 的性能都超过了 ipyparallel。此外,与 ipyparallel 不一样的是,Fiber 在运行 1024 个工做进程时也完成了这项工做。这个结果更能显示出 Fiber 与 ipyparallel 相比具备更好的可伸缩性。
Fiber 是一个新的 Python 分布式库,现已 开源。咱们设计它是为了让用户可以在一个计算机集群上轻松地实现大规模计算。实验代表,Fiber 实现了咱们的许多目标,包括有效地利用大量的异构计算硬件,动态地伸缩算法以提升资源使用效率,以及减小在计算机集群上运行复杂算法所需的工程负担。
咱们但愿,Fiber 将进一步加快解决工程难题的进展,使开发方法并大规模地运行以了解其好处变得更容易。
要了解更多细节,请查看 Fiber GitHub 库:https://github.com/uber/fiber
查看英文原文:
https://eng.uber.com/fiberdistributed/
推荐阅读
Uber开放源代码“ Manifold”:用于机器学习的可视化调试工具

本文分享自微信公众号 - 相约机器人(xiangyuejiqiren)。
若有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一块儿分享。