你的现代化 GPU 集群在理论上拥有惊人的峰值性能。但对许多团队来说,现实却截然不同。你常常会看到平均 GPU 利用率骤降到 30% 以下。承诺与现实之间的这道鸿沟,会让你付出高昂代价。怎样才能把 GPU 利用率推近 90%?那些依然闲置的 GPU 又该如何处理?在这种面向大语言模型工作的 AI 训练环境中,你必须采取严谨的方法。规模、成本与算力浪费带来的运维痛点,要求你立刻行动。每一块闲置的 GPU,都是对预算和进度的直接打击。在如此规模下管理一个 LLM,几乎容不得任何低效。你需要一套清晰的训练优化策略。

为大语言模型训练定义 GPU 利用率指标

为什么原始利用率百分比会误导你

你打开 nvidia-smi,看到 GPU 利用率是 100%。你以为硬件运行得无比完美。这个判断其实并不成立。你看到的这个百分比,衡量的只是一个非常狭窄的维度。它只跟踪在采样窗口期间,是否有任何内核在执行。它并不能衡量你的模型是否高效利用了硬件。

根据 NVML 的定义,“utilization(利用率)”表示在过去一个采样周期内,某些活动发生的时间百分比。GPU utilization 表示一个或多个内核执行时所占的时间百分比。Memory utilization 表示全局内存被读取或写入时所占的时间百分比。

考虑一个简单的内核:它只在一个 Streaming Multiprocessor 上运行无限循环。你的 GPU 可能拥有几十个 SM。真正的计算使用率,其实等于 1 除以 SM 总数。然而,nvidia-smi 仍可能显示 100% 利用率。这样的差异会制造一种虚假的信心。你以为自己昂贵的集群已经在最佳状态下运行。实际上,你的模型可能只是轻微触及了硬件能力。原始利用率数字掩盖了真相,也掩盖了你的 AI 训练效率问题。

关键指标:MFU、HFU 与内存带宽

你需要更好的测量方式。模型 FLOPs 利用率(Model FLOPs Utilization,MFU)能提供更清晰的视角。MFU 将模型实际执行的浮点运算,与硬件理论峰值进行对比。这个指标能揭示你究竟利用了多少 GPU 的数学计算能力。

硬件 FLOPs 利用率(Hardware FLOPs Utilization,HFU)则提供了另一个角度。它会把硬件执行的所有操作都计算进去,包括那些低效的操作。很多时候,真正的约束并不是计算,而是内存带宽。你的模型可能不是在等算力,而是在等数据搬运。GPU 之间的通信开销同样会造成停顿。这些瓶颈,比单纯的 SM 活跃度更重要。你必须把这些指标结合起来一起跟踪。它们会揭示你的 LLM 训练究竟把性能浪费在了哪里。只有这样,你才能真正找到优化机会。

识别大语言模型训练中的瓶颈

计算、内存与通信开销

一次大语言模型训练,通常会遭遇三类主要瓶颈。计算受限的层会把算术单元推到极限。内存受限的权重更新会因为等待数据搬运而停滞。通信受限的梯度同步,则会让整个集群在 GPU 交换梯度时暂停。每一种瓶颈,都会偷走原本可用于有效工作的时间。

通信开销往往破坏力最大。一个拥有 1,000 块 GPU 的集群,理论能力极其惊人。但在实践中,硬件花在“交谈”上的时间,往往比“思考”还多。

一个拥有 1,000 块 GPU 的集群具备惊人的理论能力,但在实际中,硬件往往把更多时间花在“交谈”而不是“思考”上。在分布式训练中,梯度同步就是瓶颈。如果某个节点的反向传播晚了 10 分钟才完成,那么整个集群都必须等待,这会导致长时间的空闲计算时间。

梯度同步中的 all-reduce 就会带来这种延迟。在朴素的数据并行训练里,每个参数张量都需要各自进行一次 all-reduce。成千上万次小型操作,每一次都要承担启动延迟。整个集群就在等待通信完成。你可以通过更好的算法来降低这部分开销:

算法

延迟步数

对 GPU 空闲时间的影响

Ring All-Reduce

2(N-1) 个顺序步骤

在大规模场景下延迟较高;空闲时间会随 GPU 数量线性增加。

Tree All-Reduce

2*log2(N) 个步骤

