LLM & Multimodal 面试复习笔记

10: 推理优化与系统设计

整合自 HarleysZhang/llm_note(推理框架解析)+ wdndev/llm_interview_note + 知乎面经
从底层原理到系统设计,覆盖 LLM 推理全链路优化技术

1. LLM 推理瓶颈分析

1.1 为什么大模型推理瓶颈是访存而非算力?

核心结论

LLM 解码阶段是 Memory-bound(受内存带宽限制),而非 Compute-bound。

原因分析:

推论:

1.2 Prefill 和 Decode 阶段的区别

阶段Prefill(预填充)Decode(解码)
输入完整 prompt(N 个 token)1 个 token(上一步输出)
计算模式矩阵-矩阵乘(GEMM)矩阵-向量乘(GEMV)
瓶颈Compute-boundMemory-bound
GPU利用率高(大矩阵并行)低(每步只算 1 token)
优化方向Flash Attention、张量并行KV Cache、量化、Speculative Decoding

Disaggregated Prefill-Decode:将 Prefill 和 Decode 分离到不同 GPU 集群(如 DistServe),分别针对各自瓶颈优化。

2. KV Cache 管理

KV Cache 大小如何计算?为什么它是推理显存的主要瓶颈? 进阶 高频

KV Cache 公式:

$$\text{KV Cache (bytes)} = 2 \times L \times n_{kv} \times d_h \times S \times B \times \text{dtype\_size}$$

其中:$L$=层数,$n_{kv}$=KV头数,$d_h$=头维度,$S$=序列长度,$B$=batch size

实际计算(LLaMA-2 13B, FP16, seq=4096, batch=32):

  • $L=40, n_{kv}=40(\text{MHA}), d_h=128$
  • $2 \times 40 \times 40 \times 128 \times 4096 \times 32 \times 2 = 107\text{GB}$
  • 远超模型本身的 26GB!

这解释了为什么:

  • GQA/MQA 如此重要(LLaMA-2 70B 用 8 组 GQA → KV Cache 降 4x)
  • PagedAttention 对工业部署不可或缺
  • Batch size 和序列长度直接决定单卡可服务的并发数
PagedAttention 的原理是什么?它如何解决内存碎片化? 进阶 高频

问题:传统 KV Cache 预分配连续内存,但序列长度未知 → 要么预留最大长度(浪费 60-80%),要么动态扩展(造成碎片)。

PagedAttention 解决方案(借鉴 OS 虚拟内存分页):

  1. 将 KV Cache 分成固定大小的物理块(Block),每块存 B 个 token 的 KV
  2. 每个序列维护一个逻辑块表,映射逻辑块号 → 物理块地址
  3. 物理块按需分配,不必连续
  4. 序列结束时释放物理块,可立即被新请求复用

优势:

  • 内存浪费从 60-80% 降到 <4%(仅最后一个块的尾部浪费)
  • 支持动态 batch:序列长度可变,随时进出
  • Copy-on-Write 共享:Beam Search / Parallel Sampling 中,多个候选共享前缀的 KV 块,仅在分叉时复制

vLLM 架构:集中式 Scheduler + 分布式 GPU Worker,Scheduler 管理逻辑→物理块映射,Worker 执行 PagedAttention kernel。

KV Cache 压缩有哪些方法? 深入
方法原理压缩比代表
GQA/MQA减少 KV 头数4-8xLLaMA-2, Qwen2
MLA将 KV 投影到低维潜空间10x+DeepSeek-V2/V3
KV QuantizationKV Cache 存为 INT8/INT42-4xKIVI, KVQuant
Token Eviction丢弃不重要的 KV token动态H2O, StreamingLLM
Cross-Layer Sharing相邻层共享 KV2xCLA

StreamingLLM 思路:只保留"注意力汇聚点"(通常是前几个 token)+ 最近窗口,无需完整历史 KV。适合超长流式场景。

