跳转至

LLM 面试题记录

问题 1:交叉注意力中的 QKV 分别来自哪里

核心原理详解

交叉注意力(Cross-Attention)是相对于自注意力的设计,核心作用是实现两个不同序列之间的信息融合,因此它的 Q 和 KV 来自不同的输入序列,这是和自注意力最本质的区别:

  • 自注意力:Q、K、V 全部来自同一个输入序列,用于序列内部的信息交互;
  • 交叉注意力:Q 来自一个序列,K 和 V 共同来自另一个序列,用于跨序列的信息传递。

具体来源分工:

  1. Query(Q):来自目标序列(需要接收信息、被引导的序列)。它相当于 “查询探针”,负责去源序列中检索匹配相关的信息。
  2. Key(K)和 Value(V):二者都来自同一个源序列(提供信息、被查询的序列)。其中 K 用于和 Q 计算相似度、得到注意力权重;V 承载实际的特征内容,被注意力权重加权后,融合进目标序列的输出中。

两个经典场景验证:

  • 经典 Transformer 机器翻译:解码器的交叉注意力中,Q 来自解码器当前层的输出(目标语言序列的隐状态),K/V 全部来自编码器的最终输出(源语言编码结果),实现用源语言语义指导目标语言生成。
  • 文生图模型(Stable Diffusion):交叉注意力中,Q 来自图像潜空间特征,K/V 来自文本编码器的提示词特征,实现文本描述引导图像生成。

补充:交叉注意力的计算流程(QKᵀ点积→缩放→softmax→加权 V)和自注意力完全一致,唯一差异就是 Q 与 KV 的来源不同。

面试回答话术总结

“交叉注意力是用于两个不同序列之间信息融合的注意力机制,它的 Q 和 KV 来自不同的序列:

  1. Q 也就是查询向量,来自目标序列,也就是接收信息的一方,比如 Transformer 解码器的输出、文生图里的图像特征;

  2. K 和 V 都来自同一个源序列,也就是提供信息的一方,比如 Transformer 编码器的输出、文生图里的文本编码特征;

  3. 计算逻辑和自注意力一致:用目标序列的 Q 去匹配源序列的 K,得到注意力权重,再加权对应的 V,把源序列的语义信息融合到目标序列里。

最典型的应用就是 Transformer 解码器的交叉注意力,用编码器的源语言语义来指导解码器生成目标语言文本。”


问题 2:LoRA 的原理是什么,AB 为什么要这样设计

核心原理详解

LoRA(Low-Rank Adaptation,低秩适配)是最主流的参数高效微调(PEFT)方案,它的核心假设是:大语言模型微调时,权重的更新量本质具有低秩特性—— 也就是权重的变化矩阵可以分解为两个小矩阵的乘积,不需要全量更新所有参数。

核心实现逻辑

  1. 冻结预训练模型的全部原始权重,不参与训练;
  2. 在模型的线性层(主要是注意力层的 QKV 投影、输出投影层)旁,新增一条旁路分支,由两个低秩矩阵 A 和 B 组成:
  3. 矩阵 A:形状为 输入维度 × 秩r,负责降维,用高斯分布随机初始化;
  4. 矩阵 B:形状为 秩r × 输出维度,负责升维,初始化为全 0;
  5. 前向传播时,输出 = 原始线性层输出 + 旁路输出(输入经过 A→B 的计算结果)× 缩放系数(α/r)。

AB 矩阵设计的核心原因(面试核心考点)

  1. 大幅压缩可训练参数量,降低训练成本

原始线性层权重形状是 d_in × d_out,参数量为 d_in×d_out;分解为 A 和 B 后,总参数量为 r×(d_in + d_out)

秩 r 远小于模型维度(比如 r=8/16,模型维度 4096),可训练参数量仅为全量微调的千分之几到百分之几,极大降低了训练显存占用和算力需求,同时每个任务只需保存很小的 LoRA 权重文件。

  1. 等价全量微调更新,推理无额外开销

从数学上看,A×B 的结果就是权重增量 ΔW。训练完成后,可以直接把 ΔW 合并到原始权重 W 中,得到 W' = W + ΔW

合并后模型结构和原始模型完全一致,推理阶段没有任何额外计算延迟,这是 LoRA 相比前缀微调、提示微调等其他 PEFT 方法最核心的优势。

  1. 初始化设计保证训练稳定,不破坏预训练能力

矩阵 B 初始化为全 0,因此训练启动时旁路的输出为 0,模型的输出和原始预训练模型完全一致。

这保证了训练起点稳定,不会因为新增分支破坏模型原有的预训练知识,微调过程更平稳、更容易收敛。

  1. 低秩约束贴合大模型微调的本质

大模型预训练后已经学到了通用知识,微调只是在特定任务上做小范围适配,权重更新集中在一个低秩子空间中。用 AB 分解强制约束更新的低秩性,既可以达到接近全量微调的效果,又避免了过拟合和冗余参数。

面试回答话术总结