延迟更低;与 ring all-reduce 相比,可在大型集群中显著减少空闲时间。

Tree All-Reduce 将延迟步数从线性降低到对数级。这样一来,集群等待的时间就更少。内存受限的操作同样会偷走性能。权重更新和优化器步骤都需要读写参数。一次优化器更新,需要从内存中读取完整的模型状态。此时内存带宽就会成为限制因素。像大型矩阵乘法这样的计算受限层,确实能让一块 GPU 保持忙碌,但即便如此,仍然存在优化空间。

存储与数据加载:隐藏的罪魁祸首

你可能已经优化了每一个计算与通信步骤,可 GPU 还是处于闲置状态。真正的原因,往往隐藏在存储 I/O 里。很多数据科学家会看到 GPU 利用率低到 30%,原因就是在等待数据加载。计算流水线会停住,因为硬件完成工作的速度,比存储系统提供新数据的速度还快。

LLM 训练流水线依赖高速的数据供给。如果存储系统跟不上,集群里的每一块加速器都只能等待。规模越大,这个问题越严重。你必须精心设计数据加载流水线。使用异步预取。缓存高频访问数据。把训练数据放在高速本地 NVMe 盘上。每一步,都是在减少硬件等待数据的时间。优化 AI 训练流水线,意味着要关注整条链路上的每一个环节。

通过并行化最大化 GPU 利用率

平衡数据并行、张量并行与流水线并行

你无法只用单个设备训练一个大语言模型。模型本身就会超过任何单块 GPU 的内存容量。你必须把工作拆分到多块 GPU 上。主要有三种拆分策略。每一种在通信开销与计算效率上都有不同权衡。选对组合,会直接影响整体性能。

数据并行会在每个加速器上复制完整模型。每个设备处理不同批次的数据。每个训练步骤之后,设备之间通过 all-reduce 交换梯度。这种方式的通信频率较低。但它要求单个模型能够装进单个设备。对于超大模型来说,光模型本身就已经超限了。

张量并行则把单层的权重切分到多块 GPU 上。每个设备持有每个张量的一部分。设备之间必须在每一层内部反复交换中间结果,并通过 all-reduce 完成同步。这会带来很高的通信开销。这种技术要求使用像 NVLink 这样的高带宽互连。更高的张量并行度会降低每个设备的内存占用,但也会缩小矩阵规模,导致那些为大矩阵优化的核心得不到充分利用。

流水线并行会把模型分成若干阶段。每个阶段由一组连续层组成。某个设备组负责一个阶段。激活值在阶段之间传递。这种方式的通信频率较低,但会遭遇 pipeline bubble(流水线气泡)——也就是阶段间的空闲时间。某个较慢或内存负载较高的阶段,会拖慢后续所有阶段。

对于超大模型,你必须把这三种策略结合起来。这种方法被称为 3D 并行,即把数据并行、张量并行和流水线并行叠加使用。它的通信成本最高。你需要具备拓扑感知能力的调度方式,才能避免瓶颈。多数生产系统会采用混合配置,例如张量并行度为 2、流水线并行度为 2。这样的平衡可以在拆分模型的同时,把通信控制在可接受范围内。某些模型规模下,经过改造的 ZeRO stage-3 变体,在通信开销上甚至可能优于张量并行。

通过微批处理减少流水线气泡

在流水线并行中,pipeline bubble 是最主要的空闲时间来源。气泡大小取决于阶段数与微批次数。其低效程度大致与 \(Nstages – 1\) 除以 \(Nmicrobatches\) 成正比。若有 8 个阶段、16 个微批次,理论气泡可达到约 44%。

微批处理能够降低这种气泡。与其处理一个大批次,不如把它拆成许多更小的微批次。你把这些微批次一个接一个地送入流水线。这样便能在所有阶段中形成稳定的工作流。预热阶段依旧存在一些空闲时间,但在稳态下,各阶段都能持续保持忙碌。

1F1B 调度比早期方法更高效。它包括一个预热阶段、一个稳态阶段——每个 worker 执行一次前向传播和一次反向传播——以及一个收尾阶段,用于完成剩余反向传播。与 GPipe 方法相比,它降低了内存使用。

更先进的调度策略,例如 Zero Bubble,可以通过把前向与反向计算进一步拆分成更小单元,来继续减少空闲时间。这些策略会交错安排反向传播中的不同计算部分,从而在保持同步训练优势的同时,将气泡压缩到接近于零。对于最大化 AI 训练吞吐而言,这一点至关重要。

