模型性能瓶颈分类及优化策略
01 四种关键性能问题类型的分类
如果不满意当前模型性能并计划投入优化时间,则需首先识别这些瓶颈问题。这四种分类中前三类通常涉及硬件限制的问题。剩下的一个则与软件因素密切相关。
首先围绕硬件相关瓶颈展开分析, 每种硬件瓶颈均映射到某种特定的工作状态或操作模式(specific operational regime:)
computational bottleneck scenario (Compute bound regime) 在这种情况下占主导地位的是运算相关的时间消耗(如图 1所示)。与之相比,在资源分配方面有明显差异的情况包括 Compute bound regime ,其核心特征是运算性能成为系统瓶颈因素。相比于其他场景,在 Compute bound regime 中运算相关的资源分配占比最高,并且由于其具有最高的效率水平,在实际应用中也应当予以优先考虑。

图 1 为 compute bound process示意图——其中计算过程与数据传输过程分别以黄色与蓝色进行标注
memory bandwidth-constrained scenario : 在此情形下, 大多数时间消耗于将数据传输至嵌入于处理器芯片上的内存与处理器之间, 其中具体包括权重矩阵(weight matrices)以及中间计算(intermediate computations), 如译者注所提及的临时性计算结果等.

图形标题为"图 2——带宽受限的相关计算流程";其中的计算过程与数据传输过程分别以黄色和蓝色进行标注
通信受限情况(Communication-constrained scenarios):未提及于文献[1]中。
该情形仅限于计算与数据在多块芯片间分布的情形。
多数任务的处理时间主要由芯片间网络的数据传输所占据(见图3)。

如图3所示为 communications bound process流程图,在该图表中可清晰地看到计算流程(yellow)、数据传输流程(blue)以及网络通信流程(green)分别以不同颜色区域标识。
请注意,在此上下文中:为了便于讨论……而选择了'芯片'这一术语。因为这些概念适用于各种类型的芯片——包括但不限于CPU、GPU、定制芯片(如Google的TPU、AWS的Neuron Cores等)。
请特别注意当前的高性能计算硬件结合先进的AI框架系统,在实际应用过程中这两个功能模块往往在同一时间段内会并行运行(见图 4 )。为了便于分析讨论,在本文中,默认情况下我们假定这两个任务是依次执行的。

、
图4——在数据传输与运算(计算)并行处理的情况下,该流程基于通信受限
最后一种是开销受限情况(overhead bound),是软件导致的瓶颈。 在这种情况下,大部分时间都用于调度计算机系统中各项任务的执行顺序和时间并将计算任务或指令发送给计算机的处理器或其他硬件设备执行 —— 很多情况下,我们花费更多的时间来确定要做什么,而非在硬件上执行实际操作(图 5)。在使用非常灵活的编程语言(如 Python)或 AI 框架(如 PyTorch)时,更有可能出现开销受限的情况,因为这些编程语言或 AI 框架不需要明确指定程序运行时期(runtime)所需的所有信息(如张量数据类型(tensor data types)、目标设备(target device)、要调用的内核(kernels to invoke)等)。这些缺失的信息必须在任务运行时期(runtime)进行推理,处理各项任务相应的 CPU 周期称为开销(overhead)。 与 CPU 相比,现在的 Accelerated hardware(译者注:用于加速特定类型计算任务的硬件,例如GPU、Google的TPU等) 速度已经非常快了,因此很可能出现开销影响硬件利用率,进而影响成本效益的情况 —— 很多情况下,硬件会处于闲置状态,等待软件提交下一个工作任务。

