NVIDIA 深度学习性能

构建和部署推荐系统的最佳实践

摘要

本文档介绍了使用 NVIDIA GPU 构建和部署大规模推荐系统的最佳实践。这些实践是多年来在 GPU 加速的推荐系统工具以及为我们的内部产品构建推荐系统和国际推荐系统竞赛的顶级解决方案中研究和开发的结晶。

推荐系统是互联网的经济引擎。这些应用程序对我们的日常数字生活产生直接影响,它们在数量庞大的选项中过滤产品和服务,缓解了大多数用户面临的选择悖论。

本文档的主要目标是提供使用 NVIDIA® GPU 构建和部署大规模推荐系统的最佳实践。这些最佳实践是多年来在 GPU 加速的推荐系统工具以及为我们的内部产品构建推荐系统和国际推荐系统竞赛的顶级解决方案中研究和开发的结晶。

本文档不仅提供了构建和部署大规模推荐系统的最佳实践,还涵盖了推荐系统的各个方面,重点是 GPU 加速和优化。

从高层次来看,推荐系统的目标是从可能包含数百万甚至数十亿个项目的大型目录中,向用户推荐相关的项目。系统将项目范围缩小到用户最感兴趣的可消费子集。

2.1. 推荐阶段

一个完整的推荐过程通常由四个阶段组成,如图 图 1 所示。

图 1. 推荐系统的四个阶段

stages.jpg

检索
候选项目从完整的项目目录中生成,该目录可能非常庞大。一种流行的检索方法涉及构建嵌入模型。这是一个表示用户和项目的密集向量空间。然后采用近似最近邻 (ANN) 搜索来有效地检索最合适的候选项目。
过滤
无效的候选项目被过滤掉。例如,不适合用户人口统计特征(如地区和年龄)、不可用的电影或用户已经看过的电影。
评分
使用更丰富的用户、项目和会话特征以及更具表现力的模型(如深度神经网络)对有效的候选项目进行评分。
排序
确定一组 Top-K 候选项目。这些 Top-K 候选项目根据其他业务逻辑和优先级重新排序。例如,如果针对特定产品类别或制造商开展营销活动,则会将其考虑在内。

2.2. 推荐系统的组件

推荐系统包含几个关键组件。如图 图 2 所示,这些组件分为四个功能区域

图 2. 推荐系统的组件

components.jpg

2.2.1. 数据管道

数据管道包含以下组件:

  • 数据采集、验证和数据存储:用户、产品和交互数据(如浏览和购买)被持续收集并放入数据存储中,如数据库或数据湖。此数据规模可达太字节 (TB) 或拍字节 (PB) 级。
  • 数据提取、预处理和特征工程:训练推荐模型所需的原始数据源需要进行聚合、提取和清理,以创建与手头问题相关的特征,并帮助提高系统的准确性。此处理可能特定于需要训练的模型。例如,决策树模型和 DLRM 模型可能需要不同的预处理。这通常是一个迭代且耗时的过程。但是,有一些工具,例如 NVIDIA NVTabularNVIDIA RAPIDS,可用于在 GPU 上加速开发和生产。

    数据预处理和特征工程在系统构建阶段的初期进行批量处理,然后在生产阶段持续进行,在此阶段模型使用新数据进行更新。

  • 特征存储:工程特征通常存储在特征存储中,该特征存储可用于训练和生产推理,以保持一致性。

2.2.2. 训练和持续再训练

进行模型的初始训练,以便可以生成和评分候选项目。这些模型候选项目在大量可用数据上进行训练并部署。持续的增量再训练确保模型保持最新,并捕获最新的趋势和用户偏好。模型验证模块用于确保模型满足指定的质量阈值。

2.2.3. 部署和服务

新合格的模型在初始部署后以无缝方式自动重新部署到生产环境中。理想情况下,这应支持金丝雀发布和回滚。推理服务器的数量也应根据需要自动向上和向下扩展。

2.2.4. 日志记录和监控

持续监控模块,以便可以通过一系列 KPI(如命中率和转化率)实时衡量推荐的质量。如果发生模型漂移,例如当某些 KPI 降至低于已知的既定基线时,模块会触发完全再训练。

数据预处理和特征工程在构建有效的机器学习系统中起着至关重要的作用。虽然深度学习的进步减少了在计算机视觉和 NLP 等领域中手动制作特征的需求,但对于表格数据,巧妙的特征创建仍然可以产生巨大的影响。

有多种特征工程技术可用于开发推荐系统的特征,例如多模态特征提取和数据增强。我们在最近的四次推荐系统竞赛中广泛应用和测试了这些技术:

3.1. 多模态特征提取技术