但微批处理也有代价。要减少气泡,就需要足够多的微批次。这往往会迫使你采用非常大的全局 batch size。过大的 batch size 可能损害收敛效果。当你把流水线并行与数据并行结合时,还必须考虑单设备 batch size 被进一步摊薄的问题。你必须在高吞吐与高模型质量之间取得平衡。对于 8 个流水线阶段,理论效率可达 87.5%。但现实系统通常只能达到 60% 到 75%,原因在于微批处理额外开销和负载不均衡。这是大规模 LLM 训练中的常见挑战。

优化训练循环以提升 GPU 利用率

利用混合精度与梯度累积

你可以通过从 FP32 切换到 BF16 来提升吞吐。下表展示了二者的关键差异:

指标

FP32

BF16(混合精度)

A100 Tensor Core 吞吐

较低

约 312 TFLOPS

每个数值的内存占用

32 位

16 位(减少 50%)

动态范围

与 FP32 相同

与 FP32 相同

是否需要 loss scaling

不需要

不需要

BF16 为指数分配 8 位、为尾数分配 7 位。因此它拥有与 FP32 相同大小的指数位。它的动态范围与 FP32 一致。这样你就能避免下溢和上溢问题,也不需要 loss scaling。每个数值减少 50% 的内存占用,意味着你可以使用更大的 batch size。更小的数据体积也会减少传输量,从而带来性能提升。

梯度累积能让你在不增加额外内存成本的前提下,模拟更大的 batch size。标准批处理会增加内存使用,因为你必须保存中间激活值。梯度累积改变了这个过程。你用更小的 micro-batch 处理数据。你在这些 micro-batch 之间累加梯度。只有在累积到足够多的梯度之后,才更新参数。有效 batch size 等于 micro-batch size 乘以 gradient steps 再乘以 device count。这个技巧与数据并行配合良好,因为每个设备都可以独立累积梯度。你也可以把它与跨多节点的数据并行结合起来使用。通过平滑计算峰值,你可以让 GPU 利用率维持在较高水平。

精简数据加载与预处理

你的加速器完成计算的速度,可能快于存储系统提供数据的速度。这种不匹配会导致空闲时间。你必须精简数据流水线。

使用异步预取和快速本地存储,把数据加载与计算重叠起来执行。这样可以消除停顿,让你的硬件在 LLM 训练期间始终保持高效运转。

使用分析工具诊断闲置 GPU

通过监控识别闲置状态

你需要看清每一秒钟加速器究竟在做什么。使用可用的 GPU 监控工具来跟踪 SM 活跃度和内存带宽利用率。较低的 SM 活跃度说明 GPU 正在等待,而不是在计算。

监控“至少有一个 warp 处于活跃状态的时间占比”。如果这个值低于 0.5,就说明利用效果不佳。若数值非常低,则表示 SM 在大部分时间里都处于空闲状态。内存带宽利用率则揭示了内存接口是否在积极传输数据。如果这里的数值也很低,就表示你的硬件是在等待,而不是在工作。

常见的闲置模式及其根因

你会遇到几种反复出现的闲置模式。同步屏障会造成最明显的停顿。当某个节点完成反向传播的时间较晚时,其他所有加速器都必须等待。这种模式会表现为所有设备同时出现周期性的活跃度下跌。

Pipeline bubble 是另一个持续存在的元凶。流水线并行天生就会引入这种空闲模式。微批次按顺序穿过各个阶段。流水线必须排空,然后新任务才能继续进入。在这个转换过程中,有些 GPU 会暂时空置。即使使用了优化调度,仍然可能产生显著的空闲时间。

I/O 瓶颈会导致长时间的闲置。有研究表明,训练时间中多达 70% 可能花在等待数据上,导致 GPU 处于空闲状态。识别这些“指纹”有助于你精准锁定优化方向。你的 LLM 训练性能,取决于你是否能判断哪一种模式主导了当前工作负载。只有这样,你才能对症下药。

通过动态调度处理闲置 GPU

你无法仅靠优化就消除所有空闲周期。同步屏障、流水线气泡和数据加载等待,总会留下空档。问题在于,你要如何利用这些空档。动态调度提供了一种解法。你需要把集群视作一个活的系统。作业会根据实时可用资源进行伸缩。

