本文整理了2024年各大厂AI/LLM大模型岗位真实面试真题,按知识点分类整理,并提供详细解答。
解答:
Self-Attention(自注意力机制)的计算分为三个步骤:
X ∈ R^{n×d},通过三个权重矩阵W_q, W_k, W_v ∈ R^{d×d_k}进行线性变换:Q = X · W_q
K = X · W_k
V = X · W_v√d_k进行缩放:Attention Score = (Q · K^T) / √d_k√d_k的原因是:当d_k较大时,点积结果的方差会变大,导致softmax函数进入梯度极小区域,缩放可以避免梯度消失问题。softmax归一化 + 加权求和:
Attention Weights = softmax(Attention Score)
Output = Attention Weights · V最终输出每个位置都融合了整个序列的上下文信息。

解答:
多头注意力机制(Multi-Head Attention)有两个主要原因:
增强表达能力:多头允许模型在不同的表示子空间中学习注意力信息,每个头可以关注不同的位置依赖关系,从而捕捉更丰富的特征。
多个注意力分布:不同的头可以学习到不同类型的注意力模式,例如一个头关注句法关系,另一个头关注语义关系。
具体实现是将Q、K、V在维度上切分成多个部分,每个部分并行计算注意力,最后将结果拼接起来。
解答:
Transformer架构主要由编码器(Encoder)和解码器(Decoder)组成:
编码器(N层堆叠):
解码器(N层堆叠):
核心组件:

