公司动态
迅雷AI工程师笔试复盘:核心考点与答题策略
2018年秋招季我投了迅雷的AI工程师岗位。当时在线笔试用的是第三方评测平台限时90分钟分选择题、简答题和两道编程题。说实话那年头AI岗的笔试还没有现在这么“卷”但迅雷的卷子考察面挺综合的既考机器学习理论也考代码功底还会结合业务问你工程落地的问题。这篇文章是我结合当时的回忆和同届同学交流整理的考点复盘列一些典型题型的思路分析和易错点给后来准备算法岗笔试的同学做个参考。1. 笔试整体结构与考察思路拆解1.1 迅雷AI岗位的考察定位迅雷这家公司大家熟悉的是下载加速和流媒体但AI团队在2018年前后主要做的事情是视频内容理解、画质增强、智能推荐、用户画像以及分布式训练平台的建设。所以笔试的考察点不会纯考学术模型而是偏向“能落地”的算法和工程能力。我当时拿到的A卷分三块选择题约20道覆盖机器学习基础、深度学习基础、概率统计、数据结构。简答题2-3道一般涉及模型推导或场景设计比如“LR为什么要用交叉熵而不是MSE”“如何在短视频场景下做去重”。编程题2道一道偏数据结构和算法一道偏机器学习实现。从结构能看出来迅雷关注的不只是你会不会调包还看你有没有数学功底和代码实现能力。这一点和很多大厂算法岗笔试一致面试官默认你了解那些常用模型笔试主要筛掉“只会调用、不懂原理”的人。1.2 考察维度与权重参考我根据后续面试过程中侧面了解到的信息结合笔试内容大致拆出这样的权重考察维度典型内容预估占比机器学习理论LR、SVM、决策树、集成学习、正则化、评估指标30%深度学习基础CNN、RNN、激活函数、反向传播、过拟合20%概率统计与线性代数贝叶斯、最大似然、矩阵运算、特征值15%数据结构与算法链表、树、DP、字符串、排序20%工程与业务场景特征工程、模型上线、业务案例分析15%你发现没有数据结构与算法依然占了五分之一。哪怕是AI岗编程基本功还是硬门槛。很多同学花大量时间死磕模型细节结果在第一道编程题上卡住反而丢了最基础的分数这一点特别可惜。2. 机器学习基础高频考点解析2.1 正则化与过拟合L1和L2的本质区别这类题目几乎是每年笔试必考的。选择题常见考法有两种一是给你四个选项问哪个手段不能防止过拟合答案经常是“增加训练轮数”或“减少训练数据”二是问L1和L2正则化在解空间上的区别。L1正则化Lasso之所以能让参数变稀疏是因为它在参数空间中对应一个菱形约束区域最优解更容易落在坐标轴上从而把某些特征的权重压成0。L2正则化Ridge对应圆形约束区域能压缩参数大小但不至于让参数变成严格的0。如果简答题让你“从贝叶斯视角解释L1和L2”你就得说出来L1等价于给参数加了拉普拉斯先验L2等价于加了高斯先验。拉普拉斯分布在0处概率密度最高所以MAP估计更容易得到稀疏解。我当年写这道题的时候额外加了一句“在特征维度极高但样本量有限的场景下L1可以自动做特征选择对工业界特征稀疏的场景非常实用”。这种落脚到业务的补充比干巴巴列公式更能拿分。2.2 模型评估AUC、PR曲线、F1的适用场景选择题经常问的是“正负样本极度不平衡时用哪个指标更好”。答案一般是PR曲线或F1而不是准确率。因为准确率在正样本只占1%的时候全部预测为负也能达到99%的准确率完全失去参考价值。AUC也有个特点是正负样本比例变化时基本保持稳定所以像CTR预估这种场景业内依然常用AUC。但如果关注的是“在有限的精密度下尽量召回更多的正样本”PR曲线更直观。有一道选择题我记得很清楚给了混淆矩阵里的TP、FP、FN、TN数值让你算Precision和Recall。这种题不需要动脑子但很多人会在分母上栽跟头——Precision分母是TPFPRecall分母是TPFN千万别搞反。2.3 经典模型对比LR、SVM、GBDT简答题常出“LR和SVM的区别”。答题要抓住几个关键维度损失函数不同LR是交叉熵对数似然损失SVM是合页损失。目标不同LR建模的是后验概率SVM找的是最大间隔超平面。对异常值敏感度LR对全部样本都敏感SVM只受支持向量影响因此SVM对远离决策边界的异常点更鲁棒。处理非线性LR需要手工做特征交叉核变换SVM可以直接用核函数。2018年前后GBDT在工业界特别火所以笔试也常考“GBDT和随机森林的区别”。一个核心点在两者都是树模型集成但随机森林是Bagging每棵树并行训练降低方差GBDT是Boosting每棵树拟合前面残差降低偏差。随机森林对异常值更鲁棒GBDT对异常值敏感容易过拟合。2.4 特征工程与数据处理有一道简答题是“给你一批用户点击日志怎么构造特征”。这题没有唯一答案考察的是你平时做特征工程的思路。我当时写的框架是统计特征每个用户点击次数、点击率、平均停留时长。序列特征点击过的内容ID序列用Embedding或统计频次表示。时间特征最近一次点击距现在的时间间隔、点击时间段分布。交叉特征用户类别与内容类别的组合或用户活跃度分段与内容时长的组合。回答这种题的核心是展示思路别只给一两个特征就停了。面试官想看你有没有体系化的思考习惯。3. 深度学习与算法题考察方向3.1 CNN基础卷积计算与感受野2018年笔试题里深度学习权重不低。最基础的考法是给一个输入尺寸、卷积核大小、步长和padding让你算输出尺寸。公式是输出尺寸 floor((输入尺寸 - 卷积核大小 2 × padding) / stride) 1如果输入是32×32卷积核是3×3stride1padding0那输出就是30×30。看似简单但很多人会忘了stride向下取整的细节。还有个高频概念“感受野”。简答题会问“两层3×3卷积的感受野等于一层多大卷积核的感受野”。答案是5×5但参数数量更少、非线性更强。计算感受野有递推公式RF_{l} RF_{l-1} (kernel_size - 1) × stride_{l}这个公式在选择题里换几个数字就能考你要记住的是stride大于1时感受野会加速增长而不是简单叠加。3.2 激活函数的选择与梯度消失选择题常考“为什么ReLU比sigmoid好”。几个要点sigmoid在两端梯度趋近于0容易造成梯度消失。sigmoid输出均值不为0会使得深层网络收敛变慢。ReLU在正区间梯度恒为1缓解梯度消失计算也简单。ReLU有个问题是负区间梯度为0导致神经元“死亡”所以后面才有LeakyReLU、PReLU等变体。当年有一道题考的是“sigmoid函数的导数最大值是多少”。如果对sigmoid函数表达式熟悉会求导能得出最大值是0.25。这个数很关键因为多层sigmoid堆叠时每层梯度都要乘以一个小于1的数层数一深梯度基本就消失了。3.3 反向传播与Softmax有一道编程题我印象很深是让你实现Softmax的前向和反向。题目不复杂但把“类和对象”“矩阵运算”和“梯度推导”串在一起纯靠背代码容易写崩。Softmax前向是exp(x_i) / sum_j exp(x_j)实现的坑在于数值稳定性。当x_i很大的时候exp(x_i)会溢出所以要先减去最大值exp(x_i - max_x)这样分子分母同时缩放了相同倍数结果不变但数值稳定。反向传播的推导是多数人的死穴。其实核心就一句话Softmax和交叉熵搭配时梯度是p - y其中p是预测概率y是one-hot标签。但如果单独实现Softmax反向就得推导Jacobian矩阵对角项是p_i(1-p_i)非对角项是-p_i p_j。笔试时我把这个写成了公式附在代码注释里后来复盘觉得这种“代码推导”的做法对拿分蛮有优势。3.4 RNN与LSTM的考察选择题常见考法是问“LSTM解决了RNN的什么问题”。标准答案是梯度消失和长期依赖。展开说就是LSTM通过输入门、遗忘门、输出门控制信息的保留和遗忘让梯度能通过“细胞状态”这条高速公路传得更远。当年还考了一道“RNN能不能并行训练”的判断题。答案是很难并行因为时间步之间存在顺序依赖。Transformer是2017年提的笔试时不算主流但如果你当时能提一句“用注意力机制替代循环结构可以并行计算”妥妥的加分项。4. 编程题实战两道经典题目拆解4.1 题目一TopK问题海量数据找最大K个数这题当年是必考的经典题型可能以“求一个数组里最大K个元素”的形式出现。它考察的不是你会不会排序而是对复杂度敏感不敏感。暴力排序O(n log n)。小顶堆维护K个元素O(n log K)。基于快速排序思想的partition平均O(n)。如果数据在磁盘上放不下需要分布式或外排序。我当时写的是小顶堆版本。用Python的话标准库heapq搞定import heapq def top_k(nums, k): return heapq.nlargest(k, nums)但笔试一般不允许直接调nlargest因为考察点就是你自己能不能实现堆化过程。我手写了一个堆的调整函数def shift_down(heap, root, size): while 2 * root 1 size: child 2 * root 1 if child 1 size and heap[child 1] heap[child]: child 1 if heap[root] heap[child]: break heap[root], heap[child] heap[child], heap[root] root child def top_k(nums, k): heap nums[:k] # 建小顶堆 for i in range(k // 2 - 1, -1, -1): shift_down(heap, i, k) for x in nums[k:]: if x heap[0]: heap[0] x shift_down(heap, 0, k) return heap这里最容易被忽视的是边界情况k等于数组长度时直接返回原数组排序k等于0时返回空数组。在线笔试平台不会给你的代码做人性化处理只要有一个边界没覆盖到运行时直接报错那一整题就废了。4.2 题目二实现K-Means的一轮迭代这道题放到现在可能算常规但在2018年看到的时候我还愣了一下因为平时刷LeetCode完全刷不到这种题。题目大致是给你一组二维点坐标和初始簇中心要求实现一轮K-Means迭代输出更新后的簇中心。思路分两步对每个点计算它到所有簇中心的距离把它归属到最近的簇。对每个簇计算簇内所有点的均值作为新的簇中心。我用Python写了个简洁版本def kmeans_one_iter(points, centers, k): clusters [[] for _ in range(k)] for p in points: dists [sum((p[i] - c[i]) ** 2 for i in range(len(p))) for c in centers] idx min(range(k), keylambda i: dists[i]) clusters[idx].append(p) new_centers [] for cluster in clusters: if cluster: m len(cluster) new_centers.append([sum(p[i] for p in cluster) / m for i in range(len(cluster[0]))]) else: new_centers.append([0.0] * len(centers[0])) return new_centers注意事项距离用欧氏距离的平方就行不用开根号省去浮点误差还省计算。空簇的处理很关键。严格来说要重新初始化或保留原中心我这里是先置零如果平台有时间限制后续可以把空簇重新赋值为一个随机点。输入的数据可能是float最小化距离的索引在Python里用min(range(k), key...)比较高效。这种考察方式其实是提醒你AI工程师的笔试不只是LeetCode机器学习经典算法也得能手写。你天天调sklearn但让你脱离库实现一轮迭代就卡壳说明基本功还是不牢。4.3 编程题通用答题策略在线笔试平台的判题机制不一样有的只看输出结果有的还有部分用例分。我的经验是先写暴力解拿部分分保证不是0分。再逐步优化而不是一开始就冲最优解。代码里多写注释告诉判卷人如果人工看的话你的思路。一定要自测示例输入确认输出格式和题目要求完全一致包括换行、空格、小数位数。2018年那会儿有的平台输入输出格式比较死板多余打印一行调试信息都会判错。别问我是怎么知道的。5. 在线笔试的答题策略与踩坑实录5.1 时间分配的“二八法则”90分钟做20道选择题加2-3道简答加2道编程题时间其实偏紧。我的策略是选择题控制在30分钟内遇到不会的先用排除法选一个标记下来别恋战。简答题每道控制在10分钟内答要点、画框架、列公式别写小作文。编程题给每道留20分钟以上。很多同学死磕一道简答题结果编程题只剩10分钟能写好才怪。笔试的目标是总分最大化不是每道题都完美。5.2 环境与IDE适应2018年在线笔试平台一般提供网页版IDE那个自动补全和代码高亮都还行但运行速度一般。你平时在本地用PyCharm/Jupyter写习惯了突然换到网页编辑器手指都像是别人的。我的建议是考前一定用牛客网或赛码网刷几道题熟悉网页编辑器的操作节奏特别是缩进和括号匹配。另外Python版本可能有差异优先写兼容Python 2和Python 3的代码像print加不加括号这种问题在平台上直接可以决定你第一题能不能过。5.3 输入输出格式的坑在线笔试最常见的翻车点不是算法不会而是输入输出格式不对。题目给的是“第一行一个整数n第二行n个整数”你必须一行一行读不能用input().split()一把梭如果某一行有多余空格就会出错。我写了一个通用模板import sys def main(): data sys.stdin.read().strip().split() if not data: return n int(data[0]) nums list(map(int, data[1:1n])) # 业务逻辑 if __name__ __main__: main()这样能用但要注意如果业务是先读一行处理一行比如多组测试用例一次性读取反而容易搞混顺序。务必看清题目约定。5.4 在线笔试平台的“隐形规则”在线笔试平台一般有防作弊机制比如切屏超过几次会被警告甚至强制交卷。我当时接到过“检测到切屏请保持专注”的提醒吓得赶紧关掉所有其他窗口。另外千万不要在代码里写明文输出特殊字符来标记做题痕迹比如打印“this is candidate answer”这种操作一旦被人工复核看到轻则扣分重则取消成绩。写代码就老老实实提交。5.5 简答题的答题模板简答题最怕的是“会但说不清楚”。我总结了一个万能框架先一句话给结论。再用公式或图示解释核心原理。最后结合业务场景说“所以在这个场景下应该怎么选”。比如问“为什么用AUC而不是准确率进行评估”回答顺序是准确率在样本不平衡时会被多数类主导。AUC衡量的是模型对所有样本排序能力不依赖具体阈值。在点击率预估这类正样本稀少的业务场景AUC能更稳定地反映模型效果。这种回答问题的方式能让面试官觉得你不是背答案而是真的理解这个指标背后反映的业务含义。5.6 心态层面别让一两道题毁掉整场考试在线笔试和面试不一样你看不到面试官的表情遇到一道完全没思路的题很容易陷入焦虑。我的体会是遇到不会的题先跳过把所有能拿的分拿到手再回头啃硬骨头。有些题看着很难但写几行暴力解可能就过了部分用例分数照样能拿。那年我做一道关于LSTM的反向传播推导题时完全卡壳当时选择先去做后面的编程题最后剩10分钟回来硬写了一个框架虽然不完整但至少写了前向和损失部分的公式没让这道题彻底空掉。后来复盘想想这种“先保底再攻坚”的节奏大概是那次笔试我能顺利进入面试环节的重要原因。说到底这类校招笔试不是要你拿满分而是要让面试官看到你的思维方式和工作潜力。把基础数学原理吃透把经典代码实现烂熟于心把业务场景和技术选型结合起来讲清楚你的通过概率自然就上去了。