MLA(DeepSeek-V2)详解:

  • 将高维 KV($h \times d_h$)压缩为低维 latent($d_c$,如 512)
  • Cache 只存 latent,解码时还原:$K = W_{UK} \cdot c_{KV}$
  • 计算正确性保持:$\text{Attn}(q, K, V) = \text{Attn}(q \cdot W_{UK}, c_{KV}, c_{KV} \cdot W_{UV})$

3. 批处理与调度

Continuous Batching 如何工作?为什么能提升 2-20x 吞吐? 进阶 高频

Static Batching 问题:

  • 一个 batch 内所有请求同时结束才处理下一批
  • 短请求生成完只能 pad 空转,等最长的那个
  • GPU 利用率极低(尤其生成长度方差大时)

Continuous Batching(Iteration-level Scheduling):

  • 每次 decode step 为调度粒度
  • 某个请求生成 EOS → 立即移出 → 新请求立即填入
  • GPU 几乎始终满载

加速原理:

  • 消除了"等最慢请求"的空闲时间
  • 配合 PagedAttention,新请求可立即获得释放的 KV 块
  • 在生成长度方差大的场景(如对话),加速可达 10-20x

工程框架:vLLM、TGI(HuggingFace)、TensorRT-LLM 均内置支持。

Prefix Caching(RadixAttention)解决什么问题? 进阶

场景:多个请求共享相同的 system prompt(如 RAG 模板、few-shot 示例)。

问题:每个请求都重新计算相同前缀的 KV → 重复浪费。

Prefix Caching 方案:

  • Radix Tree 缓存已计算的 prefix KV
  • 新请求命中缓存前缀 → 跳过 Prefill,直接从分歧点开始解码
  • 支持部分前缀匹配(不要求完全一致)

适用场景:

  • 共享 System Prompt(如 ChatGPT 的角色设定)
  • RAG 中相同检索结果被多个 query 使用
  • Multi-turn 对话中历史不变的部分

SGLang 的 RadixAttention 是目前最成熟的实现。vLLM 的 Automatic Prefix Caching 也支持。

4. 注意力优化

Flash Attention 1/2/3 的核心思想和演进? 进阶 高频

Flash Attention v1 核心思想:IO-Aware Attention

  • 问题:标准 Attention 需要将 $N \times N$ 注意力矩阵存入 HBM,IO 开销巨大
  • 方案:Tiling(分块)+ Online Softmax,在 SRAM 中完成计算,不存中间矩阵
  • 效果:IO 从 $O(N^2)$ 降到 $O(N^2 d / M)$,内存从 $O(N^2)$ 降到 $O(N)$

Flash Attention v2 改进:

  • 减少非 matmul FLOPs(将 rescaling 合并)
  • 更好的 warp 级并行(跨序列长度维度并行)
  • 实际加速 2x over v1

Flash Attention v3(H100 优化):

  • 利用 H100 的 FP8 Tensor Core + 异步流水线
  • wgmma (Warp Group MMA) 指令
  • Ping-pong 调度:计算和数据搬运重叠

面试关键:Flash Attention 不改变数学结果(精确计算,非近似),只改变计算的实现方式。

DeepSeek MLA(Multi-head Latent Attention)的设计原理? 深入

动机:GQA 将 KV Cache 压缩 4-8x,但对于超长上下文(128K+)仍然不够。MLA 进一步压缩到 10x+。

核心设计:

  1. 下投影(Down-projection):将隐藏状态 $h$ 压缩为低维 latent:$c_{KV} = W^{DKV} h$,其中 $c_{KV} \in \mathbb{R}^{d_c}$,$d_c \ll n_h d_h$
  2. 上投影(Up-projection):从 latent 还原 KV:$K = W^{UK} c_{KV}$,$V = W^{UV} c_{KV}$
  3. 缓存策略:只缓存 $c_{KV}$(维度低),不缓存完整 K/V
  4. 计算等价:将上投影矩阵吸收到 Q 的投影中,保证注意力计算结果不变

DeepSeek-V2 参数:$d_c = 512$,每层 KV Cache 仅需 512 维(vs MHA 的 $128 \times 128 = 16384$ 维)→ 32x 压缩

