9

一块RTX3050搞定DLRM训练!仅需1%Embedding参数,硬件成本降低至百分之一 | 开源

 1 year ago
source link: https://www.qbitai.com/2022/10/38748.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一块RTX3050搞定DLRM训练!仅需1%Embedding参数,硬件成本降低至百分之一 | 开源

head.jpg明敏 2022-10-19 16:30:06 来源:量子位

Colossal-AI又上新

深度推荐模型(DLRMs)已经成为深度学习在互联网公司应用的最重要技术场景,如视频推荐、购物搜索、广告推送等流量变现业务,极大改善了用户体验和业务商业价值。

但海量的用户和业务数据,频繁地迭代更新需求,以及高昂的训练成本,都对DLRM训练提出了严峻挑战。

在DLRM中,需要先在嵌入表(EmbeddingBags)中进行查表(lookup),再完成下游计算。

嵌入表常常贡献DLRM中99%以上的内存需求,却只贡献1%的计算量。

借助于GPU片上高速内存(High Bandwidth Memory)和强大算力的帮助,GPU成为DLRM训练的主流硬件。

但是,随着推荐系统研究的深入,日益增长的嵌入表大小和有限的GPU显存形成显著矛盾。如何让利用GPU高效训练超大DLRM模型,同时突破GPU内存墙的限制,已成为DLRM领域亟待解决的关键问题。

c00589bf4e704fd3a30d067b9dbd7425~noop.image?_iz=58558&from=article.pc_detail&x-expires=1666772766&x-signature=EY%2BV%2Bo2NgucoaRVVl8v%2BMjLS0l8%3D

Colossal-AI此前已成功利用异构策略将相同硬件上训练NLP模型的参数容量提升上百倍,近期成功将其拓展到推荐系统中,通过软件缓存(Cache)方法在CPU 和 GPU 内存中动态存储嵌入表。

基于软件Cache设计,Colossal-AI还添加流水预取,通过观察未来即将输入的训练数据,降低软件Cache检索和数据移动开销。

同时,它以同步更新方式在 GPU 上训练整个 DLRM模型,结合广泛使用的混合并行训练方法,可以扩展到多个 GPU。

实验表明,Colossal-AI仅需在 GPU 中保留 1% 的嵌入参数,仍能保持优秀的端到端训练速度。

相比PyTorch其他方案,显存需求降低一个数量级,单块显卡即可训练TB级推荐模型。

成本优势显著,例如仅需5GB显存即可训练占据91GB空间 Embedding Bag的DLRM,训练硬件成本从两张约20万元的A100,降低至百分之一仅需2000元左右的RTX 3050等入门级显卡。

开源地址:
https://github.com/hpcaitech/ColossalAI

现有的嵌入表扩展技术

嵌入表将离散的整型特征映射成连续的浮点特征向量,下图展示了DLRM中的嵌入表训练过程。

首先,在嵌入表中对每个特征查找Embedding Table对应的行,然后通过规约操作,比如max,mean, sum操作,变成一个特征向量,传递给后续的稠密神经网络。

可见,DLRM的嵌入表训练过程主要是不规则的内存访问操作,因此严重受限于硬件访存速度。

58a9e5a4ed33449dadef5785796cc993~noop.image?_iz=58558&from=article.pc_detail&x-expires=1666772766&x-signature=bcgUUEYgNXHQRIY4qNV4Zy1r478%3D

而工业级DLRM的嵌入表可能达到数百GB甚至TB级别,远超单GPU最高数十GB的显存容量。

突破单GPU的内存墙来增大DLRM的嵌入表规模有很多方法。

根据下图展示的GPU集群的内存层级图为例,让我们来分析几种常见方案的优劣。

GPU模型并行:

将嵌入表切分后分布在多个GPU的内存中,训练中通过GPU之间互联网络同步中间结果。

这种方式的缺点首先是嵌入表切分负载并不均匀,扩展性问题难以解决。

其次,增加GPU的前期硬件成本大,而且DLRM训练时GPU的计算能力并没有被充分利用,而是仅仅利用了它的HBM带宽优势,导致GPU使用率不高。

CPU部分训练:

将嵌入表分割成两部分,一部分在GPU上训练,另一部分在CPU上训练。

通过利用数据分布的长尾效应,我们可以让CPU计算比例尽可能少,让GPU计算比例尽可能大。但是,随着batch size增大,让mini-batch的数据全部命中CPU或者GPU很困难,如果同时命中CPU或GPU这种方法很难处理。

