随着深度学习的层数越来越多,模型的参数也呈现出了快速增长的趋势,然而GPU内存的增长速度却远慢于模型体积的增长。有限的GPU内存限制了我们训练和部署模型的灵活性,GPU内存墙成为了现在亟待解决的问题。先前已经有许多研究进行了探索,可以概括为两大类:一是基于多级存储构建透明的数据分页和迁移机制,利用page fault在多级存储中交换数据,并对上层应用透明;二是基于多级存储的卸载机制,将模型的参数或者优化器状态等卸载到CPU或者NVMe SSD中。下文中笔者对该领域的主要论文进行了简要的总结和介绍,如有错误之处,敬请指正。
DRAGON
2018.11 开源
背景
- 数据集大小越来越大,甚至超过主存的大小。
- NVM成为普遍组件。
- 使用NVM加速的应用必须手动编排多个存储器的数据移动,不适用于复杂程序。
解决的问题
- 传统方法将数据分成小块,在相应的内核之间执行双向传输,随适合流失传输,但需要大量特定于应用程序的编程工作。已有的基于硬件、操作系统、应用的方法利用主机DRAM处理GPU大数据,然而需要硬件修改、开销较大或者限定与特定类别的应用程序
- UM提供了一种从GPU内核访问主机内存的原生解决方案。UM-P依赖于本地设备发起的页面错误和驱动程序管理的交换机制,为CPU和GPU的访问提供统一的虚拟内存地址范围。尽管UM-P可能提供比其前身更快的性能,但UM-P可以分配的虚拟内存量仍然受到可用物理主机内存的限制。
使用的方法
- 通过扩展CUDA统一内存的功能,利用了NVIDIA GPU上的页面错误机制,并通过自动IO和数据传输重叠获得额外加速。为只读只写和临时数据提供了优化的访问模式类型。
- 通过修改uvm开源驱动模块
- 简单的缓存机制
相关技术
直接和透明寻址:为了在不增加内核复杂性的情况下集成NVM,GPU应该能够直接寻址NVM提供的非常大的空间,而不会或不会对性能产生明显的影响。Tseng等人和Zhang等人提出利用自定义NVMe驱动程序,使用NVIDIA的GPUDirect RDMA在GPU内存和NVM之间直接传输数据。虽然这些研究为GPU的直接NVM访问提供了有效的手段,但GPUDirect RDMA在技术上将可寻址空间限制在GPU的全局内存大小。
超越系统内存容量限制:ActivePointers是唯一一项考虑通过将GPU可寻址内存映射到文件系统来扩展其范围的研究。ActivePointers基于GPUfs,并依赖于内核内软件地址转换(即基于软件的页面错误)。它要求修改现有的CUDA内核以使用自定义指针和API。内存引用通过运算符重载实时捕获,每次访问都会执行页面错误处理内核代码。除了修改现有GPU内核的巨大成本外,这种方法还带来了巨大的开销;因此,它的效率相对较低,因为它没有利用GPU中新的硬件分页支持。
Capuchin
ASPLOS’20 2020.03 闭源
背景
- 深度学习模型越来越大,GPU内存十分宝贵,限制了DNN架构探索的灵活性。
- DNN训练中的内存占用是中间层输出,在前向传播中产生并在反向传播中再次使用,而两次使用存在很大的差距,导致存储中间结果的高内存消耗。
- 现有两种技术是交换和重新计算
解决的问题
- 现有方案基于计算图和不同层执行内存管理,但是一层模型具有非常多的节点,粗粒度的管理限制了优化空间。
- 静态分析的问题:
- 硬件和输入大小的异构性使得预测计算时间变得困难
- 基于粗粒度“定性”信息的决策无法量化特定内存操作的开销,因此很难对内存优化候选者进行优先级排序,也很难在交换和重新计算之间做出选择
- 对新模型,先验知识不可用
- 这种方式不适合在执行前没有计算图的深度学习框架,如PyTorch
使用的方法
- 提出了一种基于张量的GPU内存管理模块,通过张量的驱逐、预取、重新计算来减少内存占用。
- 根据运行时跟踪的动态张量访问模式做出内存管理决策。
- 观察到训练期间对张量的访问模式是有规律的。
- 基于TensorFlow实现
相关技术
- 深度学习框架的执行模式
- Eager mode
- Graph mode
FlashNeuron
2021 开源
背景
- GPU内存墙问题
- 增加批处理大小是提高硬件利用率的常用技术,但这可能带来次优的训练吞吐量
解决的问题
- 现有方案通过将一些中间数据卸载到主机内存来解决内存墙问题。由于GPU上的训练过程与CPU上运行的应用程序在内存带宽和容量方面存在竞争,因此它们无法提供强大的性能
- 最流行的方法是利用主机CPU内存作为后备存储器来卸载一些不立即使用的张量。然而,这种内存缓冲方法无法提供稳健的性能,因为GPU上的训练过程与CPU上运行的应用程序争夺内存带宽和容量。
- 此外,这些建议主要侧重于增加批量大小,但较少关注提高训练吞吐量。因此,它们通常会产生较低的训练吞吐量,因为CPUGPU数据传输的成本超过了更大批量的收益。
- 使用多个GPU可以解决内存墙的问题,但多个GPU通常会导致次优的成本效率。
使用的方法
- 使用NVMe SSD作为后备存储的DNN训练系统。为了充分利用有限的SSD写入带宽,FlashNeuron引入了一个卸载调度器,该调度器以压缩格式选择性地将一组中间数据卸载到SSD,而不会增加DNN评估时间。FlashNeuron对CPU进程的干扰最小,因为GPU和SSD直接通信进行数据传输。
- 引入一个卸载调度器来调度张量。在主机端,FlashNeuron由轻量级的用户级IO栈实现。
- GPU和SSD利用GPUDirect技术直接通信进行张量数据传输,因此CPU周期和内存使用的资源占用最小。
- 在PyTorch上实现。
相关技术
Sentinel
2021-02 闭源
背景
- 显存容量的限制
- 异构存储器为解决DNN训练的内存瓶颈提供了方向,但也对张量的迁移和分配提出了挑战
解决的问题
- 过去的工作严重依赖DNN领域知识,由于页级别的错误共享导致不必要的张量迁移,并浪费了快速内存空间
- 现有对DNN训练的HM,大多数专注于通过利用更大的CPU侧系统内存来缓存显存的限制。
- 使用HM的计算效率需要仔细的内存管理,现有的解决方案探索了主动释放和预取暂时不活动张量的方法,基于DNN拓扑确定不活动张量,并通过分析张量访问顺序或使用详细的领域知识来找到存储器之间的数据交换时间。
- 然而,还没有一项研究能够彻底评估个体张量特征以及深度学习框架中操作系统/架构和内存管理之间的语义差距。错过这项研究会留下许多绩效改进的机会。例如,大多数现有的解决方案都侧重于张量访问的顺序,以确定交换的时间和目标张量。然而,这些解决方案忽略了张量特征,如内存中的张量访问次数和张量寿命,这将导致不必要的张量迁移。例如,一些张量(如短期张量)最好留在快速内存中,而不是不必要地迁移到只使用几次或永远不再使用。
- 更重要的是,现有的大多数研究都是在单个张量的粒度上解决张量放置问题。然而,由于操作系统(OS)和底层架构的内存管理是在页面级别进行的,如果将具有不同访问模式的多个张量映射到同一页面,这种张量级别映射将导致内存碎片或意外的张量迁移。例如,如果有四个页面,其中每个页面的25%映射了在相似时间内频繁访问且具有相似生命周期的张量,则所有四个页面都需要放置在快速内存中,即使四个页面的其余部分填充了很少访问的张量,其生命周期与频繁访问的张量不同。然而,如果我们在这个例子中将所有频繁访问的张量放在一个页面上,那么将这个页面放在快速内存中就足以进行高性能训练。
使用的方法
- 提出了一个软件运行时系统,可以自动优化HM上的张量管理。Sentinel使用动态分析,并协调操作系统(OS)和运行时级分析,以弥合操作系统和应用程序之间的语义差距,从而实现张量级分析。这种分析允许将具有相似寿命和内存访问频率的张量共同分配到相同的页面中。这种细粒度分析和张量配置避免了不必要的数据移动,提高了张量移动效率,并由于节省了快速内存空间而实现了更大的批量训练。
- 对DNN负载进行分析,小张量和短寿命张量,访问频率。
- 通过避免页面级的错误共享来提高迁移效率。
- 采用主动迁移的策略,与现有研究不同的是,本研究考虑迁移频率和性能效益之间的性能权衡。
相关技术
ZeRO-Infinity
2021.11 开源
背景
- 大模型训练的内存墙问题
- 本文介绍了ZeRO Infinity,这是一种新型的异构系统技术,它利用GPU、CPU和NVMe内存,在有限的资源上实现了前所未有的模型规模,而不需要模型代码重构。同时,它实现了出色的训练吞吐量和可扩展性,不受CPU或NVMe带宽限制。
- 如何支持模型的快速增长。如何允许在较少的GPU上访问大模型。如何消除模型重构和多种形式的并行性,使大模型训练更容易。
解决的问题
使用的方法
- 无限卸载引擎,聚合GPU、CPU、NVM
- 以内存为中心的平铺,在不需要模型并行的情况下处理大量运算符
- 以宽带为中心的分区,在所有并行设备上聚合内存带宽
- 以重叠为中心的设计,用于重叠的通信和通信
相关技术
- ZeRO:通过在数据并行过程中划分三个模型状态(优化器状态、梯度和参数)而不是复制他们,消除了数据并行过程中的内存冗余。
GPM
2022.02 开源
背景
- GPU程序无法直接使用可字节寻址的非易失存储器
- PM通过快速字节粒度持久性和可恢复性来加速计算逐渐变成事实
解决的问题
使用的方法
- 允许从GPU内核直接访问PM,而无需修改硬件
- 演示了三类受益于PM的GPU加速应用程序,创建了一个工作负载套件
- 创建了一个CUDA编写的GPU库,以支持日志记录、检查点和原生持久性原语,以便程序员轻松利用PM
相关技术
- CAP的实现方式。完全依赖文件系统,称之为CAP-fs。在这里,在将结果DMA到DRAM后,CPU将结果写入PM驻留文件,然后使用fsync()保证持久性。或者,PMresident文件可以被内存映射到CPU的地址空间。结果可以使用cudaEmcopy从GPU的内存传输到内存映射文件。但是,cudaemcpy不会将数据直接移动到文件中。相反,它在内部使用DRAM上的固定存储器作为反弹缓冲区来复制数据,而不会出现页面错误。它会将数据从GPU复制到缓冲区,然后将其写入文件。最后,CPU线程发出缓存刷新和耗尽以保证持久性。这种方法限制了操作系统的开销,但仍然依赖于CPU的持久性。我们将其命名为CAP mm。请注意,CAP mm不能使用非临时存储,因为CPU没有生成要写入的数据。数据从GPU传输到LLC。
- CAP的限制。1无法直接访问PM驻留的数据结构并在计算结果时持久化(即内核内持久化),这使得程序员无法编写细粒度可恢复的GPU内核。2个GPU通过大规模并行加速应用程序。通过依赖CPU来持久化GPU计算的结果,并行性的许多好处都消失了。3缺乏内核内持久性可能会导致写入放大。有时,内核计算的数据中只有一部分会被更新,从而被持久化(例如,KVS的一部分)。GPU程序员无法以字节粒度有效地将结果传输并选择性地持久化到PM。
STRONGHOLD
2022.11 开源
背景
- DNN模型越来越大,需要高性能的GPU服务器,但成本高昂
- 通过量化和利用CPU内存来降低大模型的内存需求
解决的问题
- 现有的CPU内存方案都是为卷积神经网络设计的,其中训练期间的内存消耗主要由动态生成的激活而不是优化器,而最新的transformer,模型和优化器的状态而不是激活内存是内存瓶颈
- ZeRO设计,但是可训练模型大小收到GPU内存和CPU内存容量最小部分的限制
- L2L是专门为基于Transformer模型设计的,通过动态卸载模型参数,只在GPU内存中保留一个Transformer块。
- ZeRO Infinity采用动态策略来利用辅助存储,并在异构内存层次结构中划分模型参数和优化器状态。
- 上面的方法可以增加可训练模型的大小,但是会带来巨大的开销,导致1.76倍的速度减慢(使用NVMe时高达29.2倍)
使用的方法
- 在不改变用户代码的情况下实现大型DNN模型训练的方法
- 通过动态地将数据卸载到CPU RAM并启用辅助存储来扩展最大的可训练模型大小。会自动确定GPU内存中要保留的最小数据量,以最大限度地减少GPU内存的使用
- 在GPU中保留足够数量的层基于模型参数,以避免数据卸载期间GPU停止。与ZeRO将所有模型参数放在GPU内存中不同,本工作在GPU上维护一个动态窗口
- 该工作在多核CPU上运行多个并发优化器,来并行化模型参数更新过程。
- 对工作窗口的管理采用用户级GPU内存管理方案,以避免频繁调用昂贵的GPU内存操作
- 在pytorch中实现,在单GPU和分布式GPU环境中进行了评估
- 适用于微调大型预训练模型或使用预训练的DNN来指导使有限GPU资源的小型模型的训练
相关技术
- 与基于卸载的SOTA相比,可训练模型大小提高了1.9-5.6倍,训练吞吐量提高了1.2-3.7倍
DeepUM
2023.01 闭源
背景
- 大型DNN需要大量的GPU内存和计算能力
- 解决上面的问题有很多研究,数据压缩、混合精度算法、数据重新计算和内存交换,本文的工作专注于内存交换
- 以前的内存交换分为两种,一种使用CUDA统一内存和页面预取,另一种使用纯GPU内存,并结合纯换入换出的内存对象
解决的问题
- UM虽然允许页面错误机制进行内存的超额订阅,但页面迁移会带来巨大的开销。
- 由于地址转换和页面错误处理带来的巨大开销,很少有GPU内存交换研究基于UM。由于UM利用虚拟内存,需要对GPU中的每个内存请求进行地址转换,因此可能会对性能产生重大影响。此外,处理页面错误需要在CPU和GPU之间进行昂贵的I/O操作,以便在它们之间迁移页面。
- 尽管PyTorch和TensorFlow有自己的内存管理模块,但仍然存在一些内存碎片。而UM所有内存对象都以4KB页面为单位进行管理,受内存碎片影响较小。
使用的方法
- 利用CUDA统一内存来允许DNN的GPU内存超额订阅
- 本工作使用了一种新的相关性预取技术来隐藏页面迁移开销。它是全自动的,对用户透明。
- DeepUM可以使用从页面错误处理程序获得的错误地址轻松记录错误页面之间的关系。DeepUM利用了这样一个事实,即内核执行模式及其内存访问模式在DNN训练工作负载中大多是固定的和重复的。因此,通过相关性预取来记忆重复的模式并利用信息是可取的。DeepUM的关联表记录了DNN训练阶段内核执行及其页面访问的历史。它通过预测下一个内核将执行哪个内核,根据相关表中的信息预取页面。传统的相关性预取使用单个表来存储历史并记录CPU缓存行之间的关系,而DeepUM相关性预取则使用两种不同的表结构。
- 为了尽量减少故障处理时间,DeepUM为NVIDIA设备驱动程序中的GPU故障处理例程提出了两种优化技术。一种是基于相关表中的信息进行页面预驱逐。当GPU内存被超额订阅时,页面驱逐会增加页面错误处理时间,因为页面驱逐逻辑位于页面错误处理例程的关键路径上[32]。另一个优化是当页面驱逐受害者预计不再被PyTorch使用时,GPU内存中的页面无效。这种优化消除了CPU和GPU之间不必要的内存流量。
- 支持PyTorch,只需要进行少量的修改
相关技术
Elixir
2023.05 开源
背景
- 大模型的训练需要大量GPU
解决的问题
- 已有内存分区和内存卸载的方法,这些方法消除了内存冗余,并将显存使用分别转移到CPU内存和NVM,但直接部署这些方案往往会导致效率欠佳,只有经验丰富的专家才能通过仔细调整分布式配置来释放硬件的全部潜力
- 内存分区虽然解决了内存瓶颈问题问题,但它要求聚合GPU内存超过模型大小
- ZeRO Infinity有两个明显缺点:其要求用户配置多个阶段和参数,探索最优配置是个非常耗时的任务,DeepSpeed尽管提供了一个自动调优命令,但是只考虑了分区,而没有考虑卸载。第二,由于缺乏对训练过程的认识,ZeRO的效率并不理想。默认情况下,ZeRO-3对所有参数进行分区,从而在前向和后向传递期间收集参数时进行额外的通信。同样,其卸载选项将所有优化器状态卸载到CPU内存中,导致所有参数的CPU优化器更新缓慢。该工作认为,使用空闲的GPU内存来存储优化器状态或在训练过程中保留收集的参数可以提高训练吞吐量。
使用的方法
- 基于运行前模型分析自动进行高效的大型模型训练,旨在确定分区和卸载技术的最佳组合,以最大限度提高训练吞吐量
- Elixir是一种在小型GPU集群上自动进行大型模型训练的方法。主要目标是充分利用所有GPU内存,最大限度地提高训练吞吐量。为了实现这一点,开发了一个运行前分析器,可以在训练前准确测量内存使用情况。我们的分析器可以在10秒内在单个A100 GPU上分析175B OPT型号。为了方便起见,我们将参数压缩成与并行训练系统中的存储单元长度相同的连续块,称为块。我们引入rCache来实现对内存冗余程度的细粒度控制。因此,我们可以调整rCache大小或移动块以利用空闲的GPU内存。
相关技术
G10
2023.12 开源
背景
- 为了打破GPU内存墙以扩展深度学习工作负载
解决的问题
- 典型方法包括使用闪存和直接存储进行内存扩展,但这些技术一方面存在性能欠佳的问题,并且给GPU管理带来了复杂性,难以满足扩展性需求
- 现有的方案总是受到nvlink带宽、PCIe带宽、SSD带宽的限制
使用的方法
- 深度学习工作负载的张量行为具有高度可预测性,G10将主机内存、GPU内存和闪存集成到一个统一的内存空间中,并实现tensor的透明迁移。
- 利用编译器技术来表征深度学习工作负载中的张量行为,因此可以根据带宽提前安排tensor迁移。
- 基于开源模拟器实现