解答:
使用不同的权重矩阵生成Q、K、V可以让模型在不同的投影空间学习不同的功能,如果使用相同权重,模型会失去这种区分能力,表达能力下降。
解答:
点乘计算效率更高,可以通过矩阵乘法一次性完成所有位置的计算;而加法在效果上与点乘没有显著差异,但计算效率更低。在大规模数据和复杂模型情况下,点乘具有更好的性能。
解答:
二者共同提高了Transformer的训练稳定性和性能。
解答:
主要有三个原因:
信息保留:LayerNorm是对同一个样本的所有位置特征做归一化,保留样本内部特征的大小关系,这有利于Transformer捕捉样本内部的全局依赖关系;而BatchNorm是对batch中所有样本的同一位置特征做归一化,可能会抹去样本内部特征的原有大小关系。
变长序列适应性:Transformer处理变长序列,序列长度差异大,LayerNorm不受序列长度差异影响,而BatchNorm对长度差异敏感,效果不稳定。
计算效率:LayerNorm不需要存储batch统计数据,在大规模数据集和在线学习场景下内存占用更低,计算速度更快。
解答:
| 类型 | 位置 | 优缺点 |
|---|---|---|
| Post-LN | Layer Norm在残差链接之后 | 缺点:深层网络梯度范式逐渐增大,训练不稳定 |
| Pre-LN | Layer Norm在残差链接之中 | 优点:梯度范式近似相等,深层Transformer训练更稳定;缺点:模型效果略差 |
| Sandwich-LN | 在Pre-LN基础上额外插入一个layer norm | 优点:避免值爆炸;缺点:训练不稳定,可能导致崩溃 |
目前主流大模型(如LLaMA)多采用Pre-LN + RMSNorm的组合。
解答:
| 模型 | 架构类型 | 特点 |
|---|---|---|
| BART | bi Encoder + casual Decoder | 类BERT方法预训练,擅长文本生成、摘要翻译 |
| T5 | Encoder + Decoder | 统一为text2text框架,所有任务都转换成文本到文本问题 |
| GPT | Decoder-only | 主打zero-shot/few-shot,自回归语言建模 |
| GLM/ChatGLM | Prefix Decoder | 混合架构:输入双向注意力,输出单向注意力,中英双语,适合对话 |
| LLaMA | Causal Decoder | Meta开源,纯解码器,自回归,影响力最大的开源模型 |
| PaLM | Causal Decoder | Google推出,大参数量,Pathways架构 |
三种主流开源模型体系:
解答:
核心区别在于attention mask:
解答:
LLaMA基于Transformer做了三处主要改进:
解答:
解答:
ChatGLM基于GLM架构:
[mask]:BERT形式,随机mask文本中的短span[gmask]:GPT形式,mask末尾的长span[gmask],ChatGLM2完全采用gmask预训练解答:
1. Encoder-only架构
2. Decoder-only架构
3. Encoder-Decoder架构
4. Prefix Decoder架构
解答:
Transformer模型本身不包含循环或卷积结构,无法捕捉序列中的位置信息。不同位置的词,即使词向量相同,在句子中的含义也可能不同,因此需要额外的位置编码来提供位置信息,使模型能够理解词序。
解答:
绝对位置编码
相对位置编码
旋转位置编码(RoPE)
ALiBi (Attention with Linear Biases)
解答:
m和n,通过旋转变换将位置信息注入到Q和K中,使得点积结果天然包含位置信息:优点:
解答:
长度外推:指模型在训练时使用固定长度(如4k),推理时需要处理比训练更长的序列(如16k),如何保证性能不明显下降。
解决方法:
解答:
核心思路:不给QK加位置嵌入,而是直接在attention分数上加上一个与两个token距离成正比的负偏置:
attention_score[i][j] = original_score - m * |i - j|其中m是每个头学习一个斜率。距离越远,偏置越负,模型自然不会关注太远的位置。
优点:
解答:
x ∈ R^H:μ = (1/H) * Σ_{i=1 to H} x_i # 均值
σ^2 = (1/H) * Σ_{i=1 to H} (x_i - μ)^2 # 方差
y_i = γ * (x_i - μ) / √(σ^2 + ε) + βγ和β是可学习的缩放和偏置参数,ε是一个小常数避免除零。解答:
RMSNorm(Root Mean Square Layer Normalization)简化了Layer Norm:
RMS(x) = √( (1/H) * Σ_{i=1 to H} x_i^2 )
y_i = γ * x_i / RMS(x)特点:
解答:
DeepNorm是对Post-Norm的改进,对残差分支做放大:
output = LN(x + α * sublayer(x))α > 1是一个放大系数。优点:
解答:
原理:Transformer是自回归生成,每一步只预测一个新token。之前已经计算过的K和V可以缓存下来,下一步不需要重新计算,避免重复计算。
作用:
解答:
都是为了减少KV缓存显存占用的优化方法:
解答:
FlashAttention核心是分块 + IO感知:
解答:
解答:
LoRA核心思想:在原始预训练模型旁边增加一个旁路,做低秩分解来模拟参数更新:
W' = W + BA其中:
W是原始预训练权重,固定不变A ∈ R^{r×k},B ∈ R^{m×r},r远小于min(k,m)优点:
解答:
研究发现,大模型微调时,参数更新的秩很低,大部分梯度更新落在一个低维子空间里,所以用低秩分解足够近似完整的参数更新,不会损失太多效果。
解答:
两者都是挖掘大模型本身具备的知识,但目标和方法侧重点不同。
解答:
RLHF(Reinforcement Learning from Human Feedback)分为三个阶段:
阶段1:SFT(有监督微调)
阶段2:训练奖励模型(RM,Reward Model)
阶段3:PPO强化学习优化
三个阶段依次进行,最终得到对齐人类价值观的对话模型。
解答:
解答:
解答:
完整RAG流程:
数据预处理 → 文档分块 → 文本向量化 → 存入向量数据库
用户查询 → 查询向量化 → 向量检索(召回) → 重排序 → 拼接prompt(query + 检索内容) → 输入LLM → 输出回答解答:
解答:
检索环节评估指标:
生成环节评估:
解答:
解答:
解答:
LangChain是一个大语言模型应用开发框架,简化了RAG、Agent等复杂应用的搭建过程,类似于TensorFlow对神经网络开发的作用。
常用模块:
document_loaders:文档加载text_splitter:文档分块embeddings:文本向量化vectorstores:向量存储chain.RetrievalQA:检索问答链解答:
| 并行方式 | 原理 | 通信开销 |
|---|---|---|
| 数据并行 | 每个GPU保存完整模型,处理不同数据分片,同步梯度 | 每次迭代需要同步梯度,通信量是O(N)(N为GPU数),每个参数梯度需要通信 |
| 模型并行(张量并行) | 单个模型层按张量切分到多个GPU,每个GPU只存一部分参数 | 每层前向反向都需要通信,通信频繁 |
| 流水线并行 | 按层切分模型,不同GPU放不同层,以流水线方式执行 | 只在阶段边界通信,通信次数少,但有流水线气泡开销 |
实际大模型训练常用混合并行,结合多种并行策略。
解答:
DeepSpeed Zero是零冗余优化器,通过切分优化器状态、梯度、参数来节省显存:
3N * σ,存储:12σ/N + 4σ。2N * σ。3N * σ,但存储节省最大,能用1.5倍通信换近120倍显存节省。ZeRO-Offload:基于Zero2,将Adam和gradient放到CPU内存,GPU只负责计算,进一步节省GPU显存。
解答:
Ring All-Reduce:将所有GPU连成一个环,每个GPU只和左右邻居通信:
优势:
解答:
混合精度训练同时使用FP16和FP32:
优点:
需要解决的问题:
关键技术:
解答:
解答:
解答:
解答:
解答:
解答:
解答:
经验公式:
实际还需要额外空间给KV缓存和激活,所以会更大一些。
解答:
题目:给定一个长度为n的整数数组height,找出其中的两条线,使得它们与x轴共同构成的容器可以容纳最多的水。返回最大水量。
解答:使用左右指针法:
1class Solution(object):
2 def maxArea(self, height):
3 """
4 :type height: List[int]
5 :rtype: int
6 """
7 l, r = 0, len(height) - 1
8 max_area = 0
9 while l < r:
10 temp_area = (r - l) * min(height[l], height[r])
11 max_area = max(max_area, temp_area)
12 if height[l] < height[r]:
13 l += 1
14 else:
15 r -= 1
16 return max_area思路:初始首尾指针,每次移动指向较小值的那个指针,因为移动较大的不会增大面积。时间复杂度O(n),空间O(1)。
解答:
1class TreeNode(object):
2 def __init__(self, val=0, left=None, right=None):
3 self.val = val
4 self.left = left
5 self.right = right
6
7def sortedArrayToBST(nums):
8 def helper(left, right):
9 if left > right:
10 return None
11 # 总是选择中间位置左边作为根节点
12 mid = (left + right) // 2
13 root = TreeNode(nums[mid])
14 root.left = helper(left, mid - 1)
15 root.right = helper(mid + 1, right)
16 return root
17 return helper(0, len(nums) - 1)解答:
1#include <stdio.h>
2
3struct Point{
4 double x;
5 double y;
6};
7
8double mult(Point a, Point b, Point c){
9 return (a.x - c.x)*(b.y - c.y) - (a.y - c.y)*(b.x - c.x);
10}
11
12bool solution(Point aa, Point bb, Point cc, Point dd){
13 // 两个点分别在直线两侧
14 if (mult(aa, bb, cc) * mult(aa, bb, dd) > 0){
15 return false;
16 }
17 if (mult(cc, dd, aa) * mult(cc, dd, bb) > 0){
18 return false;
19 }
20 return true;
21}
22
23int main(){
24 Point aa = {0.0, 0.0};
25 Point bb = {10.0, 10.0};
26 Point cc = {0.0, 0.0};
27 Point dd = {10.0, -10.0};
28 bool ret = solution(aa, bb, cc, dd);
29 printf("%d\n", ret);
30 return 0;
31}思路:利用叉积判断两点是否在直线两侧,如果都满足则线段相交。
1#include <stdio.h>
2#include <algorithm>
3using namespace std;
4
5void swap(int *p1, int *p2){
6 int temp;
7 temp = *p1;
8 *p1 = *p2;
9 *p2 = temp;
10}解答:
1def longestCommonSubsequence(text1: str, text2: str) -> int:
2 m, n = len(text1), len(text2)
3 dp = [[0] * (n + 1) for _ in range(m + 1)]
4
5 for i in range(1, m + 1):
6 for j in range(1, n + 1):
7 if text1[i-1] == text2[j-1]:
8 dp[i][j] = dp[i-1][j-1] + 1
9 else:
10 dp[i][j] = max(dp[i-1][j], dp[i][j-1])
11 return dp[m][n]1# 迭代版本
2def reverseList(head):
3 prev = None
4 curr = head
5 while curr:
6 next_node = curr.next
7 curr.next = prev
8 prev = curr
9 curr = next_node
10 return prev
11
12# 递归版本
13def reverseListRecursive(head):
14 if not head or not head.next:
15 return head
16 new_head = reverseListRecursive(head.next)
17 head.next.next = head
18 head.next = None
19 return new_head1import random
2
3def findKthLargest(nums, k):
4 def quickselect(l, r, k):
5 pivot = random.randint(l, r)
6 nums[pivot], nums[r] = nums[r], nums[pivot]
7 i = l
8 for j in range(l, r):
9 if nums[j] > nums[r]:
10 nums[i], nums[j] = nums[j], nums[i]
11 i += 1
12 nums[i], nums[r] = nums[r], nums[i]
13
14 if i == k - 1:
15 return nums[i]
16 elif i > k - 1:
17 return quickselect(l, i - 1, k)
18 else:
19 return quickselect(i + 1, r, k)
20
21 return quickselect(0, len(nums) - 1, k)平均时间复杂度O(n)。