Appearance
01|模型架构与基础
本主题题目目录
点击题号跳转;右侧目录会高亮你正在阅读的题目
1. 简述 Transformer 基本原理2. Transformer 架构的核心组件有哪些?各自负责什么?3. 为什么 Transformer 需要多头注意力机制?4. multi-head attention 中每个 head 为什么要进行降维?5. Transformer 需要位置编码吗?为什么?6. 为什么 Transformer 块使用 LayerNorm 而不是 BatchNorm?7. 介绍一下 Post-LayerNorm 和 Pre-LayerNorm 的区别8. Transformer 的自注意力复杂度是多少?长序列下有什么问题?9. Encoder 编码器与 Decoder 掩码有什么区别?10. Transformer 中,同一个词可以有不同的注意力权重吗?11. 讲讲对 Attention 的理解?12. Attention 的计算步骤是什么?13. Attention 机制和传统 Seq2Seq 模型有什么区别?14. 请简述 FlashAttention 的原理15. KV Cache 是什么?它在推理中起什么作用?16. GQA(Grouped Query Attention)和 MHA 有什么区别?17. 简述 GPT 和 BERT 的区别18. 讲一下 GPT 系列模型是如何演进的19. 为什么现在的大模型大多是 Decoder-only 的架构?20. Prefix LM 和 Causal LM 区别是什么?21. 什么情况用 BERT 模型,什么情况用 LLaMA、ChatGLM 类大模型,怎么选?22. BERT 非线性的来源在哪里?23. 为什么 BERT 选择 mask 掉 15% 这个比例的词?24. 讲一下生成式语言模型的工作机理25. LLM 中的因果语言建模与掩码语言建模有什么区别?26. 什么是位置编码?绝对位置编码和相对位置编码有什么区别?27. 旋转位置编码 RoPE 的思路是什么?有什么优点?28. 什么是长度外推问题?有哪些解决方法?29. 推导一下旋转位置编码 RoPE30. RoPE 被哪些主流 LLM 应用?31. Byte-Pair Encoding(BPE)如何构建词典?32. WordPiece 与 BPE 的异同点是什么?33. 简单介绍一下 SentencePiece 的思路34. 不同大模型的分词方式有哪些区别?35. Wordpiece 与 BPE 之间的区别是什么?36. 涌现能力(Emergent Ability)是什么?产生的原因是什么?37. 介绍一下 Scaling Law,它与实际工程有什么关系?38. Chinchilla Law 是什么?对训练有什么指导意义?39. GPT-3 拥有的 1750 亿参数,是怎么算出来的?40. 大模型 LLM 的架构介绍?
1. 简述 Transformer 基本原理
👔面试官:来,简单说说 Transformer 的基本原理。
🙋♂️我:Transformer 就是那个注意力机制嘛,输入一句话,它会对每个词计算一个权重,权重大的词就更重要。
👔面试官:注意力机制只是其中一个组件。Encoder 和 Decoder 各自做什么?残差连接和 LayerNorm 的作用呢?
🙋♂️我:Encoder 就是编码,Decoder 就是解码……具体的说不太清楚。
👔面试官:整体架构都讲不清楚,细节就更别提了。回去系统地过一遍吧。
其实 Transformer 是一道问烂了但答不好的题,核心是要搭起架构骨架,不能只盯着注意力这一个点。
💡 简要回答
Transformer 是一种完全基于注意力机制的序列到序列模型,核心思想是用自注意力(Self-Attention)替代 RNN 的循环结构,让模型直接建立任意两个位置之间的依赖关系,不需要像 RNN 那样一步一步地传递信息。
原始架构分 Encoder 和 Decoder 两部分。Encoder 把输入序列编码成上下文表示,Decoder 基于这组表示逐步生成输出。二者都由多个相同的层堆叠而成,每层包含多头自注意力(MHA)和前馈网络(FFN),并通过残差连接和 LayerNorm 保持训练稳定性。
📝 详细解析
为什么要发明 Transformer?
Transformer 是为了解决 RNN 系列模型的三大痛点。
不能并行:RNN 的循环结构决定第 t 步必须等第 t-1 步完成,序列越长串行计算时间越高,GPU 并行算力白白浪费。
长距离依赖:哪怕 LSTM 加了门控,序列非常长时早期 token 的信息在传递过程中还是会被稀释,「记忆衰减」无可避免。
路径长度:位置 1 的信息想影响位置 100 的输出,RNN 中必须经过中间 99 步传递,梯度很难流通。
Transformer 用自注意力一刀切掉了这些问题:任意两个位置之间的信息交流在注意力层里只需要一步,路径长度是常数 O(1)。
Encoder 架构
Encoder 由 N 个相同的层堆叠(通常 N=6),每层包含两个子层:
- 多头自注意力层:让每个 token 都能「看到」序列中所有其他 token,按相关性加权聚合信息。「自」注意力的意思是 Q/K/V 都来自同一个序列。
- 前馈网络层(FFN):对每个位置的向量独立做非线性变换,通常两层全连接加 GELU,扩展中间维度(如 512 → 2048 → 512)。
每个子层都有残差连接和 LayerNorm:output = LayerNorm(x + SubLayer(x))
残差连接让梯度可以直接流过,缓解深层网络训练困难;LayerNorm 稳定每层的输入分布。
Decoder 架构
Decoder 同样 N 层堆叠,每层比 Encoder 多一个子层,共三个:
- Masked 多头自注意力:加了下三角掩码,每个位置只能看到自己和左边的 token,保证自回归生成时不「偷看」未来答案。
- Cross-Attention(编解码注意力):Query 来自 Decoder,Key 和 Value 来自 Encoder 输出,是 Decoder 读取编码信息的唯一通道。
- 前馈网络层:与 Encoder 相同。
位置编码
注意力机制是「置换不变」的——词顺序打乱,自注意力结果不变。原始 Transformer 用正弦/余弦位置编码,在 token embedding 上叠加位置相关向量:
PE(pos, 2i) = sin(pos / 10000^(2i/d_model))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))现代 LLM 通常改用 RoPE(旋转位置编码)等相对位置编码方案。
🎯 面试总结
回答这道题要覆盖五件事:Transformer 为什么出现(解决 RNN 的并行和长距离依赖问题);Encoder 结构(MHA + FFN + 残差 + LayerNorm,堆叠 N 层);Decoder 与 Encoder 的区别(Masked 自注意力 + Cross-Attention);位置编码的作用(注入顺序信息);整体数据流(Embedding → Encoder → Decoder 逐步生成)。
来源:Attention Is All You Need(Vaswani et al., 2017)
2. Transformer 架构的核心组件有哪些?各自负责什么?
👔面试官:你说说 Transformer 有哪些核心组件,各自负责什么。
🙋♂️我:有注意力层和全连接层,注意力负责提取关系,全连接负责变换特征。
👔面试官:残差连接呢?LayerNorm 呢?位置编码呢?你把撑起整个架构稳定性的东西全跳过了。
🙋♂️我:哦,还有这些……但它们不算核心组件吧?
👔面试官:哪个都不可缺。你去掉残差连接,深层 Transformer 直接训不起来,这不叫核心?
💡 简要回答
Transformer 的核心组件有六类:词嵌入与位置编码、多头自注意力(MHA)、前馈网络(FFN)、残差连接、层归一化(LayerNorm),以及 Decoder 特有的掩码注意力和Cross-Attention。每个组件都有不可替代的职责,缺任何一个都会导致模型无法正常工作或训练失败。
📝 详细解析
词嵌入 + 位置编码
词嵌入把 token id 映射成稠密向量,是一个可学习的查找表。纯词嵌入没有顺序信息,位置编码在词嵌入上叠加位置相关向量,让模型能区分词序。
多头自注意力(MHA)
核心计算:Attention(Q, K, V) = softmax(QK^T / √d_k) · V
Q 是「我想查什么」,K 是「我能提供什么标签」,V 是「我实际的内容」。除以 √d_k 防止点积过大导致 softmax 进入梯度极小的饱和区。「多头」是把这个过程并行做 h 次,每个头用不同的线性投影看不同的子空间。
前馈网络(FFN)
注意力层做 token 间的信息融合,FFN 做每个 token 位置的特征独立变换,引入非线性:FFN(x) = GELU(x·W1 + b1)·W2 + b2。中间层通常是输入维度的 4 倍。FFN 承担了大量的「知识存储」功能,事实性知识往往存在这些权重里。
残差连接:深层训练的保障
output = LayerNorm(x + SubLayer(x))
「加上 x」让梯度在反向传播时有直接通路,极大地缓解了深层网络的梯度消失问题。没有残差连接,12 层以上的 Transformer 几乎训不起来。
LayerNorm:稳定分布
LayerNorm 对单个样本的特征维度做归一化,不依赖 batch 大小,训练推理行为一致,天然适合变长序列的 NLP 任务。现代 LLM 几乎都改成了 Pre-LN(先 LayerNorm 再子层)并用 RMSNorm 代替完整 LayerNorm,速度更快。
Decoder 特有组件
- Masked Self-Attention:下三角掩码,生成时不能看未来 token,保证自回归合理性
- Cross-Attention:Q 来自 Decoder,K/V 来自 Encoder,是 Decoder 读取原始输入信息的窗口
🎯 面试总结
这道题考的是「系统性」,要能说出六类组件,每个都能一句话讲清楚职责:词嵌入给词向量表示,位置编码给顺序感,MHA 建立全局依赖,FFN 做位置级非线性变换,残差保证深层训练,LayerNorm 稳定分布。能说一句 Pre-LN 和 RMSNorm 是现代 LLM 的改进,加分不少。
3. 为什么 Transformer 需要多头注意力机制?
👔面试官:为什么用多头注意力,单头不行吗?
🙋♂️我:多头就是多几个注意力头,能提取更多的特征,效果更好。
👔面试官:为什么多头能提取更多特征?单头注意力的问题在哪里?
🙋♂️我:单头就只有一个视角……具体为什么我没太想过。
👔面试官:多头的每个头用独立的线性投影,投影到不同的子空间,这才是关键。同一个词在句法上和语义上承担的角色是不一样的,单头很难同时捕获这两种关系。
💡 简要回答
多头注意力的核心价值是让模型从多个不同的表示子空间同时关注不同类型的信息。
单头注意力只有一组 Q/K/V 投影,只能学到一种相关性衡量标准。多头通过 h 组独立的线性投影,让每个头在不同的子空间内独立计算注意力,相当于同时从 h 个角度审视序列,捕获句法关系、语义关系、局部关系、长距离依赖等不同类型的模式。
📝 详细解析
单头注意力的局限
自然语言里 token 之间的关系是多种多样的:句法关系(主谓、修饰)、语义关系(近义词、共指)、局部关系(相邻词搭配)、长距离关系(主语和谓语的对应)。
用一组投影矩阵,本质上是让模型只能在一个子空间里平衡所有不同类型的关系,容易顾此失彼。
多头:独立子空间的专业化分工
python
# d_model=512, h=8,每个头 d_k = 64
MultiHead(Q, K, V) = Concat(head_1, ..., head_h) · W^O
head_i = Attention(Q·W_i^Q, K·W_i^K, V·W_i^V)
# 每个 W_i 都是独立可学习的每个头的投影矩阵独立训练,自然地特化到不同类型的关系。实验中确实观察到:某些头专注于局部相邻关系,某些头专注于句法结构,某些头捕获长距离语义相似性。
参数量不变,能力免费提升
单头:Q/K/V 投影矩阵各是 d_model × d_model。多头:每个头的矩阵是 d_model × (d_model/h),h 个头合起来仍是 d_model × d_model。总参数量相同,但获得了「多视角」能力——近乎免费的提升。
🎯 面试总结
要说清楚三件事:单头只有一个投影子空间,难以同时捕获多种类型的关系;多头通过独立的线性投影让每个头特化到不同子空间;每个头维度缩小到 d_model/h,总参数量近似不变。能补一句「某些头在实验中被发现负责句法,某些负责共指消解」,会很加分。
4. multi-head attention 中每个 head 为什么要进行降维?
👔面试官:多头注意力里,为什么每个头要降维,用 d_k = d_model/h 而不是 d_k = d_model?
🙋♂️我:降维是为了减少计算量,省一点内存。
👔面试官:只是为了省内存?降维和减少头数对模型的影响是一样的吗?
💡 简要回答
每个头降维(d_k = d_model/h)有两个目的:控制总计算量不随头数线性增长,以及让每个头聚焦在低维子空间中捕获更专注的关系。
不降维时,h 个头的参数量是单头的 h 倍;降维后,总参数量保持不变,但模型获得了多视角能力——近乎免费的能力提升。降维和减少头数不等价:减少头数保持每头维度不变,但丧失了多视角能力;降维保留多视角,每个视角更专注,总计算量不变。
📝 详细解析
计算量的精确分析
注意力计算复杂度为 O(n² · d_k):
- 不降维:h 个头总复杂度 ≈ h × O(n² · d_model),是单头的 h 倍
- 降维后:h × O(n² · d_model/h) = O(n² · d_model),与单头完全一样
总复杂度和单头一样,但多了 h 个独立的投影视角。
低维子空间更聚焦
把 d_model 维空间切成 h 份,强迫每个头专注于不同的信息维度,减少头间冗余。类比让 8 个人分区域观察同一个场景,比 8 个人全都看完整场景,信息覆盖更全面,每个人更专注。
实验表明,同等参数量下多头+低维通常优于少头+高维,这也是原始 Transformer 选择降维方案的原因。
🎯 面试总结
要说清楚两个层面:计算层面(总复杂度保持 O(n²·d_model) 不变)和语义层面(低维子空间让每个头更专注,减少冗余)。再说「降维和减少头数不等价,多头+低维在同等参数量下通常更好」,这道题就答完整了。
5. Transformer 需要位置编码吗?为什么?
👔面试官:Transformer 为什么需要位置编码?能从数学上解释吗?
🙋♂️我:因为 Transformer 没有循环结构,不知道词的顺序,所以要加位置编码告诉它。
👔面试官:自注意力机制在数学上为什么是「顺序无感知」的?现代 LLM 用什么位置编码?
💡 简要回答
需要。原因是自注意力机制在数学上是**置换等变(Permutation Equivariant)**的——对输入序列重排列,输出也对应重排列,结果本质不变。「我爱你」和「你爱我」通过注意力得到的表示完全一样,模型无法区分词序。
位置编码通过给每个位置的 token 嵌入加上位置相关向量,把顺序信息显式注入到输入里。
📝 详细解析
自注意力的置换等变性
用置换矩阵 P 打乱输入 X 的行顺序,代入注意力计算:
Attention(PQ, PK, PV) = P · Attention(Q, K, V)输出只是把原来的输出行顺序打乱,内容完全没变。这在数学上证明了自注意力对位置完全无感知。
原始 Transformer:正弦位置编码
在 token embedding 上直接加位置相关向量:
PE(pos, 2i) = sin(pos / 10000^(2i/d_model))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))优点:不同位置编码唯一;对任意偏移量 k,PE(pos+k) 可表示为 PE(pos) 的线性变换;无额外参数,可外推到更长序列。
现代 LLM:RoPE 和 ALiBi
绝对位置编码需要从两个绝对位置推导相对距离,学习成本较高。现代 LLM 普遍采用相对位置编码:
- RoPE(旋转位置编码):在 Q/K 上乘旋转矩阵,使 Q_i·K_j 的结果自然包含相对位置 i-j 的信息。LLaMA、Qwen、ChatGLM 等都用 RoPE。
- ALiBi:在注意力 score 上直接加线性位置惩罚项,距离越远惩罚越大,对长度外推友好。
🎯 面试总结
从数学上解释自注意力是置换等变的(输入打乱顺序,输出也对应打乱,内容不变),这比「没有循环结构所以不知道顺序」更本质。再说清楚位置编码怎么注入信息,并提一句现代 LLM 用 RoPE 替代了绝对位置编码及其原因,这道题就很完整了。
6. 为什么 Transformer 块使用 LayerNorm 而不是 BatchNorm?
👔面试官:Transformer 为什么选 LayerNorm,不用 BatchNorm?从根本上解释一下。
🙋♂️我:LayerNorm 效果比 BatchNorm 好。
👔面试官:为什么好?在 NLP 任务里 BatchNorm 有什么具体的问题?
💡 简要回答
本质区别在于归一化的维度不同:BatchNorm 对 batch 维度做统计(同一特征维度、不同样本间),LayerNorm 对单个样本的特征维度做统计。
在 NLP 任务里,BatchNorm 有三个根本性问题:序列长度不一致导致统计不稳定(padding 污染均值/方差);推理时依赖 running 统计量偏差大(推理常是单条样本);小 batch size 时统计噪声很大。LayerNorm 完全绕开了这些问题。
📝 详细解析
BatchNorm 在 NLP 里的具体痛点
BatchNorm 对同一特征维度、不同样本做统计:μ_j = (1/N) Σ_i x_{i,j}
变长序列问题:NLP 的 batch 里各句子长度不同,短的用 <PAD> 填充。Padding 位置的特征是无意义的,混入统计会污染均值和方差,padding 越多统计越不准。
训练/推理不一致:BatchNorm 训练时用 batch 统计量,推理时用 running 统计量(移动平均)。推理时往往是单条样本,running 统计量与实际输入分布差距很大,容易出问题。
LayerNorm 对单个样本做归一化
μ = (1/H) Σ_j x_j
LN(x) = γ · (x - μ) / σ + β对每个样本独立做归一化,和 batch size 无关,和序列长度无关,训练推理行为完全一致。
Pre-LN 和 RMSNorm
原始 Transformer 用 Post-LN:output = LayerNorm(x + SubLayer(x))
现代 LLM 改成 Pre-LN:output = x + SubLayer(LayerNorm(x)),残差主路径上没有 LayerNorm 阻断,梯度直接流过,深层网络训练更稳定。
LLaMA 系列进一步用 RMSNorm 代替:去掉均值减法,只保留方差归一化,推理速度快约 7~15%,效果相当。
🎯 面试总结
从三个具体问题入手(变长序列统计不稳定、推理时 running 统计偏差、小 batch 噪声大),说清楚为什么 BatchNorm 不适合 NLP。LayerNorm 对样本特征维度做统计,完全绕开这些问题。能补一句 Pre-LN 和 RMSNorm 是工程上的进一步改进,显示出对实践的了解。
7. 介绍一下 Post-LayerNorm 和 Pre-LayerNorm 的区别
👔面试官:Post-LN 和 Pre-LN 各是怎么放的?工程上为什么现在都用 Pre-LN?
🙋♂️我:Pre-LN 是在前面加,Post-LN 是在后面加。Pre-LN 训练更稳定。
👔面试官:为什么更稳定?从梯度流动的角度解释一下。Pre-LN 有没有代价?
💡 简要回答
- Post-LN(原始 Transformer):
output = LayerNorm(x + SubLayer(x)),子层计算后归一化 - Pre-LN(现代 LLM 主流):
output = x + SubLayer(LayerNorm(x)),子层计算前归一化
Pre-LN 训练更稳定的根本原因:残差连接的主路径(x → output)上没有 LayerNorm 阻隔,梯度可以直接流回去,不会在深层网络中被反复的归一化操作累积影响。代价是最后一层输出未经 LayerNorm,理论性能上限略低,工程实践中稳定性优势远大于此。
📝 详细解析
梯度流动的差异
Post-LN 里,每一层的残差输出都要经过 LayerNorm,梯度在反向传播时需要穿越 LayerNorm 的缩放操作。多层叠加后累积影响不可忽视,训练初期容易出现梯度爆炸,通常需要精心的 warmup 学习率策略。
Pre-LN 里,从 output 到 x 有一条干净的加法连接,梯度无损地流过,不需要穿越 LayerNorm。对超过 24 层的深网络,这个差距非常明显。
RMSNorm:Pre-LN 的进一步简化
LLaMA 系列用 RMSNorm 替代标准 LayerNorm:
python
RMSNorm(x) = x / RMS(x) · γ, 其中 RMS(x) = √(1/H Σ x_j²)去掉了均值减法,只保留方差归一化,参数更少,计算更快(约快 7~15%),效果与 LayerNorm 相当。GPT-2 之后的模型、LLaMA 系列、Qwen、ChatGLM 等几乎全部采用 Pre-LN + RMSNorm。
🎯 面试总结
说清楚两点:位置差异(一句话描述公式区别);为什么 Pre-LN 稳定(残差主路径上没有 LayerNorm 阻断,梯度流动更顺畅)。能加一句 Pre-LN 的代价(最后一层未归一化,理论上限略低)以及 RMSNorm 是进一步简化,面试官会知道你跟进了前沿。
8. Transformer 的自注意力复杂度是多少?长序列下有什么问题?
👔面试官:自注意力的时间和空间复杂度是多少?长序列下会有什么问题?怎么解决?
🙋♂️我:是 O(n²),序列长了就很慢,然后用 FlashAttention 优化。
👔面试官:O(n²) 是时间还是空间?FlashAttention 是降低了计算复杂度吗?
💡 简要回答
标准自注意力:时间复杂度 O(n²·d),空间复杂度 O(n²)(需要存储 n×n 注意力矩阵)。
长序列下空间是最大瓶颈——序列长度翻倍,显存需求翻 4 倍。FlashAttention 没有降低时间复杂度,而是通过 IO 感知的分块计算避免把 n×n 矩阵写入显存,将显存降到 O(n),大幅减少 HBM 读写次数,实际速度快 2~4 倍。
📝 详细解析
复杂度来源
计算 Q·K^T 是 n×n 矩阵,每个元素是两个 d 维向量的点积:时间 O(n²·d),存储 n×n 矩阵需要空间 O(n²)。n=32000 时,注意力矩阵有 10⁹ 个元素,以 FP16 计算约 2GB,仅注意力矩阵就把显存打满。
FlashAttention:IO 优化而非算法优化
GPU 存储层级:SRAM(片上,~几十MB,带宽 ~19TB/s)vs HBM(显存,~几十GB,带宽 ~2TB/s)。标准注意力把 n×n 矩阵反复在 HBM 和 SRAM 之间搬运,GPU 大部分时间在「等数据搬运」而不是在计算(Memory-Bound)。
FlashAttention 的洞察:把 Q/K/V 切成小块,在 SRAM 里完成整块的注意力计算(利用 Online Softmax 在线维护 max 和 sum,不需要物化完整矩阵),避免写回 HBM:
- 时间复杂度仍是 O(n²·d)(数学等价)
- 显存从 O(n²) 降到 O(n)
- 实际速度快 2~4 倍
其他长序列解决方案
- 稀疏注意力(Longformer、BigBird):局部窗口 + 少量全局 token,复杂度降到 O(n·w)
- 线性注意力(Performer):核函数近似 softmax,复杂度降到 O(n),精度有损失
- MLA(DeepSeek):低秩压缩 KV Cache,减少推理时显存占用
🎯 面试总结
要分清楚两个复杂度:时间 O(n²·d) 和空间 O(n²),长序列下空间才是最大硬瓶颈。FlashAttention 是 IO 优化而非算法复杂度优化,核心是分块计算避免 HBM 读写——这是面试中很容易被追问的点。
9. Encoder 编码器与 Decoder 掩码有什么区别?
👔面试官:Encoder 的注意力和 Decoder 的注意力用的掩码有什么区别?为什么这么设计?
🙋♂️我:Decoder 有掩码,Encoder 没有,掩码是防止 Decoder 看到未来的词。
👔面试官:Encoder 完全没有掩码?Padding 掩码呢?能说说 Causal Mask 的具体形状吗?
💡 简要回答
- Encoder:只有 Padding Mask——把
<PAD>token 位置屏蔽,每个 token 可双向关注所有非 padding 位置。 - Decoder Masked Self-Attention:Causal Mask(下三角掩码)+ Padding Mask,位置 i 只能看位置 1 到 i。
- Decoder Cross-Attention:只有 Padding Mask,Decoder 每个位置可完整关注 Encoder 所有输出。
📝 详细解析
Padding Mask
batch 里短序列用 <PAD> 填充,Padding Mask 把所有 <PAD> 位置的注意力分数设为 -inf,softmax 后权重变 0,模型完全忽略这些位置。
Causal Mask(因果掩码)
Decoder 生成 token i 时只应看到已生成的位置 1 到 i。Causal Mask 是下三角矩阵,上三角位置设为 -inf:
position: 1 2 3 4
pos 1: [0 -∞ -∞ -∞] # 位置1只能看自己
pos 2: [0 0 -∞ -∞] # 位置2能看1和2
pos 3: [0 0 0 -∞] # 位置3能看1、2、3
pos 4: [0 0 0 0] # 位置4能看所有这确保训练时每个位置预测下一个 token 时只能「看历史」,与推理时逐步生成的行为完全一致。
纯 Decoder(GPT 类)的掩码
GPT 系列没有 Encoder,只保留 Causal Self-Attention,每个 token 只能看到它左边的所有 token,这就是因果语言模型(Causal LM)的本质。
🎯 面试总结
两个常见误区:认为 Encoder 没有任何掩码(其实有 Padding Mask);混淆 Causal Mask 和 Padding Mask 的用途。把三种场景分清楚,再解释 Causal Mask 的下三角形状和「不泄露未来」的设计意图,回答就很完整了。
10. Transformer 中,同一个词可以有不同的注意力权重吗?
👔面试官:同一个词在不同头里,注意力权重会不一样吗?为什么?
🙋♂️我:会不一样,因为上下文不一样。
👔面试官:能说得更具体吗?从多头注意力的机制上解释为什么同一个词在不同头里有不同的权重?
💡 简要回答
会,有两个维度的差异:
- 同一个词在不同上下文位置权重不同:注意力权重通过 Query 与 Key 做点积计算,Query 由当前 token 和上下文共同决定,不同上下文导致不同的权重分布。
- 同一个词在不同头里权重不同:每个头有独立的 W^Q、W^K、W^V 投影矩阵,同一个 token 在不同头的投影处于不同子空间,计算出的权重自然不同。
📝 详细解析
动态上下文表示:超越静态词向量
Word2Vec 里「银行」不管出现在什么语境,词向量固定不变。Transformer 里「银行」在「去银行存钱」和「坐在河岸边」两个句子里,经过注意力层处理后会得到完全不同的上下文感知表示——前者更多关注「钱、金融」相关 token,后者更多关注「河、水」相关 token。这是 Transformer 相比静态词向量最大的优势:动态上下文表示。
不同头的专业化分工
每个头的 W^Q_i 让同一个词投影到不同子空间,与其他词的 Key 做点积结果不同,自然导致不同的权重分布。实验研究表明不同头确实学到了不同类型的语言关系:有些头专注局部相邻词,有些头关注句法依存关系,有些头捕获长距离语义联系,这种专业化是训练过程自然涌现出来的,不是手工设计的。
🎯 面试总结
要说清楚两个维度:上下文影响(不同上下文的 Query 向量不同,导致权重分布不同)和多头投影差异(独立的 W 矩阵使同一词处于不同子空间)。用多义词的例子说明动态表示的实际价值,体现出你理解 Transformer 相比静态词向量的核心优势。
11. 讲讲对 Attention 的理解?
👔面试官:从你的角度,讲讲对 Attention 的理解,越深越好。
🙋♂️我:Attention 就是对不同的输入位置加权求和,权重由相关性决定。
👔面试官:Query、Key、Value 各是什么角色?为什么要设计成三个分开的向量,而不是直接做 token 间的相似度?
💡 简要回答
Attention 本质上是一种软寻址机制(Soft Addressing):Query 是查询信号,Key 是索引,Value 是内容。用 Query 和所有 Key 的相似度作为权重,对 Value 做加权求和,得到一个「被上下文感知的新表示」。
Q/K/V 三者解耦的精妙之处:Key 决定「被谁关注」,Value 决定「贡献什么内容」,二者可以是不同的投影,给模型更大的灵活性。
📝 详细解析
从信息检索角度理解
把注意力机制类比成模糊数据库查询:Query 是你想找什么,Key 是每条记录的索引标签,Value 是实际内容。普通数据库是精确匹配,注意力机制是软匹配:用相似度对所有 Value 加权求和,得到「综合了所有相关记录的混合信息」,即使没有任何 Key 和 Query 完全匹配,也能给出合理结果。
Q/K/V 解耦的价值
为什么不直接用 output = Σ sim(x_i, x_j) · x_j?
Q/K/V 解耦的核心价值在于:Key 和 Value 可以学不同的投影——Key 负责「让别人找到我」,Value 负责「我能提供什么」,这两件事用同一个向量表示是有约束的,分开让模型更灵活;Cross-Attention 里 Q 来自 Decoder、K/V 来自 Encoder,天然就是两个不同来源,解耦设计自然支持这种跨源注意力。
Self-Attention vs Cross-Attention
- Self-Attention:Q/K/V 都来自同一序列,用于序列内部上下文建模
- Cross-Attention:Q 来自一个序列,K/V 来自另一个序列,用于两序列间的对齐
RAG 里检索结果和问题的融合、多模态里图像和文本的对齐,本质上都是 Cross-Attention 的应用。
🎯 面试总结
要有层次:先说 Attention 是软寻址机制(相似度加权求和);再说 Q/K/V 解耦的价值(Key 决定「被谁找到」,Value 决定「贡献什么」,分开更灵活);最后说 Self-Attention 和 Cross-Attention 的区别。用「模糊数据库查询」这个类比把整个机制说清楚,印象会很深刻。
12. Attention 的计算步骤是什么?
👔面试官:说一下 Attention 从输入到输出的完整计算步骤,为什么要除以 √d_k?
🙋♂️我:输入乘以 Q、K、V 矩阵,然后 softmax,再乘以 V。
👔面试官:为什么要除以 √d_k?softmax 之前有什么处理?mask 怎么加的?
💡 简要回答
Scaled Dot-Product Attention 的完整计算步骤:
- 线性投影:
Q = X·W^Q, K = X·W^K, V = X·W^V - 计算点积:
scores = Q·K^T(形状 n×n) - 缩放:
scores = scores / √d_k - 加掩码(如有):mask 位置的 score 设为
-∞ - Softmax 归一化:
weights = softmax(scores)(每行归一化) - 加权求和:
output = weights · V
📝 详细解析
为什么要除以 √d_k?
当 d_k 很大时,两个 d_k 维随机向量的点积方差是 d_k(每个维度方差为 1,共 d_k 维相加)。方差大导致不同位置的分数差距被放大,输入 softmax 时会出现一个值特别大、其他值特别小的情况,softmax 进入「饱和区」,梯度接近 0,训练极其困难。
除以 √d_k 把方差控制在 1 附近,softmax 输入分布适中,梯度健康。
完整的多头注意力代码
python
import torch, torch.nn as nn, math
class MultiHeadAttention(nn.Module):
def __init__(self, d_model, h):
super().__init__()
self.d_k = d_model // h
self.h = h
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, n, d = x.shape
# 投影并切分多头 [B, n, h, d_k] -> [B, h, n, d_k]
Q = self.W_Q(x).view(B, n, self.h, self.d_k).transpose(1, 2)
K = self.W_K(x).view(B, n, self.h, self.d_k).transpose(1, 2)
V = self.W_V(x).view(B, n, self.h, 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'))
weights = scores.softmax(dim=-1)
# 加权求和 + 拼接 + 输出投影
out = (weights @ V).transpose(1, 2).reshape(B, n, -1)
return self.W_O(out)🎯 面试总结
计算步骤本身不难,关键是能解释每一步为什么这么做:投影让 Q/K/V 学到不同表示;除以 √d_k 防止 softmax 饱和(这是最常被追问的点);mask 处理 padding 或因果约束;W^O 整合多头结果。能写出完整的 attention 代码加分很多。
13. Attention 机制和传统 Seq2Seq 模型有什么区别?
👔面试官:Attention 和传统 RNN Seq2Seq 有什么本质区别?Attention 解决了什么问题?
🙋♂️我:Attention 让 Decoder 能关注 Encoder 不同位置的信息,而 RNN Seq2Seq 只能用最后一个隐状态。
👔面试官:「信息瓶颈」能展开说吗?Attention 是怎么打破这个瓶颈的?
💡 简要回答
传统 RNN Seq2Seq 的根本缺陷是固定大小的语义瓶颈:Encoder 把整个输入序列压缩成一个固定长度的向量(最后一个隐状态),Decoder 的所有生成都只能依赖这个向量。序列越长,压缩损失越严重。
Attention 打破了这个瓶颈:Encoder 保留所有时间步的隐状态,Decoder 在每一步生成时动态计算与所有 Encoder 隐状态的相关性,选择性地聚合当前步最需要的信息。
📝 详细解析
传统 Seq2Seq 的信息瓶颈
输入: [x1, x2, ..., xn] → Encoder → context vector c = hn(固定长度)
↓
Decoder 的所有步骤都用同一个 c一个固定维度的向量 c(比如 512 维)要承载整句话的所有信息,序列越长压缩损失越严重,早期 token 信息在反复传递中逐渐丢失,直接导致长句子翻译效果远差于短句子。
Attention 的改进:动态上下文向量
python
encoder_states = [h1, h2, ..., hn]
for t in range(m):
s_t = decoder_hidden[t] # 当前 Decoder 隐状态
e_tj = score(s_t, h_j) for all j # 与每个 Encoder 状态的相关性
alpha_tj = softmax(e_tj) # 归一化权重
c_t = Σ_j alpha_tj · h_j # 每步的 c_t 不同!动态生成每步的上下文向量 c_t 是动态的。翻译「我」时关注源句主语位置,翻译「爱」时关注谓语位置,这就是「软对齐(Soft Alignment)」。
Transformer Cross-Attention 是同一思想
Transformer 的 Cross-Attention 就是 Q/K/V 版本的 Attention:Decoder 的 Query 来自自身,Encoder 输出提供 Key 和 Value,动态聚合 Encoder 信息。本质与 Bahdanau Attention 一脉相承,形式更统一,计算更高效。
🎯 面试总结
核心是说清楚「信息瓶颈」的具体含义(固定长度向量压缩整个序列),然后说 Attention 是怎么打破它的(动态计算每步的上下文向量)。能用翻译任务的「软对齐」举例,并说出 Transformer Cross-Attention 是同一思想的变体,这道题就很完整了。
14. 请简述 FlashAttention 的原理
👔面试官:FlashAttention 的核心原理是什么?它优化的是什么?
🙋♂️我:FlashAttention 是一种优化注意力计算的方法,减少了显存占用,也加快了速度。
👔面试官:怎么减少的?它改变了注意力的计算量吗?IO 感知是什么意思?
💡 简要回答
FlashAttention 是 IO 感知(IO-Aware)的注意力算法,核心是分块(Tiling)计算 + Online Softmax:把 Q/K/V 切成小块,在 GPU 片上 SRAM 内完成整块注意力计算,避免把巨大的 n×n 注意力矩阵写入读出显存(HBM)。
数学上完全等价,时间复杂度仍是 O(n²·d),但 HBM 访问次数大幅降低,显存从 O(n²) 降到 O(n),实际速度快 2~4 倍。
📝 详细解析
为什么标准注意力慢?Memory-Bound 问题
GPU 存储层级:SRAM(片上,~几十MB,带宽 ~19TB/s)vs HBM(显存,~几十GB,带宽 ~2TB/s)。
标准注意力把 n×n 矩阵反复在 HBM 和 SRAM 之间搬运(计算 QK^T → 写回 HBM → 读出做 softmax → 写回 HBM → 读出乘 V),GPU 大部分时间在「等数据搬运」而不是在计算,这叫 Memory-Bound。
FlashAttention:分块 + Online Softmax
难点在于 softmax 需要看全部 score 才能做归一化。FlashAttention 用 Online Softmax 技巧解决:在线维护每个 block 的最大值 m 和指数和 l,递增更新,不需要物化完整的注意力矩阵:
python
m = -inf # 全局最大值(数值稳定用)
l = 0 # 指数和
O = 0 # 累积输出
for each Q_block, K_block, V_block:
scores = Q_block @ K_block.T / sqrt(d_k)
m_new = max(m, scores.max())
l_new = exp(m - m_new) * l + exp(scores - m_new).sum()
O = exp(m - m_new) * O + exp(scores - m_new) @ V_block
m, l = m_new, l_new
output = O / l # 最终归一化整个过程在 SRAM 内完成,从不把中间矩阵写回 HBM。
效果
- 显存:O(n²) → O(n),n=8192 时节省约 5~10GB
- 速度:减少 HBM 读写次数,实测快 2~4 倍
- FlashAttention-2 进一步优化线程并行策略,速度再提升约 2 倍
🎯 面试总结
FlashAttention 的考点是:它没有改变算法复杂度,优化的是 IO(HBM 读写次数),手段是分块 + Online Softmax。把「Memory-Bound」概念说清楚(GPU 在等数据而不是在算),再说分块怎么解决这个问题,面试官就知道你真正理解了而不是在背结论。
15. KV Cache 是什么?它在推理中起什么作用?
👔面试官:说说 KV Cache 是什么,它怎么加速推理的。
🙋♂️我:KV Cache 是把之前计算过的 Key 和 Value 缓存起来,下次不用重新算了。
👔面试官:为什么只缓存 KV,不缓存 Q?多缓存了这些,显存怎么管理?
💡 简要回答
KV Cache 是在自回归推理时,把每一层 Attention 计算出的 Key 和 Value 向量缓存下来,后续生成新 token 时直接复用历史的 K/V,只需要为新 token 计算 Q,避免对所有历史 token 重复计算 K/V。
不缓存 Q 是因为 Q 只用于当前 token 与 K 做点积,不需要被后续步骤复用;而 K/V 代表历史上下文信息,每步生成都需要用到全部历史 K/V。
📝 详细解析
没有 KV Cache 时的计算浪费
自回归生成时,每生成一个新 token,需要把当前 token 和所有历史 token 拼在一起做注意力:
生成第 1 个词:对 [prompt] 做注意力
生成第 2 个词:对 [prompt + 词1] 做注意力 ← 重算了 prompt 的 K/V
生成第 3 个词:对 [prompt + 词1 + 词2] 做注意力 ← 又重算了前面所有 K/V每步都在重复计算历史 token 的 K/V,计算量随生成长度线性增加。
KV Cache 的机制
python
kv_cache = [] # 每层维护一个 cache
for new_token in generate():
q = compute_Q(new_token) # 只算新 token 的 Q
k_new = compute_K(new_token)
v_new = compute_V(new_token)
kv_cache.append((k_new, v_new)) # 追加到缓存
# 用新 Q 和全部历史 K/V 做注意力
k_all = concat([k for k, v in kv_cache])
v_all = concat([v for k, v in kv_cache])
output = attention(q, k_all, v_all) # 复用历史,避免重算每步生成只需 O(1) 的计算量(只算新 token 的 QKV),而不是 O(n) 的全量重算。
KV Cache 的显存代价
KV Cache 大小 = 2 × num_layers × num_kv_heads × d_head × seq_len × dtype_size对于 LLaMA-2-7B(32 层,32 头,d_head=128,FP16),序列长度 1000 时约需 512MB。序列越长,显存占用越大。
优化方向:GQA(多个 Q 头共享同一组 K/V,减少 KV Cache 大小);PagedAttention(vLLM)(借鉴操作系统分页思想,KV Cache 按需分配内存页,提高显存利用率)。
🎯 面试总结
KV Cache 的本质是「用空间换时间」:缓存历史 K/V 避免重复计算,把每步生成的计算量从 O(n²) 降到近似 O(n)。要说清楚为什么只缓存 KV 不缓存 Q(Q 只在当前步用,不需要复用),以及 KV Cache 的显存代价公式。能补一句 GQA 是为了压缩 KV Cache 大小而设计的,面试官会很满意。
16. GQA(Grouped Query Attention)和 MHA 有什么区别?
👔面试官:GQA 是什么?它和标准的 Multi-Head Attention 有什么区别?为什么要这样设计?
🙋♂️我:GQA 是分组查询注意力,它减少了 KV 头的数量,多个 Q 头共享同一组 KV。
👔面试官:不错,那具体是怎么分组的?和 MQA 有什么区别?对推理速度有什么影响?
💡 简要回答
MHA、GQA、MQA 是三种注意力变体,区别在于 K/V Head 的数量:
- MHA:Q/K/V 头数量相同(h 个),每个 Q 头有专属的 K/V 头
- MQA(Multi-Query Attention):只有 1 组 K/V,所有 Q 头共享
- GQA(Grouped Query Attention):g 组 K/V(1 < g < h),每组 K/V 被 h/g 个 Q 头共享
GQA 是 MQA 和 MHA 的折中:比 MHA 少了大量 KV Cache,比 MQA 有更多的 K/V 表达能力,在质量和效率之间取得平衡。LLaMA-2-70B、LLaMA-3、Qwen 系列均采用 GQA。
📝 详细解析
三种变体的分组示意
MHA (h=8): Q1K1V1, Q2K2V2, Q3K3V3, Q4K4V4, Q5K5V5, Q6K6V6, Q7K7V7, Q8K8V8
GQA (g=2): Q1Q2Q3Q4 共享 K1V1, Q5Q6Q7Q8 共享 K2V2
MQA (g=1): Q1...Q8 全部共享 K1V1KV Cache 大小对比
KV Cache 大小比例:MHA : GQA : MQA = h : g : 1对于 h=32, g=8 的 LLaMA-2-70B,GQA 的 KV Cache 是 MHA 的 1/4,推理时显存大幅减少,可处理更长序列或支持更大 batch size。
对推理速度的影响
减少 KV Cache 不仅节省显存,还提升推理速度:
- KV Cache 读取是 Memory-Bound 操作,KV 越小读取越快
- 更小的 KV Cache 意味着可以支持更大的 batch size,吞吐量更高
实测 GQA 相比 MHA,在长序列场景推理吞吐量可提升 2~3 倍。
🎯 面试总结
要能清楚说出三种变体的区别(MHA 每头独立 KV、MQA 全共享、GQA 分组共享),并解释 GQA 设计动机(在质量和 KV Cache 大小之间折中)。给出 KV Cache 大小正比于 KV 头数的关系,列举 LLaMA-2-70B 等使用 GQA 的实际模型,面试官会认为你对工程实践有足够了解。
17. 简述 GPT 和 BERT 的区别
👔面试官:GPT 和 BERT 的主要区别是什么?为什么一个更适合生成,一个更适合理解?
🙋♂️我:GPT 是生成式的,BERT 是判别式的,GPT 单向看,BERT 双向看。
👔面试官:为什么双向比单向更适合理解任务?预训练目标有什么区别?Fine-tuning 的方式呢?
💡 简要回答
GPT 和 BERT 最本质的区别是注意力方向和预训练目标:
| 维度 | GPT | BERT |
|---|---|---|
| 架构 | Decoder-only(单向,Causal Attention) | Encoder-only(双向,全局 Attention) |
| 预训练目标 | CLM:预测下一个 token | MLM:预测被 mask 的词 |
| 适合任务 | 文本生成、对话、代码生成 | 文本分类、NER、问答(理解类) |
| Fine-tuning | Prompt 形式或自回归生成 | 在 [CLS] 上接分类头 |
📝 详细解析
架构差异
BERT 使用 Encoder-only 架构,每个 token 可以双向地关注序列中所有其他 token。这对理解任务非常有利:判断语义蕴含、分析情感,需要综合「上文和下文」才能作出准确判断。
GPT 使用 Decoder-only 架构,Causal Mask 保证每个 token 只能看到自己和左边的 token。这对生成任务是必须的:自回归生成要求在生成第 i 个 token 时,不能看到第 i+1 个之后还没生成的内容。
预训练目标
BERT - Masked Language Modeling(MLM):随机 mask 掉 15% 的 token,训练模型根据双向上下文预测被 mask 的词。迫使模型学习深层的双向语义关系。
GPT - Causal Language Modeling(CLM):给定前 i 个 token,预测第 i+1 个 token。每个位置都要预测,训练信号非常密集,适合大规模无监督训练,scaling 能力更强。
Fine-tuning 策略的差异
BERT 的 Fine-tuning 非常直接:在 [CLS] token 的输出上接一个任务特定的分类头,微调少量参数就能适配各种下游任务。
GPT 的 Fine-tuning 更依赖 Prompt:把下游任务格式化为「前缀 + 要生成的内容」的形式,以文本续写方式完成任务。GPT-3 之后还探索了 In-Context Learning——不需要更新参数,只靠在 prompt 里给几个示例就能适配新任务。
为什么现在大模型都是 Decoder-only?
GPT 的成功证明 CLM 预训练的 scaling 能力极强——数据越多、模型越大,CLM 目标能持续带来能力提升,而 MLM 在规模增大时提升逐渐趋于平缓。同时,Decoder-only 在推理时自然支持生成任务,理解任务也可以通过 Prompt 设计转化为生成问题来解决。
🎯 面试总结
从三个维度展开:架构(单向 vs 双向)、预训练目标(CLM vs MLM)、应用场景(生成 vs 理解)。能进一步说明为什么 CLM 的 scaling 更强,以及为什么现代大模型都是 Decoder-only,这道题就非常完整了。
18. 讲一下 GPT 系列模型是如何演进的
👔面试官:从 GPT-1 到 GPT-4,讲一下 GPT 系列的演进脉络。
🙋♂️我:GPT-1 最小,GPT-2 大一点,GPT-3 更大,GPT-4 是多模态的……
👔面试官:每一代解决了什么核心问题?技术上有哪些关键创新?不是让你背参数量的。
💡 简要回答
GPT 系列的演进本质是:从「预训练+微调」范式逐步走向「大模型+指令跟随+对齐」,每一代都在验证 Scaling Law 的同时,解决了新的对齐或能力问题。
📝 详细解析
GPT-1(2018):预训练+微调范式奠基
核心贡献:证明了「大规模无监督预训练 + 下游任务微调」的范式有效。在 BookCorpus 上用 CLM 目标预训练,然后针对各个下游任务(分类、蕴含、问答等)做轻量微调,在 9 个 NLP 基准上超越了当时的 SOTA。1.17 亿参数,12 层 Transformer Decoder。
关键洞察:预训练学到的通用语言表示是可以迁移的,不需要为每个任务从头训练。
GPT-2(2019):Zero-shot 惊艳世界
核心贡献:参数量扩大到 15 亿,训练数据扩大到 WebText(40GB 高质量网络文本)。最关键的发现是:足够大的语言模型可以在不经过任何微调的情况下(Zero-shot),通过自然语言的方式完成各种任务。
技术改进:Pre-LN(把 LayerNorm 移到子层前面),训练更稳定;词表扩大到 50257。
GPT-2 最初因为「生成文本质量太好,担心被滥用」而延迟发布,后续证明担心有些多余,但这件事让公众第一次意识到语言模型的能力边界。
GPT-3(2020):Few-shot 彻底改变游戏规则
核心贡献:参数量跳跃到 1750 亿,训练数据 45TB 原始文本(过滤后约 570GB)。证明了大模型的 In-Context Learning 能力:在 prompt 里提供几个示例(Few-shot),模型就能理解任务格式并给出正确答案,不需要任何参数更新。
关键洞察:模型够大之后,「学习如何学习」的能力自然涌现,Few-shot 学习不是训练的,是参数规模带来的涌现能力。
局限:GPT-3 很聪明但不听话——它会续写 prompt 而不是回答问题,生成的内容有时有害,不符合人类偏好。
InstructGPT(2022):对齐的关键一步
核心贡献:在 GPT-3 的基础上引入 RLHF(人类反馈强化学习)。通过 SFT(有监督微调)+ RM(奖励模型训练)+ PPO(近端策略优化),让模型学会「遵循指令」和「符合人类偏好」,而不只是预测下一个词。
只有 1.3B 参数的 InstructGPT 在人类评测中被认为比 175B 的 GPT-3 更有用,证明了对齐训练的价值远大于单纯扩大参数量。
ChatGPT(2022):工程化的对话体验
在 InstructGPT 的对话数据上继续微调,专门优化了多轮对话体验。没有太多技术创新,但工程上打磨得极好,成为了第一个真正出圈的 AI 产品。
GPT-4(2023):多模态 + 能力再跳跃
核心贡献:引入多模态输入(图像理解);通过大量 RLHF 数据和红队测试显著提升了安全性;在各种专业考试(律师资格、医师资格等)上达到人类顶尖水平;引入了更强的推理能力。
GPT-4 的参数量和训练细节 OpenAI 官方未透露,据推测采用了 MoE(混合专家)架构。
🎯 面试总结
GPT 系列演进有清晰的主线:GPT-1 证明预训练迁移可行,GPT-2 证明 Zero-shot 涌现,GPT-3 证明 Few-shot In-Context Learning,InstructGPT 解决了「聪明但不听话」的对齐问题,ChatGPT 做了工程化打磨,GPT-4 实现多模态和能力再跃升。每一代都有其核心命题,不要背参数量,要讲清楚「解决了什么问题」。
19. 为什么现在的大模型大多是 Decoder-only 的架构?
👔面试官:为什么现在主流大模型都选择 Decoder-only 架构,而不是 Encoder-Decoder 或 Encoder-only?
🙋♂️我:因为 Decoder-only 适合生成任务,现在大家主要用来做生成,所以选这个。
👔面试官:只是因为做生成吗?Encoder-Decoder 也能做生成(比如 T5),为什么不用?从预训练效率的角度怎么解释?
💡 简要回答
Decoder-only 的主导地位来自三个核心优势:
- 预训练效率更高:CLM 目标对每个 token 都产生训练信号(n 个位置预测 n 次),MLM 只对被 mask 的 15% token 产生信号,训练信号密度相差约 7 倍。
- 统一框架解决所有任务:任何 NLP 任务都可以转化为「文本补全」的形式,无需设计不同的输出头,大一统更简洁。
- KV Cache 推理高效:纯自回归结构天然支持 KV Cache 复用,推理时延低。
📝 详细解析
预训练效率:CLM 碾压 MLM
Encoder-only(BERT)用 MLM:随机 mask 15% 的 token,只对这 15% 计算损失。对于一个 512 token 的序列,只有约 77 个位置产生梯度。
Decoder-only(GPT)用 CLM:每个 token 都要预测下一个,512 个 token 产生 512 个训练信号。在相同的计算量下,CLM 学到的信息密度远高于 MLM。
这个差异在小规模时不明显,但当模型和数据规模都很大时,CLM 的效率优势被极大放大,Scaling Law 在 CLM 上表现更好。
一个框架统一所有任务
Encoder-Decoder(T5、BART)需要 Encoder 和 Decoder 分别处理输入和输出,不同任务需要不同的适配方式。
Decoder-only 的哲学是:一切皆文本续写。分类?把类别写成文本,问模型续写。翻译?写「中文:xxx,英文:」,让模型续写。数学题?写题目,让模型续写解题过程。这种统一性带来了极大的灵活性,也是 Prompt Engineering 能成为一个领域的根本原因。
Encoder-Decoder 不是一无是处
Encoder-Decoder 结构(T5、FLAN-T5)在参数量相同的情况下,在翻译、摘要等任务上有时表现更好,因为 Encoder 的双向注意力能更完整地理解输入。但随着 Decoder-only 模型参数量越来越大,这个优势逐渐被参数规模的差距抹平。
Google 的 Gemini 和一些研究(如 UL2)尝试融合两种架构的优点,但工程复杂度更高,并未成为主流。
🎯 面试总结
不要只说「适合生成任务」,要从三个角度解释:预训练效率(CLM 的信号密度是 MLM 的 7 倍,Scaling Law 更好)、统一框架(任何任务都可以转化为文本续写)、推理效率(KV Cache 天然适配自回归结构)。能补一句 Encoder-Decoder 在小参数量时有优势但随规模扩大优势被抹平,说明你对架构选择的权衡有深入理解。
20. Prefix LM 和 Causal LM 区别是什么?
👔面试官:Prefix LM 和 Causal LM 有什么区别?分别适用什么场景?
🙋♂️我:Causal LM 就是单向的,Prefix LM 是……让前缀部分可以双向看?
👔面试官:对,那为什么要这样设计?这两种 LM 在注意力掩码上有什么具体区别?
💡 简要回答
- Causal LM(因果语言模型):所有 token 只能看到自己和左边的 token,用下三角 Causal Mask。GPT 系列是标准的 Causal LM。
- Prefix LM(前缀语言模型):输入的「前缀」部分(如问题、prompt)内部使用双向注意力,输出部分使用单向 Causal Attention。GLM、T5 等采用此方式。
设计动机:前缀部分是已知的完整输入,让它双向看能更充分地理解上下文;输出部分是自回归生成,必须单向,不能看未来。
📝 详细解析
注意力掩码的具体区别
以 [前缀: "今天天气"][生成: "晴"] 为例:
Causal LM(全下三角掩码):
今 天 天 气 晴
今: [✓ ✗ ✗ ✗ ✗]
天(1): [✓ ✓ ✗ ✗ ✗]
天(2): [✓ ✓ ✓ ✗ ✗]
气: [✓ ✓ ✓ ✓ ✗]
晴: [✓ ✓ ✓ ✓ ✓]Prefix LM(前缀部分双向,生成部分单向):
今 天 天 气 | 晴
今: [✓ ✓ ✓ ✓ | ✗] ← 前缀内双向
天(1): [✓ ✓ ✓ ✓ | ✗]
天(2): [✓ ✓ ✓ ✓ | ✗]
气: [✓ ✓ ✓ ✓ | ✗]
晴: [✓ ✓ ✓ ✓ | ✓] ← 生成部分单向典型应用
Causal LM 适合:对话、续写、任意长度的开放域生成,前缀和输出的边界不固定。
Prefix LM 适合:输入-输出结构明确的任务(翻译、摘要、问答),前缀(输入)是完整的,希望对输入做充分的双向理解。
ChatGLM 系列采用 Prefix LM 的变体:用特殊 token 分隔前缀和生成部分,前缀内部全注意力,生成部分因果注意力。
🎯 面试总结
核心差别是注意力掩码:Causal LM 全下三角,Prefix LM 前缀部分全注意力 + 生成部分下三角。设计动机是:前缀是完整已知输入,双向注意力理解更充分;生成部分自回归,必须单向。能画出注意力掩码矩阵来解释,会非常直观清晰。
21. 什么情况用 BERT 模型,什么情况用 LLaMA、ChatGLM 类大模型,怎么选?
👔面试官:实际工程里,什么情况下选 BERT 类模型,什么情况下选 LLaMA 这类大模型?
🙋♂️我:理解任务用 BERT,生成任务用大模型。
👔面试官:那文本分类用 BERT?RAG 里的 Embedding 呢?LLaMA 做分类就一定不如 BERT 吗?
💡 简要回答
选型核心看任务性质、资源预算、推理延迟三个维度:
| 场景 | 推荐 | 原因 |
|---|---|---|
| 文本分类、NER、句子相似度 | BERT 类 | 参数小、推理快、微调成本低、双向理解更准确 |
| Embedding / 语义检索 | 专用 Embedding 模型(BGE、E5) | 专门为相似度训练,效果更好 |
| 开放域对话、内容生成 | LLaMA / ChatGLM | 生成能力强,指令跟随好 |
| 复杂推理、多步任务 | 大模型 | 小模型推理能力不够 |
| 资源有限的边缘部署 | BERT 类或量化小模型 | 大模型部署成本过高 |
📝 详细解析
BERT 类模型的优势场景
BERT 类(BERT、RoBERTa、ELECTRA)的核心优势是参数少、推理快、双向理解:
- 分类任务:情感分析、文本分类、NLI(自然语言推理),在有大量标注数据的情况下,BERT 微调后的效果往往不输百亿参数的大模型,但推理速度快 10~100 倍,成本极低。
- 序列标注:NER、分词、词性标注,需要对每个 token 做独立判断,BERT 的 token 级双向表示天然适合。
- 句子相似度(需注意):BERT 本身不适合直接做 Embedding,需要用 Sentence-BERT(对 BERT 做了对比学习微调的版本)或专用的 Embedding 模型(BGE、E5、GTE)。
大模型的必要场景
- 指令跟随:需要模型按照自然语言指令灵活完成各种任务,BERT 无法做到。
- 长文本生成:写报告、写代码、写邮件,BERT 不能生成。
- 多步推理:数学题、逻辑推理、代码调试,需要链式思考,小模型推理能力不足。
- Few-shot / Zero-shot:新任务没有标注数据,靠 Prompt 就能解决,BERT 微调必须有标注数据。
边界情况:大模型也能做分类
大模型通过 Prompt 可以做零样本分类,在标注数据极少(5~10 条)的情况下效果可能超过 BERT 微调。但当标注数据充足(1000+ 条)时,微调后的 BERT 类小模型通常在精度、速度、成本上都更有优势。
🎯 面试总结
不要简单地说「理解用 BERT,生成用大模型」,面试官会追问边界情况。要从三个维度来选型:任务性质(分类/生成/理解)、数据量(有大量标注数据时小模型更有优势)、资源约束(延迟要求高、成本敏感时优先小模型)。同时要知道 Embedding 任务有专用模型(BGE、E5),不要直接用裸 BERT 做向量检索。
22. BERT 非线性的来源在哪里?
👔面试官:BERT(以及 Transformer)的非线性来自哪里?自注意力本身是非线性的吗?
🙋♂️我:来自激活函数,就是那个 ReLU 或 GELU。
👔面试官:只有激活函数?softmax 是不是非线性的?LayerNorm 是不是非线性的?
💡 简要回答
Transformer 中的非线性来源有三处:
- FFN 中的激活函数(GELU/ReLU):最主要的非线性来源,引入了真正的特征非线性变换
- 注意力中的 Softmax:对注意力分数的归一化操作,是非线性的(指数函数)
- LayerNorm:对输入做归一化,其中除以标准差的操作是非线性的
📝 详细解析
FFN 中的激活函数:主要非线性来源
python
FFN(x) = GELU(x·W1 + b1)·W2 + b2GELU(Gaussian Error Linear Unit)是 BERT 使用的激活函数,比 ReLU 更平滑:
GELU(x) = x · Φ(x) # Φ 是标准正态分布的累积分布函数这个操作是非线性的,让模型能学习复杂的特征组合,是整个 Transformer 表达能力的核心来源之一。没有 FFN 的激活函数,整个 Transformer 就只是线性变换的堆叠,表达能力极为有限。
Softmax 的非线性
注意力计算中的 Softmax:
softmax(x_i) = exp(x_i) / Σ_j exp(x_j)指数函数是非线性的,且 softmax 还引入了归一化(分母依赖所有位置),这是一种全局的非线性交互。
LayerNorm 的非线性
LN(x) = γ · (x - μ) / σ + βσ(标准差)是 x 的非线性函数(涉及平方和开方),因此 LN 整体是非线性的。虽然 LayerNorm 的主要作用是稳定训练,但它确实也引入了一定程度的非线性。
为什么自注意力本身也有非线性?
即使不算 Softmax,QK^T 之后的归一化(除以 √d_k)是线性的,但 Q、K、V 本身是输入 x 的线性投影,乘以归一化的注意力权重再求和这个操作——由于注意力权重是依赖输入计算出来的(通过 Softmax),整体上是非线性的。这种「输入决定权重,权重再作用于输入」的自引用结构,引入了高阶的非线性交互。
🎯 面试总结
这道题不要只答激活函数。要说出三个来源:FFN 里的 GELU/ReLU 是主要非线性(让模型能学习复杂特征组合);Softmax 是指数函数,是非线性的;LayerNorm 的标准差计算涉及平方和开方,也是非线性的。能补一句「自注意力机制中,权重由输入动态决定这件事本身就引入了高阶非线性」,说明你理解得更深入。
23. 为什么 BERT 选择 mask 掉 15% 这个比例的词?
👔面试官:BERT 为什么选 15% 这个 mask 比例,而不是 30% 或者 5%?
🙋♂️我:这是实验调出来的最优比例,太高或太低效果都不好。
👔面试官:实验发现有道理,但能说说背后的直觉吗?太高和太低各有什么问题?
💡 简要回答
15% 是在信号密度和上下文完整性之间的权衡:
- 比例太低(如 5%):每个 batch 里产生的训练信号太少(只有 5% 的 token 有损失),训练效率很低,需要更多的步数才能收敛。
- 比例太高(如 30~40%):被 mask 掉的内容太多,剩余的上下文不足以推断被 mask 词的含义,任务变得不可能完成或变成了猜词游戏,模型学不到真正的语义关系。
15% 是经验上发现的平衡点:信号足够密集,同时保留足够的上下文让任务可解。
📝 详细解析
BERT MLM 的 mask 规则细节
BERT 的 mask 规则不是简单地把 15% 的 token 换成 [MASK],而是:
选中 15% 的 token 后,对这些 token:
- 80% 概率替换为 [MASK] token
- 10% 概率替换为词表中的随机 token
- 10% 概率保持原词不变为什么不全部替换成 [MASK]?
因为推理(fine-tuning)时不存在 [MASK] token,训练时如果全部替换,模型就专门学会了「看到 [MASK] 才预测」,而不是学习通用的上下文理解能力。加入 10% 随机词和 10% 原词,强迫模型对每个 token 都建立上下文表示,而不只是在看到 [MASK] 时才认真预测,缓解了预训练和微调之间的分布偏移。
与其他 Mask 策略的对比
后来的模型对 MLM 做了不少改进:
- ELECTRA:不用 Mask,而是用一个小的 Generator 模型生成替换词,训练一个 Discriminator 判断每个 token 是否被替换。每个 token 都产生训练信号,效率远高于 MLM,且没有 [MASK] token 引入的预训练/微调不一致问题。
- SpanBERT:不是随机 mask 单个 token,而是 mask 一段连续的 span(2~10 个词),这样模型需要理解更大范围的语义才能预测被 mask 的 span。
🎯 面试总结
15% 是信号密度和上下文完整性之间的经验平衡点:太低训练信号不足,太高上下文残缺任务不可解。还要说出 BERT 的 80/10/10 规则(不全替换为 [MASK] 是为了缓解预训练/微调的分布偏移),以及 ELECTRA 是改进方向(每个 token 都产生训练信号,效率更高)。
24. 讲一下生成式语言模型的工作机理
👔面试官:生成式语言模型(如 GPT)是怎么生成文本的?从头到尾讲一下工作机理。
🙋♂️我:它就是不断预测下一个词,一个一个地输出,直到结束。
👔面试官:为什么是「不断预测下一个词」?这个预测过程怎么做到的?温度、top-p 这些解码策略是怎么影响的?
💡 简要回答
生成式语言模型的工作机理是自回归(Autoregressive):给定当前所有已知 token,模型预测下一个 token 的概率分布,从中采样一个 token 追加到序列末尾,然后把整个更新后的序列再输入模型,预测下一个,如此循环直到生成终止符或达到最大长度。
核心是条件概率建模:P(x_t | x_1, x_2, ..., x_{t-1}),通过 CLM 预训练,模型学会了对所有可能的 token 序列建立条件概率分布。
📝 详细解析
自回归生成的完整流程
python
tokens = tokenize(prompt) # 把文本变成 token id 序列
while not done:
# 1. 把当前序列送入模型,得到下一个 token 的 logits
logits = model(tokens) # 形状 [vocab_size]
# 2. 把 logits 转成概率分布
probs = softmax(logits / temperature)
# 3. 可选:过滤(top-k / top-p)
filtered_probs = top_p_filter(probs, p=0.9)
# 4. 从分布中采样
next_token = sample(filtered_probs)
# 5. 追加并判断是否结束
tokens.append(next_token)
if next_token == EOS_TOKEN or len(tokens) >= max_length:
break解码策略:如何从概率分布里采样
温度(Temperature):控制概率分布的平滑程度。
probs = softmax(logits / T)- T < 1(如 0.5):分布更集中(尖锐),高概率的词被更大幅度地突出,输出更确定性、更保守
- T > 1(如 1.5):分布更均匀,低概率词也有机会被选中,输出更多样、更有创意,但也更容易胡说八道
- T → 0:退化为贪婪解码(总选最高概率词)
Top-k 采样:只保留概率最高的 k 个候选词,在这 k 个里采样,避免低概率词被选中。问题是固定 k 值,当概率分布平坦时 k 可能不够,分布集中时 k 可能太多。
Top-p 采样(Nucleus Sampling):动态选择累积概率达到 p(如 0.9)的最小候选集,在这个集合里采样。比 top-k 更自适应,是实践中最常用的采样策略。
Beam Search:维护 B 个候选序列(beam),每步对每个候选扩展,保留总概率最高的 B 个,最终选得分最高的序列。不随机,结果确定性强,适合机器翻译等需要高精度的任务,但容易生成重复、保守的文本。
🎯 面试总结
答这道题要说清楚三件事:自回归生成的本质(每步条件概率预测 + 采样 + 追加,循环直到结束);CLM 预训练是怎么让模型学会这个能力的(预测下一个词的目标让模型学到了整个语言的条件概率分布);解码策略(温度控制确定性 vs 多样性,top-p 是最常用的采样方法,Beam Search 适合需要精确输出的场景)。
25. LLM 中的因果语言建模与掩码语言建模有什么区别?
👔面试官:CLM 和 MLM 有什么区别?各自的优缺点是什么?
🙋♂️我:CLM 就是 GPT 那种单向预测下一个词,MLM 就是 BERT 那种 mask 掉词来预测。
👔面试官:训练信号密度有什么区别?为什么 CLM 的 Scaling 表现更好?
💡 简要回答
| 维度 | CLM(因果语言建模) | MLM(掩码语言建模) |
|---|---|---|
| 目标 | 预测下一个 token | 预测被 mask 的 token |
| 注意力方向 | 单向(只看左侧) | 双向(看上下文) |
| 训练信号密度 | 每个 token 都产生损失(100%) | 只有 15% 的 mask token 产生损失 |
| 适合任务 | 生成类(对话、续写、代码) | 理解类(分类、NER、问答) |
| Scaling 能力 | 强,随模型和数据规模持续提升 | 弱,规模增大后提升趋于平缓 |
📝 详细解析
训练信号密度的差异
这是两者最本质的效率差异。
CLM 对序列中的每个 token 都计算损失:
L_CLM = -Σ_{t=1}^{n} log P(x_t | x_1, ..., x_{t-1})n 个 token 产生 n 个训练信号。
MLM 只对被 mask 的 token(约 15%)计算损失:
L_MLM = -Σ_{i ∈ masked} log P(x_i | x_{\masked})相同的序列长度,MLM 的训练信号数量是 CLM 的 15%,信号密度相差约 7 倍。在相同的计算量下,CLM 能从数据中提取更多信息。
为什么 CLM 的 Scaling 更好?
训练信号密度高意味着同等算力下 CLM 能学更多。当模型参数量增大、数据规模增大时,CLM 的 loss 能持续下降,能力持续提升,Scaling Law 曲线更陡峭。
MLM 还有一个更本质的问题:它的目标是「根据上下文预测空缺」,这个任务有天花板——当模型足够强后,遮盖 15% 的词对它来说太简单了,继续加大规模也很难进一步提升能力。
MLM 的优势:双向理解
MLM 的双向注意力让每个 token 的表示都包含了完整的上下文信息(左右两侧都看),这对需要深度理解的任务(NLI、问答、关系抽取)很有价值。CLM 的单向注意力在理解类任务上有结构性劣势(最后一个词的表示最好,中间词只能看到前缀)。
不过随着大模型规模的增大,这个劣势在很大程度上被参数量弥补了——GPT-4 在 MMLU、AGIEval 等理解类基准上的表现不输专门为理解设计的模型。
🎯 面试总结
这道题的核心考点是训练信号密度:CLM 是 100% 的 token 产生损失,MLM 只有 15%,相差约 7 倍,这是 CLM scaling 更好的根本原因。能再补一句 MLM 的优势(双向理解)和它为什么随着规模增大优势消失(任务天花板,大模型靠参数量弥补了单向的结构劣势),面试官会觉得你理解得相当透彻。
26. 什么是位置编码?绝对位置编码和相对位置编码有什么区别?
👔面试官:说说绝对位置编码和相对位置编码的区别,各自有什么优缺点?
🙋♂️我:绝对位置编码就是每个位置加一个固定的向量,相对位置编码是考虑两个词之间的距离。
👔面试官:具体怎么做的?BERT 用的是哪种?LLaMA 用的是哪种?长度外推时谁更好?
💡 简要回答
- 绝对位置编码:给每个位置分配一个固定的编码向量,直接加到 token embedding 上。位置 i 的编码只取决于 i 本身,与其他位置无关。BERT(可学习绝对编码)和原始 Transformer(正弦绝对编码)都是此类。
- 相对位置编码:在注意力计算中直接建模两个 token 之间的相对距离(i-j),而不是各自的绝对位置。RoPE、ALiBi、T5 的 Relative Bias 都是此类。
相对位置编码天然具有长度外推能力——训练时没见过的序列长度,在推理时仍然能正确感知相对位置关系;绝对位置编码在超过训练长度时会遇到 out-of-distribution 问题。
📝 详细解析
绝对位置编码的两种形式
正弦绝对编码(原始 Transformer):
PE(pos, 2i) = sin(pos / 10000^(2i/d_model))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))不需要学习,可以外推到训练时未见过的长度(理论上),但实践中长距离外推效果较差。
可学习绝对编码(BERT):
python
# BERT 直接用一个可学习的 Embedding 层
self.position_embeddings = nn.Embedding(max_position, hidden_size)更灵活,实践中效果更好,但严格限制了序列最大长度(BERT 最大 512)。
相对位置编码:建模「距离」而不是「位置」
绝对位置编码的本质问题:模型需要从两个绝对位置(i, j)中推导相对距离(i-j),这需要额外的学习成本。而且「距离为 3 的两个词的交互模式」,在训练时可能对应位置(2, 5),也可能对应(100, 103),模型看到的是不同的绝对位置,却要学到相同的相对位置特征,存在泛化困难。
相对位置编码直接把 i-j 编码进注意力计算,让模型自然地感知「你离我有多远」,而不是「你在第几号位置」。
RoPE(旋转位置编码)原理简述
RoPE 是目前最主流的相对位置编码方案(LLaMA、Qwen、ChatGLM 等均采用)。它的核心思想是:把位置 m 处的 Query 向量旋转 mθ 角度,把位置 n 处的 Key 向量旋转 nθ 角度,那么 Q_m · K_n 的结果中自然含有 (m-n)θ 的相对旋转角,实现了相对位置的内积表示:
q_m · k_n = f(q, m) · f(k, n) = g(q, k, m-n)其中 g 只依赖 q, k 和相对距离 m-n,不依赖绝对位置。
长度外推:相对位置编码的优势
绝对位置编码(尤其可学习的)在超出训练长度时,模型遇到了训练时从未见过的位置 embedding,性能急剧下降。
相对位置编码在外推时,新的位置关系仍然通过相对距离表示,模型对「距离为 k 的两个 token 的关系」已经学过了,只要 k 不超过训练时的最大相对距离,外推就没有问题。
不过即使是 RoPE,极长序列(超出训练长度很多)时精度也会下降,这催生了 YaRN、LongRoPE 等扩展上下文长度的方法。
🎯 面试总结
这道题要点出两个核心区别:绝对编码只看自己的位置,相对编码看两个 token 的距离差;绝对编码长度外推差(超过训练长度就 OOD),相对编码外推更好。能简述 RoPE 的思想(把位置编码成 Q/K 的旋转角,使得 Q·K 内积自然包含相对距离信息),并且知道 LLaMA 用的是 RoPE,这道题就很完整了。
27. 旋转位置编码 RoPE 的思路是什么?有什么优点?
👔面试官:RoPE 的核心思路是什么?它相比绝对位置编码有什么优势?
🙋♂️我:RoPE 是旋转位置编码,把位置信息用旋转矩阵编码进去,让模型能感知相对位置。
👔面试官:为什么要用旋转?「旋转」如何实现相对位置感知?数学上怎么推导出来的?
💡 简要回答
RoPE 的核心思路是:对位置 m 的 Query 向量和位置 n 的 Key 向量分别施加与位置相关的旋转变换,使得二者的内积只依赖于相对距离 m-n,而与绝对位置无关:
RoPE: q_m · k_n = g(x_q, x_k, m-n)旋转的几何直觉:在二维平面里,把两个向量分别旋转 mθ 和 nθ,它们的点积里包含角度差 (m-n)θ,这个角度差只依赖于相对距离,不依赖于绝对位置。
📝 详细解析
从二维旋转开始理解
对于二维向量 q = (q_1, q_2) 和位置 m,旋转变换定义为:
R(m) · q = [q_1·cos(mθ) - q_2·sin(mθ)]
[q_1·sin(mθ) + q_2·cos(mθ)]这就是把向量 q 绕原点旋转 mθ 角。
两个经过旋转的向量的内积:
(R(m)·q)^T · (R(n)·k)
= q^T · R(m)^T · R(n) · k
= q^T · R(n-m) · k因为旋转矩阵满足 R(a)^T = R(-a),以及 R(a)·R(b) = R(a+b)。
关键结论:内积的结果只与相对旋转角 (n-m)θ 有关,即只与相对位置差 n-m 有关!
扩展到高维
对于 d 维(d 通常是偶数)的 Query/Key 向量,RoPE 把它拆分成 d/2 个二维子向量,每对用不同频率的旋转角:
python
# 对于向量 x 的第 2i, 2i+1 维,用旋转角 θ_i = 1/10000^(2i/d)
x_rotated[2i] = x[2i] * cos(m * θ_i) - x[2i+1] * sin(m * θ_i)
x_rotated[2i+1] = x[2i] * sin(m * θ_i) + x[2i+1] * cos(m * θ_i)不同维度对应不同的旋转频率,类似原始 Transformer 的正弦编码用不同频率,但这里是作用在 Q/K 向量上,而不是直接加到 token embedding 上。
RoPE 的五大优点
- 相对位置感知:内积自然包含相对位置信息,不需要额外学习
- 不修改 Value:只作用于 Q 和 K,V 不受影响,KV Cache 更友好
- 长度外推能力:相对位置编码天然支持比训练长度更长的序列
- 无额外参数:没有引入额外的可学习参数
- 兼容 FlashAttention:可以与 FlashAttention 无缝配合,不影响高效注意力实现
RoPE 的局限与改进
RoPE 在大幅超过训练长度时(比如训练在 4K,推理时用 32K),性能会明显下降。针对这个问题的改进方案包括:
- YaRN(Yet Another RoPE extensioN):重新缩放旋转角的频率,使模型能处理更长的序列
- LongRoPE:动态调整不同维度的旋转频率,实现更好的长度外推
🎯 面试总结
RoPE 的核心是「旋转后的内积只含相对旋转角」这个性质。面试时要说清楚两件事:数学直觉(对 Q 旋转 mθ,对 K 旋转 nθ,内积中的绝对位置项消掉,只剩 (m-n)θ);以及五个优点(相对位置感知、不改变 V、长度外推、无额外参数、FlashAttention 友好)。能补一句 YaRN 是针对长度外推问题的改进,面试官会知道你跟进了前沿。
28. 什么是长度外推问题?有哪些解决方法?
👔面试官:什么是长度外推问题?有哪些常见的解决方法?
🙋♂️我:就是模型训练时用的序列比推理时短,推理时超出了训练长度,效果变差。
👔面试官:为什么会变差?具体问题出在哪里?都有哪些解决方案?
💡 简要回答
长度外推问题:模型在训练时只见过长度为 L 的序列,在推理时处理更长(L' > L)的序列时,性能显著下降的现象。
问题根源有两个:
- 位置编码 OOD:绝对位置编码在超出 L 后遇到了训练时从未见过的位置索引
- 注意力分布偏移:即使用 RoPE,超长序列中某些注意力 score 的分布与训练时不同,模型的注意力权重出现异常(过于集中或发散)
📝 详细解析
问题的根源
对于绝对位置编码(如 BERT 的可学习 PE),训练时学到了位置 1~512 的编码,推理时遇到位置 513、514...,这些位置的 embedding 从未被优化,完全是随机初始值,自然性能下降。
对于 RoPE,即使理论上支持长度外推,在超出训练长度很多时,不同频率的旋转角积累到了训练时从未见过的范围,注意力的数值分布出现偏移,实际性能仍然下降。
解决方案一览
插值(Position Interpolation):把超出范围的位置 m 映射到训练范围内,比如把位置 m 缩放为 m * L / L',用原来的编码覆盖新的更长范围。简单有效,但轻微损失短距离精度。
YaRN(Yet Another RoPE extensioN):对 RoPE 的旋转频率进行分区域缩放——高频维度(短距离敏感)保持不变,低频维度(长距离感知)进行插值,取得短距离和长距离的平衡。Mistral、LLaMA 扩展上下文版本都用了 YaRN。
ALiBi(Attention with Linear Biases):完全避开 RoPE 的外推问题,直接在注意力 score 上加一个线性的位置惩罚项(距离越远惩罚越大),不需要学习位置编码,天然支持外推。MPT 模型使用 ALiBi。
滑动窗口注意力(Sliding Window Attention):每个 token 只关注固定大小的局部窗口,不进行全局注意力,从根本上避开了超长序列的问题。Mistral 使用了滑动窗口 + 全局注意力的混合方案。
数据层面:继续训练(Continue Training):在长序列数据上继续预训练,让模型直接学会处理长序列。LLaMA-2 Long 就是这样做的。
实际工程中的选择
目前主流选择是 RoPE + 长序列继续训练 + YaRN/LongRoPE 等频率调整方法,组合起来能把模型的有效上下文窗口从 4K 扩展到 128K 甚至更长。
🎯 面试总结
答这道题先说清楚问题根源(位置编码 OOD,或 RoPE 在超长时数值分布偏移),再列举四个解决方案:插值(压缩位置范围进训练区间)、YaRN(分频率区间精细调整)、ALiBi(换一种不依赖绝对位置的编码)、滑动窗口(从根本上限制注意力范围)。能再说一句「实际工程中多种方案组合」,体现你有实践视角。
29. 推导一下旋转位置编码 RoPE
👔面试官:能手推一下 RoPE 的核心推导过程吗?为什么旋转能实现相对位置编码?
💡 简要回答
RoPE 的推导从「寻找一种位置编码 f,使得 f(q,m)·f(k,n) 只依赖 q、k 和 m-n」出发,证明二维旋转矩阵正好满足这个性质,然后推广到高维。
📝 详细解析
目标设定
我们希望找到一个编码函数 f,满足:
<f(q, m), f(k, n)> = g(q, k, m-n)即内积只依赖相对位置 m-n,而不依赖绝对位置 m 和 n。
二维情况下的推导
在复数域里,把二维向量 (q_1, q_2) 写成复数 q = q_1 + i·q_2,把位置 m 处的旋转定义为:
f(q, m) = q · e^{imθ} = (q_1 + i·q_2)(cos(mθ) + i·sin(mθ))展开:
f(q, m) = [q_1·cos(mθ) - q_2·sin(mθ)] + i·[q_1·sin(mθ) + q_2·cos(mθ)]计算两个位置的内积(复数内积取实部):
Re[f(q,m) · conj(f(k,n))]
= Re[q·e^{imθ} · conj(k·e^{inθ})]
= Re[q · conj(k) · e^{i(m-n)θ}]结果只依赖于 q·conj(k) 和 (m-n)θ,即只依赖 q、k 和相对距离 m-n!目标达成。
推广到高维
对于 d 维向量(d 为偶数),把它拆成 d/2 对二维子向量,每对用不同频率 θ_i = 1/10000^(2i/d) 做旋转:
RoPE(x, m) = R_m · x
其中 R_m = diag(
[cos(mθ_1), -sin(mθ_1)],
[sin(mθ_1), cos(mθ_1)],
[cos(mθ_2), -sin(mθ_2)],
[sin(mθ_2), cos(mθ_2)],
...
) # 形状 d×d 的块对角矩阵实际实现的高效写法
不需要真的构造旋转矩阵,可以用向量逐元素操作高效实现:
python
def apply_rope(x, cos, sin):
# x: [batch, seq_len, n_heads, head_dim]
# cos, sin: [seq_len, head_dim/2]
x1 = x[..., ::2] # 偶数维度
x2 = x[..., 1::2] # 奇数维度
rotated_x1 = x1 * cos - x2 * sin
rotated_x2 = x1 * sin + x2 * cos
return torch.stack([rotated_x1, rotated_x2], dim=-1).flatten(-2)🎯 面试总结
RoPE 推导的核心步骤:设目标(内积只含 m-n)→ 在复数域构造旋转 e^{imθ} → 验证旋转后内积确实只含相对旋转角 (m-n)θ → 推广到高维(d/2 对独立的二维旋转)。能写出这个推导流程,加上实际实现的逐元素操作代码,面试官会印象深刻。
30. RoPE 被哪些主流 LLM 应用?
👔面试官:哪些主流大模型用了 RoPE?它们各自有没有对 RoPE 做改动?
💡 简要回答
RoPE 是目前最主流的位置编码方案,几乎所有主流开源 LLM 都采用了它(或其变体):
| 模型系列 | 位置编码 | 备注 |
|---|---|---|
| LLaMA / LLaMA-2 / LLaMA-3 | RoPE | 标准 RoPE,LLaMA-3 扩展到 128K 上下文 |
| Qwen / Qwen2 / Qwen2.5 | RoPE + YaRN | 支持超长上下文 |
| ChatGLM / GLM-4 | RoPE | ChatGLM 系列标配 |
| DeepSeek | RoPE + YaRN | DeepSeek-V2 还引入了 MLA |
| Mistral / Mixtral | RoPE + 滑动窗口 | 混合长短注意力 |
| Phi-3 | RoPE | 微软 Phi 系列 |
BERT 系列(BERT、RoBERTa)仍用可学习绝对位置编码,主要用于理解任务而非生成,上下文窗口固定为 512。
📝 详细解析
LLaMA 系列的 RoPE 应用
LLaMA-1/2 使用标准 RoPE,θ_i = 10000^(-2i/d),训练上下文为 4K(LLaMA-1)和 4K/8K(LLaMA-2)。
LLaMA-3 把 θ_base 从 10000 调整到 500000,提高了高频维度对长序列的适应性,训练上下文扩展到 8K,通过 continue training 进一步支持 128K(LLaMA-3 Long)。
Qwen2 的 RoPE 改进
Qwen2 系列在 RoPE 基础上加入了 YaRN 频率调整,并在大量长文本(高质量中英文)上进行了 continue pretraining,最终支持 128K 上下文(Qwen2-72B)。
DeepSeek-V2 的 MLA:KV Cache 压缩的新路
DeepSeek-V2 引入了 MLA(Multi-head Latent Attention),通过低秩分解把 KV 压缩到一个低维的隐变量(latent vector),再用解压缩矩阵恢复,显著减少了 KV Cache 的大小,同时还能结合 RoPE 保留位置信息。
🎯 面试总结
这道题主要考察你对主流模型的了解。核心结论是:RoPE 已经成为 Decoder-only 大模型的标配位置编码,BERT 系列因为做理解任务、上下文窗口固定,还在用可学习绝对编码。能补充一句「各家模型在 RoPE 基础上做了 θ_base 调整或 YaRN 等改进来支持更长的上下文窗口」,说明你对前沿发展有持续关注。
31. Byte-Pair Encoding(BPE)如何构建词典?
👔面试官:BPE 算法是怎么构建词表的?讲一下完整流程。
🙋♂️我:BPE 就是把频率高的字符对合并成一个新的 token,反复合并直到词表大小满足要求。
👔面试官:初始的词表是什么?合并时按什么标准判断「频率高」?合并之后原来的词还在吗?
💡 简要回答
BPE(Byte-Pair Encoding)的核心流程:
- 初始化:把所有单词拆成字符级别(加上
</w>词尾标记),构成初始词表 - 统计:对训练语料中所有相邻 token 对计算出现频率
- 合并:把频率最高的 token 对合并成一个新 token,加入词表
- 迭代:重复步骤 2-3,直到词表大小达到预设目标
- 应用:推理时用学到的合并规则(merge rules)对新文本做分词
📝 详细解析
具体示例
假设训练语料中有词:low×5,lower×2,newest×6,widest×3。初始化时拆成字符(加词尾标记):
l o w </w> : 5
l o w e r </w> : 2
n e w e s t </w> : 6
w i d e s t </w> : 3第一轮统计频率,找到最高频的相邻 token 对(假设是 e s,出现 6+3=9 次),合并:
合并规则 1:(e, s) → es
l o w </w> : 5
l o w e r </w> : 2
n e w es t </w> : 6
w i d es t </w> : 3第二轮,找到 es t(6+3=9 次),合并为 est,以此类推……
最终得到一组有序的合并规则,推理时按照这组规则对新词进行分词。
BPE 的优点
有效处理未登录词(OOV):哪怕遇到训练时没见过的词,也可以把它拆成更小的已知 token 来处理,最坏情况退化到字符级。
词表大小可控:通过设定合并次数(即目标词表大小),平衡词表大小与分词粒度。
跨语言友好:GPT 系列用 Byte-level BPE(BBE),在字节级别而非字符级别初始化,彻底消除了 OOV 问题,任何 Unicode 字符都能通过 256 个字节 token 表示。
BPE vs 传统分词
| 方式 | 优点 | 缺点 |
|---|---|---|
| 词级别分词 | 语义完整 | OOV 严重,词表过大 |
| 字符级别 | 无 OOV | 序列过长,语义粒度太细 |
| BPE | 平衡,无 OOV,序列长度适中 | 需要预训练语料学习合并规则 |
🎯 面试总结
BPE 的四步核心流程要说清楚:字符级别初始化 → 统计相邻 token 对频率 → 合并最高频对 → 迭代直到词表大小达标。要补充 BPE 的两个关键优点(无 OOV,词表大小可控),以及 GPT 用的是 Byte-level BPE(在字节级别初始化,完全无 OOV)。
32. WordPiece 与 BPE 的异同点是什么?
👔面试官:WordPiece 和 BPE 有什么区别?BERT 为什么选 WordPiece?
🙋♂️我:WordPiece 用 ## 前缀标记子词,BPE 用 </w> 词尾标记,具体的合并方式不同。
👔面试官:合并标准有什么本质区别?WordPiece 的合并标准是什么?
💡 简要回答
BPE 和 WordPiece 的核心区别在于合并标准:
- BPE:选择频率最高的相邻 token 对合并(纯粹的出现次数)
- WordPiece:选择合并后使语言模型概率提升最大的 token 对(即最大化 log P(合并后语料) - log P(合并前语料))
直觉上,WordPiece 更保守——只有当合并一对 token 能让语料的概率模型显著改善时,才执行合并。频率高不代表合并后模型更好,WordPiece 用更严格的标准决策。
📝 详细解析
合并标准的具体差异
BPE 合并准则:
选 argmax_{(a,b)} count(a, b)WordPiece 合并准则:
选 argmax_{(a,b)} [count(a, b) / (count(a) × count(b))]这个比值本质上是计算两个 token 的联合概率 / 独立概率乘积,即「合并这两个 token 相比分开 token 的似然提升比例」。分母大(每个 token 单独频率高)时,合并标准更严格,避免把两个已经很常见的独立 token 合并。
词典构建后的表现差异
BPE 的「词尾」视角:初始化时把词结尾加 </w>,合并时保留了词边界信息。
WordPiece 的「子词」视角:初始化时对词内部的非首字符加 ## 前缀,区分「一个词的开头」和「词的中间部分」。比如 unaffable 可能被分为 un ##aff ##able,## 标记表示这是上一个 token 的延续。
实际使用
- BERT 用 WordPiece(词表 30K/32K,中英文版本不同)
- GPT 系列 用 BPE(基于字节级别,词表 50K+)
- RoBERTa、DeBERTa 用 Byte-level BPE(WordPiece 的改进版)
BERT 选 WordPiece 是因为 WordPiece 生成的子词更倾向于有语言学意义(前缀、词根、后缀等),对理解任务有帮助。GPT 选 BPE 是因为简单高效,且生成任务对子词语言学意义要求不高。
🎯 面试总结
区别的核心一句话:BPE 按频率合并(频率最高的 pair);WordPiece 按概率提升合并(合并后语料似然提升最大的 pair,等价于 count(ab) / (count(a)·count(b)) 最大)。能再说一句「WordPiece 更保守,生成的子词更有语言学意义,BERT 选它是因为有助于理解任务」,这道题就很完整了。
33. 简单介绍一下 SentencePiece 的思路
👔面试官:SentencePiece 是什么?它和 BPE/WordPiece 有什么不同?
🙋♂️我:SentencePiece 是一种不依赖预分词的分词工具,可以直接处理原始文本。
👔面试官:不依赖预分词有什么好处?SentencePiece 里的 BPE 和 Unigram Language Model 有什么区别?
💡 简要回答
SentencePiece 是一个语言无关(Language-agnostic)的子词分词框架,最大的特点是直接在原始文本(字符/字节级别)上工作,不依赖语言特定的预分词步骤(比如英文按空格分词、中文需要分词工具)。
它同时实现了两种分词算法:BPE 和 Unigram Language Model,两种算法都能在这个框架下运行。
📝 详细解析
核心特点:无需预分词
传统 BPE/WordPiece 的工作流:
原始文本 → 语言特定预分词(英文按空格,中文用分词工具)→ BPE 子词分割SentencePiece 的工作流:
原始文本 → 直接输入 SentencePiece → 子词序列SentencePiece 把空格当成特殊字符 ▁(Lower One Eighth Block),显式地编码到 token 里,从而不需要依赖语言特定的预分词。这使得它天然支持多语言,对中文、日文、阿拉伯文等无空格语言也能直接使用。
Unigram Language Model 分词算法
SentencePiece 独有的一个算法是 Unigram LM,与 BPE 的「从小到大合并」相反,它是「从大到小裁剪」:
- 初始化一个很大的候选词表(包含所有可能的子字符串)
- 训练一个 Unigram 语言模型(每个 token 的概率独立)
- 对每个词表中的 token,计算「删掉它会让语料概率损失多少」
- 删掉损失最小的 X% 的 token
- 迭代直到词表大小满足要求
Unigram LM 的好处:可以给同一个字符串的多种切分方式都赋予概率,训练时可以采样不同的切分(Subword Regularization),增加训练的鲁棒性。
应用
- SentencePiece + BPE:T5、mBART、LLaMA(LLaMA 用 SentencePiece + BPE,词表 32K)
- SentencePiece + Unigram:XLNet、mBERT(多语言 BERT)
LLaMA 使用 SentencePiece + BPE,词表 32K,把中文字符大多编码为单个 UTF-8 字节序列,导致中文 token 效率较低(一个中文字可能对应 3 个 token)。Qwen 系列扩大了词表(150K+)并针对中文做了优化,中文一个字通常对应 1 个 token,token 效率大幅提升。
🎯 面试总结
SentencePiece 的核心优势是语言无关(不需要预分词)。要说明它实现了 BPE 和 Unigram LM 两种算法,其中 Unigram LM 的「从大到小裁剪」逻辑和「Subword Regularization」是它独有的亮点。能补一句 LLaMA 用 SentencePiece+BPE 词表 32K,Qwen 扩大词表提升了中文效率,展示工程实践层面的了解。
34. 不同大模型的分词方式有哪些区别?
👔面试官:主流大模型各自用什么分词方式?这些区别对实际使用有什么影响?
🙋♂️我:GPT 用 BPE,BERT 用 WordPiece,LLaMA 用 SentencePiece……
👔面试官:词表大小有什么区别?对中文支持有什么影响?token 效率为什么重要?
💡 简要回答
| 模型 | 分词方案 | 词表大小 | 中文支持 |
|---|---|---|---|
| GPT-3/4 | Byte-level BPE(tiktoken) | 100K+ | 一般,中文约 1-2 字/token |
| BERT(英文) | WordPiece | 30K | 不适合(中文版用字符级) |
| LLaMA-1/2 | SentencePiece + BPE | 32K | 弱,1 汉字约 2-3 token |
| LLaMA-3 | tiktoken(Byte-level BPE) | 128K | 显著改善 |
| Qwen/Qwen2 | BPE(自研) | 150K+ | 好,大多数汉字 1 token |
| ChatGLM | SentencePiece + BPE | 64K+ | 较好 |
| DeepSeek | BPE | 100K+ | 好 |
📝 详细解析
Token 效率为什么重要?
Token 效率直接影响三件事:
- 成本:API 按 token 计费,同样一段中文,LLaMA-2 可能需要 3 倍于 GPT-4 的 token 数,成本相差 3 倍
- 上下文占用:相同的文档内容,token 效率低的模型会占用更多上下文窗口,能处理的有效信息量更少
- 生成速度:token 越多,推理步骤越多,延迟越高
举例说明:「今天天气很好」(7 个汉字):
- LLaMA-2:约 14~21 个 token(每个汉字对应多个 UTF-8 字节 token)
- Qwen2:约 7~9 个 token(大多数常用汉字直接有对应 token)
Byte-level BPE vs 普通 BPE
GPT 的 tiktoken 和 LLaMA-3 都用 Byte-level BPE:初始词表不是字符,而是 256 个字节(0x00~0xFF)。好处是完全无 OOV,任何 Unicode 字符(包括表情符号)都能通过字节序列表示;坏处是中文字符对应的字节序列(通常 3 字节)在低频时无法合并为单一 token,效率较差。
大词表(100K+)可以缓解这个问题——词表越大,可以容纳的「完整汉字 token」越多,token 效率越高。这是 LLaMA-3 把词表从 32K 扩展到 128K 的核心动机之一。
中文专用优化
以 Qwen 为例,针对中文做了以下优化:
- 词表大小 150K+,包含大量高频汉字、词语直接作为 token
- 统计了大量中文语料,确保常见中文词汇都有高效的 token 表示
- 中英文混合文本的 token 效率都有保障
🎯 面试总结
这道题考的是工程层面的了解。核心要点:词表大小决定了 token 效率,对中文尤其重要;Byte-level BPE 无 OOV 但中文效率差;LLaMA-2 中文效率弱(32K 词表),Qwen/DeepSeek 针对中文做了词表优化(100K+ 词表);LLaMA-3 扩大到 128K 显著改善了多语言效率。能给出具体的汉字 token 数对比,面试官会觉得你有真正使用过这些模型。
35. Wordpiece 与 BPE 之间的区别是什么?
此题与第 32 题高度重叠,重点补充实际选型建议。
💡 补充要点
选型角度的总结:
从理解任务角度:WordPiece 生成的子词更有语言学意义(前缀、词根、后缀),BERT 选它是因为 MLM 预训练时预测有语义意义的子词更有助于学习深层语义。
从生成任务角度:BPE(尤其是 Byte-level BPE)更适合,因为生成任务不需要子词有语言学意义,只需要分割高效、无 OOV,BPE 的字节级变体彻底解决了 OOV 问题。
从多语言角度:SentencePiece 框架下的 BPE 或 Unigram LM 更适合,因为不依赖预分词,天然多语言友好。
36. 涌现能力(Emergent Ability)是什么?产生的原因是什么?
👔面试官:什么是大模型的涌现能力?为什么会产生涌现?
🙋♂️我:涌现能力就是模型在某个规模之前没有某种能力,到了某个规模之后突然获得了,就好像从无到有一样。
👔面试官:为什么会「突然」出现?是真的在某个规模点突然跳变,还是有其他解释?具体有哪些涌现能力的例子?
💡 简要回答
涌现能力(Emergent Ability):指在小规模模型中无法观察到、但在足够大的模型中突然表现出来的能力。典型例子包括:多步推理、思维链(CoT)、代码生成、算术运算、多语言理解等。
关于涌现的「原因」目前有两种主流观点:
- 真实涌现假说:模型规模跨越某个阈值时,内部表示发生了质变(类似相变),真正产生了新能力。
- 度量涌现假说(更近期的研究):涌现现象可能是评估指标的「不连续性」导致的视觉假象——如果用连续的评估指标(而非准确率这种二值指标),能力提升其实是连续的,并没有真正的突变点。
📝 详细解析
典型的涌现能力举例
Google 的论文《Emergent Abilities of Large Language Models》(2022)汇总了 137 种在大模型中出现的涌现能力:
- 算术:3 位数加减法——小于 13B 参数时准确率接近 0,超过某个阈值后准确率跳跃
- 多步推理(CoT):在 100B 参数以上的模型中 Chain-of-Thought prompting 才显著有效,小模型用了 CoT 反而变差
- 指令跟随(Zero-shot):GPT-3 (175B)才开始真正能零样本跟随复杂指令
- 多语言翻译:大模型在训练时没有专门的翻译数据,但达到一定规模后自然获得了翻译能力
- 代码生成:代码能力在约 12B 参数以下几乎为零,在更大规模下快速提升
涌现的机制假说
解释一:能力组合的阈值效应
某个复杂能力需要多个子能力同时具备。比如三步推理需要「记住步骤 1 的结果」+「把步骤 1 结果用于步骤 2」+「综合前两步给出答案」,每个子能力都需要一定的模型容量。当模型小时,哪怕大部分子能力都具备了,最弱的一环仍然是瓶颈,整体能力为 0;当模型大到所有子能力都到位,整体能力突然出现。
解释二:评估指标的非线性
Stanford 的后续研究(Are Emergent Abilities of Large Language Models a Mirage?)指出:用准确率这种「要么对要么错」的二值指标,即使能力是线性增长的,也会出现「阶跃」的假象。比如模型在 logits 层面的提升是连续的,但只有当 logit 跨过某个阈值对应的类别正确时,准确率才从 0 到 1 跳一格。换用 calibration loss 这类连续指标,很多涌现现象就消失了。
工程含义
无论涌现的本质是什么,实践中一个重要结论是:某些能力只有在足够大的模型中才能稳定出现。这是研究者和工程师持续追求更大规模模型的重要动机——你不知道哪个新能力会在下一个规模档位涌现出来。
🎯 面试总结
答这道题要说清楚三件事:什么是涌现(小规模时没有、大规模时突然出现);给出 2~3 个具体例子(CoT 在 100B 以上才有效、三步算术、指令跟随);说明涌现的两种解释(真实相变 vs 评估指标假象),表明这个问题目前仍有争议。能补一句「无论机制如何,工程上涌现意味着某些能力只有在大模型中才可靠出现,这是 scaling 的重要动力」,很加分。
37. 介绍一下 Scaling Law,它与实际工程有什么关系?
👔面试官:Scaling Law 是什么?它对训练大模型有什么指导意义?
🙋♂️我:Scaling Law 就是模型参数量越大、数据越多,效果越好的规律。
👔面试官:能更精确一点吗?「效果越好」的数学关系是什么?Chinchilla 对 Scaling Law 做了什么修正?
💡 简要回答
Scaling Law 描述了模型性能(loss)与模型参数量(N)、训练数据量(D)、计算量(C)之间的幂律关系:
L(N) ∝ N^(-α) # 参数越多,loss 越低,幂律关系
L(D) ∝ D^(-β) # 数据越多,loss 越低
L(C) ∝ C^(-γ) # 算力越多,loss 越低这三个因素彼此相对独立地影响性能,且每增加 10 倍的算力/参数/数据,性能(loss)提升遵循固定的幂律缩放。
Chinchilla 的修正:在固定计算预算 C 下,最优策略是让 N 和 D 同步增长(之前行业普遍认为越大越好,但没有充分训练),而不是只追求大参数量。
📝 详细解析
OpenAI 的原始 Scaling Law(Kaplan et al., 2020)
原始论文的关键发现:
- 幂律关系:loss 和 N、D 之间符合幂律,对数坐标下是直线关系
- 独立性:N 和 D 对 loss 的贡献基本独立,可以分别优化
- 「大力出奇迹」:在固定计算预算下,往往更大的模型 + 少量训练步数,比小模型充分训练效果更好
这个结论引导了 GPT-3 时代的策略:追求更大的模型,哪怕训练步数相对不足。
Chinchilla(DeepMind, 2022)的修正
DeepMind 的研究发现了原始 Scaling Law 的问题:在固定算力预算 C = N × D × 6 下,最优的参数量 N 和数据量 D 满足:
N_opt ∝ C^0.5
D_opt ∝ C^0.5
# 即 N 和 D 应该以相同的比例增长结论:模型参数量 N 应该和训练 token 数 D 大致相等(token 数约等于参数量的 20 倍是当时的推荐)。GPT-3(1750 亿参数)只用了 3000 亿 token 训练,严重数据不足;按 Chinchilla 的结论,用同样算力训练 700 亿参数但 1.4 万亿 token 的模型(这就是 Chinchilla-70B),在同等算力下效果更好。
Chinchilla 直接影响了 LLaMA 系列的设计:LLaMA-1 65B 用了 1.4T token,比当时大多数同量级模型训练得充分得多,因此在推理时性能远超体量更大但训练不足的模型。
工程指导意义
预算分配:给定计算预算,用 Chinchilla 公式计算最优 N 和 D 的分配比例,避免「大模型+少数据」或「小模型+海量数据」的两种极端。
提前预测性能:通过 scaling 曲线,可以在小模型实验中预测大模型的性能,降低昂贵的大规模实验风险。
数据策略:Chinchilla 之后,行业开始更重视数据质量和数据量,不再只追求参数量。
🎯 面试总结
Scaling Law 的核心是幂律关系(loss ∝ N^-α,D^-β,C^-γ)。要说清楚 Chinchilla 的修正(在固定算力下,N 和 D 应该同步增长,之前行业普遍训练不足),以及它对工程的影响(LLaMA 的设计哲学:中等参数量+充分训练,推理性价比更高)。能补一句「现在 LLaMA-3 用了远超 Chinchilla 推荐比例的数据(约 15T token),说明在推理部署场景下,数据过训可以进一步提升推理时性能」,体现你对最新进展的了解。
38. Chinchilla Law 是什么?对训练有什么指导意义?
此题与 37 题部分重叠,重点补充「过训」(Overtrain)的讨论。
💡 补充要点:过训的讨论
Chinchilla 的原始结论是在「训练一次」的场景下的最优解,但实际工程中还要考虑推理成本。
如果一个模型需要被调用数十亿次,推理总成本 = 推理次数 × 单次推理成本(正比于模型参数量)。在这种场景下,用更小的模型 + 更多数据训练(即「过训」),使更小的模型达到和大模型相当的性能,总成本(训练+推理)往往更低。
Meta 的 LLaMA 系列就采用了这个策略:刻意「过训」,LLaMA-3-8B 用了 15T token(远超 Chinchilla 推荐),使一个 8B 参数的小模型在性能上接近早期的 70B 模型,但推理成本只有 1/8。
🎯 面试总结
Chinchilla 给出了「训练最优」的参数/数据分配,但工程中还要考虑「推理最优」。在高频推理场景(如 API 服务)下,适度「过训」小模型,使小模型达到更高性能,总成本(训练+推理)更低。这是 LLaMA 系列设计哲学的核心,能说清楚这个权衡会很加分。
39. GPT-3 拥有的 1750 亿参数,是怎么算出来的?
👔面试官:GPT-3 号称 1750 亿参数,这些参数都在哪里?能大概算一下吗?
🙋♂️我:主要是 Transformer 层里的权重矩阵……具体我算不出来。
👔面试官:Embedding 层多少?每个 Transformer 层多少?GPT-3 有多少层?
💡 简要回答
GPT-3 的超参数:96 层,d_model=12288,头数 96,d_ff=4×12288=49152,词表大小 50257。
主要参数来源:
- Token Embedding:50257 × 12288 ≈ 6.2 亿
- 每个 Transformer 层:包含 4 个权重矩阵(QKV+O) + FFN 两层,约 3.6 亿/层
- 96 层:96 × 3.6 亿 ≈ 345 亿
- 还有 Position Embedding(4096×12288≈5亿)和 LayerNorm 参数
粗算:96 × 12 × d_model² ≈ 96 × 12 × 1.5 × 10⁸ ≈ 1720 亿,加上 Embedding 约为 1750 亿。
📝 详细解析
每层 Transformer 的参数量(以 GPT-3 为例)
多头注意力模块(4 个线性层):
W_Q, W_K, W_V: 各 d_model × d_model = 12288 × 12288 ≈ 1.5 亿
W_O: d_model × d_model = 1.5 亿
合计:4 × 12288² ≈ 6 亿参数FFN 模块(2 个线性层):
W1: d_model × 4×d_model = 12288 × 49152 ≈ 6 亿
W2: 4×d_model × d_model = 49152 × 12288 ≈ 6 亿
合计:2 × 4 × d_model² ≈ 12 亿参数每层合计:约 6 + 12 = 18 亿参数(不含 LN 的极小参数)
96 层:96 × 18 亿 ≈ 1728 亿参数
加上 Token Embedding(6.2 亿)、Position Embedding(0.6 亿),总计约 1735 亿 ≈ 1750 亿。
一般公式
对于一个 L 层、d_model 维度的 Transformer:
总参数量 ≈ 12 × L × d_model²(主要是注意力和FFN的参数)
+ 词表大小 × d_model(Embedding层)这个公式在粗估模型参数量时非常好用。
🎯 面试总结
这道题考的是你是否真正理解 Transformer 的参数分布。核心要点:注意力模块占 4 × d_model²(QKV+O),FFN 占 8 × d_model²(W1+W2,中间维度 4 倍),每层共约 12 × d_model²,L 层合计 12Ld_model²,加上 Embedding 层。能现场推导出「1750 亿 ≈ 12 × 96 × 12288²」,面试官会非常满意。
40. 大模型 LLM 的架构介绍?
👔面试官:主流 LLM(比如 LLaMA、Qwen、ChatGLM)和原始 Transformer 相比,做了哪些改动?
🙋♂️我:去掉了 Encoder,只保留 Decoder,然后用了 RoPE 位置编码……
👔面试官:具体的技术改动有哪些?为什么要改?能列举几个主要的变化吗?
💡 简要回答
主流 LLM 相比原始 Transformer(2017)有以下核心改动:
| 组件 | 原始 Transformer | 现代 LLM |
|---|---|---|
| 架构 | Encoder + Decoder | 纯 Decoder-only |
| 归一化位置 | Post-LN | Pre-LN |
| 归一化方式 | LayerNorm | RMSNorm |
| 激活函数 | ReLU | SwiGLU / GeLU |
| 位置编码 | 正弦绝对编码 | RoPE(相对位置) |
| 注意力变体 | MHA(全头) | GQA(分组查询) |
| FFN 变体 | 标准 FFN | SwiGLU FFN |
📝 详细解析
Pre-LN + RMSNorm
原始 Transformer 用 Post-LN(子层后归一化),现代 LLM 改用 Pre-LN 训练更稳定,并进一步用 RMSNorm 替代 LayerNorm(去掉均值减法,速度更快,效果相当)。
SwiGLU FFN
原始 FFN:FFN(x) = ReLU(xW1 + b1)W2 + b2
现代 LLM(LLaMA、Qwen 等)用 SwiGLU:
python
FFN_SwiGLU(x) = (SiLU(x·W1) ⊙ x·W3) · W2
# SiLU(x) = x * sigmoid(x) = x / (1 + e^(-x))
# ⊙ 是逐元素乘法
# 注意:有 3 个矩阵 W1, W2, W3SwiGLU 引入了门控机制(Gated Linear Unit),实验表明在相同参数量下效果优于 ReLU/GELU。为了参数量一致,SwiGLU 的中间维度通常设为 2/3 × 4 × d_model(原来是 4 × d_model)。
GQA:推理效率的必要改进
原始 MHA 每个 Query Head 有独立的 K/V Head,KV Cache 很大。GQA 把多个 Q Head 分组共享 K/V,在几乎不损失精度的情况下将 KV Cache 减小到 g/h(g 是 KV 组数)。LLaMA-2-70B 及之后的大模型几乎全部采用 GQA。
典型 LLM 架构对比
| 模型 | 参数量 | 层数 | d_model | 特殊设计 |
|---|---|---|---|---|
| LLaMA-2-7B | 7B | 32 | 4096 | GQA(KV:1), RoPE, SwiGLU |
| LLaMA-3-8B | 8B | 32 | 4096 | GQA(KV:8), 128K词表 |
| Qwen2-7B | 7B | 28 | 3584 | GQA, 滑动窗口+全局注意力 |
| DeepSeek-V2 | 236B(21B激活) | 60 | 5120 | MoE, MLA, GQA |
🎯 面试总结
这道题是对现代 LLM 架构改进的综合考察。要能列出六个主要变化(Decoder-only、Pre-LN、RMSNorm、SwiGLU、RoPE、GQA),并且对每个说明「改了什么」和「为什么要改」。其中 Pre-LN(训练稳定)、RMSNorm(速度)、SwiGLU(更好的门控非线性)、GQA(减少 KV Cache)是最常被追问的。
(本文档完整覆盖第一分类「模型架构与基础」全部 40 道题,包含 Transformer 基础(1-10)、Attention 机制(11-16)、模型架构对比(17-25)、位置编码(26-30)、Tokenizer(31-35)、涌现能力与 Scaling Law(36-40)。)