在这篇文章中,MosaicML工程师团队分享了如何在生产环境中充分利用流行开源语言大模型(LLM)的最佳实践。此外,他们还提供了围绕模型部署推理服务的指南,以帮助用户更好地选择模型和部署硬件。他们在生产环境中使用了多个基于PyTorch的后端。这些指南是MosaicML工程师团队基于FasterTransformers、vLLM以及NVIDIA的TensorRT-LLM等背后的经验总结而来。
MosaicML在今年年中先后开源了MPT-7B、MPT-30B语言大模型,随后被Databricks以13亿美元的价格收购。
(以下内容由OneFlow编译发布,转载请联系授权。原文:https://www.databricks.com/blog/llm-inference-performance-engineering-best-practices)
来源 | Databricks
OneFlow编译
翻译|杨婷、宛子琳
1
理解语言大模型的文本生成
语言大模型的文本生成通常可分为两个阶段:首先是“预填充(prefill)”阶段,这一阶段会以并行方式处理输入提示中的词元;然后是“解码(decoding)”阶段,在这一阶段,文本会以自回归的方式逐个生成“词元”。每个生成的词元都会被添加到输入中,并被重新喂入模型,以生成下一个词元。当LLM输出了特殊的停止词元或满足用户定义的条件(例如生成了最大数量的词元)时,生成过程就会停止。
词元可以是单词或子词,将文本拆分为词元的确切规则因模型而异。例如,我们可以对比LLaMA模型和OpenAI模型对文本进行分词处理的方式。尽管LLM推理服务供应商经常以基于词元的指标(例如每秒处理的词元数)来谈论性能,但由于模型分词规则的差异,这些数字在不同模型类型之间并不总是可比较的。例如,Anyscale团队发现,与ChatGPT的分词长度相比,LLaMA 2的分词长度增加了19%(但整体成本要低得多)。HuggingFace的研究人员也发现,与GPT-4相比,对于相同长度的文本,LLaMA 2训练所需的词元要多20%左右。
2
LLM服务的重要指标
我们应该如何准确衡量模型的推理速度呢?
我们团队使用了以下四个指标:
-
首个词元生成时间(Time To First Token,简称TTFT):即用户输入查询后,模型生成第一个输出所需的时间。在实时交互中,低时延获取响应非常重要,但在离线工作负载中则不太重要。此指标受处理提示信息并生成首个输出词元所需的时间所驱动。
-
单个输出词元的生成时间(Time Per Output Token,简称TPOT):为每个查询系统的用户生成一个输出词元所需的时间。这一指标与每个用户对模型“速度”的感知相关。例如,TPOT为100毫秒/词元表示每个用户每秒可处理10个词元,或每分钟处理约450个词,这一速度远超普通人的阅读速度。
-
时延:模型为用户生成完整响应所需的总时间。整体响应时延可使用前两个指标计算得出:时延 = (TTFT)+ (TPOT)*(待生成的词元数)。
-
吞吐量:推理服务器在所有用户和请求中每秒可生成的输出词元数。
我们的目标是:以最短的时间生成首个词元、达到最高吞吐量以及在最短的时间内生成输出词元。换句话说,我们希望模型能够尽可能快地为尽可能多的用户生成文本。
值得注意的是,我们需要权衡吞吐量和每个输出词元的时间:与依次运行查询相比,如果我们同时处理16个用户查询,吞吐量会更高,但会花费更长的时间为每个用户生成输出词元。
如果你对整体推理时延有具体目标,以下是一些有效的启发式方法可用于评估模型:
-
输出长度决定了整体响应时延:对于平均时延,通常只需将预期/最大的输出词元长度与模型的每个输出词元的整体平均时间相乘。
-
输入长度对性能来说影响不大,但对硬件要求至关重要:在MPT模型中,添加512个输入词元增加的时延要少于生成8个额外输出词元的时延。然而,支持长输入的需求可能使模型难以部署。例如,我们建议使用A100-80GB(或更新版本)来为最大上下文长度为2048个词元来部署MPT-7B模型。
-
整体时延与模型大小呈次线性关系:在相同的硬件上,较大的模型速度较慢,但速度比不一定与参数数量比相匹配。MPT-30B的时延约为MPT-7B时延的2.5倍,LLaMA2-70B的时延约为LLaMA2-13B时延的2倍。
经常有潜在客户要求我们提供平均推理时延。对此,我们建议:在锚定特定时延目标(例如,”单个词元的生成时间低于20毫秒”)之前,你应该花一些时间来描述你预期的输入长度和想要的输出长度。
3
语言大模型推理所面临的挑战
以下通用技术可用于优化语言大模型的推理:
-
算子融合:将相邻的不同算子合并在一起通常可以获得更短的时延。
-
量化:对激活值和权重进行压缩,以使用更少的比特数。
-
压缩:稀疏性或蒸馏。
-
并行化:在多个设备间进行张量并行,或者针对较大的模型进行流水线并行。
除上述方法以外,还有许多针对Transformer的重要优化技术,如KV(键-值)缓存。在基于Transformer的仅解码器模型中,注意力机制的计算效率较低。每个词元都要关注之前所有已生成的词元,因此每生成一个新词元,都要重新计算许多相同的值。例如,当生成第N个词元时,第(N-1)个词元要关注第(N-2)个词元、(N-3)个词元……直到第1个词元。同样,当生成(N+1)个词元时,第N个词元的注意力机制又需要关注第(N-1)个、(N-2)个、(N-3)个……直至第1个词元。KV缓存则用于保存注意力层的中间键/值,以便后续重复使用,避免重复计算。
4
内存带宽是关键
在LLM中,计算主要由矩阵乘法计算主导;这些维度较小的计算在大多数硬件上通常受内存带宽的限制。在以自回归方式生成词元时,激活矩阵的维度之一(由批大小和序列中的词元数定义)在小型批大小上较小。因此,速度由我们将模型参数从GPU内存加载到本地缓存/寄存器中的速度决定,而不是由计算加载数据的速度决定。相比峰值计算性能,推理硬件中可用和可实现的内存带宽能够更好地预测词元的生成速度。
对于服务成本来说,推理硬件的利用率非常重要。由于GPU的价格十分高昂,因此我们需要尽可能地让它们完成更多工作。共享推理服务通过将多个用户的工作负载组合在一起,填补各自的差距,并将重叠的请求进行批处理,以降低成本。对于LLaMA2-70B等大型模型,只有在较大的批大小下才能实现更好的性价比。拥有能够以较大批大小运行的推理服务系统对于成本效率至关重要。然而,较大的批大小意味着较大的KV缓存,这反过来又增加了部署模型所需的GPU数量。我们需要在这两者之间博弈,进行取舍,共享服务运营商需要权衡成本,优化系统。
5
模型带宽利用率(MBU)
LLM推理服务器的优化程度如何?
正如之前的简要解释,对于LLM来说,在更小的批大小下进行推理,特别是在解码阶段,其性能受到从设备内存到计算单元加载模型参数的速度限制。内存带宽决定了数据搬运的速度。为测量底层硬件利用率,我们引入了一个名为模型带宽利用率(MBU)的新指标。MBU的计算公式为(实际内存带宽)/(峰值内存带宽),其中实际内存带宽为((总模型参数大小+KV缓存大小)/ TPOT)。
例如,如果一个由70亿参数构成的16位精度的模型,在TPOT为14毫秒的情况下,它在14毫秒内传输了14GB的参数,这就意味着其带宽用量为1TB/秒。如果机器的峰值带宽为2TB/秒,则我们是以50%的MBU在运行。
为简单起见,这个例子忽略了KV缓存大小,在较小的批次大小和较短的序列长度上,KV缓存也较小。接近100%的MBU值意味着推理系统有效地利用了可用的内存带宽。MBU还可用于以标准化的方式比较不同的推理系统(硬件+软件)。MBU与模型FLOPs利用率(MFU,由PaLM论文引入的指标)互补,后者在计算受限的情况下非常重要。
图1以类似屋顶线图(roofline plot)的方式展示了MBU,橙色阴影区域中的实斜线表示内存带宽100%饱和时的最大可能吞吐量。然而,在现实情况下,对于小批次大小(白点),观察到的性能低于最大吞吐量,降低程度可通过MBU来度量。对于大批次(黄色区域),系统受计算限制,相对于理论最高吞吐量,实际所占的吞吐量以MFU衡量。
图1:展示了MBU(模型带宽利用率)和MFU(模型FLOPs利用率)。MBU是内存受限区域中达到的峰值分数,MFU是计算受限区域中达到的峰值分数。
MBU和MFU决定了在给定硬件设置上推进推理速度的可用空间。图2展示了用基于TensorRT-LLM推理服务器测算的不同张量并行度的MBU。当传输大的连续内存块时,内存带宽利用率达到了峰值。当MPT-7B等较小模型分布在多个GPU上时,因为我们在每个GPU中传输较小的内存块,所以我们观察到了较低的MBU。
图2:在A100-40G GPU上使用TensorRT-LLM,根据经验观察到的不同程度张量并行的MBU。请求:512个输入词元序列,批大小为1。
图3展示了在NVIDIA H100 GPU上,根据经验在不同级别的张量并行度和批大小下观察到的MBU。MBU随批大小的增加而减小。然而,随着GPU的扩展,MBU的减小相对不太显著。值得注意的是,具有更大内存带宽的硬件可以利用较少的GPU提升性能。在批大小为1的情况下,相比于4个A100-40GB GPU(图2),我们可以在2个H100-80GB GPU上实现更高的MBU(前者的MBU为55%,后者的MBU为60%)。
图3:在H100-80G GPU上,根据经验观察到的不同批大小和张量并行模式下的MBU。请求:包含512个输入词元的序列。
6
基准测试结果
时延
我们在MPT-7B和LLaMA2-70B模型的不同张量并行下测算了首个词元生成时间(TTFT)和单个输出词元时间(TPOT)。随着输入提示的长度增加,首个词元的生成时间开始占据整体时延的一大部分。通过在多GPU上进行张量并行,可以减少这种时延。
与模型训练不同,将规模扩展到更多GPU时,推理时延方面的收益会显著减少。例如,对于LLaMA2-70B模型,从4个GPU扩展到8个GPU时,仅在较小的批大小下将时延降低了0.7倍。原因之一是,较高的并行度导致较低的MBU(正如前文所述)。另一个原因是张量并行在GPU节点之间引入了通信计算开销。
表1: 输入请求后,对于长度为512个词元且批大小为1的情况,生成首个词元所需的时间。像LLaMA2 70B这样的较大模型至少需要4个A100-40B GPU才能匹配内存。
批大小更大时,更高的张量并行度导致词元时延的相对减少更加显著。图4显示了MPT-7B模型中单个输出词元的时间变化情况。批大小为1时,从2倍并行提升到到4倍并行仅将词元时延减少了约12%。而批大小为16时,4倍并行时延比2倍并行降低了33%。这与我们之前观察到的结果相符,即与批大小为1相比,批大小为16时的张量并行度越高,MBU的相对减少越小。
图4: 随着我们在A100-40GB GPU上扩展MPT-7B模型,每个用户的单个输出词元时延并不随着GPU数量的增加呈线性扩展。请求的词元序列包括128个输入词元和64个输出词元。
图5展示了LLaMA2-70B的类似结果,只是4倍并行和8倍并行之间的相对改进不太显著。我们还比较了两种不同硬件上的GPU扩展效果。由于H100-80GB的GPU内存带宽是A100-40GB的2.15倍,我们可以看到在批大小为1时,4倍并行系统的时延降低了36%,而在批量大小为16时,其时延降低了52%。
图5: 随着我们在多个GPU上扩展LLaMA-v2-70B模型(输入请求:512个词元长度),每个用户单个输出词元的时间如图所示。请注意,由于LLaMA-v2-70B(使用float16)无法适应1x40GB GPU、2x40GB GPU和1x80GB GPU系统,因此此处缺失以上系统的数据。
吞吐量
通过将请求进行批处理,我们可以权衡吞吐量和单个词元的时间。在GPU评估过程中,相较于逐个顺序处理查询,将查询进行分组可以增加吞吐量,但每个查询的完成时间会更长(忽略排队效应)。
几种常见的批处理推理请求技术如下:
-
静态批处理:客户端将多个提示打包到请求中,待批次中的所有序列完成后,返回响应。我们的推理服务器支持这种方式,但并不强制要求使用这种服务。
-
动态批处理:在服务器内部动态将提示进行批处理。通常情况下,这种方法的性能不如静态批处理,但如果响应很短或长度一致,则能够接近最佳性能。当请求具有不同参数时效果不佳。
-
连续批处理:这篇出色的论文(https://www.usenix.org/conference/osdi22/presentation/yu)提出了将请求在到达时一起进行批处理的理念,它是目前的SOTA方法。它不再等待批次中的所有序列完成,而是在迭代级别将序列进行分组。相比动态批处理,它可以实现10倍至20倍的更高吞吐量。
图6: LLM服务中的不同批处理类型。批处理是提高推理效率的有效方式。
批大小
批处理的效果很大程度上取决于请求流(request stream)。但通过统一请求对静态批处理进行基准测试,我们可以获得其性能的一个上限。
表2:基于静态批处理和基于FasterTransformers的后端,MPT-7B的峰值吞吐量 (req/sec) 。请求:512个输入词元和64个输出词元。对于较大输入,内存溢出边界将出现在较小的批大小。
时延权衡
随着批大小增加,请求时延也会增加。以一块NVIDIA A100 GPU为例,如果我们选择批大小为64以最大化吞吐量,时延将增加4倍,而吞吐量将增加14倍。共享推理服务通常选择一个平衡的批大小。自行托管模型的用户应该根据其应用程序来决定适当的时延/吞吐量权衡。在某些应用中,例如聊天机器人,低时延以获取快速响应是首要考虑因素。而在其他应用中,例如对非结构化PDF进行批处理时,为了并行快速处理所有文档,可能会牺牲单个文档的时延。
图7展示了7B模型的吞吐量与时延曲线。每条曲线代表通过将批大小从1增加到256所得到的结果,这对于确定在不同时延限制下可以设置多大的批大小非常有用。回顾上面的屋顶线图,我们发现这些测算结果与预期一致。在达到一定的批大小后,也就是当我们进入计算限制阶段时,每次批大小的加倍只会增加时延而不会增加吞吐量。
图7: MPT-7B模型的吞吐量时延曲线。这使得用户可以选择符合其时延要求的硬件配置,以满足其吞吐量需求。
在使用并行计算时,了解底层硬件细节非常重要。例如,在不同云平台上,并非所有的8xA100实例都相同。一些服务器在所有GPU之间具有高带宽连接,而其他服务器则将GPU成对配对,并且成对GPU之间的连接带宽较低。这可能会引入性能瓶颈,导致实际性能显著偏离上述曲线。
7
优化案例研究:量化
量化是一种常用技术,用于降低LLM推理的硬件需求。在推理过程中减少模型权重和激活值精度可显著降低硬件需求。例如,将权重从16位减少到8位,可以在内存受限的环境中(如A100上的LLaMA2-70B)将所需GPU数量减少一半。而将权重降低到4位,则使得用户在消费级硬件上进行推理成为可能(如Macbook上的LLaMA2-70B)。
根据我们的经验,使用量化技术应谨慎。简单粗暴的量化技术可能会导致模型质量显著下降,量化的影响还会因模型架构(例如MPT和LLaMA)和规模的不同而有所差异。
在尝试量化等技术时,我们建议使用像Mosaic Eval Gauntlet这样的LLM质量基准来评估推理系统的质量,而不仅仅是单独评估模型的质量。此外,探索更深入的系统优化也非常重要。具体而言,量化可以使KV缓存变得更加高效。
如前所述,在自回归词元生成中,通过注意力层获取的过去的键/值(KV)被缓存起来,而不是在每一步重新计算。KV缓存的大小取决于每次处理的序列数量以及这些序列的长度。此外,在每次生成下一个词元的迭代中,新的KV项目被添加到现有的缓存中,随着新词元生成,缓存变得更大。因此,在添加这些新值时,有效的KV缓存内存管理对于良好的推理性能至关重要。LLaMA2模型使用了一种名为分组查询注意力(GQA)的变体。请注意,当KV头的数量为1时,GQA与多查询注意力(MQA)相同。GQA通过共享键/值来帮助减少KV缓存的大小。KV缓存的计算公式为:
batch_size * seqlen * (d_model/n_heads) * n_layers * 2 (K and V) * 2 (bytes per Float16) * n_kv_heads
表3展示了在1024个词元的序列长度的不同批大小下计算的GQA KV缓存大小。相比之下,LLaMA2模型(70B)的参数大小为140GB(Float16)。将KV缓存进行量化是一种减少KV缓存大小的技术(除了GQA/MQA),我们正在积极评估其对生成质量的影响。
表3:序列长度为1024时,LLaMA-2-70B的KV缓存大小
8
结论与要点
上述提到的的每个因素都会影响我们构建和部署模型的方式。我们利用这些结果做出数据驱动的决策,综合考虑硬件类型、软件堆栈、模型架构和典型使用模式。以下是我们根据经验总结的一些建议。
明确优化目标:是否关注互动性能?是要最大化吞吐量?还是要最小化成本?其中存在可预测的权衡。
关注时延的组成部分:对于互动型应用,首个词元的时间影响你的服务响应速度,单个输出词元的时间决定其感觉起来有多快。
内存带宽是关键:生成第一个词元通常受到计算限制,而后续解码则受限于内存。由于LLM推理通常在内存受限的环境中运行,内存带宽利用率(MBU)是一个不错的度量标准,可用于优化并比较推理系统的效率。
批处理至关重要:能够同时处理多个请求对于实现高吞吐量和有效利用昂贵的GPU至关重要。对于共享在线服务来说,连续批处理不可或缺,而离线批次推理负载可通过更简单的批处理技术实现高吞吐量。
深度优化:标准推理优化技术(如算子融合、权重量化)对于LLM十分重要,但探索更深层次的系统优化同样重要,特别是那些改善内存利用的优化技术,例如KV缓存量化。
硬件配置:应根据模型类型和预期工作负载来决定部署的硬件。例如,当扩展到多个GPU时,相较于较大的模型(如LLaMA2-70B),小型模型(如MPT-7B)的MBU下降速度更快。性能也倾向于与较高程度的张量并行度呈次线性关系。尽管如此,对于较小的模型来说,如果流量较高或用户愿意为更低的时延支付溢价,较高的张量并行度可能仍有意义。
数据驱动决策:理解理论很重要,但我们建议始终测算端到端服务器的性能。推理部署性能低于预期的原因有很多,MBU可能因为软件效率低下而意外降低,云服务供应商之间的硬件差异也可能会带来意外情况(我们观察到两个云服务供应商的8台A100服务器之间存在2倍的时延差异)。
其他人都在看
试用OneFlow: github.com/Oneflow-Inc/oneflow/