斯坦福 CS336 从零构建大模型 (2025 春) - 第十讲:大模型推理优化 (Inference Optimization)
斯坦福 CS336 从零构建大模型 (2025 春) - 第十讲:大模型推理优化 (Inference Optimization)
文章目录
- 斯坦福 CS336 从零构建大模型 (2025 春) - 第十讲:大模型推理优化 (Inference Optimization)
-
- 一、 推理的核心指标与底层瓶颈 (Inference Workloads)
- 二、 缓解瓶颈策略 1:压缩 KV Cache (Architecture Hacks)
- 三、 缓解瓶颈策略 2:超越标准 Transformer 架构 (Alternative Architectures)
- 四、 缓解瓶颈策略 3:量化与模型剪枝 (Quantization & Pruning)
- 五、 缓解瓶颈策略 4:投机解码 (Speculative Decoding)
- 六、 缓解瓶颈策略 5:底层系统优化 (Systems Optimization)
- 七、 核心概念问答 (Q&A)
-
- Q1:在解释算术强度时,为什么我们不能把批次大小(Batch Size)设置得比 1 大很多呢?
- Q2:当你刚才给 Llama 2 算延迟和吞吐量图表时,这是假设在一张 GPU 上运行的吗?如果是同时把多个不同用户的请求打包成一个 Batch,它们生成结束的时间和生成的 Token 数各不相同该怎么办?
- Q3:关于跨层注意力 (Cross Layer Attention, CLA),它们是在层与层之间连权重也一起共享了,还是仅仅只共享 KV Cache 那些蓝色的存储块?
- Q4:如果用户的上下文 (Context size) 实在太长,导致 KV Cache 容量不可接受地暴涨。我们能通过总结(Summarizing)前面的上下文来强行缩减 KV Cache 吗?
- Q5:请深入拆解下 Transformer 在推理阶段的时间和空间复杂度。
- Q6:GQA 和 MQA 虽然减少了缓存,但它们在实际应用中有什么局限性?
- Q7:既然多头注意力的 K 和 V 增加了负担,为什么我们不直接减少总头数(Head Number),而要搞 GQA/MQA 这么复杂的共享?
- 八、 第十讲复习题 (Lecture 10: Inference)
- 九、 💡 参考答案与知识点解析
一、 推理的核心指标与底层瓶颈 (Inference Workloads)
衡量大模型推理性能有三个核心指标:首字延迟 (TTFT, Time to First Token)、每个 Token 的生成延迟 (Latency) 以及整体吞吐量 (Throughput)。
与训练时可以在整个序列上高度并行不同,推理(尤其是自回归生成)必须逐个 Token 串行生成,这引发了极大的效率问题。为了理解瓶颈在哪里,课程引入了算术强度 (Arithmetic Intensity) 的概念:
- 定义:执行的浮点运算次数 (Flops) 除以显存中传输的字节数 (Bytes)。若该值大于硬件的计算访存比,则是“计算瓶颈 (Compute-limited)”;若小于,则是“访存瓶颈 (Memory-limited)”。
- 多层感知机 (MLP) 的算术强度:其强度与批次大小(Batch Size, B)成比量。如果 B 很大,MLP 层可以打满算力;但在单次只生成一个 Token 时(B=1),算术强度极低,完全受限于显存带宽。
预填充 (Prefill) vs. 生成 (Generation) 阶段的区别
- 预填充阶段 (Prefill):一次性读取整个 Prompt。因为可以高度并行,算术强度正比于 Prompt 长度 S,因此它是计算瓶颈 (Compute-limited),显卡算力利用率很高。
- 生成阶段 (Generation):逐个 Token 生成。为了避免重复计算历史 Token,我们必须将过去计算的键值向量存在显存中,这就是 KV Cache。
- Attention 的致命痛点:在生成阶段,注意力机制的算术强度大约为 1,且与 Batch Size 完全无关!这是因为 MLP 层的权重可以被整个 Batch 共享复用,但在 Attention 层,每个序列都有自己独一无二的 KV Cache(像雪花一样独特)。每生成一个新 Token,都必须把该序列历史的所有 KV Cache 从显存重新搬进计算单元,这导致注意力层的生成永远是绝对的显存访存瓶颈 (Memory-limited)。
二、 缓解瓶颈策略 1:压缩 KV Cache (Architecture Hacks)
既然推理被 KV Cache 的显存搬运死死卡住,最直接的架构优化就是“砍掉 KV Cache 的体积”:
- 分组/多查询注意力 (GQA / MQA):不再让每个 Query 头都有一组对应的 Key/Value 头。MQA 所有 Query 共享一组 KV 头;GQA (如 Llama 3 采用) 是多个 Query 头共享一组 KV 头。这能极大缩减 KV Cache 体积,成倍提高吞吐量,且几乎不损失精度。
- 多头潜在注意力 (MLA, 深度求索 DeepSeek 的独门绝技):不减少头数,而是将 KV 缓存投影压缩到一个极低维度的隐空间 (Latent space, 比如从 16000 维压缩到 512 维)。生成时再投影回来,并且利用数学矩阵结合律将投影矩阵与后续权重融合。这带来了惊人的缓存压缩率。
- 跨层注意力 (Cross Layer Attention, CLA):不同层之间共享相同的 KV Cache。
- 局部注意力 (Local/Sliding Window Attention):只允许模型看过去 K 个 Tokens。超出窗口的 Token 直接从 KV Cache 中丢弃,使缓存大小保持常数。常与偶尔一层全局注意力混合使用 (如 Mistral 或 Character.ai 的做法)。
三、 缓解瓶颈策略 2:超越标准 Transformer 架构 (Alternative Architectures)
标准 Transformer 并非为推理效率而生。前沿研究正在尝试颠覆自回归与全注意力机制:
- 状态空间模型 (SSMs) 与线性注意力 (Linear Attention):如 Mamba 或 Minimax 01。它们类似 RNN,推理时间是线性的,状态(Cache)大小是常数。挑战在于它们不擅长“关联召回(Associative recall,即在超长文本中精准提取某个极远的键值对)”。目前的最佳实践是混合架构(大部分为线性层,偶尔穿插全注意力层)。
- 文本扩散模型 (Diffusion Models):彻底打破自回归的串行噩梦,一次性并行生成所有 Tokens,然后通过扩散过程迭代去噪优化(如 Llama 3 的某些探索和 Session Labs 的演示)。在 Tokens/秒的生成速度上拥有降维打击般的优势。
四、 缓解瓶颈策略 3:量化与模型剪枝 (Quantization & Pruning)
- 量化 (Quantization):既然显存带宽是瓶颈,把数据类型从 BF16 降到 FP8、INT8 甚至 INT4,就能让搬运速度翻倍甚至翻四倍。
- LLM.int8() 算法:神经网络变大后会出现极端离群值(Outliers)。该算法将极少数离群权重保持在高精度(16-bit),绝大部分普通权重压缩到 INT8,在保证精度的同时大幅提升速度。
- AWQ (激活感知量化):不再只看权重大小,而是结合观察“激活值”的分布,来决定哪些权重对性能最重要从而保留高精度。
- 模型剪枝 (Model Pruning):直接砍掉不重要的层或注意力头。为了弥补精度损失,通常会用原始大模型作为老师,对剪枝后的残缺小模型进行“知识蒸馏 (Distillation)”修复,从而实现比如将 15B 模型压缩至 4B 的壮举。
五、 缓解瓶颈策略 4:投机解码 (Speculative Decoding)
这是一种极为优雅的**“无损加速 (Lossless speedup)”**算法,让你既拥有大模型的质量,又能获得小模型的速度。
- 原理:利用了“验证比生成快”的物理鸿沟(大模型预填充并行验证快,逐字生成慢)。
- 机制:让一个极快但稍笨的**“草稿小模型 (Draft Model)”**一口气向前冲,迅速生成 K 个候选 Tokens。然后把这串 Tokens 作为一个批次送入庞大缓慢的目标模型(大模型)中进行一次并行的交叉检查(Prefill验证)。
- 数学保障:通过类似 Metropolis-Hastings 的拒绝采样概率调整(即目标模型概率 q 相比草稿模型概率 p 的比值 q/p 进行接收/拒绝),算法在数学上被严格证明等价于直接从目标大模型采样,能带来约 2 倍的无损提速。后续演进有 Medusa 和 Eagle 等。
六、 缓解瓶颈策略 5:底层系统优化 (Systems Optimization)
真实生产环境中的推理请求是长短不一、随时到来的。
- 持续批处理 (Continuous / In-flight Batching):传统的批处理必须等最长的一句话生成完才能结束。持续批处理会在每生成一个 Token 后将控制权交还给调度器,如果有旧请求完成就立刻踢出,有新请求就立刻塞入计算队列,实现零空闲。
- PagedAttention (vLLM的底层核心):由于不知道用户会生成多少 Token,预先分配一大块显存会导致极严重的碎片化浪费(内/外部碎片)。借鉴操作系统虚拟内存的分页机制,PagedAttention 将 KV Cache 切分成极小的固定 Block(页),按需动态分配显存。它彻底消灭了碎片浪费,还天生支持了针对相同 Prompt (如 System Prompt) 的 Copy-on-write (写时复制) 内存共享机制。
七、 核心概念问答 (Q&A)
Q1:在解释算术强度时,为什么我们不能把批次大小(Batch Size)设置得比 1 大很多呢?
回答:我们可以设置大于 1 的 Batch Size,但这里要理清概念。在稍后讨论吞吐量时你会看到,增大并发请求确实能提高整体的 Batch Size。但是,对于单个用户的单次长文本生成而言,生成下一个 Token 的那个瞬间,针对该序列的计算维度本质上 T=1。并且稍后分析注意力机制时我会证明,即便是你合并了多个请求(Batch Size 变大),因为每个用户请求的 KV Cache 是完全独立的,注意力机制层依然无法利用批次效应提升算术强度。
Q2:当你刚才给 Llama 2 算延迟和吞吐量图表时,这是假设在一张 GPU 上运行的吗?如果是同时把多个不同用户的请求打包成一个 Batch,它们生成结束的时间和生成的 Token 数各不相同该怎么办?
回答:对,为了方便理论推演,刚才那些公式都是基于单张 GPU 假设计算的。你提到的“多用户请求长短不一、到达和结束时间不同”的问题非常敏锐,这是生产环境中真实的噩梦。我们不会傻等整个 Batch 里最长的那个人生成完。这就是为什么本节课最后,我会专门讲系统层面的优化——**“持续批处理(Continuous Batching)”**来动态插拔这些异构的请求。
Q3:关于跨层注意力 (Cross Layer Attention, CLA),它们是在层与层之间连权重也一起共享了,还是仅仅只共享 KV Cache 那些蓝色的存储块?
回答:KV Cache 当然是共享的。同时为了让网络在数学逻辑上保持一致性,用于生成 Key 和 Value 的投影权重矩阵 (Projection weights) 也需要在相关层之间进行共享。
Q4:如果用户的上下文 (Context size) 实在太长,导致 KV Cache 容量不可接受地暴涨。我们能通过总结(Summarizing)前面的上下文来强行缩减 KV Cache 吗?
回答:是的,对于那些长到离谱的 Prompt,它们确实会占据海量的 KV Cache。除了今天讲的架构层面的改变,也存在其他策略,比如各种摘要压缩技术,或是所谓的**“要点标记 (Gist tokens)”**,用来强行把长提示词压缩进少量表征中以节省缓存,不过这通常超出了单纯推理优化的范畴,涉及到对模型的重新训练或增强。
Q5:请深入拆解下 Transformer 在推理阶段的时间和空间复杂度。
回答:Transformer 在推理阶段的复杂度分析需要分为两个截然不同的阶段:预填充阶段 (Prefill Phase) 和 解码阶段 (Decoding Phase)。
1. 预填充阶段 (Prefill Phase)
这是处理输入 Prompt 的过程。由于输入的所有 Token 都是已知的,Transformer 可以像训练时一样进行并行计算。
- 计算任务:计算所有输入 Token 的 Q, K, V 矩阵并进行自注意力计算。
- 时间复杂度: O ( N 2 ⋅ d ) O(N^2 \cdot d) O(N2⋅d) (其中 N 是输入序列长度,d 是模型隐藏层维度)。注意力矩阵 Q K T QK^T QKT 的大小为 N × N N \times N N×N,因此计算量与序列长度的平方成正比。
- 特性:计算密集型 (Compute-bound)。此时 GPU 的算力利用率通常较高,因为是大规模矩阵乘法。
2. 解码阶段 (Decoding Phase)
这是逐个生成 Token 的过程(Autoregressive)。每生成一个新 Token,都需要考虑之前所有的 Token。
A. 朴素实现(不带 KV Cache)
- 如果不使用缓存,生成第 t 个 Token 时需要重新计算前 t-1 个 Token 的状态。
- 每步复杂度: O ( t 2 ⋅ d ) O(t^2 \cdot d) O(t2⋅d)。
- 总复杂度: ∑ t = N N + T O ( t 2 ⋅ d ) ≈ O ( ( N + T ) 3 ⋅ d ) \sum_{t=N}^{N+T} O(t^2 \cdot d) \approx O((N+T)^3 \cdot d) ∑t=NN+TO(t2⋅d)≈O((N+T)3⋅d)。
- 缺点:存在大量冗余计算,随着序列变长,推理速度会呈立方级衰减。
B. 优化实现(带 KV Cache)
- 由于过去 Token 的 K 和 V 在后续步骤中保持不变,我们可以将其存储 in 内存中,这就是 KV Cache 技术。
- 每步复杂度: O ( t ⋅ d + d 2 ) O(t \cdot d + d^2) O(t⋅d+d2)。
- Attention 部分:只需计算当前新 Token 的 q n e w q_{new} qnew,并与缓存中的 K, V 进行点积。复杂度降为 O ( t ⋅ d ) O(t \cdot d) O(t⋅d)(矩阵-向量乘法)。
- FFN 部分:对新 Token 进行线性变换,复杂度为 O ( d 2 ) O(d^2) O(d2)。
- 总时间复杂度: ∑ t = N N + T O ( t ⋅ d ) ≈ O ( ( N + T ) 2 ⋅ d ) \sum_{t=N}^{N+T} O(t \cdot d) \approx O((N+T)^2 \cdot d) ∑t=NN+TO(t⋅d)≈O((N+T)2⋅d)。
- 特性:访存密集型 (Memory-bound)。在解码阶段,GPU 大部分时间在等待从内存中读取 KV Cache 及其权重,而不是在计算。
3. 空间复杂度与内存瓶颈
引入 KV Cache 后,时间复杂度降低了,但带来了巨大的空间开销。
- KV Cache 空间复杂度: O ( 2 ⋅ L ⋅ h ⋅ d h e a d ⋅ s ) O(2 \cdot L \cdot h \cdot d_{head} \cdot s) O(2⋅L⋅h⋅dhead⋅s)
- L L L:层数
- h h h:注意力头数
- d h e a d d_{head} dhead:每个头的维度(通常 h ⋅ d h e a d = d m o d e l h \cdot d_{head} = d_{model} h⋅dhead=dmodel)
- s s s:当前总序列长度(输入 + 已生成)
- 常量因子:对于 FP16 精度,每个参数占 2 字节。KV Cache 的大小通常以 GB 为单位计算。
- 示例:一个 7B 模型(32 层,4096 维度),在序列长度为 2048 时,KV Cache 约占 2GB 显存。
| 维度 | 预填充阶段 (Prefill) | 解码阶段 (Decoding, w/ KV Cache) |
|---|---|---|
| 主要操作 | 矩阵-矩阵乘法 (GEMM) | 矩阵-向量乘法 (GEMV) |
| 时间复杂度 | O ( N 2 ⋅ d ) O(N^2 \cdot d) O(N2⋅d) | O ( s ⋅ d ) O(s \cdot d) O(s⋅d) (每 Step) |
| 瓶颈 | GPU 算力 (TFLOPS) | 显存带宽 (Memory Bandwidth) |
| 并行性 | 高 (Token 间并行) | 低 (序列依赖,逐个生成) |
Q6:GQA 和 MQA 虽然减少了缓存,但它们在实际应用中有什么局限性?
回答:主要有以下四个维度的局限:
1. 模型表达能力的退化 (Representational Capacity)
这是最本质的局限。
- MHA (Multi-Head Attention):每个 Query 头都有自己对应的 Key 和 Value 头。这意味着不同的头可以“各司其职”,比如一个头关注语法结构,另一个头关注指代关系。
- MQA:极其激进。所有的 Query 头共享唯一的一组 Key 和 Value。
- 局限性:这极大地限制了模型在同一时间从不同子空间提取信息的能力。虽然 Query 仍然是多头的,但它们被迫在同一个“投影平面”(相同的 K, V)上进行注意力计算。
- GQA:虽然通过分组缓解了这个问题,但本质上依然是信息的有损压缩。
2. 训练与适配的成本 (Training/Fine-tuning Overhead)
你不能直接把一个训练好的 MHA 模型(如传统的 GPT-3)直接改成 MQA/GQA 来推理。
- 无法直接转换:如果你直接丢弃多余的 K/V 头,模型会立刻崩溃。
- 昂贵的微调:要将 MHA 模型转化为 GQA 结构,通常需要进行 Up-training 或 Distillation(蒸馏)。这意味着你需要耗费大量的计算资源,让 Query 头学会如何在共享的 K/V 空间里工作。
- 架构固化:一旦在训练时确定了分组数(Groups),推理时就无法动态更改。这缺乏灵活性。
3. 算子实现的复杂性 (Kernel Optimization)
虽然从数学上看 K/V 变少了,但在底层 CUDA 实现上,MQA/GQA 并不总是“天然”变快。
- 非对称性问题:标准的矩阵乘法库(如 cuBLAS)非常擅长处理对齐的、对称的矩阵。而在 MQA 中,我们需要将 1 个 K/V 头 Broadcast(广播) 给 N 个 Q 头。
- 内存编排:为了高效实现这种广播,需要编写专门的 Triton 或 CUDA Kernel(例如 FlashAttention-2 专门为 GQA 做了优化)。如果框架优化不到位,节省的访存时间可能会被复杂的内存索引计算抵消。
4. 收益递减效应 (Diminishing Returns)
MQA/GQA 的核心目的是减小 KV Cache,但在以下两种极端情况下,它的边际效益会迅速下降:
- 超大 Batch Size:当你的 Batch Size 增加到几千(比如在极高性能的集群上),模型权重的访存开销再次占据主导,此时优化 KV Cache 带来的总体加速比会变小。
- 短文本推理:如果你的应用场景主要是短文本对话(输入输出总和在 100 Token 以内),KV Cache 本身就很小,此时切换到 GQA 带来的性能提升可能感知不明显,反而还要承担精度损失。
| 维度 | MHA | GQA | MQA |
|---|---|---|---|
| KV Cache 大小 | 100% (最大) | 1/Groups | 1/Heads (最小) |
| 模型表达力 | 最好 | 较好 | 较差 |
| 推理吞吐量 | 低 | 高 | 最高 |
| 代表模型 | GPT-3, Llama 1 | Llama 2 (70B), Llama 3 | Falcon, PaLM |
Q7:既然多头注意力的 K 和 V 增加了负担,为什么我们不直接减少总头数(Head Number),而要搞 GQA/MQA 这么复杂的共享?
回答:这涉及到模型表达能力的核心逻辑,可以从三个层面理解:
1. 核心矛盾:搜索(Query)的复杂性 vs. 存储(KV)的冗余性
- Query (Q) 是“提问者”:每一个 Q 代表了一个不同的特征维度。例如,在一个句子中, Q 1 Q_1 Q1 可能在寻找“动词”, Q 2 Q_2 Q2 可能在寻找“代词的指代对象”, Q 3 Q_3 Q3 可能在寻找“逻辑转折点”。
- Key/Value (K/V) 是“被搜索的内容”:它们构成了序列的信息库。
- 关键点在于:即使大家看的是同一本书(共享 KV),不同的读者(多个 Q 头)由于关注点不同( W Q W_Q WQ 权重不同),得出的结论也是完全不同的。如果把 Q 也合并了,模型就只能用一个视角去看待信息,表达能力会断崖式下跌。
2. 这里的“多头”本质上是“多视角特征提取”
- 在 CNN 中,我们会用多个卷积核来提取不同的特征(边缘、纹理、形状)。Transformer 的多头 Q 也是一样的道理。
- 即使在 GQA/MQA 中,每个 Q 头依然拥有独立的权重矩阵 W Q i W_{Q_i} WQi。
- 计算过程: O i = A t t e n t i o n ( Q i , K s h a r e d , V s h a r e d ) O_i = Attention(Q_i, K_{shared}, V_{shared}) Oi=Attention(Qi,Kshared,Vshared)
- 结果:虽然 K, V 是一样的,但因为 Q 1 ≠ Q 2 Q_1 \neq Q_2 Q1=Q2,最终计算出的注意力权重分布 (Attention Score) 完全不同,输出的向量 O 1 , O 2 O_1, O_2 O1,O2 也就携带了不同的语义信息。
- 如果把两个 Q 头并成一个,那么输出的特征维度就会减半,模型后续的线性层 (Linear Layer) 收到的信息量就会大幅减少。
3. 数学上的“秩(Rank)”与子空间
- 从线性代数的角度看,多头注意力实际上是在不同的子空间中捕捉信息。
- 每一个 Q 头都在尝试将输入向量投影到一个特定的低维子空间。
- 共享 KV:意味着这些子空间都映射到同一个“参考坐标系”。
- 保留多头 Q:意味着我们依然可以从这个参考坐标系中提取出 N 种不同的线性组合。
- 如果把 Q 也减了,就相当于你把一个高维张量强行压缩了,这会导致模型退化。实验证明,缩减 KV 对性能的影响远小于缩减 Q 的头数。
| 技术 | 优化维度 | 形象比喻 | 显存收益 | 性能瓶颈 |
|---|---|---|---|---|
| GQA | 头 (Heads) | 几个人共用一个笔记本。 | 高 | 精度略微受损 |
| MLA | 维 (Latent) | 把笔记记成缩写,用的时候再查表还原。 | 极高 | 实现极度复杂 |
| CLA | 层 (Layers) | 楼上楼下共用一个书架。 | 极高 | 深度特征受限 |
八、 第十讲复习题 (Lecture 10: Inference)
一、 推理的核心指标与算力瓶颈 (Workload & Bottleneck)
- 三大核心评估指标:在衡量大模型推理系统时,TTFT(Time to First Token)、Latency(生成延迟)和 Throughput(吞吐量)分别代表什么含义?它们各自适用于什么应用场景?
- 算术强度 (Arithmetic Intensity):什么是算术强度?为什么大模型在“预填充(Prefill)”阶段通常能够打满算力(Compute-limited),但在“生成(Generation)”阶段却受限于访存瓶颈(Memory-limited)?
- Attention 的致命瓶颈:为什么在自回归生成阶段,多层感知机(MLP)的算术强度可以随批次大小(Batch Size)的增加而提升,但注意力(Attention)层的算术强度却永远是接近 1 的常数,完全无法从大 Batch Size 中获益?
二、 KV Cache 压缩与架构变体 (Architecture Hacks)
- GQA 与 MLA:为了缩减庞大的 KV Cache 显存占用,工业界提出了 GQA(分组查询注意力)和 MLA(多头潜在注意力,DeepSeek 采用)。请简述它们压缩 KV Cache 的底层逻辑分别是什么?
- 多维度的 Cache 共享:局部/滑动窗口注意力(Local Attention)和跨层注意力(Cross-Layer Attention, CLA)分别是从哪两个不同的维度来减少 KV Cache 的开销的?
- 超越 Transformer 的替代架构:状态空间模型(SSMs,如 Mamba)或线性注意力机制能够将推理的时间复杂度和缓存大小降低为常数级别。但它们在早期的评测中,常在什么类型的核心测试任务上表现糟糕?
三、 量化、剪枝与投机解码 (Quantization, Pruning & Speculative Decoding)
- 量化时的异常值困境 (Quantization Outliers):当试图用 INT8 甚至更低精度去量化大模型权重 and 激活值以加速访存时,模型内部会出现什么极端现象破坏量化精度?类似 LLM.int8() 或 AWQ 的算法是如何巧妙处理这个问题的?
- 投机解码的数学魔法 (Speculative Decoding):投机解码利用了什么直觉来实现推理加速?为什么它被称作一种“无损(Lossless)”的加速技术?它是如何通过数学机制保证最终输出与昂贵的大模型完全一致的?
四、 底层系统优化与实战场景 (Systems Optimizations)
- 分页注意力与持续批处理:在真实的线上推理服务中,用户请求长度不一且随时到达。传统的静态批处理存在极大的等待浪费和显存碎片化。业界采用了哪两种系统级技术(其中一个是 vLLM 的核心)来完美解决这两个问题?
- 课堂 Q&A(Batch Size 异构性困境):既然增大 Batch Size 可以提升系统整体吞吐量,那在多用户请求混合、Token 生成长度参差不齐的情况下,系统该如何处理 Attention 层和 MLP 层的差异化计算?
九、 💡 参考答案与知识点解析
-
三大核心评估指标?
- TTFT (Time to First Token):指用户输入 Prompt 到模型吐出第一个字的时间。对于实时对话(交互式应用)至关重要。
- Latency (生成延迟):指后续连续生成 Token 之间的平均时间间隔。也高度影响交互式体验。
- Throughput (吞吐量):指系统整体每秒能生成的总 Token 数量。对于批量数据处理(Batch processing)等离线任务最为关键。
-
算术强度与不同阶段的瓶颈?
- 算术强度定义为:执行的浮点运算次数(Flops)除以显存传输的字节数(Bytes)。
- 在预填充(Prefill)阶段,由于模型能一次性读取并并行处理整个 Prompt 的所有 Token,计算量极大,算术强度很高,因此能打满 GPU 算力,是计算瓶颈 (Compute-limited)。
- 在生成(Generation)阶段,模型必须逐个 Token 串行生成。每生成一个词,都必须把庞大的参数和历史 KV Cache 重新从显存搬进计算单元,浮点运算量极少(强度约为1),导致绝大部分时间耗费在显存搬运上,是严重的访存瓶颈 (Memory-limited)。
-
Attention 的致命瓶颈?
- 在 MLP 层中,同一 Batch 内的所有不同用户序列,都可以复用同一套模型权重矩阵,因此批次越大,算术强度越高(正比于 Batch size)。
- 但在 Attention 层,每个序列都有自己独一无二的上下文 KV Cache(被形容为 unique snowflake),序列之间无法共享这部分显存。因此即使增大并发请求数,GPU 依然得为每个序列独立搬运专属的 Cache,其算术强度永远受限在常数 1 左右。
-
GQA 与 MLA?
- GQA(分组查询注意力):大幅减少 Key 和 Value 头的数量,让多个 Query 头共享同一组 Key/Value 头,从而成倍缩小 KV Cache 的体积。
- MLA(多头潜在注意力):不直接缩减头的数量,而是将庞大的 KV 向量投影压缩到一个极低维度的隐空间(Latent space,如从上万维压缩到 512 维)进行缓存。生成时再利用矩阵乘法结合律,将投影恢复矩阵融合进后续权重中,从而实现无感知的高压缩率。
-
多维度的 Cache 共享?
- CLA(跨层注意力):在深度/层级维度上进行压缩,让 Transformer 的不同 Layer 之间共享同一套 Key 和 Value 投影及 Cache。
- Local Attention(局部注意力):在序列/时间维度上进行压缩,强制模型只关注过去有限的 K 个 Token,超出窗口外的 Cache 即可被直接丢弃,使得缓存大小不随文本长度爆炸。
-
超越 Transformer 的替代架构?
- 早期的状态空间模型(SSMs)主要在关联召回 (Associative Recall) 任务上表现挣扎。这种任务要求模型在超长序列中精准提取相隔极远的一个特定键值对。由于它们将会将所有历史压缩成了固定大小的状态,丢失了精确的远距离离散信息,因此很难像全注意力机制那样完美解决此类任务。
-
量化时的异常值困境 (Quantization Outliers)?
- 随着模型参数量的扩大,内部的权重和激活值会出现极少量的极端异常大数值 (Outliers)。
- LLM.int8() 和 AWQ 等算法通过分离处理:识别出这些极少数的关键异常值并保留高精度(如 16-bit)计算,而将绝大部分普通数值放入 INT8 中计算,从而兼顾了内存速度与模型精度。
-
投机解码的数学魔法 (Speculative Decoding)?
- 投机解码利用了**“验证比生成快”**的物理现象。它让一个小而快的“草稿模型”一口气串行生成 K 个候选 Tokens,随后将这串 Tokens 一次性送入大模型中进行并行的验证打分。
- 数学上它采用类似 Metropolis-Hastings 的拒绝采样调整,被严格证明在数学上完全等价于直接从目标大模型中精确采样,因此是真正无损的加速。
-
分页注意力与持续批处理?
- 持续批处理 (Continuous/In-flight Batching):传统机制需等待整个 Batch 中最长的那句话生成完才能退出。持续批处理在每生成一个 Token 后就会将控制权交还给调度器,迅速剔除已完成的请求并立刻塞入新请求,做到系统零空闲等待。
- 分页注意力 (PagedAttention / vLLM):借鉴操作系统虚拟内存的概念,将连续的 KV Cache 切分为固定大小的非连续内存块(Blocks)。这彻底消灭了显存碎片化浪费,并且天生支持针对重复 Prompt 的写时复制 (Copy-on-write) 共享。
-
课堂 Q&A:Batch Size 异构性困境?
- 对于注意力层 (Attention),由于必须处理异构的序列长度和独一无二的 KV Cache,计算必须相互隔离。
- 但对于多层感知机层 (MLP),由于 Token 之间互不依赖,系统可以直接将不同请求的所有张量拍平 (Flatten) 塞入同一个巨大的 Batch 维度中一起并发计算,从而巧妙地吃满 GPU 算力。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐


所有评论(0)