最近面了某出行大厂的CV算法工程师实习岗,整场面试下来最大的感受是:这和学校里的考试完全是两码事。面试官不会问你“背下来了吗”,而是会直接扔给你一个业务场景,让你现场拆解,再抛出一堆算法细节追问,直到你暴露知识盲区为止。我前后准备了三周,把常见的深度学习八股、手撕代码题和项目深挖都过了一遍,最后拿到了实习offer。这篇文章就把我完整的面试经历、准备思路和踩过的坑复盘一遍,给准备冲CV算法实习的同学一个参考。
1. 先把这场面试的底摸清楚:流程、岗位和考什么
1.1 实习面试和校招社招的区别在哪
很多人一听到“算法工程师面试”就慌,觉得要准备系统设计、要刷几百道题、要把整个深度学习框架源码都读一遍。其实实习面试的考察逻辑完全不一样。
实习岗的核心考察点就三个:基础扎不扎实、项目是不是真做过、上手能不能干活。面试官心里很清楚,实习生不等于正式员工,不可能指望你入职第一天就独立负责一个业务模型。他们想确认的是,你来了之后不需要手把手教基础概念,给你一个小任务你能自己查资料、调参、跑通实验。
所以整个面试流程也比较精简,我这次走的是:简历筛选 → 一面技术面 → 二面技术面 → HR面。一面主要抠基础,二面侧重项目深度和业务场景,HR面就是常规的行为面。相比校招的五六轮面试,实习面试节奏快很多,但也正因为快,每一轮都要在有限时间内充分展示自己,答得不好就很难有挽回余地。流程虽短,面试官问的问题却一点不含糊。
1.2 出行场景CV岗的特殊性
在面这家公司之前,我以为CV算法工程师就是做目标检测、图像分类这些通用任务。面完才意识到,出行领域的CV岗有非常强的业务属性,甚至可以说,业务理解能力比模型能力更稀缺。
出行场景的视觉任务有几个特点。数据来源复杂,有车载摄像头、路侧设备、驾驶员监控摄像头等多种设备,不同设备的视角、分辨率、光照条件差异巨大。实时性要求高,很多算法要跑在车端或边缘设备上,推理延迟压得很低,模型还要做量化、剪枝、蒸馏这类部署优化。场景长尾问题突出,极端天气、遮挡、夜间低光照、突发路况,这些在公开数据集里很少见,但在真实道路上每天都会遇到。
这就决定了面试时面试官不只会问“你怎么把mAP刷高”,还会追问“你这个模型在夜间效果怎么样”“换一个摄像头视角还能work吗”“推理速度能不能达到实时”。如果只会在服务器上用GPU跑实验,对这些实际问题完全没有概念,面试会比较被动。
2. 算法基础才是压舱石:面试官最常考的八股
2.1 卷积网络和基础结构
一面刚开始,面试官就问了一个看似人畜无害的问题:“ResNet为什么能解决梯度消失?”
这个问题我准备过,但面试官想要的答案其实分三层。第一层是残差结构本身,跳跃连接让梯度可以直接回传,缓解了深层网络的梯度消失问题。第二层是恒等映射,残差模块让网络在最差情况下也能学到恒等映射,性能不会比浅层网络差。第三层是实际训练中的表现,加了残差之后网络收敛更稳定,才能把网络叠到50层、100层甚至更深。
如果只答第一层,面试官会继续追问细节。“为什么跳跃连接能让梯度回传?”“如果残差分支和主分支的shape不一致怎么办?”这些问题看似延伸,其实都是在考察你有没有真正动手搭过网络,而不只是看过结构图。
除了ResNet,面试官还追问了BN层的原理。这个也是老生常谈,但要答得让面试官满意,得说清楚三件事:训练时为什么要按batch计算均值和方差、推理时为什么用全局统计量、BN为什么能加速收敛。这里可以打个比方:BN就像是把散落在不同量级的数据统一拉到同一个尺度的尺子上,让网络参数更新的时候不会因为输入分布飘忽不定而震荡。
我建议准备CV方向面试的同学,把下面这些基础问题全部过一遍,不要只记结论,要能用自己的话把原理讲清楚:
- 卷积层参数量怎么算,FLOPs怎么算,感受野怎么变化
- 1x1卷积的作用,为什么能改变通道数
- 池化层的作用,最大池化和平均池化各自适用场景
- 常用的激活函数对比,ReLU为什么能缓解梯度消失,又有什么缺点
- Dropout训练和推理时的行为差异,为什么推理时要乘概率系数
- 各种归一化方式的区别,BN、LN、GN分别适用什么场景
2.2 损失函数、优化器与调参
面试官第二个问题集中在目标检测任务上:“你用过的检测模型里,正负样本不平衡怎么解决?”
这个问题几乎必问。检测任务的训练样本天然就是正样本极少、负样本极多,如果直接用交叉熵损失,模型会被大量易分类的负样本淹没。解决方案也很成熟:Focal Loss、OHEM、ATSS的样本匹配策略等。
我当时讲了自己在项目里用过Focal Loss,面试官立刻追问:“你Focal Loss的超参怎么调的?alpha和gamma设了多少?效果提升多少?”
这就考到了实操细节。我确实调过,回答说gamma设为2.0,alpha设为0.25,相比默认的交叉熵,在模型难以分类的困难样本上召回率提升了几个点。这个回答面试官是认可的,因为这说明我不是只在论文里看过Focal Loss,而是真在训练脚本里改过参数、看过loss曲线变化。
优化器方面,面试官问到了Adam和SGD的区别。这个问题看起来基础,但想答好也不容易。不能只说“Adam自适应学习率,SGD要手动调学习率”,要说出两者的本质差异:Adam是动量和自适应学习率的结合,更新方向是梯度的一阶矩和二阶矩的比值,收敛快但泛化性有时不如SGD;SGD更新方向是真实梯度的方向,虽然更新慢,但配合良好的学习率调度往往能收敛到更平缓的极值点,泛化性能更好。
这里有个经验之谈:现在的训练实践里,很多模型依然会用SGD配合warmup和cosine学习率调度,而不是无脑上Adam。新手容易踩的坑是把Adam当万能解,结果在检测任务上mAP始终上不去,换成SGD加合适的调度策略反而涨点。面试官其实很爱问这类“你在实践中踩过什么坑”的问题,因为这是区分“背八股”和“真做过”的试金石。
2.3 归一化与正则化
一面还问了一个我没想到的问题:“训练集和测试集的图像分布不一致怎么办?”
这个问题看起来是数据问题,其实考察的是归一化和正则化的综合理解。我当时答了几层意思:预处理阶段的归一化参数要统一,不能用训练集的均值和方差直接套在测试集上,要统一统计;模型层面的对抗域适应,用Domain Adversarial Training让特征提取器学到域不变的特征;数据增强层面的随机遮挡、色彩抖动、风格迁移等,让模型对域变化更鲁棒。面试官听完之后说“这个思路是对的”,然后就没有继续深挖了。所以这块我复盘的经验是:遇到开放性问题不要慌,先把答案拆成数据、模型、训练策略三个层面,每一层给出对应方案。这比憋一个大而全的空泛回答更有效。
3. 手撕代码:不光是LeetCode,还有numpy
3.1 面试前的刷题策略
CV算法工程师的手撕代码环节和纯后台开发岗不一样。纯后端的LeetCode刷题频率很高,但CV岗经常考算法实现类题目,比如手写NMS、手写IoU计算、手写卷积操作、手写反向传播推导等。我这次一面遇到的是“手写numpy实现的NMS”,二面遇到了一道LeetCode中等的动态规划题。
所以准备策略要有针对性:以常见CV算法实现为主,LeetCode热题100里的简单和中等题为辅。不要花太多时间在困难题上,面试官自己也知道,45分钟的面试时间很难让候选人写出一个完美的最优解,他们更看重代码风格、边界条件考虑和思路表达。
刷题的时候我建议做两件事:第一,把NMS、IoU、非极大值抑制、BN前向计算、卷积前向计算、上采样最近邻插值和双线性插值这几种经典实现全部手敲一遍,敲到闭着眼睛能写出来的程度。第二,每道题都先讲思路再写代码,模拟面试时的状态,因为面试官会更关注你的思考过程。
3.2 实际遇到的手撕题
先是NMS这道题。题目很直接:给定一组检测框的坐标和置信度分数,实现非极大值抑制,输出保留的框索引。这道题我练过很多遍,写法比较固定:先按分数从高到低排序,然后依次选取当前最高分的框,计算它和剩余框的IoU,把IoU大于阈值的框剔除,重复这个过程直到遍历完所有框。
这里有几个坑是面试官专门埋的:
- IoU计算时交集区域的坐标要取max(0, x2 - x1)处理,不能直接用负值
- IoU阈值不是死的,不同任务取值不同,检测任务一般0.5,行人检测有时用0.3,NMS在关键点检测任务里还有变体
- 输入框的坐标格式要确认清楚,是[x1, y1, x2, y2]还是[x, y, w, h],写错了整道题就错了
我写完后面试官又问了一个变体:“如果检测框数量很大,比如一万个框,你的实现会不会慢?怎么优化?”
这个问题考察的是复杂度意识。我当时回答可以用GPU并行计算每个框和当前最大分数框的IoU,然后一次性mask掉需要抑制的框,这样复杂度能从O(n²)降下来。面试官点了点头,说如果数据量大确实要用向量化实现。这个追问其实不算难,但如果你没有写过numpy的向量化代码,很可能答不上来。
二面的手撕题是一道动态规划,类似打家劫舍的变种,难度中等。这种常规题只要刷过LeetCode热题基本没问题,关键是写之前先和面试官对齐思路:“我先定义dp[i]表示什么,状态转移方程是什么,初始条件是什么,时间复杂度是多少。”把这一套讲清楚,代码写得慢一点都不会扣分。
还有个小建议:手撕代码之前,先问清楚输入输出的格式、边界条件、是否能修改原数组。这既是为了自己写得更稳,也是让面试官看到你有工程意识,不是只顾着实现不管接口设计。
4. 项目深挖:怎么把一个项目讲清楚
4.1 项目陈述的结构
二面的大半时间都花在项目深挖上。面我这家公司时,面试官对项目细节的追问非常细,几乎每个环节都会被追问“为什么这么做”和“如果不这么做会怎样”。
我讲的项目是一个图像分割方向的研究课题,用到了U-Net结构做语义分割。一开始我按照论文式的逻辑讲:任务背景、现有方法的问题、我的改进思路、实验结果对比。讲完第一轮之后,面试官开始逐段追问。
第一个追问就是:“你为什么要用U-Net不用DeepLab系列?”
这个问题其实挺考验理解的。我当时的回答是:我的任务是小目标分割,U-Net的编码器-解码器结构配合跳跃连接可以保留空间细节信息,对小目标更友好;DeepLab系列虽然感受野大,但decoder对细节的恢复能力不如U-Net灵活。面试官对这个回答基本满意,因为我没有背对比表格,而是从任务需求出发做了选型。
第二个追问是:“你的分割结果里,边缘部分为什么会模糊?如果让你改进,你会改哪个模块?”
这是典型的“提出方案→追问局限→让你改进”的深挖套路。我当时老老实实说了自己的观察:边缘模糊主要是下采样过程中丢失了高频信息,跳跃连接虽然缓解了一部分,但在深层特征里边缘细节已经被平滑掉了。改进方向可以把深层特征和浅层特征做更充分的融合,或者加一个边缘监督分支来约束边界学习。面试官继续说“听起来有道理,你实际试过吗”,我承认没有实现,但给出了一些理论上的可行性分析。这种问题不要求每个改进都落地过,但要让面试官觉得你对模型的机制理解是清晰的。
4.2 面试官角度关注什么
面试官深挖项目其实就为了确认三件事:项目是不是你自己做的、你对技术的理解深度如何、你在团队中能不能推进问题解决。
判断“是不是自己做的”最直接的方法就是追问细节。比如问你数据怎么标注、样本量多大、模型训练多长时间、显存占用多少、有没有试过更小的模型。这些问题只要真的跑过实验,随口就能答上来,掺不了假。如果你的项目是纯调包调参跑出来的,这些细节一问就露馅。
“对技术理解深度”的考察更隐蔽。面试官提到自己在项目中用了注意力机制,面试官就会追问:“注意力的本质是什么?self-attention和CBAM这种attention有什么区别?你用了之后涨了几个点?”我当时回答的时候说attention的实质是给不同位置的特征加权,self-attention的权重是动态计算的,和位置无关,CBAM是通道和空间维度的静态加权。面试官听完之后评价说“理解得还算到位”。
这里有个很实用的经验:在介绍项目时主动说出自己的思考和权衡,而不是等着被问。比如主动说“我当时对比了A方案和B方案,A方案虽然精度高但推理速度慢,考虑到部署环境我最终选了B方案”。这样既展示了决策能力,又把话题引到了自己熟悉的领域,面试官大概率会顺着你的思路继续问,你就能掌握话语主动权。
5. 业务场景题:出行公司的CV面试特色
5.1 场景题怎么答
CV算法实习面试里,场景题往往比基础题和代码题更能拉开差距。基础题大家都能背,代码题大家都能刷,但场景题考察的是“拿到一个模糊的业务问题,你能不能拆解成技术方案”的能力。
这类问题常见的有:“我们要做驾驶员的疲劳监测,你会怎么设计算法方案?”“路侧摄像头拍到的画面里小车被大车遮挡了,你有什么办法恢复检测?”“我们要做一个车流量统计系统,摄像头角度比较刁钻,你怎么办?”
我第一次面这类问题的时候很慌,因为在学校里都是拿到明确的任务和明确的数据集,很少有这种开放式问题。后来我发现一个万能的回答框架:
- 明确任务目标和约束条件,包括精度要求、实时性要求、部署设备
- 拆解技术方案,数据采集和标注怎么设计,模型选什么结构,怎么训练,怎么做部署优化
- 充分考虑边界情况,光照变化、遮挡、极端天气怎么处理
- 给出效果评估方案,用什么指标,怎么在真实场景中验证
5.2 实际业务题
我当时遇到的一道题是:“如果车辆行驶过程中,前挡风玻璃上的摄像头要检测前方行人,你怎么保证检测的准确率?”
我按上面的框架答了一遍:检测方面用YOLO系列或更轻量的检测模型,训练时加入夜间和逆光的数据增强,部署时做量化提升帧率;行人和背景的区分对运动信息和时序信息有帮助,可以考虑前后帧的关联;遮挡场景引入跟踪模块,避免单帧检测丢失导致漏检。
面试官又问:“如果检测和跟踪的结果冲突了,你信谁?”
这个问题答得不太好,我当时犹豫了一下说“应该信检测的,因为跟踪是依赖检测的”。面试官笑了笑说“也不一定,要看置信度谁高”。后来我复盘了一下,这种问题没有绝对正确的答案,关键是要有判断思路:可以比较检测框的置信度和跟踪框的置信度,也可以利用多帧历史信息判断哪种状态更稳定。重要的不是给出标准答案,而是展示出“面对不确定情况时做决策”的能力。
还有一道让我印象很深的问题是:“你做的模型在公开数据集上效果很好,但到了真实道路上效果变差了,你会怎么排查?”
这个问题其实是考察工程经验。我回答了几个方向:数据分布不一致导致的域偏移,用错误样本分析来确认是哪些场景出了问题;模型过拟合,在公开数据集上刷得太狠导致泛化能力差;预处理差异,训练时的图像尺寸、归一化方式和部署链路不一致,等等。面试官让我具体分析一个重要原因,我说了预处理链路,因为车端图像从sensor采集到送入模型要经过很多环节,任何一个环节的尺寸、格式、色彩空间不一致都可能造成性能暴跌。这个回答应该算在点子上。
6. HR面与心态管理
6.1 HR面问什么
过了两面技术面之后就是HR面。HR面虽然不考技术,但千万不要掉以轻心。我见过有人在HR面因为沟通问题被挂掉的,不是能力不行,是态度和表达出了问题。
HR面问的问题一般包括自我介绍、为什么选择这家公司、为什么选择这个岗位、实习时间能保证多久、对加班什么看法、职业规划是什么。这些问题看起来很简单,但回答的时候有几个原则:
不要贬低过去的经历。如果之前在某家公司实习过但离开了,不要说那边坏话,而是说想尝试不同的场景、接触更核心的业务。
不要暴露不稳定的态度。比如问职业规划时,不要说“我就是想先找个实习干干,后面看情况”。更合适的表达是:“我对计算机视觉方向有长期兴趣,希望在出行场景里积累实际业务经验,同时提升自己的算法工程能力。”
实习时长问题要提前想清楚。技术面过了但HR面因为时间对不上被挂的案例每年都有,尽早明确自己能到岗的时间、每周能实习几天,爽快沟通,不要支支吾吾。
6.2 面试期间的节奏
面试的前中后期节奏也很影响结果。前期投简历不要海投同一条业务线的多个岗位,系统里会被标记为重复投递,反而降低通过率。面试前花半小时把简历里的项目过一遍,准备几个“我最大的收获”“最有挑战的问题”这样的自我介绍素材,避免第一句话就卡壳。
整个面试过程要记住一个核心原则:面试是对话,不是审讯。遇到不会的问题就说不会,然后补一句“我目前的理解大概是这样,但我还没深入到这个层面,之后可以查一下”。生硬地编造答案反而会让面试官对你的可信度打折扣。我这次面试有三四个问题答得不太完整,但没有影响最终结果,因为在其他问题上证明了自己确实有项目实操能力和解决问题的思路。
技术上准备充分,心态上保持不卑不亢,面试官其实是很愿意通过一个实习生的,他们并不指望你完美,而是希望看到一个可培养、有自驱力、沟通顺畅的候选人。
7. 我复盘出的几条独家经验
面试结束之后,我花了一天时间把整个过程复盘了一遍。写这篇文章的时候,又把当时的笔记翻出来看了看,发现有很多经验值得单独拎出来说。
第一,基础知识不要只背结论,一定要能推到公式层面。面试官问BN的工作原理、问梯度消失、问残差连接为什么有效,都会继续往下追问一两层。如果你能当场在白板上画出计算图或者写出关键公式,面试官对你的印象分会明显提升。
第二,CV方向的项目不要贪多,把一个项目吃透比写十个泛泛的项目有价值得多。面试官在二面时深挖了一个项目,前前后后问了将近半小时。如果这个项目不是你自己一步步做下来的,半小时的追问很难不露馅。
第三,投递实习的时间窗口要把握住。一般提前一到两个月投递比较合适,太早岗位还没放出来,太晚很多名额已经招满了。面试也是双向选择,面挂了不要自我怀疑,换个岗位、换个团队继续面,很多同学最后都是面了好几轮才拿到满意offer。
第四,准备一份简洁直观的项目展示材料,哪怕只是几张示意图和指标表格,面试时放在手边。面试官问到细节时你能快速翻到对应的数据,展示出你的组织能力和专业性。这个习惯帮我省了很多临场思考的时间。
第五,面试后三天内最好复盘一次。把面试官问过的问题全部记录下来,标出答得好的和答得不好的。复盘的意义不只是为了下一次面试做准备,更是逼迫自己把知识体系里的漏洞补上。我这次面试里答得不完美的几道题,事后都在技术博客和论文里补了课,这些知识在入职之后都用上了。
最后再说一个小技巧:面试前可以自己给自己录一段模拟面试的视频,看一遍回放,很多口头禅和表达问题一眼就能看出来。我在模拟时发现自己有个毛病,被人追问后容易语速变快、逻辑变乱,后来有意识控制语速,正式面试时果然稳了很多。面试不是表演,但把状态调整好,确实能让你的真实水平完整地发挥出来。