最近半年集中准备算法岗面试,我把计算机视觉相关的八股题按自己的理解重新整理了一遍,笔记标题标了“自用”,其实也是为了提醒自己:这些题不能只背结论,得能徒手推导、能讲出直觉。整理完以后有个很明显的感受——真正容易翻车的不是最新论文,而是卷积怎么算、感受野怎么推、NMS为什么这么设计这些最基础的问题。所以这篇把CV面试里最高频的几大块按我的复习顺序串了一遍,覆盖传统图像处理、CNN底层机制、经典网络、目标检测、损失函数和训练稳定性,适合正在准备算法岗实习或者校招、社招的同学,也适合想系统把CV基础补扎实的工程师。后面我会持续更新,遇到新的高频题就往对应章节里补。
1. 从直方图均衡化到特征点:传统CV为什么还常被问
很多准备深度学习方向的同学容易忽视传统图像处理,但面试官偏偏喜欢从这些点切入,因为它们最能看出你对图像本质的理解。我面了七八轮,几乎每轮都有传统CV的题,范围集中在直方图均衡化、边缘检测、特征点匹配和形态学处理这几块。
1.1 直方图均衡化:一个公式解决对比度问题
直方图均衡化(Histogram Equalization)解决的是图像对比度太低的问题。比如一张图片整体偏暗、灰度值集中在[30, 80]这个狭窄区间,人眼看不清细节,直接用CNN训练效果也差。思路很简单:把灰度分布从集中在某个小区间,映射到整个[0, 255]区间,让分布尽可能均匀。
具体做法是先统计每个灰度级的像素数量,得到概率分布 p(r_k) = n_k / N,n_k是灰度级为r_k的像素数,N是总像素数。然后计算累计分布函数CDF,最后做映射:
s_k = round( (L - 1) * CDF(r_k) )其中L是灰度级总数,8位图就是256。注意一定要先归一化CDF再乘(L-1),不归一化直接映射会出现整体偏白的问题。我笔试手撕过这道题,最稳的写法是先算直方图数组,再算累加数组,最后用查表法完成映射,实测比逐像素调round快不少。
面试官很喜欢追问:深度学习时代数据增强里为什么很少用直方图均衡化?我的理解是CNN本身能从数据里学出这种变换,而且均衡化是全局操作,容易放大噪声、改变图像的自然统计特性,对被检测目标的纹理信息可能有破坏。更常见的是用自适应直方图均衡化(AHE/CLAHE)做医学图像、低照度图像的预处理,它会分块处理再拼接,能避免全局均衡化把局部细节冲淡。
1.2 边缘检测:从Sobel到Canny的完整链路
边缘检测是图像分割、目标检测的传统基石。Sobel算子是入门级的一阶微分算子,它在水平方向用[-1,0,1; -2,0,2; -1,0,1]这个核去卷积,垂直方向用它的转置,分别得到x方向和y方向的梯度近似,然后合成梯度幅值。之所以中间行权重更大,是为了在平滑噪声的同时增强中心像素的贡献。
Canny是面试出现率最高的边缘检测算法,完整流程五步:高斯滤波去噪、计算梯度幅值和方向、非极大值抑制、双阈值检测、滞后连接。很多人能背出前两步,但说不出后两步的意义。非极大值抑制作用是把边缘细化,只保留梯度方向上局部最大的像素点,否则检测出的边缘会很粗。双阈值检测用高阈值找到确定性强边,用低阈值保留可能连上强边的弱边,滞后连接则决定弱边是否保留。
这里有个实战经验:Canny的高阈值和低阈值比例通常设为2:1到3:1,太低会引入大量伪边缘,太高会漏检。面试问到“为什么Canny比Sobel好”,核心就是它做了非极大值抑制和双阈值,既能抗噪声干扰,又能输出单像素宽、连续闭合的边缘。
1.3 SIFT为什么能做到尺度不变
SIFT(Scale-Invariant Feature Transform)在图像拼接、三维重建、SLAM里一直在用。它最核心的贡献是“尺度不变性”:同一物体距离相机远近不同,成像大小不同,普通角点检测(如Harris)匹配会失败,SIFT能在不同尺度下找到同一特征点。
理解SIFT要抓住几个层次。第一,构建高斯金字塔,对原图做不同σ的高斯模糊,形成octave和layer的尺度空间;第二,用相邻尺度的高斯图像做差得到DoG(Difference of Gaussian),近似LoG响应;第三,在DoG三维邻域(x、y、尺度三个方向)找局部极值点,并通过泰勒展开拟合亚像素位置,剔除低对比度和边缘响应点;第四,为每个关键点分配主方向,用梯度直方图峰值确定;第五,在关键点邻域计算128维描述子。
面试常问简答题:旋转不变性怎么来的?答案就是主方向归一化——统计邻域梯度方向直方图,取峰值方向作为参考,旋转图像时描述子坐标跟着转向。尺度不变性则来自尺度空间极值检测,特征点天然带有“适合它的尺度”信息。SIFT计算量大,所以后来有SURF、ORB这些加速变体。ORB用FAST角点加BRIEF描述子,速度快但尺度不变性弱,需要构建图像金字塔模拟近似尺度不变。我自己的记忆方法是:SIFT解决“能不能找到同一个点”,描述子解决“找到之后怎么比”,两件事分开想就不会乱。
1.4 形态学处理:腐蚀、膨胀的开闭运算
形态学算法在图像预处理和后处理里非常实用,尤其是分割结果的后处理。腐蚀操作是取结构元素覆盖区域的最小值,会缩小前景物体、消除孤立小噪声点;膨胀操作取最大值,会扩大前景区域、填补内部小孔。它们对二值图像效果最直观,但同样可以作用在灰度图上。
开运算是先腐蚀再膨胀,能去掉小目标和小噪声,同时保持大物体面积基本不变;闭运算是先膨胀再腐蚀,能填充前景内部的小洞、连接断裂区域。实战中我最常用的是对分割mask做开运算去噪点,再做闭运算补空洞,这套组合几乎成了后处理标配。面试有追问:为什么开运算能保持面积不变而不是变小?因为腐蚀缩小、膨胀恢复,先缩小再恢复,物体边缘会变圆滑,但尺寸基本回到原状。
传统CV部分我还会看下霍夫变换检测直线、摄像机标定涉及的内外参概念,但上面四类出现频率最高,属于必须能默写的程度。
2. 卷积与感受野:面试官从计算题开始连环追问
到了深度学习模块,面试官很少直接问概念,而是喜欢让你现场推公式、算参数量。刚开始我栽过一次,以为只要知道“卷积能提取特征”就够了,结果被追问到输出尺寸、参数量、感受野怎么算,一句话答不出来。这部分建议全部动手推一遍,不要只背结论。
2.1 卷积层的参数量与FLOPs计算
给定输入尺寸H×W×C,卷积核尺寸k,padding为p,stride为s,输出通道数为C'。输出特征图尺寸公式是:
out_h = floor((H + 2p - k) / s) + 1 out_w = floor((W + 2p - k) / s) + 1这个公式是基础中的基础,但有个容易忽略的点:stride为2时,输出尺寸是向下取整,PyTorch里有时候会因为输入尺寸不是偶数,导致拼接或反卷积后尺寸对不上。我遇到过一个UNet里skip connection尺寸不匹配的问题,最后就是靠手工用这个公式逐层算出来的。
参数量等于每个输出通道需要的卷积核大小乘以输入通道数,再加bias:
params = C' * (C * k * k) + C'FLOPs则要乘以输出特征图的尺寸:
FLOPs = C' * out_h * out_w * (C * k * k)这个只算乘法。如果面试官较真,加上加法大概再乘2,加上bias再加一项C' * out_h * out_w。一般来说能说出乘法次数就够用。举个例子:输入112×112×64,用3×3卷积输出128通道,stride=1,padding=1,输出仍是112×112,参数量=128×(64×3×3)+128=147584,大约0.14M。这个数量级心里要有数,我经常用参数量估算来判断模型是不是打印错了或者结构设计不合理。
2.2 感受野的递推公式怎么推
感受野定义是特征图上某个像素对应回输入图像上的区域大小。掌握递推公式比背具体数字重要:
RF_l = RF_{l+1} + (k_l - 1) * stride_prod其中stride_prod是从第l层到最后一层之间的所有stride的乘积。计算时从顶层向底层推。也可以用另一个从底向上累计的写法:
RF_l = RF_{l-1} + (k_l - 1) * ∏_{i=1}^{l-1} s_i我推荐从后往前推,因为编程实现时只需要维护当前RF和累计stride两个变量,来回迭代就行。
举VGG的例子,连续三个stride=1的3×3卷积,第一个输出感受野是3,第二个是5,第三个是7,所以三个3×3卷积等效一个7×7卷积的感受野,但参数量是27C²对比49C²,少了将近一半。这就是VGG用堆叠小卷积核替代大卷积核的动机。面试时如果能答出“感受野相同但参数量少、非线性更强”三层意思,这道题基本过了。
感受野在实际任务里很关键:目标检测小目标需要较高的特征分辨率,而高层特征感受野太大、空间细节丢失,所以FPN做了多尺度融合;图像分割则依赖足够大的感受野覆盖上下文。空洞卷积就是专门用来在不加池化的情况下扩大感受野的。
2.3 池化、空洞卷积与深度可分离卷积的对比
池化的作用有三个:下采样降低计算量、增大感受野、提供一定平移不变性。最大池化取邻域最大值,保留最强的纹理响应;平均池化取均值,保留整体背景信息。面试喜欢问“为什么分类网络常用最大池化”,我的理解是分类关注的是“有没有某种特征”,最大池化对这种强响应更敏感。
空洞卷积通过在卷积核像素之间插入空洞,变相扩大卷积核尺寸,感受野增大但参数量不变。比如rate=2的3×3空洞卷积,等效卷积核尺寸是5×5,感受野是5,但参数量还是9个。它的问题是高rate会带来gridding效应,特征图相邻像素来源彼此独立,局部信息丢失。所以DeepLab v3里用了多rate空洞卷积组合,而不是单一大rate。
深度可分离卷积是MobileNet的核心。普通卷积参数量是C×k×k×C',深度可分离卷积分成两步:depthwise卷积对每个输入通道单独做空间卷积,参数量C×k×k;pointwise卷积用1×1卷积混合通道,参数量C×C'。总数C×k×k+C×C'。以3×3卷积为例,计算量大约是普通卷积的1/8到1/9。面试要能写出这两种结构的参数量对比,最好再补一句“depthwise本质是跨通道解耦,牺牲通道间的相关性来换效率”。
2.4 反卷积与上采样:几种尺寸恢复路径
分割、生成模型都离不开上采样。最容易混淆的是转置卷积(常叫反卷积),它并不是卷积的逆运算,只是形状上能恢复分辨率,数值无法还原。转置卷积在数学上等价于对输入插值后做卷积,由于卷积核重叠,容易产生棋盘格伪影。我在生成实验里换过几次转置卷积和插值上采样,效果差异很明显,一般能用双线性插值解决的问题,我尽量不用转置卷积。
替代方案有双线性插值、最近邻插值、反池化(记录最大池化索引后还原)、Sub-pixel Convolution(像素重组,把通道维度转换为空间维度)。ESPCN超分就是用sub-pixel把C×r²个通道重排成C×H×W×r²输出。面试常见对比题:双线性插值性能稳定无参数,转置卷积可学习但容易伪影,sub-pixel适合像素级生成。分割里的ROI Align也涉及双线性插值,会单独问,先记住“用浮点坐标在邻近四个像素上做双线性插值得到特征值”这个核心就行。
3. 经典网络演进:ResNet为什么是分水岭
从AlexNet到EfficientNet,网络结构是一步一步演进过来的。面试官问网络结构,很多时候不是要你背参数量,而是想知道你懂不懂每个设计背后的动机。这部分我习惯按时间线捋,因为每个网络都是为了解决上一个网络的痛点提出的。
3.1 AlexNet与VGG给CNN定了哪些基调
AlexNet是2012年ImageNet夺冠的模型,真正让深度学习成为视觉主流。它做的事情现在看稀疏平常,但在当时是有突破性的:ReLU解决了梯度消失、训练更快;Dropout缓解全连接层过拟合;数据增强(随机裁剪、水平翻转)扩大训练样本;重叠池化减少信息损失。面试问“AlexNet为什么能赢”,我建议从非线性激活、正则化、并行计算三个角度答,不要只说“网络更深”。
VGG的核心贡献是提出“小卷积核堆叠”原则。相比AlexNet用11×11、5×5的大卷积核,VGG全部用3×3,但网络更深。两个3×3卷积堆叠感受野等效5×5,三个等效7×7,参数量却更少,而且中间每层都有ReLU,非线性更强。VGG的缺点是参数量集中在全连接层,前两个FC层参数占了很大比例,所以后来很多研究开始用全局平均池化替代FC压缩参数。
3.2 Inception的多尺度并联思想
GoogLeNet(Inception v1)提出在同一个层里用1×1、3×3、5×5卷积和3×3池化并联,把不同尺度的特征拼起来。这是一种“让网络自己选尺度”的思路,对多尺度目标表现更好。真正让Inception结构实用的关键点在于1×1卷积降维:先通过1×1卷积把通道数压下去,再做3×3、5×5卷积,计算量大幅下降。
面试如果问Inception v2/v3,核心是卷积分解:把5×5卷积拆成两个3×3,把n×n卷积拆成1×n和n×1两个非对称卷积。比如3×3拆成1×3加3×1,参数量从9降到6。这个思路在后来的轻量化网络里也有体现。还有一点值得提:InceptionNet大量使用辅助分类器,中间层加softmax让梯度能够传到浅层,这个设计在深层网络里很常见。
3.3 ResNet的残差连接到底解决了什么问题
ResNet提出时的背景是网络退化:层数增加,训练集误差反而升高,这不是过拟合,而是深层网络难以优化。残差结构的核心是用跳跃连接把输入x直接加到输出F(x)上,让网络只需要学习残差F(x)=H(x)-x。如果恒等映射是最优解,网络把残差学到接近0就行,比学习完整映射容易得多。这个直觉一定要能讲出来。
从梯度角度理解,反向传播时梯度经过跳跃连接多了一条从深层直接传回浅层的路径,梯度不会因为中间层的连乘而消失。这种“高速通路”让几十层上百层的网络也能稳定训练。ResNet里还设计了Bottleneck结构:1×1降维、3×3卷积、1×1升维,目的是减少3×3卷积的输入通道数,控制计算量。我复现分类模型时,习惯先把ResNet18跑通再换其他backbone,因为它结构简单、收敛稳定、不容易出bug,非常适合作为对照实验的基线。
3.4 轻量化网络与EfficientNet的复合缩放
MobileNet已经聊过深度可分离卷积,这里补充ShuffleNet,它在分组卷积后增加通道混洗操作,解决分组卷积导致的不同组之间信息不流通的问题。还有一点,轻量网络不只看FLOPs,还要看实际推理延迟。FLOPs小不代表快,因为内存访问、算子调度、并行度都会影响速度。我做过一次部署测试,MobileNetV2在移动端确实快,但在GPU上反而不如ResNet18快,说明FLOPs和硬件特性不能简单挂钩。
EfficientNet提出了一个很有指导性的问题:让网络更大、更高清、更宽,三者怎么组合?它的答案是compound scaling,用系数φ统一控制深度、宽度、分辨率:
depth = α^φ width = β^φ resolution = γ^φ其中α·β²·γ²≈2,这是通过NAS搜索得到的经验系数。这个理论用网格搜索验证了“三个维度等比缩放比单维度拉伸更有效”。面试问到这里,能说出统一放缩的原因是基于观察——不同维度的收益会饱和,联合缩放才能持续提升,就说明真的理解了。
4. 目标检测:Anchor、NMS与mAP的完整链路
目标检测是CV面试的重头戏,几乎每个面算法岗的人都会被问。这部分知识量大,问法也灵活,我从路线之争、Anchor机制、NMS、mAP计算四个角度整理,尽量把内外部逻辑串起来。
4.1 两阶段与单阶段的路线之争
两阶段检测器的代表是Faster R-CNN系列,第一阶段RPN生成候选区域,第二阶段对候选区域分类和回归。单阶段检测器代表是YOLO、SSD,直接对每个位置预测类别和框偏移。两阶段精度高,因为RPN先筛选了背景,把问题简化成“我框基本对了,只需要精修”;单阶段速度快,但正负样本极度不平衡,早期YOLO在小目标上精度较差。
面试对Faster R-CNN有几个追问是必背的:RPN是怎么训练的?答案是有Anchor的框与GT计算IoU,IoU>0.7的作为正样本,IoU<0.3的作为负样本,其余忽略。ROI Pooling为什么改ROI Align?因为ROI Pooling两次量化坐标导致特征偏移;ROI Align用双线性插值避免量化。到Mask R-CNN增加的分支是语义分割掩膜头。
4.2 Anchor机制:先验框的套路
Anchor可以理解成在特征图每个位置上预置的一组矩形框,每种框有不同尺度和长宽比。比如在feature map每个点放3种尺度和3种长宽比的9个anchor。训练时目标不是直接回归真实坐标,而是回归anchor与GT之间的偏移量和缩放量。用归一化的dx、dy、dw、dh表示,所以输出是4个值,不是直接输出坐标框。这样设计的好处是让回归目标范围更稳定,模型学起来更简单。
正负样本分配是Anchor训练的核心。Fast R-CNN对RPN生成的roi只取IoU>0.5的为正;Faster R-CNN的RPN沿用IoU>0.7正样本、<0.3负样本。如果一张图里小目标多、锚框总体IoU偏低,会导致正样本太少,这时候需要调低正样本阈值或增加anchor密度。我调过一批遥感图像目标检测,预设anchor完全不匹配目标的细长形状,后来修改长宽比范围才把recall拉上来。这说明Anchor设计不是死板的,要根据目标尺度分布统计。Anchor-free方法比如FCOS直接预测点到四条边的距离,CenterNet预测中心点和宽高,反正都是为了甩开anchor的调参负担,这个问题近两年面试出现率很高。
4.3 NMS与Soft-NMS:重复检测框怎么消解
NMS(非极大值抑制)是检测后处理必备步骤。流程是:把所有框按置信度降序排列,选最高分框保留,然后删除与它IoU超过阈值的框,重复直到处理完。阈值一般取0.5,太小会删掉并排的邻近目标,太大会保留很多重复框。
NMS的最大缺点是“一票否决”:两个高度重叠的真实实例,低分框会被直接删掉。Soft-NMS不硬删,而是按IoU大小给低分框的置信度打折,IoU越大衰减越狠。这样既抑制了重复框,又保留了相邻实例的候选。另一种思路是DIoU-NMS,把中心点距离纳入抑制标准,处理遮挡场景时更好用。面试比较喜欢问“NMS哪里耗时间、怎么加速”,答案一是排序用topk减少遍历,二是GPU并行实现,三是用低置信度框先过滤减少计算量。
4.4 mAP计算的隐藏细节
mAP(mean Average Precision)是检测任务的核心指标,计算细节很值得深挖。对每一个类别,先把所有预测框按置信度排序,然后逐个计算precision和recall,画出PR曲线,计算曲线下面积就是AP。VOC用的方法是把recall均匀分成101个点,取每个点对应的最大precision做插值,再求平均。COCO数据集更严,要求在不同IoU阈值(0.5到0.95,步长0.05)下分别计算AP再取平均,记为AP@[.5:.95],这也是更常用、更难刷的指标。
mAP计算里有个容易忽略的匹配规则:每个GT框最多匹配一个预测框,如果同一个GT框被多个预测框覆盖,只有高置信度的那个算TP,其它都算FP。因此置信度排序直接决定PR曲线的走势。这个细节面试官很喜欢用来判断你有没有真正实现过评估代码。还有个冷知识:mAP不受置信度阈值影响,因为排序后要遍历所有框,阈值只影响最后输出,不影响指标计算。
5. 损失函数与优化器:每个公式都要能徒手写
损失函数和优化器是面试里“背了就能答,不背就掉链子”的部分。我吃过一次亏,面试让写Focal Loss公式,我支支吾吾半天,所以现在对每个常用损失函数都要求自己能默写公式、说出梯度趋势。
5.1 分类损失:CrossEntropy到Focal Loss
多分类交叉熵是最常见的分类损失:
L = -Σ y_i * log(p_i)其中y_i是one-hot标签,p_i是预测概率。面试常问softmax和交叉熵组合时的数值稳定性问题,答案是计算时用log_softmax,避免exp溢出。比如softmax里e^100会溢出,先减最大值再做指数就可以避免。
Focal Loss解决的是类别极度不平衡问题,公式:
FL(p_t) = -α_t * (1 - p_t)^γ * log(p_t)p_t是正确类别的预测概率。当p_t接近1时,(1-p_t)^γ接近0,简单样本贡献被压低;p_t很小时(难样本),(1-p_t)^γ接近1,损失权重高。α_t用来平衡正负样本比例。γ一般取2,α取0.25到0.75之间。面试要能解释为什么难样本权重大:因为这个样本已经被分错了,说明模型没学会,加大它的梯度信号可以推动模型关注。
5.2 回归损失:L1、L2和Smooth L1的差异
目标检测框回归最常用Smooth L1:
smooth_L1(x) = 0.5 * x², 如果 |x| < 1 = |x| - 0.5, 否则对比L2损失,当预测值与真值差很大时,L2的梯度是x,随误差线性增大甚至更大,对异常点非常敏感,训练初期容易震荡。L1损失梯度恒定是±1,对异常值鲁棒,但在误差接近0时梯度仍然很大,不容易收敛到精确值。Smooth L1结合两者:小误差时用平方项保证平滑收敛,大误差时用线性项限制梯度大小。我在训练检测器时也发现直接换Smooth L1比L2收敛稳。
另外近年常用的IoU Loss和GIoU Loss要了解。IoU Loss把回归目标从BBox四个值转化为IoU本身,直接优化重叠程度,好处是尺度不变,但IoU为0时梯度消失。GIoU在IoU基础上加入最小外接矩形惩罚项,缓解不重叠时没梯度的问题。
5.3 Adam和SGD怎么选
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) θ_t = θ_{t-1} - lr * m_hat / (√v_hat + ε)m是一阶矩估计,相当于动量,v是二阶矩估计,相当于每个参数自适应学习率。偏差校正在训练初期防止估计算得太小。Adam优势是收敛快、对学习率不敏感,适合Transformer和大多数深度学习任务。但经验上Adam有时泛化不如SGD,尤其在早期图像分类任务里。做法是先用Adam快速找一个好区域,再切到SGD+动量精调,或者直接用AdamW(解耦权重衰减)配合cosine learning rate,这在当前大模型训练里是主流配置。
面试被问“为什么Adam收敛快但不一定泛化好”,我的表述是:自适应学习率让每个参数步长不同,能快速跨过平坦区域和陡峭区域,但也可能让模型陷入尖锐极小值,这个极小值在训练集上表现好、在测试集上泛化差。SGD的噪声和缓慢更新反而容易收敛到平坦极小值。
5.4 学习率策略:warmup和cosine decay
学习率策略是训练稳定性里被问得最多的点。Linear warmup意思是前几个epoch让学习率从很小值线性升到目标学习率,目的是避免大学习率在小步内把随机初始化的权重冲乱,尤其大batch size场景下特别重要。Cosine decay让学习率按余弦曲线从峰值降到接近0,前期降得慢、后期降得快,比StepLR更平滑。
面试喜欢问“学习率和batch size有什么关系”。经验法则是线性缩放规则:batch size扩大K倍,学习率大致也扩大K倍,但要注意warmup期间不能这么做。我实测过batch size从32升到128,学习率不调大收敛很慢,调大后训练损失下降明显。还有一招是先用小数据跑几十个step试出最大可行学习率,再按这个量级定训练用学习率,能避免一上来就发散。
6. 训练稳定性:BN、数据增强与过拟合攻防
模型结构只是第一步,能不能训练出来是另一回事。面试官问到训练细节,通常是想知道你有没有真正跑过实验,而不只是调了库。
6.1 BatchNorm的train/eval差异
BatchNorm在训练时对每个mini-batch计算均值和方差,做归一化,再用可学习的γ和β恢复表示能力。它维护一组running_mean和running_var,训练时用指数滑动平均更新,推理时直接用这组全局统计量,不再用当前batch的统计量。这个train/eval差异是高频考点。
面试陷阱是:“推理时如果batch很小,BN用当前batch统计更准?”答案是错的。因为推理模式要用全局统计量,跳过了滑动平均更新,否则同一张图放在batch里不同位置、不同batch大小下输出会变化,这在实际部署里是不可接受的。所以很多框架里model.eval()之后必须配合关闭BN更新。我还遇到过PyTorch中冻结BN的坑:用register_buffer还是parameter的区别、model.eval()和requires_grad逻辑纠缠,排查了很久。建议面试时主动提这个例子,会显得实战经验丰富。
关于BN为什么有效,早期说法是解决Internal Covariate Shift,但后来研究对这个解释存疑。更有说服力的观点是:BN让优化曲面更平滑,梯度更稳定,因此可以使用更大学习率。面试时说出“原论文的covariate shift解释已经被后续研究质疑,现在更倾向于认为BN改善了损失曲面的landscape”,会让面试官觉得你读过文献、有自己的理解。
6.2 数据增强的现代工具箱
几何增强包括随机翻转、随机裁剪、旋转、缩放,检测任务里要同步变换bbox坐标,这是老生常谈。色彩增强包括亮度、对比度、饱和度扰动,模拟光照变化。高级一点的有Cutout随机遮挡一块区域、Mixup两个样本加权混合、CutMix把一块区域从另一张图贴过来同时混合标签。这些增强的动机都是强制模型不要依赖局部特征,提升鲁棒性。
RandAugment是把多个增强算子按随机顺序组合,每个算子的幅度由统一强度控制,省去逐算子调参。我对小数据集的建议是别一上来就用太强的增强,先跑通,再加Mixup/CutMix,否则很难判断是网络结构问题还是增强不合理。面试问到“增强为什么能提点”,核心是正则化——增加数据多样性,降低模型对特定背景、位置、颜色的依赖,等价于一种隐式的模型集成。
6.3 过拟合信号与应对措施
最经典的过拟合信号是训练loss持续下降但验证loss开始上升,或者训练准确率远高于验证准确率。还有一个容易被忽略的信号:验证loss在某一轮后不降反升,但准确率还在微涨,这时候可能正好处于拟合和过拟合的边界,可以用早停保存最优模型。
应对方法优先级我一般这么排:先增加数据增强,再调dropout和weight decay,然后考虑减小模型容量,最后才用early stop。weight decay本质是L2正则,损失函数里加了参数平方项,限制权重范围,防止某些权重过度放大。Dropout训练时随机失活神经元,推理时全部保留但乘以保留概率,相当于集成多个子网络。要注意CNN里Dropout一般加在全连接层,卷积层后用DropBlock这类结构化的失活方法效果更好。
6.4 迁移学习与微调策略
很多CV项目都是站在预训练模型基础上做的,面试常问:怎么选择冻结层?我的经验是,浅层特征更通用(边缘、颜色、纹理),深层特征更靠近任务。如果目标数据集特别小,可以把backbone前几层冻结,只微调高层和分类头;如果数据量够,最好全部微调,只是backbone用更小学习率。常见做法是把backbone learning rate设为主干的0.1倍,分类头用正常学习率。冻结BN也是个坑:如果batch size很小,建议冻结BN统计量,否则BN统计量更新抖动会影响训练稳定性。
7. 复盘:最近面试被问倒的高频进阶问题
最后这部分是我血的教训。把面试中真正让我卡壳的问题复盘一遍,整理成参考答案。这些问题看起来基础,但问得细、问得深,很考验底层理解。
7.1 CNN为什么比全连接更适合图像
我最早以为只要答“局部连接、权值共享”就够了,后来被追问“为什么这两个特性对图像有效”,才意识到要往深说。一是局部相关性:自然图像中距离近的像素相关性高,远处的相关性弱,局部连接天然符合图像的统计特性。二是权值共享:同一个卷积核在图像不同位置重复使用,等于把“位置无关的特征检测器”叠加进去,使模型获得平移等变性,物体在图像里移动位置,检测器响应也跟着移动,但检测结果不变。三是参数大幅减少,降低过拟合风险。四是卷积堆叠能形成从边缘、纹理到部件、物体的层次化特征。全连接网络直接打平像素,没有这些归纳偏置,需要更多数据才能学到同样的特征。
7.2 训练和推理时BN的统计量分别怎么用
这个问题我被连环追问过。训练时用当前batch的均值方差做归一化,然后更新滑动平均:
running_mean = 0.9 * running_mean + 0.1 * batch_mean running_var = 0.9 * running_var + 0.1 * batch_var推理时不看当前batch,直接用保存的running_mean和running_var。追问点在于为什么不能混用:如果推理时还用batch统计量,batch size小则统计量噪声大,结果不稳定;而且单样本时方差为0,归一化退化,所以部署时BN必须折叠进卷积或至少切换eval模式。我补一句实测经验:在batch size=1的检测任务里不冻结BN,训练会非常飘,损失曲线像锯齿,冻结后立刻稳定。
7.3 BatchSize大小对收敛和性能的影响
大batch size梯度估计更准确,收敛更平滑,但容易收敛到尖锐极小值,测试性能可能下降;训练时需要同步增大学习率,否则单步更新太保守。小batch size梯度噪声大,天然带正则化效果,有时泛化更好,但BN统计量波动大,训练不稳定。实际使用中,如果显存够,大batch配合warmup和cosine大部分时候更好,尤其是大模型。数据并行时还有一个细节:SyncBN会把所有卡的统计量同步,避免单卡batch太小导致BN失真。这个点也能体现工程经验。
这份“自用”笔记写到这儿,已经覆盖了我在面试里遇到的大部分计算机视觉基础问题。我还是要提醒一句:八股背得再熟也只是入场券,真正跟别人拉开差距的,是你对每个机制背后的动机能不能讲出逻辑。每道题建议都合上笔记自己复述一遍,能顺畅讲出来才算真会。后面我会继续补充分割、Transformer、大模型相关的内容,有新的高频题就往对应章节里填,算是把这个系列持续更新下去。