额外设计:解耦的 RoPE head——由于 RoPE 与低秩压缩不兼容,单独分出几个 head 使用 RoPE,其余用 MLA。

5. 解码加速

Speculative Decoding 的原理、数学保证和实际加速比? 进阶 高频

核心思想:用小模型(Draft)快速生成 $\gamma$ 个候选 token,大模型(Target)一次并行验证。

算法(Rejection Sampling):

  1. Draft model 自回归生成 $t_1, ..., t_\gamma$,记录概率 $q(t_i | t_{<i})$
  2. Target model 对 $\gamma$ 个位置做一次前向,得到 $p(t_i | t_{<i})$
  3. 从左到右验证:若 $p(t_i) \geq q(t_i)$ → 接受;否则以概率 $1 - p/q$ 拒绝,按修正分布 $\frac{\max(0, p-q)}{\sum \max(0, p-q)}$ 重采样
  4. 从第一个拒绝位置之后全部丢弃

数学保证:输出分布 严格等于 Target model 的分布(无损加速)。

加速比:

$$\text{Speedup} \approx \frac{\gamma}{1 + (1-\alpha)\gamma / c}$$

其中 $\alpha$ = 接受率,$c$ = Draft/Target 速度比。典型 2-3x。

Draft model 选择:

  • 同系列小模型(如 LLaMA-1B draft → LLaMA-70B target)
  • 自身浅层 exit(Self-Speculative)
  • N-gram 模型(Lookahead Decoding,无需额外模型)
Medusa 和 EAGLE 是什么?与 Speculative Decoding 的区别? 深入

Medusa(多头并行猜测):

  • 在 Target 模型最后一层之上接多个轻量 head
  • 每个 head 预测不同未来位置的 token(head 1 预测 next+1,head 2 预测 next+2...)
  • 组合多个 head 的预测形成候选树,用 Tree Attention 一次验证
  • 优势:无需单独的 Draft 模型,单模型即可

EAGLE(Draft 特征复用):

  • 用 Target 模型的倒数第二层特征作为 Draft 的输入
  • Draft 只是一个轻量 head,直接预测后续 token
  • 特征比 token embedding 信息更丰富 → 接受率更高
  • EAGLE-2:动态调整猜测树的结构(哪些分支更可能被接受)

对比:

方法需要额外模型无损加速比
Speculative Decoding是(Draft model)2-3x
Medusa否(多头)可选2-3x
EAGLE否(轻量头)2.5-4x

6. 量化技术

量化的基本原理?PTQ 和 QAT 的区别? 基础

量化本质:将连续浮点数映射到有限离散整数集合,减少存储和计算开销。

基本公式(对称量化):

$$x_q = \text{round}\left(\frac{x}{s}\right), \quad s = \frac{\max(|x|)}{2^{b-1} - 1}$$

两大类:

类别PTQ(训练后量化)QAT(量化感知训练)
过程训练完成后直接量化训练时模拟量化误差
精度损失较大(尤其低比特)较小
成本低(校准数据即可)高(需重新训练)
适用部署时快速压缩追求极致精度

Weight-only vs W+A 量化:

  • Weight-only(W4/W8):只量化权重,激活保持 FP16。主要压缩模型大小和权重加载带宽
  • W+A(如 W8A8):权重和激活都量化。可以用 INT8 tensor core 加速计算
GPTQ、AWQ、GGUF 的原理与选择? 进阶 高频

GPTQ(基于 OBQ 的逐层量化):

  • 利用 Hessian 信息确定哪些权重的量化误差影响最大
  • 按列顺序量化,用剩余列补偿已量化列的误差
  • 只需少量校准数据(128 条)
  • 支持 3-bit / 4-bit / 8-bit

AWQ(Activation-aware Weight Quantization):

  • 观察:少数"显著通道"(对应激活值大的维度)对精度影响巨大
  • 对这些显著通道做 per-channel scaling(乘大系数),让量化后精度保留更好
  • 不修改权重格式,只是预处理
  • 通常精度 > GPTQ