图表 5——带 overbound 的界限过程,在计算过程与数据传输过程以及软件执行过程中所消耗的额外时间中分别以黄色、蓝色和紫色标注
该模型中执行前向或反向传播的过程(backward or forward pass)涉及在GPU上并行处理多个内核函数或程序段。一般而言,在当前系统架构下,并非所有内核都能运行于同一底层机制。因此,在性能优化中起着关键作用的是确定哪种底层机制消耗了大部分时间。接着,在持续改进的过程中应优先针对主要性能瓶颈进行优化,并依次解决其他较次要但同样重要的问题。
准确识别性能瓶颈类型对于解决问题具有重要意义。不同类型的性能问题通常需要各自特定的解决策略。如果诊断错误,则即使实施了优化措施也可能达不到预期效果;这种做法无疑是一种低效的做法。
确定影响系统性能的关键因素
本文将不深入探讨这一问题
文献 [1] 强调,在开销受限的情况下
运行时间的增长并非与计算量或数据传输量成正比
若增加计算能力或数据传输强度
程序运行时间未随之延长
那么这个程序很可能因开销瓶颈而停滞
否则...可能是硬件层面的瓶颈...
需借助FLOP计数等指标来判断具体情况
请注意LLM(大语言模型)的相关技术细节中提到,在训练阶段以及 inference pre-fill 阶段(注释:可能指在执行推理之前进行数据填充或资源准备的过程),通常会遇到计算资源受限的问题;而在 inference decoding 阶段(注释:指将模型输出解码为最终可读结果的过程),则普遍面临内存带宽瓶颈的影响。因此,在优化训练过程的有效性方面(例如通过采用低精度矩阵乘法来降低运算开销),虽然这些方法可以在一定程度上减少整体推理时间;但因为推理过程的时间主要由解码阶段决定,在多数硬件平台上仍然无法显著改善推理效率。
就对各类性能瓶颈实施优化工作以提升运行效率 如果处于计算能力受限情况下可以通过以下方式实现
采用高性能且高昂成本的芯片设计,并提供更强的计算能力。特别适用于诸如矩阵乘法等特殊的运算任务,在NVIDIA H100 PCIe架构下(参考文献[2]),通用计算核心(GEMM)可达到51 TFLOPS的峰值计算性能;而若采用专门设计的专用加速单元——NVIDIA Tensor Cores(参考文献[3]),则可提升至378 TFLOPS(在全精度情况下)。具体而言,在降低模型运行所需计算操作数量方面取得显著成效——例如,在机器学习模型中实现相同效果所需参数数量减少一半或更多(如剪枝技术[4]或知识蒸馏方法[5])。通过采用更低精度但计算速度更快的数据类型进行处理——例如,在NVIDIA H100 PCIe架构下(参考文献[2]),8位Tensor Cores提供的峰值FLOPS可达1,513 TFLOPS(较16位Tensor Cores提升一倍),而后者又较32位Tensor Cores提升一倍至756 TFLOPS;然而这一优化策略需配合对模型所有输入数据进行量化处理(包括权重矩阵和激活值),并依赖特定算法如LLM.int8()或SmoothQuant[6]来进行低精度计算。
如果系统运行处于内存带宽受限状态(Memory bandwidth bound),则可以通过以下方式优化:
升级至功能更加强大、价格更为昂贵且内存带宽更高的芯片