另外,由于DDR带宽和HBM相差一个数据量级,即使10%的输入数据在CPU上训练,整个系统也会有至少一半速度下降。

此外,CPU和GPU需要传输中间结果,这也有不小的通信开销,进一步拖慢训练速度。

因此,研究人员设计了异步更新等方式来避免这些性能缺陷,但是异步方式会造成训练结果的不确定性,在实践中并不是算法工程师的首选方案。

软件Cache:

保证训练全部在GPU上进行,嵌入表存在CPU和GPU组成的异构空间中,每次通过软件Cache方式,将需要的部分换入GPU。

这种方式可以廉价扩展存储资源,满足嵌入表不断增大的需求。

而且,相比使用CPU来计算,这种方式的整个训练过程完全在GPU上完成,充分利用HBM带宽优势。但Cache的查询、数据移动会带来额外性能损耗。

目前已经有一些针对嵌入表优秀的软件Cache方案实现,但是它们往往使用定制的EmbeddingBags Kernel实现,比如fbgemm,或者借助第三方深度学习框架。

而Colossal-AI在原生PyTorch基础上不做任何Kernel层次改动,提供了一套开箱用的软件Cache EmbeddingBags实现,还进一步针对DLRM训练流程进行优化,提出预取流水来进一步降低Cache开销。

c2779bab7e9d4f2eaf79e5950c7af47b~noop.image?_iz=58558&from=article.pc_detail&x-expires=1666772766&x-signature=311ZlInP4sBs3gYX2XGfG8SViKM%3D

△Memory Hierarchy

Colossal-AI的嵌入表软件Cache

Colossal-AI实现了一个软件Cache并封装成nn.Module提供给用户在自己模型中使用。

DLRM的嵌入表,一般是由多个Embedding组成的EmbeddingBags,驻留在 CPU 内存中。

这部分内存空间被命名为CPU Weight。而EmbeddingBags一小部分数据存储在 GPU内存中,它包括即将被训练用到的数据。

这部分内存空间被命名为CUDA Cached Weight。

在 DLRM 训练期间,首先需要确定本次迭代输入mini-batch的数据所对应嵌入表的行,如果有的行不在GPU中,需要将它们从CPU Weight传输到 CUDA Cached Weight中。

如果GPU中没有足够的空间,它会使用LFU算法,根据访问缓存的历史频率来淘汰被使用最少数据。

为了实现Cache的检索,需要一些辅助数据结构帮忙:cached_idx_map是一维数组,存储CPU Weight中行号和CUDA Cached Weight的行号对应关系,以及对应行在GPU被访问的频率信息。

CUDA Cached Weight 大小与 CPU Weight 大小的比值命名为 cache_ratio,默认为1.0%

Cache在每个迭代forward之前运行,以调整CUDA Weight中的数据,具体来说分三个步骤。

Step1:CPU索引

检索CPU Weight中需要被Cache的行号。

它需要对输入mini-batch的input_ids和cached_idx_map取交集,找到CPU Weight中需要从CPU移动到GPU的行号。

Step2:GPU索引

根据使用频率找到CUDA Weight中可以被驱逐的行。

这需要我们根据频率以从低到高顺序,对cache_idx_map和input_ids取差集合之后的部分进行top-k(取最大值k个数)操作。

Step3:数据搬运:

将CUDA Cached Weight中的对应行移动到CPU Weight中,然后将CPU Weight中的对应行移动到CUDA Weight中。

数据传输模块负责CUDA Cached Weight和CPU Weight之间的数据双向传输。

不同于低效的逐行传输,它采用先缓存再集中传输方式来提升PCI-e的带宽利用率。

分散在内存中的嵌入行在源设备的本地内存中集中为连续的数据块,然后块在 CPU 和 GPU 之间传输,并分散到目标内存的相应位置。以块为单位移动数据可以提高 PCI-e 带宽利用率,merge和scatter操作只涉及CPU和GPU的片上内存访问,因此开销并不是很大。

Colossal-AI用一个尺寸受限的缓冲区来传输CPU和GPU之间数据。

在最坏的情况下,所有输入 id 都未命中缓存cache,那就需要需要传输大量元素。为了防止缓冲区占用过多内存,缓冲区大小被严格限制。如果传输的数据大于缓冲区,会分为多次完成传输。

