Ray分布式机器学习:利用Ray进行大模型的数据处理、训练、推理和部署
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

1.1 Ray是什么

Ray是为Python数据科学社区构建的灵活的分布式计算框架,它满足所有分布式计算需求,广受欢迎。

Ray易于入门,并且符合Python编程简单便捷的特点。Ray的核心API非常精简,有助于用户高效创建分布式应用程序。用户可以在笔记本计算机上高效地并行化Python程序,几乎不需要任何修改即可将本地测试过的代码扩展到集群上。Ray的高级库易于配置,并且库与库之间支持无缝连接。其中一些库,比如Ray的强化学习库,无论是否以分布式的方式使用,都有希望成为独立项目。虽然Ray的核心是用C++构建的,但它从一开始就是以Python为主[1]的框架,支持集成许多重要的数据科学工具,并且持续增长的Python生态也为Ray提供助力。

分布式Python并不是新出现的,Ray也不是该领域的首个框架(也不会是最后一个),但Ray提供了优于其他框架的功能。组合使用Ray的模块并进行自定义,就能轻松完成复杂的机器学习任务,不使用Ray则很难实现。Ray大大简化了分布式计算,你可以利用熟悉并想要使用的Python工具灵活执行复杂的计算任务。换句话说,通过学习Ray,你将掌握灵活的分布式Python机器学习。本书目标就是展示Ray的分布式计算功能。

在本章中,你将初步了解Ray的功能。我们将讨论构成Ray的三层架构,即内核、库和生态。本章首先通过代码示例展示Ray的特点,读者可以将本章作为全书的导览,后面的章节将详细介绍Ray的API和组件。

1.1.1 Ray的渊源