除了表格数据(构建推荐系统最流行的数据源)之外,还可以在可能的情况下使用多模态数据。示例包括用户和产品图像、自由文本描述以及用户文本个人资料。可以使用特定领域的神经网络(如用于图像的 ResNet 和用于文本的 BERT)从这些模态中提取特征。然后将这些特征与其他数值和分类特征结合起来。在 SIGIR 电子商务挑战赛 期间,我们发现,对于基于文本和图像的特征,应用 L2 归一化比使用原始向量更好。在与其他特征连接之前,对每个多模态特征单独应用层归一化可以提高性能。

3.2. 数据增强技术

可以使用特定领域的数据增强技术来丰富训练数据。这方面的示例包括反转序列和向“非产品”添加辅助数据。

Booking.com WSDM WebTour 挑战赛 2021 的目标是根据旅行者在整个行程过程中的先前预订历史记录来预测其最后的目的地城市。为了增强数据,旅行序列被反转,这有效地使训练数据量增加了一倍。NVIDIA 数据科学家发现,使用这种方法,预测准确性得到了提高。

Coveo SIGIR 电子商务研讨会挑战赛 2021 中,通过将用户与“非产品”页面的交互视为虚拟产品,在很大程度上提高了我们的推荐准确性。对于其他具有与项目无关的页面浏览量的推荐问题,这种技术值得尝试。

3.3. 创建和提取更多特征

机器学习从业者采用了各种特征工程技术。这些特征工程技术包括以下内容:

  • 目标编码:用目标变量的平均值替换分类值。
  • 计数编码:用在训练集上计算的类别计数替换类别。
  • 滞后特征:从时间上两个点之间的差异生成。
  • 时间循环特征:提取表现出循环模式的特征,例如一天中的小时和一周中的天。
  • 特征交叉:将两个或多个特征组合以创建新特征。

除了这些特征工程技术之外,应始终利用领域知识来创建特征。这方面的示例包括提取 Twitter 推文中的提及和主题标签,因为它们代表特别感兴趣的实体。

为了简单起见,我们将推荐模型分为传统机器学习模型或深度学习模型。

根据 NVIDIA KGMON 团队的说法,始终重要的是从非常简单的模型开始,使用少量特征、简单的模型类型和架构来开发基线,然后添加更复杂的模型类型和架构以及其他特征。

4.1. 传统机器学习模型

传统机器学习模型包括矩阵分解和梯度提升模型等模型,这些模型是经过充分验证的模型,已在生产环境中广泛部署。基于树的梯度提升模型是高性能模型,通常在机器学习和推荐系统竞赛中采用。

为什么深度学习模型在推荐系统竞赛中尚未持续获胜? 研究论文中,NVIDIA 研究人员解释了为什么较新的基于深度学习的推荐模型在公开竞赛中没有持续胜过传统机器学习模型。我们可以通过我们最近的 RecSys 2020Recsys 2021Booking.com 挑战赛的胜利以及我们在 SIGIR 电子商务挑战赛(任务 2)中的第二名解决方案来证实这一说法,在这些解决方案中,梯度提升机 (GBM) 是一个重要的组成部分。虽然深度学习模型也在这些竞赛中使用,但它们并没有完全压倒传统的机器学习模型。

4.1.1. 在 GPU 上训练和部署基于树的 GBM

流行的 GBM 库(如 XGboostLightGB)都在 GPU 上加速。NVIDIA Triton Inference Server FIL Backend 允许将由多个流行的机器学习框架(包括 XGBoost、LightGBM、Scikit-Learn 和 cuML)训练的森林模型部署在使用 RAPIDS Forest Inference LibraryTriton Inference Server 中,以实现快速的基于 GPU 的推理。使用此后端,森林模型可以与深度学习模型无缝部署在一起,以实现快速、统一的推理管道。

4.2. 深度学习推荐模型

RecSys 领域中大型多模态数据集的日益普及,以及深度学习在 NLP、计算机视觉和语音处理领域的进步,推动了近年来对用于构建推荐系统的深度学习模型的探索。

图 3 描述了 DLRM(深度学习推荐模型)的架构。DLRM 的输入可以是数值特征或分类特征。数值特征(如观看的电影数量)可以直接输入到 MLP 层。但是,分类特征(如国家/地区、语言、电影标题和类型)需要具有可以处理的数值表示。

图 3. DLRM 的架构图

dlrm.jpg

与图像或音频数据(通常是数值和连续值)不同,推荐器中的分类输入是非数值的,因此需要一个中间处理步骤将其转换为数值向量,以便可以对其进行处理。有两种主要方法可以做到这一点:

  • 编码:使用独热编码或多热编码将分类特征转换为 0 和 1 的稀疏向量。然后可以将这些稀疏数值向量直接输入到机器学习模型中,例如基于树的梯度提升模型或神经网络,如 Wide & Deep Learning 模型 (WDL) 的宽部。
  • 嵌入:分类特征被映射到用于索引的整数 ID,并且这些 ID 被嵌入到多维向量空间中。这种多维表示/映射在训练期间学习。与编码生成的稀疏向量相比,嵌入维度要小得多。

4.2.1. 嵌入

