1. 从“调参侠”到AI-Infra:一个一线工程师的转型起点
如果你现在打开招聘软件,搜“AI工程师”,会发现一个很有意思的现象:算法岗的JD(职位描述)里,越来越多地出现“熟悉分布式训练”“了解CUDA编程”“有大规模集群调优经验”这样的要求。而另一边,基础架构岗的JD里,也开始要求“理解Transformer结构”“熟悉PyTorch底层机制”。这两个方向正在快速融合,融合出来的那个交叉地带,就是现在圈子里讨论越来越热的AI-Infra。
我自己就是在这个交叉地带里摸爬滚打过来的一线工程师。几年前我还在做传统的后端服务开发,后来因为项目需要,被拉去搞模型训练平台。刚开始那段时间,我连NCCL是什么都不知道,看到torch.distributed的文档一头雾水,GPU利用率上不去只能干瞪眼。踩了无数坑之后,我慢慢摸清了AI-Infra这条路的脉络——它不像纯算法那样有明确的论文可以跟,也不像传统运维那样有成熟的体系可以套,很多东西需要你自己去试、去调、去总结。
这篇文章是我个人对AI-Infra这个方向的一次系统性梳理,也是“一线工程师的AI-Infra之路”系列的第一章。我打算从最基础的问题讲起:AI-Infra到底在做什么?它和传统的MLOps、DevOps有什么区别?一个从零开始的工程师需要掌握哪些核心能力?以及在实际工作中,那些文档里不会写、但每天都会遇到的真实问题该怎么处理。不管你是刚入行的新人,还是从其他方向转过来的老兵,希望这些内容能帮你少走一些弯路。
2. AI-Infra到底在解决什么问题:拆开“模型训练”这层皮
2.1 从单卡到千卡:规模带来的不是线性增长
很多人对AI-Infra的理解停留在“帮算法同学配环境”这个层面,这其实是个很大的误解。配环境只是最表层的活儿,AI-Infra真正要解决的核心问题是:当模型规模、数据规模、集群规模同时膨胀时,如何让整个训练和推理系统保持高效、稳定、可扩展。
我举个具体的例子。你在单卡上训练一个BERT-base模型,batch size设成32,跑一个epoch大概几十分钟,整个过程很顺畅。现在你把模型换成GPT-3级别的1750亿参数,数据量放大到几百GB,单卡显存放不下模型,你不得不做模型并行;单卡训练时间从几十分钟变成几个月,你不得不做数据并行加流水线并行;几百张卡同时跑,通信开销指数级上升,你不得不优化集合通信策略。这时候你会发现,原来单卡上那些理所当然的事情——比如梯度同步、参数更新、checkpoint保存——全都变成了需要重新设计的工程问题。
这就是AI-Infra存在的意义。它要处理的是系统层面的复杂度,而不是模型层面的创新。算法工程师关心的是“这个结构能不能提升准确率”,AI-Infra工程师关心的是“这个结构在512张A100上跑起来,MFU(Model FLOPs Utilization)能不能到50%以上”。
2.2 AI-Infra和MLOps、DevOps的边界在哪里
这三个概念经常被混在一起说,但它们的侧重点完全不同。我用一个表格来对比:
| 维度 | DevOps | MLOps | AI-Infra |
|---|---|---|---|
| 核心目标 | 加速软件交付 | 管理模型生命周期 | 优化训练/推理系统性能 |
| 主要对象 | 代码、服务 | 模型、数据、实验 | GPU集群、通信、存储 |
| 关键指标 | 部署频率、故障恢复时间 | 模型迭代速度、复现性 | 吞吐量、延迟、MFU、显存利用率 |
| 典型工具 | Jenkins、K8s、Terraform | MLflow、Kubeflow、DVC | NCCL、DeepSpeed、Megatron、vLLM |
| 技能栈 | 脚本、容器、云平台 | 数据工程、实验管理 | 分布式系统、CUDA、网络、存储 |
简单来说,DevOps管的是“代码怎么上线”,MLOps管的是“模型怎么迭代”,AI-Infra管的是“模型跑得快不快、稳不稳、省不省”。三者有交集,但核心关注点截然不同。一个成熟的AI团队,这三个角色往往都需要,只是在不同阶段侧重点不一样。
2.3 为什么现在AI-Infra变得这么重要
原因很直接:模型规模的增长速度远远超过了硬件性能的增长速度。根据公开的数据,过去几年里大模型的参数数量每年增长一个数量级以上,而单卡GPU的显存和算力增长大概每两年翻一倍。这个剪刀差意味着,你不可能靠单卡解决问题,必须走分布式路线。而分布式系统天生就复杂——通信、同步、容错、调度,每一个环节都可能成为瓶颈。
另一个原因是成本压力。一张A100或者H100的卡,云上按需价格每小时几十块钱,一个千卡集群跑一天就是几十万的成本。如果MFU只有20%,意味着80%的钱白花了。AI-Infra工程师的核心价值之一,就是把这80%的浪费尽可能地压下去。我见过一个真实的案例:某团队通过优化数据加载和通信重叠,把训练吞吐提升了40%,一年下来省下的算力成本够养一个小组。
3. 一个AI-Infra工程师的能力地图:我踩过的坑和补过的课
3.1 底层基础:CUDA、通信库和操作系统
刚转过来的时候,我以为自己Linux玩得挺溜,结果第一次上机就懵了。nvidia-smi显示的显存占用和torch.cuda.memory_allocated()对不上,训练过程中突然OOM但不知道是谁占的内存,多卡跑起来GPU利用率忽高忽低。这些问题逼着我去补底层知识。
CUDA层面,你不需要会写kernel,但必须理解几个核心概念:显存分配机制(为什么PyTorch的缓存分配器会导致“假OOM”)、流和事件(怎么用CUDA Stream做通信计算重叠)、以及SM占用率(为什么你的kernel跑不满GPU)。我自己的经验是,把CUDA的编程模型过一遍,再回头看PyTorch的torch.cuda模块,很多之前看不懂的API就豁然开朗了。
通信层面,NCCL是绕不过去的。你需要知道AllReduce、AllGather、ReduceScatter这些集合通信操作的区别,知道Ring AllReduce和Tree AllReduce的适用场景,知道NVLink和InfiniBand的带宽差异对训练的影响。我踩过的一个坑是:在一个跨节点的训练任务里,没有设置NCCL_SOCKET_IFNAME,结果NCCL走了一个慢速的管理网口,通信时间占了整个迭代的60%以上。后来指定了正确的网卡,吞吐直接翻倍。
操作系统层面,你需要关注的是:CPU亲和性设置(避免进程在NUMA节点间乱跳)、共享内存配置(/dev/shm太小会导致DataLoader卡死)、以及文件描述符限制(大规模训练时打开的文件数可能上万)。这些都是小细节,但每一个都能让你debug半天。
3.2 框架层:PyTorch的“隐藏面”
PyTorch用起来简单,但要用好、用快,需要理解它背后的机制。我总结下来,AI-Infra工程师需要特别关注的PyTorch知识点有这么几个:
- Autograd的计算图构建和释放:为什么你的显存占用在backward之后没有下降?可能是计算图没有被释放,或者有引用残留。
- DataLoader的num_workers和pin_memory:这两个参数设不对,GPU就会饿着等数据。我一般会先用
nvidia-smi看GPU利用率,如果低于80%且波动大,大概率是数据加载的问题。 - DistributedDataParallel(DDP)的通信钩子:DDP默认在backward时触发AllReduce,但你可以通过
register_comm_hook自定义通信策略,比如做梯度压缩或者异步通信。 - 混合精度训练(AMP)的scale机制:loss scaling不是越大越好,动态loss scaling的初始值和增长策略需要根据模型调整。
这些知识在PyTorch官方文档里都有,但比较分散。我的建议是,不要只读文档,要动手写一些最小复现脚本。比如写一个简单的DDP训练脚本,然后故意把bucket_cap_mb调大调小,观察通信时间的变化。这种实验做多了,直觉就出来了。
3.3 分布式训练:从数据并行到3D并行
分布式训练是AI-Infra的核心战场。我把它分成几个层次来理解:
第一层:数据并行(DP/DDP)。这是最常用的方式,每张卡持有完整的模型副本,数据切分到不同卡上,梯度通过AllReduce同步。DDP比DP快很多,因为DDP只在梯度同步时通信,而DP每个iteration都要广播参数。但DDP的显存开销是O(模型大小),当模型大到单卡放不下时,就需要下一层。
第二层:模型并行(MP)。把模型的不同层放到不同卡上,比如前几层在GPU0,后几层在GPU1。这种方式的问题是GPU利用率低,因为同一时间只有一张卡在计算。后来发展出了流水线并行(PP),把数据切成micro-batch,让不同卡可以同时处理不同micro-batch,提高了利用率。但PP需要仔细设计micro-batch的数量和调度策略,否则会出现“气泡”(bubble),浪费算力。
第三层:张量并行(TP)。把单个矩阵运算切分到多张卡上,比如把一个大矩阵乘法拆成多个小矩阵乘法并行计算。这种方式通信频繁,适合NVLink这种高带宽互联的场景。Megatron-LM是这方面的代表工作。
第四层:3D并行。把DP、PP、TP组合起来,形成三维并行策略。这是目前训练千亿级以上模型的主流方案。但组合起来之后,通信模式变得非常复杂,需要仔细调优。
我自己的学习路径是:先把DDP吃透,然后手动实现一个简单的流水线并行,再去看Megatron和DeepSpeed的源码。不要一上来就啃3D并行,容易劝退。
3.4 推理优化:训练只是上半场
很多人以为模型训练完就万事大吉了,其实推理优化是另一个深坑。训练关注的是吞吐量(每秒处理多少样本),推理关注的是延迟(单个请求多长时间返回)和吞吐的平衡。
推理优化的核心手段包括:
- 量化:把FP16降到INT8甚至INT4,减少显存占用和计算量。但量化会带来精度损失,需要做校准。
- KV Cache优化:自回归生成时,Key和Value矩阵需要缓存。PagedAttention(vLLM的核心技术)把KV Cache分页管理,大幅减少了显存碎片。
- 连续批处理(Continuous Batching):传统批处理要等一个batch里所有请求都完成才能开始下一个batch,连续批处理可以动态加入新请求,提高了GPU利用率。
- 算子融合:把多个小算子合并成一个大算子,减少kernel launch开销。TensorRT和TVM在这方面做得很好。
我做过一个对比测试:同一个LLaMA-7B模型,用HuggingFace的默认推理,吞吐是每秒8个token;换成vLLM之后,吞吐提升到每秒120个token。这个差距在线上服务里就是能不能扛住流量的问题。
4. 真实工作场景:那些文档里不会写的日常
4.1 集群调度:当K8s遇上GPU
大部分公司的训练集群都是用Kubernetes管理的。但K8s原生对GPU的支持比较基础,你需要装NVIDIA Device Plugin,还需要考虑GPU共享、拓扑感知调度、故障隔离等问题。
我遇到过一个很典型的问题:两个训练任务被调度到了同一台物理机的两张GPU上,但这两张GPU之间没有NVLink,只有PCIe。结果跨GPU通信走了PCIe,带宽只有NVLink的几分之一,训练速度直接腰斩。后来我们引入了拓扑感知调度,确保需要频繁通信的任务被分配到NVLink互联的GPU上。
另一个坑是GPU内存碎片。K8s的device plugin只报告GPU数量,不报告显存使用情况。有时候一个任务申请了一张GPU,但只用了10%的显存,另一张卡上的任务却因为显存不足被OOM kill。解决方案是用MIG(Multi-Instance GPU)或者时间片共享,但这又带来了隔离性和性能的问题。
4.2 存储与数据加载:最容易被忽视的瓶颈
训练一个大规模模型,数据加载往往是第一个瓶颈。我见过太多团队花大价钱买了A100,结果GPU利用率只有30%,原因是数据从远程存储读取太慢。
解决这个问题的思路是分层缓存:
- 第一层:本地NVMe SSD。把当前epoch的数据预先缓存到本地盘,读取速度可以达到几GB/s。
- 第二层:节点内共享内存。如果多个进程在同一节点上训练,可以用
/dev/shm做进程间数据共享,避免重复读取。 - 第三层:分布式文件系统。比如Lustre、GPFS或者云上的对象存储。这一层容量大但延迟高,适合做冷数据存储。
另外,数据格式也很关键。把原始图片或文本预处理成WebDataset或者TFRecord格式,比每次训练时实时解码要快得多。我做过测试,同样的数据,用WebDataset比用原始文件读取,DataLoader的吞吐提升了3倍以上。
4.3 故障排查:当训练突然变慢或崩溃
分布式训练最让人头疼的就是故障排查。一个千卡任务挂了,你不可能一张卡一张卡去查。我的经验是建立一套分层排查流程:
第一步:看全局指标。用Prometheus+Grafana监控整个集群的GPU利用率、显存、温度、功耗、网络带宽。如果发现某张卡的利用率明显低于其他卡,那问题大概率出在那张卡或者它的通信链路上。
第二步:看单任务日志。NCCL会输出通信初始化的详细信息,包括用了哪些网卡、带宽是多少、有没有超时。PyTorch的DDP也会在初始化时打印一些信息。这些日志里往往藏着线索。
第三步:用工具定位。py-spy可以dump出Python进程的调用栈,看看是不是卡在某个函数上。nsys和ncu可以分析CUDA kernel的执行情况。nccl-tests可以单独测试通信性能。
第四步:最小复现。如果问题只在特定配置下出现,尝试缩小规模复现。比如从千卡缩到8卡,看看问题是否还在。如果在8卡上能复现,排查起来就简单多了。
我印象最深的一次故障:一个训练任务跑了三天突然变慢,GPU利用率从90%掉到40%。查了半天发现是某个节点的网卡出现了间歇性丢包,导致NCCL重传。换掉那块网卡之后恢复正常。这种硬件层面的问题,没有监控数据根本无从下手。
5. 给刚上路的同行:几条实在的建议
5.1 不要只盯着算法,系统能力才是护城河
现在算法岗卷得厉害,但AI-Infra岗的人才缺口还很大。原因很简单:算法可以速成,但系统能力需要时间积累。你花三个月学完Transformer和Diffusion,但你可能需要一年才能真正搞懂分布式训练里的各种坑。
我的建议是,如果你对系统感兴趣,不要犹豫,往AI-Infra方向走。这个方向的天花板很高,而且随着模型规模继续增长,需求只会越来越大。
5.2 动手比看书重要,但要有方向地动手
AI-Infra是个实践性极强的领域。你看十篇讲流水线并行的文章,不如自己写一个简单的流水线调度器。但动手也要有方向,不要盲目地造轮子。我的做法是:先跑通一个开源框架(比如DeepSpeed或Megatron),然后尝试修改它的某个模块,观察性能变化。比如把AllReduce换成AllGather,看看吞吐和显存有什么变化。这种“改-测-分析”的循环,是成长最快的方式。
5.3 建立自己的性能分析工具箱
每个AI-Infra工程师都应该有一套自己的性能分析工具。我常用的包括:
nvidia-smi和nvitop:看GPU整体状态nsys和ncu:分析CUDA kernel和通信py-spy:分析Python进程nccl-tests:测试通信性能iperf和ibstat:测试网络带宽dcgm:GPU集群监控
这些工具不需要全部精通,但要知道在什么场景下用哪个。比如GPU利用率低,先用nvidia-smi看是不是有卡在等数据,然后用py-spy看Python进程在干什么,最后用nsys看kernel执行有没有问题。
5.4 保持对硬件的敏感度
AI-Infra和硬件结合得非常紧密。你需要关注每一代GPU的架构变化(比如Hopper的Transformer Engine、Blackwell的FP4支持),关注互联技术的演进(NVLink的带宽、InfiniBand的速率),关注存储介质的更新(NVMe SSD的IOPS、CXL内存扩展)。这些硬件特性直接决定了你的优化空间。
我自己的习惯是,每出一代新卡,就去读它的白皮书,看看有哪些新特性可以利用。比如Hopper的TMA(Tensor Memory Accelerator)可以大幅提升数据搬运效率,如果你不知道这个特性,就白白浪费了优化机会。
5.5 多和算法同学聊天,理解他们的痛点
AI-Infra是服务于算法和业务的。如果你不了解算法同学在做什么,你的优化可能根本用不上。我经常和算法同事一起看训练日志,听他们抱怨“这个模型跑得太慢了”“显存又不够了”“这个实验复现不出来”。这些抱怨里藏着真实的优化需求。
比如有一次算法同学说,他们做超参搜索时,每个实验都要重新加载数据,很浪费时间。我后来帮他们做了一个数据预加载服务,把常用数据集缓存在内存里,实验启动时间从几分钟缩短到几秒。这种优化不需要多高深的技术,但需要你理解他们的工作流程。
6. 这一章先聊到这里
AI-Infra这条路不好走,但走通了之后,你会发现自己看问题的视角完全不一样了。你不再只是关注“这个模型准不准”,而是会去想“这个模型在真实系统里跑起来会是什么样”“瓶颈会在哪里”“怎么用有限的算力做更多的事”。这种系统思维,是AI-Infra工程师最核心的竞争力。
后面几章我打算具体展开讲几个方向:分布式训练的通信优化、推理服务的性能调优、以及GPU集群的监控和故障排查。每一块都会结合我实际踩过的坑和用过的方案来写,尽量做到看完就能上手试。
如果你也在走这条路,或者正准备走,欢迎一起交流。这个领域变化太快,一个人闷头搞容易走偏,多听听同行的经验总没坏处。