PyTorch:训练与微调的调度语义与抢占影响

草稿

训练平台的本质挑战不是“GPU 够不够”,而是如何把调度语义变成可治理的资源服务。

训练/微调与在线推理看似都“吃 GPU”,但它们对平台的压力点完全不同。推理更像排队系统(到达率、并发、尾延迟),训练更像生产流水线(持续吞吐、同步通信、拓扑敏感)。因此,推理平台做得好不等于训练平台就能跑得稳。训练要稳定、要效率,核心不在“能启动多少卡”,而在“能否持续产出有效步数”。

本章聚焦三个问题:

  • 训练/微调的资源曲线是什么?为什么它比推理更敏感、也更容易被共享、抢占、碎片化击穿?
  • 训练作业需要哪些调度语义?例如最小可用、成组调度、拓扑亲和、可抢占、可挂起。
  • 资源紧张时怎么维持整体效率?抢占与弹性策略如何设计,才能让平台“忙而不乱、抢而不崩”。

训练/微调的资源曲线:稳定吞吐优先,而非瞬时峰值

训练与推理的性能瓶颈表现不同。在线推理常见“QPS 与 P99 的冲突”,而训练/微调则是“有效吞吐(有效 tokens/steps)与系统摩擦(通信/抖动/重启)的冲突”。

训练的关键资源特征如下:

  1. 持续性

    训练通常是小时/天级任务,价值来自连续推进的 step。任何中断都会引入无效成本(回滚、重建 cache、重新 warmup)。

  2. 同步通信与拓扑敏感

    分布式训练(如 DDP、FSDP、ZeRO)依赖高频 collective(AllReduce/AllGather)。这类通信对节点内 NVLink、节点间 RDMA、网络拥塞极其敏感:

    • 同样的 GPU 数量,跨机分散往往显著慢于同机集中。
    • “坏邻居”带来的网络抖动会直接映射为 step time 抖动。
    • 一张慢卡可能拖慢整个同步组(典型的“拖尾”)。
  3. 资源单位更刚性

    推理可以在共享方案下“切小块”跑起来;训练往往需要固定数量的 GPU + 固定拓扑约束才有意义。可以理解为:要么成团满足,要么就不该启动。

  4. 显存与 IO 的相互制约

    微调(尤其 LoRA/QLoRA)表面上更轻,但仍可能被显存碎片、数据加载瓶颈、checkpoint IO 限制。训练的“资源曲线”不是单维 GPU utilization,而是 GPU/CPU/内存/网络/存储的耦合曲线。

结论: 对训练而言,“让作业快点开始”不如“让作业开始后别掉速、别中断”。因此调度系统要支持:成组准入、拓扑约束、抢占策略、可恢复机制。

训练工作负载分层:你调度的是“语义”,不是 Pod

治理训练/微调时,建议按“调度语义”分层,而不是按框架或模型分层:

A 类:单机微调/小规模训练(1~N GPU,单节点)

  • 目标:快速周转、低运维成本。
  • 典型:LoRA、短跑实验、评估任务。
  • 调度重点:排队公平、基本配额、低抢占损失。

B 类:分布式训练(多节点 DDP/FSDP,强同步)

  • 目标:稳定 step time,避免跨域/跨机不确定性。
  • 调度重点:最小可用(min-available)、成组调度(gang)、拓扑(机内优先、机架/域约束)、低抖动环境。

C 类:弹性训练(可伸缩 worker、容忍波动)

  • 目标:在资源紧张时保持总体吞吐最大化。
  • 调度重点:允许伸缩/重排、与自动扩缩容协同、抢占后快速恢复。

平台治理的关键是:不同层的作业要用不同的承诺模型。A 类可以"尽快跑";B 类必须"整团满足";C 类才适合机会式资源。

下图展示训练工作负载的分层分类。A 类(绿色):单机微调/小规模训练(1~N GPU,单节点),目标快速周转、低运维成本,调度重点是排队公平、基本配额、低抢占损失。B 类(黄色):分布式训练(多节点 DDP/FSDP,强同步),目标稳定 step time 避免跨域不确定性,调度重点是最小可用 min-available、成组调度 gang、拓扑约束、低抖动环境。C 类(蓝色):弹性训练(可伸缩 worker,容忍波动),目标资源紧张时保持总体吞吐最大,调度重点是允许伸缩重排、与自动扩缩容协同、抢占后快速恢复、机会式资源利用。底部灰色区域展示训练的四个关键资源特征:持续性、同步通信与拓扑敏感、资源单位更刚性、显存与 IO 相互制约。结论:对训练而言让作业快点开始不如让作业开始后别掉速、别中断,调度系统必须支持成组准入、拓扑约束、抢占策略、可恢复机制。

