查看: 3|回复: 0

[显卡与算力] 当四块显卡抢着喝同一口井里的水:一场关于GPU微调的资源调度战

[复制链接]

15

主题

1

回帖

57

积分

注册会员

积分
57
发表于 4 小时前 | 显示全部楼层 |阅读模式


2024年前后,有一件事情让很多想微调大模型的人很头疼。
你手上有一块甚至四块GPU,想对一个几十亿参数的模型做全参数微调,不是那种只调几个小插件的轻量化方法,而是实打实地更新每一个权重。问题是,模型的参数、梯度、优化器状态加起来,内存占用可能是参数量的16倍。一个140亿参数的模型,光是这些状态就要吃掉两百多GB内存,GPU的显存根本装不下。
于是有人想了个办法:把这些状态都放到内存里,GPU只负责临时借用一层一层的参数来算,算完就还回去,腾地方给下一层。这个思路本身没问题,单卡上跑得还不错。
但真正的麻烦出现在你想用多块卡一起训练的时候。
**一块卡能应付的事,四块卡一起做反而更慢了。**
这不是危言耸听,论文里给出了实打实的数字:在八块A800显卡上,面对同一个1.4万参数的Qwen3模型,当batch size固定、GPU数量从4涨到8时,理论上计算时间应该减半,但某个基线系统(SlideFormer)的实际运行时间几乎纹丝不动,卡在43秒附近。
这就是SlideDP这篇论文要解决的核心问题:GPU之间看起来是在并肩作战,但背后它们在抢同一个资源池。
核心问题:共享的厨房,多个厨子
要理解这个问题,先得搞明白"内存驻留式分层流式加载"到底在干什么。
**内存驻留式分层流式加载**:把模型的主权重和优化器状态长期放在CPU内存里,GPU只在计算某一层时临时把这一层的参数搬过去,用完就释放,这样GPU显存压力大大降低。
这个设计对单卡训练很友好。GPU一边算当前层,CPU一边把下一层的参数转换好格式、搬运过去,只要这个搬运和转换的时间比GPU算一层的时间短,就能被完全"藏"起来,用户感知不到延迟。论文管这个叫做"隐藏条件":主机侧的参数搬运、梯度回传、CPU端优化器更新,必须能和独立的GPU计算重叠,并且赶在结果真正被需要之前完成。
问题来了,当你从一块GPU扩展到R块GPU时,两个麻烦同时冒出来。
第一个麻烦,论文叫它"可避免的放大效应"。如果简单粗暴地把单卡方案复制R份,每块卡都要自己拉一份完整的参数副本,算完梯度后再各自传回CPU汇总。这意味着主机需要处理的数据流量直接乘以R,但CPU的算力、内存带宽这些资源并没有跟着变成R倍,它们是固定的。
这就像你家厨房本来配了一个灶台和一个厨子,饭做得挺快。现在你请了三个厨子一起做菜,但灶台只有一个,水龙头只有一个,案板也只有一个。厨子数量翻了四倍,但灶台还是那个灶台。如果你让每个厨子都单独去领一遍食材、单独占用灶台清洗食材,四个人反而比一个人做得更慢,因为大家都在排队等资源,而不是真的在并行干活。如果不解决这个问题,你增加的GPU数量越多,浪费在"重复领料"上的时间就越多,甚至会出现GPU越多反而越慢的荒谬结果。
论文给出的实测数据印证了这一点:在A800平台上,并发两块GPU同时搬运一个8亿参数层的数据时,每块卡能分到的带宽从单卡时的15.6 GB/s直接腰斩到8.7 GB/s每卡。
第二个麻烦更隐蔽,叫"残留的流水线暴露"。就算你把重复的流量去掉了,CPU更新、必要的数据搬运、跨GPU之间的依赖关系还是存在的。当你用更多GPU去跑同一个固定的总batch size(这叫强扩展)时,每块卡分到的本地batch变小了,GPU算得更快了,这意味着原本用来"藏"CPU工作的计算窗口也跟着变短了。CPU那边的活儿没见得少干,但能藏身的"掩体"变薄了,暴露出来的部分就成了纯粹的等待时间。
**这两个麻烦叠加起来,就是为什么直接把单卡方案搬到多卡上会翻车。**
论文测的CPU端Adam优化器更新速度也很说明问题:在16个物理核心上能跑到182-184 GB/s,但把核心数翻倍到32个,速度只提升了8.5%到10%。这说明CPU这边的服务能力存在明显的天花板,不是你多塞人进厨房就能线性提速的。
SlideDP的解法:一份账本,多条送菜路线
面对这两个麻烦,SlideDP的设计思路可以概括成两句话:状态只留一份权威副本,但送菜的路线可以灵活选。
**共享主机状态**:整个训练过程中,CPU内存里只保留一份FP32精度的主权重和优化器动量状态,所有GPU rank共享这同一份"账本",而不是每块卡各自维护一份。
这个设计砍掉了前面说的"可避免放大效应"。既然账本只有一份,更新时也只需要做一次,不用R份数据各自汇总再各自更新。但账本只有一份不代表运货方式只有一种,SlideDP给参数分发设计了两条路线:一条是"全量分发",每块卡都拿到完整的一层参数;另一条是"分片分发",每块卡只拿参数的1/R,然后通过GPU之间的高速互联做一次"集合通信"(all-gather)把完整参数拼出来。
梯度回传这边也有两条路:一条是GPU先在本地做归约,算出一个汇总后的梯度再传回主机,这样主机只需要处理一份梯度流量;另一条是每块卡的梯度都各自传回CPU,让CPU来做汇总,但这样CPU端要处理R份数据,还要和优化器更新抢内存带宽。
论文做了个很有意思的实验,证明了"哪条路线最优"这件事根本没有标准答案,完全取决于你的硬件和工作负载。在带NVLink桥接的A800节点上,当每卡batch size是16时,分片分发比全量分发快17%。但把NVLink桥拆掉之后,同样的场景下全量分发反而比分片分发快26%。batch size换成8时差距更夸张,达到33%和19%。
**这就好比送外卖,你手里有两种方案:一种是每个骑手都去中央厨房取一份完整的菜,另一种是让骑手们先各自取一小份食材,到小区门口再拼成一份完整的菜。**
如果小区到中央厨房的路(相当于PCIe总线)很堵,但小区内部骑手互相传递东西的小路(相当于NVLink)很畅通,那显然应该让骑手们少跑几趟中央厨房,就近拼单,这时候分片分发更优。但如果小区内部传递东西反而比去中央厨房还慢(没有NVLink桥接),那还不如让每个骑手自己跑一趟中央厨房拿齐全套,这时候全量分发更优。如果你不根据实际路况动态选择,而是固定用一种方案,很可能在某些硬件配置下白白损失20%到30%的效率。
搞定了"运什么、怎么运",接下来是"怎么安排时间"的问题。SlideDP引入了跨rank的流水线调度和分块重叠机制。
论文里描述了六条并行运作的"逻辑车道":参数准备与搬运、激活值的卸载与重新加载、GPU计算、梯度归约、梯度回传、CPU端的逐层优化器更新。这六条车道共享主机的DRAM和PCIe带宽,SlideDP要做的就是让它们尽量不互相干扰,同时保证每一层最终只产生一次聚合后的梯度和一次主机更新。
这里有个关键的调度技巧叫分块重叠。参数搬运的时候,CPU在转换下一块数据格式的同时,DMA硬件正在传输当前这一块,两件事同步发生而不是排队进行。梯度回传也是类似逻辑,整层的归约计算完成后,梯度数据分块拷贝到主机,每拷贝完一块就立刻释放给CPU去更新,不用等整层数据都搬完。
论文的单层微基准测试显示,这个分块策略把"格式转换加搬运"的耗时从127.8毫秒压缩到50.8毫秒,"搬运加更新"从135.9毫秒压缩到91.7毫秒。放到真实的四卡训练场景里,Qwen3-8B模型的吞吐量从每秒3218个token提升到3465个token,提升了7.7%;如果是单卡场景,提升幅度更夸张,达到33.6%。
一个步时建模:到底卡在哪儿
光靠直觉调参数是不够的,SlideDP还配了一套分析性的步时模型,用来量化到底是哪个环节在拖后腿。
这套模型把一个训练步骤拆解成两部分加和:一部分是资源的服务能力上限,一部分是执行依赖关系带来的等待。
简单来说,每种资源(GPU算力、PCIe带宽、CPU更新速度)都有一个处理能力上限,你分配给它的工作量除以这个上限,就是这个资源至少需要花费的时间。所有资源里耗时最长的那个,就是整个步骤时间的下限。但现实中还有一层复杂性:某个操作要等它依赖的前置操作完成才能开始,比如反向传播要等参数到位、激活值加载完毕、前一层计算结束,这三者里最晚完成的那个决定了它的启动时间。
论文给了一个简化的近似公式:训练步时间约等于GPU计算时间和主机/传输服务时间两者中的较大值,再加上由执行依赖造成的额外延迟。当主机工作量超过GPU计算量时,系统处于"主机瓶颈"状态;反过来则是"GPU瓶颈"状态。
**这个模型最大的价值,是解释了为什么同样的优化在不同场景下效果天差地别。**
在主机瓶颈的场景下,减少主机端的工作量能实实在在缩短训练步时间;但一旦进入GPU瓶颈状态,再怎么优化主机端的传输效率,省下来的时间也会被"隐藏"起来,因为真正的瓶颈已经转移到GPU计算本身。这就像给一辆车换更快的轮胎,如果你本来就被红灯和堵车卡住了,轮胎再快也体现不出来;只有当路况通畅、真正卡脖子的是车本身的加速能力时,换轮胎才有意义。
弹性检查点和AutoPolicy:把省出来的显存用在刀刃上
前面的优化解决了"怎么搬数据"和"怎么调度时间",还有一块空白:省下来的GPU显存该怎么花。
论文观察到一个现象,在H100上跑Qwen3-14B,batch size为32时,固定配置只用了15GB的峰值显存,而H100有80GB容量,这意味着还有大量显存处于闲置状态。
**弹性检查点(Elastic Checkpointing)**:利用GPU窗口之外的空闲显存,灵活决定每一层的激活值要不要保留在GPU上、要不要卸载到CPU、要不要干脆重新计算而不保存。
这里涉及一个训练中常见的权衡,叫"激活值检查点"(activation checkpointing),本质是用计算时间换内存空间:反向传播需要用到前向传播时产生的中间结果(激活值),如果把这些中间结果全部保留在显存里,显存压力很大;但如果都不保留,反向传播时就得重新算一遍前向过程,这叫"重计算",会增加额外的计算开销。
论文给出了四种检查点粒度:整层级别的检查点、更细粒度的"片段级"检查点(用七位掩码标记七种不同的切分边界)、选择性激活检查点(只缓存部分关键算子的输出)、完全不做检查点。每种粒度还可以搭配一个"卸载比例",决定保留下来的激活值里有多少比例要进一步搬到CPU内存。
问题是,到底该为每一层选哪种策略?这就是AutoPolicy要做的事。
**AutoPolicy**:一套自动化的策略选择系统,先探测硬件上不同通信路线和分块大小的实际表现,再用一个精简的训练流水线校准各种检查点策略的真实开销,最后通过整数规划求解出一套在显存预算内、总体代价最低的逐层配置方案。
AutoPolicy的工作流程很像一个精打细算的管家先去市场摸底(探测不同路线和分块大小),再拿样品做小规模试做(在缩小版流水线里校准候选策略的真实代价),最后才按预算拍板最终菜单(用整数规划分配给每一层具体策略),而不是闭着眼睛按一套固定食谱做菜。
这套系统带来的收益是实打实的。表格数据显示,在四块H100上跑Qwen3-14B,batch size为32时,经过AutoPolicy优化后吞吐量从每秒17370个token提升到19530个token,提升12.4%,同时主机内存占用反而从261.9GB降到200.6GB,下降23.4%。
更关键的是,这套自动选策略的过程本身也是有代价的。论文测算,在四块H100上对Qwen3-14B做一次完整的策略选择,大约需要1218秒(20.3分钟)。但选出来的策略每一步能省下0.97秒,算下来大概1257步就能把这20分钟的"调研成本"赚回来,相当于2.72小时的训练时间,如果整个训练任务要跑24小时,这个前期投入只占1.4%。
实测效果:从消费级显卡到数据中心级显卡
这套系统在三种硬件平台上做了测试:四块消费级RTX 4090(PCIe互联,没有高速桥接)、八块A800(部分配备NVLink桥接)、八块数据中心级H100(NVSwitch全互联,最高速的架构)。
在吞吐量对比上,SlideDP相比三个基线系统(SlideFormer、MegaTrain、ZeRO-Offload)的几何平均吞吐比达到1.46到2.64倍。具体场景里,四块RTX 4090跑Qwen3-8B,batch size为64时达到每秒9810个token,而同场景下几个基线系统都因为显存不够直接报错退出(OOM,out of memory)。
在四块H100上,Qwen3-14B在batch size为256时达到每秒23200个token,单步处理超过104万个token,还不需要梯度累积这种为了凑大batch而拆分计算的权宜之计。更值得一提的是,这个数字比GPU显存完全够用、不需要做任何流式加载的FSDP2方案(一种PyTorch原生的全分片数据并行实现)的实测峰值还要高11.2%。
这个结果有点反直觉。一个要靠主机内存、要做流式加载腾挪的"穷办法",居然在某些场景下跑赢了显存完全够用的"富办法"。原因在于当batch size足够大时,GPU计算本身的时间已经足够长,长到可以完全盖住主机那边传输和更新的耗时,这时候SlideDP不但没有额外负担,反而因为可以处理更大的batch,摊薄了单位token的开销。
在长序列场景下,四块H100跑Qwen3-14B,SlideDP成功支持了256K token这样超长的输入序列,而FSDP2和另一个基线Megatron在64K长度时就已经因显存不足被标记为不可行。
内存效率方面,在相同可行batch size下,SlideDP相比ZeRO-Offload峰值显存占用降低51%到59%,相比MegaTrain降低29%到42%。主机内存的增长斜率也更平缓,每增加十亿参数模型规模,SlideDP只需要多消耗14.2GB主机内存,而其他系统需要19.8到22.9GB。
论文还验证了混合专家模型(MoE,Mixture of Experts,一种只激活部分参数子网络的大模型架构)的适配性,在Qwen3.6-35B-A3B和Gemma4-26B-A4B两个MoE模型上,SlideDP相比ZeRO-Offload吞吐量提升1.98到3.21倍。
正确性方面,论文拿SlideDP和FSDP2跑了200步同样数据、同样初始权重的训练,对比每一步的损失值,最大绝对差异只有0.00063,说明这套复杂的异步重叠调度机制并没有破坏同步数据并行本该保证的数学一致性。
写在后面
读完这篇论文,最让我意外的一点是,多卡训练慢下来的原因,很多时候不是算法设计得不够聪明,而是大家在共享一套基础设施时,没有意识到这套设施本身是有限的。
CPU核心数翻倍只换来不到10%的性能提升,这个数字其实在提醒我们一件更普遍的事:很多系统的瓶颈根本不在计算力本身,而在于数据怎么流动、谁先谁后、谁等谁。这和很多组织管理问题其实是一回事,人多了未必效率高,如果大家都在抢同一个会议室、同一份文档的编辑权,人越多反而越慢。
论文里那个"换NVLink桥接后最优路线反转"的实验让我印象很深。17%对26%,方向完全掉了个个。这说明在系统设计里,不存在放之四海而皆准的"最佳实践",很多所谓的最优解都是和具体环境深度绑定的。如果你把一套在某个硬件上验证过的方案直接套用到另一套硬件上,不做重新评估,很可能正好踩进那个被反转的坑里。
这篇论文也留了一个没有完全解决的问题:当GPU数量继续往上涨,涨到几十块甚至上百块的时候,单台主机的共享资源瓶颈会不会变成硬限制?论文的实验最多只做到了八卡,而且都在单个节点内。如果训练任务需要跨节点、跨主机,这套"一份账本"的设计思路还能不能成立,答案目前还不清楚。
Q&A
Q1:SlideDP是什么?
A:SlideDP是一套面向多GPU的大模型全参数微调运行时系统,核心做法是让多块GPU共享同一份放在主机内存里的权威参数状态,并通过灵活的通信路线选择和流水线调度,减少数据冗余传输、缩短训练步时间。
Q2:SlideDP相比传统方案能提升多少训练速度?
A:在匹配batch size的测试中,SlideDP相比SlideFormer、MegaTrain、ZeRO-Offload三个基线系统的几何平均吞吐比达到1.46到2.64倍,在部分H100场景下甚至超过了显存充足的FSDP2方案11.2%。
Q3:为什么多GPU训练反而会出现速度不升反降的情况?
A:因为多块GPU共享同一套主机资源(CPU、内存带宽、PCIe总线),如果每块卡都独立重复拉取参数和回传梯度,主机侧的流量会随GPU数量线性增加,但主机服务能力是固定的,导致资源争抢反而拖慢整体速度。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关注公众号

相关侵权、举报、投诉及建议等,请发 E-mail:2776601884@qq.com

Powered by Discuz! X5.0 Licensed © 2001-2026 Discuz! Team.|青ICP备2025004122号-1

在本版发帖
关注公众号
返回顶部