嵌入是 NLP 中的一个流行概念,其中单词/WordPiece 标记通过嵌入表以数值方式表示。在将推荐模型嵌入与其他类型的模型嵌入进行比较时,需要注意一些关键差异:

关于此任务

  • 在语言模型的情况下,需要嵌入单个词汇表。在 BERT 中,使用了具有 30,000 个标记词汇表的 WordPiece 嵌入。与此同时,推荐器可能具有多个分类特征,每个特征都有单独的词汇表,每个词汇表都需要嵌入。
  • 与 NLP 模型相比,计算仍然是吞吐量的主要因素,深度学习推荐器在内存占用方面往往更重。现代推荐器中的嵌入表可以达到数太字节,通常超过 CPU 或 GPU 内存的容量,并且涉及纯内存查找操作。MLP 部分相比之下仍然相对小得多,这使得深度学习推荐器受内存限制。
  • 推荐器中的某些特征可以是多热的,这意味着特征字段具有多个非零条目。这方面的一个很好的例子是可用于指示用户过去一周观看的电影的特征。在此示例中,电影是嵌入的项目。用户可能在一周内观看了多部电影。与每个标记倾向于进行一次查找的语言模型相比,多热特征需要多次嵌入查找。通常,从每个特征的表中检索的多个向量通过求和/平均池化操作组合/缩减以创建一个向量。此操作对于独热特征不是必需的。

访问嵌入通常会生成分散的内存访问模式。观看的电影不太可能导致连续的访问模式。这可能会给内存系统带来挑战,使其效率低下。NVIDIA GPU 具有高度并行化的内存系统,该系统具有多个内存控制器和地址转换单元,这非常适合分散的内存访问。此外,借助最新的 NVIDIA GPU 技术,多 GPU 和多节点 GPU 内存容量变得足够大,可以容纳大型嵌入。此外,还有一些方法可以通过自适应多级存储机制来利用 CPU 内存和/或 SSD/HDD/NFS。

4.2.1.1. 批量大小和 GPU 内存带宽

由于嵌入表的大小主要取决于特征中不同类别的数量(词汇表大小)、嵌入向量大小(嵌入向量的维度)和精度,因此嵌入表大小的计算方式如下:

嵌入     大小     词汇表   大小   *   嵌入   向量   大小   *   精度

对于单精度嵌入,单热特征操作的嵌入表查找大致访问 批量大小   *   嵌入   向量   大小   *   sizeof ( FP32 ) 内存中的字节数。

为了将其推广到多热特征,并考虑到索引查找造成的任何内存使用,访问的内存将按如下方式计算,其中 NNZ 表示特征字段中具有 INT64 索引的非零数或条目数 n = 1 批量大小 ( ( NN Z n   *   嵌入   向量   大小   *   sizeof ( FP32 ) )   +   NN Z n   *   sizeof ( INT64 ) )

优化 GPU 内存流量需要随时有足够的正在进行的访问(读取/写入)。根据观察,对于较小的批量大小,较高的嵌入宽度可以更有效地利用 GPU 内存带宽。对于较大的批量大小,即使较窄的宽度也创建了足够的工作负载来更好地利用内存流量,因此内存流量会饱和。

图 4. 不同批量大小的 GPU 内存带宽 (GB/s) 使用率

gpu-memory-bandwidth.jpg

不同批量大小的 GPU 内存带宽 (GB/s) 使用率 显示了使用以下实验设置的不同批量大小的 GPU 内存带宽 (GB/s) 使用率:

  • A100 40 GB GPU,具有 1.55 TB/s 内存带宽
  • 包含 10M 个类别的单个嵌入表,使用三种不同的宽度(32、64 和 128 个 FP32 元素)进行测试
  • 单个 64 热,需要读取 64 个向量并将它们相加以便可以组合
  • 嵌入表行访问遵循均匀分布

根据 不同批量大小的 GPU 内存带宽 (GB/s) 使用率,对于一个 64 热表,首选 4K-16K 的批量大小。如果需要并发查找 N 个此类表,则可以使用(批量大小 / N)来实现相同的总内存流量。这是因为批处理中访问的总内存保持不变。作为最佳实践,请使用允许您获得足够好的准确度以保持效率的最大批量大小。

4.2.1.2. 嵌入宽度

嵌入宽度是指嵌入表中每个向量的大小(以字节为单位)。例如,如果表中的每个向量的嵌入向量大小为 16,并且以 FP32 精度表示,则嵌入宽度将为 64 字节。

建议将嵌入宽度填充为 16 字节的倍数。通常,64 或 128 字节的倍数会导致更好的性能。

根据 图 5,我们看到,选择嵌入宽度或将其填充为 16 字节的倍数可带来平均 1.05 倍的性能加速、最大 1.26 倍的性能加速和 0.97 倍的性能减速。在倍数出现之前的边缘附近可以看到更大的加速。这方面的一个示例是选择 32 字节的宽度来代替 31 字节。额外的容量甚至可以通过更好的表示来使模型受益。