图 1: 训练工作负载分层:你调度的是语义,不是 Pod
图 1: 训练工作负载分层:你调度的是语义,不是 Pod

PyTorch 训练需要的调度语义清单

训练系统落到 Kubernetes 时,最容易踩的坑是:把“训练作业”降维成“Pod 集合”,于是丢掉了语义。要让训练可治理,需要至少具备以下语义(由控制面实现,而非靠用户自觉):

最小可用(Min-Available)

分布式训练常见需求:没有足够 worker/PS/launcher 就不要启动。否则会出现:

  • 只启动了一部分 worker,反复 crash / backoff;
  • 训练框架一直等 rendezvous,造成 GPU 空转;
  • 资源被占着不产出,形成隐性浪费。

成组调度(Gang Scheduling)

训练的基本单位是一个“组”(一个 job),不是单个 Pod。成组调度解决两件事:

  • 同时分配:避免分配到一半卡住;
  • 一致性:保证训练拓扑与通信预期一致。

拓扑与亲和(Topology Awareness)

对训练而言,拓扑优先级通常是:

  1. 同一节点(NVLink/共享内存)
  2. 同机架/同网络域(RDMA/更低抖动)
  3. 跨域(最不稳定)

如果控制面无法表达拓扑偏好,训练会被随机摊开,导致吞吐不可预测。

可抢占(Preemptible)与不可抢占(Guaranteed)

训练平台必须允许用户声明“可抢占”层(低优先级、容忍中断)与“保证层”(关键训练、不可随意打断)。否则多租户下要么大家都不敢跑大任务,要么谁都在抢占别人。

可挂起/恢复(Suspend/Resume)

比“杀掉重启”更温和的治理手段是“挂起”:

  • 把训练从运行态转为等待态,释放 GPU;
  • 资源回来后再恢复;
  • 结合 checkpoint,降低抢占损失。

这会显著改善资源紧张时的整体效率与用户体验(尤其是大作业)。

下图展示 PyTorch 训练需要的 5 种核心调度语义。最小可用(Min-Available):没有足够 worker/PS/launcher 就不要启动。成组调度(Gang Scheduling):同时分配与一致性,保证训练拓扑与通信预期一致。拓扑与亲和(Topology Awareness):优先级从高到低为同节点(NVLink)、同机架(RDMA)、跨域(最不稳定)。可抢占/保证(Preemptible/Guaranteed):声明可抢占层(低优先级)与保证层(关键训练)。可挂起/恢复(Suspend/Resume):比杀掉重启更温和,结合 checkpoint 降低抢占损失。右侧灰色区域强调这些语义由控制面实现而非靠用户自觉:Kueue 负责准入配额优先级与公平,Volcano 负责成组调度与策略落地,数据平面定义资源单位与隔离边界。底部展示拓扑优先级,核心理念:把训练作业降维成 Pod 集合会丢失语义,要让训练可治理需要完整的调度语义支撑。

图 2: PyTorch 训练需要的调度语义清单
图 2: PyTorch 训练需要的调度语义清单

抢占的真实代价:你抢走的是"已完成的有效工作"

抢占不仅仅是“把 GPU 让给更重要的人”,它伴随三类成本:

  1. 重启成本(Restart Overhead)

    重新拉起容器、重新下载权重/数据、重新初始化通信组。

  2. 回滚成本(Rollback / Lost Progress)

    checkpoint 周期越长,被抢占损失越大;周期越短,IO 压力越大。这是一个可度量的权衡。

  3. 震荡成本(Systemic Thrashing)

    如果抢占策略不稳定,会出现“你抢我、我抢你”的系统性抖动:

    • GPU 使用率看似很高,但有效训练吞吐下降;
    • 队列里作业频繁切换,整体完成时间变长;
    • 用户感知为“平台不靠谱”。

抢占策略的目标不应是“让某个高优先级作业立刻启动”,而是:

在满足关键作业 SLA 的前提下,让全局有效吞吐最大,并把无效成本控制在可接受范围内。

