A Survey of LLM Inference Systems
James Pan · Guoliang Li
A1 主要贡献
本文是一篇关于大型语言模型(LLM)推理系统的综述。随着ChatGPT等服务的普及,对能够支持高性能模型服务的专用LLM推理系统的需求日益增长。这些系统设计的核心驱动力是LLM请求处理独特的自回归特性,它催生了在处理大容量、高速度工作负载时,既要实现高性能又要保持高质量推理的新技术。
核心问题与挑战:
LLM推理的自回归特性,即逐个生成token,导致其输出具有根本性的不确定性,从而带来三大挑战:
1. 输出质量不确定性: 输出是通过非确定性采样生成的,而非从数据中分析构建,因此无法保证其质量能完全满足请求表达的任务。
2. 内存使用不确定性: 由于执行轮数(即输出长度)未知,处理请求的最终内存使用量也未知,这给同时处理多个请求的系统带来了内存分配的挑战。
3. 处理时间不确定性: 请求处理时间同样不确定,这使得设计能够避免“掉队者”(stragglers)和“队头阻塞”(head-of-line blocking)等问题的批处理(batching)和调度(scheduling)技术变得困难。
研究目标与内容:
本综文旨在系统性地回顾和分析为应对上述挑战而发展的各种技术,并将它们置于一个完整的推理系统框架下进行讨论和比较。论文涵盖了LLM推理栈的各个层面,从用户前端到执行运行时,具体包括:
* 请求处理: 讨论了执行高质量LLM推理所需的基础算子(如Attention、FFN、Token Sampling)和序列生成算法(如流式生成、结构化生成)。
* 模型优化与执行: 涵盖了内核设计、批处理和调度技术。
* 内存管理: 详细介绍了分页内存、驱逐与卸载技术、量化和缓存持久化等。
* 系统架构: 探讨了如何将这些技术组合成单副本和多副本推理系统,包括能够更精细控制资源分配的解耦式推理系统和可部署于共享硬件基础设施的无服务器系统。
主要贡献与观点:
本文的主要贡献在于提供了一个全面的LLM推理系统框架,并阐述了各类技术如何组合成专用的LLM推理系统。文章指出,所有这些技术从根本上都依赖于负载预测(load prediction)、自适应机制(adaptive mechanisms)和成本降低(cost reduction)这三个核心原则,以克服自回归生成带来的挑战并实现系统目标。
A3 背景知识/关键Observation/设计原则
2 请求处理
基于Transformer的语言模型在一个离散的有限token集合上运行,针对一个输入token序列 $x_1...x_p$ 生成一个输出token。这是通过将token集合映射到高维向量空间,并对token嵌入应用简单的线性变换来生成 $x_p$ 的上下文嵌入,最终从中选择输出token来完成的。所有在第5节中介绍的LLM推理系统都使用基于Transformer的模型,遵循相同的基本推理工作流程,主要依赖于嵌入上的注意力(attention)、前馈(feed-forward)和token采样算子来生成输出token(第2.1节)。然而,注意力与前馈算子的高昂基础成本,以及生成语义连贯且可接受文本的需求,激发了大量关于算子设计的工作(第2.2节)。此外,由于token只能逐个生成的内在限制,生成长文本序列需要多轮模型执行,并且每个输出token对每轮的给定输入都高度敏感,这些担忧也导致了各种序列生成技术(第2.3节)的出现。面对这些多样化的请求处理技术,系统设计者必须仔细权衡这些技术的各种优缺点,以及它们如何与系统的其余部分设计相协调,其下游影响将在第2.4节讨论。
2.1 推理工作流
自回归生成过程。一个请求由一个初始输入 $x_1...x_p$ 组成,称为提示(prompt)或前缀(prefix)。响应是基于该提示的一个完整序列 $x_1...x_p...x_n$。计算token $x_{i+1}$ (当 $i \ge p$ 时),需要对之前所有的token执行一次模型运算,即 $x_{i+1} = LLM(x_1...x_i)$。因此,输出序列是通过将前一个token反馈回来,逐个token地形成的,这个过程被称为自回归生成。
Transformer层内部工作流。为了生成一个输出token,每个输入token都通过一个嵌入模型映射到一个高维嵌入。然后,这些嵌入流经一系列功能相同但参数不同的Transformer层,从而变得上下文相关。输入序列最后一个输入token的上下文嵌入被送入token采样器以生成输出token。图2展示了此工作流程。在每个Transformer层内部,有一个注意力算子与一个前馈网络(FFN)耦合,中间有一个归一化算子【索引97,Attention is all you need. NeurIPS'17】。注意力和FFN主要通过将嵌入与各种权重矩阵相乘来工作,这些矩阵的值是通过训练确定的。因此,这些算子的基础计算和存储(内存)成本取决于这些矩阵的大小。具体对于注意力算子,将其应用于第 $i$ 个嵌入需要对第 $j$ 个嵌入($j
性能与准确性指标。高成本表现为高的端到端延迟,包括从请求提交到生成完整输出序列之间的时间。但由于LLM的自回归特性,输出可以随着token的生成流式传输给用户。因此,对于像问答这样的交互式应用,只要token间时间(TBT)和首个token时间(TTFT)短,长延迟不一定会导致糟糕的用户体验。其他应用,如文档摘要,可能对token或请求吞吐量更敏感。对于对延迟和吞吞吐量都敏感的请求,有效吞吐量(goodput)可能是一个更有用的性能指标,定义为每秒在特定延迟目标(即服务水平目标,SLO)内完成的请求数量【索引104,Revisiting SLO and goodput metrics in LLM serving, 2024】。用户也要求高质量的输出。但由于用户提示可以表达各种各样的任务,从知识检索到语义操作【索引100,AOP: Automated and interactive LLM pipeline orchestration for answering complex queries. CIDR'25, 2025】,输出的质量高度依赖于任务,这使得通用质量指标难以确立。为了衡量LLM的通用质量,通常使用困惑度(perplexity)【索引17,Evaluation metrics for language models. Technical report, Carnegie Mellon University, 1998】。此外,对于特定任务,如机器翻译和文档摘要,已分别使用BLEU【索引77,BLEU: A method for automatic evaluation of machine translation. ACL'02, 2002】和ROUGE【索引57,ROUGE: A package for automatic evaluation of summaries. ACL'04, 2004】等指标。
2.2 算子
算子设计动机。对高性能和高准确性推理的渴望,激发了对注意力、FFN和token采样算子的新设计,超越了【索引97,Attention is all you need. NeurIPS'17】中的设计。对于注意力算子,【索引97】引入了多头注意力(MHA)机制以提高推理质量。分组查询注意力(GQA)【索引3,GQA: Training generalized multiquery transformer models from multi-head checkpoints. EMNLP'23, 2023】和多查询注意力(MQA)【索引90,Fast transformer decoding: One write-head is all you need, 2019】进一步发展了这个思想,通过减少转换矩阵的大小和数量来降低基础计算和内存成本。同样,许多工作专注于稀疏注意力,例如【索引99,FlashMask: Efficient and rich mask extension of FlashAttention, 2024】,其中注意力计算只部分应用,从而进一步降低成本。还有共享注意力的技术,例如【索引124,Split-K: A new method for efficient self-attention with prefix-aware KV cache and two-phase partition. ACL'24, 2024】,其中某些注意力输出在多个请求之间共享,从而减少内存负担。对于FFN,专家混合(MoE)技术通过将FFN分成多个小型独立网络来工作【索引64,A survey on inference optimization techniques for mixture of experts models, 2025】,从而减少计算负担。对于token采样,随机采样技术,如top-k采样和核采样(nucleus sampling)【索引37,The curious case of neural text degeneration, 2020】,通过探索token空间的狭窄区域之外来提高推理质量,而推测解码(speculative decoding)技术则利用小型草稿模型,随后进行并行验证来提高token吞吐量【索引118,Decoding speculative decoding, 2025】。
2.2.1 注意力
注意力计算公式。给定token $x_i$ 的嵌入 $x_i$,注意力算子产生一个增量向量 $u_i$,使得上下文嵌入向量 $x_i \leftarrow x_i + u_i$ 更好地捕捉该token的语义。向量 $u_i$ 的计算公式如下:
其中 $q_i^\top = x_i^\top W_q$。向量 $q_i$ 称为token $x_i$ 的查询(query),而 $q_i^\top K^\top$ 称为注意力模式(attention pattern)。矩阵 $K$ 和 $V$ 是由 $x_i$ 之前的token,即 $x_1...x_{i-1}$ 形成的。具体来说,K的第j行或键(key)$k_j$,以及V的第j行或值(value)$v_j$,分别对应第j个嵌入向量的线性投影,即 $k_j^\top = x_j^\top W_k$ 和 $v_j^\top = x_j^\top W_v$。因此,每执行一次注意力算子,K和V矩阵就会增加一行,以包含第i个token的投影。由于K和V矩阵在请求的整个生命周期中都会使用,它们被持久化在内存中,通常被称为KV缓存(KV cache)。
批处理能力。注意力算子也可以通过将嵌入垂直连接成一个嵌入矩阵,并将softmax替换为行式softmax,在单次调用中为整个token序列生成增量向量。所有嵌入的键和值向量在计算整个矩阵的注意力模式之前,使用嵌入矩阵一次性计算完成。这个能力导致了请求处理的两个阶段:预填充(prefill)阶段,将此技术应用于提示(prompt)token(图2(a));解码(decode)阶段,对生成的输出token应用公式1(图2(b))。此外,只要使用正确的键和值向量,嵌入矩阵甚至可以包含来自多个独立请求的嵌入,从而实现批处理(第3.2节)。但随着KV缓存的增长,算子成本越来越高,这导致了旨在降低成本的各种注意力变体。
预填充(Prefill)与批处理(Batching)。在预填充阶段,所有提示token的嵌入被垂直连接形成一个单一的输入矩阵X,然后与每个权重矩阵相乘以获得 $Q=XW_q$, $K=XW_k$, $V=XW_v$。更新向量随后通过以下公式获得:
其中softmax是按行应用的。上下文嵌入向量通过 $X \leftarrow X + U$ 获得。在数据并行硬件(如GPU)上,通过一次应用公式2来计算 $X \leftarrow X + U$ 比多次应用公式1更高效,即使基础成本相同。除了预填充,这个特性也促进了请求批处理(第3.2节),有效地允许在单次调用中为多个请求执行多个解码(图10)。这个特性也是使推测解码变得实用的原因。
注意力变体。对于具有长提示的请求,或需要大量解码轮次的长时间运行请求,K和V中的行数最终可能达到数万甚至数十万,增加了内存和计算成本。针对此问题,出现了多种注意力变体:
1. 多头注意力 (Multi-headed attention, MHA): 通过垂直分割 $W_q$, $W_k$, $W_v$ 来并行化公式1和2,基于这些小矩阵计算部分增量向量,然后聚合结果,同时也提高了推理质量【索引97,Attention is all you need. NeurIPS'17】。
2. 注意力分组 (Attention grouping): 包括分组查询注意力 (GQA)【索引3,GQA: Training generalized multiquery transformer models from multi-head checkpoints. EMNLP'23, 2023】和多查询注意力 (MQA)【索引90,Fast transformer decoding: One write-head is all you need, 2019】,通过丢弃一些小矩阵直接降低成本,如图4和表1所示。
3. 稀疏注意力 (Sparse attention): 通过仅为某些键计算注意力模式来降低计算成本(图14)。发现这些重要键的技术包括静态或查询相关的掩码和过滤器【索引4, 7, 24, 42, 52, 85, 99, 111, 113】以及k-近邻搜索索引【索引18, 61, 130】。
4. 共享注意力 (Shared attention): 通过在多个输入间共享注意力模式来降低内存和计算成本,这些输入可以属于单个请求(如波束搜索)或跨多个请求(如系统提示)【索引45, 119, 124, 136, 140】。该技术通过仅计算一次共享token的注意力模式来降低计算成本,同时通过在多个输入间共享内存条目来降低内存成本。
Table 1 主要注意力变体的特征。
2.2.2 前馈网络 (Feed-Forward Network)
FFN 计算过程。给定嵌入 $x_i$,前馈网络计算 $x_i \leftarrow f_2(g(f_1(x_i)))$,其中 $f_1(x_i) = x_i^\top W_1 + b_1$, $f_2(h) = h^\top W_2 + b_2$,而 $g(h)$ 是一个非线性激活函数,例如 $g(h) = max(0,h)$,它被逐元素应用。代入后得到:
计算和内存成本与参数的大小成正比。但与注意力不同,注意力的成本随KV缓存大小而变化,FFN对所有输入的成本是相同的。
专家混合 (Mixture-of-Experts, MoE)。在MoE系统中【索引91,Outrageously large neural networks: The sparsely-gated mixture-of-experts layer. ICLR'17, 2017】,FFN被一组更小的网络取代,每个网络称为一个专家(expert)。一个门(gate)决定使用哪个专家来处理给定的输入。由于每个专家都比原始FFN小得多,计算成本显著降低。关于MoE系统的大部分工作集中在专家的架构、门的设计、专家的动态加载以及专家计算的硬件优化上。在分布式设置中,还需要考虑专家的放置和负载均衡。感兴趣的读者可以参考【索引64,A survey on inference optimization techniques for mixture of experts models, 2025】。
2.2.3 Token 采样
采样过程。给定上下文嵌入 $x_i$,token采样器计算 $p = softmax(x_i^\top W_b)$ 来产生token范围内的概率质量,即logits。$p$ 的长度等于可能的token数量,通过一个 $p$ 的索引与token范围之间的映射来根据选定的索引决定token。在每个解码轮次贪婪地选择最大logit索引可能导致不自然的文本【索引106,Neural text generation with unlikelihood training, 2019】,这激发了替代的采样策略,例如top-k或核采样【索引37,The curious case of neural text degeneration, 2020】。同时,公式2的并行解码能力推动了旨在增加token吞吐量的推测解码技术【索引118,Decoding speculative decoding, 2025】。
采样策略。
* 贪婪采样 (Greedy sampling): 选择p中持有最大logit的索引,即 $\text{arg max}_{0 \le i \le |p|} p_i$。
* 概率采样 (Probabilistic sampling): 为了使生成的文本更自然,该策略根据实际logits随机选择下一个token。例如,如果 $p_i = 0.1$,那么尽管logit较低,i仍有不可忽略的被选中机会。该策略可以增加输出文本的多样性,但有风险有时会选择不合适的token。
* Top-k 采样: 该策略只在top-k个logits上进行概率采样,直接防止低概率的token被选中。
* 核采样 (Nucleus sampling): 在该策略下,k参数被设置为使其logit总和超过给定阈值的最小索引数【索引37,The curious case of neural text degeneration, 2020】。
推测解码 (Speculative Decoding)。推测解码的算法在【索引53,Fast inference from transformers via speculative decoding. ICML'23, 2023】中有给出和分析。简要来说,给定 $x_1...x_i$:
1. 使用一个独立的进程(如一个小型语言模型)来近似接下来的b个token, $\hat{x}_{i+1}, ..., \hat{x}_{i+b}$。
2. 并行运行主模型 $b+1$ 次,以便 $x_{i+1} = LLM(x_1...x_i)$, $x_{i+2} = LLM(x_1...x_i\hat{x}_{i+1})$, 以此类推,直到 $x_{i+b+1} = LLM(x_1...x_i\hat{x}_{i+1}...\hat{x}_{i+b})$。
3. 确定最小的 $j$ 使得 $\hat{x}_{i+j} \neq x_{i+j}$,然后返回 $x_1...x_{i+j}$。
关键在于,步骤2中的 $b+1$ 次并行执行可以由一次对 $LLM(x_1...x_i\hat{x}_{i+1}...\hat{x}_{i+b})$ 的调用得到,就像预填充(prefill)阶段一样,从而生成所有 $\hat{x}_{i+j}$ (对于 $0 \le j \le b$) 的上下文嵌入向量集合【索引118,Decoding speculative decoding, 2025】(图5)。从这些向量中,可以通过采样获得每个 $x_{i+j}$ token。关于草稿(步骤1)和验证(步骤2和3)阶段的技术,在【索引110, 118, 139】中有综述。
2.3 序列生成
流式生成。为了生成一个完整的输出序列,可以将部分生成的序列递归地反馈给模型以生成下一个token,直到达到终止条件(例如生成终止token)。然而,提示中的微小差异,例如思维链(CoT)【索引105,Chain-of-thought prompting elicits reasoning in large language models. NeurIPS'22, 2022】,少样本示例(few-shot examples)【索引115,Does few-shot learning help LLM performance in code synthesis?, 2024】以及其他提示工程技术【索引86,A systematic survey of prompt engineering in large language models: Techniques and applications, 2025】,都可能在输出中产生巨大差异,对成本和准确性都有影响。
* (1) 思维链(Chain-of-thought, CoT)提示: 在提示中插入“展示你的工作”等关键短语,以引导LLM产生更长的响应,增加生成更好完成任务的文本的机会【索引105】。
* (2) 少样本示例(Few-shot examples): 在提示中附加一些所需任务的已完成实例,目标类似【索引115】。
* (3) 内化CoT(Internalized CoT): 除了直接操纵提示,还可以训练模型来模拟这些技术的效果,而无需显式插入这些关键短语。例如,内化CoT是一种技术,其中模型通过奖励引导的强化学习被训练或微调,以生成类似于思维链的输出【索引28,Efficiently serving LLM reasoning programs with Certaindex, 2024】。感兴趣的读者可以参考【索引86】获取提示工程技术的综述。
结构化生成。结构化方法维护一个潜在输出序列的集合,自回归地推进每个候选序列,直到需要选择其中一个作为最终输出序列。这些方法会增加请求处理成本,但可以为许多任务带来更高质量的输出。
* (1) 波束搜索(Beam search): 同时跟踪k个候选序列,如图6所示。对于每个序列,采样多个潜在的输出token,然后保留所有样本中总分最高的k个token,推进相应的序列,同时修剪其余的。一旦k个序列都完全推进,累积logits最大的序列将作为最终输出返回【索引34,Sequence transduction with recurrent neural networks, 2012】,其变体在【索引27,Beam search strategies for neural machine translation. WNMT'17, 2017】中有介绍。
* (2) 思维树(Tree-of-thoughts): 将候选序列组织在一个搜索树中。树的每个节点代表一个潜在的输出,并对每个节点应用各种提示策略以生成下一级节点【索引122,Tree of thoughts: Deliberate problem solving with large language models. NeurIPS'23, 2023】。
* (3) 思维图(Graph-of-thoughts): 通过将节点视为逻辑图,引入了对节点的额外操作,例如从多个父节点聚合【索引8,Graph of thoughts: Solving elaborate problems with large language models. AAAI'24, 2024】。
* (4) 自洽性(Self-consistency): 为了避免低质量的候选者,该技术修剪与其他候选者最不相似的候选者,以鼓励剩余的候选者收敛到一个高质量的输出【索引101,Self-consistency improves chain of thought reasoning in language models. ICLR'23, 2023】。
2.4 讨论
自回归处理的根本挑战。支持自回归请求处理的需求定义了LLM推理系统,并将其与其他大规模数据处理系统区分开来。由于这一特性,处理请求的成本与输出长度挂钩。但关键是,除了应用程序约束输出序列的情况外(见第5.1节),最终长度是无法预知的。由于注意力算子的作用,提示嵌入之间的复杂交互使得分析性地确定终止前的轮数变得困难。这种根本性的不确定性,尤其是在内存方面,催生了像分页注意力(第4.1节)和作业再平衡(第3.3节)这样的技术,这些技术试图适应动态变化的内存条件,以及旨在预测总请求内存成本(第3.4节)或从根本上降低这些成本(第4.3节)的技术。
各种技术的系统设计考量。同时,注意力、FFN和token采样技术以及序列生成技术都是自包含的,可以被任何推理系统轻松采用。但它们独特的特性必须在系统设计中加以考虑。例如,推测解码需要一个独立的草稿模型,这使得执行工作流复杂化,并且最终不能保证更高的吞吐量。因此,它可能更适合于草稿模型成功率高的应用,例如基于常识知识检索的任务,而不是依赖于输出多样性的任务,例如创造性合成。对于那些最终用准确性换取效率的技术,如稀疏注意力和MoE,以及用效率换取准确性的技术,如结构化生成,也存在类似的考虑。
未来展望。展望未来,LLM在各行各业乃至自然语言之外领域的持续扩展【索引68,Projecting molecules into synthesizable chemical spaces, 2024】,加上专用硬件的趋势【索引50,LoL-PIM: Long-context LLM decoding with scalable DRAM-PIM system, 2025】,为有针对性的算子设计和序列生成策略提供了越来越多的用例,可能受益于这些策略,包括强化学习方法【索引21,DeepSeek-R1: Incentivizing reasoning capability in LLMs via reinforcement learning, 2025】、新颖的提示策略【索引134,ReAcTable: Enhancing ReAct for table question answering. Proc. VLDB Endow., 2024】等。在这些领域出现的任何新技术都可能导致对推理系统设计的重新评估。
A2 方法细节
3 模型优化与执行
通用CPU在主要为数据并行性质的操作上远不及GPU和其他极端并行处理器架构。为了最大限度地利用这种能力,催生了旨在为GPU执行推理算子开发优化内核程序的内核设计技术(第3.1节)。这些设备提供的极端计算能力也导致了旨在饱和这种能力同时关注如掉队者(stragglers)和因KV缓存增长导致的内存超额订阅等问题的请求批处理技术(第3.2节)。类似的考虑也激发了请求调度技术(第3.3节),包括作业优先级和负载均衡技术。这些技术取决于能否准确预测一个请求在其生命周期内的总内存成本,以及执行轮数。在没有准确预测的情况下,可以使用缓解策略来适应新的内存条件。这些技术在第3.4节中集体讨论。
3.1 内核 (Kernels)
物理算子成本的来源。物理算子成本除了算子设计本身带来的基础因素外,还包括多种因素,如运行时的I/O成本(由算子执行期间读写中间产物引起)和调用成本(由加载和卸载中间程序进出处理器核心引起)。对于LLM推理,由于注意力和FFN算子可能产生的大量矩阵乘积(即激活值),I/O成本尤为重要。对于基于GPU的工作流,由于完成单个算子可能需要单独启动多个内核,调用成本也可能变得显著。
内核优化技术。内核融合(Kernel fusion)【索引11,Optimizing tensor computations: From applications to compilation and runtime techniques. SIGMOD'23, 2023】将多个操作流水线化到一个单一内核中,从而同时避免了中间结果的物化和调用成本。这项技术结合分块矩阵乘法【索引75,Stream-K: Work-centric parallel decomposition for dense matrix-matrix multiplication on the GPU, 2023】和在线softmax【索引69,Online normalizer calculation for softmax, 2018】,激发了分块注意力内核(blockwise attention kernels)的开发【索引38, 88, 125】,相比使用通用GPU内核,提供了巨大的速度提升,以及旨在通过多个GPU加速推理的分布式注意力内核【索引63,Ring attention with blockwise transformers for near-infinite context, 2023】。这些技术也启发了注意力之外的其他算子内核,包括FFN【索引62,Blockwise parallel transformers for large context models. NeurIPS'23, 2023】以及非矩阵算子【索引102, 128, 129】。
3.1.1 注意力内核 (Attention Kernels)
注意力内核的挑战。公式2中的注意力算子需要计算两个矩阵乘积以及softmax。虽然矩阵乘法期间的单个标量乘法和加法是可交换和可结合的,允许简单的并行化,但天真地将标量操作分布到GPU的处理器核心(即SM单元)上可能会因掉队者(stragglers)而导致低利用率。此外,物化中间矩阵乘积需要昂贵的I/O。
分块注意力(Blockwise Attention)。为了提高核心利用率,Stream-K【索引75】将矩阵乘积划分为缓存局部(cachelocal)的块(tiles),并顺序地将每个块中的标量乘积分配给处理器核心,如图7(c)所示。这种流式机制被证明可以消除其他策略(如轮询分配,图7(a);或固定分割分配,图7(b))可能导致的空闲工作单元。虽然该技术可直接用于注意力机制中的矩阵乘积,但它仍然需要在应用softmax之前物化完整的 $QK^\top$ 中间产物(图8(a))。在【索引69】中,给出了一种在线计算softmax的数值方法,其中归一化项是在线收集的,无需完全物化。在线softmax为融合注意力乘积的分块化提供了可能性(图8(b)),这一想法在FlashAttention【索引20,FlashAttention: Fast and memory-efficient exact attention with IOawareness. NeurIPS'22, 2022】(采用轮询分配)、FlashDecoding【索引38,FlashDecoding++: Faster large language model inference with asynchronization, flat GeMM optimization, and heuristics. MLSys'24, 2024】(采用固定分割分配)以及Lean Attention【索引88,Lean attention: Hardware-aware scalable attention mechanism for the decode-phase of transformers, 2025】和FlashInfer【索引125,FlashInfer: Efficient and customizable attention engine for LLM inference serving, 2025】(采用流式分配)中得到了探索。现在已经有许多针对其他注意力变体(主要是稀疏注意力)的下游内核,主要采用了这些技术。例如,FlashMask【索引99】将融合注意力推广到支持注意力掩码。给定任意掩码算子,FlexAttention【索引24,Flex Attention: A programming model for generating optimized attention kernels, 2024】会根据该算子编译一个新的融合注意力内核。自动生成的内核提供了与手工制作的内核(如FlashAttention)相似的加速效果。
分布式注意力(Distributed Attention)。Ring Attention【索引63】考虑了注意力算子分布在多个设备上,而不仅仅是在单个设备的处理器核心上并行化的情况。Q矩阵按行分块,使得每个工作设备获得对应于一个提示片段的查询子集,然后K矩阵按列分块并分发给工作设备。为了写入一个注意力行,每个工作设备必须处理每一个K矩阵块,这需要一个可以协调块从一个工作设备传输到下一个的交换机制。Ring Attention采用了一种去中心化机制,其中工作设备按确定性顺序传输块,同时将通信与块处理重叠以减少有效开销。图9展示了一个简化的例子。
3.1.2 其他内核
FFN和其他算子的内核优化。对于FFN,函数 $f_1, f_2$ 和 $g$ 都可以逐元素实现,这使得将它们流水线化到一个单一的融合内核中成为可能。这个特性还允许它直接与分块注意力内核融合,从而带来适度的延迟降低【索引62】。对于其他算子,LightSeq【索引102,LightSeq: A high performance inference library for transformers. NAACL'21, 2021】将连续的非GeMM操作组合成单一的融合内核,为层归一化、张量重塑、softmax和ReLU激活等操作产生了几个手工制作的内核。结果是每个Transformer块的内核调用次数相比基于供应商内核的实现减少了4倍。类似的技术也用于【索引25, 128, 129】。除了融合内核,DeepSpeed-Inference【索引5,DeepSpeed-Inference: Enabling efficient inference of transformer models at unprecedented scale. SC'22, 2022】利用CUDA Graphs通过一次调用启动多个内核。
3.2 批处理 (Batching)
批处理基本原理。在计算注意力模式之前,输入嵌入会乘以 $W_Q, W_K, W_V$ 以产生低维的查询、键和值向量。这些向量可以通过计算单个矩阵乘积来生成,对于多个批处理的请求,可以通过水平连接权重矩阵和垂直连接token嵌入来实现。得到的向量同样可以与KV缓存中的向量连接起来,形成用于批处理注意力的三维矩阵输入。图10(a)展示了这一技术。如果批处理注意力算子的输入是“不规则的”(ragged),也就是说每个请求的查询和键矩阵的长度或宽度不相等,那么计算矩阵乘积可能会因为矩阵稀疏而导致处理器核心利用率不足。这种情况在解码阶段由于请求的KV缓存大小不等,以及在预填充阶段由于提示长度不等而频繁出现。另一方面,将批次拆分(bursting)可以避免稀疏矩阵,但需要为批次中的每个请求单独启动内核【索引126,Orca: A distributed serving system for transformer-based generative models. OSDI'22, 2022】(图10(b))。
批处理频率与大小的影响。批处理的频率和大小会影响内存超额订阅和由“掉队者”(stragglers)引起的延迟等问题。在静态批处理(static batching)下,一个批次中的每个请求都会执行到完成,然后才处理下一个批次,这可能导致掉队者延迟整个批次。此外,由于解码轮数未知,静态批处理存在内存容器超额订阅的风险,因为内存使用量在每轮后都会增加。动态批处理(Dynamic batching)【索引2, 126】可用于减轻掉队者的影响,而仔细控制批次大小可用于避免超额订阅,特别是与作业优先级(第3.3节)和内存管理技术(第4节)结合使用时。
动态批处理 (Dynamic Batching)。使用静态批处理时,批次中的请求会一起执行并返回,因此它们的延迟看起来是相等的,即使某些请求可能在其他请求之前很久就已终止。为了避免掉队者延迟批次完成,(1)连续批处理(continuous batching)在每次执行轮次后重新构建批次,而不是在完成时【索引126】(图11)。这种简单的机制提供了对请求执行的更大控制。例如,如果批次中的一个请求在执行轮次后完成,其KV缓存可以立即被驱逐,为下一个排队的请求加入批次腾出空间。(2)分块预填充(Chunked prefills)将连续批处理的思想扩展到预填充阶段,通过将提示分割成小块,在多个执行轮次中处理【索引2,Taming throughput-latency tradeoff in LLM inference with SarathiServe. OSDI'24, 2024】。
批次大小 (Batch Size)。对于静态批处理,批次可以通过贪婪的装箱算法(greedy bin-packing)形成【索引44,S3: Increasing GPU utilization during generative inference for higher throughput. NeurIPS'23, 2023】。批次大小受可用内存限制,因为所有批处理请求的KV缓存和中间产物的最大总内存使用量,在所有解码轮次中,都必须能容纳在内存容器内。对于动态批处理,一个批次即使其总内存最终会超过内存容器也可以执行,因为批次在每轮后都会重新构建,因此通过批处理许多具有小KV缓存的请求,可以实现非常大的批次大小。即便如此,大批次会增加因缓存增长而导致抢占的风险,但另一方面,小批次会降低吞吐量并可能导致资源利用不足。大多数推理系统通过将批次大小固定为通过离线测试发现的常数(例如Orca【索引126】)或通过固定的token预算(例如Sarathi-Serve【索引2】)来平衡这两种风险。
3.3 调度 (Scheduling)
调度问题背景。当请求速率超过系统吞吐量时,新请求必须在队列中等待处理。由于在队列中等待的时间会增加请求延迟,处理请求的顺序会通过缩短或延长等待时间来影响延迟。这类作业调度问题出现在许多领域,经典技术如先到先服务(FCFS)、最短作业优先(SJF)和多级队列(MLQ)可以很容易地应用于LLM推理【索引51, 89, 108】。
LLM调度的特殊挑战。由于KV缓存增长引起的极端且不可预测的内存压力,LLM推理系统可能面临高抢占风险。同时,抢占后的请求恢复可能成本高昂,需要计算密集的预填充阶段或带宽密集的从二级或远程存储传输来恢复丢失的缓存。这些因素导致了旨在防止昂贵抢占的动态提升机制【索引28, 49, 89, 108】,以及恢复机制(第4.2节)。
多副本系统中的调度。此外,配备多个推理副本的系统(第5.2节)需要负载均衡机制来执行请求分配,例如通过贪婪的最小负载分配【索引49, 65】。为了弥补不准确的负载预测,可以使用动态再平衡技术来响应工作节点条件的变化迁移请求【索引65, 95】。对于支持缓存共享的系统(第4.4节),缓存可用性也可以用来指导负载均衡决策,因为最大化这些机会有助于减少总负载【索引14, 82, 94, 136】。
作业优先级 (Job Prioritization)。请求优先级确定了请求处理的顺序,同时也影响与内存相关的抢占,因为最低优先级的请求通常是被抢占的那个。请求抢占通过移除被抢占请求对应的缓存条目来减少内存压力。但在恢复时,缓存条目需要被恢复,是重新计算还是从卸载的容器中检索,取决于缓存大小和其他因素,如【索引51】中所讨论。
* (1) FCFS (先到先服务): 在队列中等待时间更长的请求被赋予更高优先级,但此策略可能导致队头阻塞,因为早期的长耗时请求可能会延迟后期本可以快速完成的短耗时请求的执行。
* (2) SJF (最短作业优先): 该策略避免了队头阻塞问题并实现了最小的平均延迟,但需要准确预测解码轮数。我们将在3.4节中集体讨论负载预测。此外,SJF还存在作业饥饿的风险,因为预测轮数高的请求可能会因预测轮数低的请求的到来而不断被降级。为避免饥饿,可以物理上限制请求被降级的次数【索引89】,或者,可以将长等待时间【索引28, 49, 108】或大的恢复成本【索引89】用作提升指标,人为地提高那些原本优先级永远很低的请求的优先级。
* (3) MLQ (多级队列): 如果无法获得准确的作业完成时间,可以使用MLQ策略通过对长耗时请求进行逐步降级来模拟SJF,而不是依赖固定的优先级。在【索引108】中,该技术应用于LLM推理,通过根据提示长度为新请求分配初始优先级,然后根据生成的输出token数量逐步降低每个活动请求的优先级。
* (4) 基于缓存的策略 (Cache-based policies): 除了这些经典调度技术,计算KV向量的高成本促使支持缓存共享的系统采用基于缓存的策略,这些策略优先处理请求以最大化缓存命中,从而避免缓存颠簸【索引66, 96, 136】。
负载均衡 (Load Balancing)。当所有工作节点上的最大负载(以总计算成本衡量)最小时,就实现了最优负载均衡。当分配各种作业所引起的负载已知时,贪婪地将到达的作业分配给负载最小的工作节点,其产生的最大负载(即完工时间,makespan)在最坏情况下最多是最优解的两倍。贪婪负载均衡的合理性能促使其在多副本推理系统中的采用,但也不可避免地需要负载预测。使预测复杂化的是,由于KV缓存随时间增长,加上请求抢占、恢复和自然终止引起的内存波动,负载会动态变化。由于负载预测对调度和负载均衡都很重要,我们将在第3.4节中集体讨论这些技术。除了减少完工时间,还可以分配请求以最大化缓存命中,从而利用缓存共享【索引14, 82, 94, 136】。为了弥补不准确的负载预测,可以定期对请求进行再平衡。在【索引65】中,解码阶段的请求根据其KV缓存大小的变化进行再平衡。为了更好地描述工作节点负载,为工作节点设置了缓存大小限制,以便可以将少数长耗时请求分配给具有高大小限制的工作节点以避免与内存相关的抢占,而可以将大量短耗时请求分配给具有低大小限制的工作节点,因为抢占风险降低。最初,请求根据前缀长度分配给工作节点。但随着解码轮次导致缓存大小增长,缓存超过某些大小阈值的请求将被再平衡到更合适的工作节点。在【索引95】中,请求通过根据负载形成工作节点对,然后将请求从对中的高负载工作节点迁移到低负载工作节点,直到两个工作节点之间的负载平衡,从而定期进行再平衡。
3.4 讨论
负载预测的挑战。硬件加速器已被充分利用来开发高效的内核以加速LLM推理,但负载预测仍然是一个紧迫的挑战。与此相关的是动态批处理场景下的最优批次大小问题。大批次增加了吞吐量,但也增加了与内存相关的抢占风险,而小批次可能导致计算能力未被充分利用。现有系统倾向于建立一个token预算,动态地将批次大小调整到该预算。但这种方法更多地是为了实现动态批处理提供的平衡的TTFT和TBT,而不是为了平衡吞吐量与计算能力。为了后一个目标,现有系统诉诸于离线测试来设置预算,例如Sarathi-Serve【索引2】。
负载预测的方法。关于负载预测,一种方法是训练一个预测模型。为了实现高预测精度,【索引29,Efficient LLM scheduling by learning to rank, 2024】训练了一个小型的OPT-125M模型【索引132】来预测给定提示相对于其输出长度的相对排名,而不是确切的长度,这种方法被证明比使用长度预测能带来更稳健的调度。在【索引44】中使用了类似的方法,但模型被训练来选择包含输出长度的数值范围,而不是预测提示排名。在【索引89】中,没有使用语言模型,而是使用LLM的激活值作为特征训练了一个专门的MLP。在【索引137,Response length perception and sequence scheduling: An LLM-empowered LLM inference pipeline. NeurIPS'23, 2023】中,通过在提示中附加特殊前缀,LLM本身被用于长度预测。鉴于负载预测的困难,我们注意到,针对某些应用的推理系统可以与前端以及执行运行时共同设计,以约束输出,使其长度可以高精度地知道。我们将在第5.2节中详细阐述这一策略。
负载预测的应用。这些类型的负载预测可以直接用于SJF调度,但为了将它们用于负载均衡,它们应包括考虑工作节点上负载波动的其他因素。例如,【索引49,Is the GPU half-empty or half-full? Practical scheduling techniques for LLMs, 2025】结合了请求内存使用预测和估计的内存回收率,以提供更积极的内存可用性度量。Mooncake【索引82,Mooncake: A KVCache-centric disaggregated architecture for LLM serving, 2024】使用了类似的方法,同时还考虑了因KV缓存传输而损失的时间。
4 内存管理
未能考虑KV缓存内存可能导致内存容器的超额订阅,从而导致昂贵的内存交换。作为预防措施,可以在请求时预先分配每个请求的最大内存,从而不可能超额订阅容器【索引102】。然而,除了长度受限的生成(见第5.1节),KV缓存的确切最终大小是未知的,这有因过度分配而浪费内存的风险。即使知道大小,预先分配内存也会阻止它在此期间被其他请求使用。与静态预分配不同,动态的基于页面的内存管理在需要时以小块分配内存,避免了因大量保留内存而导致的低实际利用率(第4.1节)。同时,为减轻内存负担,可以采用驱逐和卸载技术(第4.2节)从内存容器中移除不需要的KV条目,而量化技术(第4.3节)可以用来减小物理字节大小。在某些情况下,如共享系统提示或某些RAG工作流中,缓存持久化技术(第4.4节)可以允许在多个请求之间重用KV条目,避免昂贵的重新计算和存储冗余。卸载、恢复、量化和持久化技术的各种组合为我们将在第4.5节中讨论的新型内存方案开辟了潜力。
4.1 基于页面的内存分配 (Paged-Based Memory Allocation)
分页内存的优势。由于KV缓存随着每个解码轮次逐渐增长,在需要时以小块分配内存,相比静态预分配避免了巨大的前期内存成本。然而,动态的分块分配可能导致KV缓存不连续,需要一个能够将逻辑缓存条目(即缓存页)映射到物理块的内存管理器,以及专门为不连续内存范围设计的基于页面的内核【索引51, 81】。但除了实现动态分配外,基于页面的内存还为块共享【索引51】提供了机会,以避免重新计算和存储冗余。块共享构成了将在第4.4节讨论的缓存持久化技术的基础。
内存管理器 (Memory Manager)。内存管理器负责页面的创建、删除和查找。为了跟踪页面块的地址和内容(即映射到存储在该页面中的KV条目的token及其在序列中的位置),可以使用页表来列出每个页面的地址和内容(图13)。在vLLM【索引51,Efficient memory management for large language model serving with PagedAttention. SOSP'23, 2023】中,GPU内存作为内存容器,内存管理器和页表在主机上实现。对于使用基于CPU的内存管理器的GPU系统,由于物理块驻留在GPU上,页面的创建和删除会导致内存分配和释放命令从CPU提交到GPU。同样,由在GPU内部运行的特殊页面感知注意力内核执行的页面查找,会导致查找命令从内核提交到内存管理器。在vAttention【索引81,vAttention: Dynamic memory management for serving LLMs without PagedAttention, 2025】中,通过利用GPU的原生内存管理能力减少了这些通信带来的开销。这样做还有一个次要优势,即让缓存在内核看来像是存储在连续内存中,从而能够使用非分页内核,如第2.2节中讨论的那些。
块共享 (Block Sharing)。要实现块共享,可以将对应于不同请求的多个页表条目简单地分配给同一个块地址。何时以这种方式链接页面的条件取决于共享注意力机制(第4.4节)。
* (1) 精确匹配共享 (Exact-match sharing)【索引51, 136, 94】:只有一个或多个请求之间最长公共前缀的缓存条目可以被共享。块大小影响这些共享机会的数量,因为页表只允许共享整个块。小块大小更容易找到块中所有条目都满足此条件的块,但同时在推理过程中增加了块检索的数量。
* (2) 部分匹配共享 (Partial-match sharing):此条件被放宽,允许部分前缀匹配,即共享部分或全部相同token但可能乱序的前缀。
4.2 驱逐与卸载 (Eviction and Offloading)
使用场景与成本考量。缓存驱逐和卸载对于支持抢占是必要的,但对于支持否则会超出内存容器的长上下文也很有用。在抢占的情况下,可以驱逐或卸载低优先级请求的缓存条目,为高优先级请求腾出空间。由于被抢占的请求最终必须恢复,是驱逐还是卸载主要取决于恢复成本【索引51】。对于长上下文的情况,可以驱逐对最终输出序列影响不大的不重要条目,以允许解码继续进行,即稀疏注意力。驱逐哪些条目可以取决于多种因素,包括token位置【索引114】和注意力分数【索引74, 67, 135】。或者,大缓存也可以部分卸载,利用分层存储来补充内存容器。但与被抢占的请求一样,卸载的条目最终必须重新加载到内存容器中,这催生了旨在平衡内存使用与恢复成本的技术【索引5, 52, 93】。对于持久化缓存,缓存驱逐可用于控制缓存大小,传统的缓存控制技术(如LRU)可用于此目的【索引136】。
恢复机制。被驱逐的条目可以通过基于部分LLM输出重新计算键和值向量来恢复,而卸载的条目可以通过将它们传回内存容器来恢复。对于提示较短且经历了解码轮次较少的被抢占请求,重建实际上可能比从卸载的存储中加载更快,这一权衡在【索引51】中有所研究。对于卸载的缓存,可以通过提前异步执行传输,将传输与其他模型执行阶段重叠,以隐藏传输延迟,从而降低有效传输成本【索引52】。对于解耦的运行时(见第5.2节),解码工作节点必须在解码开始前从预填充工作节点恢复缓存条目。如果解码工作节点与预填充工作节点同时被选择,那么缓存可以异步恢复,即在预填充时将条目流式传输到解码工作节点【索引78】。
长上下文驱逐 (Long Context Eviction)。驱逐特定的缓存条目可以为更重要的条目腾出空间,同时对输出质量的影响最小。
* (1) 基于位置的策略 (Position-based policies): 根据其对应token在输出序列中的位置对缓存条目进行排序。在【索引114,Efficient streaming language models with attention sinks. ICLR'24, 2024】中,发现靠近输出序列开头或结尾的token具有比其他token更大的注意力值,这导致了一种通过手工制作的注意力掩码(图14(b))针对这些特殊位置的驱逐策略。
* (2) 基于注意力的策略 (Attention-based policies): 根据其注意力值对缓存条目进行排序【索引74,Transformers are multi-state RNNs, 2024】(图14(c))。为了提高准确性,技术包括添加不对称噪声【索引1】,在解码轮次中平均分数【索引84】,或使用累积分数【索引67, 135】。
长上下文卸载 (Long Context Offloading)。或者,可以使用长上下文卸载将大型KV缓存分布到分层存储中,同时保持缓存完整。
* (1) 逐层卸载 (Layer-wise offloading): 将一个或所有Transformer层的缓存移动到二级缓存存储中【索引5, 52】。由于模型执行是逐层进行的,第 $i+1$ 层的缓存可以在第 $i$ 层执行期间异步传输,有效地隐藏了传输延迟。
* (2) 模型级卸载 (Model-wise offloading): 尽管如此,对于大型缓存,传输成本仍然很高,因此模型级卸载只部分卸载所有层的缓存,允许通过设置卸载比例来控制传输成本【索引93,FlexGen: High-throughput generative inference of large language models with a single GPU. ICML'23, 2023】(图15)。
4.3 量化 (Quantization)
量化基本概念。量化通过降低数值精度来减小物理字节大小。为避免降低推理质量,量化器被设计为在减小的范围内最大限度地保留原始范围中信息丰富的区域。均匀量化器通过数值四舍五入将浮点数映射到压缩范围(如整数),其参数包括偏移量以及范围两端的钳位值【索引71,A white paper on neural network quantization, 2021】;而非均匀量化器则旨在通过非线性方法进一步减少信息损失【索引26, 127】。由于模型组件的信息含量不同,通过为单个组件应用单独的量化器也可以提高质量,这导致了基于张量级【索引71, 127】、向量级【索引22, 123】和维度级量化【索引12,Understanding and overcoming the challenges of efficient transformer quantization. EMNLP'21, 2021】的量化方案(图16)。此外,异常值保护技术,如混合精度保留【索引22, 127】(图17)和异常值平滑【索引58, 112, 131】(图18),可用于防止因量化重要异常值而导致的质量下降。
量化器设计 (Quantizer Design)。对于均匀和非均匀量化器,设计通常旨在最小化量化前后的损失函数,如均方误差。对于形式为 $\lfloor x/s \rceil + z$ 的均匀量化器,由于参数数量少,网格搜索是发现最优值的可行技术【索引71】。对于非均匀量化器,可以使用分桶【索引127】或更复杂的搜索算法【索引26】来直接发现一个映射。其他技术在【索引31,A survey of quantization methods for efficient neural network inference, 2021】中有详细介绍。
量化方案 (Quantization Schemes)。
* (1) 张量级量化 (Tensor-wise quantization): 由于模型权重通常需要大量存储,对权重矩阵进行张量级量化可以直接节省大量存储空间【索引26, 71, 127】。
* (2) 向量级量化 (Vector-wise quantization): 对于激活矩阵,向量级量化通过将矩阵分层为g个组,每组包含n/g个嵌入向量,然后对每组应用不同的量化器,从而对量化矩阵的质量提供更精细的控制【索引22, 123】。g值可根据所需粒度进行调整。更高的g值提供对量化范围更精细的控制,但需要训练更多的量化器并使下游矩阵乘法操作复杂化。
* (3) 维度级量化 (Dimension-wise quantization): 为了更精细的控制,维度级量化将每个向量划分为k个段,有效地将d维向量空间划分为d/k维子空间,然后对每个段应用单独的量化器【索引12】。
异常值保护 (Outlier Protection)。异常值已被证明对模型质量有不成比例的影响【索引22, 112, 127】。
* (1) 混合精度保留 (Mixed-precision preservation): 将异常值保留为原始形式,但这会导致张量处于混合精度状态。可以使用专门的数据结构来存储这些张量,例如通过为低精度和高精度值使用不同的字节区域【索引23, 127】(图17),但操作这些结构需要能够识别这些区域的专门解码器或内核算子。
* (2) 异常值平滑 (Outlier smoothing): 另一方面,可以使用异常值平滑来避免在矩阵乘法期间使用混合精度张量,同时仍然保留异常值的信息。给定两个矩阵操作数,该技术应用标量除法来减少高方差矩阵中异常值的有效强度,同时在低方差矩阵中执行反向缩放,有效地将高方差信息保留在矩阵乘积内部(图18)。在【索引112,SmoothQuant: Accurate and efficient post-training quantization for large language models. ICML'23, 2023】中,该技术应用于激活和权重矩阵,而在【索引58, 131】中,该技术应用于构成KV缓存的键和值矩阵。
4.4 缓存持久化 (Cache Persistence)
缓存共享的挑战。内部注意力层中的KV向量根据其各自token在生成序列中的位置而取不同值。因此,两个请求的KV条目仅在其序列中token不同的第一个位置之前是相同的,这导致了直接缓存共享的精确匹配条件。但在某些情况下,KV条目仍然可以在一定程度上共享。例如,在RAG工作流中,两个请求可能使用相同的文档块,即使提示不同。
缓存共享技术。
* (1) 前缀共享 (Prefix sharing): 该基础技术在精确匹配前缀下重用持久化的缓存条目。为找到最长匹配前缀,可以从头到尾扫描请求前缀,在每个token处执行缓存查找,看该token在其序列位置上是否已存在缓存条目【索引66,Optimizing LLM queries in relational workloads, 2024】。如果存在许多持久化缓存块,可以使用索引结构(如基数树)来加速此检索【索引136】。
* (2) 选择性重建 (Selective reconstruction): 对于部分匹配共享,该技术通过重新计算一部分最具影响力的token的KV条目来减轻因使用未对齐条目而导致的质量下降,如图19所示。这些token可以通过使用第一个Transformer层中的注意力分数偏差作为排名标准来识别【索引121,CacheBlend: Fast large language model serving for RAG with cached knowledge fusion, 2204】,或使用token位置作为启发式方法【索引32, 40】。
4.5 讨论
技术总结与应用场景。本节讨论的技术源于减少由数十亿模型参数以及推理期间生成的大量KV缓存所引起的内存压力的需求。分页内存相比静态预分配提供了更灵活的内存分配,而驱逐和卸载、量化以及缓存持久化技术都旨在直接减少内存使用。此外,这些方法的多样性使得可以针对不同LLM系统和应用中的内存容量、期望准确性和上下文长度的差异进行优化。
* 驱逐与卸载: 对于被抢占的请求,由于分层存储充足,卸载可以有效降低恢复成本,避免缓存重新计算,特别是当恢复可以异步执行时。对于支持长上下文,驱逐和卸载可以成为分布式注意力机制(如Ring Attention【索引63】)的有吸引力的替代方案,后者需要水平可扩展的GPU。
* 量化: 量化可以被任何推理系统应用,但确定实现内存节省和模型质量之间平衡的最优量化方案可能需要反复试验。例如,在【索引123,ZeroQuant: Efficient and affordable post-training quantization for large-scale transformers. NeurIPS'22, 2022】中,权重和激活矩阵都使用向量级量化,但由于观察到权重值的方差小于激活值,g项对于权重设置为g>1,对于激活设置为g=1。相比之下,在【索引22,LLM.int8(): 8-bit matrix multiplication for transformers at scale. NeurIPS'22, 2022】中,为实现更激进的空间节省,权重和激活矩阵的g项都设置为g=1,但对激活进行了异常值保护以防止准确性损失。模型大小和架构也可能影响量化方案。例如,编码器-解码器BERT模型已被证明对激进的权重量化不那么敏感,而解码器-解码器GPT模型则不然。因此,GPT模型似乎受益于更复杂的量化方案,如向量级或维度级量化,如【索引123】所示。模型大小也被证明是决定特定量化方案时的关键考虑因素【索引22】。
* 缓存持久化: 如果准确性不是最重要的,选择性重建可以是一种有用的技术,用于激进的内存节省,否则可以使用前缀匹配,而不会影响准确性。
关键设计决策与未来方向。推理系统设计的一个关键决策是KV缓存内存应该是受约束还是不受约束。约束缓存大小使内存使用更可预测,因为最大内存使用量已知,简化了批处理和调度决策,但也可能降低模型准确性,特别是对于长耗时请求。为了两全其美,我们提到一种有趣的技术。在【索引13, 120】中,内存约束被允许在各层之间变化,通过为早期层分配比后期层更多的内存,可以在对输出质量影响很小的情况下实现大的内存减少。未来类似的技术可以关注请求级别的动态内存分配,或其他分配方案。另一种类似于驱逐的方法是条目合并,即不是丢弃被驱逐的条目,而是将它们合并到剩余的未被驱逐的token中。目标不再是选择影响最小的token,而是选择相似的token,以便合并后的KV条目整体上与合并前没有太大差异,只是条目数量减少了【索引60, 98, 103, 133】。
5 推理系统
在一个LLM推理系统中,各种请求处理、执行和内存管理技术被结合起来,以支持高效和高质量地处理通用的LLM工作负载,或针对更具体的应用。一个完整的推理系统由一个前端和一个运行时组成。前端允许用户交互,例如通过声明式或命令式接口,并可能提供结构化输出和自动提示优化等功能(第5.1节)。运行时管理模型执行的所有其他方面,单副本运行时针对在单个LLM上处理请求,多副本运行时针对具有多个相同LLM的环境(第5.2节)。单副本和多副本系统都可以支持分布式执行,而后者还可以设计为支持解耦执行。我们在第5.3节中总结了一些流行系统的关键特性。
Table 2 前端特性。
5.1 前端 (Frontends)
前端功能。前端允许用户以编程方式访问底层的LLM,同时保留对精确LLM输入和输出的控制。前端可以提供模块或命令,将用户指令转录为CoT、少样本或RAG提示,根据先前提示的输出提交不同的提示,约束输出以遵守特定的模板或格式等。在这些功能中,结构化输出和模板完成尤其允许交错提示,可用于加速推理。关于提示策略已有大量工作,我们建议感兴趣的读者参考【索引86】。接口本身可以是命令式或声明式(表2)。命令式接口提供较低级别的API,可用于形成LLM程序,而声明式接口则通过查询字符串或高级模块允许更友好的基于查询的交互。
基本交互。控制流,例如if...else
和for
语句,通过捕获LLM输出,然后根据输出提交不同的提示来处理。
* 示例1 (捕获与控制流): 生成的输出被捕获在s["tool"]
中,并参与控制执行流程。
s += assistant("To answer " + q + ", I need " + gen("tool", choices=["calc", "www"]))
if s["tool"] == "calc": // .. do something
elif s["tool"] == "www": // .. do something
约束生成,即在满足用户指定条件时停止LLM生成,对于终止否则会很长的LLM响应很有用,同样可以使用输出捕获来实现。例如,LMQL【索引9,LMQL Chat: Scripted chatbot development, 2023】通过声明式语法暴露此功能,例如提示脚本"Give your answer here: [y]"
,其中len(TOKENS(y)) < 25
在Python解释器捕获的生成输出长度超过25个token时终止。
结构化输出。一个相关的功能是结构化输出,其中LLM的输出被约束为用户指定的类型和格式,例如两位数。为了实现此功能,前端将约束转录为提示短语,例如“以两位数形式给出答案”,然后根据LLM的响应,通过logit掩码【索引107,Efficient guided generation for large language models, 2023】、token重采样或重新提示来强制执行约束。结构化输出可以扩展到支持模板完成,其目标是提示LLM填写一个模板,例如JSON模式。由于每个模板项都是一个结构化输出,可以通过简单地为每个项提示LLM来填写模板。或者,可以提示LLM一次性填写模板,但此策略可能需要多轮重新提示,直到LLM生成完全遵守模板的输出,特别是因为模板本身必须完整地出现在生成的响应中。逐项提示还允许交错提示和解码,以利用快速预填充来加速推理,尤其是在支持持久化缓存的运行时上。
* 示例2 (约束模板生成):
Write a summary of Bruno Mars, the singer:
name
上面是一个LMQL程序。大写括号项指定了类型约束。给定此程序,LMQL将其解析为提示并协调执行以及输出捕获。为了说明预填充和解码交错技术,下面是LMQL提交的第一个提示:`Write a summary of Bruno Mars, the singer: { "name": "`。在LLM输出`Bruno Mars`后,LMQL提交第二个提示:`Write a summary of Bruno Mars, the singer: { "name": "Bruno Mars", "age": "`,其中先前的输出(红色显示)直接包含在提示中。由于大部分提示与第一个提示重叠,运行时可以利用共享缓存条目来加速预填充。此过程重复直到模板被填满。
声明式前端 (Declarative Frontends)。在声明式接口中,用户通过调用声明性语句或模块来访问这些功能。
* (1) LMQL【索引10,Prompting is programming: A query language for large language models. Proc. ACM Program. Lang., 2023】使用声明式语法,例如一个提示语句后跟一个from
子句指定模型和一个where
子句约束输出。这些声明式查询可以包装在控制流结构中。LMQL前端将查询转录为提示链,并对生成的输出强制执行约束。由于提示结构是预先声明的,它可以被视为一个模板,允许通过提示和解码交错进行高效的模板生成。
* (2) DSPy【索引46,DSPy: Compiling declarative language model calls into selfimproving pipelines. ICLR'24, 2024】提供了一个面向对象的声明式接口。与LMQL不同,用户不是编写提示查询,而是编写模块声明,不同的模块封装了不同的提示策略。提示内容和其他参数在调用模块前传入。这个框架允许DSPy执行提示优化,例如合成少样本示例以提高模型准确性。
命令式前端 (Imperative Frontends)。用户也可以通过命令式接口访问这些功能。
* (1) SGLang【索引136,SGLang: Efficient execution of structured language model programs, 2024】提供了一个用于与底层LLM交互的低级API。为了提高推理速度,它采用了一种推测执行技术,允许LLM在用户终止条件之后继续解码,希望生成额外的有用token,从而避免多次API调用。共同设计的SGLang运行时还允许前端通过提示和解码交错进行模板生成,从而利用缓存持久性。
* (2) Guidance: 提供了与LMQL类似的功能,但使用命令式语法而不是声明式。与LMQL一样,输出约束作为参数传递给生成函数。
* (3) LangChain: 与Guidance类似,但更面向对象。提示和LLM输出被封装在可以编程操纵的类中。LangChain还提供了一个名为LangGraph的基于代理的框架,可用于编程复杂的交互,例如嵌套的if/else梯级。
A7 补充细节
5.2 运行时 (Runtimes)
推理运行时可以针对单副本或多副本环境。对于多副本运行时,由于容纳每个副本的工作节点(无论是分布式还是非分布式)可能负载不同,即处理处于不同完成状态的请求,由于KV缓存增长而具有不同的内存负担,以及更长或更短的请求队列,多副本运行时依赖负载均衡技术来选择性地将请求分配给副本以保持高性能。同时处理多个请求的能力,结合分块的持久化缓存,也催生了块复制和分区技术,以最大限度地利用缓存重用。最后,仔细管理资源密集型副本数量的需求导致了解耦和无服务器架构,以及单体架构,它们提供了更精细的扩展和控制。
Table 3 模型执行特性。
Table 4 内存管理特性。
5.2.1 单副本 (Single-Replica)
单副本运行时的挑战与发展。单副本运行时需要处理LLM执行的基本系统级挑战,包括批处理、调度和内存管理。这些运行时开发的技术也为多副本运行时奠定了基础。
* Orca【索引126】是最早专门设计用于处理LLM独特自回归特性的推理运行时之一,开创了现已广泛采用的基于轮次的连续批处理思想。为管理缓存内存,该运行时使用静态内存分配,根据应用指定的最大上下文长度为每个请求预分配固定量的内存。调度器不允许抢占,因此没有驱逐或卸载被抢占请求的机制。由于每个内存块对每个请求都是私有的,因此也没有缓存共享的机会。
* 为了解决静态分配的局限性,vLLM【索引51】引入了基于块的缓存内存。内存块由内存管理器处理,允许多个活动请求共享某些块。即便如此,vLLM并未明确管理跨多个请求生命周期的缓存持久性。为应对低内存情况,vLLM增加了基于请求优先级的请求抢占支持。在低内存条件下,调度器会驱逐与最低优先级请求对应的所有缓存块以释放内存。
* SarathiServe【索引2】将连续批处理的思想扩展到预填充阶段,在vLLM之上引入了分块预填充。分块预填充允许用预填充token填充批次,从而可以基于token预算进行动态批次大小调整。
* SGLang【索引136】引入了受管理的缓存持久性,开发了一个协同设计的前端和运行时来利用这一技术。运行时将所有缓存块持久化在内存中,并使用基数树来加速预填充期间的块检索。为控制持久化缓存的大小,SGLang对持久化条目使用LRU驱逐。为避免缓存颠簸,请求根据共享前缀的长度进行优先级排序。
* 为解决FCFS的局限性,FastServe【索引108,Fast distributed inference serving for large language models, 2024】引入了基于到达时间的多级队列(MLQ)作业优先级排序,作为减少平均请求延迟的一种方式。
5.2.2 多副本 (Multi-Replica)
多副本运行时的架构与技术。多副本运行时使用负载均衡器在多个工作节点间均匀分配工作负载。对于支持缓存持久性的多副本运行时,持久化的条目可以分布在不同的工作节点上,这催生了分布式缓存管理技术。不同的应用扩展需求导致了除单体运行时外,还出现了分离式和无服务器运行时(图20)。
单体式(Monolithic)。作为单体式运行时的例子,Preble【索引94,Preble: Efficient distributed prompt scheduling for LLM serving, 2024】展示了如何将缓存持久性扩展到多副本场景。一个中央调度器维护一个全局基数树,负载均衡基于缓存命中率和工作节点负载进行。由于持久化缓存分布在工作节点上,一些工作节点的命中率更高。为避免负载均衡器过载这些工作节点,热门条目被复制到其他工作节点上。
解耦式(Disaggregated)。与单体架构相比,为预填充和解码阶段使用专门的工作节点为独立控制和扩展这两个阶段提供了机会。在解码工作节点开始处理请求之前,必须首先将预填充的KV缓存条目传输到解码工作节点。
* 对于(1) 同步传输,DistServe【索引138,DistServe: Disaggregating prefill and decoding for goodput-optimized large language model serving. OSDI'24, 2024】通过根据推理集群中GPU的物理位置以及工作负载需求,仔细地将推理设备(GPU)分配给预填充或解码任务,从而降低了传输成本。例如,通过将同一台机器中的GPU分配给独立的预填充和解码任务,GPU可以利用高带宽的NVLink来降低传输成本。但由于解码工作节点是在预填充阶段之后选择的(图20(b)),如果工作负载出现突发,贪婪的解码端负载均衡器可能会无意中过载一个解码工作节点。TetriInfer【索引39,Inference without interference: Disaggregate LLM inference for mixed downstream workloads, 2024】通过采用二的幂次方负载均衡【索引70】来解决此问题。
* 对于(2) 异步传输,SplitWise【索引78,Splitwise: Efficient generative LLM inference using phase splitting. ISCA'24, 2024】和Mooncake【索引82】在选择预填充工作节点的同时选择解码工作节点,允许缓存在生成时异步流式传输到解码工作节点(图20(c))。但由于在预填充期间解码工作节点的负载可能会变化,一旦预填充完成,所选的解码工作节点可能不再有足够的可用内存来处理该请求。为避免抢占,Mooncake在解码开始前检查解码工作节点的负载。如果内存不足,请求将被终止。
* 对于热门条目复制,Mooncake使用一个中央哈希表,该表记录了每个持久化缓存块的位置和内容。在预填充期间,如果检测到缓存命中,可重用的块将被复制到预填充节点上,有效地在多个工作节点间复制热门块。
无服务器(Serverless)。无服务器运行时利用无状态的硬件资源来实现灵活的资源扩展。但由于机器是无状态的,这些运行时必须克服冷启动问题,即在机器被使用前,必须在采购时将模型权重加载到机器上。例如,DeepFlow【索引41,DeepFlow: Serverless large language model serving at scale, 2025】旨在在共享基础设施上进行LLM推理。为避免冷启动,它在多个请求之间持久化采购的机器,而不是在每个请求后将它们返回到资源池,同时还保留一个预热的机器池以便快速采购。DeepFlow通过将缓存条目卸载到主机内存中来利用缓存共享机会,这些内存由一个中央基数树管理。
5.3 讨论
专用系统的优势与趋势。虽然像Clipper【索引19】、TensorFlow Serving【索引73】、TensorRT、Clockwork【索引36】和Hugging Face Accelerate等非专用的深度学习推理系统可以应用于LLM推理,但它们通常被专用的LLM推理系统所超越。本节介绍了一些系统,每个系统都引入了新的创新来提高吞吐量、降低延迟和减少内存使用,同时保持高质量的推理。这些技术中的许多可以无冲突地一起使用,事实上,最近的系统已经趋于融合。例如,像分页注意力和带分块预填充的连续批处理等技术已经被广泛采用,而更新的技术,如MLQ调度和在分层存储上的异步缓存恢复,由于其相对于先前方法的明显优势,也可能随着时间的推移变得更加普遍。
系统架构的选择。在系统架构方面,多副本系统包括额外的组件,如负载均衡器和分布式缓存管理机制,即热门缓存副本和缓存传输机制。对于单副本环境,在多副本系统中禁用这些功能可以减少额外的开销,否则单副本系统可能更合适。对于多副本环境,解耦系统允许更灵活的资源管理,与单体系统相比没有明显的缺点,特别是在使用混合工作节点池时。如果部署在共享基础设施上,像DeepFlow【索引41】这样的无服务器系统可以用来解决包括冷启动和无状态工作节点在内的问题。
未来的差异化与挑战。量化方案可能是未来系统可以区分的一个领域。如4.3节所述,准确性和压缩之间存在固有的权衡,这种权衡取决于模型架构以及请求所包含的任务类型。因此,最优的量化方案取决于推理系统所针对的应用和模型。另一方面,也明显需要更具适应性的推理系统。由于请求生命周期的不可预测性,工作负载本质上是复杂的。虽然部分不可预测性可以通过约束输出生成(例如,只允许约束生成)或通过工作负载解耦(例如,将要求低延迟的交互式请求与更受益于高吞吐量的非交互式请求分开处理【索引79, 96】)来管理,但针对更通用工作负载的LLM推理系统将需要更强大的技术,包括更准确的负载预测以及如动态批次大小调整和弹性资源配置等自适应技术来处理工作负载变化。已经有开发更具弹性推理系统的努力。例如,为了弹性扩展解耦系统,Splitwise【索引78】和TetriInfer【索引39】可以根据工作负载动态调整预填充和解码工作节点的比例。对于静态资源配置或确定初始资源配置,iServe【索引56,iServe: An intent-based serving system for LLMs, 2025】引入了轻量级指纹模型的思想,可用于快速评估不同的配置。
A4 实验环境
本文是一篇综述性论文,旨在对现有的LLM推理系统及其相关技术进行系统性的回顾、分类和分析。因此,文章本身不包含独立的、全新的实验部分,没有具体的数据集、模型架构、硬件或软件配置。文中引用的性能数据和结论均来自其所引用的原始研究论文。
A4 实验结果
作为一篇综述,本文没有提出新的实验结果。它通过整合和分析现有文献中的发现来阐述观点。例如,文章会引用FlashAttention【索引20】的论文来说明融合内核带来的性能提升,引用vLLM【索引51】的论文来论证分页注意力在内存管理上的优势,或引用Orca【索引126】的论文来解释连续批处理对吞吐量的改进。所有关于技术有效性的结论都是基于对这些已发表工作的总结和比较,而非本文作者进行的直接实验验证。
A5 结论
结论回顾:
随着大型语言模型(LLM)的迅速普及,处理高速度、大容量工作负载的专用高性能推理系统变得至关重要。LLM推理的自回归特性带来了独特的挑战,催生了多种新技术。本综述在一个统一的框架下,系统地分析了这些技术,涵盖了请求处理、模型执行和内存管理等多个层面。文章的核心观点是,这些技术为了应对自回归生成带来的成本不确定性,普遍依赖于负载预测、自适应设计和基础成本削减三大策略来维持高性能。这些技术最终被整合到单副本和多副本系统中,其中包括通过逻辑任务解耦提供更精细资源管理的解耦式系统。
挑战与未来展望:
随着LLM的应用范围从自然语言扩展到更多领域,高性能推理系统的重要性将日益增加。未来的研究和发展机遇主要集中在以下几个方面:
* 新的算子与算法: LLM在自然语言之外的应用(如化学分子【索引68】)可能会产生不同的注意力模式,为开发更具针对性的算 子和序列生成技术提供了机会。
* 模型执行优化: 新的算子和算法自然会催生新的内核设计需求。同时,负载预测仍然是优化作业优先级和负载均衡的关键难题。
* 内存管理创新: 对于繁多的量化方案,需要更系统地理解何时、何物以及如何进行量化。此外,新的逻辑内存层次结构(如金字塔缓存【索引13, 120】)和新颖技术(如条目合并【索引60】)也值得进一步探索。
* 弹性系统设计: 持续的努力方向是开发能够响应工作负载变化、自适应地管理有限硬件资源的弹性系统。
* 其他新兴方向:
* 测试时扩展(Test-time scaling)【索引109】:在固定的延迟预算内最大化推理质量,而不是直接最小化延迟,这可能催生新的系统设计。
* 适配器加载(Adapter Loading):对于支持通过LoRA进行配置切换的模型,推理过程中的适配器加载也需要考虑【索引30, 92】。
* 专用与多模态LLM:专用LLM(如移动端LLM【索引117】)、多模态LLM【索引76】和机器人LLM【索引59】的兴起带来了新的系统需求。
* 硬件发展:新设备的多样化特性为作业优先级和负载均衡增加了额外的复杂性,已有部分技术开始涌现【索引35, 43】。
💬 评论讨论
欢迎在这里分享您的想法和见解!