跳转到内容

LLM 基础概念面试题

12 道题
分类
AI 与大模型
子分类
llm
题目数
12 道
已阅读 0 / 12 题
1 Transformer 架构的核心组成与自注意力(Self-Attention)机制的数学原理

答案:

Transformer 由 Encoder 与 Decoder 两个堆叠结构组成,核心是 Self-Attention 机制,通过 Query-Key-Value 三元组计算序列内部任意位置之间的依赖关系。

整体架构:

flowchart TB
    Input["输入 Token"] --> Embed["Input Embedding + Positional Encoding"]
    Embed --> Encoder
    subgraph Encoder["Encoder Stack(N 层)"]
        direction TB
        E1["Multi-Head Self-Attention"] --> E2["Add & LayerNorm(残差 + 归一化)"] --> E3["Feed-Forward Network(FFN)"] --> E4["Add & LayerNorm"]
    end
    Encoder --> Decoder
    Embed --> Decoder
    subgraph Decoder["Decoder Stack(N 层)"]
        direction TB
        D1["Masked Multi-Head Self-Attention(防止看到未来 token)"] --> D2["Add & LayerNorm"] --> D3["Cross-Attention(Encoder-Decoder Attention)"] --> D4["Add & LayerNorm"] --> D5["Feed-Forward Network"] --> D6["Add & LayerNorm"]
    end

Self-Attention 数学表达:

$$ \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^{\top}}{\sqrt{d_k}}\right)V $$
  • Q(Query):当前位置的查询向量
  • K(Key):所有位置的键向量,与 Q 计算相似度
  • V(Value):所有位置的值向量,根据注意力权重加权聚合
  • $\sqrt{d_k}$:缩放因子,防止点积方差过大导致 softmax 进入饱和区

多头注意力(Multi-Head Attention):

# PyTorch 风格伪代码
class MultiHeadAttention(nn.Module):
    def __init__(self, d_model, num_heads):
        super().__init__()
        self.num_heads = num_heads
        self.d_k = d_model // num_heads
        self.W_q = nn.Linear(d_model, d_model)
        self.W_k = nn.Linear(d_model, d_model)
        self.W_v = nn.Linear(d_model, d_model)
        self.W_o = nn.Linear(d_model, d_model)

    def forward(self, x, mask=None):
        B, T, _ = x.shape
        # 拆成 num_heads 个头
        Q = self.W_q(x).view(B, T, self.num_heads, self.d_k).transpose(1, 2)
        K = self.W_k(x).view(B, T, self.num_heads, self.d_k).transpose(1, 2)
        V = self.W_v(x).view(B, T, self.num_heads, self.d_k).transpose(1, 2)
        # 注意力分数
        scores = (Q @ K.transpose(-2, -1)) / math.sqrt(self.d_k)
        if mask is not None:
            scores = scores.masked_fill(mask == 0, float('-inf'))
        attn = F.softmax(scores, dim=-1)
        out = attn @ V
        return self.W_o(out.transpose(1, 2).contiguous().view(B, T, -1))

与 RNN/CNN 的对比:

维度RNN/LSTMCNNSelf-Attention
路径长度O(n)O(log n)O(1)
长程依赖弱(梯度消失)受限于感受野强(任意两位置直连)
并行性差(时序依赖)好(无时序约束)
计算复杂度O(n·d²)O(k·n·d²)O(n²·d)
位置信息隐式局部+位置编码必须显式位置编码
2 位置编码(Positional Encoding)的作用及主流实现方式

答案:

Self-Attention 本身是置换等变的(permutation equivariant),对输入 token 顺序不敏感,必须显式注入位置信息。

Sinusoidal 位置编码(原始 Transformer):

$$ PE_{(pos, 2i)} = \sin\left(\frac{pos}{10000^{2i/d}}\right) $$$$ PE_{(pos, 2i+1)} = \cos\left(\frac{pos}{10000^{2i/d}}\right) $$
  • 频率沿维度指数衰减,使不同维度对应不同波长
  • 可天然外推到比训练更长的序列
  • 与 Embedding 相加注入

主流实现方式:

方案代表模型核心思想优势劣势
Sinusoidal原始 Transformer固定三角函数无需训练、可外推相对位置关系表达弱
Learned AbsoluteBERT、GPT-1/2可学习 Embedding 表简单最大长度受限
Relative PositionT5、Transformer-XL编码 token 相对距离长度外推好实现复杂
RoPELLaMA、GPT-NeoX、Qwen旋转矩阵编码绝对位置、内积表达相对位置长度外推优、广泛验证极长序列仍有衰减
ALiBiBLOOM在注意力分数上加线性偏置简单、外推性强精度略低于 RoPE
NTK-aware / YaRN社区扩展 RoPE动态调整频率基数支持超长上下文需要调参

RoPE 原理示意:

# RoPE 简化实现(按对维度旋转)
def rotate_half(x):
    x1, x2 = x[..., :x.shape[-1]//2], x[..., x.shape[-1]//2:]
    return torch.cat((-x2, x1), dim=-1)

def apply_rope(x, cos, sin):
    return x * cos + rotate_half(x) * sin

RoPE 将位置信息编码为复数域的旋转,Q 与 K 的内积自动携带相对位置差 $|i-j|$。

3 GPT、BERT、Llama 三大模型族的架构差异与适用场景

答案:

三者的根本差异在于 注意力掩码预训练任务,决定了它们擅长理解(NLU)还是生成(NLG)。

架构对比:

特性GPT(Generative Pre-Training)BERT(Bidirectional Encoder)LLaMA(Meta)
架构Decoder-onlyEncoder-onlyDecoder-only
注意力Masked Self-Attention(单向)双向 Self-AttentionMasked Self-Attention + GQA
位置编码Learned(GPT-1/2)/RoPELearnedRoPE
激活函数GELUGELUSwiGLU
归一化Pre-LayerNormPost-LayerNormRMSNorm(Pre-LN)
预训练任务Next Token Prediction(自回归 LM)MLM + NSPNext Token Prediction
典型规模175B(GPT-3)340M(BERT-Large)7B/13B/65B/70B
优势文本生成、Few-shot文本理解、分类、抽取开源可商用、推理性能优
劣势双向理解弱无法直接生成中文能力需额外微调

Masked Attention 的区别:

# GPT / LLaMA:因果掩码(Causal Mask),位置 i 只能看到 <=i 的 token
mask = torch.triu(torch.ones(T, T), diagonal=1).bool()  # 上三角为 True
attn_scores = attn_scores.masked_fill(mask, float('-inf'))

# BERT:双向注意力,无 mask,所有位置互相可见
attn_scores = attn_scores  # 完整 n×n 注意力矩阵

适用场景:

  • GPT / LLaMA:对话、写作、代码生成、Chain-of-Thought 推理
  • BERT:文本分类、命名实体识别、问答(抽取式)、搜索召回
  • LLaMA 系列:开源生态首选,是 vLLM、Ollama、llama.cpp 等推理引擎的事实标准底座
4 Tokenization 原理:BPE、WordPiece、SentencePiece 的差异

答案:

Tokenization 将原始文本切分为模型可识别的最小单元(token),直接影响词表大小、OOV 处理、多语言能力与推理效率。

主流子词算法:

算法代表模型训练方式核心指标中文处理
BPE(Byte Pair Encoding)GPT-2/3、LLaMA频次最高的字符对合并合并次数依赖预分词
WordPieceBERT似然增益最大的字符对合并语言模型似然依赖预分词
Unigram LMXLNet、ALBERT反向:从大词表裁剪概率低的 token整体似然需 SentencePiece
SentencePieceLLaMA、T5、QwenBPE 或 Unigram 统一框架端到端无预分词原生支持 CJK

BPE 训练流程:

# BPE 简化训练示意
from collections import Counter

def train_bpe(corpus, num_merges):
    # 1. 初始化:将每个词拆为字符序列 + 词尾标记 </w>
    vocab = Counter()
    for word in corpus:
        vocab[' '.join(list(word)) + ' </w>'] += 1
    # 2. 迭代 num_merges 次
    for _ in range(num_merges):
        # 统计所有相邻字符对频次
        pairs = Counter()
        for word, freq in vocab.items():
            symbols = word.split()
            for i in range(len(symbols) - 1):
                pairs[(symbols[i], symbols[i+1])] += freq
        # 合并频次最高的字符对
        best = pairs.most_common(1)[0][0]
        new_vocab = {}
        for word in vocab:
            new_word = word.replace(' '.join(best), ''.join(best))
            new_vocab[new_word] = vocab[word]
        vocab = new_vocab
    return vocab

关键差异点:

  • BPE:基于频次贪心合并,实现简单,GPT 系标配
  • WordPiece:基于语言模型似然(合并后似然提升最大),BERT 系标配
  • SentencePiece:直接在原始文本上训练,将空格视为特殊 token(),避免语言相关预分词,对中日韩文友好

LLaMA Tokenizer 特征:

  • 基于 SentencePiece + BPE
  • 词表大小 32K(LLaMA 1)→ 128K(LLaMA 3,支持多语言)
  • 数字按位切分,提升数字推理与算术能力
  • 特殊 token:<s>(BOS)、</s>(EOS)、<unk><pad>
5 预训练(Pre-training)与微调(Fine-tuning)的核心机制

答案:

预训练在大规模无标注文本上学习通用语言知识,微调在下游任务标注数据上做有监督适配,两者构成现代 LLM 的两阶段范式。

两阶段对比:

维度预训练微调
数据量TB 级无标注语料KB-MB 级任务数据
算力数千 GPU·月单卡到数十卡·天
目标函数Next Token Prediction(自回归 LM)任务 Loss(分类 CE / 指令 SFT)
学习率1e-4 ~ 3e-4(peak)1e-5 ~ 5e-5
训练步数百万 ~ 千万 step数百 ~ 数千 step
输出基座模型(Base)任务模型 / 指令模型

全参数微调的痛点:

  • 7B 模型全参数微调需 ~60GB 显存(FP32 梯度 + 优化器状态)
  • 灾难性遗忘(Catastrophic Forgetting):下游任务过拟合导致通用能力下降
  • 多任务部署成本高:每个任务一份全量权重

LoRA(Low-Rank Adaptation):

核心思想:冻结原始权重 $W_0 \in \mathbb{R}^{d \times k}$,仅训练低秩分解增量 $\Delta W = BA$,其中 $B \in \mathbb{R}^{d \times r}$,$A \in \mathbb{R}^{r \times k}$,秩 $r \ll \min(d, k)$。

# PEFT 库 LoRA 配置示例
from peft import LoraConfig, get_peft_model

config = LoraConfig(
    r=8,                          # 秩,越小越省显存
    lora_alpha=16,                # 缩放系数,通常 = 2*r
    target_modules=["q_proj", "v_proj"],  # 注入位置
    lora_dropout=0.05,
    bias="none",
    task_type="CAUSAL_LM"
)
model = get_peft_model(base_model, config)
# 可训练参数量从 7B 降至 ~4M

QLoRA(Quantized LoRA):

  • 将基座模型量化到 4-bit(NF4),冻结存储
  • 反向传播时反量化到 FP16/BF16 计算梯度
  • 配合 Double QuantizationPaged Optimizer 进一步省显存
  • 单张 24GB 消费级显卡即可微调 65B 模型
方法显存占用(7B)训练速度性能损失
Full Fine-tuning~60GB1x0
LoRA(FP16)~16GB~0.9x<1%
QLoRA(4-bit)~6GB~0.7x<2%
6 RLHF(Reinforcement Learning from Human Feedback)三阶段流程与算法演进

答案:

RLHF 通过人类偏好数据训练奖励模型,再用强化学习将 LLM 对齐到人类意图。后续演进出 DPO、PPO 等多种变体。

经典三阶段流程:

flowchart TD
    S1["Stage 1: 监督微调(SFT)
高质量指令-回答数据
Cross-Entropy Loss 训练 SFT 模型"] S2["Stage 2: 奖励模型训练(Reward Model)
同一 prompt 的多个回答
人类排序标注 → Pairwise Loss"] S3["Stage 3: 强化学习对齐(RL: PPO)
SFT 模型作为策略 π_θ
RM 评分作为奖励 r
目标: max E[r − β·KL(π_θ ‖ π_ref)]"] S1 --> S2 --> S3

PPO 目标函数:

$$ \mathcal{L}_{PPO} = \mathbb{E}_{x \sim \mathcal{D}, y \sim \pi_\theta(\cdot|x)} \left[ r_\phi(x, y) - \beta \cdot \text{KL}(\pi_\theta(y|x) \| \pi_{ref}(y|x)) \right] $$
  • $r_\phi$:奖励模型打分
  • $\beta$:KL 惩罚系数,防止策略漂移过远
  • $\pi_{ref}$:参考策略(通常是 SFT 模型)

RLHF 算法演进:

算法核心思想优势劣势
PPOActor-Critic + KL 约束稳定、可控需训练 4 个模型、显存大
DPO将 RL 转化为 SFT,直接拟合偏好简单、无需 RM 与 Critic依赖参考模型分布质量
IPODPO 改进,解决偏好过拟合对噪声更鲁棒收敛略慢
KTO利用 Kahneman-Tversky 前景理论不需要成对数据调参敏感
GRPO组内相对优势估计,无 Critic显存减半,DeepSeek 验证训练稳定性需经验
RLOOREINFORCE Leave-One-Out实现简单方差大

DPO 损失函数:

$$ \mathcal{L}_{DPO} = -\mathbb{E}_{(x, y_w, y_l)} \left[ \log \sigma \left( \beta \log \frac{\pi_\theta(y_w|x)}{\pi_{ref}(y_w|x)} - \beta \log \frac{\pi_\theta(y_l|x)}{\pi_{ref}(y_l|x)} \right) \right] $$

其中 $y_w$ 为偏好回答(winner),$y_l$ 为非偏好回答(loser)。

7 提示工程(Prompt Engineering):Few-shot、Chain-of-Thought、ReAct

答案:

提示工程通过设计输入文本的结构与示例,引导 LLM 产生期望输出,是不更新权重即可提升任务表现的核心手段。

主要范式:

范式关键思想适用场景局限性
Zero-shot直接提问,依赖模型先验简单分类、翻译复杂推理弱
Few-shot在 prompt 中提供 3-10 个示例格式控制、风格迁移占用上下文窗口
Chain-of-Thought(CoT)引导模型输出中间推理步骤算术、逻辑、规划推理时延与成本增加
Self-Consistency多次采样 CoT,投票选最终答案高准确率场景成本 N 倍
ReActThought + Action + Observation 循环工具调用、Agent错误传播
Tree-of-Thoughts多路径搜索 + 评估剪枝复杂规划实现复杂

CoT 提示示例:

# Zero-shot CoT
Q: 一个水池有两根管子,A 管 4 小时注满,B 管 6 小时注满,两管同时开多久注满?
A: 让我们一步步思考。

# Few-shot CoT
Q: 鸡兔同笼共 35 头 94 足,几只鸡几只兔?
A: 设有鸡 x 只,兔 y 只。x + y = 35,2x + 4y = 94。解得 y = 12, x = 23。答案是 23 只鸡 12 只兔。

Q: 一个水池有两根管子,A 管 4 小时注满,B 管 6 小时注满,两管同时开多久注满?
A: 

ReAct 框架:

# ReAct 伪代码
def react_agent(question, tools, max_steps=5):
    scratchpad = ""
    for step in range(max_steps):
        thought = llm(f"{scratchpad}\nQuestion: {question}\nThought:")
        if "Final Answer:" in thought:
            return extract_answer(thought)
        action = llm(f"{scratchpad}\nThought: {thought}\nAction:")
        observation = tools[action.tool].run(action.input)
        scratchpad += f"\nThought: {thought}\nAction: {action}\nObservation: {observation}"
    return "未找到答案"

最佳实践:

  • 使用结构化分隔符:### Instruction ### / ### Context ### / ### Question ###
  • 指定输出格式:JSON Schema、Markdown 表格
  • 系统提示(System Prompt)放置全局规则,用户提示(User Prompt)放置具体任务
  • 复杂任务拆解:让模型"先列出步骤,再逐步执行"
8 LLM 幻觉(Hallucination)的成因与缓解策略

答案:

幻觉指模型生成貌似合理但与事实不符或无中生有的内容,是 LLM 部署的核心风险之一。

幻觉分类:

类型描述示例
事实性幻觉与可验证事实矛盾错误引用论文、虚构历史事件
忠实性幻觉输出与输入上下文矛盾总结时篡改原文档内容
内在幻觉同一 prompt 多次生成结果自相矛盾数学推理中途更改变量
外在幻觉输出无法从输入或世界知识中验证捏造不存在的 API 名称

根因分析:

  1. 训练数据噪声:互联网语料本身含错误信息
  2. Next Token 目标函数:只优化局部似然,不保证全局事实正确
  3. 知识截止:训练数据时效性限制
  4. 解码策略:高 temperature、top-p 采样增加随机性
  5. 长尾知识稀疏:低频实体训练样本不足
  6. 过度自信:模型未学习"不知道"的能力

缓解策略:

层级策略实现方式
数据高质量清洗、事实性过滤数据流水线去重、事实核查
训练RLHF、RLAIF、DPO 对齐人类标注偏好、宪法 AI
解码Retrieval-Augmented Generation(RAG)检索外部知识注入 Prompt
提示Chain-of-Thought、Self-Verification引导模型逐步推理并自检
后处理幻觉检测 + 事实核查NLI 模型、引用溯源
工程降低 temperature、约束解码logit processor、JSON Schema

RAG 缓解幻觉的机制:

  • 提供可溯源上下文,模型有据可依
  • 实时注入新知识,突破训练截止时间
  • 支持引用标注,便于人工核查
9 上下文窗口(Context Window)的技术挑战与长上下文方案

答案:

上下文窗口指模型一次推理能处理的最大 token 数。LLM 的注意力复杂度为 $O(n^2)$,窗口扩大带来显存与计算双重压力。

主流模型上下文长度演进:

模型上下文窗口注意力实现
GPT-3.54K密集注意力
GPT-48K / 32K密集注意力
GPT-4 Turbo128K密集注意力
Claude 2100K密集注意力
Claude 3200K密集注意力
LLaMA 24K密集注意力
LLaMA 38K → 128KGQA + RoPE scaling
Qwen 2.5128K密集注意力
Gemini 1.5 Pro1M → 2M稀疏/混合注意力

长上下文的核心挑战:

  1. 显存爆炸:$n$ 个 token 的 KV Cache 占用 $O(n \cdot d \cdot L)$,70B 模型 128K 上下文需 ~40GB KV Cache
  2. 计算复杂度:$O(n^2)$ 自注意力在 128K 时已不可承受
  3. 位置编码外推:训练时未见过的长度位置表现下降
  4. “迷失在中间”(Lost in the Middle):长上下文中段信息利用效率低
  5. 预训练成本:长文本训练数据稀缺

主流长上下文方案:

graph TD
    A[长上下文方案] --> B[位置编码外推]
    A --> C[注意力优化]
    A --> D[KV Cache 压缩]

    B --> B1[RoPE Scaling]
    B --> B2[ALiBi]
    B --> B3[YaRN]
    B --> B4[NTK-aware]

    C --> C1[Sparse Attention]
    C --> C2[Sliding Window]
    C --> C3[FlashAttention]
    C --> C4[Linear Attention]

    D --> D1[PagedAttention]
    D --> D2[Multi-Query Attention]
    D --> D3[Grouped-Query Attention]
    D --> D4[KV Cache Quantization]
方案核心机制代表实现
RoPE Scaling线性 / 动态调整频率基数LLaMA-2-Long、Code LLaMA
YaRNNTK-aware + 注意力温度调节Mistral、Yi
GQA多 Q 头共享一组 KVLLaMA 2/3、Qwen
MQA所有 Q 头共享 1 组 KVPaLM、StarCoder
FlashAttentionIO-aware 分块计算GPT-4、LLaMA
Sliding Window局部窗口 + 跨层信息传递Mistral 7B
PagedAttention分页管理 KV CachevLLM
10 RAG(Retrieval-Augmented Generation)架构与关键组件

答案:

RAG 通过在生成前检索外部知识库的相关片段,注入 LLM 上下文,解决知识时效性、幻觉、私域知识整合问题。

完整 RAG 流水线:

graph LR
    A[用户 Query] --> B[Query 理解]
    B --> C[Query 改写/扩展]
    C --> D[Embedding 模型]
    D --> E[向量检索]
    F[BM25/全文检索] --> E
    E --> G[Top-K 文档]
    G --> H[Rerank 重排]
    H --> I[Prompt 拼接]
    I --> J[LLM 生成]
    J --> K[带引用回答]

    L[文档] --> M[Chunk 切分]
    M --> N[Embedding]
    N --> O[向量数据库]
    O --> E

核心组件:

组件作用主流实现
Chunking文档切分,平衡召回与上下文LangChain、LlamaIndex
Embedding文本向量化,捕捉语义BGE、M3E、OpenAI text-embedding-3
Vector DB高效相似度检索Milvus、Qdrant、Weaviate、Chroma
Reranker精排提升 Top-K 质量BGE-Reranker、Cohere Rerank
LLM最终答案生成GPT-4、Claude、LLaMA、Qwen

Chunking 策略:

# 常见切分方式
strategies = {
    "fixed_size":   "按固定 token 数切分,块大小 256-512",
    "recursive":    "按 [\\n\\n, \\n, 。, 空格] 递归切分,LangChain 默认",
    "semantic":     "按 embedding 相似度聚类切分",
    "markdown":     "按 Markdown 标题层级切分",
    "parent_child": "检索小块,注入大块上下文"
}

RAG 进阶技术:

  • Hybrid Search:向量检索 + BM25 关键词检索融合,兼顾语义与字面
  • Query Rewriting:用 LLM 改写用户 query,提升召回
  • HyDE(Hypothetical Document Embeddings):先用 LLM 生成假设性答案,再检索相似文档
  • Self-RAG:模型自主决定是否检索,并自评检索质量
  • GraphRAG:构建知识图谱,捕获实体关系
  • Agentic RAG:多 Agent 协同检索,支持多轮、工具调用、条件分支

评估指标:

指标衡量内容
Context Precision检索 Top-K 中相关文档比例
Context Recall真实相关文档被检索到的比例
Faithfulness回答是否忠于检索上下文
Answer Relevancy回答与问题的相关度
11 量化(Quantization):INT8、INT4、GPTQ、AWQ 的原理与对比

答案:

量化将模型权重与激活从 FP16/BF16 降精度到 INT8/INT4/FP8,减少显存占用、加速推理,但需控制精度损失。

核心概念:

  • 对称量化:$x_q = \text{round}(x / s)$,$s = \max(|x|) / (2^{b-1}-1)$
  • 非对称量化:$x_q = \text{round}((x - z) / s)$,多零点偏移
  • Per-tensor / Per-channel / Per-group:缩放因子粒度,越细越准
  • PTQ(Post-Training Quantization):训练后量化,无需重训
  • QAT(Quantization-Aware Training):训练中模拟量化,精度更高

主流方法对比:

方法精度是否需要校准集核心思想适用场景
INT8 动态W8A8激活动态计算 scale通用部署
INT8 静态W8A8校准集统计激活分布边缘设备
GPTQW4A16是(~128 样本)二阶 Hessian 信息,逐列量化GPU 推理
AWQW4A16保护 1% 显著权重,激活感知GPU 推理
SmoothQuantW8A8数学等价变换平滑激活分布GPU 推理
GGUF(llama.cpp)W2-W8K-Quant / I-Quant 多级量化CPU 推理
bitsandbytesW4A16NF4 + 双量化QLoRA 训练
FP8(E4M3 / E5M2)W8A8H100/H200 原生支持新一代 GPU

GPTQ 原理:

# GPTQ 核心思想:逐层量化,最小化重构误差
# 对每层权重 W,目标是找到量化后 Ŵ 使得 ||W X - Ŵ X||² 最小
# 利用 Hessian H = 2 X X^T 做二阶信息,计算量化顺序

# 使用示例
from auto_gptq import AutoGPTQForCausalLM
model = AutoGPTQForCausalLM.from_quantized(
    "TheBloke/Llama-2-7B-Chat-GPTQ",
    quantize_config={"bits": 4, "group_size": 128}
)

AWQ 原理:

  • 观察:约 1% 的显著权重(salient weights)决定了大部分激活值
  • 不量化这些显著权重(保留 FP16),其余权重量化到 INT4
  • 激活感知:依据激活分布自动寻找最优 per-channel 缩放因子
  • 优势:相比 GPTQ 推理速度更快,相同精度下 group_size 更小

量化选型建议:

硬件推荐方案原因
NVIDIA A100/H100FP16 / INT8 / FP8原生支持,吞吐最高
消费级 4090/3090AWQ-INT4 / GPTQ显存 24GB 友好
Apple SiliconGGUF Q4_K_Mllama.cpp 优化
边缘端(手机/嵌入式)INT4 / SmoothQuant内存与功耗严苛
12 推理优化:KV Cache 与 PagedAttention 的工作机制

答案:

LLM 推理是显存带宽与计算双重密集型任务,KV Cache 优化是吞吐提升的核心。

KV Cache 基础:

自回归推理时,每个新 token 需与历史所有 token 计算注意力。为避免重复计算历史 token 的 K、V 矩阵,将其缓存到显存:

# 推理时维护 KV Cache
class KVCache:
    def __init__(self, batch_size, num_heads, seq_len, head_dim):
        self.k = torch.zeros(batch_size, num_heads, seq_len, head_dim)
        self.v = torch.zeros(batch_size, num_heads, seq_len, head_dim)
        self.pos = 0

    def update(self, k_new, v_new):
        # 增量写入新 token 的 K、V
        self.k[:, :, self.pos] = k_new
        self.v[:, :, self.pos] = v_new
        self.pos += 1
        return self.k[:, :, :self.pos], self.v[:, :, :self.pos]

显存占用估算:

  • 7B 模型(32 层,32 头,128 维):单 token KV Cache ≈ $2 \times 32 \times 32 \times 128 \times 2 \text{ bytes} = 0.5 \text{ MB}$
  • 128K 上下文:$0.5 \text{ MB} \times 128000 = 64 \text{ GB}$(单序列单 batch)
  • 并发 32 路:直接爆显存

传统 KV Cache 的问题:

  • 预分配最大长度,内部碎片 25%-50%
  • 不支持请求间共享(如 system prompt 重复)
  • 显存利用率低,限制并发

PagedAttention 核心思想:

借鉴操作系统虚拟内存的页表机制,将 KV Cache 划分为固定大小的 Block(如 16 token / block),通过 Block Table 做逻辑到物理的映射。

graph TB
    subgraph 请求1
        A1[Seq 1: 48 tokens] --> BT1[Block Table: 0,2,5]
    end
    subgraph 请求2
        A2[Seq 2: 32 tokens] --> BT2[Block Table: 1,3]
    end
    subgraph 物理Block池
        B0[Block 0: tokens 0-15]
        B1[Block 1: tokens 0-15]
        B2[Block 2: tokens 16-31]
        B3[Block 3: tokens 16-31]
        B4[Block 4: Free]
        B5[Block 5: tokens 32-47]
    end
    BT1 -.-> B0
    BT1 -.-> B2
    BT1 -.-> B5
    BT2 -.-> B1
    BT2 -.-> B3

关键技术收益:

指标传统连续分配PagedAttention
内部碎片25%-50%<4%
显存利用率~60%~96%
并行采样(Parallel Sampling)每条独立分配全部 KV共享 Prompt 部分 Block
Prefix Caching不支持Block 级共享,多请求复用 system prompt
Preemption整段重算Swap 到 CPU,按需恢复

配套优化技术:

  • Continuous Batching:请求完成即刻释放 slot,新请求即时插入,GPU 利用率最大化
  • Chunked Prefill:长 prompt 切分为多 chunk,与 decode 请求混合调度
  • Prefix Cache:自动识别相同前缀,共享 KV Block
  • Speculative Decoding:用小模型 draft token,大模型 verify,加速 2-3x
  • FlashAttention:IO-aware 分块注意力,HBM 读写次数从 $O(n^2)$ 降至 $O(n)$
  • KV Cache 量化:FP8 / INT8 缓存,显存再降 2-4x
  • MQA / GQA:减少 KV 头数,KV Cache 体积降 4-8x

推理引擎对比:

引擎核心特性部署形态
vLLMPagedAttention + Continuous Batching推理服务(OpenAI 兼容 API)
TGI(HuggingFace)Rust 内核 + PagedAttention推理服务
TensorRT-LLMNVIDIA 深度优化编译极致性能
llama.cppGGUF + CPU/GPU 混合本地/边缘
SGLangRadixAttention + 程序化提示复杂 prompt 编排
MLXApple Silicon 原生Mac 本地