WholeGraph 介绍#

WholeGraph 帮助训练大规模图神经网络 (GNN)。WholeGraph 提供了称为 WholeMemory 的底层存储结构。WholeMemory 是一种类似 Tensor 的存储,并提供多 GPU 支持。它针对像 DGX A100 服务器这样的 NVLink 系统进行了优化。通过与 cuGraph、cuGraph-DGL、cuGraph-PyG 以及上游的 DGL 和 PyG 协同工作,构建 GNN 应用程序将变得容易。

WholeMemory#

WholeMemory 可以被视为 GPU 内存的整体视图。无论底层数据如何跨多个 GPU 存储,WholeMemory 都暴露一个内存实例的句柄。WholeMemory 假定使用单独的进程来控制每个 GPU。

WholeMemory 基础知识#

要定义 WholeMemory,我们需要指定以下内容

1. 指定处理内存的 GPU 集#

由于 WholeMemory 归一组 GPU 所有,因此必须指定这组 GPU。这可以通过创建 WholeMemory Communicator 并在创建 WholeMemory 时指定 WholeMemory Communicator 来完成。

2. 指定内存位置#

虽然 WholeMemory 归一组 GPU 所有,但内存本身可以位于主机内存或设备内存中。需要指定内存位置,可以指定两种类型的位置。

  • 主机内存:将使用固定主机内存作为底层存储。

  • 设备内存:将使用 GPU 设备内存作为底层存储。

3. 指定内存的地址映射模式#

由于 WholeMemory 归多个 GPU 所有,每个 GPU 都将访问整个内存空间,因此我们需要地址映射。有三种类型的地址映射模式(也称为 WholeMemory 类型),它们是

  • 连续模式 (Continuous):每个 GPU 的所有内存都将映射到每个 GPU 的单个连续内存地址空间中。在此模式下,每个 GPU 都可以使用单个指针和偏移量直接访问整个内存,就像使用普通设备内存一样。软件不会看到差异。硬件对等访问将处理底层通信。

  • 分块模式 (Chunked):每个 GPU 的内存将映射到不同的内存块中,每个 GPU 一个块。在此模式下,也支持直接访问,但不是使用单个指针。软件将看到分块内存。然而,一个抽象层可以帮助隐藏这一点。

  • 分布式模式 (Distributed):来自其他 GPU 的内存不会映射到当前 GPU 中,因此不支持直接访问。要访问其他 GPU 的内存,需要显式通信。

要了解 WholeMemory 位置和 WholeMemory 类型的更多详细信息,请参阅 WholeMemory 实现细节

WholeMemory Communicator#

WholeMemory Communicator 有两个主要目的

  • 定义一组在 WholeMemory 上协同工作的 GPU。WholeMemory Communicator 由所有希望协同工作的 GPU 创建。只要所需的 GPU 集相同,WholeMemory Communicator 就可以重复使用。

  • 提供 WholeMemory 所需的底层通信通道。WholeMemory 在创建期间以及对某些类型的 WholeMemory 进行某些操作时,可能需要 GPU 之间的通信器。

要创建 WholeMemory Communicator,首先需要创建一个 WholeMemory Unique ID,这通常由 GPU 集中的第一个 GPU 创建,然后广播给所有希望协同工作的 GPU。然后此通信器中的所有 GPU 将使用此 WholeMemory Unique ID、当前 GPU 的 rank 以及所有 GPU 计数来调用 WholeMemory Communicator 创建函数。

WholeMemory 粒度#

由于底层存储可能会在物理上分割到多个 GPU 中,这通常不是单个用户数据块内所希望的。为解决此问题,在创建 WholeMemory 时可以指定数据的粒度。然后 WholeMemory 被视为具有相同粒度的多个块,并且在粒度内部不会被分割。

WholeMemory 映射#

由于 WholeMemory 向 GPU 提供内存的整体视图,因此访问 WholeMemory 通常需要映射。不同类型的 WholeMemory 支持不同的映射方法,与其名称相符。支持的一些映射包括

  • 所有 WholeMemory 类型都支持映射本地 GPU 负责的内存范围。也就是说,每个 rank 可以在所有 WholeMemory 类型中直接访问“本地”内存。这里的“本地”内存不一定非得在当前 GPU 的内存上,它可以位于主机内存甚至可能在其他 GPU 上,但它保证可以被当前 GPU 直接访问。

  • 分块模式 (Chunked) 和连续模式 (Continuous) 的 WholeMemory 也支持分块映射。也就是说,所有 GPU 的内存都可以映射到当前 GPU,每个 GPU 一个连续块。当前 GPU 可以直接访问每个块。但不同块的内存不保证连续。

  • 连续模式 (Continuous) 的 WholeMemory 可以映射到连续的内存空间中。也就是说,所有 GPU 的内存都映射到单个虚拟内存范围,访问此内存的不同位置将物理上访问不同的 GPU。此映射由硬件(CPU 页表或 GPU 页表)处理。

