前阵子帮人做了一次模拟面试。我准备了五道中等难度的题,他二十分钟做完四道,边界条件也处理得干净。
然后我问了一个不在题库里的问题:为什么一个模型很自信地答错时,交叉熵损失会特别大。
他停了很久,最后说,公式我背过,但没想过这个角度。
那个停顿比前面二十分钟更能说明问题。不是他基础差,是他从来没被要求把公式和模型行为连起来。而这恰好是现在面试里越来越常出现的那类问题。
题库的区分度正在变薄
标准算法题的处境有点尴尬。
对候选人来说,模板和题解是公开的,AI 补全得比多数人手写更快。对面试官来说,一场四十五分钟的白板题,能验证的东西越来越窄:能不能在压力下写出边界正确的代码,能不能说清复杂度。这两件事仍然重要,但它们不再能代表一个人处理真实问题的能力。
所以题目在往两个方向移动。一个是“带工具的编码题”,允许查文档、允许用助手,但会追问为什么选这个解法、怎么发现生成的实现复杂度退化了、会补哪些测试来证明它没错。另一个是“读代码和排障”,给一段能跑但有问题的代码,要求定位、解释、给最小修复,再判断修复的副作用。
我观察到的变化是,很多团队会在写代码之前先问概念。三五个基础问题连着问,答不上来后面就不必谈了。对候选人来说这有点残酷,因为这些题没有标准题库,靠突击很难补。
我也不认为算法题和工程能力是对立的。能把一道中等题写干净的人,通常在变量命名、边界处理、调试习惯上也不会太差。问题只在于,这类题被当成了唯一的筛子。一个只会做题、没接过系统的人,和一个做过系统、题做得一般的人,后者在多数岗位上更省心。
我不觉得这是面试官在故意为难人。真实工作本来就是这样:大部分时间花在读别人的代码、接手已有系统、判断一个看起来对的结果到底对不对。默写模板反而是最少用的能力。
但 LeetCode 没有消失,它退回到了基础设施的位置。它像体能测试,不代表会打球,但体能太差,上场也撑不住。很多公司的流程也不会为了这个判断立刻重构,算法轮仍然是标准环节,只是后面的权重变了。
我的判断是:中等题稳定通过就够了,不必刷到竞赛水平。能在一个小时里写出边界正确、复杂度说得清的解,剩下的时间应该花在别的地方。完全无视算法题也不行,有些流程连后面几轮都走不到。
我自己的准备方式也因此变了。以前是刷题量,现在是维护手感:每周做两三道中等题,限时,写完口述一遍思路和复杂度。剩下的时间用来读别人的训练代码,猜它哪里会坏,然后跑一遍验证。后者更累,但更接近真实工作。
还有一点需要说清楚:我不认为所有人都要补同一套数学。做业务开发的人,把概率和统计的直觉补齐就够用;做模型训练的人,优化和信息论绕不过去;做基础设施的人,线性代数和数值稳定性更要紧。按岗位裁剪,比照着书单从头学一遍现实得多。面试里真正拉开差距的,往往不是学过多少,而是能不能把学过的东西落到一个具体问题上。
五类数学,各管一件事
如果只记一句话:概率处理的是不确定性,信息论在量它;线性代数和优化负责模型怎么表示、怎么训练;统计学习回答它到底有没有学到。
概率是最容易被低估的。多数人会说条件概率、贝叶斯公式,但面试里真正想听的是:能不能把“看到证据之后信念怎么变”讲清楚。垃圾邮件那个经典例子,算到 0.75 不难,难的是顺手说一句,这个词把后验从 20% 推到了 75%,这就是更新。
朴素贝叶斯的独立性假设几乎从来不成立,但它仍然有用。原因是它把估计难度降到了可以接受的程度:参数少、训练快、小数据也稳。这是一个典型的工程取舍,用一个错的假设换一个能用的模型。面试里能说清“假设错在哪、为什么还能用”,比背公式更值钱。
贝叶斯的另一个用法是排查。线上某个指标掉了,先验是“大概是数据问题”,看到某个特征缺失率飙升之后,后验就该转向数据管道。这个思路比公式本身更常用:先有一个初始判断,再让证据按权重修正它,而不是每次都从零开始猜。
期望和方差也常被当成计算题。真正有用的是那个二分类的结论:预测概率 p 的方差是 p(1-p),p 接近 0.5 时最大。这解释了一个很实际的现象,边界样本难判断,不是因为模型笨,是因为这类样本本身携带的信息就少。做阈值、做风控、做人工复核排期的时候,这个直觉比公式值钱。
期望的题还常被包装成业务问题。两个策略,一个点击率高但转化低,一个点击率低但客单价高,选哪个。正确的做法不是比单个指标,是定义随机变量、乘上收益、算期望。很多人卡在这里,不是不会算,是没养成“先把指标翻译成收益”的习惯。
信息论是分水岭。熵、信息增益、KL 散度,公式都不长,但能把它们接到模型上的人不多。KL 不对称这件事,比公式本身更能看出有没有想过:用 Q 近似 P,和用 P 近似 Q,代价不是一回事。P 是高概率的地方 Q 给少了,罚得重;反过来 Q 抓住一个峰、放掉其他模式,有时反而“省”。这个差别不是数学洁癖,它直接影响变分方法里模型倾向于覆盖还是倾向于收敛到单个模式。
拿两个分布算一遍比看十遍定义有用。P 是 (0.9, 0.1),Q 是 (0.5, 0.5),前者到后者的 KL 大约 0.37,反过来大约 0.51。差得不多,但方向已经不同。这个不对称不是细节,它决定了模型在不确定的时候,是倾向于覆盖所有可能,还是押注一个最像的。
决策树那边,信息增益和 Gini 做的是同一件事,只是度量不同。熵带对数,解释更贴近信息论;Gini 不带对数,算起来更快,结论通常接近。两套标准没有对错,只有实现偏好。
还有一层关系值得说清楚:交叉熵等于真实分布的熵加上 KL 散度。真实分布固定时,熵是常数,所以最小化交叉熵就是在把预测分布往真实分布上拉。语言模型训练时那句“最小化交叉熵”,本质上就是这个意思。知识蒸馏用的也是同一套逻辑,只是把真实分布换成了教师模型的输出分布,因为软标签保留了类别之间的相对关系。
信息增益有一个坑,面试里很少有人主动提:它偏好取值多的特征。一个几乎能给每条样本单独分组的 ID,训练集纯度会非常高,但泛化很差。所以 C4.5 才引入增益率。能说出这一点,说明不只是记住了“信息增益越大越好”。
线性代数我反而不太看重推导。矩阵乘法在神经网络里不是算术,是空间映射:权重矩阵的每一列可以看成一个可学习的特征探测器,输入和这些方向做组合,得到新的表示。想清楚这一点,shape 报错就不再是语法问题,而是没搞清输入空间、输出空间和参数维度之间的关系。
我面试时会给一个两层网络的 shape,让对方标每一层的维度。这个动作很枯燥,但能看出他是不是真的想过计算过程。矩阵乘法的内维必须对上,这不是框架的限制,是定义本身。说不清这件事的人,写出来的代码通常靠试错跑通,改一层就崩。
再往上一层是特征分解和 SVD。它们回答的是“数据里哪些方向更重要”。PCA 之所以能降维,是因为数据云团沿某些方向变化最大,保留前几个主方向,就保留了大部分方差。工程上更常用 SVD,因为真实数据矩阵往往不是对称方阵,SVD 对任意矩阵都成立。做过 embedding 压缩的人对这件事会有体感:删掉的那些维度,很多确实只是在放大噪声。
注意力也是同一套语言。query 和 key 做点积得到相似度,softmax 归一化成权重,再对 value 加权求和。说穿了就是在一个向量空间里找相关方向。能把这件事讲清楚的人,通常也能解释为什么 embedding 需要归一化、为什么检索里常用余弦相似度而不是欧氏距离。
优化考的是训练行为。梯度给方向,学习率给步长。步长太小学得慢,太大在谷底两边弹,再大就发散。深层网络里的梯度消失,本质是连乘:每层乘一个小于 1 的因子,传到前面就趋近于零。这个解释比背“梯度消失”四个字有用得多,因为它同时指出了解法在哪:换激活、加残差、改初始化。
反向传播值得单独说一句。它的高效不是因为公式优雅,是因为复用了前向的中间结果,把梯度计算压到和前向同一量级。没有这一点,大模型训练根本不可能。理解到这个程度,优化器之间的差别就不神秘了:SGD 简单但容易抖,Momentum 加惯性,Adam 给每个参数自适应步长。Adam 通常更好训,但最终泛化不一定赢,这是选择,不是排名。
还有一个常被问的点:为什么不能用数值差分算梯度。参数量一大,每个参数都要前向一次,成本直接爆炸。反向传播把一次前向的中间结果复用下来,反向再走一遍,就拿到全部梯度。这个效率差别不是常数级的,是能不能训练的区别。
学习率是我调试时最常动的参数。太大,loss 前几步就震荡;太小,看起来在学,实际几乎不动。有没有用 warmup、batch 大小变了要不要跟着调,这些经验书上有,但手感和判断只能自己跑出来。
我把训练排查压成一个顺序:先看数据,标签有没有错位、特征有没有归一化、batch 是不是空的;再看前向,输出 shape、激活函数、loss 输入是否合理;再看反向,梯度是不是全零、有没有 NaN、梯度的范数是否异常;最后看优化,学习率、有没有清梯度、有没有真的调用 step。这个顺序救过我很多次,因为它把“模型不收敛”从玄学变成了一层层可排除的问题。
类别不平衡也是高频题。准确率在这种数据上没有意义,因为全预测成负类也能有很高的分。这时候要看召回、看 AUC、看不同阈值下的业务代价。能主动说出“先看业务更怕误杀还是漏杀”的人,通常比背指标定义的人更接近可用。
偏差和方差的取舍也不是理论问题。模型复杂度上去,偏差降、方差升;数据量上去,方差降。真正难的是判断当前卡在哪一边。我的经验是,先看训练和验证的差距,再看差距随数据量怎么变。如果加数据能缩小差距,多半是方差问题;如果两边都很差,多半是偏差问题。
统计学习负责收口。偏差高是模型太笨,方差高是模型太敏感,泛化是换一批数据还行不行。训练 99%、测试 82%,说“过拟合”只是及格。更重要的是先怀疑评估本身:切分是不是随机、有没有数据泄漏、两边类别分布一致吗。再谈模型复杂度和正则化。
我在真实项目里见过最多的一类误判,是拿离线指标解释线上问题。离线 AUC 涨了,线上坏账没降,原因可能是样本口径变了,也可能是审批策略同期调整过。这类问题数学本身回答不了,但没有数学,连该怀疑哪一层都不知道。
分布漂移是另一个常被忽略的点。训练时表现好、上线后慢慢变差,很多时候不是模型退化,是流量变了。这时候调模型没用,要先看特征分布和时间窗口。我现在的习惯是给关键特征加监控,漂移超过阈值就先查数据管道,而不是先重训。重训很快,但它只是把新分布记下来,不解决为什么变。
我会怎么问
如果让我面一个 AI 相关岗位,我大概只问三个问题,然后顺着回答往下追。
第一个:训练 loss 降不下去,按什么顺序查。
我想听的不是“调学习率”,而是有没有分层的意识。数据层的标签和归一化,前向层的 shape 和 loss 输入,反向层的梯度是不是全零、有没有 NaN,优化层有没有忘记清梯度、有没有真的 step。能按这个顺序走的人,多半真的跑过训练。
我还会追一句:如果 toy data 上都过拟合不了,说明什么。这题很狠,因为它把问题从“模型不够强”拉回到“链路有 bug”。答得出来的人,通常自己踩过。
第二个:离线 AUC 很高,上线之后坏账率反而涨了,怎么排查。
这题没有标准答案,我要看的是他会不会先怀疑口径。样本定义变了吗,标签有没有延迟,训练和线上的分布是不是同一批人,审批策略有没有同期改动。只会说“模型漂移”的人,通常没在真实链路上待过。
第三个:KL 散度为什么不是距离。
这题很便宜,但很好用。答得出不对称,说明他至少推过一遍;能接着说出这对优化行为的影响,说明他想过。
偶尔我还会问第四个:如果只能保留一个指标,留哪个。答案本身不重要,重要的是他会不会先问业务目标。风控场景留召回,营销场景留响应率,内容场景可能留停留。会说“看情况”并且说得出是哪种情况的人,通常比背标准答案的人可靠。
反过来,我自己也有答不上来的时候。变分推断的完整推导我记不住,ELBO 展开到第三行就开始含糊。我的做法是直接说记不住,然后讲直觉:用一个简单分布逼近复杂后验,用 KL 约束近似误差。多数面试官接受这种坦白,因为他们自己也不一定推得出来。
面完之后我会记三件事:有没有主动澄清假设,答不上来时有没有给出边界,有没有把答案落回具体场景。技术细节可以补,这三样很难补。反过来说,一个把每个问题都答成教科书的人,我反而会担心他没做过真实系统。
模拟面试我也会做,但重点不是答对,是练停顿。真实面试里,想三秒再答比脱口而出好,尤其在不确定的问题上。我会让对方把“我不确定,但我的思路是”这句话说顺,因为它在现场比任何技巧都管用。
我不太相信“满分回答”。一个能把边界说清楚、在不确定的地方停一下的人,比一个把所有问题都答得很顺的人更可靠。前者能看出他的知识边界在哪,后者往往要等上手之后才发现。
我自己的练习方式也很笨。拿两三个数的玩具样本,手推一遍梯度,再用几行代码验证;跑一个小模型,故意把学习率调大,看 loss 怎么炸;把交叉熵和 KL 分别算一遍,确认差值就是熵。这些动作不产出任何东西,但它们让公式变成了可观察的现象。
护城河这个词我不太喜欢
数学是底层语言,不是护城河。语言的价值在于能用它说清什么,而不在于别人不会说。
我见过数学很好但做不好模型的人,也见过数学一般但排障极快的人。后者的优势来自另一件事:他知道一个看起来对的答案可能错在哪里,并且愿意去验证。这种判断力不是刷题刷出来的,是在一次次模型失效、指标对不上、线上回滚里长出来的。
我也不觉得数学能单独构成壁垒。它更像门槛:过不了门槛的人很多,过了之后,大家差不多。真正分开人的是后面的东西:有没有把一个系统从数据跑到上线,有没有在指标不动的时候坚持查了三天,有没有在所有人都说“模型就这样”的时候找到一个数据管道的 bug。
数学之外还有一层东西,是品味。选择哪个指标、接受多大的误差、什么时候停止优化,这些没有公式。它们来自做过足够多的项目之后形成的判断。面试里很难直接考,但共事三个月就能看出来。
这些事跟数学有关,但它们的核心是愿意为不确定性负责。数学提供语言,工程提供证据,最后做判断的还是人。
而且我也不确定这个优势能维持多久。AI 现在已经在解释 KL、解释偏差方差,讲得比我清楚。等它连“这段训练代码为什么在 toy data 上都过拟合不了”也能稳定定位,面试考什么还会再变一次。
所以我不太担心 AI 把数学题做出来。它做得越快,越说明背公式这件事不值钱。真正值钱的是知道该用哪个公式、公式的前提成不成立、结果不符合预期时先怀疑哪一步。这些事需要有人对结果负责。
短期内不会变的是另一件事:当模型给出一个很像对的答案时,能判断它哪里不对的人仍然稀缺。这个能力需要数学,但不止数学。它还需要亲手弄坏过一些东西,并且记得它是怎么坏的。
评论