d4e27a06d4c84b4781914b4dd4083dee~noop.image?_iz=58558&from=article.pc_detail&x-expires=1666772766&x-signature=%2BScXuBqOORWLwl0yFy8tRyraqWE%3D

△Cached EmbeddingBag Workflow

软件Cache性能分析

上述Cache Step1和Step2的操作都是访存密集的。

因此为了能利用GPU的HBM的带宽,它们是在GPU上运行的,并使用深度学习框架封装好的API来实现。尽管如此,与嵌入表在GPU上的训练操作相比,Cache操作的开销尤为突出。

比如在一次总计199秒训练任务中,Cache操作的开销为99秒,占比总计算时间接近50%

经过分析,Cache的主要开销主要是Step1和Step2引起。下图base位置展示了此时的Cache开销时间分解,Cache的step1,2 红色和橙色两阶段占Cache总开销的70%。

49829277a22f451395f16ca7b515f008~noop.image?_iz=58558&from=article.pc_detail&x-expires=1666772766&x-signature=j4LYRNNEU1BL5W4btjEy%2BNFk2uI%3D

△Cache操作的时间分解

而上述问题的原因,是因为传统的Cache策略有些“短视”,只能根据当前mini-batch情况调整Cache,因此大部分时间浪费在查询操作上。

Cache流水预取

为了缩减Cache的开销,Colossal-AI设计了一套“高瞻远瞩”的Cache机制。与其只对前mini-batch进行Cache操作,Colossal-AI预取后续将会被使用的若干mini-batch,统一进行Cache查询操作。

如下图所示,Colossal-AI使用预取来合并多个mini-batch数据统一进行Cache操作,同时采用流水线方式来重叠数据读取和计算的开销。

例子中预取mini-batch数量是2。在开始训练前,先从磁盘读取mini-batch 0,1数据到GPU内存,随后开始Cache操作,然后执行这两个mini-batch的正、反向传播和参数更新。

与此同时,可以和对mini-batch 2,3的开始数据读取,这部分开销可以和计算重叠。

44f0780c858f43c5af9afcb05226dad5~noop.image?_iz=58558&from=article.pc_detail&x-expires=1666772766&x-signature=%2FegRL0fm%2FsTKbEPemL1RpbIQ7rM%3D

和baseline Cache执行方式相比,图【Cache操作的时间分解】对比了prefetch 8个mini-batch和baseline的Cache时间分解。

训练总时间从201秒下降到120秒,图中所示的Cache阶段操作时间占比也显著下降。可以看到和每个mini-batch独立进行Cache操作相比,各部分时间都减少了,尤其是Cache的前两步操作。

总结起来,Cache流水预取带来两个好处。

1、摊薄Cache索引开销

预取最显而易见的好处是减少了Step1和Step2的开销,使这个两步操作在总的训练过程占比小于5%。如【Cache操作的时间分解】所示,通过预取8个mini-batch数据,和没有预取的baseline相比,Cache查询的开销显著降低。

2、增加CPU-GPU数据移动带宽

通过集中更多数据,提升数据传输粒度,从而充分利用CPU-GPU传输带宽。对于上面例子,CUDA->CPU带宽从860MB/s提升到1477 MB/s,CPU->CUDA带宽从1257 MB/s提升到 2415 MB/s,几乎带来了近一倍的性能增益。

和Pytorch EmbeddingBag用法一致,在构建推荐模型时,仅需如下数行代码进行初始化,即可大幅提升嵌入表容纳量,低成本实现TB级超大推荐模型训练。

from colossalai.nn.parallel.layers.cache_embedding import CachedEmbeddingBag
emb_module = CachedEmbeddingBag(
num_embeddings=num_embeddings,
embedding_dim=embedding_dim,
mode=”sum”
include_last_offset=True,
sparse=True,
_weight=torch.randn(num_embeddings, embedding_dim),
warmup_ratio=0.7,
cache_ratio = 0.01,
)

NVIDIA A100 GPU (80GB)和AMD EPYC 7543 32-Core Processor (512GB)硬件平台上,Colossal-AI以Meta的DLRM模型作为测试目标,用超大数据集Cretio 1TB和Meta的dlrm_datasets生成数据集作为测试模型。

实验中采用将嵌入表全部存储GPU上的PyTorch训练速度作为baseline。

Cretio 1TB

Cretio 1TB嵌入表总共177944275行,设置embedding dim=128,其嵌入表内存需求91.10 GB

想把EmbeddingBags全部存储在单个GPU内存中,即使是最高端的英伟达A100 80GB也无法满足其内存需求。

