Hello大家好,在过去二十年中,单芯片的计算能力增长了约6000倍。你本以为工作负载的速度会快六倍,但事实并非如此。工程师在分析其工作负载时,往往看不到明显的性能差异。这些芯片大部分时间都处于空闲状态,等待来自内存的数据。这就是“内存墙”问题。
如果你从事构建、训练或部署模型的工作,这个概念将解释为什么当芯片的浮点运算次数(FLOPS)翻倍时,你的工作负载或AI模型并没有快两倍。它还解释了为什么批处理在某些情况下能提升性能,而在其他情况下则不然;同时也说明了AI加速器为何如此设计。在过去二十年中,有两个指标以不同的速率增长:计算能力和内存带宽。
首先来看计算能力(Compute),其单位为每秒浮点运算次数(FLOPS)。例如,在2006年初的视频GPU中,其性能约为每秒几千亿次运算。而到了2025年,我们关注的B200芯片能够执行约每秒两千万亿次运算。可以看出,计算能力实现了大约6500倍的增长。
与此同时,在同一时期内增长的另一个指标是内存带宽(Memory Bandwidth),单位为每秒字节数。你可以看到,与计算能力的增长相比,内存带宽的增长要慢得多。两者之间的差距实际上在不断扩大,目前约为7倍左右。这个差距就是我们所说的“内存墙”。
因此,更快的芯片并不意味着工作负载一定更快,特别是如果我们无法以芯片所需的速度向其提供数据时。这就是内存墙的核心思想:额外的计算能力并不会自动提升性能,原因在于一个称为“算术强度”(Arithmetic Intensity)的比率。
算术强度定义为每移动一个字节所执行的数学运算次数,即FLOPS除以字节数。其核心思想是:如果你每移动一个内存中的字节能执行大量的数学运算,你就处于所谓的“计算受限”(Compute Bound)模式。
相反,如果你每移动一个字节执行的运算很少,或者说从内存中移动的每个数据字节对应的数学运算远少于预期,你就处于“内存受限”(Memory Bound)模式。接下来我们将引入一个称为Roofline模型来进一步说明这一点。
在Roofline模型中,X轴表示算术强度(即FLOPS除以字节数),Y轴表示可实现的带宽,单位为每秒浮点运算次数(FLOPS)。我们在图中绘制了两个关键指标:内存带宽(单位为字节/秒)和峰值计算能力(Peak Compute,单位为FLOPS)。
注意X轴测量的是工作负载的属性。这两条曲线相交于一点,我们称之为“脊点”(Ridge Point)。例如,对于B200 GPU,该值为每秒281次浮点运算。这个数值是芯片本身的属性:在这一点左侧,我们讨论的是内存带宽限制;右侧则是峰值计算能力。
其核心思想是:提高算术强度可以提高芯片的可实现带宽(即每秒能执行的FLOPS数量)。但随着你接近脊点,你会开始触及芯片物理性能的极限。因此,在计算算术强度这一工作负载依赖的特性时,需要将其与脊点进行比较或对应。
那么281这个数值是如何得出的呢?根据B200 GPU的规格,其峰值带宽约为每秒2.25 petaflops。而在内存方面,它支持每秒8 terabytes的带宽。计算脊点的方法是将2.25 petaflops除以8 TB/s,结果约为每秒281次浮点运算。
这里有一个小注记:在NVIDIA GPU的规格书中,提到的36 petaflops是针对8个GPU且为BF16稀疏模型的数据。因此我们需要将其除以8,得到单个芯片约为2.25 petaflops,从而得出上述的281这一数值。
这对我的工作负载意味着什么?如果我的工作负载算术强度处于脊点左侧的区域,我属于内存受限模式,意味着我无法每移动一字节内存就处理尽可能多的运算。如果我的算术强度大于脊点(在此例中为281),则属于计算受限模式。
这也向我揭示了特定工作负载面临的瓶颈所在。让我们以大语言模型的解码(Decode)和预填充(Prefill)阶段为例进行说明。在解码阶段,我们需要从内存中读取大量权重以一次生成一个令牌(假设批大小为1)。
因此,解码阶段的算术强度通常处于脊点左侧的极低区域。这使得我们处于内存受限模式。这就是解码工作负载的特点。
然而,如果我们看预填充阶段,我们执行的是大规模GEMM运算。在这种情况下,每字节的浮点运算次数超过1000次。因此,预填充阶段的算术强度大于1000。相比之下,解码阶段的算术强度约为每秒一次浮点运算(每字节)。
请注意,预填充的数值远高于我们的脊点,这意味着它处于计算受限模式。因此,如果工作负载处于内存受限状态,即使投入更多的计算资源也不会带来太大帮助;我们需要更快地将数据获取到芯片中。
解决这一问题的一种常用技术称为“批处理”(Batching)。批处理的本质作用是提高算术强度,使其更接近脊点。具体来说,它允许同时服务多个请求。
重复使用已加载到内存中的权重来进行多次令牌生成。因此,实际上,在移动相同数量的数据时,你执行了更多的数学运算。这基本上提高了你的算术强度(Arithmetic Intensity),使你更接近屋顶线模型的峰值,从而提升性能。这就是为什么许多成熟的 LLM 推理服务环境,如 vLLM、SGLang 和 TensorRT-LLM,都使用批处理(batching)和连续批处理技术来改善性能。
在这里你可以看到,芯片或硬件保持不变,发生变化的是工作负载(workload)。这是一个非常重要的观察点。算术强度反映了工作负载的特征,并让你了解你的工作负载相对于屋顶线峰值的位置。同时,它也有助于解释瓶颈的来源:你需要增加更多的计算能力,还是需要改进内存带宽?
总结一下,这就是“内存墙”问题。核心思想是:为了让工作负载运行得更快,我们需要更快地将数据移动到芯片上。有几种方法需要理解:首先,在基准测试之前,利用算术强度估算你的工作负载,以帮助你了解情况。其次,从硬件规格表中获取峰值内存带宽和最大计算能力等数据。
通过这些信息,你可以使用类似屋顶线建模的技术粗略判断自己所处的位置。这样你就能明白需要在哪些方面投入更多时间进行优化,从而提升工作负载的性能。感谢观看。