实现弹性训练与抢占

弹性训练会改变作业边界。你不再定义一个固定的 worker 数量,而是定义最小值和最大值范围。TorchElastic 是 PyTorch 的工作负载管理工具,它让这种方式变得切实可行。你可以在作业定义中设置 minReplicasmaxReplicas。系统会在这个范围内上下扩缩 worker,而不必中断训练。

这种架构会把控制平面组件与 worker 节点分离。你把 TorchElastic controller 和 Rendezvous server 运行在不可抢占的 CPU 节点上。这些核心组件必须保持可用。worker 则运行在 GPU spot instance 上。成本节省就来自这种部署方式。当某个 spot 节点被驱逐时,TorchElastic 不会让整个作业失败。只有当活跃 worker 数量跌破 minReplicas 时,controller 才会判定作业失败。否则,它会重新调度丢失的 pods,并从最近一次 checkpoint 恢复训练。

这种设计能优雅地处理抢占。失去一个 worker 变得可以接受。你的训练数据和作业状态存放在挂载的云存储上。系统可以无缝恢复。这样一来,原本可能闲置的 GPU 时间,就被转化成了可产生价值的训练周期。

缩容与暂停之间的取舍非常关键。缩容会释放 GPU 给其他作业使用。暂停则会保留资源分配,但让它们处于空闲状态。对于存在竞争性工作负载的集群来说,缩容更高效。你可以把硬件释放给更高优先级任务。暂停只适合很短暂的空档。但如果暂停时间较长,就会浪费容量。具体选择取决于你的工作负载结构。对于 LLM 训练而言,在可预测的空闲期进行缩容,通常是更优方案。你既能把硬件回收给其他任务使用,又保留了在需要时再次扩容的能力。

Kubernetes 中的动态资源分配

Kubernetes 把这种动态行为扩展到了整个集群。NVIDIA GPU Operator 负责部署所需组件。GPU Device Plugin 以 DaemonSet 形式运行在每个 GPU 节点上。在初始化期间,插件会调用 NVIDIA Management Library(NVML)查询可用 GPU。它会获取显存容量、计算能力以及互连拓扑等信息。随后,插件通过 nvidia.com/gpu 这个资源名,将这些 GPU 注册给 kubelet。Pods 便可通过标准资源声明来申请 GPU。

你必须决定,如何在多个工作负载之间共享 GPU。主要有三种方案。下表总结了它们之间的权衡:

方案

隔离性

灵活性

最适用场景

MIG

强(硬件级)

静态(预定义配置文件)

推理、多租户

Time Slicing

弱(无显存隔离)

动态(无需预先分区)

Notebook、批处理作业

Custom Scheduler

软隔离(基于调度策略)

高度可配置

受信任的内部用户

Time slicing 可运行在任何 NVIDIA GPU 上。它是最容易起步的方案。但它不提供显存隔离,也不提供故障隔离。MIG 提供硬件级隔离和可预测性能,但依赖静态配置文件。重新配置 MIG profile 在运维上较为复杂,甚至可能需要重置 GPU。Custom scheduler 拥有很高的灵活性,但代价是更高的运维复杂度。你需要根据自身工作负载需求来做选择。

具备 GPU 感知能力的调度机制,可以让闲置资源转化为有效工作。你可以把一个节点配置为让多个 pods 共享其 GPU 时间。某个 pod 在流水线气泡期间运行,就等于利用了本来会白白流失的算力周期。NVIDIA GPU Operator 负责管理所有 GPU 相关资源的部署与生命周期。它会部署驱动、设备插件和监控工具。GPU Feature Discovery 组件会扫描节点上的 GPU 能力,并将显存大小与 CUDA capability 等信息暴露出来,供工作负载使用。MIG Manager 则允许把硬件切分为更小的实例。每个分区都可以分配给不同工作负载。这样一来,一块物理 GPU 就能被多个工作负载共享,从而最大化 GPU 利用率。

LLM 训练作业保留其已分配的容量。辅助任务则去填补空隙。每一个空闲周期,都会变成一次产出价值的机会。

将闲置 GPU 重新用于辅助工作负载

在流水线气泡期间进行推测式推理

Pipeline bubble 会在训练计划中制造出可预测的空档。这些 GPU 空闲窗口会规律性地反复出现。你可以用它们来做有价值的工作。推测式推理就是一个很有吸引力的选择。这种技术会让草稿模型先于主验证模型运行。草稿模型提前生成 token 序列。随后,你的主模型并行验证多个 token。这样就能在不牺牲准确性的前提下,加速推理过程。

SpecInF 就是这一思路的一个实际实现。该系统会在计算气泡期间调度推测式推理任务。训练作业始终保有最高优先级。推理工作只在空档中填充执行。这样一来,浪费掉的周期就转化成了有价值的输出。你获得了额外的推理吞吐,却不必延长训练时间线。关键在于调度精度。你必须让推理任务与每一个气泡的精确持续时长相匹配。较短的气泡适合小型草稿模型。较长的空档,则可以容纳更重一些的验证工作。

在资源隔离下运行辅助任务

除了推理之外,你还可以在空闲时段运行其他工作负载。数据预处理通常会消耗大量 CPU 时间。你可以在训练暂停期间,把这类工作卸载到 GPU 上。针对验证集的评估任务也很适合。它们需要的是突发式算力,而不是持续占用。对更小模型进行面向下游任务的微调,也是一个可行选项。每一种辅助作业,都能为你的 LLM 生态增加价值。

在共享硬件时,资源隔离至关重要。你绝不能让辅助任务拖慢主训练作业。硬件分区方案,例如 NVIDIA Multi-Instance GPU(MIG),可以把一块物理 GPU 划分成多个相互隔离的实例。每个分区都拥有专属的显存和计算切片。这种硬件级隔离可以防止互相干扰。Time slicing 则提供了更灵活的替代方案。多个工作负载通过快速上下文切换来共享同一块 GPU。这种方式可运行在任何 NVIDIA 硬件上。然而,它的隔离能力弱于 MIG。

你的选择取决于工作负载特征。MIG 适合对性能有严格要求的生产环境。Time slicing 更适合探索性任务和开发工作。你还必须考虑安全边界。不受信任的工作负载需要 MIG 提供的更强隔离。受信任的内部任务则可以安全地使用 Time slicing。这种资源分配策略,能确保每一块 GPU 都在创造价值。你的训练性能得到保护,而闲置容量则被用于其他用途。最终结果,是一个持续朝多个目标同时运转的集群。

从原始利用率指标,到动态调度系统,你已经走过了一条完整路径。这段过程揭示了一个根本事实:实现高 GPU 性能,并不是一个终点,而是一个持续进行分析、调优与适配的循环。每一次训练运行,都会暴露新的瓶颈。每修复一个问题,往往又会显露出更深一层的约束。

大规模 LLM 工作的未来,在于可组合、可弹性的基础设施。闲置 GPU 应该被视为一种设计缺陷,而不是不可避免的现实。你必须把每一块未被使用的加速器都看作一种机会。建立“资源 stewardship(资源治理)”的思维方式。用辅助任务填补空档。条件允许时就缩容。把空余容量重新投入评估任务或更小模型。你的训练会从这种纪律性关注中受益。你的预算也会因此受益。你的 GPU 的每一个周期,都应该产生价值。把这一点,变成你的标准实践。

常见问题

原始 GPU 利用率和 MFU 有什么区别?

原始利用率只跟踪在一个采样周期内是否有任何内核运行。即使你的硬件几乎没有真正发力,它也可能显示 100%。MFU 衡量的是实际算术效率相对于理论峰值的比例。这个指标更能揭示你的 LLM 训练真实性能。

我该如何找出训练中的主要瓶颈?

使用监控工具跟踪 SM 活跃度和内存带宽。同步屏障通常表现为所有 GPU 同时出现活跃度下跌。流水线气泡则表现为规律性的空档。若数据加载跟不上,存储 I/O 就会造成停顿。

我能在不拖慢主任务的情况下使用闲置 GPU 吗?

可以。你可以使用硬件分区或 Time slicing 实现资源隔离。在流水线气泡期间调度推测式推理。也可以在空档中运行数据预处理或评估任务。动态调度工具能够高效管理这些资源。

大规模分布式训练中的流水线气泡是怎么产生的?

流水线气泡发生在不同阶段完成时间不一致时。某个较慢的阶段会拖住后续所有 GPU。微批处理可以减少空闲时间。更先进的调度技术还能进一步压缩这些空档。