在这篇博文中,我们分享了如何利用流行的开源大语言模型 (LLM) 进行生产使用的最佳实践。我们还提供了部署围绕这些模型构建的推理服务的指南,以帮助用户选择模型和部署硬件。 我们在生产中使用了多个基于 PyTorch 的后端;这些指南源自我们在 FasterTransformers、vLLM、NVIDIA 即将发布的 TensorRT-LLM 等方面的经验。
1. 了解LLM文本生成
大型语言模型 (LLM) 通过两步过程生成文本:“预填充”,其中并行处理输入提示中的令牌(Tokens),以及“解码”,其中文本在自回归中一次生成一个“令牌”方式。每个生成的令牌都会附加到输入并反馈到模型中以生成下一个令牌。当 LLM 输出特殊停止令牌或满足用户定义的条件(例如,已生成某个最大数量的令牌)时,生成停止。如果您想了解有关LLM如何使用解码器块的更多背景信息,请查看:LLM研发基础:Llama2大语言模型从原理到实战。
令牌(Tokens)可以是单词或子单词;将文本拆分为标记的确切规则因模型而异。尽管 LLM 推理提供商经常谈论基于令牌的指标(例如令牌/秒)的性能,但考虑到这些变化,这些数字并不总是在模型类型之间具有可比性。举一个具体的例子,Anyscale 团队发现 Llama 2 令牌比 ChatGPT 令牌长 19%(但总体成本仍然低得多)。HuggingFace 的研究人员还发现,Llama 2 需要比 GPT-4 多约 20% 的令牌来训练相同数量的文本。
2. LLM服务的重要指标
那么,我们到底应该如何考虑推理速度呢?我们的团队使用四个关键指标来衡量LLM服务:
-
首次令牌时间 (TTFT): 用户输入查询后开始看到模型输出的速度。较短的响应等待时间对于实时交互至关重要,但对于离线工作负载则不太重要。该指标由处理提示然后生成第一个输出令牌所需的时间驱动。
-
每个输出令牌的时间 (TPOT): 为查询我们系统的每个用户生成输出令牌的时间。该指标与每个用户如何感知模型的“速度”相对应。例如,100 毫秒/tok 的 TPOT 意味着每个用户每秒 10 个令牌,或每分钟约 450 个单词,这比一般人的阅读速度要快。
-
延迟: 模型为用户生成完整响应所需的总时间。总体响应延迟可以使用前两个指标来计算:延迟 = (TTFT) + (TPOT) *(要生成的令牌数量)。
-
吞吐量: 推理服务器每秒可以针对所有用户和请求生成的输出令牌数。
我们的目标是第一个令牌输出尽可能快、吞吐量尽可能高以及每个输出令牌的时间尽可能短。换句话说,我们希望我们的模型能够尽可能快地为我们支持的尽可能多的用户生成文本。
值得注意的是,吞吐量和每个输出令牌的时间之间存在权衡:如果我们同时处理 16 个用户查询,与顺序运行查询相比,我们将具有更高的吞吐量,但我们将花费更长的时间为每个用户生成输出令牌。
如果您有总体推理延迟目标,以下是一些用于评估模型的有用启发式方法:
-
输出长度决定总体响应延迟: 对于平均延迟,您通常只需将预期/最大输出令牌长度乘以模型每个输出令牌的总体平均时间即可。
-
输入长度对性能并不重要,但对硬件要求很重要: 添加 512 个输入令牌增加的延迟小于 MPT 模型中产生 8 个额外输出令牌的延迟。然而,支持长输入的需要可能会使模型更难以服务。例如,我们建议使用 A100-80GB(或更新版本)来服务 MPT-7B,其最大上下文长度为 2048 个令牌。
-
总体延迟与模型大小呈次线性关系: 在相同的硬件上,较大的模型速度较慢,但速度比不一定与参数计数比匹配。MPT-30B 延迟约为 MPT-7B 延迟的 2.5 倍。Llama2-70B 延迟约为 Llama2-13B 延迟的 2 倍。
潜在客户经常要求我们提供平均推理延迟。我们建议,在您将自己定位到特定的延迟目标(“我们需要每个令牌少于 20 毫秒”)之前,您应该花一些时间来描述您的预期输入和所需的输出长度。
3. LLM推理的挑战
优化 LLM 推理可受益于通用技术,例如:
-
运算符融合:将不同的相邻运算符组合在一起通常会带来更好的延迟。
-
量化:激活和权重被压缩以使用更少的位数。
-
压缩:稀疏或蒸馏。
-
并行化:跨多个设备的张量并行性或较大模型的管道并行性。
除了这些方法之外,还有许多重要的 Transformer 特定优化。一个典型的例子是 KV(键值)缓存。仅解码器、基于 Transformer 的模型中的注意力机制计算效率低下。每个令牌都会涉及所有以前见过的令牌,因此在生成每个新令牌时会重新计算许多相同的值。例如,在生成第 N 个令牌时,第 (N-1) 个令牌会涉及第 (N-2) 个、第 (N-3) 个……第一个令牌。类似地,在生成第 (N+1) 个令牌时,对第 N 个令牌的注意力再次需要查看第 (N-1) 个、第 (N-2) 个、第 (N-3) 个、…第一个令牌。 KV 缓存,即保存注意力层的中间键/值,用于保存这些结果以供以后重用,避免重复计算。
4. 内存带宽是关键
LLM中的计算主要以矩阵-矩阵乘法运算为主;在大多数硬件上,这些小尺寸的操作通常会受到内存带宽的限制。 当以自回归方式生成标记时,激活矩阵维度之一(由批量大小和序列中标记的数量定义)在小批量大小时较小。 因此,速度取决于我们将模型参数从 GPU 内存加载到本地缓存/寄存器的速度,而不是我们对加载数据进行计算的速度。推理硬件中可用的和已实现的内存带宽比其峰值计算性能更能预测令牌生成的速度。
就服务成本而言,推理硬件利用率非常重要。GPU非常昂贵,我们需要它们完成尽可能多的工作。共享推理服务有望通过组合来自多个用户的工作负载、填补各个空白并将重叠请求批量处理在一起来降低成本。对于像 Llama2-70B 这样的大型模型,我们只有在大批量时才能实现良好的性价比。拥有可以大批量运行的推理服务系统对于成本效率至关重要。然而,大批量意味着更大的KV缓存大小,这反过来又增加了为模型提供服务所需的GPU数量。这里存在一场拉锯战,共享服务运营商需要进行一些成本权衡并实施系统优化。
5. 模型带宽利用率 (MBU)
LLM推理服务器的优化程度如何?
正如前面简要解释的那样,LLM 在较小批量大小下的推理(尤其是在解码时)的瓶颈在于我们将模型参数从设备内存加载到计算单元的速度。内存带宽决定了数据移动发生的速度。为了衡量底层硬件的利用率,我们引入了一种称为模型带宽利用率 (MBU) 的新指标。MBU 定义为(实现的内存带宽)/(峰值内存带宽),其中实现的内存带宽为((总模型参数大小 + KV 缓存大小)/ TPOT)。
例如,如果以 16 位精度运行的 7B 参数的 TPOT 等于 14ms,那么它会在 14ms 内移动 14GB 参数,这意味着 1TB/秒的带宽使用量。如果机器的峰值带宽为 2TB/秒,则我们的 MBU 为 50%。为简单起见,此示例忽略了 KV 缓存大小,对于较小的批量大小和较短的序列长度来说,该大小较小。MBU 值接近 100% 意味着推理系统正在有效地利用可用内存带宽。MBU 还可用于以标准化方式比较不同的推理系统(硬件+软件)。MBU 是对模型触发器利用率(MFU;在 PaLM 论文中介绍)指标的补充,该指标在计算密集型设置中非常重要。
图 1 在类似于屋顶线图的图中显示了 MBU 的图形表示。橙色阴影区域的斜实线显示内存带宽在 100% 完全饱和时可能的最大吞吐量。然而,实际上,对于小批量大小(白点),观察到的性能低于最大值——MBU 的衡量标准是低多少。对于大批量(黄色区域),系统受计算限制,所实现的吞吐量作为可能峰值吞吐量的一部分,以模型失败率利用率 (MFU) 来衡量。
图 1:说明了 MBU(模型带宽利用率)和 MFU(模型触发器利用率)
MBU 和 MFU 分别是在内存限制和计算限制区域中实现的峰值的分数。 MBU 和 MFU 确定在给定硬件设置上还有多少空间可用于进一步提高推理速度。图 2 显示了使用我们基于 TensorRT-LLM 的推理服务器测量的不同张量并行度的 MBU。当传输大的连续内存块时,会达到峰值内存带宽利用率。当像 MPT-7B 这样的较小模型分布在多个 GPU 上时,我们会观察到较低的 MBU,因为我们在每个 GPU 中移动较小的内存块。
图 2:根据经验观察,在 A100-40G GPU 上使用 TensorRT-LLM 实现不同程度的张量并行性的 MBU。请求:512 个输入标记的序列,批量大小为 1。
图 3 显示了根据经验观察到的 NVIDIA H100 GPU 上不同张量并行度和批量大小的 MBU。MBU 随着批量大小的增加而减少。然而,当我们扩展 GPU 时,MBU 的相对下降就不那么显着了。还值得注意的是,选择具有更大内存带宽的硬件可以用更少的 GPU 来提高性能。在批量大小为 1 时,我们可以在 2xH100-80GB GPU 上实现 60% 的更高 MBU,而在 4xA100-40GB GPU 上实现 55%(图 2)。
图 3:根据经验观察 H100-80G GPU 上不同批量大小和张量并行模式的 MBU。请求:512 个输入标记的序列
6. 基准测试结果
6.1 延迟(Latency)
我们测量了 MPT-7B 和 Llama2-70B 模型不同张量并行度下的第一个令牌的时间 (TTFT) 和每个输出令牌的时间 (TPOT)。随着输入提示的延长,生成第一个令牌的时间开始消耗总延迟的很大一部分。跨多个 GPU 的张量并行有助于减少这种延迟。
与模型训练不同,扩展到更多 GPU 会显着降低推理延迟的回报。 例如。对于 Llama2-70B,在小批量大小下,从 4 倍 GPU 增加到 8 倍 GPU 仅将延迟降低了 0.7 倍。原因之一是并行度越高,MBU 越低(如前所述)。另一个原因是张量并行性引入了跨 GPU 节点的通信开销。
表 1:给定输入请求的第一个令牌的时间为 512 个令牌长度,批量大小为 1。Llama2 70B 等较大模型需要至少 4xA100-40B GPU 才能适应内存
在批量大小较大时,较高的张量并行度会导致令牌延迟相对显着减少。 图 4 显示了 MPT-7B 每个输出令牌的时间变化情况。在批量大小为 1 时,从 2 倍到 4 倍仅将令牌延迟减少约 12%。在批量大小为 16 时,4x 的延迟比 2x 的延迟低 33%。这与我们之前的观察结果一致,即与批量大小 1 相比,批量大小 16 的张量并行度较高时,MBU 的相对下降较小。
图 4:我们在 A100-40GB GPU 上扩展 MPT-7B 时每个用户每个输出令牌的时间。延迟不会随着 GPU 数量的增加而线性扩展。请求:128 个输入和 64 个输出令牌的序列
图 5 显示了 Llama2-70B 的类似结果,但 4 倍和 8 倍之间的相对改进不太明显。我们还比较了两种不同硬件上的 GPU 扩展。由于与 A100-40GB 相比,H100-80GB 的 GPU 内存带宽是 A100-40GB 的 2.15 倍,因此我们可以看到,对于 4x 系统,批处理大小 1 时的延迟降低了 36%,批处理大小 16 时的延迟降低了 52%。
图 5:我们在多个 GPU 上扩展 Llama-v2-70B 时每个用户每个输出令牌的时间(输入请求:512 个令牌长度)。请注意,此处缺少 1x40GB GPU、2x40GB 和 1x80GB GPU 编号,因为 Llama-v2-70B(float16 格式)不适合这些系统。
6.2 吞吐量(Throughput)
我们可以通过将请求一起批处理来权衡每个令牌的吞吐量和时间。与按顺序处理查询相比,在 GPU 评估期间对查询进行分组可提高吞吐量,但每个查询将需要更长的时间才能完成(忽略排队效应)。
有一些用于批量推理请求的常用技术:
-
静态批处理: 客户端将多个提示打包到请求中,并在批处理中的所有序列完成后返回响应。我们的推理服务器支持这一点,但不要求它。
-
动态批处理: 提示在服务器内动态批处理在一起。通常,此方法的性能比静态批处理差,但如果响应较短或长度统一,则可以接近最优。当请求具有不同参数时效果不佳。
-
连续批处理: 这篇优秀论文介绍了在请求到达时将请求一起批处理的想法,目前是 SOTA 方法。它不是等待批次中的所有序列完成,而是在迭代级别将序列分组在一起。它可以实现比动态批处理高 10 倍到 20 倍的吞吐量。
图 6:使用 LLM 服务的不同类型的批处理。批处理是提高推理效率的有效方法。
连续批处理通常是共享服务的最佳方法,但在某些情况下,其他两种方法可能更好。在低 QPS 环境中,动态批处理的性能优于连续批处理。有时,在更简单的批处理框架中实现低级 GPU 优化会更容易。对于离线批量推理工作负载,静态批处理可以避免大量开销并实现更好的吞吐量。
批量大小(Batch Size)
批处理的工作效果很大程度上取决于请求流。但是我们可以通过使用统一请求对静态批处理进行基准测试来获得其性能的上限。
表 2:具有静态批处理和基于 FasterTransformers 的后端的峰值 MPT-7B 吞吐量(请求/秒)。请求:512 个输入令牌和 64 个输出令牌。对于较大的输入,OOM 边界将采用较小的批量大小。
延迟权衡(Latency Trade-Off)
请求延迟随着批量大小而增加。例如,对于一个 NVIDIA A100 GPU,如果我们以批量大小 64 最大化吞吐量,则延迟会增加 4 倍,而吞吐量会增加 14 倍。共享推理服务通常选择平衡的批量大小。 托管自己模型的用户应为其应用程序决定适当的延迟/吞吐量权衡。在某些应用程序中,例如聊天机器人,低延迟以实现快速响应是首要任务。在其他应用程序中,例如非结构化 PDF 的批量处理,我们可能希望牺牲处理单个文档的延迟,以便快速并行处理所有文档。
图 7 显示了 7B 模型的吞吐量与延迟曲线。该曲线上的每条线都是通过将批大小从 1 增加到 256 来获得的。这对于确定我们可以在不同延迟约束下将批大小设置为多大非常有用。回顾上面的屋顶线图,我们发现这些测量结果与我们的预期一致。 在达到一定的批量大小之后,即当我们进入计算限制状态时,批量大小的每次加倍只会增加延迟,而不会增加吞吐量。
图 7:MPT-7B 模型的吞吐量延迟曲线。这允许用户在延迟限制下选择满足其吞吐量要求的硬件配置。
使用并行性时,了解底层硬件细节非常重要。例如,不同云中的所有 8xA100 实例并非都相同。一些服务器在所有 GPU 之间具有高带宽连接,而另一些服务器则对 GPU 进行配对,并且对之间的带宽连接较低。这可能会引入瓶颈,导致实际性能与上述曲线显着偏离。
7.** 优化案例研究:量化**
量化是一种常用技术,用于降低 LLM 推理的硬件要求。降低推理过程中模型权重和激活的精度可以显着降低硬件要求。例如,从 16 位权重切换到 8 位权重可以将内存受限环境中所需 GPU 的数量减少一半(例如 A100 上的 Llama2-70B)。权重降至 4 位使得在消费类硬件(例如 Macbook 上的 Llama2-70B)上运行推理成为可能。
根据我们的经验,量化应该谨慎实施。简单的量化技术可能会导致模型质量大幅下降。量化的影响也因模型架构(例如 MPT 与 Llama)和大小而异。我们将在以后的博客文章中更详细地探讨这一点。
在尝试量化等技术时,我们建议使用 LLM 质量基准(例如 Mosaic Eval Gauntlet)来评估推理系统的质量,而不仅仅是孤立模型的质量。此外,探索更深层次的系统优化也很重要。特别是,量化可以使 KV 缓存更加高效。
如前所述,在自回归令牌生成中,来自注意力层的过去的键/值(KV)被缓存,而不是在每一步重新计算它们。KV缓存的大小根据一次处理的序列数量和这些序列的长度而变化。此外,在下一个令牌生成的每次迭代期间,新的 KV 项都会添加到现有缓存中,使其随着新令牌的生成而变得更大。因此,添加这些新值时有效的 KV 缓存管理对于良好的推理性能至关重要。Llama2 模型使用一种称为分组查询注意(GQA)的注意力变体。请注意,当 KV 头数为 1 时,GQA 与 Multi-Query-Attention (MQA) 相同。GQA 通过共享键/值来帮助缩小 KV 缓存大小。
KV缓存大小的计算公式为 batch_size * seqlen * (d_model/n_heads) * n_layers * 2(K 和 V) 2(每个 Float16 字节) n_kv_heads。**
表 3 显示了在序列长度为 1024 个令牌的情况下在不同批量大小下计算的 GQA KV 缓存大小。相比之下,Llama2 模型的参数大小为 70B 模型的 140 GB (Float16)。KV 缓存量化是另一种减少 KV 缓存大小的技术(除了 GQA/MQA 之外),我们正在积极评估其对生成质量的影响。
表 3:序列长度为 1024 时 Llama-2-70B 的 KV 缓存大小
如前所述,在低批量大小下使用 LLM 生成令牌是一个 GPU 内存带宽限制问题,即生成速度取决于模型参数从 GPU 内存移动到片上缓存的速度。将模型权重从 FP16(2 字节)转换为 INT8(1 字节)或 INT4(0.5 字节)需要移动更少的数据,从而加快令牌生成速度。然而,量化可能会对模型生成质量产生负面影响。我们目前正在使用 Model Gauntlet 评估对模型质量的影响,并计划很快发布有关它的后续博客文章。
8. 结论和建议
我们上面概述的每个因素都会影响我们构建和部署模型的方式。我们使用这些结果来制定数据驱动的决策,同时考虑硬件类型、软件堆栈、模型架构和典型使用模式。以下是根据我们的经验得出的一些建议。
- 确定您的优化目标: 您关心交互性能吗?最大化吞吐量?成本最小化?这里存在可预见的权衡。
- 注意延迟的组成部分: 对于交互式应用程序,第一个令牌的时间决定了服务的响应速度,而每个输出令牌的时间决定了服务的速度。
- 内存带宽是关键: 生成第一个令牌通常受计算限制,而后续解码则受内存限制操作。由于 LLM 推理通常在内存受限的设置中运行,因此 MBU 是一个有用的优化指标,可用于比较推理系统的效率。
- 批处理至关重要: 同时处理多个请求对于实现高吞吐量和有效利用昂贵的 GPU 至关重要。对于共享在线服务,连续批处理是必不可少的,而离线批处理推理工作负载可以通过更简单的批处理技术实现高吞吐量。
- 深度优化: 标准推理优化技术对于LLM很重要(例如算子融合、权重量化),但探索更深层次的系统优化也很重要,尤其是那些提高内存利用率的优化。一个例子是 KV 缓存量化。
- 硬件配置: 应根据模型类型和预期工作负载来决定部署硬件。例如,当扩展到多个 GPU 时,较小模型(例如 MPT-7B)的 MBU 下降速度比较大模型(例如 Llama2-70B)下降得更快。随着张量并行度的提高,性能也趋向于次线性扩展。也就是说,如果流量较高或者用户愿意为超低延迟支付额外费用,那么高度张量并行性对于较小的模型可能仍然有意义。
- 数据驱动的决策: 理解理论很重要,但我们建议始终测量端到端服务器性能。推理部署的性能低于预期的原因有很多。由于软件效率低下,MBU 可能会出乎意料地低。或者云提供商之间的硬件差异可能会导致意外(我们观察到两个云提供商的 8xA100 服务器之间存在 2 倍的延迟差异)。