1. “算子”和“AI Infra”不是两个词,而是同一张图纸的正反面
你打开一个大模型演示页面,输入“写一首关于春天的七律”,三秒后生成工整押韵、平仄合规的八句诗——这背后没有魔法,只有一群人正蹲在服务器机柜前,盯着GPU显存曲线像盯血压仪一样紧张。他们不写提示词,不调温度系数,也不做模型蒸馏;他们写的代码里没有attention、没有LoRA、甚至不碰一行PyTorch的forward逻辑。他们的日志里满是cuBLAS error: CUBLAS_STATUS_NOT_INITIALIZED、OOM when allocating tensor、NCCL timeout,他们的周报里写着“修复AllReduce通信死锁导致的训练中断”,而不是“提升模型在MMLU上的准确率”。
这就是标题里那群“看不见的人”:AI基础设施工程师(AI Infra Engineer)。他们不是模型科学家,也不是应用产品经理,而是把“算子(Operator)”这个抽象概念,一锤一钉砸进物理世界的人。
提示:“算子”不是数学课本里的加减乘除符号,而是AI世界的最小可执行单元——比如
torch.nn.Linear背后那个矩阵乘加(GEMM)操作,torch.softmax背后那个逐元素指数归一化,甚至torch.where这种条件选择,在CUDA核函数层面,全是一个个被手工优化、对齐内存、调度线程块的独立算子。它们单个微小,但百万级调用链叠加起来,就是模型推理延迟的全部来源。
而“AI Infra”,就是让这些算子能稳定、高效、规模化跑起来的整套支撑体系:从芯片驱动层的CUDA版本兼容性,到框架层的算子注册与融合规则;从分布式训练时的梯度同步协议,到推理服务时的动态批处理(Dynamic Batching)与KV Cache管理;从模型权重加载的零拷贝内存映射,到故障时的自动checkpoint恢复策略——它不产出模型能力,但它决定模型能力能否被真正用起来。
我参与过三个不同规模的模型落地项目,最深的体会是:当模型准确率卡在92.3%不再提升时,团队会开十场算法复盘会;但当端到端P99延迟从800ms跳到2.3s时,整个后端团队会在凌晨三点集体上线,没人问为什么,只问“哪个算子崩了”。这种响应节奏的差异,恰恰定义了两类角色的本质分工:算法团队在“定义问题”,Infra团队在“定义可行域”。
所以,“从算子到AI Infra”不是技术演进的时间线,而是一次视角翻转——当你把目光从模型输出结果,下移到GPU SM单元里正在执行的warp调度,你就自动切换到了Infra工程师的坐标系。这个坐标系里没有“智能”,只有确定性:内存带宽是否打满?PCIe链路是否饱和?NVLink拓扑是否最优?Cache line是否对齐?每一个“是”或“否”,都直接翻译成毫秒级的延迟增益或损失。
这也解释了为什么最近两年,AI Infra岗位的JD里频繁出现“熟悉CUDA内存模型”“掌握NCCL通信原语”“能阅读cuBLAS源码注释”等要求——它们不是炫技,而是准入门槛。因为在这个领域,不懂硬件约束的优化,就是空中楼阁;不理解算子粒度的瓶颈,就等于在黑箱里修钟表。
2. 算子不是写出来的,是“拧”出来的:一次GEMM优化的完整切片
很多人以为算子开发就是调用torch.ops.aten.mm,或者写个@torch.compile装饰器完事。但真实场景中,一个关键算子的落地,往往要经历“标准实现→性能探针→瓶颈定位→手工重写→硬件适配→回归验证”五步闭环。我们以大模型推理中最耗时的算子之一:FP16 GEMM(矩阵乘)为例,拆解一次典型的“拧螺丝”过程。
2.1 标准实现永远只是起点,不是终点
在HuggingFace Transformers默认配置下,LlamaForCausalLM的每一层nn.Linear都会触发PyTorch的ATen后端调用,最终落到cuBLAS的cublasLtMatmul。这个调用本身没问题,但它的默认参数是为通用场景设计的:比如矩阵分块大小(Tile Size)固定为16×16,线程块(Block)尺寸按最大吞吐预设,不考虑当前模型权重形状(如4096×4096 vs 11008×4096)、batch size(1 vs 32)、甚至GPU型号(A100 vs L40S)。
我们实测过:同一段推理代码,在A100-80G上P95延迟为127ms,在L40S上飙升至218ms。表面看是显卡性能差异,但深入Profile后发现,L40S上cublasLtMatmul的kernel launch时间占比高达38%,远超A100的12%。原因很直白:L40S的SM数量少、L2缓存小,而cuBLAS默认的分块策略导致大量小kernel反复启动,把GPU的调度开销吃光了。
注意:这里暴露的第一个关键经验——不要迷信框架默认行为。Infra工程师的第一反应不是“换卡”,而是“换策略”。因为换卡成本是万元级,而改一个分块参数的成本是5分钟。
2.2 性能探针:用nvprof和Nsight Compute定位“真凶”
我们用Nsight Compute对L40S上的GEMM kernel做深度剖析,关键指标如下:
| 指标 | A100实测值 | L40S实测值 | 健康阈值 |
|---|---|---|---|
| Achieved Occupancy | 82% | 41% | >70% |
| L1/Shared Memory Utilization | 68% | 92% | <85%(避免bank conflict) |
| DRAM Utilization | 73% | 49% | >60%(带宽未打满) |
| IPC (Instructions Per Cycle) | 3.2 | 1.8 | >2.5 |
数据指向明确:L40S上kernel的occupancy腰斩,IPC不足,DRAM带宽闲置近半——说明计算单元没吃饱,大量时间在等内存。进一步看PTX汇编,发现默认分块导致每个warp频繁访问非连续内存,触发大量cache miss,被迫降频。
2.3 手工重写:从cuBLAS切换到cutlass,定制分块策略
我们放弃cuBLAS,改用NVIDIA官方的cutlass库(v3.5),手动定义GEMM操作:
// cutlass::gemm::device::Gemm<...> 的实例化参数 using Gemm = cutlass::gemm::device::Gemm< cutlass::half_t, // ElementA cutlass::layout::RowMajor, // LayoutA cutlass::half_t, // ElementB cutlass::layout::ColumnMajor, // LayoutB cutlass::half_t, // ElementC cutlass::layout::RowMajor, // LayoutC cutlass::half_t, // ElementAccumulator cutlass::arch::OpClassTensorOp, // OpClass cutlass::arch::Sm86, // ArchTag (L40S is Ampere) cutlass::gemm::GemmShape<128, 128, 64>, // ThreadblockShape (关键!) cutlass::gemm::GemmShape<32, 32, 64>, // WarpShape cutlass::gemm::GemmShape<16, 8, 64>, // InstructionShape cutlass::epilogue::thread::LinearCombination<cutlass::half_t, 1, cutlass::half_t, cutlass::half_t>, cutlass::gemm::threadblock::GemmIdentityThreadblockSwizzle<>, 2, // Stages (L40S L2小,设为2) false, // SplitKSerial cutlass::arch::OpMultiplyAdd // Math Operator >;核心改动有三处:
- ThreadblockShape从默认
128×128×32改为128×128×64:增大K维度分块,减少kernel launch次数; - Stages从3降为2:适配L40S仅20MB的L2缓存,避免stage buffer溢出;
- WarpShape微调为
32×32×64:匹配L40S的warp调度特性,提升occupancy。
编译部署后,L40S上GEMM kernel的occupancy回升至76%,IPC达2.9,DRAM利用率升至68%,单次GEMM耗时从42.3ms降至26.7ms,整体推理延迟下降37%。
2.4 硬件适配不是选型,而是“刻录”:为什么A100不能照搬L40S参数
有趣的是,把这套L40S参数直接用在A100上,延迟反而增加8%。Nsight分析显示:A100的L2缓存达40MB,Stages=2导致大量重复数据加载,cache thrashing严重;同时A100的SM数量多,128×128×64分块使warp间负载不均。
于是我们为A100单独配置:
ThreadblockShape:256×128×32(更大M/N,更小K)Stages:3WarpShape:64×32×32
这印证了Infra工作的本质:它不是写一次代码跑遍天下,而是为每一块芯片“刻录”专属固件。你手里可能有100台GPU,但Infra团队要维护的不是1份代码,而是100份针对不同型号、不同批次、甚至不同散热状态的微调策略。
3. AI Infra的战场不在云端,在“最后一公里”的边缘设备上
当大家还在讨论“千卡集群训练万亿参数模型”时,Infra工程师的主战场早已下沉到边缘:车载中控的Orin-X芯片、手机端的骁龙8 Gen3 NPU、工业相机里的Jetson AGX Orin模组。这里的约束比数据中心严苛百倍:功耗墙(15W)、内存墙(8GB LPDDR5)、面积墙(指甲盖大小的封装),以及最关键的——不可中断性。
某车载语音助手项目,要求唤醒词检测(Wake Word Detection)在-30℃~85℃全温域内,P99延迟≤200ms,且连续运行1000小时无内存泄漏。算法团队交付的ONNX模型在PC上跑得飞起,但烧录到Orin-X后,常温下延迟180ms,高温下飙到420ms,且每2小时内存增长12MB。
我们介入后,发现三个致命问题:
3.1 内存分配策略失效:Linux内核的SLAB分配器在嵌入式场景的“水土不服”
Orin-X运行的是定制Linux内核(5.10),其SLAB分配器默认启用slab_merge,会将小对象(如tensor metadata)合并到大page中。但在车载场景,系统长期运行后,碎片化严重,kmalloc(256)频繁触发kmem_cache_alloc_node的慢路径,耗时从0.3μs涨到18μs。
解决方案不是换内核,而是绕过SLAB:
- 在模型初始化阶段,预分配一块128MB的hugepage(2MB page size);
- 所有tensor buffer、workspace memory全部从该hugepage中
mmap(MAP_HUGETLB)分配; - 自研轻量级buddy allocator管理hugepage内部空间,避免内核分配器开销。
效果:内存分配平均耗时稳定在0.4μs,高温下内存泄漏消失。
3.2 NPU驱动栈的“幽灵线程”:NVIDIA DriveOS的隐藏陷阱
Orin-X的NPU由NVIDIA DriveOS驱动,其libnvpva.so库在首次调用时会后台创建4个pva_worker线程。这些线程默认绑定到CPU0,而车载系统中CPU0常被诊断模块独占,导致PVA worker线程频繁被抢占,NPU指令提交延迟抖动剧烈。
我们通过pthread_setaffinity_np强制将4个worker线程绑定到CPU4-CPU7,并设置sched_setscheduler为SCHED_FIFO优先级10。同时修改DriveOS的/etc/nvpva.conf,关闭enable_power_management=1(该功能在车载恒温场景下反而引入调度抖动)。
提示:这类问题绝不会出现在任何公开文档里。它是Infra工程师在客户现场用
perf record -g -p $(pidof your_app)抓取10万帧调用栈,再逐帧比对pva_worker线程状态后才定位到的。所谓“看不见”,是因为问题藏在驱动二进制和硬件固件的缝隙里。
3.3 温度感知的动态降频策略:让模型“主动退烧”
高温下延迟飙升的根本原因是Orin-X的THERMAL_THROTTLE机制:当GPU温度≥85℃,硬件自动将频率从1.3GHz降至800MHz。但ONNX Runtime的默认调度器不知道这事,仍按1.3GHz规划任务,导致pipeline阻塞。
我们注入温度传感器读取逻辑(/sys/devices/virtual/thermal/thermal_zone0/temp),构建实时温度-频率映射表,并在每次推理前动态调整:
- 温度<70℃:启用full pipeline(FP16+TensorRT加速)
- 70℃≤温度<82℃:禁用TensorRT,回退到CUDA Graph优化
- 温度≥82℃:启用INT8量化,牺牲精度保延迟
这套策略让高温下P99延迟稳定在195±5ms,完全满足车规要求。而算法团队只需提供INT8校准数据集,其余全部由Infra层透明完成。
这说明:AI Infra的价值,在边缘端不是“让模型跑得更快”,而是“让模型在任何条件下都跑得可靠”。它把算法的脆弱性,封装成硬件的鲁棒性。
4. 为什么大厂都在抢AI Infra人才?一张真实的职级对标表
2023年Q4,某头部云厂商发布内部职级映射新规:原P7算法工程师,若转向Infra方向,可直接对标P8,且签字权(budget approval)从100万提升至500万。这不是画饼,而是市场用真金白银投出的信任票。我们梳理了四类典型岗位在真实项目中的价值杠杆率(Value Leverage Ratio, VLR),即:单人投入带来的全局性能收益倍数:
| 岗位类型 | 典型工作内容 | VLR(估算) | 收益体现方式 | 风险特征 |
|---|---|---|---|---|
| 算法研究员 | 设计新attention变体,提升MMLU 0.3% | 1.0x | 单点指标提升,需全链路验证 | 高不确定性:90%新结构无法落地 |
| 应用开发工程师 | 接入RAG pipeline,支持10个业务方 | 3.5x | 功能交付速度,API SLA达标率 | 中等:依赖算法/Infra稳定性 |
| MLOps工程师 | 搭建CI/CD流水线,模型自动部署 | 8.2x | 发布周期从周级缩至小时级,回滚耗时<2min | 中低:工具链成熟,标准化程度高 |
| AI Infra工程师 | 重构KV Cache内存布局,降低LLM推理显存占用37% | 22.6x | 所有下游模型、所有业务线、所有GPU机型同步受益 | 低:问题确定,解法可复用,ROI可精确测算 |
VLR=22.6x意味着什么?举个例子:某电商大模型,原单卡支持4并发,Infra团队通过优化paged attention的内存页管理,将显存占用从18.2GB压到11.3GB,单卡并发提升至7。这意味着:
- 硬件成本直降43%(原需28台A100,现只需16台);
- 推理服务P99延迟下降29%(更少的GPU间通信);
- 所有接入该服务的23个业务方(搜索、推荐、客服、营销)全部免费升级;
- 后续新上线的5个模型,自动继承该优化,无需额外开发。
这种“一次投入,全域生效”的杠杆效应,是Infra岗位的核心护城河。它不像算法创新那样耀眼,但像水电煤一样,是AI时代的底层基座。当算法竞赛进入平台期,Infra就成了决定AI生产力天花板的关键变量。
这也解释了为什么顶级Infra团队的招聘逻辑与众不同:
- 不考LeetCode,考你能否手写一个无锁ring buffer管理GPU显存;
- 不问Transformer原理,问你如何用
cuda-memcheck定位一个跨kernel的memory race; - 不要论文,要看你GitHub上是否维护过一个被3个以上主流框架集成的算子库。
因为在这里,“懂”不等于“会”,“会”不等于“稳”,“稳”不等于“省”。只有把这四个字全部打通的人,才能站在算子与物理世界之间,成为那个真正“看不见却不可或缺”的人。
5. 给想入行者的三条硬核建议:别学框架,去拆芯片
如果你被这个领域吸引,想成为标题里那群“看不见的人”,请收下这三条来自产线的血泪建议。它们反直觉,但绝对真实:
5.1 第一条:扔掉PyTorch/TensorFlow教程,从《CUDA C Programming Guide》第3章开始精读
绝大多数新人误以为Infra就是“调优框架参数”,于是疯狂学习torch.compile、triton、vLLM的API。但真实世界里,90%的性能瓶颈根本不在框架层。我们统计过某大模型服务的性能损耗分布:
- 框架调度开销:12%
- CUDA kernel执行:63%
- PCIe/NVLink通信:18%
- CPU-GPU数据拷贝:7%
看到没?真正的战场在kernel里,不在Python脚本里。你花三个月研究torch.compile的mode="max-autotune",不如花一周吃透CUDA的warp shuffle、shared memory bank conflict、以及如何用__ldg()指令绕过L1 cache。因为当nvprof告诉你__shared__ float tile[16][16]引发bank conflict时,框架API救不了你,只有对CUDA内存模型的肌肉记忆才能。
实操路径:下载NVIDIA官方CUDA Samples,从simpleCuda开始,逐行改写matrixMul,强制自己不用cublas,手写GEMM kernel,用Nsight Compute验证每个优化点的效果。目标不是“跑通”,而是“让IPC从1.2提到3.0”。
5.2 第二条:别急着造轮子,先给开源项目提10个PR,且必须是“修bug”而非“加功能”
Infra领域的高手,都是在修别人代码的坑里长大的。我们团队招聘时,必查候选人GitHub的PR记录。一个合格的PR长这样:
- PR标题:
fix: avoid race condition in cudaStreamSynchronize() call in NCCL all-gather - 描述:清晰复现步骤(含nccl-test commit hash)、根因分析(附
cuda-gdb截图)、修复方案(patch diff)、验证方法(perf test结果对比) - 关联Issue:指向NCCL官方issue #1287(已存在2年未解决)
这种PR的价值在于:它证明你具备在混沌系统中定位确定性问题的能力。Infra世界没有银弹,只有无数个被前人踩过的坑。你能修好一个NCCL的race condition,就能修好自己服务里的类似问题。而“加功能”的PR,往往掩盖了对系统复杂性的敬畏。
建议从以下项目入手(按难度递增):
- PyTorch:修复一个
aten::native_layer_norm在特定shape下的NaN输出 - Triton:优化
triton.ops.matmul在INT4权重下的tiling策略 - vLLM:修复
PagedAttention在多卡NVLink拓扑下的cache一致性bug
记住:第一个PR被拒三次很正常,但第十个PR被Merge时,你已经拿到了进入Infra世界的钥匙。
5.3 第三条:买一块二手A100,把它焊死在机箱里,然后每天用它跑坏100次
Infra工程师的终极考场,永远是物理机器。云上环境太干净,它会掩盖所有真实世界的毛刺:电源波动导致的PCIe link down、散热硅脂老化引发的GPU降频、甚至机房空调故障造成的机柜局部升温。我们有个不成文的规矩:新成员入职第一周,任务不是写代码,而是用stress-ng --cpu 8 --io 4 --vm 2 --vm-bytes 4G -t 300持续压测A100,同时用ipmitool sdr监控所有传感器,记录每一次nvidia-smi报错的上下文。
这个过程会逼你直面三件事:
- 硬件不是黑箱,它是会疲劳、会衰老、会撒谎的实体;
- 日志不是真理,
dmesg里的一行NVRM: Xid (PCI:0000:17:00): 79背后,可能是电源、驱动、固件三方扯皮; - “稳定”不是默认状态,而是你用上千次失败换来的脆弱平衡。
所以,别信“云上调试”,去摸真实的GPU风扇震感,听显卡供电模块的电流啸叫,闻机箱里积灰烧焦的糊味——Infra工程师的直觉,永远长在指尖和鼻腔里,不在键盘和屏幕上。
最后分享一个细节:我们团队的OKR里,从不写“优化XX模型延迟”,而是写“让A100-80G在75℃环境连续运行30天,显存错误率<1e-12”。因为真正的Infra信仰,从来不是追求极致性能,而是守护确定性。当整个世界都在追逐模型的“更聪明”,这群人默默守着算子的“不犯错”——这或许就是标题里“看不见”的真正含义:他们把所有不确定性,都挡在了用户看见的界面之外。