LLM推理加速3:推理优化总结Mooncake/AttentionStore/vllm0.5/cache优化 etc

https://github.com/kvcache-ai/Mooncake

https://github.com/kvcache-ai/Mooncake/blob/main/Mooncake-v1.pdf

ZHANG Mingxing:Mooncake (1): 在月之暗面做月饼,Kimi 以 KVCache 为中心的分离式推理架构

KimiChat是由北京月之暗面科技有限公司(MoonshotAI)开发的一款人工智能助手产品,一年不到的时候就开始爆火,能够支持长达200w长文本的处理,让大家十分好奇如何能够做到这么好的模型效果,考虑到相关人员声称推理过程没有用到RAG技术,那么如何优化才能达到这么快的推理速度??

这几天终于有相关技术报告出来。这里简单介绍一下。

采用以KVCache为中心的分散式体系结构,将预填充和解码群集分开。核心是以KVCache为中心的调度器,它在最大化总体有效吞吐量和满足与延迟相关的服务级别目标(SLO)之间取得平衡

LLM推理简介

最大化总体有效吞吐量是LLM推理优化主要目标,这里也不例外。主要是首次token时间(TTFT)和单token迭代时间(TBT),简单说就是prefilling阶段耗时优化+decoding阶段耗时优化。

再简单说就是GPU和CPU、内存等资源尽量打满。那么就需要判断当前推理瓶颈在什么地方?(什么地方还有资源可以用)

  • 若是计算瓶颈,但所有的GPU打满了,那么是不是可以放到CPU进行计算。

  • 若是存储瓶颈,但是显存已经占满了,那么是不是可以放到内存中。

  • 若是传输瓶颈,是不是可以进行量化或者其他方式。

以LLaMA2-70B为例,分析Prefilling和decoding的吞吐量和和延迟如下。

Prefilling阶段是计算瓶颈,随着输入长度增加,耗时超线性增加(吞吐量下降,如果耗时线性增加,那么平均吞吐量不变)。

decoding阶段是传输瓶颈,随着bs的增大,耗时略有增加(主要是因为数据增多导致传输耗时增多,计算耗时基本认为不变),吞吐量大概是线性增加。

由于Prefilling和decoding的特性不同,对其进行分离已经是常用方法。有几篇论文都提到类似思路。

Splitwise: Efficient generative llm inference using phase splittingDistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Servinghttps://hao-ai-lab.github.io/blogs/distserve/akaihaoshuai:LLM推理加速调研Inference without interference: Disaggregate llm inference for mixed downstream workloads

分离后,如何最大效率的调度Prefilling服务器和Decoding服务器是核心。这里有两个要点:

  1. kv cache肯定是要用的(相比计算资源来说,存储更廉价和充足,需要优化kv cache的重复传输问题)。

  2. Decoding阶段要最大化batch(但是太大的bs也会导致平均单个token的生成时间变长)。

Mooncake Architecture

Mooncake整个请求的生成过程基本如下:

  • 1、每个请求创建一个prefiling instances和decoding instances实例对。

  • 2、尽可能多地将可重用的kv cache传输到所选择的prefiling instances,减少计算量;

  • 3、prefiling计算,以chunked/layer的形式完成预填充阶段,并将输出的kv cache连续流到对应的decoding instances

  • 4、加载kv cache并将请求添加到解码实例的continuous batching过程中,以生成请求输出。

在预填充阶段,主要目标是尽可能多地重用KVCache,以避免冗余计算。但是使用最频繁的kvcache block应该复制到多个节点以避免获取拥塞,而不怎么使用的block应该被换出以降低预留成本。

实际情况是复杂的。我们需要预测未来的负载,如果在预填充阶段之后没有可用的解码时隙,我们需要提前拒绝某些请求,以节省浪费的计算资源。然而,这种早期拒绝策略的直接实现出人意料地导致了过载的波动。这使得我们的目标是预测特定查询的生成长度,并在短期内进行整体负载预测,以实现更好的拒绝策略。

还需要对不同的请求优先级进行分类,以实现基于优先级的调度。本文将这些问题归结为面向过载的调度问题,并给出了初步的研究结果。

Mooncacke设计

使用chunked pipeline parallelism(CPP)机制来扩展跨多个节点的单个请求的处理,这是减少长上下文输入的TTFT所必需的。与传统的基于序列并行(SP)的解决方案相比,CPP降低了网络消耗,并简化了对频繁弹性伸缩的依赖。这一机制还补充了分层预填充,使KVCache的流传输能够重叠延迟。

