以下代码创建并操作了 2 TB 的随机生成数据。
import dask.array as da
rs = da.random.RandomState()
x = rs.normal(10, 1, size=(500000, 500000), chunks=(10000, 10000))
(x + 1)[::2, ::2].sum().compute(scheduler='threads')
在单个 CPU 上,此计算耗时两小时。
在一个八块 GPU 的单节点系统上,此计算耗时十九秒。
实际上,这个计算并不算令人印象深刻。这是一个简单的工作负载,大部分时间都花费在创建和销毁随机数据上。计算和通信模式也很简单,反映了数据处理工作负载中常见的简单性。
真正令人印象深刻的是,我们通过组合这四个现有的库,快速创建了一个分布式并行 GPU 数组:
这些工具已经存在。我们只需要用少量“胶水代码”和微小修改将它们连接起来。通过将这些工具组合使用,我们可以快速构建并切换不同的架构,以探索最适合我们应用的方案。
对于这个例子,我们依赖于上游的以下更改:
现在我们可以轻松地在不同架构上运行一些实验。这很容易,因为……
这些库使我们能够快速判断以下硬件选择下的计算成本:
下面我们将给出这四种选择的代码,但首先,我们先展示一个结果表。
架构 时间 单核 CPU 2小时 39分钟 四十核 CPU 11分钟 30秒 单块 GPU 1分钟 37秒 八块 GPU 19秒
import cupy
import dask.array as da
# 生成由大量 numpy 随机数组组成的分块 dask 数组
rs = da.random.RandomState()
x = rs.normal(10, 1, size=(500000, 500000), chunks=(10000, 10000))
print(x.nbytes / 1e9) # 2 TB
# 2000.0
(x + 1)[::2, ::2].sum().compute(scheduler='single-threaded')
(x + 1)[::2, ::2].sum().compute(scheduler='threads')
我们通过更改数据源以生成 CuPy 数组而非 NumPy 数组来从 CPU 切换到 GPU。其他一切基本都能正常工作,无需为 CuPy 进行特殊处理。
(实际上这还不完全正确,dask.array 中的许多功能对于非 NumPy 数组会中断,但我们正在 Dask、NumPy 和 GPU 数组库内部积极解决这个问题。不过,这个例子中的所有内容都能正常工作。)
# 生成由大量 cupy 随机数组组成的分块 dask 数组
rs = da.random.RandomState(RandomState=cupy.random.RandomState) # <-- 这里我们指定了 cupy
x = rs.normal(10, 1, size=(500000, 500000), chunks=(10000, 10000))
(x + 1)[::2, ::2].sum().compute(scheduler='single-threaded')
from dask_cuda import LocalCUDACluster
from dask.distributed import Client
cluster = LocalCUDACluster()
client = Client(cluster)
(x + 1)[::2, ::2].sum().compute()
再次,这是结果:
架构 时间 单核 CPU 2小时 39分钟 四十核 CPU 11分钟 30秒 单块 GPU 1分钟 37秒 八块 GPU 19秒
首先,这是我第一次接触 40 核系统。我很惊讶能看到这么多核心。我也很高兴看到 Dask 的普通线程调度程序能够愉快地充分利用这么多核心。
虽然之后它确实下降到 5000-6000% 左右,如果你计算一下,你会发现我们并没有获得 40 倍的加速。我的猜测是,如果我们尝试线程和进程的混合使用,例如使用十个进程,每个进程八个线程,性能可能会有所提升。
然而,从最大的多核 CPU 到单个 GPU 的飞跃仍然是一个数量级的提升。而跃升到多 GPU 又是一个数量级的提升,将计算时间缩短到 19 秒,这已经足够短,我可以愿意等待它完成而不用离开我的电脑。
实际上,在仪表板上查看进程非常有趣(尤其是在你已经为顺序解决方案等待了三个小时之后)
这个计算很简单,但我们探索的架构范围却很广泛。我们切换了底层架构,从 CPU 到 GPU(后者有完全不同的代码库),并尝试了多核 CPU 并行和多 GPU 多核并行。
我们在不到二十行代码内完成了这一切,使得这个实验成为本科生或其他新手在家也能进行的尝试。我们正接近这样一个节点:非专家也能轻松地进行多 GPU 系统的实验(至少对于数组计算而言)。
我们可以朝着各种方向扩展上述计算。要使其稳定可靠,我们还有大量工作要做。
如果上面的工作听起来让你感兴趣,那就来帮忙吧!有很多容易入手且影响深远的工作可以做。
如果您有兴趣通过专注于这些主题获得报酬,那么可以考虑申请一份工作。NVIDIA 公司正在招聘与 Dask 在 GPU 上的使用相关的职位。
那是一个相当通用的招聘信息。如果您感兴趣,即使招聘信息看起来不太符合,也请申请,我们会进行调整。