图 5. 将嵌入宽度填充为 16 字节倍数的好处

padding-embedded.jpg

图 5 展示了在使用以下实验设置的不同嵌入宽度下嵌入访问操作的速度:

  • A100 40 GB GPU,具有 1.55 TB/s 内存带宽
  • 单个嵌入表,包含 10M 个类别,针对不同的嵌入宽度进行了测试
  • 一个 64 热、奇异特征,批量大小为 8K
  • 嵌入表行访问遵循均匀分布

如果行访问根据幂律分布分布(这基本上意味着很少的行被非常频繁地访问,而许多行被不频繁地访问),则使用与 图 5 中使用的类似实验设置,可以观察到平均 1.03 倍的加速。

4.2.1.3. 超出 GPU 内存的嵌入的常用实践

如果嵌入表的大小超过单个 GPU 的内存,则通常在实践中使用以下方法或这些方法的组合:

  • 使用 NVIDIA NVLink 和/或 Infiniband 等互连在多个 GPU 或节点之间分配嵌入。有几种分配嵌入的方法,例如拆分嵌入,以便:
    • 每个嵌入表完全放置在单个 GPU 上,该 GPU 保存所有嵌入的子集(按表划分),
    • 每个 GPU 保存来自所有表的列的子集(按列划分),或者
    • 每个 GPU 保存来自所有嵌入表的行的子集(按行划分)
  • 在 CPU 和 GPU 内存之间拆分嵌入表。 频繁访问的行可以保留在 GPU 内存中,而不太常用的行可以保留在通过 PCIe 总线获取的 CPU 内存中。最佳实践是,并且正如在 Criteo 等流行数据集中看到的那样,数据集通常遵循幂律分布,其中少量常用行可以保存在快速 GPU 内存中,而许多不常用的行可以保存在 CPU 内存中。处理非常大的嵌入的另一种方法是将所有较小的表保存在 GPU 中,而将较大的表保存在 CPU 中。
  • 将所有嵌入表保存在 CPU 上,并在 GPU 上运行 MLP。 这是一种相对简单的方法,它仍然可以比仅 CPU 模型更快。

为了支持大型嵌入,NVIDIA HugeCTR 在设计中内置了多个最佳实践。HugeCTR 是一个 GPU 加速的推荐框架,旨在跨多个 GPU 和节点分配训练,并估计点击率 (CTR)。它还将其模型并行训练的功能扩展到其他框架,如 TensorFlow,通过其 Sparse Operation Kit (SOK),它利用单节点或多节点系统中所有可用的 GPU 进行模型并行分布式嵌入。要了解有关这些功能的更多信息,请参阅 NVIDIA HugeCTR

4.2.1.4. 融合嵌入表

在推荐模型中,需要嵌入分类特征才能将其馈送到 MLP 层。

如果多个嵌入表具有相同的宽度(嵌入向量大小),则将它们融合以创建一个更大的表可能是有益的。这是因为 PyTorch 和 TensorFlow 等框架可能具有单独调用嵌入查找的额外开销。因此,尽可能组合表(除非有充分的理由不这样做)将在 GPU 执行和调度方面提供更好的效率。查看以下伪代码,其中声明并分别访问了两个宽度相同的表 embedding1embedding2

复制
已复制!
            

# Unfused implementation pseudocode # declaration embedding1 = embeddingBag(cardinality_emb_1, vector_dim=128) embedding2 = embeddingBag(cardinality_emb_2, vector_dim=128) # Lookup batch_emb1 = embedding1([list of indices feature 1]) batch_emb2 = embedding2([list of indices feature 2])


作为最佳实践,融合嵌入表以创建一个更大的表可以带来更好的性能。

复制
已复制!
            

# Fused implementation pseudocode # declaration embedding12 = embeddingBag(cardinality_emb_1+cardinality_emb_2, vector_dim=128) # Lookup new_indices_feature2 = [list of indices feature 2] + cardinality_emb_1 lookup_indices = concat([list of indices feature 1] , new_indices_feature2 ) batch_emb = embedding12([lookup_indices])

4.2.2. MLP 层

全连接层通常在深度学习推荐模型中的嵌入层之后,以及在某些模型中的特征交叉层之后。MLP 的输入包括特征嵌入和数值特征。输出取决于正在训练的模型类型。在排名模型中,MLP 输出标量概率,指示项目与用户的相关性。而在嵌入模型中,输出可能是向量,表示嵌入。

通常,推荐排名模型中的 MLP 非常浅(在 3-5 层之间),并且通常采用塔形,因为层向输出方向变窄。例如,N-2048-1024-512-256-1,其中 N 等于所有输入特征的组合。但是,在其他拓扑中,例如等宽 MLP(其中每一层具有相同数量的节点)也很常见,并且 研究 表明,等宽 MLP 的性能略好。较大的批量大小有助于使可用计算 (FLOP) 饱和。建议以下批量大小以获得最佳训练:

  • 对于大型 MLP(如 N-2048-1024-512-256-1),为 8K-16K
  • 对于较小的 MLP,为 32K-64K