以KVCache为中心的请求调度算法,平衡了TTFT和TBT SLO衡量的实例负载和用户体验。这包括基于启发式的自动化热点迁移方案,该方案无需精确预测KVCache的未来使用情况即可复制热KV缓存数据块。

与基准方法相比,月饼在满足SLO的同时可以实现高达525%的吞吐量提升。在实际工作负载下,月饼使Kimi能够处理75%以上的请求。

提前拒绝策略的实现,该策略减少了过载场景中计算资源的浪费。我们进一步探讨了由直接的早期拒绝引起的负荷波动问题,以及预测未来负荷如何缓解这一问题。

Mooncake架构

Mooncake采用了分解架构,不仅将预填充与解码节点分开,还将GPU集群的CPU、DRAM、SSD和RDMA资源分组,以实现分解的KVCache。这种分散的缓存利用未充分利用的资源来提供充足的缓存容量和传输带宽,从而在不增加成本的情况下实现高效的接近GPU的前缀缓存。

KVCache pool

在CPU内存中,KV缓存以分页块的形式存储。它可以使用缓存清除算法,如LRU(最近最少使用)、LFU(最不频繁使用)或基于请求特征的算法。这些KV缓存数据块的跨CPU和GPU的传输是由一个单独的(GPUDirect)基于RDMA的组件Messenger处理。这一架构还使我们能够向外部用户提供上下文缓存API,以便更高地重用KVCache。

名为Conductor的全局调度器调度所有这些分散的组件。Conductor负责根据KVCache和工作负载的当前分布来调度请求。如果对将来的推断有利,它还会复制或交换KVCache的某些数据块。

