四、推理加速技术
四、 推理加速技术¶
1. FlashAttention 为什么能加速?它的核心是近似算法吗?¶
FlashAttention 是当下大模型推理和训练中最关键的注意力加速技术之一。它的加速核心不是近似算法,而是一个精确算法——它通过重新编排计算顺序,在数学上完全等价于标准注意力,但大幅减少了对显存(尤其是高带宽显存,HBM)的读写量。
标准注意力的性能瓶颈¶
标准注意力计算分为两步:
-
计算注意力得分矩阵: $ S = Q \times K^T \in \mathbb{R}^{N \times N} $,其中 $ N $ 是序列长度。
-
计算输出: $ O = \text{softmax}(S) \times V $。
在 GPU 上,计算单元(Tensor Cores)的速度远快于显存带宽。以 A100 为例,算力 312 TFLOPS(FP16),但显存带宽只有 2 TB/s。标准实现中,S 和 softmax(S)这两个巨大的 $ N \times N $ 矩阵需要被完整地写入和读出 HBM,这构成了严重的显存带宽瓶颈。当序列长度 N 较大时,绝大多数时间都花在了数据搬运上,而非实际计算。这就是所谓的“内存墙”。
FlashAttention 的核心思想:分块 + 重计算
FlashAttention 通过两个关键操作打破了这一瓶颈:
-
分块(Tiling):将 Q、K、V 按序列维度切分成小块,每次只加载一小块到片上高速 SRAM 中。
-
重计算(Recomputation):在反向传播时,不保存巨大的中间矩阵 S,而是利用 SRAM 中的小块在反向时快速重算。
它是如何做到精确的?¶
FlashAttention之所以不是近似算法,是因为它在分块计算时引入了一个动态更新的归一化因子
(Running Statistics)。具体来说,当计算第 i 块 Q 与第 j 块 K 的局部注意力得分时,由于 softmax 的全局归一化特性,不同分块的结果不能简单拼接。FlashAttention 同时维护局部分子(sum of exponentials)和局部分母(sum of all exponentials),在完成所有分块计算后,用正确的全局统计量对每个分块的输出进行重新缩放。这一数学技巧完全保留了标准 softmax 的精度。
因此,FlashAttention 的加速完全是精确计算 + IO 优化的结果,没有任何信息损失。
具体加速效果¶
训练:前向传播时间可缩短2-4倍,反向传播由于完全避免了S的读写,加速更显著。
推理(Prefill 阶段):同样受益,可以支持更长的 prompt 输入。
长序列:当 N > 2048 时,优势尤为明显,因为标准实现的带宽瓶颈呈平方级恶化。
核心洞察:FlashAttention 让 GPU 不再被注意力矩阵的巨大数据搬运所拖累,而是让计算单元真正“忙碌”起来。

2. FlashAttention 如何通过分块和重计算来减少显存读写?¶
FlashAttention的显存优化是它最精妙的地方。我们以FP16精度、单头注意力为例,详细拆解其前向和反向过程中的显存读写。
标准实现的内存开销¶
在标准注意力中,你需要为 $ S \in \mathbb{R}^{N \times N} $ 和 $ P = \text{softmax}(S) \in \mathbb{R}^{N \times N} $ 分配显存,每个元素 2 字节,总占用 $ 2 \times 2 \times N^2 $ 字节。当 $ N = 32768 $ 时,仅这两个矩阵就占用 8 GB 显存!而这些中间结果在反向传播时还需要被重新读取,导致巨大的带宽浪费。
FlashAttention的分块策略(Tiling)¶
FlashAttention 利用 GPU 的片上 SRAM (~20 MB, 带宽 19 TB/s, 远高于 HBM 的 2 TB/s) 作为缓存:
-
将 Q、K、V 按序列维度切分成若干块,每块大小 $ B_r \times d $ (d 为头维度)。
-
外层循环遍历 Q 的块,内层循环遍历 K 和 V 的块。
-
对于每个 $ Q_i $ 块和 $ K_j $ 块,将其加载到 SRAM 中,计算局部注意力得分 $ S_{ij} $,并直接在 SRAM 中完成 softmax 和与 $ V_j $ 的加权求和。
-
关键点:整个 $ S_{ij} $ 矩阵只在 SRAM 中存在,从未被写回 HBM。
通过分块,HBM 中只需要存储输入 Q、K、V 和输出 O,中间所有巨大的临时矩阵都保持在 SRAM 内,极大减少了 HBM 读写。
重计算(Recomputation)在反向时的应用¶
在训练的反向传播中,标准实现需要读取前向时存储的 $ S $ 和 $ P $ 来重新计算梯度。FlashAttention 则不保存这些中间结果。在反向传播时,它利用 SRAM 中重新加载的 $ Q $、 $ K $、 $ V $ 块,重新计算出需要的局部注意力得分和 softmax 输出,然后直接用于梯度计算。这相当于用一点额外的计算来换取大量显存和带宽的节省。
显存复杂度对比¶
· 标准注意力: $ O(N^{2}) $ 显存。
FlashAttention: O(N) 显存。
这意味着 FlashAttention 让模型在训练和推理时可以处理更长的序列,或者使用更大的 batch size。
用直觉理解:标准注意力就像你每次做数学题都要翻遍整本教材,教材还得完全摊开在桌上;FlashAttention就像你把教材分成若干章,每次只拿一章到眼前,做完题就放回去,桌上永远干干净净。

3. FlashAttention 对于不同序列长度,加速效果有什么差异?¶
FlashAttention 的加速效果高度依赖于序列长度 N,可以概括为:序列越长,加速越显著。
短序列(N < 512)¶
在短序列下, $ N^{2} $ 仍然较小,S 矩阵的大小可能还小于片上 SRAM,或者显存带宽尚未构成严重瓶颈。此时 FlashAttention 的分块和重计算带来的一些额外开销(如循环、动态归一化等)反而可能使速度略慢于高度优化的标准实现(如 PyTorch 的 scaled_dot_product_attention)。不过对于实际的大模型推理和训练,这种轻微损失可以忽略。
中等序列(512 < N < 4096)¶
这是 FlashAttention 发挥显著优势的起点。随着 \(N\) 增加,\(S\) 矩阵大小快速膨胀,标准实现的显存读写时间占比急剧上升。FlashAttention 通过消除 \(O(N^2)\) 的中间数据搬运,前向速度可达到标准实现的 2-3 倍。

