数据科学

NVIDIA Merlin Distributed-Embeddings轻松快速训练TB 级推荐模型

Embedding在深度学习推荐模型中起着关键作用。它们被用于将输入数据中的离散特征映射到向量,以便下游的神经网络进行处理。Embedding 通常构成深度学习推荐模型中的大部分参数,大小可以达到 TB 级。在训练期间,很难将它们放入单个 GPU 的内存中。因此,现代推荐系统可能需要模型并行和数据并行的分布式训练方法组合,以最佳利用GPU计算资源来实现最好的训练性能。

NVIDIA Merlin Distributed-Embeddings ,可以方便TensorFlow 2 用户用短短几行代码轻松完成大规模的推荐模型训练。

背景

在数据并行分布式训练中,整个模型被复制到每个 GPU 上。在训练过程中,一批输入数据在多个 GPU 中分割,每张卡独立处理其自己的数据分片,从而允许计算扩展到更大批量的数据。在反向传播期间,计算的梯度通过reduction算子(例如, horovod.tensorflow.allreduce ) 来同步更新多个GPU间的参数。

另一方面,模型并行分布式训练中,模型参数被分割到多个GPU上。这种方法更适合分布存储大型embedding。训练中,每个GPU 通过alltoall通信算子(例如, ) 访问不在本机中的参数。

在之前的相关文章中, 用TensorFlow 2 在DGX A100上训练100B +参数的推荐系统 , Tomasz 讨论了如何将1130 亿参数的DLRM 模型中的embedding分布到多个 NVIDIA GPU 进行训练,并相比纯CPU 的方案实现 672 倍的性能提升。这一重大突破可以将训练时间从几天缩短到几分钟!这是通过模型并行 embedding层和数据并行MLP层来实现的。和CPU方案相比,这种混合并行的方法能够有效利用GPU 的高内存带宽加速内存受限的embedding查找,并同时利用多个 GPU 的算力加速 MLP 层。作为参考, NVIDIA A100-80GB GPU 具有超过 2 TB / s 的带宽和 80 GB HBM2 存储)。

1.用于训练大型推荐系统的通用混合并行方法

embedding表可以按表为分割单位(图中表 0 和 N ),按”列“分割(图中表 2),或者按”行”分割。MLP 层跨所有 GPU 复制,而数字特征则可以直接输入 MLP 层。

然而,实现这种复杂的混合并行训练方法并不简单,需要领域内专家设计数百行底层代码来开发和优化。为了使其更普适,  NVIDIA Merlin Distributed-Embeddings 提供了一些易于使用的TensorFlow 2的封装,让所有人都只需三行 Python 代码即可轻松实现模型并行。它提供了一些涵盖并拓展原生TensorFlow功能的高性能embedding查找算子。在此基础上,它提供了一个可规模化的模型并行封装函数,帮助用户自动将embedding分布于多个GPU上。下面将展示它如何实现混合并行。

分布式模型并行

NVIDIA Merlin Distributed-Embeddings 提供了 distributed_embeddings.dist_model_parallel 模块。它有助于在多个 GPU 之间分布embedding而无需任何复杂的代码来处理跨GPU间的通信(如  all2all )。下面的代码示例显示了此 API 的用法:

import dist_model_parallel as dmp

 

class MyEmbeddingModel(tf.keras.Model):

  def  __init__(self, table_sizes):

    …

    self.embedding_layers = [tf.keras.layers.Embedding(input_dim, output_dim) for input_dim, output_dim in table_sizes]

    # 1. Add this line to wrap list of embedding layers used in the model

    self.embedding_layers = dmp.DistributedEmbedding(self.embedding_layers)

  def call(self, inputs):

    # embedding_outputs = [e(i) for e, i in zip(self.embedding_layers, inputs)]

    embedding_outputs = self.embedding_layers(inputs)

    …

要使用 Horovod 以数据并行方式运行MLP层,请将 Horovod的 Distributed GradientTape  和 broadcast 方法替换成 NVIDIA Merlin Distributed-Embeddings 里同等的API。以下示例直接取自 Horovod 文档,并进行了相对应修改。

@tf.function

def training_step(inputs, labels, first_batch):

  with tf.GradientTape() as tape:

    probs = model(inputs)

    loss_value = loss(labels, probs)

 

  # 2. Change Horovod Gradient Tape to dmp tape

  # tape = hvd.DistributedGradientTape(tape)

  tape = dmp.DistributedGradientTape(tape)

  grads = tape.gradient(loss_value, model.trainable_variables)

  opt.apply_gradients(zip(grads, model.trainable_variables))

 

  if first_batch:

    # 3. Change Horovod broadcast_variables to dmp’s

    # hvd.broadcast_variables(model.variables, root_rank=0)

    dmp.broadcast_variables(model.variables, root_rank=0)

  return loss_value

