网易深度学习算法岗笔试题复盘:从逻辑回归到KMP的备考路线
2018年网易校招深度学习算法工程师的笔试卷,到现在我偶尔还会拿出来让准备校招的同学做一遍。不是因为题目多新,恰恰相反,整套卷子里几乎没有追热点式的偏题怪题,翻来覆去考的就是那些越基础越容易忽略的东西——逻辑回归的梯度推导、CNN感受野的计算、BatchNorm为什么能加速收敛、概率题里的条件概率陷阱,外加一道KMP或动态规划。
很多准备校招的人第一反应是去背最新的模型结构、赌哪个热点模型会出现在卷子上,结果一上来就被手推公式打懵。这份卷子真正想筛掉的,就是那种只会调用接口、说不清原理的简历型选手。所以这篇内容不只是对着一张试卷讲答案,更想顺着它的命题逻辑,把机器学习、深度学习、数学基础、数据结构四条线完整拆开,给准备算法岗笔试的人一条可以直接照做的复习路径。
1. 网易DL算法岗笔试的筛选逻辑:先搞清楚卷子为什么这么出
1.1 从岗位JD反推考点:笔试到底在筛什么人
"深度学习算法工程师"这个岗位听起来很前沿,但校招笔试考的东西其实非常古典。我复盘这份试卷后最大的感受是:网易笔试考的不是"你了解多少新模型",而是"你能否把一个基础模型吃透到可以手推的程度"。
原因很简单。校招候选人的背景差别非常大,有人实习时跑过几个开源项目,有人发过论文,也有人本科不是计算机相关专业。实验室方向各不相同,简历上写的东西五花八门,笔试要想公平,只能回到通用基本功:数学(概率、线代、高数)、机器学习经典模型、深度学习基础组件、基础数据结构与算法。这四个方向在岗位JD里都有对应——要懂模型训练就需要理解损失函数和优化器;要能调网络结构就需要理解卷积计算和梯度传播;要处理数据就得有概率统计感觉;要能落地原型就得会写代码。
所以拿到试卷先不要急着做题,花两分钟扫一遍题型分布,往往就能看出命题人的意图。下面这个表格是我根据当年算法岗笔试的常见题库整理的考点覆盖情况,不同批次可能略有出入,但整体覆盖面大差不差:
| 考查模块 | 常见题型 | 主要考点 |
|---|---|---|
| 机器学习基础 | 选择/简答/推导 | LR、SVM、决策树、朴素贝叶斯、集成学习、特征工程 |
| 深度学习基础 | 选择/填空/简答 | CNN、RNN、激活函数、梯度消失、BatchNorm、过拟合方法 |
| 数学基础 | 选择/填空 | 概率论、条件概率、特征值、最优化 |
| 数据结构与算法 | 编程/手写 | 排序、字符串匹配、动态规划、二叉树 |
这样的分布背后有个潜台词:如果你连这些基础题的稳定性都不够,后面面试环节聊模型的工程细节也会很难展开。笔试本质上是在给面试划一条底线,而不是真的指望一张卷子测出你的全部能力。
1.2 题型分布与时间分配:先拿稳必得分再攻难题
关于时间分配,我见过太多人栽在"选择填空花费太久,编程题没时间写"上。一般的校招笔试时长约90到120分钟,可以用一个非常实用的"十秒原则":一道选择题如果10秒内没有清晰思路,先标记跳过,把会做的题全部拿完,再回来处理。编程题通常是一道或两道,建议至少预留40分钟。
这里有一个容易被忽略的策略:填空和简答往往有几道送分题,比如"softmax输出总和等于多少"、"3×3卷积步长为1padding为1能否保持尺寸"这类。这类题是保证底分的关键,也是整张试卷中性价比最高的部分。而真正有区分度的题通常只有两三道,比如手推梯度、KMP的next数组、超参调整中的概率计算。做对基础题,拿到中上分,比死磕难题性价比高得多。
我在面试季帮学员做模考时统计过一个数据:能进面试的卷面往往不是难题全对的,而是基础题几乎不丢分的。这个经验值得所有备考的人重视。深度学习算法岗的笔试不像数学竞赛,它不要求满分,只要求你展现出"基础扎实、可以培养"的潜质。
1.3 不同背景考生的应对策略差异
备考策略不能一概而论。科班出身的人,数据结构和算法通常问题不大,但容易轻视数学推导和深度学习细节,结果逻辑回归梯度推不完整、BN的训练测试差异说不清。非科班转行的同学则相反,可能对模型原理下过功夫,但概率题和手撕代码容易拖后腿。
我一般会先让备考者做一次自我诊断:拿一份往年真题限时做一遍,对照答案找出丢分模块。如果丢分集中在数学和代码,就提前进入刷题节奏;如果丢分集中在深度学习原理,就先啃理论书再做题。知道自己短板在哪里,比盲目刷十套卷子更有用。这个诊断方法放到任何大厂的算法岗笔试准备中都适用。
2. 机器学习基础题:损失函数、优化器与手推套路
2.1 逻辑回归为什么年年考:推导过程和易错点
网易深度学习算法岗笔试中,逻辑回归几乎是必考的。它看起来简单,但可以一路延伸到分类任务、交叉熵损失、梯度下降、正则化,甚至在线性模型和神经网络之间建立桥梁。
一个很典型的问题是:写出逻辑回归的损失函数并求梯度。标准做法是:
假设样本标签 y ∈ {0, 1},模型输出概率:
p = σ(w^T x) = 1 / (1 + e^{-w^T x})
交叉熵损失:
L = - [ y log p + (1 - y) log(1 - p) ]
对 w 求梯度时,关键是先求 ∂L/∂z,其中 z = w^T x。很多人在这一步卡住,原因是没有用对链式法则:
∂L/∂z = p - y
这个式子推导过程非常干净:
∂L/∂z = -[ y × (1/p) × p(1-p) + (1-y) × (1/(1-p)) × (-p(1-p)) ]
= -[ y(1-p) - (1-y)p ]
= p - y
然后:
∂L/∂w = (p - y) x
这个结果的直观解释是:残差越大,梯度越大;当模型对样本的预测完全正确时(p=y),梯度为0。笔试如果让你手推,一定要写出"∂L/∂z = p - y"这个中间步骤,它既是得分点,也是后续所有神经网络反向传播的基础。
易错点主要有三个:
一是把 sigmoid 的导数写错。σ'(z) = σ(z)(1-σ(z)),而不是随便一个 [0,1] 区间内的值。
二是忘了对全量样本求和时会产生 1/N 系数。面试官并不在乎 1/N 放在哪里,但推导过程前后要一致,别前半段写 1/N、后半段又丢掉。
三是正则项的梯度。如果损失是 L + λ||w||²,那么 w 的梯度要额外加 2λw(或者 λw,取决于正则项定义),别只写数据项。
另外,如果题目进一步问"为什么不用平方误差做二分类",可以从非凸性和梯度饱和两个角度回答:平方损失对 sigmoid 输出求梯度时,由于 sigmoid 在饱和区导数接近0,梯度会被压缩得非常小,训练极慢;而交叉熵配合 sigmoid/softmax,梯度形式简洁且不包含 σ'(z) 项,数值上也更稳定。这个连带问题出现的概率很高,值得顺手准备。
2.2 优化器比较:从SGD到Adam的细节
笔试对优化器的考查通常不是"背名字",而是问"为什么Adam常用、SGD+动量有什么区别、学习率怎么调整"。
SGD + Momentum 的更新公式:
v_t = γ v_{t-1} + η ∇L(w_t)
w_{t+1} = w_t - v_t
动量项 γ 一般取0.9,它的好处是在梯度方向变化剧烈时能平滑路径,相当于给小球加了惯性。笔试会问的变体是"动量越大越容易冲过极小值吗",答案是:会。动量过大会导致在极小值附近震荡,甚至发散。
Adam 的公式要能默写核心两步:
m_t = β1 m_{t-1} + (1-β1) g_t
v_t = β2 v_{t-1} + (1-β2) g_t²
再加上偏差校正:
m_hat = m_t / (1-β1^t)
v_hat = v_t / (1-β2^t)
然后参数更新:
w = w - η × m_hat / (√v_hat + ε)
偏差校正是高频考点。很多人背公式但不知道为什么要除以 (1-β^t)。原因很简单:t=1 时 m_1 = 0.9×m_0 + 0.1×g_1 = 0.1×g_1,这比真实梯度小了一个数量级,直接用它更新会让前几步步长偏小。除以 (1-β1^t) 后,t=1 时 m_hat = 0.1×g_1 / 0.1 = g_1,正好还原。
由 Adam 引申出来的坑是"在BERT等大规模预训练模型中,为什么常用AdamW而非Adam"。因为Adam的权重衰减是通过梯度方式实现的,L2正则项会被动量的历史梯度平均干扰,而AdamW把权重衰减直接加到更新项上,解耦了正则化与梯度更新,对大规模稀疏特征更友好。这个点2018年前后考得不算多,但放到现在值得知道,属于笔试之后的面试加分项。
3. 深度学习原理题:感受野、BatchNorm与梯度消失
3.1 CNN计算题:感受野和参数量
深度学习岗笔试很少让你写一个完整网络,但非常喜欢考感受野和参数量,因为这两项能准确反映你对卷积操作的理解深度。这类题一旦理解透了,基本就是套公式计算,但因为公式里的细节多,也特别容易出错。
感受野的递推公式,我建议用这个版本:
RF_l = RF_{l-1} + (k_l - 1) × S_l
其中 S_l 是从第1层到第 l-1 层所有stride的乘积(不含当前层),初始 RF_0 = 1。
举一个典型例子:输入 224×224,第一层 conv 7×7,stride=2;第二层 maxpool 3×3,stride=2;第三层 conv 3×3,stride=1。计算第三层输出的感受野:
- 初始 RF_0 = 1
- conv1:k=7, stride=2, S_1=1,RF_1 = 1 + (7-1)×1 = 7
- pool:k=3, stride=2, S_2=2,RF_2 = 7 + (3-1)×2 = 11
- conv2:k=3, stride=1, S_3=2×2=4,RF_3 = 11 + (3-1)×4 = 19
如果你忘了公式,也可以从直觉理解:第一层卷积后每个输出点看到输入上的7×7区域;经过stride=2的pool后,后面每移动一步,在输入上要跨过2个像素,所以池化层把感受野从7扩大到了11;最后一层3×3卷积又进一步扩大。笔试时写出这个递推过程,比只写最终数字更容易拿分。
参数量计算的典型题是:输入 3×224×224,第一层卷积 7×7 输出64个通道,求参数量。
= 7×7×输入通道数3×输出通道数64 + 偏置64 = 9408 + 64 = 9472
注意:很多人在这里忘记乘输入通道数,或者把偏置漏掉。卷积层参数量不依赖输入的空间尺寸(224×224),只依赖卷积核大小和通道数,这也是"全连接层参数量远大于卷积层"的原因。
1×1卷积的作用也是一个高频小问。回答时可以列出三点:跨通道信息融合、通道升降维、增加非线性。如果面试官再往下问,可以补一句"在MobileNet等轻量网络中,1×1卷积被用来控制计算量",这样就把笔试知识串到了实际应用场景。
3.2 梯度消失与BatchNorm/残差连接的解题逻辑
关于梯度消失,笔试最常见的问题是"深层网络为什么难训练?"以及"BatchNorm和ResNet分别是怎么缓解的"。
梯度消失的根因可以用链式法则解释:反向传播时梯度需要逐层相乘,如果每层导数都小于1,连乘后梯度会指数级衰减。sigmoid函数的导数最大值只有0.25,即使权重初始化为1,经过若干层后梯度也会趋近于0,这就是sigmoid在深层网络中表现差的数学原因。同样的道理,如果初始化权重过大、激活函数导数又大于1,也可能出现梯度爆炸。
BatchNorm能缓解这个问题的机制主要有两层:
第一,它把每层输入归一化到均值为0方差为1的分布,让输入落入激活函数的敏感区域。对sigmoid来说,输入不再容易进入两侧饱和区,导数不会整体过小。
第二,它引入了可学习的scale和shift参数,让网络有能力在需要时恢复原始的分布,而不是强制所有层都使用标准正态分布。
这里有一个易错点:BatchNorm在训练时使用当前batch的均值和方差,在推理时使用训练阶段滑动平均得到的全局统计量。如果笔试问"BN层在训练和测试时行为有什么不同",一定要把这一点答出来。很多人能背出BN公式,却忽略了训练/测试行为的差异,这一丢分非常可惜。
残差连接则是从另一个角度解决退化问题:即使某些层的权重被学成接近恒等映射,残差块也能通过 y = F(x) + x 让信息直接跨层传递,梯度可以沿着"捷径"回传而不需要经过多层连乘。所以ResNet做到100多层依然能训练,本质上是给梯度开了一条高速公路。
如果再延伸,可以提到梯度裁剪、更好的初始化方法(如Xavier、He初始化)、激活函数从sigmoid/tanh换成ReLU,这些都是缓解梯度问题的通用手段。笔试中,这类"请列举并解释"的问题,要按"手段+原理"组织答案,而不是只列名称。面试官想听的是"为什么有效",不是"我知道有这个技术"。
4. 数学基础与手撕代码:概率、线性代数与KMP
4.1 概率统计题:难在"条件"而非"公式"
数学部分通常是整张卷子的"掉分区"——不是题目多难,而是太久没做导致手生。网易的命题风格偏实用:概率题很少考复杂的密度函数积分,更多是条件概率、期望和常见分布。
一个出现率极高的经典题:设 X ~ N(0,1),求 E[X | X > 0]。
这个题有陷阱:很多人直接写成0。因为X的期望是0,但给定X>0后就不是了。
正确解法是利用对称性和条件期望定义:
E[X | X > 0] = ∫0^∞ x·φ(x)dx / P(X > 0)
分子 = (1/√(2π)) ∫0^∞ x·e^{-x²/2}dx = 1/√(2π)
分母 = 1/2
所以结果是 2/√(2π) = √(2/π) ≈ 0.7979。
这个题的精髓在于它考查"条件概率下期望的计算",不是死记正态分布公式。类似的还有"掷硬币直到出现正面,投掷次数的期望"这类几何分布问题,或者"三门问题"的变种。
线性代数部分,PCA和特征值分解是常客。题目通常会问:PCA的目标是什么?为什么是最大化方差?解决方案是求样本协方差矩阵的特征值分解,取最大特征值对应的特征向量作为第一主成分。如果想拿高分,最好能写出:投影方向为 w 时,投影后方差 = w^T Σ w,约束 w^T w=1,用拉格朗日乘子法得到 Σ w = λ w,所以方差最大等价于最大特征值。
这部分复习建议是每天保持2-3道题手感,不要只看不做。笔试考场上时间紧张,必须在30秒内判断出该用哪个公式,临时推导是来不及的。概率和线代的很多结论其实都是"一眼熟、动手错",所以做题比看题重要得多。
4.2 手撕代码:快排、KMP和DP的应试策略
编程题在深度学习算法岗笔试中的权重往往被低估。很多人把精力全放在模型原理上,结果栽在一道基础排序题上。网易这类公司很看重代码基本功,毕竟算法工程师本身也是工程师。
手写快排是出现频率最高的一道。写法很多,笔试时我建议用最容易写对且边界清晰的"挖坑填数"版本,或者直接使用递归+partition的双指针写法。重点不是写得多花哨,而是保证在半小时内一次通过边界测试。
以快速排序核心partition为例:
def partition(arr, left, right): pivot = arr[left] while left < right: while left < right and arr[right] >= pivot: right -= 1 arr[left] = arr[right] while left < right and arr[left] <= pivot: left += 1 arr[right] = arr[left] arr[left] = pivot return left def quick_sort(arr, left, right): if left < right: p = partition(arr, left, right) quick_sort(arr, left, p - 1) quick_sort(arr, p + 1, right)这段代码的边界条件是死记硬背容易出错的地方。建议用一个小数组手工模拟一遍,理解"挖坑"过程,考场就不容易乱。
KMP也是算法岗笔试的高频考点。你可能会看到类似 "对于模式串 p='abacaba',求其 next 数组" 这样的题。这里的next数组在不同教材里有不同定义,需要先看清题目给的定义。
以"next[i] 表示模式串长度为 i 的前缀子串的最长相同前后缀长度"这个定义为基准,p="abacaba" 的逐位计算过程如下:
- 长度为1的前缀 "a":最长相同前后缀长度为0
- 长度为2的前缀 "ab":0
- 长度为3的前缀 "aba":前缀 "a" 与后缀 "a" 相同,长度为1
- 长度为4的前缀 "abac":0
- 长度为5的前缀 "abaca":前缀 "a" 与后缀 "a" 相同,长度为1
- 长度为6的前缀 "abacab":前缀 "ab" 与后缀 "ab" 相同,长度为2
- 长度为7的前缀 "abacaba":前缀 "aba" 与后缀 "aba" 相同,长度为3
所以如果按 next[0] = -1 的常见版本,这个模式串的 next 数组为 [-1, 0, 0, 1, 0, 1, 2, 3]。如果题目把 next[i] 直接定义为最长相同前后缀长度,那么结果是 [0, 0, 0, 1, 0, 1, 2, 3]。不同版本并不矛盾,关键是要在考场上看清它把 next 的第一个元素定义为 -1 还是 0。
这里我特别提醒:字符串匹配相关的题目近年在算法岗笔试里出现频率一直在涨,因为 KMP、Trie、AC自动机这类数据结构对处理文本、Token化、序列标注等NLP任务有直接帮助。备考时至少要做到:能快速手写KMP匹配过程,能说明 next 数组的构建为什么是 O(m) 复杂度。
动态规划是另一个无法绕过的方向。常见的题有零钱兑换、最长公共子序列、编辑距离。对算法岗来说,编辑距离尤其值得重点复习,因为它和NLP里的文本相似度、拼写纠错直接相关,面试官很容易从笔试往下深挖。
5. 备考路线与复盘:从这份卷子延伸出的完整复习框架
5.1 复习误区:只背结论不推公式是最大坑
我见过太多准备深度学习算法岗的人,把大量时间花在追最新论文和新模型结构上。结果一到笔试卷子,经典的逻辑回归推导写不完整,KMP的next数组算不对,概率题卡壳。这不是能力问题,是复习方向错了。
这份卷子最值得学习的不是某几道题,而是它对"基础"的强调。一个能把逻辑回归梯度推导写清楚、能准确计算感受野和BN行为、能快速手撕快排和KMP、能正确计算条件概率的人,即使没听说过某个最新模型,面试官也愿意继续聊下去。相反,只会报最新模型名字、说不出原理的人,第一轮就会被刷掉。
我还想多说一个容易忽略的点:推导一定要动手在纸上写。看视频、看博客时你觉得"我会了",闭卷手写一遍才发现一堆细节漏了。建议每次复习完一个专题,就做一次"闭卷默写":损失函数推导、梯度公式、BN训练和测试差异、KMP的next数组构造。这个过程很痛苦,但提分极快。
5.2 三条主线与时间规划
以这份笔试卷为参照,我给准备校招的同学一个复习框架,分为三条主线:
主线一:数学基础。重点是概率论和线性代数。概率论重点复习条件概率、贝叶斯公式、常见分布(正态、二项、泊松)、期望与方差;线性代数重点复习矩阵乘法、特征值分解、SVD、投影和PCA推导。不用刷太偏的题,保持手感即可。
主线二:机器学习与深度学习基础。以经典模型为主:逻辑回归、SVM、朴素贝叶斯、决策树、GBDT、随机森林。深度学习重点在CNN、RNN、激活函数、损失函数、优化器、BatchNorm、Dropout、正则化。建议配合《统计学习方法》和《动手学深度学习》两本书,每学完一章就把公式手推一遍。
主线三:数据结构与算法。重点排序(快排、堆排、归并)、字符串(KMP)、动态规划(背包、LCS、编辑距离)、二叉树遍历。刷题平台建议用LeetCode,每天2-3道,保持到笔试前。
时间规划上,如果给自己4个月:第一个月完成数学基础;第二个月完成机器学习基础;第三个月集中攻深度学习原理并开始做整套笔试模拟卷(牛客网上有历年校招真题);第四个月专项补弱,重点是手撕代码。如果时间只有6周,那就压缩成:前两周数学+机器学习,中间两周深度学习,最后两周密集刷题和模拟。
5.3 练习资源和每日节奏
最后说资源。书方面,机器学习用李航《统计学习方法》(第二版),深度学习用《动手学深度学习》(李沐),数学基础可以直接看对应的大学教材或知名公开课。刷题方面,LeetCode Top 100 和牛客网历年校招笔试真题是最高效的组合。
每日节奏可以参考这个模板:上午2小时数学+原理推导,下午2小时LeetCode,晚上1小时做模拟卷并复盘错题。复盘比做题更重要,弄懂错题背后的知识点,比多做十道新题有价值。我见过不少同学一天刷完五六十道LeetCode,晚上一回忆什么也没留下,这种刷法效率极低。正确的做法是一道题吃透、把题目背后涉及的知识点整理到笔记里,然后隔两周再重做一遍。
从我这几年带人准备校招的经验看,网易这份2018校招深度学习算法工程师笔试卷的难度不算顶级,但它非常全面地覆盖了成为一名合格算法工程师所需的基础素养。如果你能把这份卷子涵盖的考点吃透,不只针对网易,其他大厂的算法岗笔试也大概率能对应上。备考的思路从来不是迷信某一家公司的题库,而是借一张卷子,把整个知识体系补齐。这点想明白,比多做几套题重要得多。
