Hugging Face博客揭示:通过调整GPU任务调度顺序而非增加资源,在同一集群上实现了显著的资源利用率提升。
![]()
![]()
![]()
我们构建了一个支持约束的 GPU 分配器,并在七组基准测试场景中将其与 FIFO 调度器进行了对比评测。在完全相同的硬件上运行完全相同的工作负载,GPU 利用率最高提升了 33 个百分点,且在所有场景中,按优先级加权的输出均有提升,最高达到 105%。硬件没有任何变化。变化的是分配决策的顺序。
在数据开始之前先说明一下测量方式。以下所有收益均以同一场景下 FIFO 结果为基准进行计算。利用率以百分点(percentage points)为单位报告;价值以优先级加权输出的百分比增幅报告。
精确的决策陈述
"让 GPU 保持繁忙"不是系统能够执行的决策。真正的决策要窄得多、也难得多:为每个 GPU 在每个时间步分配哪个任务、以什么优先级运行。形式上,这是 GPU、任务、时间步三者组合对应的二元选择,输出是一张网格——每块 GPU 横跨整个调度周期,每个格子中是一个任务名或空白。
四类工作负载在这张网格上相互竞争:训练、实时推理、批量推理和量化。它们分成两种分配形态,难度就藏在这种分裂之中。训练、批量推理和量化属于批处理类:一旦启动,每者都需要连续占用一块 GPU,且在任务完成前不能中断。实时推理则相反:它是弹性的,受需求曲线驱动,每个时间步都在变化——随着流量增减而伸缩。
两种互不兼容的形态在同一时间步内竞争同一批硬件,这就是核心问题。另一个异质性存在于单一类型内部:对于同一个基础模型,训练任务从几小时到数天不等,从一块 GPU 到数十块不等。
FIFO 在竞争下的代价
整个对比的基准是基于 FIFO 的调度器:实时推理从固定预留中获取服务,其他所有任务按到达顺序排列,不考虑优先级。
在条件合适时,这是一个合理的策略。当集群有闲置资源时,分配顺序不会造成任何利用率损失,所有任务无论以什么顺序都能装下,因此 FIFO 和任何更复杂的策略都会占用相同的资源池比例。竞争才会让这种排序代价从不可见变得损耗资源。它随后以两种独立的方式变得昂贵,值得逐一分析。
预留的代价。实时推理不能等待资源;当流量需要 GPU 时,GPU 必须立即到位。如果调度器按任务到达顺序放置作业,就没有机制在低谷期释放 GPU 并在下一个峰值前重新回收它们,因此保证可用性的唯一方法是将每个实时应用一天中的最大需求作为预留 GPU 数量,一整天都保持这个数量。代价落在每一个非峰值时段。一个应用在中午需要六块 GPU、凌晨 4 点只需要两块,却要为一整天预留全部六块——四块空闲的 GPU 在整个一天里无法被任何批处理任务使用。它们没有被使用,但也不是免费的。这就是为什么在预留主导的两类场景中,基准利用率徘徊在集群总量的一半左右:混合控制场景为 51.6%,训练重载场景为 53.6%。大约半个资源池,其中大部分空闲的一半是预留的而不是自由的。无论集群是否存在竞争,这部分代价都会产生——竞争只是让它暴露出来。
排序的代价。在真正的竞争条件下,哪些任务能装下取决于你放置它们的顺序,而不仅仅取决于存在多少容量。顺序不是在容量问题解决后才应用的决胜规则。顺序本身就是容量决策。FIFO 按任务到达顺序放置每个任务,不权衡该任务的价值,也不检查还有多少任务必须塞进整个时间范围内,所以高优先级工作会等待在最先到达的任务后面,容量被那些后续任务无法使用的放置决策所占用。
两者叠加。全天为实时峰值需求预留的区块对队列中每个批处理任务来说是不可用的,每个小时都是如此,剩余部分则按请求到达的顺序分发出去。
这相当于一家航空公司把飞机分配给第一个呼叫的包机客户,然后发现没有飞机可飞实际盈利的航线。而全天候为仅持续几小时的峰值预留的 GPU 就是前文所说的停飞飞机最字面意义上的版本:处于待命状态、不产生任何收益、无法被其他人使用。

