去年我被拉进一个AI平台组,接手的第一件事,是给一个正在训练的模型调算力资源。当时的想法很简单——哪台机器闲,把任务排上去就行。真正动手才发现,任务跑得快不快,根本不只取决于显卡本身,还牵涉到隔壁任务的干扰、数据读取的阻塞、通信网络的拓扑、检查点保存的频率、甚至存储集群的抖动。那一次踩坑之后我才彻底想明白:AI Infra不是"硬件运维",更不是"算法辅助",而是一整套把算力、数据、模型、服务串起来的系统工程。
这篇笔记是我从零开始梳理AI Infra知识全景的记录,不追求面面俱到,只把真正影响工作、也最容易被新人忽略的几条主线讲透——算力资源管理、数据管道、分布式训练、推理服务、可观测性与成本治理。无论你是刚转做平台工程的研发,还是想搞懂"模型背后那套跑批系统"的算法同学,这篇都能给你一张可以照着查的地图。我会把每块知识的本质、常见误区、以及我在实际运维中踩过的坑一起写进去,尽量说人话。
1. 先画全景图:AI Infra到底在管哪几层
1.1 从训练任务到模型服务,中间夹着一层"隐形系统"
大多数人对AI系统的理解是一条直线:数据进模型,模型出结果。但真正跑过一个大规模训练任务的人会告诉你,这条直线是假的。你写好的模型代码只是其中一小部分,在它前后左右,还站着数据管道、资源调度、分布式通信、故障恢复、推理加速、监控告警这一整套东西。这套东西就是AI Infra。
我习惯把它拆成五个层面来看:
- 硬件资源层:GPU/加速卡、显存、CPU算力、存储、网络设备。这一层决定"天花板",比如单卡多少T算力、多少钱能换来多少显存。
- 资源调度层:把裸设备变成可以按需分配的资源池,涉及容器、队列、配额、优先级。这一层决定"能不能分得好"。
- 数据与训练支撑层:样本存储、读取、预处理、数据增强、分布式训练框架、检查点管理。这一层决定"训练跑多快、稳不稳"。
- 推理服务层:模型部署、批处理、缓存、量化、弹性伸缩。这一层决定"线上响应多快、成本多高"。
- 可观测与治理层:监控指标、链路追踪、成本账单、配额审计。这一层决定"出了事能不能及时发现、钱花哪了"。
每层解决一类独立问题,但又相互耦合。比如数据管道慢了,GPU利用率就会掉下去;调度策略粗糙了,共享集群里的大任务会把小任务"饿死";缺少监控,训练中断一个月你都不知道是哪天断的。
1.2 为什么AI Infra和传统后端不一样
很多从后端转过来的同学,最开始会对AI Infra感到别扭,因为它的思维方式和传统互联网后端差别很大。传统后端面对的是海量短请求,追求的是低延迟、高并发、削峰填谷;AI Infra面对的是少数几个超长任务,追求的是高吞吐、稳定推进、快速恢复。
我列过一张对比表,方便新人快速建立认知框架:
| 维度 | 传统后端 | AI Infra |
|---|---|---|
| 工作负载 | 大量短小请求 | 少量长时训练/推理任务 |
| 核心指标 | 延迟、QPS、可用性 | GPU利用率、训练吞吐、作业完成时间 |
| 失败模式 | 请求失败后重试即可 | 任务中断要恢复检查点,代价极高 |
| 资源形态 | CPU、内存,按实例弹性伸缩 | GPU显存、高速互联,拓扑敏感 |
| 主要瓶颈 | 服务逻辑与数据库 | 数据I/O、通信、显存容量 |
| 优化手段 | 缓存、异步、扩容 | 并行策略、混合精度、数据预取 |
这张表不是要分高下,而是提醒你:把后端的经验直接搬过来,十有八九会失灵。比如后端习惯"小步快跑、随时发布",而训练任务一旦跑起来,中断重来的成本可能是几十个小时的算力账单。
1.3 学习路径建议:先横向铺认知,再纵向挖细节
这个领域最劝退的地方是"什么都沾一点"。硬件、网络、存储、分布式、框架、运维、成本,每块单拎出来都是能写一本书的知识。我的经验是,不要一上来就扎进某个细节(比如量化算法),先横向铺认知,搞清楚每层解决什么问题、各层之间怎么协作,然后挑一个你最常用的方向纵向挖。
这篇笔记的章节顺序,就是我认为比较合理的横向认知路径:先看算力资源怎么管理,再看数据怎么喂进去,接着看训练怎么并行、怎么容错,然后看模型怎么上线服务,最后看怎么观测和控成本。顺着这条路走完一遍,你再看任何AI Infra的具体方案,都能迅速定位它在全景图里的位置。
2. 算力资源管理:GPU从来不是"插上就能跑"的
2.1 选卡不能只看算力,还要看显存和互联
很多团队采购加速卡时,只盯着"每秒多少万亿次浮点运算"这个数字,结果用起来才发现卡脖子的是显存和带宽。模型参数、梯度、优化器状态、中间激活值,全都放在显存里。显存不够,模型就塞不进一张卡,就得拆成多卡并行,而一旦拆卡,通信开销就上来了。
所以看一块卡,至少要盯四个指标:算力(决定计算速度)、显存容量(决定能装多大的模型)、显存带宽(决定参数和激活值读写速度)、互联带宽(决定多卡协作效率)。显存带宽尤其容易被忽略,但它恰恰是很多算子(尤其是Attention类算子)的真实瓶颈。算力再高,显存读得慢,整体吞吐一样上不去。
这里面有个生活化类比:算力像餐厅的灶台数量,显存像冰箱容量,显存带宽像传菜通道的宽度。灶台再多,传菜通道窄,菜还是一盘一盘慢慢上。实际调优时,我先看的往往不是算力利用率,而是带宽有没有吃满。
2.2 集群网络拓扑:分布式训练的隐形天花板
单卡之外,多卡之间的网络是第二个大坑。GPU集群里的通信大致分两类:一类是机内卡间通信,靠高速私有互联总线,速度快、延迟低;另一类是跨机通信,靠RDMA网络,速度取决于网卡规格和交换机拓扑。
这里最容易踩的坑是:把任务随机调度到两台机器上,结果每个step都有一大半时间在等跨机通信。我遇到过一种情况,代码逻辑完全一样,只是任务分别跑在"网络拓扑友好"和"网络拓扑糟糕"两组机器上,吞吐差了将近一倍。排查到最后才发现,问题不在于网络带宽标称值,而在于任务跨了机房核心交换机层级,多跳了一次。
实操上的建议是:大模型训练任务尽量按"机器内优先、机架内次之、跨机架最次"的原则调度。很多内部调度器支持"拓扑感知",如果你们使用的平台没有这个能力,那至少要在任务申请资源时,把多卡的分配策略改成"尽量聚合在同一台机器"。
2.3 调度器真正要解决的问题:不是排队,是"装箱"
资源调度这块,外行以为是"先进先出排队"这么简单,实际上它面对的是一个个复杂的装箱问题。每个训练任务需要的GPU数量和显存大小不同,每台机器的卡数、显存、网络位置也不一样,调度器要在这些约束下,尽量把集群资源塞满,同时还要保证任务不会被饿死。
我所在的内部平台用的是标准容器编排系统加自定义队列调度。实操中遇到过几个典型问题:
- 碎片化:集群里每台机器都剩1张卡,但新任务要4张卡,于是任务一直排不上去。解决思路是定期做"碎片整理",或者允许任务申请时容忍跨机器。
- 优先级反转:低优先级任务霸占资源,高优先级任务反而排队。后来给队列加了优先级和抢占策略,高优先级任务可以抢占低优先级任务的空闲卡,但抢占本身要小心,不能频繁打断正在训练的任务。
- 大小任务混跑:大任务占了一整台机器的8张卡,小任务只要1张卡,两者混跑容易互相干扰。调度器需要支持GPU显存隔离和计算资源限制,否则小任务会拖垮共享卡的训练稳定性。
2.4 成本认知:空转的GPU才是最大的浪费
算力资源的成本,不在于你买了多少卡,而在于这些卡真正干活的时间占比。训练任务常见的时间黑洞包括:数据加载卡顿导致的GPU空转、通信等待导致的并行效率下降、检查点保存导致的周期性停顿、以及任务排队等待的资源闲置。
我们团队曾经做了一次全集群利用率审计,发现平均GPU利用率只有四成多。最大的原因不是调度器不好,而是大量任务存在"计算三五秒、等待十几秒"的节奏问题。当时把数据管道修了一遍,利用率立刻涨了二十个百分点。这让我深刻体会到,算力管理如果只盯着调度策略,不看数据管道,那相当于只管理了资源的"出入口",没管理资源内部的"消化效率"。
3. 数据管道:训练跑不满,八成问题在喂数环节
3.1 数据读取链路到底有多长
一条典型的数据读取链路是:样本存在对象存储或分布式文件系统里 → 训练进程通过网络拉取 → 写入本地磁盘缓存 → 解码成原始样本 → 做数据增强/预处理 → 打包成训练批次 → 送进GPU。这中间任何一个环节变慢,GPU就会在那里干等。
我见过最夸张的一次,某个训练任务的数据集存放在对象存储上,每次都直接远程读取,没有做本地缓存。结果每个训练迭代的GPU空闲时间占到六成,整体训练速度慢得像在爬。后来把样本预先拉到本地NVMe盘,再配合预取机制,同样一套代码,吞吐翻倍还多。
所以判断数据管道有没有问题,最简单的办法就是看GPU利用率。如果模型计算本身已经优化过,但GPU利用率长期低于五成,优先级最高的怀疑对象就是数据管道。
3.2 文件格式与存储选型:不是随便存一下就行
数据格式这件事,新人最容易觉得"无所谓,能读就行"。真到了大规模训练,文件格式直接决定I/O瓶颈的上限。
常见的样本存储格式有三类:小文件直存(每个样本一个文件)、大文件序列化打包(把大量样本拼成一个大文件)、列式存储(主要用于结构化特征数据)。我强烈建议训练场景用大文件序列化打包,少用小文件。原因很简单:文件系统处理海量小文件的开销极大,每个文件都有元数据操作,几千几百万个小文件,光打开文件就能把CPU耗干。
打包格式还有一个实际好处:容易做预取和混洗。你可以按文件粒度预取,在内存里按样本粒度做随机打乱,既保证了训练随机性,又避免了频繁访问存储。另外,数据压缩也要考虑,压缩比高的格式能减少网络传输量,但会消耗CPU解压,需要结合实际带宽和CPU资源做权衡。
3.3 Prefetch、多进程加载、数据增强的overlap
数据管道优化的核心思想是"重叠"——让数据的加载、解码、增强和GPU计算同时进行,而不是串行等待。实现的常用手段是多进程数据加载,主训练进程只管计算,几个后台进程提前把下一批数据准备好,放在队列里。
这里面的坑主要体现在:
- prefetch数量不是越大越好。prefetch太多,占用内存太多,反而挤压了训练进程的显存和系统内存;prefetch太少,又覆盖不了抖动。一般建议先从2到4开始试,观察GPU空转率变化。
- 数据增强要在CPU上做还是GPU上做,要分算子看。简单算子(如裁剪、缩放)在CPU上做就行,但如果增强逻辑特别重,CPU可能成为瓶颈,这时可以考虑把一部分算子放到GPU上。
- num_workers不是越多越好,起太多进程会造成CPU争抢,甚至拖慢主进程。我通常的做法是:观察CPU核数和数据解码开销,从4个worker开始往上压,直到GPU利用率不再明显提升为止。
3.4 数据质量监控:脏数据会导致训练"隐性崩溃"
数据管道还有一个容易忽视的问题:脏数据不会报错,但会让模型训练变差。比如样本标签错乱、数值异常(NaN、超大值)、图片解码失败后成空张量等。很多训练任务跑完一个epoch后loss突然飙升,查到最后都是某个文件里的脏样本在作怪。
成熟的训练平台应该加一道数据质量校验环节,在样本进入训练前做基础检查:维度对不对、数值范围是否符合预期、标签是否合法、有没有重复样本。除了这种离线校验,训练过程中也要盯几个信号:每个epoch的样本量是否一致、数据分布有没有明显漂移、loss曲线在某个固定step附近有没有异常跳变。如果这两类监控都做了,数据问题基本能在几小时内暴露,而不是等到模型训完才发现效果不对。
4. 分布式训练:并行策略是通信开销的博弈
4.1 四种并行方式,本质是"拆什么、怎么合"
单卡放不下大模型时,就要做分布式并行。常见的并行维度可以拆成四个:
- 数据并行:每张卡持有完整的模型副本,只切分数据。每步训练结束,各卡把梯度做一次全局归并,保证参数同步。
- 张量并行:把单个算子(比如矩阵乘法)按维度切分,多个卡协同算一个算子。通信量大,适合机内卡间高带宽互联。
- 流水线并行:把模型按层切成多段,每张卡负责一段,数据像流水线一样逐段流过。通信量小,但存在流水线气泡(部分卡在等待)。
- 专家并行:主要用于稀疏门控结构,只有被路由到的专家所在卡参与计算,用于超大规模稀疏模型。
这四种不是互斥的,实际的大模型训练往往是混合并行。比如先用张量并行把单卡装不下的层拆开,再按层做流水线并行,最后在每个流水线阶段内部做数据并行。混合并行的核心矛盾在于:并行度越高,通信量越大,而通信会让每张卡的有效算力打折。所以并行策略设计本质上是"显存容量 vs 通信开销 vs 计算效率"的三方博弈。
4.2 通信原语:AllReduce、AllGather、P2P 各管各的事
分布式训练离不开集合通信。理解几个最基础的原语,后面的并行策略就都好懂了:
- AllReduce:所有卡把自己的结果传给别人,最后每张卡都拿到全局归并后的结果。数据并行里的梯度同步就是AllReduce。
- AllGather:每张卡把自己持有的数据广播出去,最后所有卡都拿到完整数据。张量并行中,两个矩阵切分在不同卡上,做拼接时就会用到。
- P2P发送/接收:一对卡之间的点对点通信。流水线并行中,前一段给后一段传中间激活值,用的就是P2P。
通信开销的规则很简单:数据量越大、跨卡距离越远,开销越高。所以在设计并行方案时,通信量大的操作(比如张量并行的每步通信)要尽量放在机内高带宽互联的卡之间;通信量小但频率高的操作(比如流水线的阶段间传递)可以容忍跨机。
4.3 混合精度与显存优化:从FP32到BF16再到分片
训练大模型,显存永远是稀缺资源。最常用的显存优化手段是混合精度训练:计算用高精度,存储用低精度。现在的加速卡主流做法是用BF16做前向和反向计算,用FP32做主权重更新,这样能把显存占用几乎砍半,同时不牺牲训练稳定性。
光靠混合精度还不够时,就要做优化器状态分片。以前数据并行是每张卡都复制一份完整的优化器状态,模型一大,光优化器状态就能占掉几倍的参数显存。分片的思想是:把优化器状态轮流分散到各张卡上,每张卡只更新自己那部分,最后再同步参数。这种方式能大幅降低单卡显存压力,让千亿参数模型在不大幅增加卡数的前提下塞进集群。
这里有个实操提醒:分片后通信量会增加,因为每步训练都需要额外收集完整参数。如果集群网络带宽不高,分片带来的显存收益会被通信耗时抵消。这时要结合实际情况做取舍,不能盲目追求"所有状态都分片"。
4.4 断点续训与容错:训练跑一个月的底气所在
大模型训练动不动跑几周甚至一个月,中断重来是不可接受的。**断点续训(Checkpoint)**是AI Infra的核心基本功,但很多人对其中的设计细节理解不够。
检查点不只是把模型权重存一下那么简单。一个完整的检查点应该包含:模型参数、优化器状态(比如Adam的一阶二阶动量)、当前训练步数、随机数生成器状态、数据加载器的位置索引。如果只存模型参数不存优化器状态,恢复训练后,模型虽然能继续,但优化器的动量和方差都丢了,学习节奏会乱,轻则训练变慢,重则loss震荡上不去。
检查点保存的频率也要设计。存太频繁,每个检查点都要停顿写入,浪费时间;存太少,一旦中断,丢失的进度太多。我常用的策略是:每N步存一个完整检查点,每隔几步存一个更轻量的临时检查点,恢复时优先用最近的可恢复点。另外,保存到远端存储时要注意写一致性和原子性——不能出现检查点写到一半任务挂了,恢复时读到半截文件。
5. 推理与服务:模型上线后是另一个工程世界
5.1 训练与推理的本质差异
很多人把训练时的优化经验直接搬到推理上,结果效果很差,因为它们面对的是完全不同的目标。训练看重吞吐和收敛,推理则分两种场景:在线推理要低延迟,用户点一下就得回;离线批量推理要高通量,比如给一批历史数据打标签。
在线推理有个特点:请求是稀疏到达的,单个请求的计算需求又很依赖输入长度。如果每个请求单独起一个模型实例,GPU利用率会很低;如果按照传统后端的方式简单排队,又容易让延迟超标。所以推理服务需要一套完全不同于训练的批处理和调度机制。
另一个被忽视的点是:推理阶段也要存KV缓存。大语言模型在逐token生成时,会把已经计算过的注意力键值缓存下来,避免重复计算。这个缓存占用的显存极其可观,随并发请求数和序列长度线性增长,管理不好,再大的显存也不够用。
5.2 动态批处理:让不同请求"搭车"同一次计算
静态批处理的做法是凑满固定数量再算,但请求长度不一样,凑齐一批可能要等很久,延迟就上去了。现代推理框架普遍用连续批处理(Continuous Batching):不再等整个批次一起结束,而是在一个批次内,哪个请求先生成完就先"下车",空出来的位置立刻补一个新的请求进来。这样GPU始终在处理有效token,吞吐可以比静态批处理高好几倍。
实现连续批处理的前提是显存管理足够灵活。因为每个请求的KV缓存是动态增长的,如果预先给每个请求固定分配一块最大可能长度的KV缓存,显存会浪费得惊人。解决办法是把显存按小块管理,动态分配给需要的请求,用完释放。这个思路有点像内存管理里的分页机制,实测下来,对大模型推理吞吐的提升非常显著。
5.3 量化与精度:把模型压到能上线的大小
推理阶段,模型参数和KV缓存都可以用更低精度存储。常见路径是:训练完的模型先做量化,把权重从高精度压到8位、4位甚至更低,然后用量化后的权重做推理。量化可以减少显存占用、加快计算速度,但也会带来精度损失。
真正实操时要注意:不是所有层都能一刀切量化。有些敏感层(比如某些注意力投影层)量化后效果崩得厉害,就需要做混合量化——大部分层用低精度,少数层保留高精度。我踩过最典型的坑是,某次紧急上模型,为了省显存把所有层都用低精度量化,结果线上回答质量肉眼可见地变差。后来花了整整一天逐层排查,才发现是其中两类层出了问题。
这里给个建议:上线前一定要做量化前后的效果对比评测,不能只看显存和速度指标。评测不一定要多全面,但至少要在业务关键场景上跑一批真实输入,人工抽查输出质量。速度再快,效果不行等于白干。
5.4 服务编排与弹性:推理也要讲"成本效益"
推理服务还有一个跟调度相关的问题:在线模型通常有多个副本,副本多了成本高,少了又扛不住峰值流量。比传统后端复杂的地方在于,每个副本的显存占用很大,扩容时不一定能找到连续空闲的GPU,缩容时还要考虑正在处理的请求不能被打断。
我的经验是,推理服务的弹性伸缩要基于GPU实际利用率 + 队列积压长度 + 延迟分位数这三个信号来判断,不能只看每秒请求数。因为请求长度差异太大,请求数小但每个都超长,照样能把集群打满。另外,不同模型副本之间要尽量做亲和性调度,把副本聚在同一批机器上,方便突发流量时快速扩容,也能减少跨机推理带来的延迟抖动。
6. 可观测性与成本治理:先量化一切,再谈优化
6.1 核心指标:GPU利用率只是起点
很多团队对训练任务的监控只停留在GPU利用率这一个数字上,这远远不够。GPU利用率只能告诉你"计算单元忙不忙",却看不出工作是有效计算还是在等待数据。
我建议训练任务至少盯这几类指标:
- 有效计算指标:实际浮点吞吐与理论峰值的比值(业界俗称MFU)。这个数越接近1越好,大模型训练能做到五成以上就算相当不错了。
- 资源等待指标:GPU空闲占比、数据加载耗时、通信耗时占比。这些能直接定位瓶颈在数据管道、网络还是调度。
- 稳定性指标:loss是否异常波动、每次迭代耗时是否稳定、显存占用是否有泄漏、是否存在NAN值。
推理服务则要额外盯:首token延迟、尾token延迟的P50/P95/P99分位数、KV缓存命中率、显存碎片率、批次平均大小。这些指标组合起来,才能准确判断线上服务质量。
6.2 Profiling:遇到性能问题怎么一步步定位
当训练速度不达标时,正确的做法不是拍脑袋改代码,而是做一次系统的性能剖析。我的排查顺序一般是这样的:
- 先看GPU利用率和迭代耗时曲线,确认问题在哪个阶段。
- 抓数据管道的耗时分布,看加载、解码、增强各花了多少时间。
- 抓通信耗时,看是不是某些集合通信步占比异常高。
- 用性能分析工具生成算子级时间线,看哪个算子在GPU上耗时最多。
- 最后才决定优化动作:是改数据管道、改并行策略,还是换算子实现。
这个流程看起来很基础,但真实情况是大多数人跳到第4步就开始乱调。有一次我们遇到一个"GPU利用率正常但训练吞吐上不去"的诡异问题,沿着这个流程一步步查,最后发现是某个数据增强算子在CPU上的耗时被隐藏在了GPU空闲时间里,用时间线工具看到后,两行代码就解决了。
6.3 成本治理:配额、优先级与账单透明
最后聊成本。AI Infra的支出大头是算力,而算力成本的治理本质是把资源变成可度量、可管制、可追溯的配额体系。
实操层面有三个要点:
- 配额分级:不同团队、不同任务设定不同配额上限和优先级。核心业务训练任务应保证配额,实验性任务允许排队和抢占。
- 账单归属:每个训练任务、每个模型服务都要能追溯到项目和负责人,GB·小时和卡·小时按实际使用量计费。只有账单透明了,团队才会主动关掉闲置任务。
- 闲置扫描:定期扫描长时间无进展或利用率极低的任务,自动提醒甚至关停。我们发现很多"纸面在线"的模型服务挂着好几个副本,实际流量很低,白白占着显存。
成本治理做得好不好,直接决定了同样一笔预算能支持多少实验迭代。我们在内部推行"按项目维度看成本报表"之后,不到两个月,整体算力开销就降了将近三成,而且几乎没有影响正常训练进度——大多数省下来的,都是过去没人管的空转和闲置。
6.4 关于可观测性的一点忠告
指标采集本身也会消耗资源。有些团队把细粒度指标用极高的频率上报,监控系统自身占用的算力和网络带宽都不小。我的建议是:基础指标高频采集,明细指标按需采样,遇到问题再临时开全量。监控系统的价值在于帮你快速定位问题,而不是让监控本身成为新的问题。
7. 写在最后的一些个人体会
整理这份笔记的过程中,我最大的体会是:AI Infra的知识不是"看会的",而是"踩会的"。每个看似简单的概念——比如数据预取、检查点、量化——背后都对应着真实系统里的一堆边界情况和教训。你不真正经历过一次"训练跑了一周结果检查点损坏"或者"线上模型因为量化效果崩了"的瞬间,很难对这些细节产生敬畏。
如果非要说几个最值得投入时间去掌握的方向,我会选这三样:一是数据管道,因为它是最容易出效果、也最容易被低估的环节;二是分布式训练的可观测能力,因为大模型训练就像黑箱,没有好的观测手段,优化无从谈起;三是推理的成本意识,因为模型做出来不是终点,让它低成本地服务用户才是价值落地的地方。
最后分享一个小技巧:每处理完一次线上故障或性能问题,都把它按"现象—排查过程—根因—修复方案—可以复用的检查项"这个格式写成一条笔记。时间久了,这就是属于你自己的AI Infra排障手册。遇到新问题时先翻旧笔记,你会发现很多问题原来都见过,只是换了身衣服。