图 6. 针对具有不同层大小的四层 MLP 的批量大小比较 TFlops 和经过时间 (ms)

tflops-elapsed-time.jpg

图 6 中描述的结果来自前向传递和仅 MLP 层,这些层在 NVIDIA A100 GPU(理论峰值为 312 个密集 FP16 TFlops)上进行了测试。

图 6 中,我们观察到,在批量大小达到 2K 到 4K 之间之前,对于三种 MLP 配置,经过时间大致是平稳的。排名推理模型可以使用更大的批量大小,而不会在 MLP 部分造成太多的延迟性能损失。排名模型比候选生成模型具有更高的保真度,因此保持所有内容不变将可以增加生成的候选数量,而只需付出极小的额外成本。

总的来说,考虑到嵌入和 MLP,将批量大小保持在 8K 或以上可能有利于获得最佳训练。

4.2.3. 启用自动混合精度

自动混合精度 (AMP) 支持使用半精度 (FP16) 进行训练,而不会损失全精度实现的网络准确性。自动混合精度降低了训练时间和内存需求,从而可以实现更高的批量大小、更大的模型和更大的输入。与 FP32 相比,它可以提供高达三倍的训练性能,只需几行代码即可自动利用 NVIDIA GPU 中的 Tensor Core

大多数主要框架(如 PyTorchTensorFlowMXNetPaddlePaddle)都原生支持 AMP。建议尽可能利用 AMP。

有关更多信息,请参阅我们的 NVIDIA 混合精度训练文档

4.2.4. 顺序和基于会话的推荐模型

传统的推荐算法(如协同过滤)在尝试对用户行为建模时,通常会忽略时间动态和交互序列。但是,用户的偏好会随着时间而变化。顺序推荐算法能够捕获用户浏览中的顺序模式,这可能有助于预测用户的兴趣,从而实现更好的推荐。例如,开始一项新爱好(如烹饪或骑自行车)的用户可能会探索初学者产品,并可能随着时间的推移转向更高级的产品。他们也可能完全转向另一项感兴趣的爱好。因此,推荐与其过去偏好相关的项目将变得无关紧要。

基于会话的推荐任务是顺序推荐的一个特例,您只能访问当前会话中的短交互序列。这对于电子商务、新闻和媒体门户等在线服务非常常见,在这些服务中,用户可能是全新的或喜欢匿名浏览,并且由于 GDPR 合规性,不会收集 Cookie。此任务也适用于用户兴趣随时间推移而发生很大变化的情况,具体取决于用户的上下文或意图,因此,利用当前会话交互比旧交互更有希望提供相关的推荐。

为了处理顺序和基于会话的推荐,许多先前在机器学习和 NLP 研究中应用的序列学习算法已被探索用于 RecSys,例如 K 最近邻、频繁模式挖掘、隐马尔可夫模型、循环神经网络,以及最近使用自注意力机制和 Transformer 架构的神经架构。

在 NVIDIA 内部研究中,我们发现 Transformer 架构能够为序列和基于会话的推荐提供更准确的推荐。我们开发了 Transformers4Rec 库,该库充当 Transformer 架构之间的桥梁。 有关更多信息,请参阅 Transformers4Rec:弥合 NLP 与序列/基于会话的推荐之间差距 论文以及 Transformers4Rec:用于序列和基于会话的推荐的灵活库 文章。

图 7. 使用 Transformers4Rec 进行序列和基于会话的推荐

sequential.jpg

我们从广泛的 实证分析 中吸取的经验教训(包括对不同算法的基准测试)以及我们在以下挑战赛中取得的最新胜利已应用于 Transformers4Rec 库的开发:Recsys Challenge 2021Booking.com 的 WSDM WebTour Challenge 2021 以及 Coveo 的 SIGIR eCommerce Workshop Challenge 2021。 例如,我们了解到使用掩码语言建模方法(如 BERT 提出的自编码)训练的 XLNet Transformer 架构在各项竞赛和研究数据集中表现出色,并且将是序列推荐问题的首选。

此处引用的最佳实践将帮助您使用 NVIDIA NVTabular、NVIDIA HugeCTR、PyTorch 和 TensorFlow 等框架构建深度学习推荐器。

5.1. NVIDIA NVTabular

NVIDIA NVTabular 是一个用于表格数据的功能工程和预处理库。 它旨在快速轻松地处理 TB 级数据集,以便可以训练基于深度学习的推荐系统。

5.1.1. 数据加载

NVIDIA NVTabular 为 TensorFlow 和 PyTorch 中的推荐系统训练提供高度优化的数据加载器,这些加载器直接将数据读取到 GPU 中。

5.1.2. 使用 NVIDIA NVTabular 进行高效数据加载

