简介:大模型推理成本高企,“把硬件打满”就是真金白银。本文从SOL分数与MFU两大核心指标入手,结合“注意力输出投影+残差融合”的完整案例,拆解GPU算子优化的天花板逻辑与瓶颈分析方法;进而评估AI自动生成kernel的进展与边界,以四点论证回答AI Infra为何仍在大量招聘算子工程师,并给出入行路径建议。
过去两年,大模型把算力需求推到了前所未有的高度,GPU集群的租金与折旧在训练和推理成本中占绝对大头。于是行业里形成了一个朴素而硬核的目标:把硬件“打满”。模型结构和量化方案确定之后,同样的计算量,实现得好与不好,成本可能相差数倍。无论是自研大模型的团队,还是像百度智能云这样对外提供推理服务的云平台,算子优化都是降本的核心抓手——这正是GPU Kernel(算子)工程师成为AI Infra团队最紧俏岗位之一的根本原因。
与此同时,“AI能不能自己写kernel”的讨论也越来越多。笔者作为编译器工程师,去年也尝试过转型:借助在线判题式的GPU编程练习平台入门算子开发,发现只要反复打磨提示词并认真调优,大模型确实能写出质量不错的kernel。但当笔者读完近期业界出现的、以SOL为核心评分的算子基准测试论文后,对“算子工程师会不会被AI取代”反而有了更清晰的判断。本文把这条思考线完整展开。
SOL即Speed of Light,直译“光速”,在性能工程语境中指性能上限、天花板,也就是算子开发中常说的“打满”。它的思想很简洁:任何算子的执行时间都存在一个由硬件物理参数决定的理论下限。设算子总计算量为FLOPs、总访存量为Bytes,则理想最短时间为:
T_ideal = max( FLOPs / 峰值算力, Bytes / 峰值显存带宽 )
之所以取max,是因为计算单元和访存通路是两套并行工作的资源,算子至少会被其中更慢的那一条“卡死”。SOL分数通常定义为理想时间与实际时间之比:
SOL = T_ideal / T_actual
SOL越接近1,说明实现越逼近硬件极限;SOL只有0.2,则意味着理论上还有5倍的优化空间。
把公式稍作变形,可以引入算术强度:AI = FLOPs / Bytes,并定义机器平衡点 = 峰值算力 / 峰值带宽。若算子的算术强度高于机器平衡点,算子是计算受限的;反之则是访存受限的。这就是经典的Roofline模型:以算术强度为横轴、可达算力为纵轴,性能曲线先随带宽线性爬升,触及峰值算力后进入平台区。
这个判断直接决定优化方向:处在斜坡区的算子(访存受限),应该减少访存量、提高访存合并效率、采用更低精度的数据格式;处在平台区的算子(计算受限),则要优化分块与流水线、提高矩阵计算单元的占用率。不看Roofline就动手优化,很容易在南墙上白费力气。
SOL不仅是技术指标,还能直接换算成成本。同样的卡、同样的模型,SOL从0.5提到0.8,意味着同样的负载只需要原来约六成的机器时间,等效于用六折的算力价格跑同样的业务。对推理规模不断攀升的团队来说,这百分之三十几的差距就是真金白银。也正因如此,近年业界出现了以SOL为核心评分、题目取自真实业务负载的算子基准测试集,把“距离硬件极限还有多远”变成了可量化、可排名的公开标尺。
MFU(Model FLOPs Utilization)描述实际计算吞吐相对于理论峰值算力的比例。与SOL通常作用于单个算子不同,MFU一般在模型或整个训练/推理作业层面统计,它把“模型结构 + 算子实现 + 硬件配置”作为一个系统的最终结果来评价。
它有两点重要的工程含义:
工程实践中,SOL与MFU是一对互补的标尺:SOL告诉你“单个算子离极限还有多远”,MFU告诉你“整个系统离理想状态还有多远”。
以真实负载中一道典型题目为例:对注意力输出执行线性投影(o_proj),并与残差相加。用类Python伪代码表达朴素实现:
# 形状:attn_output (16, 512, 2560),residual (16, 512, 2560),weight (2560, 2560)projected = matmul(attn_output, transpose(weight)) # 第一步:线性投影output = projected + residual # 第二步:残差相加
看似简单的两步,在框架执行层面是两个独立kernel。按fp16估算(以上述shape为示意):三个(16,512,2560)张量各约42MB,权重约13MB;总计算量约1.07e11 FLOPs。
不融合时,投影结果要先写回显存(42MB),再被加法kernel读回来(42MB),加完再写一次输出(42MB),总访存量约223MB。融合成一个kernel后,投影的累加结果可以停留在片上寄存器中,直接完成残差相加再写回,总访存量降到约139MB——省掉整整两次显存往返,约84MB。融合kernel的核心思想可用伪代码表达:
for 每个输出tile (m, n):acc = 0for k in ...:acc += A[m, k] * W[k, n] # 分块载入片上存储,寄存器中累加out[m, n] = acc + residual[m, n] # 累加完成的同时就地加上残差
这就是所谓“epilogue融合”:把逐元素的后处理挂到矩阵乘的收尾阶段,让中间结果根本不落显存。
用一组示意数字(峰值算力1000 TFLOPS、显存带宽4 TB/s,仅用于演示量级分析):
同一个算子,在不同推理阶段呈现完全不同的瓶颈。通用算子库不可能对所有shape、所有阶段都逼近SOL,这种“长尾 + 动态”正是手写kernel长期存在的结构性原因。
近一年的变化有目共睹。在判分明确、单文件、目标清晰的练习型题目上,“agent + 反复调优提示词”已经能写出像样的kernel;新出现的SOL类基准专门用来自真实负载的算子题目考察自动生成能力,不少题目上自动化方案能拿到可观的分数。对标准化程度高的算子,自动生成已越过“能跑对”的门槛,正在逼近“跑得好”。
把前面的分析收敛成四点论证:
SOL分数告诉我们,性能优化存在物理终点;但通向终点的路径上,充满了随负载、shape、硬件代际变化的权衡。AI正在快速接管这条路径上标准化的部分,而“判断哪里有取舍、取舍向谁倾斜”的能力,仍然牢牢掌握在工程师手里。这就是AI Infra仍在大量招聘GPU算子工程师的最终答案:不是没人写kernel了,而是需要被打满的硬件,比以往任何时候都多。