但使用Colossal-AI仍然在单GPU上完成训练,当cache ratio=0.05,显存消耗仅为5.01 GB,直接降低约18倍,可进一步扩展到在单张GPU上实现TB级推荐系统模型的训练。

在训练速度上,如下图所示,展示了不同batch size下训练100M个样本的延迟。

绿色Prefetch1是不使用预取,蓝色Prefetch8是使用预取(prefetch mini-batch=8)的延迟,可见预取流水优化对整体性能提升发挥了重要作用。

图中每个柱子深色部分为Cache开销,使用预取后,Cache开销控制在训练总时间的15%范围内。

d3deda47e7ab44e4a21127e0a6383fdf~noop.image?_iz=58558&from=article.pc_detail&x-expires=1666772766&x-signature=McCAWBKPQCzOlApW4V6J5aU20Lg%3D

多GPU扩展性

用8192作为全局batch size,在8张GPU卡上使用table-wise sharding作为EmbeddingBags并行方式训练DLRM,训练100M samples。

此时设置Prefetch大小为4,ColossalAI-mem-cr0.05是cache ratio=0.05,ColossalAI-mem-cr0.5=0.5。

下图展示了不同GPU情况下的训练延迟。除了1 GPU时PyTorch OOM无法训练之外,其余情况PyTorch和Colossal-AI训练时间类似。

可以观察到使用4和8 GPU并没有带来明显性能提升,这是因为:

  1. 同步结果需要通信开销巨大。
  2. table-wise sharding会导致切分负载不均衡。也说明使用多GPU来扩展embedding table训练扩展性并不是很好。
3ca1c02ec34544a7a19e6be56c8f2ed7~noop.image?_iz=58558&from=article.pc_detail&x-expires=1666772766&x-signature=mjtNt%2Fw0gCpvCH6tnn890syuS8g%3D

下图展示了显存使用,显存使用在不同卡上并不相同,这里展示最大显存数值。

在仅使用一张GPU时,只有Colossal-AI的软件Cache方法可以训练,多卡并行的占用内存也显著减少数倍。

01d2befde51f403e8e811eeca2883a62~noop.image?_iz=58558&from=article.pc_detail&x-expires=1666772766&x-signature=ujQmlb9%2FbmjdRMCm6pNqaz5ZToY%3D

Meta Research的合成数据集dlrm_datasets模仿了工业界嵌入表的训练访问行为,因此常在研究中作为推荐系统相关的软硬件设计的测试参考。

选取其中的5亿行嵌入表项的作为子数据集,构造256GB和128GB大小的两个EmbeddingBags用于测试。

8074b922e41b4bd6873cc6b0a1cdf251~noop.image?_iz=58558&from=article.pc_detail&x-expires=1666772766&x-signature=IE83UczeEa2RZwN1echloTO9DrA%3D

PyTorch由于显存内存不足无法在单卡A100上训练。作为对比, Colossal-AI的软件cache将显著降低GPU内存需求,足以训练大至256GB的嵌入表,并可进一步扩展至TB级别。

而且,流水预取也能体现出加速效果,当预取数为32时,相比没有预取总时间下降60%,而且对GPU的存储的需求却没有增大。

One More Thing

面向大模型时代的通用深度学习系统 Colossal-AI,通过多项自研领先技术如高效多维自动并行、异构内存管理、大规模优化库、自适应任务调度等实现高效快速部署AI大模型训练和推理,降低AI大模型应用成本。

Colossal-AI相关解决方案已成功在自动驾驶、云计算、零售、医药、芯片等行业知名厂商落地应用,广受好评。

Colossal-AI注重开源社区建设,提供中文教程,开放用户社群及论坛,对于用户反馈进行高效交流与迭代更新,不断添加PaLM、AlphaFold、OPT等前沿应用。

自然开源以来,Colossal-AI已经多次在GitHub及Papers With Code热榜位列世界第一,与众多已有数万star的明星开源项目一起受到海内外关注!

项目开源地址:
https://github.com/hpcaitech/ColossalAI

参考链接:
https://ai.facebook.com/blog/dlrm-an-advanced-open-source-deep-learning-recommendation-model/

本文参考自:
https://medium.com/@yangyou_berkeley/embedding-training-with-1-gpu-memory-and-10-times-less-budget-an-open-source-solution-for-6b4c3aba07a8

观点为作者所有。

版权所有,未经授权不得以任何形式转载及使用,违者必究。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK