news 2026/10/26 21:11:47

ZeRO-Infinity: Breaking the GPU Memory Wallfor Extreme Scale Deep Learning 关键技术解读(持续刷新)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ZeRO-Infinity: Breaking the GPU Memory Wallfor Extreme Scale Deep Learning 关键技术解读(持续刷新)

关键技术一:Memory-centric tiling for working memory(用于工作内存的内存中心分块)

即使把模型状态(参数、梯度、优化器状态)都卸载到 CPU/NVMe,在 GPU 上执行前向/后向传播时,仍然需要把当前算子的参数和梯度加载到 GPU 内存中。如果单个算子太大,它的参数和梯度本身就可能超过 GPU 内存,导致无法训练。

传统做法是用模型并行(张量切片)把一个大算子拆到多个 GPU 上。但 ZeRO-Infinity 想避免模型并行,于是提出了“内存中心分块”。


核心思想

把一个大线性算子 Y=XWY=XW 拆成多个更小的线性算子,按顺序执行。具体来说,把权重矩阵 WW 沿输出维度切成 NN 块:

W=[W1,W2,…,WN]W=[W1​,W2​,…,WN​]

然后依次计算:

Y1=XW1,Y2=XW2,…,YN=XWNY1​=XW1​,Y2​=XW2​,…,YN​=XWN​

最后把 Y1,Y2,…,YNY1​,Y2​,…,YN​ 拼接起来得到完整输出 YY。

每次只把一块 WiWi​ 加载到 GPU 内存,计算完就释放,再加载下一块。这样 GPU 上同时只需要容纳一块参数及其梯度,而不是整个大矩阵。

结合 ZeRO-3 的参数分区机制,每个数据并行进程只拥有参数的一部分。内存中心分块可以配合 ZeRO-3 的“按需 allgather、用完即释放”模式:需要哪一块参数,就通过 allgather 收集哪一块,算完立即释放。


具体例子

假设一个 Transformer 的 FFN 层,隐藏维度 hd=64Khd=64K。第一个线性层把 64K64K 映射到 4hd=256K4hd=256K。

  • 权重矩阵大小:64K×256K=16G64K×256K=16G 个参数。

  • FP16 存储:16G×2=3216G×2=32 GB。

  • 梯度也是 FP16:再加 32 GB。

  • 总共需要64 GB的 GPU 内存来容纳这个线性层的参数和梯度。

而单块 NVIDIA V100 只有 32 GB 内存,根本放不下,更别说还要放激活和其他东西。

使用内存中心分块:

  1. 把输出维度 256K256K 切成 N=16N=16 块,每块大小 16K16K。

  2. 每块权重矩阵:64K×16K=1G64K×16K=1G 参数。

  3. FP16 下每块权重占 22 GB,梯度占 22 GB,合计4 GB。

  4. 依次计算 16 块:加载 W1W1​ → 计算 Y1Y1​ → 释放 W1W1​ 和梯度 → 加载 W2W2​ → 计算 Y2Y2​ → 释放 W2W2​ …… 直到 Y16Y16​。

  5. 最终得到完整的输出 YY。

这样,单个 GPU 就能处理这个巨大的线性层,不需要模型并行,也不需要把层拆到多个 GPU 上。


好处

  • 避免模型并行:数据科学家不用修改模型代码,不用把算子手动切分到多个 GPU。

  • 降低工作内存:GPU 上只需要同时驻留一块参数和梯度,内存需求降为原来的 1/N1/N。

  • 支持任意大的算子:只要分块数足够多,理论上可以支持任意大的隐藏维度。

  • 缓解内存碎片:分块降低了对连续大块内存的需求,减少因碎片导致的 OOM。

关键技术二:Bandwidth-Centric Partitioning(带宽中心分区)

当模型状态被卸载到 CPU 或 NVMe 后,如何高效地把它们加载回 GPU的问题。核心思想是:不要让一个 GPU 独自承担全部数据的加载,而是让所有数据并行进程一起分担,利用所有 PCIe 链路的聚合带宽。

下面用对比的方式解释。


1. 传统方法:广播(Broadcast)—— 只有一条 PCIe 在工作

在 ZeRO 和 ZeRO-Offload 中,每个参数(或每层参数)完整地属于某一个数据并行进程。比如有 4 个 GPU(dp=4),某个参数完整地存放在 GPU 0 的 CPU 内存中。

当需要这个参数时:

  1. GPU 0 先从自己的 CPU 内存把参数读到自己的 GPU 内存(通过 GPU 0 的 PCIe)。

  2. 然后 GPU 0 通过 GPU-GPU 通信(NVLink 或 PCIe)把参数广播给 GPU 1、2、3。

问题在于:从 CPU 到 GPU 的这一步,只有 GPU 0 的 PCIe 链路在传输数据。GPU 1、2、3 的 PCIe 链路完全空闲。单条 PCIe Gen3 的带宽大约 12 GB/s,这远低于训练所需的 70 GB/s(参数和梯度)或 1.5 TB/s(优化器状态)。

所以,传统广播方式下,CPU/NVMe 到 GPU 的有效带宽被限制在单条 PCIe 的带宽,无法随 GPU 数量增加而提升。


2. ZeRO-Infinity 的方法:带宽中心分区 + Allgather

ZeRO-Infinity 换了一种思路:

  • 不再让一个进程完整拥有一个参数,而是把每个参数切成 dp 份,每个数据并行进程只拥有其中的 1/dp1/dp。

  • 这些分片分别存储在各个进程自己的 CPU 或 NVMe 中。

  • 当需要完整参数时,所有进程同时从各自的 CPU/NVMe 读取自己那一份到自己的 GPU(所有 PCIe 链路并行工作)。

  • 然后执行allgather集合通信,每个 GPU 都从其他 GPU 那里收到别人拥有的分片,最终每个 GPU 都得到完整的参数。

关键点:

  • 从慢速内存到 GPU 的传输:所有 GPU 的 PCIe 同时工作,聚合带宽 = 单 PCIe 带宽 × dp。

  • GPU 之间的 allgather:数据量是完整的参数,通信成本与广播相同(因为每个 GPU 最终都要得到完整参数)。但这一步走的是 GPU-GPU 高速链路,不是瓶颈。

这样,从 CPU/NVMe 到 GPU 的有效带宽就随数据并行度 dp 线性增长。


3. 具体数字例子

假设有 16 个 GPU(dp=16),每个 GPU 的 PCIe Gen3 到 CPU 的带宽是 12 GB/s。

  • 传统广播:从 CPU 到 GPU 的带宽始终是12 GB/s(只有拥有者的 PCIe 在工作)。

  • 带宽中心分区:每个 GPU 从自己的 CPU 读取 1/161/16 的参数,16 条 PCIe 同时工作。理论聚合带宽 = 16×12=19216×12=192 GB/s。实际中受限于 CPU 内存带宽或 NVMe 带宽,论文中测得:

    • CPU 内存到 GPU 的聚合带宽约48 GB/s(每 GPU 3 GB/s)。

    • NVMe 到 GPU 的聚合带宽约25 GB/s(每 GPU 1.6 GB/s)。

虽然单条 PCIe 仍然只有 12 GB/s,但聚合后已经能接近甚至超过训练所需的 70 GB/s(参数和梯度)。随着节点增加,聚合带宽继续线性增长。例如 64 个 DGX-2 节点,CPU 内存聚合带宽超过 3 TB/s,NVMe 聚合带宽超过 1.5 TB/s,完全满足优化器状态的带宽需求。


4. 为什么这很重要?

  • 打破了单 PCIe 带宽瓶颈:卸载到 CPU/NVMe 后,参数和梯度的加载不再受限于单条 PCIe。

  • 随规模线性扩展:GPU 越多,聚合带宽越高,训练效率不会因为卸载而下降。

  • 使得 ZeRO-Infinity 能在有限资源上训练超大模型:即使只有少量 GPU,也能通过聚合带宽高效利用慢速内存。


5. 一句话总结

带宽中心分区就是把参数切成很多份,让每个 GPU 只负责从自己的慢速内存中读取一小部分,然后所有 GPU 同时读取,最后通过 allgather 拼成完整参数。这样,所有 PCIe 链路都在并行传输,聚合带宽随 GPU 数量线性增长,从而避免了单条 PCIe 带宽不足的问题。

这就像搬家:传统方式是所有东西都放在一个人家里,搬家时只有他一个人搬,其他人看着;带宽中心分区是把东西分散到所有人家里,搬家时所有人同时搬自己的那份,最后在目的地拼起来,速度就快多了。

关键技术三:Overlap-Centric Design(重叠中心设计)

重叠中心设计”(Overlap-Centric Design)是 ZeRO-Infinity 用来把慢速内存的数据搬运时间隐藏到 GPU 计算背后的核心机制。它的目标很简单:别让 GPU 闲着等数据。

下面我按“问题 → 思路 → 具体做法 → 效果”的顺序讲清楚。


1. 问题:数据搬运太慢,GPU 会空等

当模型状态卸载到 CPU 或 NVMe 后,GPU 需要参数时,数据要走三段路(以 NVMe 为例):

  1. NVMe → CPU 内存(nc-transfer)

  2. CPU 内存 → GPU 内存(cg-transfer,走 PCIe)

  3. GPU 之间 allgather(gg-transfer,走 NVLink 或 PCIe)

这三段路的速度依次是:NVMe 最慢,PCIe 次之,GPU 间通信最快。

如果串行执行:

text

先花时间把数据从 NVMe 读到 CPU, 再花时间从 CPU 拷到 GPU, 再花时间 allgather 到所有 GPU, 最后才开始计算。

那么总通信时间 = nc + cg + gg,而这段时间 GPU 完全空闲。训练效率会非常低。

所以需要“重叠”:让数据搬运和 GPU 计算同时进行。


2. 核心思想:一边算,一边提前搬后面的数据

ZeRO-Infinity 的重叠引擎有两个主要部分:

(1)动态预取器(Dynamic Prefetcher)

它会跟踪前向/后向传播中算子的执行顺序,提前知道接下来要用哪些参数。然后,在计算当前算子的同时,为未来几个算子发起数据搬运。

论文举了一个非常具体的例子:

假设现在正在执行第 ii 个算子。预取器会同时做三件事:

  • 为第 i+3i+3 个算子做nc-transfer(从 NVMe 读到 CPU)

  • 为第 i+2i+2 个算子做cg-transfer(从 CPU 拷到 GPU)

  • 为第 i+1i+1 个算子做gg-transfer(GPU 间 allgather)

这三个传输全部与第 ii 个算子的 GPU 计算并行发生。

等到计算推进到第 i+1i+1 个算子时,它的参数已经通过 allgather 准备好了;到第 i+2i+2 个时,CPU→GPU 拷贝也完成了;到第 i+3i+3 个时,NVMe→CPU 也完成了。

GPU 一直在算,数据搬运被“藏”在计算后面。

而且,预取器还能处理动态工作流(比如不同迭代的算子顺序变了),它会更新内部的算子序列映射,保证预取正确。

(2)后向传播中的重叠

后向传播需要计算梯度,并把梯度写回慢速内存。

ZeRO-Infinity 可以:

  • 在计算第 ii 个算子的梯度时,同时为第 i+1i+1 个算子的梯度做reduce-scatter(GPU 间通信)。

  • 同时把第 i+2i+2 个算子的梯度从 GPU 写回 CPU 或 NVMe。

这样,梯度的通信和卸载也完全与计算重叠。


3. 为什么需要“三步”分开预取?

因为三段传输的速度不同,如果全部同时开始,慢的(NVMe→CPU)会拖后腿。所以预取器错开启动时间:

  • 最慢的 nc-transfer 提前最多(为 i+3i+3 准备)

  • 中速的 cg-transfer 提前中等(为 i+2i+2 准备)

  • 最快的 gg-transfer 提前最少(为 i+1i+1 准备)

这样,当计算到达某个算子时,它的参数刚好已经“流水线”式地准备好了,不需要等待。


4.流水线的“节拍”由谁决定?

流水线的吞吐量由最慢的阶段决定。在这个例子里,nc 最慢,所以:

  • NVMe 一直在忙(处理不同算子的 nc)

  • PCIe 会空闲一段时间(因为 cg 比 nc 快)

  • GPU 间链路也会空闲(gg 最快)

  • GPU 计算也可能空闲

这不是断流,而是流水线被最慢阶段限制。快阶段有空闲是正常的。

论文通过聚合多个节点/GPU 的 nc 带宽来解决这个问题:节点越多,nc 聚合带宽越高,最终 nc 不再是瓶颈。

5. 效果

论文第 8.6 节图 6d 显示:在 64 块 GPU 上训练 8B 模型,开启预取和重叠后,小批量下吞吐量显著提升;关闭后性能急剧下降。

一句话总结:重叠中心设计就是让 GPU 一边算当前算子,一边提前把后面要用的参数从 NVMe/CPU 搬过来,同时把算完的梯度搬回去。数据搬运和计算并行,GPU 不再空等慢速内存,从而在卸载到慢速内存的同时仍保持高训练效率。

你可以把它想象成做菜:如果等水烧开再切菜,就慢;如果烧水的同时切菜、备料,就快。重叠中心设计就是让“烧水”(数据搬运)和“切菜”(GPU 计算)同时进行。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/26 21:11:47

2027届大数据管理与应用秋招:物流运营面试的数据分析思路拆解

先说判断:面试官问履约效率,想听的不是你懂大数据,而是你懂履约。 大数据管理与应用专业的优势不在算法,在于能把一个模糊的效率问题拆成可量化的环节,再定位到具体节点。京东物流2027届新锐之星的综合运营管理方向定位…

作者头像 李华
网站建设 2026/10/26 21:10:54

TPS259483AYWPR+ATmega32构建智能电源路径保护系统

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/26 21:11:02

coreldraw实操笔记

适用:广告、海报、展板、图文排版、标识标牌、手举牌制作基础图形绘制(矩形)1. 绘制矩形快捷键:F6操作步骤:按F6,画布拖动绘制矩形;V挑选工具调整位置大小应用场景:展板底框、图片外…

作者头像 李华
网站建设 2026/10/26 21:10:09

eFuse与MCU协同:嵌入式系统电源路径保护实战方案

1. 先说结论:这一套组合到底在保护什么 很多嵌入式板卡损坏,不是死在CPU手里,而是死在电源入口那一瞬间。现场热插拔、24V电源抖动、负载短路、大电容充电瞬间的冲击电流,任何一次波动都可能把DC-DC、主控甚至整块板卡带走。常规做…

作者头像 李华
网站建设 2026/10/26 21:11:23

Ponytail 插件完全指南:从核心定位到配置避坑的实战解析

1. 从“ponytail”这个词说起:它到底指什么第一次看到“ponytail”这个词,绝大多数人的第一反应是“马尾辫”——一个再普通不过的发型名词。但如果你是在插件、工具或者某个技术社群的语境里撞见它,那它大概率不是指发型,而是某个…

作者头像 李华
网站建设 2026/10/17 4:44:24

裸金属服务器芯片适配实战:驱动安装与透传配置避坑指南

1. 从"装不上"到"跑得稳":裸金属适配到底卡在哪 搞过裸金属服务器的人大概都有过这种体验:系统装完了,网卡不认,驱动装了三遍还是报错,好不容易网通了,配个透传又给你甩一脸"设备…

作者头像 李华