长序列(N > 4096,尤其是8k、16k、32k甚至更高)¶
加速效果达到极致。在这个长度下,标准注意力几乎不可用——不是因为算力不够,而是因为S矩阵完全超出了显存容量,导致严重的swap或直接OOM。FlashAttention则是线性显存复杂度,使得处理32k甚至65k的长序列成为可能。以LLaMA-7B为例,在A100上做32k的Prefill,FlashAttention可以让延迟从几十秒降到几秒,吞吐量提升5-10倍。
Decode 阶段的差异¶
在自回归的Decode阶段,每次只生成一个token,Q的序列长度为1,注意力计算变成了“一个查询对海量键值”的模式。此时FlashAttention的优化重点不同:它需要高效地读取KV Cache(长序列下KV Cache巨大),并通过分块减少SRAM和HBM之间的数据搬运。因此,在长上下文的Decode阶段,FlashAttention依然有关键作用,但加速倍数通常低于Prefill阶段。
一句话:FlashAttention是长序列推理的“必需品”,不是“锦上添花”。如果你需要支持8k以上的上下文,不用FlashAttention,工程上几乎寸步难行。
4. FlashAttention-2 相比 v1 做了哪些优化?¶
FlashAttention-2 是 2023 年由 Tri Dao 发布的改进版本,主要在 GPU 线程调度、并行度、工作分配等方面做了进一步优化,使得训练和推理速度再提升约 2 倍。
关键优化点¶
1. 减少非矩阵乘法运算(Non-GEMM Operations)¶
v1 版本中,分块循环内存在较多的逐元素操作(如 softmax 的指数、求和、缩放),这些操作的吞吐量受限于 GPU 的显存带宽。v2 将更多计算融合为高效的矩阵乘法(GEMM),例如将 softmax 的缩放因子合并到矩阵乘中,减少了单独的逐元素 kernel 启动。
2. 优化线程束(Warp)调度¶
v1 在计算每个分块时,一个线程块(Thread Block)只处理一个 Q 头和 K 头。v2 改为一个线程块处理多个头,提高了 GPU 的占用率(Occupancy),减少了调度开销。
3. 更精细的分块策略¶
v2 调整了 Q 和 K 的分块大小,特别是在 Decode 阶段(Q 序列长度为 1),将 K 的分块做得更大,减少循环次数,提高并行度。
4. 消除冗余重计算¶
在反向传播中,v2 优化了梯度计算顺序,减少了对 Q、K 等输入数据的重复读取。
实际效果¶
训练吞吐:在 GPT 类模型上,FlashAttention-2 将训练速度在 v1 基础上再提升 1.5-2 倍。
推理吞吐:Prefill阶段提升1.5-2倍,Decode阶段也因线程调度优化而受益。
FlashAttention-2已成为当前主流框架(如 PyTorch 2.0+、vLLM)的默认注意力后端。
直观对比:v1像是把杂乱的工作台整理得井井有条;v2则是进一步优化了流水线,让每个工人都忙起来,没有空闲,整个生产效率再上一个台阶。
5. FlashDecoding 解决什么场景下的问题?¶
FlashDecoding 专门解决长序列推理的 Decode 阶段中,注意力计算效率低下的问题。
传统Decode的瓶颈¶
在Decode阶段,每次只生成一个token,因此Q的序列长度始终为1,而K和V的序列长度等于上下文总长度S。注意力计算变为一个“向量vs海量矩阵”的操作。标准实现中,为了充分利用GPU,通常需要将多个请求的Q拼成一个batch。但在在线服务中,不同请求的到达时间是异步的,且它们的Q是独立的,强行组batch会引入延迟。
FlashDecoding 提供了一种不依赖 batch 的、长序列 Decode 加速方案。
FlashDecoding 的核心思想¶

FlashDecoding 的核心思想¶
它将 K 和 V 在序列维度上进行切块(Tiling),然后并行处理这些块。对于单独的 Q(batch=1),每个 K/V 块被分配给不同的 GPU 线程块,独立计算局部注意力,最后通过一个高效的归约(reduction)kernel 将各块的局部结果合并为最终输出。这完全打破了 batch 限制,即使只有一个请求,也能充分利用 GPU 的并行计算能力。
适用场景与效果¶
在线推理,低并发:当只有少数几个用户请求时,FlashDecoding能显著降低每token的生成延迟(通常2-4倍)。
长上下文:当 S 达到 32k 或更高时,传统 Decode 几乎无法在 batch=1 下保持低延迟,Flash Decoding 能让延迟保持在可接受的时间内。
与 PagedAttention 结合:vLLM 已集成了 FlashDecoding 的思想,实现了高效的、非连续批处理的 Decode。
比喻:传统Decode像是只有一个收银员的超市,顾客必须排队等前面的人结完账。FlashDecoding则是开放了所有自助结账机,每个顾客(每个token)可以立即开始,不用等前面的,收银效率大幅提升。