图6展示了对CNN模型在横向和平行方向上实施了多类内存操作的融合过程,并比较了起始位置(上方)与最终位置(下方)的状态变化[8]
如果处于通信受限情况(Communications bound)下,建议:
采用了功能更为强大且价格更为昂贵的芯片设计。
通过采用一种更具效率的 partitioning and collective communication strategy(译者注:分布式环境中的一种策略)来减少通信量。
例如,在参考文献[9]中所提出的策略中,默认情况下扩展了参考文献[10]中主流的 Transformer 模型的 tensor parallelism layout(译者注:张量在分布式环境下的划分与管理方法),引入了一种新的张量并行策略(tensor parallel strategies),从而在分布式系统中传输数据所需的时间得以更好地扩展(即避免通信时间成为瓶颈)。
例如,在参考文献[10]中所提出的 tensor parallelism layout 中维持 weights shards 不会因计算过程的变化而发生改变(译者注:权重参数不会因计算过程的变化而发生变化),而 activation shards(译者注:激活值)则会在不同处理器之间移动。
在预填充阶段处理大规模的数据序列时,在参考文献[9]中指出激活值可能比权重值更大。
因此,在从通信角度来看更加高效的做法是不移动激活值或调整其位置仅移动 weight shards ,类似于 “weight-gathered” 区间划分策略(译者注:一种将权重参数集中在一起但激活值分布在不同处理器上的划分策略)。
如果你处于开销受限情况(overhead bound)下,建议:
使用 C++ 等性能较好但效率较高的语言,在提高性能的同时降低了运算消耗(overhead)。
将多个内核任务并行提交给 GPU 执行,在减少单个内核负担的同时实现了更好的资源利用效率。
特别适用于需要反复执行较短作业的任务场景中(如多轮迭代或复杂计算过程中),这种策略能显著提升执行效果。
CUDA Graphs 提供了便捷工具来记录所有 GPU 操作,并将其组织成有向图结构以便高效执行。
通过分析模型的行为模式来记录完整的运算步骤序列,并生成一个可重现性极高的计算图(compute graph)。例如,在 PyTorch 中可以通过 torch.jit.trace 方法捕获整个程序流程并将其打包成独立部署的服务程序。
无论如何,你又一次以可变性(flexibility)为代价换取了较小的开销(overhead)。由于跟踪/编译(tracing/compilation)要求张量大小和类型等参数在运行时保持不变,因此这些参数必须预先确定.这些控制流结构如if-else通常会被丢失.
对于无法满足 dynamic tensor shapes 和 control flow 等灵活性要求的场景(例如,在模型运行过程中张量的维度和大小或程序的执行路径可能会根据输入数据或其他条件动态变化),PyTorch 的 just-in-time (JIT) 编译器能够在运行时阶段对模型代码进行动态优化(虽然不如 AOT 编译器那样彻底)。例如,在 PyTorch 2.x 中引入了 TorchDynamo 作为一种 JIT 编译器工具。通过使用 TorchDynamo 工具无需修改现有 PyTorch 程序即可实现性能提升的同时还能减少开发者的编程负担,并在保持优质 Python 开发体验的同时降低了引入 JIT 编译器所带来的额外开销。
补充说明:模型优化器(model optimizers)与AOT编译器之间的区别是否存在?在我的理解中,两者之间的界限并不清晰。关于如何从概念上区分这两种术语的问题,请问有什么样的看法?
此外,在程序实际运行之前对其进行编译或优化处理的方案主要包括:从所支持的主要深度学习框架(如PyTorch、TensorFlow、MXNet等)中收集代码,并提取其计算图到中间表示(IR)中;随后应用一系列通用的硬件无关优化技术(如代数重写、循环展平和操作符融合等)来生成经过精炼后的计算图;最后结合目标硬件特性的特定优化方法(如分析模型特性选择最适合的内核或算法、优化数据在计算设备与内存之间的传输路径等),最终为特定硬件生成可部署的工作件。这些AOT模型编译器的具体实现包括PyTorch中的TorchInductor、XLA以及Meta开发的Glow等工具。
该模型优化器是一个工具集合,包含 AOT(即 ahead-of-time 编译),特别针对特定硬件进行了优化(如面向英特尔硬件的 OpenVINO、面向英伟达硬件的 TensorRT 和 TensorRT-LLM)。此外,在完成模型训练后还可以实施量化和剪枝等额外的技术
到目前为止, 我们一直专注于延迟(处理单个请求所需的时间)的影响. 现在, 我们将深入研究在计算能力及内存带宽受限条件下的系统性能, 并将其纳入当前性能模型的评估体系中.
04 Bottleneck(性能瓶颈)等于f(Hardware(硬件配置),Arithmetic intensity(算术强度))。值得注意的是,在使用相同算法处理同一组输入时,可能会遇到两种不同的限制因素:要么是计算能力不足导致的问题,要么是内存带宽不足的问题。具体表现为哪一种问题则取决于该算法的算术强度。即每次访问一单位字节内存时所执行的算术运算数量。
我们致力于使算术强度达到或更接近更高效率的计算能力限制范围内。我们观察到,在算术强度值上升时,吞吐量(throughput)与成本效益比(cost efficiency)均有所提升。需要注意的是,在某些情况下,通过提高算术强度可能会导致延迟。这提示着,在系统设计中应当综合考虑延迟与吞吐量的关系,并选择合适的算法或技术以平衡性能与效率。
每次程序运行时,在内存间传输的数据字节数 b 被定义为每次程序执行时的数据加载量。其中 p 则表示每一次程序运行期间所进行的算术运算数量。假设 BW_mem 代表每秒传输的存储容量(单位:TB/s),它是衡量硬件存储性能的关键指标;而 BW_math 代表每秒可执行的浮点运算数量(单位:TFLOPS),反映了硬件在算术处理方面的最大能力。此外 t_mem 表示完成数据传输所需的时延;而 t_math 则表示完成一次算术操作所需的时间。
该方法在执行计算任务时效率较低,在进行数值运算时所需时间较长。

