大厂算法工程师面试题深度解析
本文整理了来自科大讯飞、小米、百度等知名互联网大厂的算法工程师面试真题,涵盖自然语言处理(NLP)、深度学习模型原理、工程实践及基础数据结构等内容。通过对这些问题的深入解析,帮助读者系统复习核心知识点,提升技术面试通过率。
一、科大讯飞 NLP 方向 AI 算法工程师
1. jieba 分词的原理
jieba 分词是一款流行的中文文本分词工具,其核心在于结合词典匹配与动态规划算法,实现高效的中文句子切分。
核心原理:
- 前缀词典与 DAG 构建:基于前缀词典实现高效的词图扫描。对于输入句子,生成所有可能成词情况所构成的有向无环图(DAG)。例如,"研究生命"可以切分为"研究/生命"或"研究生/命",DAG 会包含所有这些路径。
- 最大概率路径查找:采用动态规划算法查找 DAG 中的最大概率路径。通过计算每个词的词频概率,找出基于词频的最大切分组合,从而得到最优分词结果。
- 未登录词处理:对于词典中不存在的未登录词(OOV),采用基于汉字成词能力的 HMM(隐马尔可夫模型)模型。利用 Viterbi 算法进行状态解码,识别出人名、地名等特定类型的未登录词。
2. word2vec 的原理与训练
word2vec 是一种将词语映射为低维稠密向量空间的模型,旨在捕捉词语间的语义关系。
训练方法:
- CBOW(Continuous Bag-of-Words):给定一个窗口大小,将目标词周围的上下文词作为输入,预测目标词本身。输入是上下文词向量的累加或平均,通过浅层神经网络输出目标词的概率分布。
- Skip-gram:与 CBOW 相反,给定一个目标词,预测其上下文词。这种结构在数据量较少时通常表现更好,能更好地捕捉细微的语义差异。
优化技巧:
- 训练过程中常使用负采样(Negative Sampling)或层次 Softmax 来加速收敛,避免全量 Softmax 带来的计算瓶颈。
- 使用大规模语料库迭代训练,配合梯度下降等优化算法更新参数。
3. ChatGPT 的训练流程
ChatGPT 是基于 GPT 架构的大型语言模型,其训练过程主要分为预训练和微调两个阶段。
预训练阶段:
- 使用海量无标注文本数据进行自监督学习。模型通过预测被遮挡的单词(Masked Language Modeling)或下一个单词来学习语言模式和结构。
- 目标是让模型掌握通用的语言知识,具备理解上下文和生成文本的能力。
微调阶段:
- 有监督微调(SFT):使用人工编写的对话数据集对模型进行训练,使其适应问答和对话格式。
- 人类反馈强化学习(RLHF):这是 ChatGPT 的关键步骤。通过收集人类对模型回答的偏好排序,训练奖励模型,并利用 PPO(Proximal Policy Optimization)算法优化策略模型,使输出更符合人类价值观和指令要求。
4. BERT 模型简述
BERT(Bidirectional Encoder Representations from Transformers)打破了传统语言模型单向的限制,实现了真正的双向上下文编码。
核心特点:
- 双向编码器:同时利用左侧和右侧的上下文信息,相比 LSTM 或单向 Transformer 能更准确地理解语境。
- 预训练任务:
- MLM(掩码语言建模):随机掩盖输入中的部分词,要求模型根据上下文预测原词。
- NSP(下一句预测):判断两个句子是否连续,增强句子间关系的理解。
- 下游应用:在分类、命名实体识别、问答等任务上,只需添加简单的输出层并进行微调即可取得 SOTA 效果。
5. PyTorch 中的 train 和 eval 模块
在 PyTorch 框架中,正确切换训练和评估模式对模型性能至关重要。
- train() 模式:启用 Dropout 和 BatchNorm 的统计特性。BatchNorm 会使用当前批次的均值和方差,Dropout 会随机丢弃神经元以防止过拟合。此模式用于反向传播和参数更新。
- eval() 模式:关闭 Dropout 和 BatchNorm 的动态行为。BatchNorm 使用训练期间累积的全局均值和方差,Dropout 不再随机丢弃。此模式用于验证集测试或推理,确保结果稳定。
- 代码示例:
model.train()
for data in train_loader:
optimizer.zero_grad()
loss = criterion(output, target)
loss.backward()
optimizer.step()
model.eval()
with torch.no_grad():
for data in val_loader:
output = model(data)
6. Python 字典的结构及实现方式
Python 中的字典(dict)是内置的高效键值对存储结构。
- 底层实现:基于哈希表(Hash Table)。通过哈希函数将键转换为索引,直接定位到内存位置。
- 特性:键必须唯一且不可变(如字符串、数字、元组),值可以是任意对象。
- 冲突解决:Python 字典采用开放寻址法处理哈希冲突,当发生冲突时,按特定步长寻找下一个可用槽位。
- 性能:平均时间复杂度为 O(1) 的查找、插入和删除操作。
7. 无序数组取前 10 个最大的数
针对无序数组获取 Top K 大元素的问题,有多种解决方案。
方案一:全排序
- 直接使用快速排序或堆排序,时间复杂度 O(n log n)。
- 适用于数据量较小或对稳定性要求高的场景。
- 代码示例:
nums = [3, 1, 5, 9, 2, 8]
sorted_nums = sorted(nums, reverse=True)
top_10 = sorted_nums[:10]
方案二:最小堆(推荐)
- 维护一个大小为 K 的最小堆。遍历数组,若当前元素大于堆顶,则替换堆顶并调整堆。
- 时间复杂度 O(n log k),当 K 远小于 n 时效率更高。
二、小米 AIGC 大模型岗位
1. Transformer 的原理
Transformer 彻底改变了序列建模的方式,摒弃了循环结构,完全依赖注意力机制。
核心组件:
- 自注意力机制(Self-Attention):计算序列中每个 token 与其他所有 token 的相关性得分,加权求和得到新的表示。公式为 $Attention(Q, K, V) = softmax(\frac{QK^T}{\sqrt{d_k}})V$。
- 多头注意力(Multi-Head Attention):并行执行多个注意力头,分别关注不同的子空间信息,最后拼接输出,增强了模型的表征能力。
- 位置编码(Positional Encoding):由于 Self-Attention 不具备顺序感知,需加入正弦余弦位置编码或可学习的位置嵌入,以区分 token 的顺序。
- 前馈神经网络(FFN):在每个注意力层后接两层全连接网络,引入非线性变换。
2. 微调方法 P-Tuning V2 的原理
P-Tuning V2 是针对大语言模型参数高效微调(PEFT)的重要改进版本。
主要改进:
- 深层 Prompt 注入:不同于仅在输入层添加 Prompt,P-Tuning V2 在每一层 Transformer 中都加入了可学习的连续 Prompt tokens。这使得提示信号能更深地影响中间层的特征表示。
- 去除重参数化:移除了 V1 版本中的重参数化编码器,简化结构并提升小模型上的表现。
- 多任务学习支持:支持跨任务的 Prompt 共享与适配,利用连续提示作为任务知识的载体,缓解优化困难。
3. BiLSTM-CRF 模型
BiLSTM-CRF 是序列标注任务(如命名实体识别)的经典架构。
- BiLSTM 层:双向长短期记忆网络负责提取序列特征。前向 LSTM 捕捉过去信息,后向 LSTM 捕捉未来信息,两者拼接形成完整的上下文特征。
- CRF 层:条件随机场位于顶层,用于建模标签之间的转移约束。它计算全局最优路径,避免非法标签序列(如"B-PER"后面不能接"I-LOC")。
- 优势:结合了局部特征提取能力和全局标签约束能力,显著提升了标注一致性。
4. 代码题:两数之和
给定整数数组 nums 和目标值 target,找到和为目标值的两个整数下标。
解题思路:
- 使用哈希表存储已遍历的数字及其下标。
- 遍历数组时,计算
complement = target - num。 - 检查
complement是否在哈希表中,若在则返回结果;否则将当前数字存入哈希表。 - 时间复杂度 O(n),空间复杂度 O(n)。
代码实现:
def two_sum(nums, target):
seen = {}
for i, num in enumerate(nums):
complement = target - num
if complement in seen:
return [seen[complement], i]
seen[num] = i
return []
三、百度算法工程师
1. LoRA 的原理
LoRA(Low-Rank Adaptation)是一种高效的参数微调技术,旨在减少大模型微调时的显存占用和计算成本。
核心思想:
- 低秩分解:冻结原始预训练模型(PLM)的参数,在权重矩阵旁增加旁路分支。旁路由两个低秩矩阵 A 和 B 组成($W' = W + BA$)。
- 训练策略:仅训练 A 和 B 矩阵,PLM 参数保持不动。A 通常用高斯分布初始化,B 用零矩阵初始化。
- 优势:参数量大幅减少,推理时无需合并权重,可直接叠加计算,节省显存。
2. GBDT 的原理
GBDT(Gradient Boosting Decision Tree)是一种强大的集成学习算法。
工作流程:
- 迭代拟合残差:每棵新树都试图拟合前一棵树预测结果的残差(负梯度)。
- 加法模型:最终模型是所有树的预测结果之和。
- 损失函数:通过最小化特定的损失函数(如平方误差、对数损失)来指导树的生长。
- 应用场景:广泛用于结构化数据的分类与回归任务,如 XGBoost、LightGBM 均基于此思想。
3. 翻译任务架构
机器翻译任务经历了从统计机器翻译到神经机器翻译的演变。
- Seq2Seq 架构:早期主流方案,由编码器(Encoder)将源语言编码为上下文向量,解码器(Decoder)生成目标语言。
- Transformer 架构:目前的主流标准。利用自注意力机制替代 RNN,解决了长距离依赖问题,支持并行计算,训练速度更快,效果更佳。
4. Encoder-only, Decoder-only, Encoder-decoder 的区别
- Encoder-only:仅包含编码器,输出固定维度的向量表示。适用于分类、检索、特征提取任务(如 BERT)。
- Decoder-only:仅包含解码器,自回归生成序列。适用于文本生成任务(如 GPT 系列)。
- Encoder-decoder:包含编码器和解码器,用于序列到序列的任务。编码器压缩信息,解码器展开生成(如 T5, MarianMT)。
5. Transformer 结构详解
Transformer 由堆叠的编码器和解码器块组成。
- 编码层:包含多头自注意力机制和前馈网络,每层后有残差连接和 Layer Normalization。
- 解码层:包含掩码多头自注意力(防止看到未来信息)、编码器 - 解码器注意力(关注编码器的输出)以及前馈网络。
- 标准化:所有子层均采用残差连接和归一化,保证训练稳定性和梯度流动。
6. Flash Attention 的原理
Flash Attention 旨在优化 Attention 计算的 GPU 内存访问效率。
- IO 感知设计:传统 Attention 需要将 Q, K, V 矩阵写入高速缓存再读出,导致大量 HBM 读写开销。
- 分块计算(Tiling):将矩阵分块存储在 SRAM 中进行计算,减少 HBM 访问次数。
- 重计算:利用重计算技术在不增加额外显存的情况下恢复中间激活值,进一步降低显存峰值。
7. FP32 和 FP16 的区别及混合精度
- FP32:单精度浮点数,精度高,但占用 4 字节显存,计算速度慢。
- FP16:半精度浮点数,占用 2 字节,计算速度快,适合矩阵运算,但数值范围小。
- 混合精度训练:
- 模型参数使用 FP16 存储,减少显存占用。
- 主副本(Master Weights)保留 FP32 以保证精度。
- 梯度累积使用 FP32,防止溢出。
- 利用 Tensor Core 加速 FP16 计算,显著提升训练吞吐量。
8. Beam Search 的原理
Beam Search 是序列生成任务中常用的搜索算法,用于平衡生成质量与计算成本。
- 工作机制:在每一步生成中,保留概率最高的 K 个候选序列(Beam Width)。
- 扩展与剪枝:对每个候选序列扩展下一个词,计算新序列的联合概率,然后剪枝保留前 K 个。
- 优缺点:相比贪婪搜索(Greedy Search),Beam Search 能探索更多可能性,避免局部最优;但计算量随 K 增大而增加,且可能产生重复内容。
四、总结与建议
以上面试题涵盖了从基础数据结构到前沿大模型技术的广泛领域。准备算法工程师面试时,建议:
- 夯实基础:熟练掌握 Python 数据结构、常见排序与搜索算法。
- 深入理论:理解 Transformer、BERT、LoRA 等核心模型的数学推导与实现细节。
- 工程实践:熟悉 PyTorch/TensorFlow 框架,掌握分布式训练、混合精度等优化技巧。
- 项目复盘:能够清晰阐述个人项目中遇到的难点及解决方案,体现技术深度。
通过系统性的复习与实战演练,可以有效提升应对大厂算法岗面试的信心与能力。