GGUF(llama.cpp 格式):

  • 专为 CPU + GPU 混合推理设计
  • 支持多种量化类型:Q2_K ~ Q8_0
  • Q4_K_M 是精度/速度的最佳平衡点
  • 适合本地/边缘设备部署

选择:GPU 部署 → AWQ/GPTQ;CPU/边缘 → GGUF;需要 A+W 都量化的高吞吐 → SmoothQuant/FP8。

SmoothQuant 如何解决激活值量化的困难? 深入

问题:激活值中存在少数"离群值"(outlier),某些通道的值可能比其他通道大 100x。直接量化会导致大多数通道精度被浪费。

SmoothQuant 思路:将激活中的量化难度"迁移"到权重上。

方法:

$$Y = (X \cdot \text{diag}(s)^{-1}) \cdot (\text{diag}(s) \cdot W) = \hat{X} \cdot \hat{W}$$

其中 $s_j = \max(|X_j|)^\alpha / \max(|W_j|)^{1-\alpha}$,$\alpha$ 控制难度分配。

效果:处理后激活更"平滑"(各通道尺度接近),权重稍微不平滑,但权重是静态的(可以离线精细量化)。

最终实现 W8A8:权重和激活都用 INT8,利用 INT8 Tensor Core 计算,吞吐比 FP16 提升约 1.5x。

7. 长上下文技术

NTK-aware RoPE 如何实现长度外推? 深入

问题:RoPE 的旋转频率 $\theta_i = 10000^{-2i/d}$ 在训练长度之外,高频分量出现混叠(aliasing),模型性能崩溃。

朴素外推方法(线性插值):将位置 $m$ 缩放为 $m/k$($k$ 为外推倍数)。问题:高频信息被压缩,近距离分辨率下降。

NTK-aware RoPE:

  • 修改基数:$\theta_{base}' = \theta_{base} \cdot k^{d/(d-2)}$
  • 等效于在频率空间中"拉伸"低频分量(长距离),保留高频分量(短距离)
  • 不需要微调即可获得一定的外推能力

直觉:低频对应远距离关系(需要外推),高频对应近距离关系(不需要改变)。NTK-aware 的修改方式恰好对低频拉伸更多、高频几乎不动。

YaRN 是什么?为什么比 NTK-aware 更好? 深入

YaRN = Yet another RoPE extensioN

改进点:

  1. 分频段处理:将 RoPE 的频率分为三段——高频(不动)、低频(线性插值)、中频(插值与外推混合)
  2. 温度缩放:对 attention logits 乘以缩放因子 $\sqrt{t}$,补偿长序列注意力分散

为什么更好:NTK-aware 对所有频率统一处理,YaRN 针对不同频段定制策略,保留了高频的精度同时允许低频外推。

实际效果:LLaMA-2 (4K 训练) + YaRN → 128K 有效上下文,仅需少量继续训练(~400 steps)。

Ring Attention 如何实现超长序列的分布式注意力? 深入

问题:超长序列(如 1M tokens)的 KV 无法 fit 单卡。

Ring Attention 方案:

  1. 将序列沿长度维度切分到 $N$ 张 GPU(每卡负责 seq_len/$N$ 个 token)
  2. 每卡持有自己的 Q 和本地 KV
  3. KV 块在 GPU 之间环形传递:每步把 KV 发给下一卡,同时接收上一卡的 KV
  4. 每卡在收到所有 KV 块后累积完整的 attention 输出
  5. 通信与计算重叠:收到一块 KV 就立即计算,同时传输下一块

效果:序列长度随 GPU 数线性扩展,理论上无上限。

限制:需要高速互联(NVLink/IB);通信量 = $O(N \cdot L \cdot d)$,网络带宽可能成为瓶颈。

8. 分布式推理

推理时的张量并行(Tensor Parallelism)如何工作? 进阶

原理:将模型的权重矩阵按列/行切分到多张 GPU,每张 GPU 计算部分结果,通过 AllReduce 同步。