图7:计算与数据传输的时间分别以黄色和蓝色标注。其中计算时间采用黄色表示、数据传输时间采用蓝色表示。
因此,我们在进行计算任务时会受到限制:

数值A代表该算法的算术强度, 其计算基于每字节浮点运算次数(FLOP)。在数据传输过程中, 每个字节所执行的算术运算数量越多, 相应的计算能力就越强。
如公式所示,在计算能力受限的情况下

图 8 —— 受限于内存带宽或计算能力这两种情况的判断边界
注

表 1 —— 常用于 LLM 训练和推理服务的英伟达™(NVIDIA®)数据中心 GPU 规格
这表明什么呢?以NVIDIA A10为例,在这种情况下,在该特定硬件上移动一个字节的数据与其所执行的浮点运算速度相当(FLOPs)。因此,在NVIDIA A10上运行时每传输一个字节的数据时若无法至少执行208次浮点运算(或每传输一个半精度浮点数至少需执行416次浮点运算),那么在这种情况下数据传输的时间就会不可避免地超过计算时间从而受到内存带宽限制换句话说算术强度低于hardware bandwidths ratio(译者注:在特定硬件上进行运算时每单位数据传输所需的时间与其每次运算操作所需时间之间的比率)的算法都会受到内存带宽限制
因为 LLM 推理过程的解码阶段具备较低的计算能力(如前所述),导致在多数硬件设备上容易受到内存带宽的限制。相比之下,NVIDIA H200 在带宽比方面更适合处理这类低计算强度的任务类型(low-intensity workloads)。这也解释了为何英伟达将 H200 的官方宣传语定为 "supercharging generative AI inference, " 因为其硬件设计正是针对内存受限的应用场景而优化构建。
现在,让我们把算术强度与延迟和吞吐量联系起来:

请注意,在这里我们采用TFLOPS作为衡量吞吐量的标准,并非基于每秒请求数。值得注意的是二者之间呈正相关关系。此外这一事实进一步解释了其与硬件利用率(hardware utilization)以及成本效益(cost efficiency)之间的内在联系。进一步解释表明吞吐量实际上可以用每个芯片处理器在一秒内所能处理的任务数量来衡量其性能——也就是说芯片处理器完成一次请求所需的时间越短(计算时间 chip time),相应的计算效率也会提高。
当我们将算术强度置于x轴时,并将其(最大可能达到的吞吐量)被表示为因变量并置于y轴后,则得出了所谓(初始状态下的roofline模型模型图9)。其中, 译者注:一种用于评估计算机程序性能表现的技术图形模型, 可以帮助识别程序中的性能瓶颈, 并指导优化措施; 图9展示了该方法的应用结果。参考文献[12]

图 9 —— The roofline model
通过一个简短的思维实验来理解图 9 上绘制出的吞吐量数值为何能达到最大可能水平。当计算能力受限时,这一点显而易见:我们无法突破硬件峰值能力(hardware’s maximum processing capability)。当内存带宽受限时,在1秒内可处理的最大数据量由硬件内存带宽决定。若算法具有算术强度A,则每秒可达的最大浮点运算数量等于BW_mem乘以A。
增加算法的算术强度会产生什么影响?我们可以考虑这三种情况(见图 10 ):