通过这些微小的改变,您就可以使用混合并行训练了!

我们还提供了以下完整示例: 使用 Criteo 1TB 点击日志数据训练 DLRM 模型 以及 扩展到 22.8 TiB的合成数据 模型。

性能

为了展示 NVIDIA Merlin Distributed-Embeddings 的性能,我们在 Criteo 1TB 数据集DLRM 模型和最高达到 3 TiB embedding的合成模型上进行了模型训练的基准测试。

Criteo 数据集上的 DLRM 模型基准测试

测试表明,我们使用更简单的 API 取得了近似于专家代码的性能。NVIDIA深度学习DLRM TensorFlow 2示例代码现已更新为使用 NVIDIA Merlin Distributed-Embeddings 进行分布式混合并行训练,更多信息请参阅我们之前的文章, TensorFlow 2 DGX A100上训练100B +参数的推荐系统. README中的 基准测试 部分提供了对性能结果的更多详述。

 

我们对1130 亿个参数( 421 个 GiB 大小)的 DLRM 模型在 Criteo TB 点击日志 数据集上用三种不同的硬件设置进行了训练:

  • 仅 CPU 的解决方案。
  • 单 GPU 解决方案,其中 CPU 内存用于存储最大的embedding表。
  • 使用 NVIDIA DGX A100-80GB 的 8 GPU 的混合并行解决方案。此方案利用了 NVIDIA Merlin Distributed-Embeddings 里提供的模型并行api和embedding API 。

Hardware

Description

Training Throughput (samples/second)

Speedup over CPU

2 x AMD EPYC 7742

Both MLP layers and embeddings on CPU

17.7k

1x

1 x A100-80GB; 2 x AMD EPYC 7742

Large embeddings on CPU, everything else on GPU

768k

43x

DGX A100 (8xA100-80GB)

Hybrid parallel with NVIDIA Merlin Distributed-Embeddings, whole model on GPU

12.1M

683x

1.各种设置的训练吞吐量和加速

我们观察到, DGX-A100 上的 NVIDIA Merlin Distributed-Embeddings 方案比仅使用 CPU 的解决方案提供了惊人的 683 倍的加速!我们还注意到与单GPU 方案相比,混合并行的性能也有显著提升。这是因为在 GPU 显存中存储所有embedding避免了通过 CPU-GPU 接口查找embedding的开销。

合成模型基准测试

为了进一步演示方案的可规模化,我们创建了不同大小的合成数据以及对应的 DLRM 模型(表 2 )。有关模型生成方法和训练脚本的更多信息,请参见 GitHub NVIDIA-Merlin/distributed-embeddings 代码库。

Model

Total number of embedding tables

Total embedding size (GiB)

Tiny

55

4.2

Small

107

26.3

Medium

311

206.2

Large

612

773.8

Jumbo

1,022

3,109.5

2.合成模型尺寸

每个合成模型使用一个或多个 DGX-A100-80GB 节点进行训练,全局数据batch大小为 65536 ,并使用 Adagrad 优化器。从表 3 中可以看出,  NVIDIA Merlin Distributed-Embeddings 可以在数百个 GPU 上轻松训练 TB 级模型。

Model

Training step time (ms)

1 GPU

8 GPU

16 GPU

32 GPU

128 GPU

Tiny

17.6

3.6

3.2

 

 

Small

57.8

14.0

11.6

7.4

 

Medium

 

64.4

44.9

31.1

17.2

Large

 

 

 

65.0

33.4

Jumbo

 

 

 

 

102.3

3.各种硬件配置下合成模型的训练步长时间( ms

另一方面,与传统的数据并行相比,即使对于可以容纳在单个 GPU 中的模型,多GPU分布式模型并行仍然提供了显著加速。表 4 显示了上述Tiny模型在DGX A100-80GB 上的性能对比。

Solution

Training step time (ms)

1 GPU

2 GPU

4 GPU

8 GPU

NVIDIA Merlin Distributed Embeddings Model Parallel

17.7

11.6

6.4

4.2

Native TensorFlow Data Parallel

19.9

20.2

21.2

22.3

4. Tiny模型( 4.2GiB )的训练步长时间( ms )比较 NVIDIA Merlin Distributed-Embeddings 模型并行和原生 TensorFlow 数据并行

本实验使用了 65536 的全局批量和 Adagrad 优化器。

结论

在这篇文章中,我们介绍了  NVIDIA Merlin Distributed-Embeddings,仅需几行代码即可在 NVIDIA GPU 上实现基于 embedding的深度学习模型,并进行可规模化,高效率地模型并行训练。欢迎尝试以下 使用合成数据的可扩展训练示例 和 基于 Criteo 数据训练 DLRM 模型 示例.

 

Tags