下图展示抢占的三种真实成本。重启成本(红色):重新拉起容器、重新下载权重/数据、重新初始化通信组、重新 warmup。回滚成本(黄色):checkpoint 周期越长被抢占损失越大,周期越短 IO 压力越大,这是一个可度量的权衡。震荡成本(蓝色):GPU 使用率高但有效训练吞吐下降、作业频繁切换整体完成时间变长、你抢我我抢你的系统性抖动、用户感知为平台不靠谱。绿色区域说明抢占策略的正确目标:在满足关键作业 SLA 的前提下让全局有效吞吐最大并把无效成本控制在可接受范围内,而不是简单让某个高优先级作业立刻启动。灰色区域列出降低抢占损失的 5 种策略:区分可抢占层与保证层、制定 checkpoint 规范、引入挂起恢复机制、避免震荡、分离训练与推理资源池。底部核心洞察:抢占不是免费的,真正的代价是已完成的有效工作和系统稳定性。

图 3: 抢占的真实代价:你抢走的是已完成的有效工作
图 3: 抢占的真实代价:你抢走的是已完成的有效工作

把训练纳入队列治理体系:以 Kueue 为准入核心

推荐的治理分工如下:

  • Kueue:负责准入、配额、优先级与公平(Admission / Quota / Fairness)
    解决“谁能用、何时能用、能用多少”,并做全局资源承诺与统计。

  • 调度器/批处理控制面(如 Volcano 或具备同等语义的组件):负责成组调度与策略落地(Gang / Policy)
    解决“怎么分配到具体节点、如何满足 min-available、如何处理拓扑与抢占”。

  • 数据平面(MIG/共享方案):定义资源单位与隔离边界
    决定“一个训练作业申请的 GPU 单位到底是什么”。

这套组合能避免一个常见错误:用一个组件同时管准入、公平、拓扑与成组,最终谁都管不好。

推荐的落地路径(从易到难)

  • 阶段 0:先把训练从推理池里分出来
    最小化互相伤害:推理看尾延迟,训练看吞吐,两者混跑时冲突巨大。

  • 阶段 1:用 Kueue 建立队列与配额
    先做到可解释:每个团队有配额、作业进队列、等待有原因、使用可统计。

  • 阶段 2:为分布式训练引入成组与 min-available
    否则多节点训练会产生大量“半启动”浪费。

  • 阶段 3:引入抢占,但必须同时引入 checkpoint 规范
    没有 checkpoint 的抢占等于破坏性操作。

  • 阶段 4:引入弹性训练(可伸缩 worker)与机会式资源层
    把可抢占/可弹性的作业放到低成本资源上(空闲、夜间、可回收节点),提升全局利用率。

验收指标:训练平台要验“有效产出”,不是只看 GPU 利用率

建议把验收指标分三层:

作业级(Job)

  • Time-to-Start:从提交到开始训练的时间(含队列等待)
  • 有效吞吐:tokens/s 或 steps/s(建议对关键模型固定基准)
  • step time P50/P95:衡量抖动
  • 重启次数与恢复时间:抢占/失败后的恢复能力
  • checkpoint 开销占比:IO 成本是否可控

队列级(Queue)

  • 公平性:同优先级作业的等待时间分布
  • 阻塞与头阻塞(HOL):大作业是否长期卡住队列
  • 抢占损失率:被抢占导致的无效 GPU 时间占比

集群级(Cluster)

  • 有效训练吞吐总量(全局)
  • 跨作业干扰事件(网络/存储拥塞导致的抖动)
  • 碎片率:由于资源单位/拓扑导致的不可用碎片

关键风险点清单(评审时必须回答)

  1. 多节点训练是否强制 min-available + gang?否则大概率出现“占着资源不产出”。
  2. 拓扑不可控时,性能 SLO 如何保证?不能保证就要在产品层明确“best effort”。
  3. 抢占发生时,checkpoint 策略谁负责?频率如何约束?不回答就等于默认“抢占不可用”。
  4. 恢复时是否会造成队列震荡?需要明确:恢复优先级、冷却时间、最大并发恢复数。
  5. 训练与推理是否共享同一物理池?如果共享,必须有明确的隔离与优先级边界,否则推理尾延迟会被训练放大。

总结

PyTorch 训练/微调之所以难,不在于 GPU 数量,而在于它需要的平台语义更多:成组、最小可用、拓扑、可恢复、可抢占、可解释。当这些语义被治理体系(以 Kueue 为准入中心)承接后,训练就不再是“谁先抢到算谁的”,而是变成可评审、可实施、可验收的资源服务。

下一章将进入更具体的拓扑与分布式场景(Ray 与拓扑),把“语义”落实到可观测、可实验的结论链中。

创建于 2025/12/30 更新于 2026/01/05 4630 字 阅读约 10 分钟