ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

RL后训练GPU利用率高却产出低?解耦式协同调度如何破局

RL后训练GPU利用率高却产出低?解耦式协同调度如何破局 如果你的团队最近开始把精力投到 RL 后训练上你大概率会撞上一个很诡异的场景集群监控面板上 GPU 利用率顶着 90% 以上但 rollout 的 token 产出速度就是上不去训练侧时不时饿得发慌一个 iteration 的墙上时间比预期多出两三倍。这不是简单的资源不够而是调度的思路还停留在预训练时代。OSDI 是系统领域最顶的会议之一OSDI26 上这篇 Weave 瞄准的正是这个痛点——面向解耦式 RL 后训练的高效协同调度。标题里的解耦式和协同调度两个词基本把 RL 后训练基础设施最近几年的核心矛盾都说透了。这篇东西我反复读了几遍结合自己跑 RL 训练踩过的坑把理解整理成下面这些内容希望对正在搭或者准备搭 RL 后训练基础设施的团队有帮助。1. 从 Pre-training 到 Post-trainingGPU 集群为什么突然不好使了1.1 预训练是一道长流水RL 后训练是一张流水网预训练的工作负载在调度器眼里是极其友好的一个大 job资源需求静态确定一跑就是几天几周中间几乎不变化。调度器要做的事情简单粗暴——把足够的 GPU 圈起来Tensor Parallel、Pipeline Parallel 排布好丢进去跑完事。集群的平均利用率这个指标在这个场景下是真实可信的。但 RL 后训练完全不是这么回事。以 LLM 的 RLHF 为例一个 iteration 要经历策略模型 rollout 生成数据、奖励模型打分、策略模型梯度更新这三个主要阶段而且它们是生产-消费关系rollout 是生产者训练是消费者。更麻烦的是策略模型每更新一次rollout 阶段的数据分布就变了这跟预训练里数据分布一直静态完全不一样。所以 RL 后训练在调度器眼里是一张网有一个不断在变的策略模型一个或多个奖励模型一条条动态变化的产出-消费链路。用预训练时代跑长流水的思路去调度这张网必然出事。1.2 三种负载三种脾气把 RL 后训练拆开看每个阶段对 GPU 的脾气要求是冲突的这是所有调度难题的根源。阶段计算模式资源需求特征性能敏感点Rollout 生成推理自回归解码显存带宽密集、需要大量并发序列延迟波动、吞吐稳定性奖励/评判模型打分推理较短序列显存占用较小、吞吐导向吞吐、批处理效率策略模型训练训练前向反向算力密集、需要大批量GPU 算力利用率、通信效率Rollout 阶段的典型特征是并发序列数巨大——为了给训练凑够样本通常要同时跑几百上千条 prompt 的生成每个序列的 KV Cache 又吃显存又吃带宽。这个阶段最优的硬件利用方式是把 GPU 当成一个吞吐优先的推理引擎来调。训练阶段则完全相反它需要的是大矩阵乘法算力需要模型并行、数据并行协同batch size 越大越好。奖励模型打分夹在中间跟 rollout 类似是推理但序列短得多又不太一样。这三个阶段的资源需求如果叠加在同一批 GPU 上互相之间就不是协作而是打架。Rollout 的推理延迟和训练的稳定批量计算互相干扰最后谁都没跑好。2. 解耦式方案思路对了一半另一半卡在调度2.1 为什么要解耦把 GPU 从一锅烩里解放出来最早期的 RLHF 实现是高度耦合的一份模型参数同时承担 rollout 推理和训练同一批 GPU 上既跑前向推理又跑梯度计算。这种方案在模型不大、实验性的场景下没问题一旦到 70B、数百 B 参数级别的模型立刻暴露出两个致命问题。第一是内存冲突。推理需要为大量并发序列维护 KV Cache训练需要大的 activation 和梯度状态。两者挤在同一批 GPU 上内存互相挤压不说显存分配一会儿给推理一会儿给训练碎片化严重。第二是性能干扰。推理请求是延迟敏感的一个序列生成慢了整个 rollout 链路的吞吐就受拖累而训练又希望把 GPU 塞满跑大矩阵乘法。一锅烩的结果是推理延迟不稳、训练算力吃不饱。所以业界的主流做法是解耦——把 rollout、奖励打分、训练拆成独立部署的组件各用各的 GPU 资源池。OpenRLHF、veRL 这些框架都已经支持了训练集群和推理集群分离的架构。这样每个组件都能按自己的最优方式配置推理侧用高带宽的推理优化配置训练侧用大 batch 高算力配置互不干扰。2.2 解耦之后新问题来了谁来协调解耦解决了一锅烩的问题但它不是免费的午餐。拆成独立的组件之后三个新的麻烦立刻浮出水面。麻烦一数据管道变成瓶颈。Rollout 产出的是一批批 prompt-response 序列在训练侧要吃进 memory 做 advantage 计算动辄几十 GB 甚至上百 GB 一次 iteration。这些数据要在不同资源池之间搬运走网络还是走存储怎么保证传输不拖慢整个 iteration 周期麻烦二阶段之间的速率必须匹配。Rollout 侧要看推理吞吐训练侧要看加速器算力。两者天然存在速率差刚起跑时训练在等 rollout 攒数据跑到中途可能 rollout 拖了后腿。任何一个环节慢下来整个流水线就要空转。麻烦三资源池的静态划分是浪费。如果 rollout 固定分 100 张卡、训练固定分 64 张卡那训练在等数据的时候那 64 张卡就是闲着的。反之 rollout 在某个时刻请求量小分给它的卡也闲着。静态划分等于在资源池之间砌了一堵墙两边的闲置资源互相借不了。前面这些麻烦恰恰是题里协同调度要解决的东西。也就是说解耦理念是对的但光解耦不够——你得有一套调度机制在解耦开来的多个组件之间做协调让整体效率最大化。这就是 Weave 这类系统存在的意义。3. Weave 的协同调度到底协同了什么3.1 从论文标题拆解三个关键词先把标题掰开看。Weave是系统名字单词本身有编织、穿梭的意思暗示它做的事情是把多条线多个阶段、多种资源交织协调起来。高效体现在对 GPU、网络、存储的综合利用上。协同调度是最核心的修饰词——它调度的对象不是单个 job而是解耦开来的多条 RL 处理链路上的多个组件。这里有个关键区分协同调度不是分开调度。如果 rollout 和训练各自用一套独立的调度系统比如推理走推理的调度器、训练走训练的调度器那就是分开调度是当前很多框架的默认状态。分开调度的问题在于互相之间没有全局信息推理调度器不知道训练侧还缺多少数据训练调度器也不知道 rollout 侧现在的产出能力如何。Weave 式的协同调度核心特征是有一个全局视角——它能看到整条流水线的状态并以此为根据做出分配决策。就像交通调度不是每个路口各管各的红绿灯而是有个区域中心看全路网做协调。3.2 Weave 类系统大概率做了哪几件事我没有直接拿到论文的完整实验细节以下按照领域内这类系统的常见设计逻辑来拆解核心思路在业界已经有共识第一件是弹性资源分配。在一个 iteration 的生命周期里不同阶段的资源需求是波动的。Rollout 阶段需要大量推理资源快速攒数据训练阶段需要集中计算资源。协同调度器应该能够在两个资源池之间动态挪移 GPU——比如训练在等数据时把一部分训练卡临时借给 rollout 用等数据攒够了再把资源收回来给训练跑大 batch。这个借和收的过程需要调度器对 GPU 的再分配延迟有精确估计否则频繁切换带来的额外开销比省下的资源还大。第二件是跨阶段的负载感知排队。每个阶段都有对应的任务队列但这些队列不是各自为政。协同调度器监控上下游队列的长度变化——上游队列堆积说明产出能力过剩或者消费能力不足下游队列干涸说明生产者要加速。基于这些信号做反馈控制类似控制理论里的 PID 思路队列长了给下游加资源队列空了催上游提产出始终保持整条流水线处于有活干但不堆积的平衡态。第三件是数据传输与资源放置的联合规划。数据在 rollout 池和训练池之间搬运如果两个池子的物理位置隔了很远的网络跳数传输一个大 iteration 的数据就要耗费不可忽略的时间。协同调度会尽量把有生产-消费关系的资源池放置在网络拓扑上相邻的位置甚至通过数据分片和流水线传输让训练侧在数据还没完全到达时就先算起来。这部分是很典型的系统论文会抠的细节——理论上传输占用的时间窗口可以通过 overlap 计算来隐藏掉。第四件是 straggler 处理。分布式环境下总会有慢节点某张卡散热不好降频了、某条网络链路拥塞了。在 RL 后训练里一个慢的 rollout worker 会导致整个 iteration 的数据不完整训练要等它。协同调度器要做的是识别 straggler 并把它的负载重新均衡给其他空闲 worker或者在数据组装阶段用补偿机制把 straggler 的损失降到最低。这类内容在论文里通常会有很细的实验支撑读的时候可以重点关注它怎么定义和检测 straggler。4. 一个具体的调度决策过程推演协同调度是怎么工作的光说概念不够我找个具体场景推演一遍把抽象的东西落到数字上。假设有一个 7B 模型的 RL 后训练任务资源集群总共 32 张 A100。场景设定初始配置 rollout 池 20 张卡训练池 12 张卡。用朴素的静态划分方式跑过程是这样的训练侧每完成一轮梯度更新把最新策略参数同步给 rollout 侧同步参数本身也有开销然后 rollout 开始用新策略生成下一批数据。假设一轮 rollout 需要 60 秒生成足够数据训练一轮需要 30 秒。那么理想情况下训练算完后 rollout 还没算完训练要等 30 秒空转rollout 算完后训练只需要 30 秒消化rollout 又空转 30 秒。这样一个 iteration 的周期是 90 秒其中有 30 秒训练空转、30 秒 rollout 空转资源有效利用率只有大约 66%。协同调度的做法会是这样第一步调度器观察到一个稳定的模式训练 30 秒一轮、rollout 60 秒一轮训练资源存在周期性空闲。它判断可以把训练池的 12 张卡里临时分出 4 张给 rollout 池使用训练池保留 8 张。第二步分配之后重新评估。8 张卡训练一轮可能要 40 秒batch 变小但并行度降低但 rollout 侧多了 4 张卡产出能力提升到 45 秒一轮。这时两者的节奏变成 rollout 45 秒、训练 40 秒周期从 90 秒缩短到 50 秒左右资源利用率提到 80% 以上。注意这个过程中调度器需要精确评估资源变动对每个阶段耗时的影响——这就是为什么论文里一定会对阶段耗时建模。第三步当数据攒够一轮训练量时调度器再把借出去的 4 张卡收回来让训练池回到 12 张卡的状态以保证训练阶段有足够的并行度跑大 batch。第四步如果某个时期 rollout 因为生成长尾 prompt比如代码生成任务里某条 prompt 特别长导致整体产出延迟飙升调度器检测到 rollout 池负载不均衡会把这些长尾任务分散给其他空闲 worker同时考虑暂缓从训练池借资源过来的动作避免进一步增加 rollout 侧的调度压力。这个推演里面每一步都依赖调度器对两个核心量的准确估计一是资源增减如何影响阶段耗时二是队列状态和负载状态的实时反馈延迟。如果估计不准调度器的决策还不如静态划分——这恰恰是这类系统真正难的地方也是论文里实验对比最值得看的部分。4.1 调度决策里容易忽略的参数传递开销上面那个推演漏了一个重要细节策略参数更新后要在 rollout 侧加载新权重。参数同步本身在网络里要传 7B 个浮点数1-2 个 GB 量级如果集群内部有 NVLink 高速互联还行跨节点走 InfiniBand 也要花几秒到几十秒。协同调度器在决策资源再分配时必须把这个参数同步的时间也计入 iteration 周期模型里否则会出现典型的调度器拍脑袋借资源结果省下的时间全浪费在参数同步上的尴尬。我自己遇到过的真实案例是某个框架把 rollout 池和训练池分在两个不同的计算节点组中间走的是共享的以太网。每次策略更新完同步参数要花将近 20 秒几乎占了整个 iteration 周期的四分之一。后来我们把 rollout 池和训练池在物理上拉近走高速互联同步时间压到了 3 秒以内整体吞吐提升非常明显。这就是论文里常说的communication-aware placement听起来不起眼落地效果比任何花哨的调度算法都实在。5. 基础设施团队读这篇论文最该盯住的四个细节5.1 资源画像与调度粒度论文的实验部分通常会给出不同阶段在典型配置下的资源消耗画像。读的时候重点看它给出的调度决策频率——是每一轮 iteration 做一次资源调整还是更细粒度到分钟级甚至秒级。这个粒度直接决定了你的集群管理系统能不能支持它的方案。如果你的集群用的是 Kubernetes 那一套节点级调度和容器级调度的时间开销是天壤之别。Granularity 越细对编排系统的要求越高你需要先确认自己的资源管理系统能不能扛住这个调度频率。5.2 数据落盘还是直通解耦之后的数据传输方案有的系统走共享存储数据先落盘再消费有的走内存直通 producer 直接推给 consumer。两者对存储带宽的要求完全不同。论文里会说明它的数据路径设计。如果某篇论文默认数据落盘那么你的集群需要配置高性能共享存储如果走直通反而要关注网络拓扑和内存分配策略。这个细节决定了你在复现时是加存储节点还是调网络。5.3 弹性伸缩的代价边界协同调度最大的卖点是弹性调配资源但它有个隐含的假设资源的再分配代价足够低。如果一次 GPU 再分配要 2 分钟包括销毁容器、拉起新进程、加载模型权重而一轮 iteration 才 1 分钟那弹性调度就是灾难。论文实验里一定会给再分配代价的测量数据看的时候留意这个值的量级。如果论文里的假设跟你的环境差很多——比如它是拿专门的高性能调度器测的而你的环境只能靠重启 Pod 来调整资源——那它方案里的弹性收益在你这边要大打折扣。5.4 评估指标不要只盯着吞吐RL 后训练这块论文常见的评估指标是每小时内完成的有效训练步数或者单个 iteration 的端到端耗时。但作为基础设施团队你要额外关注资源空闲率和阶段等待时间分布。吞吐高不代表资源用得好——可能只是其中一个阶段冲得很快另一个阶段长期闲置。看论文实验部分时画个时间线图把每个阶段的忙闲状态标出来比看平均值有价值得多。6. 写在最后从 Weave 这类系统里我能带走的实际经验虽然我们还没法直接拿到 Weave 的代码跑起来但从这类面向解耦式 RL 后训练的调度系统的核心思路里有几个经验是当下就能用的。第一立刻检查你的资源池划分方式。如果我现在还是用静态固定比例给 rollout 和训练分卡那第一件事就是把分卡改成脚本化、可动态调节的。先不用做得很智能至少保证每次调整资源分配的操作时间在可控范围——启动一个带模型权重的推理容器如果能控制在 30 秒内你就有资格开始尝试动态调配了。第二先建立 stage 耗时的精确画像。调度做得好不好取决于你对每个阶段耗时模型的估计准不准。把 rollout 吞吐、训练单轮耗时、参数同步延迟这几个关键量用监控数据记录下来跑几轮之后你就有了自己集群的标定曲线。有了这份标定数据哪怕你手动调配资源也能明显比瞎猜强一大截。第三从协同的角度去审视现有的可观测性。如果你的监控面板只能看到单阶段的利用率看不到上下游队列的堆积和消费关系那离协同调度还很远。至少要让代码记录每个时间点的阶段状态正在攒数据、正在训练、正在同步参数。有了这个你才能看到空转到底发生在哪个环节——这是所有优化的事实基础。我在实际跑 RL 后训练的过程中最深的一个体会是瓶颈永远在你不注意的那个衔接处。可能是参数同步的那条网络链路可能是策略更新后 rollout 侧 reload 权重的耗时也可能是奖励模型打分拖慢了整条数据流水线。Weave 这样的系统把协同调度摆到台面上本质上是在提醒我们RL 后训练的基础设施优化视线要从单个阶段挪到整条流水线上来。希望这篇文章能帮你在读论文或者搭系统的时候少走一些我走过的弯路。
返回列表