每年秋招一到,后台总有人问我计算机视觉岗的笔试该怎么准备。2018年秋季我参加过滴滴出行计算机视觉研发工程师的网申笔试,而且是第三批。说实话,第三批是个很微妙的时间点,前面两批已经考完,网上多少能搜到一些题目碎片,但第三批的考点和题目风格往往又和前两批不完全一样。计算机视觉方向的同学应该都有体会,校招笔试不像课程考试有明确范围,它考的常常是“你以为自己会,但一动手就卡壳”的东西。这篇文章我把这次第三批笔试的备考过程和做题思路完整记录下来,给后来投递这个岗位的同学做个参考,也顺便聊聊滴滴这类公司的CV岗笔试到底在筛什么人。
计算机视觉研发工程师表面上是算法岗位,实际上要干的活很杂,既要有数学和图像处理的基本功,又要能快速实现深度学习模型,还得用工程标准写出能上线的代码。滴滴的出行场景里,CV不是发论文,而是每天处理海量的图片和视频。所以笔试部分从来不是单一维度,而是数学基础、传统图像处理、机器学习/深度学习、编程能力四合一。下面我按一条完整的备考线展开,每一步都结合我当时踩过的坑和总结的规律。
1. 先看清岗位要求,再拆解第三批笔试
1.1 滴滴的计算机视觉,到底解决哪些真实问题
很多同学一听说“计算机视觉研发工程师”,第一反应就是目标检测、图像分类这些通用任务。但滴滴的业务场景对CV岗位的技术栈有很强的导向性。我当时在准备笔试前,先把滴滴出行App里跟图像视频相关的功能过了一遍,发现核心需求集中在几块:
- 司机身份与证照审核:行驶证、驾驶证OCR识别,人脸与证件照片比对,识别翻拍和伪造。
- 车内安全监测:通过车载摄像头检测疲劳驾驶、分心驾驶、打电话、吸烟等行为,这需要人脸关键点、头部姿态估计、手势识别。
- 行车记录仪与路面分析:车道线检测、车辆和行人检测、车位检测,甚至极端天气下的图像增强。
- 地图与POI数据:路边门店招牌识别、图像检索、图片质量打分。
- 司乘纠纷的证据分析:对用户上传的图片和视频进行分类、检索、关键帧提取。
这些场景决定了笔试不会只考深度学习。比如证件审核会用到图像预处理、直方图均衡化、形态学操作;车内监测会考到目标检测的轻量化设计,比如YOLO系列、NMS、模型量化;路测画面分析则可能涉及经典边缘检测和透视变换。所以准备笔试时,不能盲目刷算法题,要先想清楚这家公司的CV岗位在业务里承担什么角色,再倒推考点。
1.2 第三批笔试:晚投不意味着简单
很多人把第三批理解为“补录批”,觉得前两批大神都走了,第三批应该轻松一点。我参加过之后只想说:别被批次迷惑了。企业设置多个笔试批次,核心原因是网申时间跨度大,并不是按先来后到排序。第三批里既有第一批失手后重新投递的同学,也有刻意准备充分、专门选后面批次的高手。而且第三批的题目往往会在前两批基础上做微调,出现“影子题”的概率很高——题目场景变化了,但考点内核不变,比如把“车辆检测”换成“行人检测”,把二维框换成旋转框。
所以我的建议是:第三批备考,一定要把前两批的回忆帖当作最重要的线索,但不能背题。我当时的做法是,把网上的零散信息整理成一个考点清单,按“出现次数”和“我不会的程度”排序,再针对高频考点逐个攻破。先把这些帖子当成地图,而不是答案,就稳了一半。
2. 计算机视觉研发岗笔试考点全拆解
2.1 数理基础:矩阵、概率、优化,一个都不能少
第一次做模拟题的时候,我发现很多看似“AI问题”的背后全是数学题。数理基础在笔试里通常以选择、填空和简答推导的形式出现,考察的不是死记硬背,而是能不能理解模型为什么成立。
线代部分最常出现的三个点:矩阵求导、特征值分解、奇异值分解(SVD)。比如PCA与SVD的关系经常会以选择题出现,答案核心是“对样本矩阵做SVD,右奇异向量就是主方向,奇异值对应方差贡献”。再比如卷积操作本质上是矩阵乘法,卷积核的旋转、翻转都是在做矩阵变换。我当时把线代教材的前五章快速过了一遍,重点看几何意义而不是套公式。
概率论部分,贝叶斯公式、高斯分布、最大似然估计是必考。有一道比较经典的简答题:给定N个独立同分布的高斯样本,求均值和方差的最大似然估计。答题时先写出似然函数,再取对数,分别对均值和方差求导,令导数为零。均值的估计是样本均值,方差的估计是样本方差除以N,注意这里和统计学里的无偏估计不同,无偏估计分母是N-1。这个差异极易踩坑,笔试时如果能主动指出“最大似然估计的方差有偏,但工程上仍常用”,会显得理解更深一层。
优化部分主要考梯度下降、SGD、学习率策略、梯度消失和爆炸。比如为什么深度网络要用ReLU而不是Sigmoid?除了计算快,更重要的是ReLU在正区间梯度恒为1,能缓解梯度消失。这类题其实是在考察你训练过真实模型,而不只是背概念。
| 考点 | 常见考查方式 | 易错点 |
|---|---|---|
| SVD与PCA | 选择题、简答 | 混淆左奇异向量与右奇异向量的含义 |
| 极大似然估计 | 推导题 | 方差估计忘记除N还是N-1 |
| 贝叶斯公式 | 选择题 | 后验概率计算漏项 |
| SGD与批量梯度下降 | 简答 | 忘记说明小批量带来的噪声作用 |
| 梯度消失 | 简答 | 只说ReLU,没有提初始化与BN |
2.2 经典图像处理:深度学习时代的“硬通货”
很多同学觉得有深度学习就够了,传统图像处理可以跳过,但滴滴这类公司的笔试实际上很偏爱传统图像处理。因为真实业务数据里充斥着低光照、模糊、反光、遮挡,模型再强也需要先做好预处理,而很多问题用经典算法就能快速解决。
高频考点之一是图像滤波。均值滤波、高斯滤波、中值滤波的区别要熟记:高斯滤波适合去除高斯噪声,中值滤波对椒盐噪声特别有效。很多时候会给你一个小矩阵,让你手写3x3中值滤波的输出结果。这种题必须注意边界,通常做法是补零、复制边界或忽略边界,题目若不说明,默认使用补零是比较稳妥的。
边缘检测也是常客,尤其是Canny算子的五个步骤:高斯滤波降噪、用Sobel等算子计算梯度幅值和方向、非极大值抑制、双阈值检测、边缘连接。简答题如果问“Canny为什么不直接用Sobel结果”,要答出Sobel得到的边缘过宽,非极大值抑制能瘦边,双阈值能减少断点和伪边缘。
特征点方面,SIFT为什么具备尺度不变性?因为它在构建图像金字塔后,对每一层做DoG(高斯差分),并在空间和尺度两个维度上寻找极值点。ORB则是Fast角点加BRIEF描述子,速度更快但存在尺度瓶颈。笔试可能让你比较SIFT和ORB,核心从旋转不变性、尺度不变性、速度、专利限制几个维度展开。
还有直方图均衡化,定义很简单,但为什么能增强对比度?因为均衡化的本质是让灰度直方图尽可能均匀分布,把集中在一个区间的像素拉伸到整个灰度范围。工程里判断图像是否模糊,常用拉普拉斯算子计算二阶导数的方差,方差越低越模糊。这些经典知识不需要写完整代码,但要能清晰地讲出步骤和适用场景。
2.3 机器学习与深度学习:从“调包”到“懂原理”
这部分是笔试的大头,也是最容易拉开差距的地方。我备考时把机器学习的基础模型和深度学习经典结构都列了出来,每个都按“是什么、怎么用、为什么有效”三句话过了一遍。
传统机器学习部分,逻辑回归必考。常见的问题包括:为什么要用交叉熵损失,而不是均方误差?因为逻辑回归的预测值是经过Sigmoid变换的,如果使用MSE,损失函数是非凸的,梯度更新容易陷入局部最优;而交叉熵配合Sigmoid时,梯度形式简洁,能有效学习。SVM常考核函数的作用:把低维空间线性不可分的数据映射到高维,使其线性可分。这里要补充一句,核函数不是万能的,高维映射也容易过拟合,所以有了软间隔和惩罚系数C。
决策树、随机森林、GBDT也经常出现。比如“随机森林的随机性体现在哪里?”答案有两个:样本随机有放回抽样,特征随机选择。GBDT和随机森林的区别则要强调串行与并行、拟合残差与投票平均。这类题在笔试中出现时,如果时间充裕,最好举例说明,比如“预测年龄,随机森林是问多人后取平均,GBDT是每次修正上次的预测偏差”。
深度学习基础不可回避。反向传播要能推导一个简单两层的例子,理解链式法则。CNN要能计算感受野和参数量,尤其是5x5卷积和两个3x3卷积堆叠拥有相同的感受野,但参数更少、非线性更强,这是面试和笔试的高频点。BN层的作用可以从三个方面答:加速收敛、允许更大学习率、对初始化不那么敏感,同时它把每个batch的特征分布拉回标准正态分布。Dropout训练时随机失活神经元,测试时不失活,但要对权重乘以保留概率,我的经验是笔试里要在公式层面说清这一点。
目标检测是CV岗位的重头戏,必须熟记Faster R-CNN、YOLO、SSD的核心区别。R-CNN系列是两阶段,先生成候选区域,再分类和回归,精度高但速度慢;YOLO是一阶段,直接回归边界框和类别,速度快但小目标效果一般。我总结的答题套路是:网络结构、正负样本定义、损失函数、后处理NMS、评价指标mAP、优势和局限。如果题里问“如何改进YOLO对小目标的检测”,可以考虑多尺度特征融合、增加anchor数量、提高输入分辨率三种方向,每题尽量答三点以上,显得有工程思路。
图像分割也很重要,FCN把全连接层换成卷积层,可以接受任意尺寸输入;U-Net通过跳跃连接把浅层细节和深层语义融合,在医学和遥感小样本场景表现好。笔试里如果问语义分割与实例分割的区别,不要只回答“像素级 vs 个体实例”,要强调实例分割通常需要先检测目标再做分割,代表方法是Mask R-CNN。
2.4 编程与算法题:笔试的“分水岭”
编程题是最考验临场发挥的部分。第三批的编程题我印象里没有太偏的竞赛题,更多是基础数据结构加一点图像处理的味道。常考的题型包括:
- 字符串与数组:最长公共前缀、小数组的峰值、快慢指针。
- 滑动窗口:给定一个数组和窗口大小,求每个窗口的最大值。
- 二叉树:层序遍历、最大深度。
- 图像处理实现:实现高斯滤波、计算两个矩形的IoU、最近邻插值缩放。
以IoU为例,这是我强烈建议每个人都能手写的代码。IoU定义是两个矩形交集面积除以并集面积,看起来简单,但边界条件特别多。下面这个版本在我当年的笔试里直接能跑通:
def iou(box1, box2): # box1, box2: [x1, y1, x2, y2] x1_min, y1_min, x1_max, y1_max = box1 x2_min, y2_min, x2_max, y2_max = box2 xx1 = max(x1_min, x2_min) yy1 = max(y1_min, y2_min) xx2 = min(x1_max, x2_max) yy2 = min(y1_max, y2_max) inter_w = max(0.0, xx2 - xx1) inter_h = max(0.0, yy2 - yy1) inter_area = inter_w * inter_h area1 = (x1_max - x1_min) * (y1_max - y1_min) area2 = (x2_max - x2_min) * (y2_max - y2_min) union_area = area1 + area2 - inter_area if union_area <= 0: return 0.0 return inter_area / union_area代码里的关键点在于,计算交集宽高时用max(0, ...),保证不相交时交集面积为0;并集面积等于两框面积之和减去交集面积,分母为0时返回0。很多同学只写核心公式,忽略分母为零保护,在真实笔试里会扣鲁棒性的分。类似地,滑动窗口最大值可以用单调队列实现,保证均摊O(n)复杂度。笔试时如果时间紧张,我一般先写暴力解,再标注“可用单调队列优化到O(n)”,这样至少能拿到大部分用例分。
3. 第三批笔试的备考实操细节
3.1 从网申到开考,三周复习规划表
第三批笔试一般会在网申截止后一周内发出,从你决定参加那一刻到正式开考,通常有两到三周。我把自己当时用的计划表整理成了下面这个模板,适用于基础中等偏上的同学:
| 阶段 | 时间 | 重点任务 | 产出物 |
|---|---|---|---|
| 第一周 | Day1-7 | 数学基础、经典图像处理、传统机器学习 | 错题清单、公式卡片 |
| 第二周 | Day8-14 | 深度学习理论与目标检测、编程题刷题 | 模型对比笔记、2道/天代码实践 |
| 第三周 | Day15-21 | 模拟套题、简答题表达、错题复盘 | 3套完整模拟记录、易错点汇总 |
第一周不用急着刷编程题,重点是查漏补缺。我用周末两天把线性代数、概率论的考试型知识点过了一遍,周一到周三集中过图像处理,周四周五整理传统机器学习,每天睡前把当天模糊的知识点写成一句“人话卡片”。这里说的人话卡片不是抄定义,而是用自己的语言描述概念,比如“SVD就是能把任意矩阵分解成旋转+缩放+旋转,奇异值就是缩放因子”。只要你能不看资料写出解释,说明真的理解了。
第二周开始刷代码,我给自己定的目标是每天做2道LeetCode中等题加1道图像处理实现题。刷题时不要只看题解,必须自己跑通。LeetCode不用刷完,但以下类型必刷:数组、字符串、链表、二叉树、滑动窗口、动态规划基础。图像处理实现题可以自己造数据,比如生成一个随机矩阵,再用OpenCV的结果和自己写的函数对比,这个过程能快速暴露边界处理问题。
第三周的核心是模拟笔试。我在牛客和公司笔试平台上找了几套往年的在线模拟题,严格按照正式笔试的时间和环境来做。模拟时手机放远处,不开搜索,遇到不会的题先跳过,模拟结束后再复盘。这个阶段最重要的是练“取舍感”:知道什么题先做,什么题可以直接放弃。
3.2 用“知识卡片”管理考点
考点太多,靠一本笔记本翻来翻去效率太低。我把所有高频考点都做成了卡片,每张卡片固定包含四栏:考点名称、一句话解释、常见问法、我的死穴。举个例子:
- 考点名称:NMS(非极大值抑制)
- 一句话解释:在检测结果中,保留局部得分最高的框,删除与其他高分框重叠过大的框。
- 常见问法:NMS的不足?如何改进?——不足是密集场景下容易误删,改进方向包括Soft-NMS、基于IoU的加权合并。
- 我的死穴:曾经忘了说阈值通常是0.5,以及如何选择阈值。
我用的是Excel,因为可以按考点名称排序,也可以筛选。考前半小时把“我的死穴”这一列单独过一遍,效果比临时翻书好得多。如果自制力强,也可以用Anki做成间隔重复卡片,每天自动提醒。
3.3 在线笔试做题顺序与时间分配
正式笔试的题量通常不小,我记得当时单选、多选、简答、编程都有,总时长约120分钟。我的做题顺序是:先写编程题,再做简答题,最后做选择题。理由很简单:编程题分值大,且思路如果被打断,重新进入状态需要好久;选择题虽然多,但单题分值小,会的快速选,不会的可以先标记跳过。
时间分配上,我会按每道编程题20分钟、每道简答题10-15分钟、选择题平均每题1分钟来做。如果一道选择题超过3分钟还没思路,直接跳。如果编程题卡在某个奇怪的bug上,先写一个暴力解法保住部分用例,不要追求第一版就是最优解。我在模拟测试时发现,很多人最后考砸不是题不会,而是前面选择题纠结太久,编程题只剩15分钟,手忙脚乱写不完。
在线笔试还有一个容易被忽视的问题:代码编辑器的自动补全不一定好用。如果平时用IDE习惯了,突然切换到在线编辑器,API的拼写很容易出错。建议在模拟阶段就用和正式考试一样的在线编辑器,把常用库(比如Python的numpy、collections)的手写方式过一遍,至少要知道有哪些方法,不至于现场想函数名。
4. 笔试中的避坑指南与后续准备
4.1 环境与入场检查清单
滴滴这类大厂在线笔试通常会有摄像头监控或屏幕录制,对网络要求不低。我第三次模拟时因为宿舍Wi-Fi不稳定,中途断线一次,被迫重新登录,幸好题目做了保存。建议考试当天提前30分钟做以下准备:
- 笔记本插上电源,关掉所有弹窗软件和下载任务。
- 提前用手机热点做备用网络,台式机可准备一个USB无线网卡。
- 在书桌边放草稿纸和黑笔,允许使用草稿纸,但一般不允许用计算器。
- 提前登录笔试平台,测试摄像头、麦克风和浏览器兼容性。
- 找一个安静的时段,如果宿舍太吵,可以考虑图书馆讨论室或预约自习室。
笔试开始后,如果遇到技术问题,立刻截图并通过平台客服或者邮件联系,保留证据。大多数公司会安排重考,但前提是你别慌,先把问题反馈清楚。
4.2 代码提交的隐性扣分点
编程题不是只判暴力对错,还会看代码风格和边界条件。我参与过几次代码评审,发现应届生代码最容易出现三个问题:变量名写成a、b、c;没有考虑输入为空或者长度为1的极端情况;不写注释,逻辑全靠面试官猜。笔试时当然不需要写工程级注释,但关键步骤加一行注释,能让你的思路更清晰,也方便自己回头检查。
比如前面IoU代码中,我专门写了if union_area <= 0: return 0.0,这就是一个明显的鲁棒性体现。再比如实现图像滤波时,如果图像边缘处理不当,很容易报索引越界。一个加分做法是开头的注释写明“边界采用补零处理”,哪怕实现时用最简单的方式,面试官也能看到你理解这个问题。
此外,除非题目明确允许使用OpenCV、numpy等库,否则核心算法要自己实现。有些同学直接调cv2.GaussianBlur完成高斯滤波,虽然代码很短,但笔试大概率不给分。因为这类题目考的就是你懂不懂原理,调用库没法体现。
4.3 笔试后的复盘与面试衔接
笔试结束后,最忌讳对完答案就彻底放下。我一般会做两步:第一步,把考场上所有不确定的题目和答案抄进一个文档,标注“当时犹豫的点是什么”;第二步,把犹豫点对应的知识点回到课本或文档里查一遍,写成“一句话理解”。这一步非常关键,因为笔试中暴露的模糊点,往往就是面试官最喜欢追问的深度盲区。比如当时我在“BN层在训练和测试时有什么区别”这道题上犹豫很久,后来笔试复盘发现我对测试时使用全局均值和方差理解不够,于是重新推导了一遍,结果面试时真被问到了。
另外,考完如果感觉通过率不大,也别灰心。校招是持久战,一批笔试不代表最终结果。我知道有同学第一批笔试没发挥好,后来面试表现不错照样拿到offer;也有在第三批笔试中发现基础薄弱,经过一个月补课,在终面逆袭的。笔试最大的价值是逼着你系统过一遍基础,不管最后进没进面试,这个积累都是硬通货。
我个人印象最深的一点是,滴滴第三批笔试里的很多题目,并不需要你会多么高深的模型,而是考察你有没有真正上手处理过图像数据。只要你平时动手写过预处理、训练过模型、调过损失函数,再经过系统的考点梳理,这套笔试没有想象中那么难。最后再分享一个小技巧:每次模拟完笔试,我会花半小时把错题和模糊题抄进一个“一句话笔记”,按“考点—我的错误—正确理解”的格式记录。考前只看这一页,比翻厚书有用得多。如果能把这份笔记坚持做完整轮秋招,你收获的绝对不只是offer,而是一套属于自己的知识复盘体系。