NVIDIA NVTabular 数据加载器旨在有效地将表格数据馈送到使用 PyTorch 或 TensorFlow 的深度学习模型训练中。 在我们的实验中,我们能够使用我们高度优化的数据加载器将现有的 TensorFlow 管道加速九倍,并将现有的 PyTorch 管道加速五倍。 有关更多信息,请参阅 使用 TensorFlow 加速训练使用 PyTorch 加速训练

5.1.3. 首选存储格式

使用 NVIDIA NVTabular 时,Parquet 是首选存储格式。 它是一种压缩表格数据格式,被广泛使用,并且可以被 Pandas 和 CuDF 等库读取,以使用高级抽象快速搜索、过滤和操作数据。 NVIDIA NVTabular 可以非常快速地读取 parquet 文件。

5.2. NVIDIA HugeCTR

NVIDIA HugeCTR 是一个高效的 GPU 框架,专为点击率 (CTR) 估计训练而设计。 它提供分布式训练,具有模型并行嵌入表、嵌入缓存以及跨多个 GPU 和节点的数据并行神经网络,以实现最佳性能。

5.2.1. 大型嵌入表

通过设计,NVIDIA HugeCTR 有效地跨多个 GPU 和节点分发嵌入以进行训练。 对于多节点训练,支持 GPU-RDMA 的 InfiniBand 将最大限度地提高节点间事务的性能。 例如,如果您在一个服务器节点中有一个 1TB 的嵌入表和 16 个 NVIDIA V100 32 GB GPU,则可以使用两个服务器节点来容纳该表。

NVIDIA HugeCTR 还将其功能扩展到其他框架(如 TensorFlow),并提供其 Sparse Operation Kit,为模型并行训练提供高效的功能,以充分利用单节点或多节点系统中的所有可用 GPU。 它还与数据并行训练兼容,以实现“混合并行”,其中内存密集型嵌入参数可以分布在所有可用的 GPU 中,而 GPU 资源密集度较低的 MLP 层可以保持数据并行。 有关更多信息,请参阅我们的 Sparse Operation Kit 文档

借助其嵌入训练缓存 (ETC) 功能,NVIDIA HugeCTR 可以训练超出可用累积 GPU 内存的大型模型。 它通过在训练阶段将嵌入表的子集动态加载到 GPU 内存中来实现这一点,从而可以训练 TB 级大小的模型。 它支持单节点/多 GPU 和多节点/多 GPU 配置。

5.2.2. 嵌入向量大小

嵌入向量大小与 NVIDIA HugeCTR 内核启动的 Cooperative Thread Array (CTA) 的大小有关。 它不应超过每个块的最大线程数(NVIDIA A100 GPU 为 1024 个)。 建议将嵌入向量大小配置为 warp 大小的倍数(NVIDIA A100 GPU 的一个 warp 中有 32 个线程),以提高占用率。

5.2.3. 嵌入性能

NVIDIA HugeCTR 嵌入支持模型并行性,其中庞大的嵌入表跨越多个 GPU。 这意味着嵌入层和带有 MLP 的密集层之间存在 GPU 间通信。 为了获得最佳性能,我们建议使用配备 NVSwitch 的机器(例如 DGX A100),尽管 NVIDIA HugeCTR 也适用于使用 NVIDIA Collective Communications Library (NCCL) 而不使用 NVSwitch 的机器。

5.2.4. 数据读取器

NVIDIA HugeCTR 数据读取器本质上是异步和多线程的。 用户可以指定用于读取数据集的工作线程数。 为了实现最佳 GPU 利用率和负载平衡,建议工作人员的数量是 GPU 数量的倍数。 例如,如果可用 GPU 的数量为 8,则建议工作人员的数量为 8 或 16。

5.3. PyTorch

PyTorch 包含多项功能,可以帮助加速在 NVIDIA GPU 上训练基于深度学习的推荐模型,例如 自动混合精度CUDA Graphs

5.3.1. 使用 CUDA Graphs

为了减少由于多次内核启动而产生的开销,可以使用 CUDA graphs 将一系列 CUDA 内核聚集到一个单元中。 CUDA graphs 在 CUDA 10 中引入,并在 PyTorch v1.10 中 原生 提供,作为一组 Beta API。 有关 CUDA graphs 的更多信息,请参阅 使用 CUDA Graphs 加速 PyTorch 文章,其中介绍了各种模型的 API 示例 和基准测试。

图 8 说明了使用 CUDA graphs 的好处,其中 CUDA graph 代替 CPU 启动的一系列短内核。 最初,创建和一次启动整个 graph 会花费更多时间,但由于内核之间的间隔最小,因此总体时间得以节省。

图 8. 通过使用 CUDA graphs 减少内核启动开销来节省时间

reduce-kernel.jpg

在 PyTorch 中,扩展 GPU 训练的最有效方法之一是 torch.nn.parallel.DistributedDataParallel 与 NCCL 后端结合使用。 它适用于单节点和多节点分布式训练。 前面提到的 CUDA graph 的好处也 扩展 到具有 NCCL 内核启动的分布式多 GPU 工作负载。 此外,在内核启动时序因各种 CPU 负载和操作系统因素而不可预测的情况下,CUDA graphs 可建立性能一致性。