“LoRA 是低秩适配的参数高效微调方法,核心思想是大模型微调时权重的更新量具有低秩特性,可以用两个小矩阵拟合权重变化,不需要全量更新参数。

具体来说,我们冻结原始模型的所有权重,在线性层旁加一条由 A、B 两个低秩矩阵组成的旁路:A 是降维矩阵,B 是升维矩阵。前向输出等于原始线性层的输出加上旁路的输出。

这么设计的原因主要有三点:

第一,大幅减少参数量。把原本 d_in×d_out 的大权重更新,拆成 d_in×r 和 r×d_out 的两个小矩阵,r 远小于模型维度,可训练参数量只有全量微调的千分之几,极大降低训练和存储成本。

第二,推理无额外开销。A 乘 B 本质就是权重增量 ΔW,训练完可以直接合并到原始权重里,模型结构和原来完全一致,推理没有任何延迟。

第三,训练更稳定。B 矩阵初始化为全 0,训练初始时旁路输出为 0,不会破坏预训练模型的原有能力,训练起点和全量微调一致,收敛更平稳。

整体就是用极低的成本,达到接近全量微调的效果。”


问题 3:KV Cache 缓存机制

核心原理详解

KV Cache 是大语言模型自回归推理阶段的标准性能优化技术,核心是解决自回归生成过程中的重复计算冗余问题。

背景:为什么需要 KV Cache

大语言模型的文本生成是自回归模式:每次只生成 1 个 token,再把这个 token 拼到输入末尾,继续生成下一个。

如果没有缓存,每生成一个新 token,都要重新计算整个历史序列所有 token 的 K 和 V;但历史 token 的 KV 和上一步完全一致,存在大量重复计算。序列越长,重复计算越严重,推理速度越慢。

核心工作机制

KV Cache 的思路非常朴素:把已经计算过的历史 token 的 K、V 向量缓存起来,后续步骤直接复用,只计算新 token 的 KV

完整流程分为两个阶段:

  1. 预填充阶段(Prefill)

首次输入完整 Prompt 时,一次性计算出所有 Prompt token 的 K 和 V,存入专门的缓存空间;同时基于全部 KV 计算注意力,生成第一个输出 token。此时缓存长度等于 Prompt 长度。

  1. 解码阶段(Decode)

从第二个 token 开始,每一步的输入只有上一步生成的 1 个新 token:

  • 仅计算这 1 个新 token 对应的 K 和 V;
  • 将新的 K、V 拼接到历史缓存的末尾,更新缓存;
  • 用当前新 token 的 Q,和缓存中全部的历史 KV 计算注意力,生成下一个 token。

关键细节

  • 只缓存 K 和 V,不缓存 Q:因为每一步的 Q 只对应当前 1 个新 token,本身没有重复计算,不存在冗余;而注意力计算需要用到所有历史 token 的 K 和 V,因此缓存 KV 能最大化消除冗余。
  • 缓存是逐层、分头存储的:Transformer 每一层、每一个注意力头都有独立的 KV 缓存。

收益与代价

  • 收益:解码阶段单步计算量基本恒定,不会随序列长度线性增长,推理速度提升数倍到数十倍,吞吐量大幅提升。
  • 代价:需要额外显存空间存储 KV 缓存,序列越长、模型越大,缓存显存占用越高,是长文本推理的主要显存开销来源。

延伸优化

为了降低 KV Cache 的显存占用,业界衍生出两类主流优化:

  • 算法层面:MQA(多查询注意力,所有 Q 头共享一套 KV)、GQA(分组查询注意力,分组共享 KV),通过减少 KV 头数压缩缓存体积;
  • 工程层面:KV Cache 量化(4/8 比特量化)、分页 KV Cache(PagedAttention,像操作系统内存分页一样管理缓存,提升显存利用率)。

面试回答话术总结

“KV Cache 是大模型自回归推理阶段的核心优化,用来解决逐 token 生成过程中的重复计算问题。

大模型生成文本是每次输出一个 token,如果没有缓存,每生成一个新 token 都要重新计算所有历史 token 的 KV,存在大量冗余计算。KV Cache 就是把已经计算过的历史 token 的 Key 和 Value 缓存下来,后续步骤直接复用。

它的工作流程分两个阶段:

第一是预填充阶段,第一次输入 Prompt 时,一次性算出所有 Prompt token 的 KV 并存入缓存,同时生成第一个输出 token;

第二是解码阶段,之后每一步只输入上一个新生成的 token,只计算这个新 token 的 KV,拼到缓存末尾,再用当前 token 的 Q 和全部缓存的 KV 计算注意力,生成下一个 token。

这样做的好处是解码阶段计算量基本恒定,推理速度大幅提升;代价是需要额外显存存储缓存,序列越长显存占用越高。我们只缓存 KV 不缓存 Q,是因为 Q 每一步只有当前一个 token,没有重复计算的冗余。

像 GQA、MQA 这些技术,本质也是为了减少 KV Cache 的显存占用。”