Conductor选择一对预填充节点和解码节点:

  1. KVCache重用:预填充节点(组)接收请求(包括原始输入、复用的kvcache内存ID、以及分配的完整kvcache内存块ID。它根据复用的kvcache块ID将缓存从CPU内存加载到GPU内存。如果不存在kvcache复用,则跳过此步骤。此选择平衡了三个目标:尽可能多地重复使用KVCache、平衡不同预填充节点的工作负载以及保证TTFT SLO。

  2. prefilling阶段如果新输入token的长度超过PREFILL_CHUNK,则prefilling会被拆分成多个chunk并以流水线方式执行。选择这个阈值是为了充分利用相应的GPU的计算能力,这个长度通常大于1000token。计算完成后将新生成的KVCache存储回CPU内存。

  3. KVCacheTransfer:在每个节点部署前述Messenger服务作为独立进程运行,并与上面的增量预填充计算步骤重叠,将每个模型层生成的KVCache流式传输到目的解码节点的CPU内存,以减少等待时间。

  4. decoding:在解码节点的CPU DRAM收到所有KVCache后,请求以连续分批的方式加入下一批。Conductor根据其当前负载预先选择解码节点。

Workflow of inference instances

chunked prefilling的出现,一定程度上降低了prefilling和decoding分离的必要性。

Layer-wise Prefill

如果一个请求的KVCache大小为S,处理时间为T,则其占用开销为S∗T。如果该请求被分块,并且每个块的处理都内联到分块预填充中的其他解码请求,则T会增加,从而导致更大的占用成本。

VRAM的有限大小也是一种宝贵的资源,目标是最小占用成本。

由于预填充是逐层处理的,并且受计算限制,因此可以将KVCache的传输和转储与计算重叠,从而进一步降低其占用成本。在每一层的注意力计算开始之前,模型等待该层的KVCache的异步加载完成,并触发下一层的异步KV缓存加载。在完成关注度计算后,启动该层的KVCache的异步存储。传输重叠允许预填充实例的执行时间大致等于KVCache加载时间或标准预填充时间,具体取决于前缀缓存的相对比例。

Layer-wise Prefill和不进行kvcache计算的延迟对比

以KVcache为核心的调度机制

对于每个新请求,Conductor根据请求长度和prefix_len(因实例而异)估计相应的执行时间。然后将该请求的估计等待时间相加,以获取该实例上的TTFT。Conductor将请求分配给TTFT最短的实例,并相应地更新该实例的缓存和队列时间。

为了预测请求的预填充阶段的计算时间,我们使用了从离线测试数据派生的预测模型。该模型基于请求的长度和前缀缓存命中长度来估计预填充计算时间。请求的排队时间是通过汇总所有排队请求的预填满时间来计算的。

由于较高的实例负载,请求可能不总是被定向到具有最长前缀高速缓存长度的预填充实例。在这种情况下,如果估计的额外prefilling时间短于传输时间,则指挥器将高速缓存的位置和请求转发到替代实例。如果最佳远程前缀匹配长度不大于当前本地可重复使用的前缀乘以阈值,则我们更愿意直接计算输入令牌。

为了验证该策略的有效性,我们进行了一个调度实验,将随机调度和负载均衡调度与该策略进行了比较。在随机调度中,为每个请求任意选择一个预填充实例。在负载均衡调度中,选择负载最轻的实例。

使用空闲的机器构建了一个由8个预填充实例和8个解码实例组成的集群。使用了23000个请求。

The prefill scheduling experiment in theMooncake cluster

请求过载调度

当请求超过一定阈值,剩余的请求将被直接拒绝(return网络不好请重试)或推迟以供稍后重试。

负载通常简单地通过正在处理的请求数量与系统的最大容量之比来衡量。Mooncake使用SLO满意度作为直接的负载测量。和 为当前请求的TTFT和TBT SLO约束。通过将实例上预测的最大TTFT和TBT与该请求的 和 进行比较来确定用于预填充和解码实例的负载。

如果在预填充阶段已经完成后,由于高负载而导致请求被解码实例拒绝,则在预填充阶段花费的计算资源是浪费的。为了优化,自然会将解码实例的负载评估提前到预填充阶段开始之前。我们将这种策略称为早期拒绝(开始时同于预估prefilling负载和decoding负载)。

在请求到达时,Conductor根据预填充池和解码池之间的较大负载来评估是否接受该请求。早期拒绝显著减少了被拒绝请求的无效计算,并增强了负载平衡。

显示了在使用早期拒绝策略后,在20台机器组成的集群中观察到的20分钟内的真实实例负载。它突出了预填充机和解码机之间显著的反相位波动。这一现象在预填充机较少的集群中以及在预填充阶段花费较长时间的情况下变得更加明显。

Early Rejection

我们发现这种负载波动问题的根源在于预测解码负载与实际执行之间的时延。基于当前解码负载的调度固有地被延迟。这种延迟会导致预填充和解码实例上的负载之间的波动和相位交错。

  • 在阶段1中,预填充实例和解码实例上的负载都很低,因此Conductor会接受大量请求,直到预填充实例上的负载达到极限。

  • 在阶段2中,预填充实例处理的请求被调度到解码实例,导致解码实例的负载很高。因此,Conductor会拒绝传入的请求,从而降低预填充实例的负载。

  • 在阶段3中,没有新的请求进入解码阶段,从而减少了负载。此时,Conductor再次接受大量请求,直到预填充实例完全加载。

  • 在阶段4中,随着解码实例上的负载增加,Conductor拒绝请求,从而导致预填充实例上的低负载。

这种在预填充和解码实例之间的负载的严重波动导致推理集群的资源利用率较差。

为了解决负载波动问题,我们提出了一种基于预测的早期拒绝框架。该框架预测传入请求的预填充阶段之后的解码负载,并使用该预测来决定是否接受请求,这有助于缓解波动问题。

1、请求级预测

如果能提前确定输出长度,就有可能更准确地估计TTFT和TBT。这将有助于预测解码实例可以完成的请求数量以及在指定时间之后将添加的新请求数量,从而获得该时间的负载。然而预测每个请求的输出长度是具有挑战性的,特别是在资源稀缺且需要准确预测的过载条件下,这使得请求级预测变得特别困难。

2、系统级预测

系统级预测估计指定时间之后实例的总批次计数或TBT状态。这种类型的预测正在进行中,需要的精度较低,使其更适合于超载情况。

Mooncake使用系统级预测:假设每个请求的decoding阶段花费的时间都是 。对于当前时刻t,从之前的直接估计当前时刻decoding负载,改为估计 时刻的decoding负载(记录每个decoding请求的起始时间,删除 时刻已经结束的请求 )。优化后的效果如下。

Early Rejection Based on Prediction

评估

在Arxiv摘要和L-EVAL数据集上,mooncake-[3P+1D]在满足SLO的情况下,吞吐量分别比vLLM-[4M]提高了20%和40%。mooncake-[2P+2D]在TTFT指标上表现不佳。这种差异是由于预填充和解码实例之间的负载不平衡造成的。

使用模拟数据进行端到端实验。模拟数据中的长上下文请求显著扰乱了vLLM的解码阶段。为了应对这种情况,vLLM单独处理请求,而不是成批处理。虽然月饼采用了批处理,但其两级分解设计有效地将预填充阶段对解码阶段的影响降至最低,确保其永远不会打破TBT SLO。与vLLM相比,在遵守相同的TTFT和TBT SLO限制的同时,月饼表现出显著更高的吞吐量,提升幅度从50%到525%不等。

我们评估过载情况下的性能,重点是系统可以处理的最大请求数量。在提前拒绝和基于预测策略的提前拒绝下,月饼分别拒绝了3,771和3,589个请求。这表明,通过提前拒绝请求,月饼可以避免不必要的预填充计算,从而提高系统资源的有效利用。此外,通过预测解码实例的负载,月饼可以缓解负载波动,提高请求处理能力。

未来工作

1、与其他线性变换算子不同,注意算子在解码阶段的算术强度仅与注意头数除以键/值头数成正比。这种强度不能通过增加批处理大小来增加,并且通常比其他操作符更受内存限制。因此,可以将注意算子与其他线性算子分开,以进一步提高资源利用率。根据我们的初步模拟结果,该体系结构具有提高总体吞吐量的巨大潜力。

Efficient and Economic Large Language Model Inference with Attention Offloading分析了LLM推理中的计算模式,特别是注意力操作符的内存密集型特性,以及它与现代加速器的优势不匹配的问题。介绍了异构架构的概念,使用内存优化的设备处理注意力操作,而使用计算优化的设备处理其他模型部分。开发了一个名为Lamina的LLM推理系统,在不同模型大小和上下文长度下,每美元的估计吞吐量提高了1.48倍至12.1倍。

2、DeepSeek-v2最近提出的MLA算子直接增加了运算强度。

3、减少KVCache的大小(跨层共用、量化等)。

4、复用prefix cache(system prompt变化越小,加速效果越好)

Prompt Cache: Modular Attention Reuse for Low-Latency Inferencehttps://github.com/yale-sys/prompt-cachePreble:Efficient Distributed Prompt Scheduling for LLM Serving

AttentionStore


Cost-Efficient Large Language Model Serving for Multi-turn Conversations with CachedAttention

这篇论文是针对多轮对话场景下,通过AttentionStore缓存系统保存历史对话的kv cache,以减少重复计算的方法。

AttentionStore作为GPU的外部存储,通过低速链路连接到GPU,为了减少KV缓存加载开销,CachedAttendant采用分层预加载方案,将加载KV缓存的时间与推理计算逐层重叠。

KV缓存会占用了大量的存储空间,需要将其放置在CPU甚至磁盘内存中,动态加载(一次性加载–>分层加载)。

比如在4*A100上运行Llama-65B,prefilling计算2k token需要360ms左右,而加载计算好的kv cache(5G,内存消耗很大)则只需要190ms左右。

注意:kvcache中包含了位置编码信息,不支持sliding window操作。虽然论文中提到了利用位置编码解耦截断方案来保存没有嵌入位置编码的KV缓存,从而支持直接在KV缓存上截断。但是个人感觉并不合理,除了第一次计算attention时得到的kv值没有pos信息外,之后的所有计算kv值的输入都是上一轮应用位置编码后进行attention计得到的,无法解耦位置编码信息。

kv cache加载过程如下,可以只把第一层的kvcacche保存在GPU中(5G/80层=64M),内存不大,可以接受。

若每层的prefilling耗时快于cache加载耗时,就会有bubble存在,此时可以预加载更多的layer

考虑到这么大的内存保存到GPU也是及其耗时的,因此也可以异步进行写入

Asynchronous KV cache saving.

耗时对比效果图下。CA(Cached Attention)相比Recomputed显著降低了耗时,并提高了Thoughout。

总结

AttentionStore主要介绍了多轮对话场景下的prefix prompt的预加载加速方法。

vllm0.5.0


vllm发布了0.5.0和0.5.0.post1版本

https://github.com/vllm-project/vllm/releases

ppt:https://docs.google.com/presentation/d/1iJ8o7V2bQEi0BFEljLTwc5G1S10_Rhv3beed5oB0NJ4/edit?usp=sharing

主要功能点如下

后续优化方向

vllm和FlashInfer的速度对比

prefix prompt caching加速

预测解码使用

Chunked Prefill

Taming Throughput-Latency Tradeoff in LLM Inference with Sarathi-Serve

当bs很大的时候,对速度有较大提升

模型FP8量化

速度上也有提升

Automatic Prefix Caching

通过共享prompt对应的cache,以内存换取计算速度的提升

Speculative Decoding

Accelerating Speculative Decoding using Dynamic Speculation Length

sarathi-serve—chunk prefilling


Taming Throughput-Latency Tradeoff in LLM Inference with Sarathi-Serve

https://github.com/microsoft/sarathi-serve

每个LLM服务请求经历两个阶段。第一个是预填充,它处理整个输入提示并生成第一个输出令牌,第二个是解码,它一次一个地生成其余的输出令牌。预填充迭代具有很高的延迟,但由于输入提示的并行处理而使GPU计算饱和。相反,译码迭代具有低延迟,但计算利用率也低,因为译码迭代每个请求仅处理单个令牌。

然而,对多个请求进行批处理会导致预填充和解码迭代的交织,这使得实现高吞吐量和低延迟都具有挑战性。

SarathiServe引入了分块预填充,它将预填充请求拆分成大小接近相等的块,并创建无停顿调度,从而在不暂停正在进行的解码的情况下批量添加新请求。

vllm0.5.0中引进了chunk prefilling。

https://docs.google.com/presentation/d/1iJ8o7V2bQEi0BFEljLTwc5G1S10_Rhv3beed5oB0NJ4/edit?usp=sharing

介绍

预填充阶段是计算受限的,因为它并行处理输入提示的所有令牌,而解码阶段是内存受限的,因为它一次只处理每个请求一个令牌。因此,解码从批处理中受益匪浅,因为较大的批处理可以更有效地使用GPU,而预填充不能从批处理中受益。当前的LLM推理调度器可以大致分为两类1,即预填充优先级排序和去剥夺排序。

  • FasterTransformer

采用解码优先级调度。这些系统向执行引擎提交一批请求,执行引擎首先计算所有请求的预填充阶段,然后调度它们的解码阶段。只要一个或多个请求正在进行解码,就不会调度新的预填充。

但是,解码优先级调度程序会严重影响吞吐量,因为即使批处理中的某些请求提前完成,执行也会继续,批处理大小会减小,直到最后一个请求完成。

  • vLLM

将迭代级批处理与预填充优先级调度相结合,其中它们急切地首先调度一个或多个请求的预填充阶段,即当GPU内存变得可用时。这样,预填充优先排序的调度器具有更好的吞吐量,因为首先计算预填充允许后续的解码以高批次大小运行。

然而,对预填充进行优先排序会导致高延迟,因为它会干扰正在进行的解码。

Sarathi-Serve基于两个关键思想:分块预填充和无失速调度。分块预填充-预填充将预填充请求拆分成相等的计算大小的块,并在多次迭代(每次使用提示令牌的子集)中计算提示的预填充阶段。无停顿调度允许新请求加入正在运行的批处理,而不会暂停正在进行的解码。

由Sarathi-Serve构造的混合批(由预填充令牌和解码令牌组成)具有近乎一致的计算需求。借助流水线并行性,我们可以创建基于微批处理的平衡调度,显著减少流水线气泡并提高GPU利用率,从而实现高效和可扩展的部署。

动机

预填充阶段并行处理所有输入令牌并有效地使GPU计算饱和,但解码阶段一次只处理一个令牌,效率非常低。

将预填充和解码计算时间分解为线性时间、注意力时间和其他时间。线性运算符贡献了大部分运行时成本。

矩阵乘法内核将存储器访问与数学运算的计算重叠。操作的总执行时间可以近似为T=max(Tmath,Tmem)。当Tmath=Tmem时,计算和内存带宽利用率都达到最大。

vLLM仅支持包含所有预填充请求或所有解码请求的批处理,可以通过最大化批处理大小来提高吞吐量。

  • VLLM通过在恢复正在进行的解码之前调度尽可能多的预填充来导致生成停滞。

  • Orca尽管支持混合批处理,但不能缓解生成停滞,因为包含长提示的批处理的执行时间仍然很长

  • FasterTransformer没有生成停滞,因为它在调度新的预填充之前完成所有正在进行的解码,但由于解码批次大小较低,因此会损害吞吐量。

Sarathi-SERVER生成的调度消除了生成停滞,同时提供了高吞吐量。

即使使用迭代级调度,流水线气泡也会在PP中浪费大量的GPU周期

识别了三种类型的气泡:

  • (1)由于在两个连续的微批次中预填充令牌的数量不同而发生的气泡(如PB1);prefilling & prefilling

  • (2)由于一个接着一个的预填充级和解码阶段的不同计算时间而发生的气泡(如PB2);prefilling & decoding

  • (3)由于关注成本取决于累积的上下文长度(KV-高速缓存的大小)并且因请求而异而由于微批次之间的解码计算时间不同而发生的气泡(如PB3)。decoding& decoding

对于FALCON-180B,4k token在prefilling阶段生成单个token时间为≈1150ms,而批次大小为32的decoding迭代的时间约为≈200ms。这些迭代的交错可能导致≈950ms的气泡。总的来说就是不同阶段的耗时不一致,导致并行处理时出现了bubble。解决方法就是将计算拆分,让每部分的耗时基本一致,并行处理的bubble就会降低很多。

Sarathi-Serve

prefilling阶段耗时长,那么将其拆分成多个chunk,使单个chunk的耗时接近单次decoding的耗时。如图所示,预填充吞吐量在512个令牌的序列长度左右开始饱和。

而输入prompt可能在数千个token,那么将其拆分成多个512的chunk,可以降低prefilling和decoding同时处理产生的延迟。

  • Stall-free batching

Sarathi-SERVE首先根据用户指定的SLO计算一批可执行的最大令牌数量的预算。在每一次调度迭代中,我们首先将所有运行的decoding打包到下一批(算法3中的第6-8行)。在此之后,打包部分完成的预填充(第9-12行)。只有在满足了所有运行的请求之后,我们才接受新的请求(第13-20行)。(肯定要优先处理先输入的数据)

当向批添加预填充请求时,先先当bs还剩几个,然后将新请求的部分chunk添加到进来(第11、15行)。通过在每次迭代中限制计算负载,无停顿批处理确保解码不会因为共同运行的预填充块而经历生成停滞。

我们比较了使用和不使用分块预填充的混合批处理的延迟。与仅解码批处理相比,朴素混合批处理导致TBT延迟显著增加28.3倍。相比之下,Sarathi-Serve通过分块提供了相当低的延迟。

这里就有一个问题,chunk按多少进行分块最合适。分块太大,仍存在较大的bubble。分块太小,无法充分充分利用GPU,并且由于softmax操作需要全部kv数据,太小的分块会增加内存访问次数。(即使在小块大小情况下,注意预填充操作也是计算受限操作。)

选择合适的令牌预算是一个复杂的决定,它取决于所需的TBT SLO、并行度配置和特定的硬件属性。在某些情况下,与使用块大小256相比,使用块大小为257的块可以将预填充时间增加32%。

效果评估

SLO-strict:在严格的延迟SLO下操作时,我们使用严格的象征性预算,并将提示拆分为较小的块。这会略微降低系统效率,但允许我们实现更低的尾部延迟。比如512个token

SLO-relaxed:当延迟限制放松时,我们增加令牌,以允许更有效的预填充。比如2048个token。

由上图可以看出,Sarathi-Serve相比vllm,提升明显。

使用三种不同的批处理大小来评估vLLM。

对于所有三种批处理大小设置,vLLM的容量基本保持相同。这意味着,即使PagedAttendant能够通过高效的内存管理实现大批量处理–在具有延迟限制的实际情况下,vLLM也无法利用大批处理大小,因为它的预填充优先级调度程序在延迟和吞吐量之间进行了巨大的权衡。不同chunk大小时prefilling阶段的开销增长情况

可以看出,较小的区块会带来较高的开销。然而,即使在最小的区块大小为512的情况下,我们也观察到适度的开销至多为∼25%。当token增加到2048以上,基本没有任何额外的开销。(一般设置在512~2048之间)

总结

针对prefilling阶段在优化吞吐量方面更好,而decoding阶段在优化TBT延迟方面更好的特点,将prefilling阶段进行chunk拆分,平衡了吞吐量和latancy,提高了server的整体性能。

KV cache筛选:PyramidKV


https://github.com/Zefan-Cai/PyramidKV

PyramidKV: Dynamic KV Cache Compression based on Pyramidal Information Funneling

由以往知识可知,decoding阶段是传输瓶颈,降低kvcache的内存可以有效提升decoding阶段的效率。

PyramidKV通过研究不同layer间的注意力机制,探索了跨层共享kvcache的效果。将更多的KV缓存分配给信息更加分散的较低层(前几层),每个KV包含的信息较少,同时减少较高层的KV缓存,其中信息变得集中在较少的关键token中。在仅使用12.0%KV缓存的情况下保持了性能,在极端条件下仅保留0.7%的KV缓存也可以有非常好的效果。

PyramidKV原理

那么问题来了,这么做的理论依据在哪里???

首先通过Llama处理数据集,对每一层的每个head计算的attention可视化,得到下图

attention可视化

可以看出在前几层,attention的分布大致较为均匀,信息比较分散。而在比较深层的layer中,attention分数较为集中,参考有人认为Attention计算是一个信息筛选机制,这里可以认为模型已经将需要的信息集中到了部分token中。其他的token由于值很低,最后被采样的概率也很低,因此可以考虑丢弃这部分token的cache。

最终就变成了在前几层使用全部的kvcache,越深的层使用越少的kvcache,那么就是把论文中提到的PyrimadKV。

想法有了,如何实现这个想法,保证模型质量不下降或者只有轻微下降。

1、首先要确定最前面的token和最近邻的token都包含重要信息,对生成效果影响显著,不能舍弃,用超参数控制,比如始终保留初始64个token和最近的128个token。

2、确定第一层和最后一层要保留的token总数,比如第一层是全部,最后一层是1/10(超参数控制)的token。那么中间layer需要保存的token数目从第一层到最后一层线性递减。

3、确定了token数目k就可以进行topk的选择。由于qk矩阵每一行的权重和value值加权平均后得到最终的hidden_status,因此筛选规则就是qk矩阵每一行的权重值。

最终筛选的效果图如下所示

每一层layer在decoding时,只加载对应数目的kvcache进行计算。

效果评估

评测效果上,在大海捞针测试中有不错的效果

Needle In A HayStack

在常规测评中也有不错的表现,尤其在kvcache size较小的时候,优势较为明显。

不同的压缩比下,模型质量下降并不明显

总结

PyramidKV方法发现了attention score随着layer的加深,分布从均匀到集中。因此定义了从第一个layer使用全部kvcache到最后一个layer只使用少部分重要kvcache的线性递减方法,筛选规则就是根据attention score进行topk筛选。

KV cache方法全面评估


KV Cache Compression, But What Must We Give in Return? A Comprehensive Benchmark of Long Context Capable Approaches

KV cache优化的方法有很多(量化、drop、压缩等),到底哪种方法好,本文进行了全面的评估。

Mistral-7B-Instruct-v0.2

rador图如下所示

rador

相比来说,KIVI量化方法效果最好,其次是 (cache剔除),这里没有对比PyramidKV,效果应该也不错错。

akaihaoshuai:LLM推理加速2:PRepBN/Turbo Sparse/MatMul-free/KIVI/Speculative Decoding

Character.AI架构


https://research.character.ai/optimizing-inference/

文中提到了为了优化QPS,使用了如下方法:

1、MQA。这已经是比较常用的加速方法了

2、混合注意力。将全局注意力和局部注意力(sliding windows)结合,每 6 层中只有 1 层使用全局注意力,大幅降低了kv cache占用。

Hybird Attention

3、跨层kv共享。由Character.AI提出,目前使用的较少。可以减少2~3倍的cache

Reducing Transformer Key-Value Cache Size with Cross-Layer Attention

Cross-Layer Attention

Cross-Layer Attention

4、system prompt缓存。与RadixAttention类似,将cache存储在具有树结构的LRU缓存中,提高cache加载效率。最终实现了95% 的缓存率,大幅降低了计算成本。

5、cache使用了int8量化。这点也比较常用,可以优化decoding阶段的传输效率。

总结


1、prefilling和decoding两阶段分离是一个方向,两阶段的瓶颈不同,高效的调度分配机制可以大幅提升分阶段计算的效率。

2、长上下文场景,chunked prefilling降低latency有效,但一定程度上降低了prefilling和decoding分离的必要性。

3、对prefilling阶段来说,在prompt变化不多的场景下 or 多轮对话场景下,prefix caching对提升相当明显(总的来说能cache的都cache,少计算)。

4、decoding阶段可以使用量化、压缩、共享kvcache进行加速,但生成质量会有一定程度的下降(减少cache内存,提高读cache的速度)。

5、估计了两阶段的负载,在开始时处理前对于可能超出负载的请求直接退回或延迟处理,优化服务器超载问题。

6、AttentionStore中提到了预加载和分层加载cache可以降低耗时。

7、通过评估LLM中Attention和MLP的计算量可知,当token<1536时,MLP计算量更大。当token>4608时,Attention的计算量平方增长特性才占据绝对主导地位,因此对于常规场景,MOE是比较好的加速方式。

线性Transformer应该不是你要等的那个模型 - 科学空间|Scientific Spaces

8、相关文章评测了kv cache优化的结果,其中KIVI量化效果最佳,其次是 (cache剔除),虽然没有对比PyramidKV(和H2O有些相似),但其效果也不错。

9、Character.AI中还是用了跨层kv cache共享机制,进一步降低了cache总量。

相关系列文章


  • akaihaoshuai:LLM前沿技术跟踪:比vllm更强的多节点推理框架LM-Infinite

  • akaihaoshuai:LLM前沿技术跟踪:PagedAttention升级版vAttention

  • akaihaoshuai:LLM推理加速调研

  • akaihaoshuai:LLM推理加速2:PRepBN/Turbo Sparse/MatMul-free/KIVI/Speculative Decoding

如何学习大模型 AI ?

由于新岗位的生产效率,要优于被取代岗位的生产效率,所以实际上整个社会的生产效率是提升的。

但是具体到个人,只能说是:

“最先掌握AI的人,将会比较晚掌握AI的人有竞争优势”。

这句话,放在计算机、互联网、移动互联网的开局时期,都是一样的道理。

我在一线互联网企业工作十余年里,指导过不少同行后辈。帮助很多人得到了学习和成长。

我意识到有很多经验和知识值得分享给大家,也可以通过我们的能力和经验解答大家在人工智能学习中的很多困惑,所以在工作繁忙的情况下还是坚持各种整理和分享。但苦于知识传播途径有限,很多互联网行业朋友无法获得正确的资料得到学习提升,故此将并将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。

在这里插入图片描述

第一阶段(10天):初阶应用

该阶段让大家对大模型 AI有一个最前沿的认识,对大模型 AI 的理解超过 95% 的人,可以在相关讨论时发表高级、不跟风、又接地气的见解,别人只会和 AI 聊天,而你能调教 AI,并能用代码将大模型和业务衔接。

  • 大模型 AI 能干什么?
  • 大模型是怎样获得「智能」的?
  • 用好 AI 的核心心法
  • 大模型应用业务架构
  • 大模型应用技术架构
  • 代码示例:向 GPT-3.5 灌入新知识
  • 提示工程的意义和核心思想
  • Prompt 典型构成
  • 指令调优方法论
  • 思维链和思维树
  • Prompt 攻击和防范

第二阶段(30天):高阶应用

该阶段我们正式进入大模型 AI 进阶实战学习,学会构造私有知识库,扩展 AI 的能力。快速开发一个完整的基于 agent 对话机器人。掌握功能最强的大模型开发框架,抓住最新的技术进展,适合 Python 和 JavaScript 程序员。

  • 为什么要做 RAG
  • 搭建一个简单的 ChatPDF
  • 检索的基础概念
  • 什么是向量表示(Embeddings)
  • 向量数据库与向量检索
  • 基于向量检索的 RAG
  • 搭建 RAG 系统的扩展知识
  • 混合检索与 RAG-Fusion 简介
  • 向量模型本地部署

第三阶段(30天):模型训练

恭喜你,如果学到这里,你基本可以找到一份大模型 AI相关的工作,自己也能训练 GPT 了!通过微调,训练自己的垂直大模型,能独立训练开源多模态大模型,掌握更多技术方案。

到此为止,大概2个月的时间。你已经成为了一名“AI小子”。那么你还想往下探索吗?

  • 为什么要做 RAG
  • 什么是模型
  • 什么是模型训练
  • 求解器 & 损失函数简介
  • 小实验2:手写一个简单的神经网络并训练它
  • 什么是训练/预训练/微调/轻量化微调
  • Transformer结构简介
  • 轻量化微调
  • 实验数据集的构建

第四阶段(20天):商业闭环

对全球大模型从性能、吞吐量、成本等方面有一定的认知,可以在云端和本地等多种环境下部署大模型,找到适合自己的项目/创业方向,做一名被 AI 武装的产品经理。

  • 硬件选型
  • 带你了解全球大模型
  • 使用国产大模型服务
  • 搭建 OpenAI 代理
  • 热身:基于阿里云 PAI 部署 Stable Diffusion
  • 在本地计算机运行大模型
  • 大模型的私有化部署
  • 基于 vLLM 部署大模型
  • 案例:如何优雅地在阿里云私有部署开源大模型
  • 部署一套开源 LLM 项目
  • 内容安全
  • 互联网信息服务算法备案

学习是一个过程,只要学习就会有挑战。天道酬勤,你越努力,就会成为越优秀的自己。

如果你能在15天内完成所有的任务,那你堪称天才。然而,如果你能完成 60-70% 的内容,你就已经开始具备成为一名大模型 AI 的正确特征了。

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

在这里插入图片描述

  • 9
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值