Attention 层的 TP:

  • Q/K/V 投影矩阵按列切分(每卡负责部分 head)
  • 每卡独立计算自己负责的 head 的 attention
  • 输出投影 $W_O$ 按行切分
  • 最终 AllReduce 合并输出

FFN 的 TP:

  • 第一层 $W_1$ 按列切分 → 每卡计算部分中间维度
  • 第二层 $W_2$ 按行切分 → AllReduce 合并

通信开销:每层 2 次 AllReduce(Attention 后 + FFN 后),总通信量 $O(2 \cdot B \cdot S \cdot D)$。

适用场景:单节点多卡(NVLink 带宽 900 GB/s),跨节点 TP 效率差(需要 IB)。

推理时的流水线并行(Pipeline Parallelism)和 TP 如何配合? 进阶

流水线并行:将模型按层切分,前 N 层在 GPU 0,后 N 层在 GPU 1。

推理时的 PP 问题:解码是逐 token 的串行过程,PP 中每次只有一个 stage 活跃 → 利用率低。

解决方案:Micro-batch interleaving

  • 将多个请求的不同 decode step 交错调度
  • Stage 0 处理 request A 的 step 5 时,Stage 1 同时处理 request A 的 step 4

TP + PP 组合策略(业界标准):

  • 节点内:TP(利用 NVLink 高带宽)
  • 节点间:PP(通信量小,只传一层的激活)
  • 例:8 卡 A100 节点 × 4 节点 = 节点内 TP=8,节点间 PP=4

9. 系统设计面试题

设计题:如何设计一个支持 1000 QPS 的 LLM 推理服务? 深入 高频

需求分析:

  • 假设:7B 模型,平均输入 500 tokens,输出 200 tokens,P99 延迟 < 5s
  • 每请求 decode 时间 ≈ 200 × 30ms = 6s(单卡串行)

方案设计:

  1. 模型部署:
    • AWQ INT4 量化 → 单卡可 fit(~4GB)
    • 单卡支持 batch_size ≈ 64(受 KV Cache 限制)
    • 单卡吞吐 ≈ 50 req/s(Continuous Batching)
    • 需要 1000/50 = 20 张 GPU
  2. 推理框架:vLLM + PagedAttention + Continuous Batching
  3. 负载均衡:
    • 请求路由到最空闲的实例(Least-Connection)
    • Prefix Caching 减少重复计算
  4. 优化手段:
    • Speculative Decoding(2x 加速 → 10 卡即可)
    • Chunked Prefill(大 prompt 不阻塞 decode)
    • Streaming 输出(降低用户感知延迟)

监控:TTFT(首 token 时延)、TPOT(每 token 时延)、吞吐、GPU 利用率、KV Cache 命中率。

设计题:如何设计一个 70B 模型的训练 pipeline(256 张 A100)? 深入

资源:32 节点 × 8 A100-80G,NVLink 节点内,IB 跨节点

显存估算:

  • 模型参数 (BF16): 140 GB
  • 梯度 (BF16): 140 GB
  • 优化器 (FP32 Adam): 840 GB
  • 总计: 1120 GB → 需要分布式

并行策略(3D 并行):

维度选择原因
TP (Tensor Parallel)8(节点内)利用 NVLink 600 GB/s
PP (Pipeline Parallel)4(跨节点)通信量小,IB 可承受
DP (Data Parallel)8(ZeRO-1)分摊优化器状态

每卡显存:

  • 模型参数 (TP=8): 140/8 = 17.5 GB
  • 优化器 (ZeRO-1, DP=8): 840/8 = 105 GB → 再被 PP=4 切分 → 26 GB/卡
  • 激活值:梯度检查点 → ~10 GB
  • 总计 ~55 GB/卡 ✓(fit 80G)

其他考量:混合精度 (BF16)、梯度累积 (降低 PP bubble)、Flash Attention (省激活显存)、数据预处理 pipeline (不让 GPU 等数据)。