NVIDIA 的 MLPerf v1.0 训练结果证明了其性能优势,其中 CUDA graphs 在扩展到 4000 多个 GPU 时发挥了重要作用,并在各个方面都创下了新纪录。 有关更多信息,请参阅 全球计算机制造商使用 NVIDIA AI 提供突破性的 MLPerf 结果 博客文章。

NVIDIA 的 Deep Learning Recommendation Model (DLRM) 模型的实现 的基准测试结果(请参阅 图 9)显示,训练和推理的速度都显着加快。 当 CPU 开销更明显的小批量大小时,效果更加明显。

图 9. 通过使用 CUDA graphs 获得的训练和推理性能优势

train-inference.jpg

如果您正在使用 CUDA 编程或对底层原理感到好奇,那么编程指南的 CUDA Graphs 部分CUDA Graphs 入门文章 是很好的资源。

5.4. TensorFlow

TensorFlow 提供了多个资源,您可以利用这些资源来优化 GPU 的性能。 本节包含用于最大限度提高 NVIDIA GPU 上深度学习推荐器性能的其他技术。 有关如何在 GPU 上分析和提高性能的更多信息,请参阅 TensorFlow 的 GPU 性能分析和优化指南

5.4.1. I/O 管道

TFRecord 是一种用于存储二进制记录序列的格式,TensorFlow 首选这种格式,并且可以使用 TensorFlow 的原生数据读取器快速读取。

与 MLP GEMM 计算相比,深度学习推荐器训练经常受到数据加载速度的限制,相比之下,MLP GEMM 计算往往花费的时间较少。

TFRecords 为数据中的每个示例存储字段名称及其值。 对于表格数据,其中小的浮点或整数特征的内存占用空间小于字符串字段名称,这种表示形式的内存占用空间可能会非常快地变得非常大。

5.4.2. 短字段名称

考虑到 TFRecords 中字符串字段名称的内存占用空间,一个小的优化可能是将字段名称保持非常短,保持唯一特征名称的最小字符限制,以帮助改进优化。 这取决于具体情况。 但是,如果数据管道受到磁盘读取速度的限制,并且数据集具有许多小特征,则仅此一项就可能提高速度。

5.4.3. 预批处理 TFRecords

加快数据加载速度的一种方法是“预批处理”您的数据。 这意味着在每个条目(键、值对)中,我们存储值的序列化列表,而不是减少由于冗余字符串字段名称而产生的开销。 因此,每个条目本质上是在数据准备时创建一个批次,我们将此称为“预批处理”。 一个条目中存储的值的数量是“预批处理大小”。

图 10. TFRecord 预批处理

prebatching.jpg

如图 图 10 所示,让我们以具有 N 个条目的 TFRecord 为例。 我们不是单独存储每个值,而是为每个特征序列化 M 个这样的值,并存储每个条目的列表。 通过这样做,我们存储 N/M 个条目,并减少了由于字符串字段名称而产生的开销。

我们观察到在数据加载时间和整体上速度显着加快,这通常是 GPU 上训练推荐模型的瓶颈。

但这并非没有限制,并且可能会导致某些灵活性丧失。 您可能需要在数据工程管道中添加一个组件来创建此预批处理,并在您的 tf.data 管道中添加一个组件来解析它。 此外,这样做可能会限制打乱数据的能力,并对可以训练的最小批次大小施加预批处理大小的限制。 这些限制可能重要也可能不重要,具体取决于用例。

5.4.4. 对相似数据类型进行分组

与预批处理类似,另一种选择是将数据类型的键值对分组在一起。

例如,假设您的数据有三个分类特征。 我们可以将其存储为 {cat: [[0,5,4]]},而不是使用 {cat1: [[0]], cat2: [[5]], cat3: [[4]]}。 这同样适用于数值。 通过这样做,我们减少了将键存储为两个字符串(一个用于数值,一个用于分类)的开销。 但是,这可能会增加跟踪哪个类别在哪个索引上的开销,并且会使处理 multi-hots 更加困难。

有关构建用于 GPU 训练的高性能数据输入管道的更多信息,请参阅 Tensorflow Performance Guide for tf.data API

5.4.5. 使用 XLA 编译器

XLA 或 Accelerated Linear Algebra 是 TensorFlow 的优化编译器,它支持优化 GPU 代码。 TensorFlow 提供了 文档 以开始使用 XLA。

NVIDIA 的 DLRM 模型实现 也支持 XLA JIT 编译。 根据硬件平台、精度和 GPU 数量,它可以稳定地提高 10% 到 30% 的性能。

5.4.6. 优化的嵌入层