编写分布式系统极具挑战性,需要专业的知识和丰富的经验,这是大多数人不具备的。理想情况下,分布式系统不会妨碍用户,而是提供抽象化的方法让用户专注于本职工作。但实际上,正如Joel Spolsky指出的(https://oreil.ly/mpzSe),“某种程度上,所有复杂的抽象都是存在漏洞的”,因此让计算机集群按照用户意愿执行任务无疑是困难的。许多软件系统需要远远超出单台服务器的资源。即使单台服务器是足够的,现代系统也需要具备容错性和高可用性。这意味着需要在多台服务器甚至多个数据中心上执行计算任务,才能确保系统可靠运行。

即使你对机器学习(Machine Learning,ML)或人工智能(Artificial Intelligence,AI)不是特别熟悉,也一定听说过该领域取得的新成果。这里只举两个示例,DeepMind的AlphaFold(https://oreil.ly/RFaMa)通过人工智能解决了蛋白质折叠问题,OpenAI的Codex(https://oreil.ly/vGnyh)可协助软件开发者进行开发工作。你可能还听说过,机器学习系统通常需要大量的数据进行训练,并且机器学习模型正变得越来越大。OpenAI在论文“AI and Compute”(https://oreil.ly/7huR_)中指出,训练AI模型所需的算力呈指数级增长。OpenAI的AI系统所需的运算量以每秒千万亿次浮点运算(Peta FLoating-point Operations Per Second,PetaFLOPS)为单位,并且自2012年以来,每3.4个月就翻一番。

将算力需求与摩尔定律[2]相比,后者指出计算机中的晶体管数量每两年翻一番。即使你对摩尔定律持乐观态度,也可以看到ML中存在明显的分布式计算需求。你还应该了解到,ML中的许多任务支持并行运行。所以,应尽量通过并行计算提高模型训练的速度[3]

人们通常认为实现分布式计算很困难。正确的方法应该是不考虑单台机器及其互操作,而是在集群上运行代码的抽象方法。这样用户才能专注于AI计算任务。实现这样的需求很难吗?

加州大学伯克利分校的RISELab(https://oreil.ly/1zsMj)的研究人员创建了Ray来解决以上问题。通过分布式方式,RISELab正在研究加速计算的高效方法。不过,研究中涉及的计算任务非常灵活,现有框架无法支持。RISELab还希望创建支持分发任务的系统。通过合理的默认设置,使开发者专注于本职工作,不必考虑计算集群的具体细节。而且,最好让开发者仍能继续使用他们喜欢的Python工具。因此,Ray在设计上注重高性能和异构计算任务[4]。为了更好地理解这些要点,我们接下来仔细研究Ray的设计原则。

1.1.2 Ray的设计原则

Ray构建于若干设计原则之上。Ray的API简单且通用、计算模型能提供充分的灵活性、系统架构兼具高性能和可扩展性。下面进行详细介绍。

简洁性和抽象性

Ray的API不仅高度简洁,而且易于上手(详见第2章)。无论是利用笔记本计算机上的所有CPU内核,还是充分利用集群中的所有机器,都能轻松实现。开发者只需修改一两行代码,Ray代码基本保持不变。与任何优秀的分布式系统一样,Ray在后台管理任务分发和协调。这样用户就不必考虑分布式计算的机制。Ray提供了良好的抽象层,能让用户专注于自身工作。

由于Ray的API具有广泛的适用性并符合Python编码风格,因此很容易将Ray与其他工具集成。例如,Ray的执行器(actor)可以调用现有的分布式Python计算任务,计算任务也可以调用执行器。在这个意义上,因为Ray兼具高性能和强大的灵活性,支持在不同的系统和框架之间进行通信,所以非常适合作为分布式计算任务中的“胶水代码”。

灵活性和异构性

对于AI计算任务,特别是在处理强化学习等任务时,用户需要灵活的编程模型。Ray的API支持编写灵活和可组合的代码。简单来说,如果你能用Python表明计算任务,就可以通过Ray进行分布式处理。当然,用户需要确保有足够的资源,并且要谨慎考虑分发的任务。但是,Ray不会限制开发者的操作。

Ray在计算的异构性方面也非常灵活。例如,假设你正在进行复杂的模拟。模拟通常可以分解为多个任务或步骤。其中一些步骤可能需要运行几小时,而其他步骤只需要运行几毫秒,但它们都需要快速调度和执行。有时,模拟中的单个任务可能需要很长时间,但其他较小的任务支持并行运行,以免发生阻塞。此外,后续任务可能依赖上游任务的结果,因此你需要支持动态执行并能很好地处理任务依赖项的框架。Ray在运行此类异构任务流时提供了充分的灵活性。

开发者还需要确保在资源使用上具有灵活性,而Ray支持异构硬件。例如,某些任务可能需要在GPU上运行,而其他任务在CPU内核上运行效果最佳。Ray也提供了此种灵活性。

高性能和可扩展性

Ray的另一个设计原则是Ray执行任务的速度很快。Ray每秒支持处理数百万个任务,并且延迟非常低。Ray执行任务的延迟达到毫秒级的水平。

为了使分布式系统快速运行,还需要良好的可扩展性。Ray在计算集群中分发和调度任务时非常高效,而且具备容错性。第9章将详细介绍Ray集群支持自动扩展,以适应高度弹性的计算任务。Ray的自动扩展器尝试在集群中启动或停止设备,以满足当前的需求。这有助于最大限度地降低成本,并确保集群具有足够的资源来运行计算任务。

在分布式系统中,问题不是会不会出现故障,而是何时出现故障。机器可能会发生故障、中止任务,甚至燃烧起火[5]。无论如何,经过设计,Ray能够快速从故障中恢复,这有助于提高整体速度。

由于尚未讨论Ray的架构(第2章将介绍),暂时不清楚Ray的设计原则是如何实现的。接下来,我们把注意力转向Ray在实践中的具体功能。

1.1.3 Ray的三层架构:内核、库、生态

知道了Ray的渊源和设计原则,接下来介绍Ray的三层架构。这不是唯一的分类方式,但对于本书是最合理的:

● 底层的Python分布式计算框架,具有简洁的核心API和用于集群部署的工具Ray Core[6]

● 由Ray开发者创建和维护的一组高级库,其中包括Ray AIR,用于在常见的机器学习任务中使用库的统一API。

● 持续蓬勃发展的项目生态,Ray与许多知名项目建立了集成与合作关系,扩展了前两层架构。

这里有很多内容需要展开,本章其余部分将逐一研究这三层架构。

Ray的核心引擎及其API位于中心位置,其他所有内容都是基于该引擎和API构建的。Ray的数据科学库建立在Ray Core之上,并提供了特定领域的抽象层[7]。在实践中,许多数据科学家可以直接使用这些库,而机器学习或平台工程师可能大量依赖Ray Core API开发工具和插件。Ray AIR可以看作连接Ray库并处理常见任务的一致框架的封装结构。Ray的第三方集成不断增加,也为经验丰富的开发者提供了很好的入口。接下来,我们逐一探究每个层级。