[图:并排的分配网格——上方为分配器,下方为 FIFO,同一场景]
在五组为真正竞争环境构建的基准测试场景中,分配器同时改善了两个指标。利用率从 52%–85% 的区间移动到了 72%–88% 的区间。优先级加权价值提升了 24.6% 到 105.1%,平均为 52%。每个场景、两个指标均有所改善,无需解释权衡。
最强的单一案例是 8 块 GPU 上的训练重载工作负载:利用率从 53.6% 提升到 87.0%,价值翻了一倍多,提升了 105%。固定且已在折旧的资产上找回了 33 个百分点,方式是通过回收预留的待命容量并按优先级排列其余部分。(此数据反映单一基准排序。)
分配器消除了这两种行为。实时需求被视为一条曲线而非天花板,在每个时间步按需分配,批处理类工作占据低谷期,同时受限于实时任务在连续时间步之间可交换的 GPU 数量上限。批处理类任务则在整个时间范围内按优先级放置,而非按到达顺序。其余部分将讲述如何实现。
利用率是必要条件。优先级才将其转化为价值。
利用率衡量的是占用率:可用 GPU 时间中有多少比例被分配给了某项任务。它不携带任何关于该任务价值的信息。有一个场景完全将二者分开,而且差距的方向很容易被忽略。
在规模测试中,30 个任务、64 块 GPU,FIFO 和分配器产生了完全相同的利用率,均为 44.9%,吞吐量也相同,30 个任务中完成了 27 个。分配器多交付了 15.9% 的优先级加权价值。每块仪表盘读数都一样。集群实际上产生了截然不同的产出。
一个不以优先级定价的目标可以将集群填到完全相同的水平、完成任务的数量也完全相同,但仍然产出更少。前文论述了占用率是衡量集群是否盈利的糟糕指标;这就是该论断的量化版本。
将问题写下来
另一种方案不是更长的启发式规则列表。有些约束只在全局层面才有意义,没有任何局部规则能够表达它们:连续块、整个时间范围内可接受的 GPU 切换次数预算、保证运行中的工作永远不会被抢占。要尊重这些约束,问题必须被写成一件完整的事。
五条约束定义了一个合法的分配:
每块 GPU 在每个时间步最多服务一个任务。
每个任务都遵守其需求范围,已经在运行的任务被继承并保持。
批处理类任务占用连续 GPU 块,大小为 2 的幂次。
实时任务在连续时间步之间可交换的 GPU 数量有硬性上限。
已启动的任务不能被中断。
目标函数有两个项。将 GPU 分配给批处理类任务获得的奖励等于其优先级乘以一个时间衰减权重。未满足实时需求将招致惩罚,惩罚与缺口的规模成正比。
这些权重的相对大小就是整个服务级别策略,表达为一个数字。实时惩罚权重比分配权重高 5 到 10 倍。因此,一单位未满足的实时需求的代价相当于 5 到 10 个同等优先级批处理工作 GPU 时间步的代价。这种不对称是刻意的,它意味着延迟义务在同一个优化过程中被执行——即放置批处理工作的同一个优化——而不是由一个独立的自动扩缩器与调度器争夺同一批 GPU。
这也使得对实时需求的弹性处理变得安全。在低谷期,分配器可以将 GPU 分配给批处理工作,因为后续未满足实时需求的惩罚——而非任何批处理工作的收益——要高得多;正是这种惩罚机制,而非静态预留,保护了服务的可用性。
时间权重在时间范围上衰减的原因,只有在在线系统中才讲得通:到下一次调度运行时,新的作业已经到达。当下使用的容量比承诺给后续的容量更有价值。
形式化模型定义了什么是一次合法且得分高的分配。响应传入请求是一项独立作业,属于独立组件。这是一个 NP 难的组合分配问题,而且调度器在每次作业到达时都会被重新调用,因此决策必须在两次 API 请求的间隙中返回。这个延迟预算是架构设计所围绕的固定约束,这就是为什么启发式方法位于热路径上,而形式化模型位于其后,作为启发式方法构建所依据的规范。
这个启发式方法并非通用的贪心分配器。它的规则来自形式化模型的结构约束,这意味着它生成的每个网格都是按构造合法的分配。不是通常意义上的合法,而是设计上的合法。
这种设计应用于整个时间范围而非逐个到达地处理,正是产生利用率提升的原因。分配器在放置任何作业之前就能看到所有排队的作业,它可以将空闲池保持成剩余工作实际能够占用的形状,一个需要连续块且大小固定的批处理作业在轮到它时仍有空间。优先级决定谁先占用这个空间。FIFO 两者都看不到:它将容量承诺给最先请求的作业,而后到达的需要特定形状的作业可能找不到任何合适的剩余空间,导致无法被调度,它本应消耗的 GPU 小时数也就被浪费了。
在五个争用场景中,分配器运行时间为 1 到 2 毫秒,在 64 个 GPU 和 30 个作业的场景下为 15 毫秒——足以在每个传入请求上运行。
系统暴露两种模式。快速模式单独运行分配器并返回其网格;这是热路径。完整模式将该网格作为形式化模型的起点,试图对其进行改进——适用于周期性审查而非逐请求决策。
在除一个场景外的所有场景中利用率都有提升,该场景恰好持平。在全部七个场景中价值都有提升。
规模测试之所以重要,是因为它证明了在规模上的稳定性:64 个 GPU、30 个作业、15 毫秒、价值提升 15.9%。
均匀优先级测试之所以重要,是因为它回应了显而易见的质疑。将每个作业的优先级覆盖为相同优先级,使得没有任何优先级信号可以区分它们,分配器仍然将利用率从 76.8% 提升到 87.5%,价值提升 23.1%。收益并非纯粹来自按优先级排序。跨时间范围规划放置本身就有贡献。
以上所有内容都假设调度器知道每个作业需要多少 GPU 小时数,以及将有多少实时流量。两者都是预测,而非输入,调度器的好坏完全取决于它们。
单个通用估算器无法工作,因为四种工作负载类型有本质不同的成本驱动因素。这正是前文 specialization 论点的重新连接:使任务特定模型优于通用模型的相同逻辑,同样适用于为调度器提供信息的估算器。
训练并非单一工作负载。它沿着两条独立的、可自由组合的轴变化。策略决定有多少模型被更新(全量微调对比 LoRA 等参数高效方法)。技术决定优化目标和训练循环(SFT、DPO、RLHF、RLVR、CPT)。差异并非边缘性的:LoRA 在相同基础模型上,将可训练参数削减最多 10,000 倍,GPU 内存削减约 3 倍(对比全量微调)。DPO 移除了 RLHF 的奖励模型和采样循环。仅从模型大小估算会在运行结果中取平均值,而这些运行在调度器所依据的两个量——持续时间和 GPU 数量——上相差数个数量级。我们的训练预测器以 22 个特征为条件,包括一个区分 10 种具体训练变体的分类变量。
量化是一项可调度的作业,而非后台琐事。量化单个大模型可能消耗其他工作正在等待的 GPU 硬件数小时的时间。它有自己的预测,基于参数计数的校准层级构建,对每种算法(bitsandbytes、AWQ、GPTQ)有区分处理,并在向上取整到完整 GPU 小时数之前留有安全边际。该领域的先前工作将量化完全置于调度范围之外。
实时推理根本不是按作业估算的。它被预测为持续重新校准的每周需求曲线,从小时级流量历史重建,并在与形式化模型强制执行的相同交换成本下映射到 GPU 数量。因此预测器和优化器对什么是切换成本达成一致,而非产生分歧并相互对抗。正是这个预测取代了峰值预留。逐时间步的需求曲线是调度器在低谷期释放 GPU 的唯一保障,使其确信这些 GPU 可以在下一个峰值到来之前被回收。
这又回到了排序论 Better demand estimates are what make priority-aware placement possible in the first place,没有对作业消耗量的了解,就无法对作业进行良好的排序。
对这一切的明显反驳是:预测是错误的。那会发生什么?
需要避免的失败模式有一个值得借用的名称:世界末日效应(end-of-world effect)。一个看不到时间范围终点的优化器,会做出在时间范围之外的下一个时间步造成破坏的当前决策,因为对模型而言,时间范围之外什么都不存在。
该架构同时回答了这两个问题。调度器优化 24 小时时间范围,但只提交当前时间步,并每 30 到 60 分钟重新运行一次。在 9 点运行时,9 点的分配是真实的;10 点到下午 5 点的计划仅存在于使 9 点决策由一个知道未来存在的模型做出。真正的 10 点分配来自 10 点的运行,使用的是新数据。
其结果是预测误差被重新优化吸收,而非累积。每次运行都继承实际正在运行的内容并将其固定到位,因此后续计划是更新而非振荡。
这还有二次收益。时间范围计划本身就是一种预测产品:它在到来之前就揭示了实时覆盖风险和可预测的空闲窗口,无论这些具体分配是否最终被提交,这都很有用。
这也正是时间衰减权重存在的原因。到下一次运行时,工作负载组合将已经发生变化。
航空公司并非通过计算最优时刻表来解决利用率问题。它们通过将操作规范编码到事情发生的顺序中(周转序列、维护窗口、机组排班)并让这种规范产生复合效应来解决。
这里发生了同样的事情。在最拥挤的场景中获得 33 个百分点的利用率,在平均情况下获得 52% 的优先级加权产出,使用相同的硬件、相同的工作负载、在几毫秒内完成——这些都来自将集群的物理允许条件编码到决策顺序中。结构胜过了精巧。
前文论证了专业化和编排是一个问题的两个 half:专业化缩小每个工作负载的需求,编排决定差异去向。两个杠杆单独都无法发挥价值。这就是第二个 half 被构建后看起来的样子。
GPU 已经安装完毕、已经承诺使用、已经在折旧。收益来自于我们如何选择花费它们。
![]()
![]()
![]()
![]()
![]()
本文中提到的模型 1
本文中提到的 Spaces 1