TensorFlow 原生嵌入层(例如 tf.nn.embedding_lookuptf.nn.embedding_lookup_sparse)不支持开箱即用的模型并行性,例如跨多个 GPU 或节点的分布式嵌入。 这限制了嵌入表的大小,并施加了表必须适合单个 GPU 内存的限制。

为了解决这个问题,NVIDIA HugeCTR SOK 为 TensorFlow 2.x 和 TensorFlow 1.15 提供了优化的嵌入层实现。 SOK TensorFlow 嵌入插件旨在方便且无缝地与 TensorFlow 一起使用,作为 TensorFlow 原生嵌入层的直接替代品。 它还提供开箱即用的高级功能,例如模型并行性,可以将嵌入表分布在多个 GPU 上。 有关更多信息,请参阅我们的 博客 和 SOK 文档

声明

本文档仅供参考,不得视为对产品的特定功能、条件或质量的保证。 NVIDIA Corporation(“NVIDIA”)对本文档中包含的信息的准确性或完整性不作任何明示或暗示的陈述或保证,并且对本文档中包含的任何错误不承担任何责任。 NVIDIA 对因使用此类信息或因使用此类信息而可能导致的专利或第三方其他权利的任何侵权行为的后果或使用概不负责。 本文档不构成开发、发布或交付任何材料(如下定义)、代码或功能的承诺。

NVIDIA 保留随时对此文档进行更正、修改、增强、改进和任何其他更改的权利,恕不另行通知。

客户在下订单前应获取最新的相关信息,并应核实此类信息是否为最新且完整。

NVIDIA 产品根据订单确认时提供的 NVIDIA 标准销售条款和条件进行销售,除非 NVIDIA 和客户的授权代表签署的单独销售协议(“销售条款”)另有约定。 NVIDIA 在此明确反对将任何客户通用条款和条件应用于购买本文档中引用的 NVIDIA 产品。 本文档不直接或间接地形成任何合同义务。

NVIDIA 产品并非设计、授权或保证适用于医疗、军事、航空、航天或生命支持设备,也不适用于 NVIDIA 产品的故障或故障可能合理预期会导致人身伤害、死亡或财产或环境损害的应用。 NVIDIA 对在此类设备或应用中包含和/或使用 NVIDIA 产品不承担任何责任,因此此类包含和/或使用由客户自行承担风险。

NVIDIA 不保证基于本文档的产品适用于任何特定用途。 NVIDIA 不一定对每种产品的所有参数进行测试。 客户全权负责评估和确定本文档中包含的任何信息的适用性,确保产品适合并满足客户计划的应用,并为应用执行必要的测试,以避免应用或产品的默认设置。 客户产品设计的缺陷可能会影响 NVIDIA 产品的质量和可靠性,并可能导致超出本文档中包含的附加或不同条件和/或要求。 NVIDIA 对可能基于或归因于以下原因的任何默认设置、损坏、成本或问题不承担任何责任:(i) 以任何违反本文档的方式使用 NVIDIA 产品或 (ii) 客户产品设计。

本文档未授予任何 NVIDIA 专利权、版权或其他 NVIDIA 知识产权下的明示或暗示许可。 NVIDIA 发布的有关第三方产品或服务的信息不构成 NVIDIA 授予使用此类产品或服务的许可,也不构成对产品或服务的保证或认可。 使用此类信息可能需要获得第三方在其专利或其他知识产权下的许可,或获得 NVIDIA 在其专利或其他知识产权下的许可。

只有在事先获得 NVIDIA 书面批准的情况下,才允许复制本文档中的信息,复制时不得进行修改,并且必须完全符合所有适用的出口法律法规,并附带所有相关的条件、限制和声明。

本文档和所有 NVIDIA 设计规范、参考板、文件、图纸、诊断程序、列表和其他文档(统称为“材料”,单独而言亦如此)均“按原样”提供。 NVIDIA 对材料不作任何明示、暗示、法定或其他形式的保证,并且明确否认所有关于非侵权性、适销性和特定用途适用性的暗示保证。 在法律未禁止的范围内,在任何情况下,NVIDIA 均不对因使用本文档而引起的任何损害(包括但不限于任何直接、间接、特殊、附带、惩罚性或后果性损害,无论因何种原因造成,也无论责任理论如何)承担责任,即使 NVIDIA 已被告知可能发生此类损害。 尽管客户可能因任何原因而遭受任何损害,但 NVIDIA 对此处所述产品的针对客户的累计责任应根据产品的销售条款进行限制。

Google

Android、Android TV、Google Play 和 Google Play 徽标是 Google, Inc. 的商标。

商标

NVIDIA、NVIDIA 徽标、CUDA、Merlin、RAPIDS、Triton Inference Server、Turing 和 Volta 是 NVIDIA Corporation 在美国和其他国家/地区的商标和/或注册商标。 其他公司和产品名称可能是与其相关的各自公司的商标。

© 2022-2023 NVIDIA Corporation 及关联公司。 保留所有权利。 上次更新时间:2023 年 2 月 1 日。