在本博客中,我们将介绍大型语言模型(LLM)推理的基础知识,并强调传统批处理策略的低效性。我们将介绍continuous batching,并讨论现有批处理系统的基准测试结果,如HuggingFace的文本生成推理和vLLM。通过利用vLLM,用户可以在减少p50延迟的同时实现23倍LLM推理吞吐量。
由于LLM的GPU内存占用和计算成本较高,服务在大多数实际应用中占主导地位。ML工程师通常将LLM视为只能通过量化、自定义CUDA内核等内部变化进行优化的“黑盒”。然而,情况并非完全如此。因为LLM迭代生成输出,并且因为LLM推理通常受内存限制而不是计算限制,所以存在令人惊讶的系统级批处理优化,这些优化在实际工作负载中可产生10倍或更多的差异。
最近提出的一种此类优化是continuous batching,也称为动态批处理或迭代级调度的批处理。我们想看看这种优化表现如何。下面我们将详细介绍,包括我们如何模拟生产工作负载,但要总结我们的发现:、
- 使用continuous batching和连续批处理特定的内存优化(使用vLLM),吞吐量提高多达23倍。
- 使用continuous batching,吞吐量比朴素的批处理高出8倍(在Ray Serve和Hugging Face的text-generation-inference上)。
- 使用优化的模型实现(NVIDIA的FasterTransformer),吞吐量比朴素的批处理高出4倍。
您今天可以尝试使用连续批处理:请参阅此示例以在Ray Serve上运行vLLM。
本博客的其余部分结构如下:
- 我们将介绍LLM推理工作原理的基本知识,并强调传统基于请求的动态批处理策略中的低效率之处。
- 我们将介绍连续批处理,并说明它如何解决基于请求的动态批处理中的许多低效率问题。
- 然后我们将讨论我们的基准测试,以及这对于如何经济高效地服务LLM模型有何影响。
LLM推断的基本原理
有很多关于LLM推断的知识,我们建议用户参考Efficient Inference on a Single GPU和Optimization story: Bloom inference以了解更多细节。然而,从高层次上看,LLM推断非常简单。
对于每个请求:
- 从一组token(称为“前缀”或“提示”)开始。
- LLM产生一组完成token,只有在产生停止标记或达到最大序列长度后才停止。
这是一个迭代过程。对于模型的每次新的前向传递,您可以获得一个额外的完成token。例如,假设您提示一个句子“加利福尼亚的首都是什么:”,它需要十次前向传递迭代才能得到完整的响应[“S”, “a”, “c”, “r”, “a”, “m”, “e”, “n”, “t”, “o”]。这个例子简化了一些事情,因为在实际情况中标记并不按1:1映射ASCII字符(一种流行的标记编码技术是字节对编码,这超出了本博客文章的范围),但是无论您如何标记您的序列,生成都是迭代性的。
简化LLM推理。本图示例展示了一个假设模型,该模型支持最大序列长度为8个标记(T1,T2,…,T8)。从提示标记(黄色)开始,迭代过程每次生成一个标记(蓝色)。一旦模型生成了序列结束标记(红色),生成循环就会停止。这个例子显示了一个只有一个输入序列的批处理,所以批处理大小为1。
现在,我们已经了解了LLM推理的简单迭代过程,让我们深入探讨一些您可能不知道的关于LLM推理的事情:
- 提示“What is the capital of California: ”的初始摄取(“prefill”)与生成每个后续标记所需的时间大致相同。这是因为预填充阶段预先计算了在整个生成过程中保持恒定的注意力机制的一些输入。这个预填充阶段有效地利用了GPU的并行计算,因为这些输入可以彼此独立地计算。
- LLM推理是内存IO约束,而不是计算约束。换句话说,目前将1MB数据加载到GPU的计算核心上所花费的时间比这些计算核心对1MB数据进行LLM计算所花费的时间要多。这意味着LLM推理吞吐量在很大程度上取决于您可以在高带宽GPU内存中适应多大的批处理量。请参阅NVIDIA文档中的此页面以了解更多详细信息。
- GPU内存消耗量与基本模型大小+标记序列的长度成比例。在每个LLM开发人员都应该知道的数字中,估计一个13B参数模型为每个序列标记消耗近1MB的状态空间。在具有40GB RAM的高端A100 GPU上,根据留在存储26GB模型参数后剩下的14GB,可以同时在内存中存储约14k个标记。这可能看起来很高,但实际上非常有限;如果我们将序列长度限制为512,则最多可以处理约28个序列批次。对于更高的序列长度,问题会更糟;2048个序列长度的意思是我们批次大小限制为7个序列。请注意,这是一个上限,因为它没有留下存储中间计算的空间。
这意味着,如果你能优化内存使用,可以说有很大的“桌面空间”。这就是为什么像AutoGPTQ这样的模型量化策略潜力如此强大的原因;如果你能通过从16位转移到8位表示来减少一半的内存使用,你就可以将更大的批量大小的空间翻倍。然而,并非所有策略都需要修改模型权重。例如,FlashAttention通过重新组织注意力计算,实现了显著的性能提升,同时减少了内存IO。
continuous batching是另一种不需要修改模型的内存优化技术。接下来,我们将解释朴素批处理是如何工作的(并且效率低下),以及连续批处理如何提高LLM生成的内存效率。
LLM Batching 解释
GPU是具有海量并行计算架构的设备,其计算速率(以每秒浮点运算次数衡量,或flops)在teraflop(A100)甚至petaflop(H100)范围内。尽管这些计算量惊人,但LLM很难实现饱和,因为芯片的内存带宽中有很大一部分用于加载模型参数。
批处理是改善这种情况的一种方法;您不必每次有输入序列时都加载新的模型参数,而是一次加载模型参数,然后使用它们来处理多个输入序列。这更有效地利用了芯片的内存带宽,从而提高了计算利用率、提高了吞吐量、降低了LLM推理的成本。
Naive batching / static batching
我们称这种传统的批处理方法为静态批处理,因为批大小在推理完成之前保持不变。以下是LLM推理中静态批处理的示意图:
使用静态批处理完成四个序列。在第一次迭代(左)中,每个序列从提示标记(黄色)中生成一个标记(蓝色)。在多次迭代(右)之后,完成的序列各有不同的大小,因为每个序列在不同的迭代中发出了其序列末标记(红色)。虽然序列3在两次迭代后完成,但静态批处理意味着GPU将在批处理中的最后一个序列完成
与传统的深度学习模型不同,LLM的批处理可能很棘手,这是由于它们的推理具有迭代性。直观地说,这是因为请求可能提前“完成”,但是释放其资源并添加可能处于不同完成状态的新请求是棘手的。这意味着,随着GPU在批次中不同序列的生成长度与最大生成长度不同而未充分利用。在上面的右图,这通过序列1、3和4的序列末标记后的白色方块来说明。
静态批处理不充分利用GPU的频率是多少?这取决于批次中序列的生成长度。例如,可以使用LLM推断来发射单个标记作为分类任务(有更好的方法可以做到这一点,但让我们以此为例)。在这种情况下,每个输出序列具有相同的大小(1个标记)。如果输入序列也具有相同的大小(例如,512个标记),则每个静态批次将实现最佳的GPU利用率。
另一方面,LLM驱动的聊天机器人服务不能假定固定长度的输入序列,也不能假定固定长度的输出序列。在撰写本文时,专有模型提供的最大上下文长度超过8K个标记。使用静态批处理,生成输出的变化可能会导致GPU严重未充分利用。难怪OpenAI首席执行官Sam Altman称计算成本高得惊人。
由于没有对用户输入和模型输出的限制性假设,未经优化的生产级LLM系统无法充分利用GPU并导致不必要的较高成本。我们需要优化我们如何为LLM提供服务,以使其能够广泛使用。
Continuous batching
业界认识到效率低下,并提出了更好的方法。Orca: A Distributed Serving System for Transformer-Based Generative Models是OSDI’ 22上发表的一篇论文,这是我们所知道的第一个解决这个问题的论文。Orca不是等待批次中的每个序列完成生成,而是实现迭代级调度,其中批量大小由每次迭代决定。结果是,一旦批处理中的序列完成生成,就可以在其位置插入新序列,从而产生比静态批处理更高的GPU利用率。
利用连续批次操作完成7个序列。左边显示单次迭代后的批处理,右边显示几次迭代后的批处理。一旦一个序列发出一个序列末尾标记,我们就在其位置插入一个新的序列(即序列S5、S6和S7)。这样可以提高GPU的利用率,因为GPU不会等待所有序列完成后再开始新的序列。
现实情况比这个简化模型要复杂一些:因为预填充阶段需要计算,并且与生成阶段的计算模式不同,所以不能轻易地与令牌的生成进行批处理。目前,连续批处理框架通过超参数管理等待预填充请求和等待序列结束标记的比例(waiting_served_ratio)。
说到框架,Hugging Face在他们基于Rust和Python的文本生成-推理LLM推理服务器中实现了连续批处理。我们使用他们的实现来了解以下基准测试中连续批处理的性能特征。
注意:连续批处理、动态批处理和迭代级调度在意义上是如此接近,以至于它们中的任何一个都可以用来描述批处理算法。我们选择使用连续批处理。动态批处理是适合的,但可能会与请求级批处理混淆,其中LLM推理服务器使用一个静态批来生成,该大小在当前批次完全生成完成时选择。我们认为迭代级调度是对调度机制的描述,但不是整个过程。
PagedAttention and vLLM
对于这篇博客文章,我们想展示静态批处理和连续批处理之间的区别。事实证明,通过改进Orca的设计,连续批处理可以释放静态批处理无法实现的内存优化。
PagedAttention是一种在vLLM(GitHub)中实现的新注意力机制。它从传统操作系统的概念中获得灵感,例如分页和虚拟内存。它们允许KV缓存(在上述“预填充”阶段计算的内容)通过分配固定大小的“页”或块来非连续分配内存。然后可以将注意力机制重写为在块对齐的输入上运行,从而允许在非连续的内存范围内执行注意力。
这意味着缓冲区分配可以即时发生,而不是提前发生:在开始新生成时,框架不需要分配大小为maximum_context_length的连续缓冲区。在每次迭代中,调度器可以决定是否需要为特定生成分配更多的空间,并动态分配内存,而不会降低PagedAttention的性能。这并不能保证内存的完美利用率(他们的博客称浪费现在限制在最后一个块的4%以下),但与当今行业广泛使用的提前分配方案相比,它显着提高了浪费率。
总之,PagedAttention+vLLM能够实现大量内存节省,因为大多数序列不会消耗整个上下文窗口。这些内存节省直接转化为更高的批大小,这意味着更高的吞吐量和更便宜的服务器。我们在下面的基准测试中包括了vLLM。
Benchmarking setup
我们的目标是在模拟的现实世界实时推理工作负载上查看连续批处理与静态批处理的表现如何。我们关心成本我们将其分解为吞吐量和延迟,因为成本直接与在给定延迟下服务的效率相关。
我们将在各自的结果部分讨论数据集和实验的其他细节。我们对由Anyscale提供的单个NVIDIA A100 GPU的吞吐量和延迟进行了基准测试。我们的A100拥有40GB的GPU RAM。我们选择Meta的OPT-13B模型是因为每个测试框架都可以与该模型进行集成。我们之所以选择13B,是因为它适合我们的GPU,不需要张量并行,但仍然足够大,可以应对内存效率挑战。虽然静态批处理和连续批处理都使用张量并行,但为了保持实验的简单性,我们选择不使用张量并行,其中每个变压器块被分割到多个GPU上。
测试框架如下表
我们测试了两种静态批处理框架和三种连续批处理框架。我们的静态批处理框架是:
- Hugging Face的Pipelines。这是最简单的推理解决方案。它提供了一个易于使用的API,可以与任何模型一起使用,并支持比简单文本生成更多的任务。我们将其用作基准。
- NVIDIA的FasterTransformer。这是一个提供各种变换器模型优化实现的库。它目前只提供静态批处理(Triton推理服务器提供请求级动态批处理,但尚未提供连续批处理)。这让我们了解了一个极其优化的模型实现可以在静态批处理方面达到什么程度-它提供了比Hugging Face Hub上相对未经优化的OPT-13B实现更具竞争力的基准。
我们的连续批处理框架是:
- Hugging Face的文本生成推理。这是Hugging Face用于支持其LLM实时推理API的推理服务器。它实现了连续批处理。
- Ray Serve上的连续批处理。Ray Serve利用Ray的无服务器功能提供无缝自动扩展、高可用性,并支持复杂的DAG。我们想了解连续批处理是如何工作的,因此我们在Ray Serve上使用纯Python重新实现了文本生成推理的核心连续批处理逻辑。正如您将在我们的结果中看到的那样,我们的实现达到了与文本生成推理相同的性能,这验证了我们的理解。
- vLLM。这是加州大学伯克利分校(GitHub)最近发布的开源项目。它建立在Orca的连续批处理设计之上,完全控制动态内存分配,使其能够显著减少GPU内存碎片的不同形式。我们测试这个框架,因为它展示了迭代级调度和连续批处理所能实现的进一步优化的影响。
Benchmarking results: Throughput
基于我们对静态批处理的了解,预计在每个批次的序列长度变化较大时,连续批处理的表现将显著更好。为了证明这一点,我们在每个数据集上对每个框架进行了四次吞吐量基准测试,每次数据集中序列长度的变化都较大。
为了做到这一点,我们创建了一个包含1000个序列的数据集,每个序列有512个输入令牌。我们将模型配置为始终按照每个序列的生成长度发出,通过忽略序列结束标记并配置最大令牌数。然后我们生成1000个生成长度,每个请求一个,从均值为128个令牌的指数分布中采样。我们使用指数分布,因为它是对ChatGPT等应用程序中可能遇到的生成长度的良好近似。为了使每次运行的方差不同,我们只从指数分布中选择小于或等于32、128、512和1536的样本。则总输出序列长度最多为512+32=544、512+128=640、512+512=1024和512+1536=2048(我们模型的最大序列长度)。
然后,我们使用简单的asyncio Python基准测试脚本来向我们的模型服务器提交HTTP请求。基准测试脚本以突发方式提交所有请求,以便计算饱和。
结果如下:
正如预期的那样,对于较低的方差生成长度,静态批处理和朴素的连续批处理的表现大致相同。但是随着方差的增加,朴素的静态批处理的性能直线下降到81个令牌/秒。FasterTransformers显著改进了朴素的静态批处理,几乎与朴素的连续批处理保持同步,直到生成长度限制为1536。Ray Serve和text-generation-inference上的连续批处理取得了与朴素连续批处理相同的性能,这是我们期望的,因为它们使用相同的批处理算法。
最令人印象深刻的是vLLM。对于每个数据集,vLLM相对于朴素的连续批处理将性能提高了一倍以上。我们还没有分析哪个优化对vLLM的性能贡献最大,但我们怀疑vLLM动态预留空间而不是提前预留的能力使vLLM能够大大增加批量大小。
我们将这些性能结果相对于朴素的静态批处理绘制出来:
注意FasterTransformer 4x改进有多令人印象深刻是很重要的;NVIDIA推出时,我们非常有兴趣对FasterTransformers和连续批处理进行基准测试。然而,即使使用优化模型,连续批处理也明显优于静态批处理。如果您像vLLM一样采用连续批处理和迭代级调度来实现进一步的内存优化,性能差距就会变得非常巨大。
Benchmarking results: Latency
实时推理端点通常面临必须根据用户需求进行优化的延迟-吞吐量权衡。我们针对实际工作负载对延迟进行基准测试,并测量每个框架的延迟的累积分布函数如何变化。
与吞吐量基准类似,我们配置模型以始终发出每个请求指定的指定数量的令牌。我们通过从1个令牌和512个令牌之间的均匀分布中采样长度来准备100个随机生成的提示。我们从带有mean=128和最大大小为1536的capped指数分布中采样100个输出长度。选择这些数字是因为它们是相当现实的,并允许生成使用我们的模型的全上下文长度(512+1536=2048)。
我们没有像在吞吐量基准中那样同时提交所有请求,而是将每个请求延迟预定的秒数。我们使用泊松分布采样来确定每个请求在前一个已提交请求之后的等待时间。泊松分布由λ(预期速率)参数化,在我们的情况下是每秒(QPS)有多少查询命中我们的模型端点。我们测量QPS=1和QPS=4时的延迟,以查看负载变化时延迟分布如何变化。
我们看到,在提高吞吐量的同时,连续批处理系统也改善了中位数延迟。这是因为连续批处理系统允许在每个迭代时将新请求添加到现有批次中(如果有空间)。但是其他百分位数的情况如何?事实上,我们发现它们改善了所有百分位数的延迟:
QPS=1时每个框架生成请求延迟的累积分布函数。静态批处理器和连续批处理器具有由连续批处理器中的迭代级批量调度引起的不同曲线形状。所有连续批处理器在此负载下表现大致相同;FasterTransformers在简单的模型实现上明显优于静态批处理。
QPS=4时每个框架生成请求延迟的累积分布函数。与QPS=1相比,FasterTransformer的延迟分布与简单模型上的静态批处理更相似。Ray Serve和text-generation-inference的连续批处理实现表现相似,但明显不如vLLM。
我们观察到FasterTransformer变得更类似于简单的静态批处理,并且text-generation-inference和Ray Serve的连续批处理实现看起来正在走向FasterTransformer的QPS=1曲线。也就是说,随着系统变得饱和,立即注入新请求的机会减少,因此请求延迟会增加。这与vLLM曲线一致-它在QPS=1和QPS=4之间基本保持不变。这是因为由于其先进的内存优化,它的最大批次大小更高。
据我们观察,vLLM在QPS=8左右达到饱和,吞吐量接近1900个令牌/秒。为了与其他服务系统进行同类比较,需要进行更多的实验;但是我们已经表明,连续批处理通过1)在可能的情况下立即注入新请求来减少延迟,以及2)启用高级内存优化(在vLLM的情况下)来显著改善静态批处理。
结论
LLM呈现了一些惊人的能力,我们认为它们的影响仍然大部分未被发现。我们分享了一种新的服务技术——连续批处理是如何工作的,以及它如何优于静态批处理。它通过减少浪费安排新请求的机会来提高吞吐量,并通过能够立即将新请求注入计算流中来改善延迟。我们很期待看到人们能够用连续批处理做什么,以及这个行业将走向何方。
注:本文为翻译稿,原文地址:Achieve 23x LLM Inference Throughput & Reduce p50 Latency (anyscale.com)
零基础如何学习AI大模型
领取方式在文末
为什么要学习大模型?
学习大模型课程的重要性在于它能够极大地促进个人在人工智能领域的专业发展。大模型技术,如自然语言处理和图像识别,正在推动着人工智能的新发展阶段。通过学习大模型课程,可以掌握设计和实现基于大模型的应用系统所需的基本原理和技术,从而提升自己在数据处理、分析和决策制定方面的能力。此外,大模型技术在多个行业中的应用日益增加,掌握这一技术将有助于提高就业竞争力,并为未来的创新创业提供坚实的基础。
大模型典型应用场景
①AI+教育:智能教学助手和自动评分系统使个性化教育成为可能。通过AI分析学生的学习数据,提供量身定制的学习方案,提高学习效果。
②AI+医疗:智能诊断系统和个性化医疗方案让医疗服务更加精准高效。AI可以分析医学影像,辅助医生进行早期诊断,同时根据患者数据制定个性化治疗方案。
③AI+金融:智能投顾和风险管理系统帮助投资者做出更明智的决策,并实时监控金融市场,识别潜在风险。
④AI+制造:智能制造和自动化工厂提高了生产效率和质量。通过AI技术,工厂可以实现设备预测性维护,减少停机时间。
…
这些案例表明,学习大模型课程不仅能够提升个人技能,还能为企业带来实际效益,推动行业创新发展。
学习资料领取
如果你对大模型感兴趣,可以看看我整合并且整理成了一份AI大模型资料包,需要的小伙伴文末免费领取哦,无偿分享!!!
vx扫描下方二维码即可
加上后会一个个给大家发
部分资料展示
一、 AI大模型学习路线图
整个学习分为7个阶段
二、AI大模型实战案例
涵盖AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,皆可用。
三、视频和书籍PDF合集
从入门到进阶这里都有,跟着老师学习事半功倍。
四、LLM面试题
五、AI产品经理面试题
如果二维码失效,可以点击下方链接,一样的哦
【CSDN大礼包】最新AI大模型资源包,这里全都有!无偿分享!!!
😝朋友们如果有需要的话,可以V扫描下方二维码联系领取~