WholeMemory 操作#

WholeMemory 上可以执行一些操作。它们基于 WholeMemory 的映射。

本地操作#

由于所有 WholeMemory 都支持本地内存映射,因此支持本地内存操作。操作可以是读或写。像使用当前设备的 GPU 内存一样使用即可。

加载和存储#

为了方便文件操作,支持从文件加载 WholeMemory 或将 WholeMemory 存储到文件。WholeMemory 对磁盘操作使用原始二进制文件格式。对于加载,输入文件可以是单个文件或文件列表,如果是一个列表,它们将被逻辑连接在一起然后加载。对于存储,每个 GPU 将其本地内存存储到文件中,生成文件列表。

收集和分散 (Gather and Scatter)#

WholeMemory 还支持收集/分散操作,它们通常在 WholeMemory Tensor 上运行。

WholeMemory Tensor#

与 PyTorch 相比,WholeMemory 类似于 PyTorch Storage,而 WholeMemory Tensor 类似于 PyTorch Tensor。目前,WholeMemory 仅支持 1D 和 2D tensors,即数组和矩阵。仅第一个维度被分区。

WholeMemory Embedding#

WholeMemory Embedding 就像一个 2D WholeMemory Tensor,增加了两个功能。它们支持缓存和稀疏优化器。

缓存支持#

要创建带缓存的 WholeMemory Embedding,首先需要创建 WholeMemory CachePolicy。WholeMemory CachePolicy 可以通过以下字段创建

  • WholeMemory Communicator:WholeMemory CachePolicy 也需要 WholeMemory Communicator。WholeMemory Communicator 定义了缓存所有 Embedding 的 GPU 集。它可以与创建 WholeMemory Embedding 时使用的 WholeMemory Communicator 相同。

  • WholeMemory 类型:WholeMemory CachePolicy 使用 WholeMemory 类型来指定缓存的 WholeMemory 类型。

  • WholeMemory 位置:WholeMemory CachePolicy 使用 WholeMemory 位置来指定缓存的位置。

  • 访问类型:访问类型可以是只读 (readonly) 或读写 (readwrite)。

  • 缓存比例:指定缓存将使用多少内存。此比例针对缓存整个 embedding 的每个 GPU 集计算。

两种最常用的缓存是

  • 设备缓存的主机内存 (Device cached host memory):当 Cache Policy 的 WholeMemory Communicator 与创建 WholeMemory Embedding 时使用的 WholeMemory Communicator 相同时,这意味着缓存与 WholeMemory Embedding 具有相同的 GPU 集。因此,每个 GPU 只缓存其自己部分的原始 Embedding。最常见的情况是,当原始 WholeMemory Embedding 位于主机内存上,而缓存位于设备内存上时,每个 GPU 只缓存其自己部分的主机内存。

  • 本地缓存的全局内存 (Local cached global memory):WholeMemory CachePolicy 的 WholeMemory Communicator 也可以是 WholeMemory Embedding 的 WholeMemory Communicator 的一个子集。在这种情况下,GPU 的子集共同缓存所有 embedding。通常,当原始 WholeMemory Embedding 分区在不同的机器节点上,并且我们想在本地机器或本地 GPU 中缓存一些 embedding 时,GPU 的子集可以是本地机器中的所有 GPU。对于本地缓存的全局内存,仅支持只读。

WholeMemory Embedding 稀疏优化器#

WholeMemory Embedding 的另一个特点是它支持 embedding 训练。为了高效训练大型 embedding 表,需要稀疏优化器。WholeMemory Embedding 稀疏优化器可以在带缓存或不带缓存的 WholeMemory Embedding 上运行。当前支持的优化器包括 SGD、Adam、RMSProp 和 AdaGrad。

图结构#

WholeGraph 中的图结构也基于 WholeMemory。在 WholeGraph 中,图以 CSR 格式存储。ROW_INDEX (记为 csr_row_ptr) 和 COL_INDEX (记为 csr_col_ind) 都存储在 WholeMemory Tensor 中。因此,加载图结构可以使用 WholeMemory Tensor 加载机制