图 10 —— 增加算法的算术强度可能出现的三种情况
情景1:计算能力的增长幅度较低,在无法突破内存带宽瓶颈的情况下,吞吐量将成比例上升。系统依然受限于内存带宽问题, 因此系统的延迟表现将直接关联于该算术强度对数据传输速率及处理效率的具体影响
随着算术强度的增长, 系统被切换至计算能力受限的状态. 吞吐量达到了硬件的最大吞吐量水平. 现在系统的计算能力已受到限制, 对延迟的影响取决于更高算术强度对其运算策略有何影响.
情景3:受限于计算能力并已达到峰值吞吐速率的情况下,额外提升算术强度并不会带来吞吐量上的提升。 延迟受其影响的程度仍由更高水平的算术强度对其产生怎样的影响所决定。
如何提高计算强度?这一结果受到算法细节的影响。我们计划深入探讨影响 Transformer 解码器块(decoder blocks)计算能力的关键因素。通过增大 batch size 我们可以探索哪些操作会显著提升计算效率。
一些在前文已经述及过的优化手段同样能够通过提升算术强度来提高吞吐量和资源利用率。针对Transformer模型而言(其解码阶段受限于内存带宽),算术强度的提升主要依赖于operation fusion技术以及数据量化方法的应用。具体而言,operation fusion技术通过将多个计算操作整合成一个较大的操作块来降低间隙,并结合权重矩阵、KV缓存等量化处理进一步缩减数据传输规模与频率。
在此问题中作出的关键假设是该算法在理论上充分地利用了硬件资源。例如,在传输数据的过程中设想该算法能够最大可能地利用其理论内存带宽。然而实际上并不如此(尽管某些算法确实能够接近最优的资源利用率),如果这种资源利用率达到不了最优(sub-optimal)水平,则会对之前的分析结果产生怎样的影响?
这表明,在实际应用中应当采用现实中的数据替代上文提到的带宽数据。次优系统的rooftline曲线通常位于最优roofline曲线下方(如图11所示),这是因为它们未能充分利用硬件资源。具体而言,提高吞吐量的方式主要有两种:一是通过提升算术强度来最大化硬件计算能力;二是通过优化算法以更好地利用内存带宽和其他资源。

图 11 —— 资源利用率未达到最佳状态的 roofline model
在实践层面,我们通过一个真实的算法优化案例来总结这一发现。在 FlashAttention 的 2.2 版本及其之前的版本中,在解码阶段的效率较低。值得注意的是,在旧的数据加载策略未能有效提升内核在解码阶段对内存带宽的利用率的情况下,并未采取任何措施去提高内存带宽利用率。值得注意的是,在 batch 大小增加的情况下,内存带宽利用率进一步下降。因此,在内存受限的情况下,默认使用较小 batch 大小时处理较长序列会导致性能表现受限。为此,在 KV 缓存加载数据的过程中,并未对序列长度这一维度进行并行化操作导致相关问题得以解决。为此,在推理过程中使用的内核——FlashDecoding——针对解码阶段进行了优化改进,并显著提升了处理较长序列时的表现[13]。
在本文中,我们掌握了可能导致模型延迟的关键性能障碍类型共有四种。识别导致模型延迟的主要因素至关重要,在此基础之上才可制定相应的优化策略
为了避免过于复杂的情况,在本研究中我们假设不考虑分布式环境的影响。在此简化模型下,在实际运行过程中硬件操作会受到计算能力和内存带宽两个因素中的某一个限制。内核的算术强度直接决定了系统面临何种性能瓶颈。当系统的算术强度较低且内存带宽成为瓶颈时,在这种情况下可达到的最大吞吐量与系统算术强度呈线性关系;而当计算能力成为瓶颈时(即系统峰值浮点运算能力被限制),此时的实际吞吐量将由硬件峰值浮点运算能力决定。这种现象的根本原因在于影响系统算术强度的因素不同,在某些特定条件下我们有可能通过提升系统的算术强度来改善吞吐量表现,在最优情况下甚至能恢复到由计算能力所决定的性能水平;然而,在某些情况下增加系统的算术强度可能会导致延迟问题加剧