6. 投机采样(Speculative Decoding)的原理是什么?能带来多少加速?¶
投机采样是一种让大模型推理“跳过”部分串行计算的方法,通过引入一个小模型并行地“猜测”未来的token,从而突破自回归生成的串行瓶颈。
原理解析¶
自回归生成必须一个个 token 串行产生,因为每个新 token 都依赖于之前所有的 token。这是推理延迟的根本来源。投机采样的巧妙之处在于:
-
草稿模型(Draft Model):引入一个比主模型小得多(例如 100M 参数 vs. 7B)但同词表的草稿模型。它速度快,但生成质量低。
-
猜测:草稿模型用自回归方式快速生成 K 个候选 token(例如 5 个)。
-
验证:将原 prompt 加上这 K 个猜测 token,一次性输入给主模型。主模型做一次并行前向,预测出这 K 个位置上的概率分布。
-
接受/拒绝:主模型根据自己预测的概率,通过一个拒绝采样(Rejection Sampling)机制,依次检查每个猜测 token。如果某个 token 的概率低于阈值,则该 token 及之后的所有猜测都被拒绝。主模型只接受那些符合自己“心意”的 token。
-
接续生成:被拒绝的 token 位置,主模型用自己的概率重新采样一个 token,然后可以重新开始一轮投机采样。
这样,主模型的一次前向推理就可能验证并接受多个 token,从而在一步中“跳跃”着生成多步,实现了推理加速。
加速效果¶
理论加速比:期望加速比为 $ K \times \alpha $,其中 $ \alpha $ 是草稿模型的接受率。如果草稿模型质量高, $ \alpha $ 可达 0.8-0.9,K 通常取 3-5,加速比可达 2-4 倍。
· 实际测试:在代码生成、摘要等任务上,加速比通常在1.5-3倍,具体取决于领域和草稿模型的质量。
无精度损失:因为验证和拒绝机制保证了最终输出的概率分布与主模型严格一致,所以不会降低生成质量。这就是“无损加速”的核心。
比喻:这就像一个资深编辑(主模型)在审核一个实习生(草稿模型)写的稿子。实习生写得快但经常出错,编辑只需要快速扫一眼,大部分句子直接通过,发现错误的地方再亲自修改。这样编辑不用自己逐字写,速度自然快很多。
7. 投机采样中,草稿模型需要满足什么条件?如何选择或训练?¶
草稿模型的选择和训练是投机采样能否达到高加速比的关键。一个理想的草稿模型需要在速度和准确率之间取得最佳平衡。
草稿模型必须满足的条件¶
- 同词表:草稿模型必须与主模型使用相同的 tokenizer 和词表,否则猜测的 token 主模型无法识别,验证无从谈起。
-
足够小、足够快:草稿模型每次猜测 K 个 token 的自回归时间,必须远小于主模型做一次 K 步验证的时间。通常草稿模型的参数量是主模型的 1/10 到 1/100,延迟在微秒到毫秒级。
-
输出分布与主模型高度相关:草稿模型预测的 token 序列,最好有高概率是主模型也会选择的。两者分布越接近,接受率 $ \alpha $ 越高,加速比越大。
-
能处理相同的上下文:草稿模型在验证时,需要接收完整的 prompt + 已生成的历史作为输入,因此其最大上下文长度应与主模型一致。
如何选择或训练草稿模型¶
选择现有小模型:¶
最直接的方法是使用同一个家族的小模型。例如主模型是LLaMA-70B,草稿模型可以选LLaMA-7B或TinyLlama。它们架构相似,分布接近,接受率较高。
也可以使用专门为投机推理设计的蒸馏模型,如 Medusa、EAGLE 等,它们不是简单的小模型,而是通过预测多个后续 token 来加速。
训练专用草稿模型:¶
用主模型生成大量的 prompt-回答对,然后用这些数据去微调一个小模型,使其模仿主模型的输出分布。这类似于知识蒸馏。
可以在特定领域(如代码、数学)上微调,以获得更高的接受率。
一些研究还探索了动态调整草稿模型的大小或 K 值,以适应不同的推理阶段。
工程部署考量¶
硬件亲和性:草稿模型应尽可能与主模型共享计算资源,避免数据在不同 GPU 之间频繁搬运。
调度策略:在实际服务中,可以使用异步的草稿-验证流水线,进一步隐藏草稿模型的计算延迟。
📚 实践经验:如果你的主模型是基于 LLaMA 架构,用 TinyLlama 或 LLaMA-68M 作为草稿模型往往是一个开箱即用的好选择。对于更极致的加速需求,可以尝试 Eagle 这类专门训练的头,它们甚至可以做到一次猜测 10+ token,接受率仍保持在 0.8 以上。
8. 投机采样的接受率是什么意思?接受率和加速比的关系是什么?¶
接受率(Acceptance Rate)是投机采样中衡量草稿模型“猜测”质量的核心指标。它指的是在验证阶段,主模型根据自身的概率分布,通过拒绝采样机制接受草稿模型所生成的token的比例。
形式上,对于草稿模型生成的每一个候选 token,主模型会计算该 token 在原分布下的概率,并将其与一个随机阈值比较。如果该 token 的概率足够高,主模型就“接受”它,直接将其作为正式输出;否则,主模型会“拒绝”该 token 及其后续所有猜测,并从这个位置重新采样。整个过程保证了最终输出的分布与主模型自回归生成完全一致,没有任何精度损失。
因此,接受率 = (被主模型接受的 token 数)/ (草稿模型猜测的总 token 数)。例如,草稿模型一轮猜测了 5 个 token,主模型接受了其中的 4 个,接受率就是 80%。
接受率越高,意味着草稿模型的预测与主模型越“合拍”,投机采样的效率就越高。
接受率与加速比的关系¶
投机采样的理论加速比公式为:
$$ \begin{aligned}& 加速比 =\frac{ 主模型一次自回归生成 K 个 token 的耗时 }{ 草稿模型生成 K 个 token 的耗时 + 主模型一次并行验证 K 个 token 的耗时 }\ &\& 更直观地 , 可以近似为:\ \end{aligned} $$
$$ 加速比 \approx\frac{K\times\alpha}{ 草稿开销因子 } $$
其中 K 是每轮猜测 token 数, $ \alpha $ 是接受率,“草稿开销因子”反映了草稿模型相对于主模型的推理速度。当草稿模型极快(开销可忽略)时,加速比趋近于 $ K \times \alpha $。例如,如果每次猜测 5 个 token,接受率 80%,且草稿模型开销极小,那么加速比理论上限约为 4 倍。
但现实中,草稿模型的自回归生成也需要时间,且主模型的并行验证本身也比单步自回归要稍慢(需要处理多个token),所以实际加速比通常在1.5~3倍之间。接受率越高,草稿模型越快,K越大(但不能太大,否则草稿模型的自回归延迟会超过验证开销),加速比就越大。
👑 工程直觉:接受率就像实习生写稿子时,编辑直接点头通过的段落比例。如果实习生水平高(接受率高),编辑就轻松;如果实习生经常写错(接受率低),编辑就得亲自改,加速效果打折。通常接受率低于50%时,投机采样的收益就很有限了,可能不如直接用主模型。
9. 📸 什么是自投机采样?Medusa 或 EAGLE 如何做到无独立草稿模型?¶
自投机采样(Self-Speculative Decoding)是一种不需要独立草稿模型的投机采样变体。传统投机采样需要一个独立的小模型来猜测 token,但自投机采样巧妙地复用主模型自身的部分能力来生成候选 token,从而省去了额外加载模型的显存开销。
典型方法包括 Medusa 和 EAGLE,它们通过在原始主模型上附加轻量级的“预测头”来实现快速猜测,而无需另一个完整的模型。
Medusa¶
Medusa 的核心思想是在主模型的最后一层隐藏层之上,增加多个并行的、简单的预测头(通常是单层线性层或小型 MLP)。每个预测头负责直接预测未来的第 i 个 token,即:
头1预测当前token的下一个token(即普通预测)
头2跳过一步,预测下下个token
・・・
头K预测第K步后的token
在推理时,对于给定的输入,主模型前向传播一次,得到最后一层的隐藏状态。这些隐藏状态同时输入给所有预测头,一次性产生K个候选token。这K个token构成了一条预测序列。然后,主模型再执行一次并行前向,验证这一整条预测序列,使用与标准投机采样相同的拒绝采样机制。
关键点:
· 无独立草稿模型:预测头极轻量(通常只有几千参数),与主模型共享底座,加载和计算开销可忽略。
训练高效:预测头通常用主模型生成的语料进行微调,学习“跳跃预测”的能力。
加速效果:在多个任务上达到2~3倍的加速。
EAGLE
EAGLE(Extrapolation Algorithm for Greater Language-model Efficiency)更进一步,它不仅在最后一层做预测,而是利用特征级别的外推。EAGLE训练一个轻量级的“预测器”,接收当前token的嵌入和隐藏状态,直接预测未来token的嵌入,然后利用主模型的语言模型头将这些嵌入映射为词表上的概率。这种方法比Medusa更准确,接受率更高,且同样不需要独立草稿模型。
两者优势:省显存(不需要加载额外模型),结构简单,容易集成到现有推理框架中。它们让投机采样真正变得“平民化”,尤其适合显存紧张的部署环境。
10. 动态批处理(Continuous Batching)和静态批处理有何不同?¶
静态批处理是传统的推理服务方式:将一批请求凑齐后,同时送入模型进行推理,直到该批次中所有请求都完成(生成结束符或达到最大长度),然后才处理下一批。这意味着,如果批次中某个请求生成了很长的回复,其他已完成的请求也必须等待,造成计算资源的空闲(即“气泡”)。
动态批处理(Continuous Batching)则完全打破了这种限制。它允许请求随时加入和离开正在计算的批次。当某个请求完成时,其占用的资源(如KV Cache)立即被释放,调度器可以马上从等待队列中拉取一个新请求,插入到当前批次中,与新的一批请求一起继续解码。这种机制就像一个不停滚动的传送带,而不是一辆等所有人都到齐才发车的班车。
核心区别总结:¶
| 维度 | 静态批处理 | 动态批处理 (Continuous Batching) |
| 批次形成 | 预先凑齐一批,同时开始,同时结束 | 请求可以随时加入和退出 |
| 短请求延迟 | 受同批长请求拖累,等待时间长 | 完成后立即退出,延迟低 |
| 吞吐量 | 有大量计算气泡,GPU 利用率低 | 气泡极少,GPU 几乎一直满载 |
| 显存管理 | 通常预分配固定大小,灵活性差 | 需要配合 PagedAttention 等动态内存管理 |
| 实现复杂度 | 简单 | 较复杂,需要精细调度和内存管理 |
典型的动态批处理实现是 vLLM,它采用 PagedAttention 将 KV Cache 分页管理,使得请求的插入和移除非常轻量。
比喻:静态批处理就像坐公交车,必须等所有乘客上齐、下完才发车;动态批处理则是空出的座位不断补客,乘客随时可以下车,车辆始终运行,效率极高。
11. ✓ Continuous Batching 如何提高 GPU 利用率?¶
Continuous Batching 通过消除计算气泡和提升批处理规模两大手段,让 GPU 的计算单元几乎一直处于忙碌状态。
1. 消除气泡(Bubble)¶
在静态批处理中,一个批次的完成时间由其中最长的请求决定。当短请求已经结束时,GPU 的计算核心实际上在空转,等待长请求的剩余 token 逐步生成。这些空转期就是计算气泡。动态批处理允许短请求完成后立即释放资源并加入新请求,从而填满这些原本会空闲的时间片,使 GPU 持续不断地进行计算。
2. 动态维持大 batch¶
推理时,batch size 越大,GPU 的并行计算效率越高(因为一次矩阵乘法可以处理多个 token)。静态批处理在后期由于请求不断完成,batch size 会逐渐减小,效率下降。动态批处理则通过不断补充新请求,让 batch size 始终保持在一个较高水平,最大化 GPU 的计算吞吐量(Token/s)。
3. 异步流水线¶
动态批处理往往与 Prefill/Decode 混合调度结合,可以在 GPU 执行 Decode 的同时,CPU 上执行新请求的 Prefill,进一步隐藏延迟。
实际数据:在相同的硬件和模型下,使用 VLLM(Continuous Batching)的吞吐量可达传统静态批处理的 3~5 倍,尤其在多用户、短回复的对话场景中优势极其明显。
12. 在 Continuous Batching 中,如何处理 prefill 和 decode 的混合调度?¶
一个推理请求包含两个阶段:Prefill(一次性处理输入 prompt,生成首个 token)和 Decode(逐个生成后续 token)。两者计算特性截然不同:
Prefill 是计算密集型(大量并行矩阵乘法),且显存占用大(需要为整个 prompt 生成 KV Cache)。
• Decode 是带宽密集型(每次只处理一个 token),但持续时间长。
在 Continuous Batching 中,系统需要同时调度 Prefill 和 Decode 任务,以平衡吞吐和延迟。
常见的调度策略:¶
-
优先Decode:由于Decode是一个token一个token地生成,如果暂停会直接影响用户体验。通常调度器会优先保证正在进行的Decode任务不被阻塞,将GPU资源先分配给它们。
-
插入式 Prefill:当 GPU 在 Decode 阶段有空闲(例如 batch size 较小),调度器可以“插入”一个新请求的 Prefill。但 Prefill 可能会消耗大量计算和显存,如果时机不当,会增加 Decode 延迟。因此,引擎会限制单次 Prefill 的规模(例如最多处理 512 个 token),或将 Prefill 拆分成多个小块,分批进行。
-
显存感知调度:VLLM 等框架会持续监控显存使用情况。当剩余显存足够容纳新请求的 KV Cache 时,才允许加入。Prefill 完成后,该请求即转入 Decode 池,享受常规的动态调度。
流水线化 Prefill:有些系统将 Prefill 和 Decode 放在不同 GPU 上流水线执行,但更常见的是在同一 GPU 上时分复用,通过精细的 CUDA Stream 管理让两者交替进行。
优化效果:好的混合调度能让系统在处理大量涌入请求时,既保持低延迟(优先保障Decode),又迅速消化新请求(合理插入Prefill),达到整体吞吐和用户体验的最佳平衡。
13. 算子融合是什么?在 Transformer 推理中通常融合哪些算子?¶
算子融合(Operator Fusion)是一种编译优化技术,将多个连续的、较小的计算 kernel 合并成一个大的 kernel,以减少 GPU 显存读写和 kernel 启动开销。
在推理中,许多操作本身并不涉及大量计算,但频繁地在计算单元和显存之间搬运数据会严重拖慢速度。算子融合通过让数据在片上缓存(SRAM)中一次性完成多个计算,从而显著提升性能。
Transformer 推理中常见的融合模式:¶
• Conv2D + BatchNorm + ReLU: 在计算机视觉模型中,将卷积、批归一化和激活函数融合为一个kernel。对于 Transformer,类似的操作包括 Linear + LayerNorm + Activation。
- 自注意力融合:将 Query、Key、Value 的线性投影合并为一个大矩阵乘法(即 QKV 融合)。这样原本需要三次独立 kernel 启动和数据搬运的操作,变成一次。
• Attention + Softmax + Dropout: FlashAttention 本质上就是一个极致的融合 kernel,它把整个注意力计算(包括 $ Q \times K $、softmax、与 V 加权)全部融合,中间矩阵完全在 SRAM 内处理。
残差连接融合:将 Add 和 LayerNorm 融合进前面的线性层或注意力层的输出 kernel 中。
激活函数与逐元素操作融合:如 GELU、SiLU、ReLU、Dropout、Residual Add 等,可被融合进前一个矩阵乘法的输出 kernel,避免单独启动内核。
- MLP 块融合:将 Transformer 的 FFN 中的两个线性层和中间的激活函数融合。
价值:融合后,推理延迟可降低20%~40%,且显存带宽压力减小。TensorRT、VLLM、PyTorch 2.0的torch.compile都大量应用了算子融合。
14. 💪 CUDA Kernel 优化方面,如何利用 Tensor Core 加速矩阵乘法?¶
Tensor Core 是 NVIDIA 从 Volta 架构开始引入的专用硬件单元,专门用于加速矩阵乘法和卷积运算。它在一个时钟周期内可以完成 $ 4 \times 4 \times 4 $ 的矩阵乘加(MMA)运算,提供远超普通 CUDA Core 的吞吐量。
要利用 Tensor Core 加速,需要满足以下条件:
-
数据精度要求:Tensor Core 支持特定的低精度数据类型。Volta/Turing 支持 FP16(累加到 FP32);Ampere(A100)及以后增加了 TF32、BF16、INT8、INT4 等。
-
矩阵维度对齐:Tensor Core 的 MMA 指令要求矩阵的 M、N、K 维度满足特定的对齐要求,通常是 8 或 16 的倍数。这要求我们在 kernel 设计时进行填充(padding)或分块(tiling)来保证对齐。
-
数据加载方式:使用wmma(Warp-level Matrix Multiply-Accumulate)或mma(Matrix Multiply-Accumulate)PTX指令,在warp(线程束)级别将数据从共享内存或寄存器加载,并执行矩阵乘法。
具体的优化技巧:¶
混合精度训练/推理:将模型权重和激活值转换为 FP16/BF16,用 Tensor Core 做矩阵乘法,累加到 FP32,既加速又保持精度。
内存布局优化:使用 ldmatrix 指令高效地将数据从共享内存加载到寄存器,避免 bank conflict。
· 流水线化(Software Pipelining):通过异步拷贝(cp.async)将下一个分块的数据提前从全局内存加载到共享内存,隐藏内存延迟。
分块策略:将大矩阵乘法分解成多个小分块,每个分块的计算恰好适配 Tensor Core 的尺寸,最大化利用率。
实例:在 A100 上,一个优化良好的 FP16 矩阵乘法(C=AB),使用 Tensor Core 可以达到 312 TFLOPS,而同样算法用普通 CUDA Core(FP32)只有 19.5 TFLOPS,差距超过 10 倍。因此,现代推理引擎(如 vLLM、TensorRT)无一例外都深度依赖 Tensor Core。
15. 为什么小 batch 推理往往是带宽瓶颈,而大 batch 变成计算瓶颈?¶
这源于 GPU 硬件中计算能力与显存带宽的不匹配,以及矩阵乘法在不同规模下的特性。
小batch推理(带宽瓶颈):¶
• 当 batch size 很小时(如 1~4),每次矩阵乘法涉及的矩阵规模较小。对于 GEMM(通用矩阵乘法),它的计算量是 $ O(B \times M \times N \times K) $,但需要从显存读取的数据量(模型权重)是固定的。
由于 batch size 小,计算单元产生的浮点运算需求远低于硬件峰值。但每次前向都需要把整个模型的权重从 HBM 读到计算核心,这会耗尽显存带宽。GPU 的大部分时间花在等待数据上,算力闲置。这就是带宽受限。
常见于单用户推理、长文本Decode阶段(Decode时Q的batch=1)。
大 batch 推理(计算瓶颈):¶
当 batch size 增大,计算量线性增长,而权重的读取量相对不变(权重被所有 batch 共享)。此时,计算单元终于被喂饱,GPU 利用率接近 100%。
此时限制吞吐的因素不再是带宽,而是GPU的算力峰值。我们称之为计算受限。
实际影响:¶
为了最大化吞吐(服务端场景),应尽可能增大 batch size,利用 Tensor Core 的算力。
但在线服务必须控制延迟,batch 不能无限大,所以需要在两者间权衡。
优化思路:小 batch 时尝试权重量化、算子融合、FlashAttention 等减少数据搬运的技术;大 batch 时则考虑使用更高效的 GEMM 实现、充分利用 Tensor Core。
16. 量化推理中,INT4 的矩阵乘法需要特殊硬件支持吗?如何在 GPU 上实现?¶
INT4 量化将权重或激活值表示为 4 位整数,理论上比 FP16 减小 4 倍存储。但 GPU 是否原生支持 INT4 矩阵乘法?
硬件支持情况:¶
NVIDIA GPU:从 Turing 架构开始,Tensor Core 支持 INT8、INT4 的矩阵乘法。特别是 A100/H100 的 Tensor Core 可以高效处理 INT4(通过 mma.sp 指令支持稀疏化,也可用于稠密 INT4)。但具体到 INT4,NVIDIA 的 cuBLAS 和 CUTLASS 库提供了 INT4 GEMM 的实现,利用 Tensor Core 将多个 INT4 元素打包,并使用高效的累加。
对于没有 Tensor Core 的旧 GPU,INT4 计算只能退化为软件模拟(解量化回 FP16 再算),此时推理速度可能反而变慢。
GPU 上的实现方法:¶
-
利用 CUTLASS:CUTLASS 是 NVIDIA 开源的 CUDA C++ 模板库,专门用于编写高性能 GEMM。它提供了 INT4 的 kernel 示例,通过 cutlass::int4b_t 类型和专门的 Epilogue(用于反量化和激活)来实现。
-
使用 vLLM/Aphrodite 等推理框架:这些框架内部集成 GPTQ、AWQ 等量化方法,将 INT4 权重量化,并调用高度优化的 CUTLASS INT4 kernel 或 Marlin kernel(一种针对 INT4 优化的高度并行 kernel)。Marlin 是专为 INT4 设计的,能达到接近理论上限的性能。
-
Marlin 的特点:它使用 16 线程协作加载一个 4-bit 权重块,通过巧妙的共享内存重排和 Tensor Core 指令,最大化吞吐。在 A100 上,Marlin 的 INT4 GEMM 可以达到 70% 以上的硬件利用率。
注意:激活值通常仍保持 FP16(W4A16)。推理时,权重以 INT4 存储,在进入 Tensor Core 前会被解量化成 FP16,与 FP16 激活值做矩阵乘法。解量化步骤融合在 kernel 中,几乎没有额外开销。
结论:在 A100/H100 上,INT4 矩阵乘法有成熟的软硬件支持,可以达到近似的理论加速。但在较老的 GPU 上,INT4 量化往往只节省显存,不加速甚至减速。因此,部署前务必检查硬件兼容性和选用正确的推理后端。
17. 投机采样在多卡或分布式推理中如何实现?¶
投机米样(Speculative Decoding)的核心是通过一个小型“草稿模型”快速生成多个候选 token,再由主模型并行验证。在单卡上,主模型和草稿模型通常部署在同一 GPU 上,通过流式并行降低延迟。但在多卡或分布式推理环境中,情况变得复杂,需要解决模型放置、通信开销和负载均衡等问题。
多卡实现方案¶
主要有三种架构:¶
1. 草稿模型与主模型同卡部署¶
如果单卡显存足够同时容纳主模型和草稿模型,这是最简单的方案。推理时,主模型负责验证,草稿模型负责猜测。两者可以时分复用同一GPU,或者通过CUDA Stream并发执行。优点是零通信开销;缺点是显存压力大。
2. 草稿模型与主模型分卡部署(模型分离)¶
将主模型放在 GPU 0,草稿模型放在 GPU 1。两者通过高速 NVLink 或 PCIe 通信。流程如下:
GPU 1 上的草稿模型自回归生成 K 个候选 token。
将这K个token传输给GPU 0。
GPU 0 上的主模型并行验证这些 token,并将接受结果(接受的 token 列表和被拒绝位置)回传给 GPU 1。
GPU 1 根据结果更新自己的 KV Cache,继续下一轮猜测。
这种方式显存占用分开,但引入了数据传输延迟。如果 K 较小,通信开销相对验证计算可能不明显。
3. 分布式草稿模型(多个草稿模型并行)¶
在更大规模的系统中,可以使用多个独立的草稿模型同时猜测不同的候选序列,然后由主模型从中选择或合并。这类似于 ensemble,但工程复杂度高,收益有限,目前较少采用。
多卡下的特殊优化¶
· 流水线并行:如果主模型本身已采用流水线并行(PP)分布在多卡上,草稿模型可以放置在流水线的第一张卡上,猜测完成后将候选 token 直接发送给下一张卡开始验证,形成流水。
通信优化:草稿 token 数据量极小(每次几个 token ID),传输延迟远小于模型推理,对整体加速比影响不大。
· 草稿模型的分布式推理:如果草稿模型本身也需要多卡推理(极少见,因为草稿模型通常很小),则可
采用数据并行。
👑 实际案例:在 vLLM 等框架中,投机采样目前主要用在单节点多卡场景,通过指定草稿模型与主模型在不同 GPU 上实现分离部署。例如在 $ 2 \times A100 $ 上,用一张卡跑 TinyLlama-1B 做草稿,另一张跑 LLaMA-70B 做主模型,实现 2-3 倍加速。
18. 推理时常用的解码策略(贪心、束搜索、采样)对计算量有什么影响?¶
解码策略决定了模型在每一步如何选择下一个 token,不同的策略对计算量的影响主要体现在需要维护的候选序列数量和是否并行上。
| 策略 | 每步需处理序列数 | 计算量 | 备注 |
| 贪心解码 (Greedy) | 1 | 基准 | 每次只选概率最高的 token,不需要额外计算 |
| 束搜索 (Beam Search) | B (束宽) | 约 B 倍 | 每个束需独立计算 log-prob,且需对 B 条序列重新排序 |
| 随机采样 (Sampling) | 1 | 基准 | 与贪心类似,但需从多项式分布中采样,额外开销极小 |
| Top-k / Top-p 采样 | 1 | 略高于基准 | 需要先排序 logits 或累积概率,略有额外计算 |
束搜索(Beam Search)¶
束搜索在每步保持 B 条最优候选序列。每生成一个新 token 时,需要对 B 个序列的每个候选位置都计算下一个 token 的 log-prob,然后从 $ B \times V $(词表大小)个候选中选出 B 个最优。这带来了:
- 计算量:B 倍的 logits 计算(通常在解码阶段,因为每步只处理一个新 token,所以 B 个序列可以合并为 batch=B 的推理,计算量近似 B 倍于单序列)。
• 显存:需要存储 B 条序列的 KV Cache,显存压力增大。
延迟:因为 batch size 增大,解码速度可能受带宽限制。
因此,束搜索通常用在模型较小、束宽较小(B=4-8)的场景,如翻译。对于大语言模型,束搜索不仅慢,而且常导致生成文本重复、缺乏多样性,实践中很少使用。
随机采样与 Top-k/Top-p¶
随机采样只维护一条序列,计算量与贪心相同,但在得到 logits 后需要做采样操作。Top-k 和 Top-p 采样需要额外对 logits 进行排序(Top-k)或累积概率筛选(Top-p)。这些操作的计算量相对于整个Transformer 推理微乎其微,因为词表大小 V(通常数万)相对模型隐藏维度(数千)小得多。唯一可能成为瓶颈的是对超大词表(如 32000)做 Top-k 排序,但可通过高效的 torch.topk 实现,耗时占比不到 1%。
结论:在 LLM 推理中,贪心和解码策略的计算量差异远不如束搜索显著。为了生成多样、自然的文本,通常推荐使用 Top-p 采样(如 p=0.9)配合温度调节,计算开销可忽略。
19. 如何通过减少 Top-k 或限制采样范围来加速生成?¶
减少 Top-k 或限制采样范围的主要目的是减少候选 token 数量,从而降低 logits 后处理的计算开销。但需注意,这部分的加速效果在整体推理中通常非常有限,因为 logits 处理的计算量远小于 Transformer 本身的计算。
加速原理¶
-
减少 Top-k 排序计算:如果 k 值很小(如 k=10),可以利用部分排序算法(如 torch.topk)只选出最大的 k 个,这比全排序快很多。
-
降低词表大小的后处理:在采样时,我们只需要处理前 k 个 token 的概率分布,无需对全部 V 个 logits 做 softmax。可以用局部 softmax 近似,但多数框架仍会对全部 logits 做 softmax 再过滤,因此加速不明显。
-
减少数据传输:在投机采样等场景,草稿模型可能只预测前几个 token,限制采样范围能帮助草稿模型更快收敛。
实际工程中的取舍¶
单纯通过减小 k 来加速生成,收效甚微。如果 k 太小,会严重损害生成质量,导致文本重复、不连贯。
更有意义的优化是融合 logits 处理和采样操作,减少 kernel launch 开销。例如,将 logits 的 Top-k 过滤、softmax、采样合并在一个 CUDA kernel 中,避免中间数据写回显存。
对于批量推理,如果多个请求的 Top-k 和 Top-p 设置相同,可以合并这些操作,提高吞吐。
建议:不要为了加速而过度牺牲生成多样性。如果推理延迟是瓶颈,优先考虑 FlashAttention、量化、投机采样等大头;Top-k 和采样优化是锦上添花。
20. 为什么在流式输出中,TTFT(首 token 延迟)比总延迟更影响用户体验?¶
流式输出(Streaming)是指模型一边生成 token,一边将结果逐字推送给用户,而不是等全部生成完后一次性返回。在这种模式下,TTFT(Time-To-First-Token)成为核心体验指标。
用户心理模型¶
当用户发送一个 prompt 后,他们期望看到即时响应,就像与真人对话一样。TTFT 是用户第一次收到反馈的时间,这段“空白期”直接决定用户的感知延迟。如果首 token 在 200ms 内出现,用户会感觉“流畅”;超过 1 秒,就会觉得“卡顿”;超过 2-3 秒,可能怀疑是否卡死。
而总延迟(生成整个回答的时间)虽然影响任务完成时间,但因为后续 token 是连续流式出现的,用户会将其感知为“正在打字”,容忍度远高于首 token 的等待。就像打电话时,等待接通的时间最让人焦虑,而通话过程中的轻微延迟则不易察觉。
实证研究¶
多个 UX 研究证实,对于流式输出,TTFT 每增加 100ms,用户满意度显著下降。因此,在工程上,优化 Prefill 阶段(即 TTFT 的主要构成)的优先级远高于优化 Decode 阶段的总延迟。这也是为什么 FlashAttention、KV Cache 预填充、前缀缓存等技术广受重视——它们直接缩短 TTFT。
设计启示:在设计推理系统时,应把 TTFT 作为第一指标。可以通过投机采样加速首 token 生成,或用预加载 KV Cache 等方式将 TTFT 压到 100ms 以下。
21. 如何通过异步流水线重叠推理和生成来降低延迟?¶
异步流水线的核心思想是将模型的推理过程拆分成多个阶段,并让这些阶段在不同计算单元上同时执行,从而隐藏延迟、提高整体吞吐。
典型的流水线设计¶
在自回归生成中,可以把一次迭代分解为:
-
计算 Attention(或整个 Transformer 层)
-
数据搬运(加载权重、KV Cache)
3. 后处理(采样、输出)¶
通过 CUDA Stream、多线程或分布式,将这些步骤重叠执行。
具体实现技术¶
双缓冲(Double Buffering):将输入 buffer 和输出 buffer 交换使用。当 GPU 正在处理当前批次的推理时,CPU 同时准备下一批次的输入数据,并在 GPU 空闲时立即传入。
Prefill 与 Decode 流水线:在 Continuous Batching 中,将新请求的 Prefill 和正在进行的 Decode 异步执行。Prefill 可以在单独的 GPU 或 CUDA Stream 上处理,不影响已在进行中的 Decode。
- KV Cache 异步写回:在 Decode 阶段,当计算新 token 的注意力时,可以同时异步地将新 KV 追加到缓存,而不阻塞计算。
多模型流水线(如投机采样):草稿模型和主模型可以异步执行,草稿模型在生成候选 token 时,主模型可以同时验证上一轮的 token,或者预处理下一轮的输入。
软件实现¶
NVIDIA Triton Inference Server 支持动态批处理和模型流水线。
· VLLM 内部使用多个 CUDA Stream 和 PagedAttention 机制实现异步内存管理。
自定义推理框架中,可以用 cudaStreamCreate 创建多个流,并将数据拷贝、核函数启动分配到不同流上,实现 kernel 并发执行。
效果:通过流水线,可以有效降低整体推理延迟10-30%,特别是在高并发场景下,GPU利用率可进一步提升。
22. 模型并行(TP)对推理有什么好处?什么时候需要用它?¶
模型并行(Tensor Parallelism, TP)是将模型的单层(例如注意力层或 FFN 层的权重矩阵)切分到多个 GPU 上,每个 GPU 只保存一部分参数,计算时进行局部的矩阵乘法,然后通过 All-Reduce 通信合并结果。
✓ 好处¶
-
突破单卡显存限制:当模型权重加上 KV Cache 超过单卡显存时,必须使用 TP。例如 LLaMA-70B 在 FP16 下权重约 140GB,单张 A100-80G 放不下,用 TP=2 即可部署。
-
提升计算吞吐:TP 将计算量分到多卡,每张卡承担更小的矩阵乘法,并行度提高,对于 Prefill 阶段的延迟有直接降低。
-
减少 I/O 压力:每张卡的权重大小降为原来的 1/TP,对显存带宽的压力同步下降,在 Decode 阶段可以减少权重读取时间。
何时需要用它?¶
模型超大:如70B、175B模型,单卡无法加载。
Prefill 延迟要求高:即使单卡可放下,但 Prefill 太慢,用 TP 可加速。
结合流水线并行(PP):对于超大规模模型,通常使用 TP+PP 混合并行,TP 负责层内切分,PP 负责层间切分。
▲代价¶
通信开销:每层需要 All-Reduce 或 All-Gather 通信,如果 GPU 间带宽不足(如 PCIe 而非 NVLink),延迟会显著增加。
硬件要求:TP 需要高速互联(NVLink、NVSwitch),通常在单机多卡内使用,跨机 TP 通常不推荐。
实践建议:对于7B-13B模型,单卡推理通常是首选。70B以上建议TP=2或4,并确保使用NVLink连接。例如70B模型用2xA100(NVLink)做TP=2,Prefill延迟可降低30-40%。
23. 如果单卡放不下模型权重,除了量化,还有哪些办法?¶
除了量化,你可以通过模型并行、CPU Offload、层级卸载和分布式推理等手段来解决单卡显存不足的问题。
技术方案一览¶
| 方法 | 原理 | 显存节省 | 速度影响 |
| 模型并行 (TP/PP) | 将权重切分到多卡 | 与卡数成反比 | 增加通信,但能跑 |
| CPU Offload | 将部分层或权重放在 CPU,计算时加载 | 极大(取决于卸载比例) | 速度大幅下降,受 PCIe 带宽限制 |
| 硬盘 Offload | 使用 NVMe SSD 作为交换 | 极大 | 极慢,仅用于极限推理 |
| 分布式推理 (如 DeepSpeed-Inference) | 自动将模型切分到多卡并管理 Offload | 高 | 中等,利用 NVLink 加速 |
| 层级加载 (Layer-by-Layer) | 一次只加载一层到 GPU,算完释放 | 显存需求仅为单层 | 慢,适用于 CPU 推理 |
| 参数共享 / 复用 | 共享 Embedding 或某些层 | 有限 | 几乎无损 |
组合使用¶
实际中常将以上技术组合。例如:
ZeRO-Inference:将模型参数分片到多卡,同时利用 CPU 内存作为溢出空间。
DeepSpeed-Inference:结合 TP、PP 和 Offload,自动寻找最佳配置。
· llama.cpp:在 CPU 上通过 mmap 加载模型,利用系统内存,可跑 70B 模型(速度慢但可行)。
经验法则:如果只是临时测试超大模型,用 llama.cpp 在 64GB 内存的 Mac 上跑 70B,可行但慢。生产环境需要至少足够多 GPU 做张量并行,并配合量化。
24. 对于极长序列,除了 FlashAttention,还可以用哪些技术降低计算量?¶
极长序列(如 32k 以上)的推理瓶颈主要在注意力的二次复杂度。除 FlashAttention 外,以下技术可从算法和系统层面降低计算量。
算法优化¶
· 稀疏注意力:限制每个 token 只能关注部分 token。例如滑动窗口(Sliding Window,只关注最近 N 个 token),或全局+局部结合(Longformer、BigBird)。
• 线性注意力近似:如 Linformer、Performer、RWKV 等,通过将注意力复杂度降到 O(N),但可能损失精度。
分块并行(Sequence Parallelism):将序列切分到不同 GPU 上,每个 GPU 计算自己那部分序列的注意力,然后通过通信汇总。如 Ring Attention、Flash Attention-3 中的序列并行。
状态空间模型:如 Mamba,完全摒弃注意力,用线性复杂度的选择性状态空间模型替代,在长序列上表现出色。
系统工程优化¶
- KV Cache 淘汰策略:如 H2O、StreamingLLM,只保留重要的 KV 对,丢弃不重要的,减少缓存大小和后续的注意力计算。
· 前缀缓存(Prefix Caching):多个请求共享相同前缀时,只计算一次,减少 Prefill 计算。
动态窗口扩展:根据上下文动态调整注意力窗口大小。
组合效果:例如,用 Ring Attention + 滑动窗口 + FlashAttention,可以在多 GPU 上训练百万级 token 的长序列。推理时,Mamba 等新架构已成为长序列生成的有力竞争者。
25. 你如何设计一个低延迟、高并发的 LLM 推理系统?¶
设计这样一个系统需要从模型部署、请求调度、显存管理、网络传输等多方面进行全局优化。以下是一个蓝图:
1. 模型部署层¶
量化:使用 GPTQ/AWQ 将权重压缩到 INT4,减少模型大小和带宽需求。
并行策略:如果单卡放不下,用 TP=2;大 batch 场景加流水线并行。
- 推理引擎:选用 vLLM(开源高吞吐)或 TensorRT-LLM(极致性能),并开启 FlashAttention、PagedAttention。
投机采样:如果显存允许,部署草稿模型以加速单请求延迟。
2. 请求调度层¶
Continuous Batching:允许请求随时加入和退出,消除计算气泡。
优先级调度:区分实时请求(要求低延迟)和离线批处理任务,优先调度实时请求。
· TTFT 优化:小批次快速 Prefill,利用前缀缓存减少 Prefill 计算。
3. 显存管理层¶
PagedAttention:动态分配 KV Cache,显存利用率 > 90%。
· KV Cache 量化:将 KV 缓存压缩到 INT8,支持更长上下文。
· 前缀共享:多个请求相同的 system prompt 只存一份 KV Cache。
4. 服务架构层¶
负载均衡:前端用反向代理(如 Envoy)将请求分发到多个推理实例。
异步流水线:使用消息队列(如 Kafka)缓冲请求,异步处理 token 生成和流式返回。
弹性伸缩:基于 Kubernetes + HPA,根据请求队列长度动态增删推理 Pod。
· 监控与告警:实时监控 TTFT、吞吐、显存利用率、请求延迟分布,设定阈值自动扩容或告警。
5. 性能调优¶
对高频 prompt 进行预填充(缓存其 KV Cache)。
对于多轮对话,利用历史KV Cache复用,减少Prefill。
· 持续分析瓶颈:用 Nsight Systems 找出是带宽还是计算瓶颈,针对性优化 kernel。
落地示例:某对话产品使用7B模型,2xA100卡,部署vLLM + AWQ INT4,开启Continuous Batching,TTFT中位数<150ms,吞吐200+tokens/s,支持200并发用户。关键成功因素是PagedAttention+Continuous Batching+前缀缓存。