计算机视觉(CV)面试与实战红宝书

最近接了不少练手/面试卡壳的私信:要么只会调 YOLOv8 落地不了,要么被面试官问“ResNet 为什么能做深层”“你用的 Focal Loss alpha/gamma 怎么调”答不上来。

这篇红宝书就是来补这个缺口的——浓缩 3 年算法岗面试经验 + 2 年落地踩坑,从底层到工程,文字只说“面试/实战要用的”,代码都是“可复现/可修改”的


一、底层功底:面试敲门砖,调优基本功

1. 颜色空间与通道(🎯面试常考应用场景)

在面试中,颜色空间相关的考题通常围绕“什么时候该用什么空间”展开。下面这个代码片段演示了最经典的 HSV 颜色分割场景(比如绿幕抠图、交通标志提取):

import cv2
import numpy as np

def hsv_color_segment():
    """【实战必备】绿幕/交通标志颜色分割"""
    img = cv2.imread("traffic_red.jpg")
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    # 红色在 HSV 色相环上环绕 0° 附近,需要分成两段
    lower1, upper1 = np.array([0,50,50]), np.array([10,255,255])
    lower2, upper2 = np.array([170,50,50]), np.array([180,255,255])
    mask = cv2.inRange(hsv, lower1, upper1) + cv2.inRange(hsv, lower2, upper2)
    return cv2.bitwise_and(img, img, mask=mask)

几种常用颜色空间的对比总结如下:

颜色空间应用场景优缺点
RGB显示、深度学习基础训练通道高度耦合,对光照变化敏感
HSV颜色分割(如交通标志、绿幕)光照鲁棒,色调通道独立于亮度
GRAY底层特征提取、降维丢失颜色信息,但计算量更小

面试话术:为什么不做 RGB 分割?因为 RGB 三个通道同时受光照影响,而在 HSV 中色调 H 基本独立于亮度和饱和度,阈值容易设定。


2. 滤波降噪(⚠️实战避坑:选对滤波器)

图像滤波往往是图像预处理的第一步,不同噪声需要不同的滤波器。这里直接给出实战口诀 + 踩坑场景

  • 椒盐噪声(随机黑白点):使用 中值滤波 cv2.medianBlur,能有效去除离散噪点,同时保护边缘。
  • 高斯噪声(画面整体模糊、颗粒细小):使用 高斯滤波 cv2.GaussianBlur
  • 磨皮美颜 / 保边去噪:推荐 双边滤波 cv2.bilateralFilter,它在平滑区域的同时保持边缘清晰,缺点是计算速度相对较慢。

面试时如果被问到“为什么不用均值滤波”,可以这样回答:均值滤波会同时模糊噪声和边缘,而中值滤波对椒盐噪声的去除效果更好,且保边能力更强。


3. 经典特征与边缘(🎯传统岗/入门面试必问)

Canny 边缘检测(4 步要背)

Canny 是计算机视觉中几乎不可绕开的传统算法,它的完整流程只有 4 步,却常常作为面试问题出现:

  1. 高斯去噪 – 先用高斯滤波平滑图像,降低噪声干扰。
  2. 梯度幅值与方向计算 – 利用 Sobel 算子获取每个像素的梯度强度和方向。
  3. 非极大值抑制 – 只保留梯度方向上的局部最大值,让边缘“变瘦”。
  4. 双阈值滞后连接 – 设定高、低两个阈值:强边缘直接保留,弱边缘只有与强边缘相连时才保留,否则丢弃。

经典特征对比(直接记面试答案)

特征不变性速度专利应用
SIFT旋转/尺度/亮度较慢有(现已过期)高精度拼接、图像匹配
ORB旋转/部分尺度极快实时 SLAM、移动端匹配

面试小 tip:当被问到“为什么不用 SIFT”时,可以说 SIFT 虽然精度高,但在实时场景下速度太慢,而且早些年存在专利问题;ORB 作为免费替代方案,在 SLAM 等应用中更为常用。


二、深度学习核心:面试重灾区(占比 60%+)

1. CNN 基础(3 个核心点)

局部感知 + 参数共享

卷积神经网络通过局部连接和共享权重,大幅降低参数量。网络从浅层到深层,特征也从简单到复杂:边缘 → 纹理 → 物体部件 → 整体场景

1×1 卷积的 3 个作用(🚀ResNet/MobileNet/Inception 都在用)

1×1 卷积看似简单,却在现代网络中扮演着关键角色:

  • 跨通道特征融合:对不同通道的信息进行线性组合。
  • 降维 / 升维:通过改变输出通道数减少或增加特征图数量,控制计算量。
  • 增加非线性:与激活函数配合,在不改变空间尺寸的情况下提升模型表达能力。

面试常问:为什么 MobileNet 和 ResNet 都要用 1×1 卷积?
回答:MobileNet 里 1×1 卷积是 Pointwise 部分,负责通道间的信息流动;ResNet 瓶颈结构中先用 1×1 降维,再 3×3 卷积,最后 1×1 恢复维度,大幅节省参数。

BatchNorm 的 3 个作用(🎯面试必背)

  • 缓解梯度消失/爆炸:将每一层的输入分布稳定在合理范围。
  • 加快收敛速度:使网络对初始化和学习率不那么敏感。
  • 允许使用更大的学习率:训练过程更稳定,提速明显。

2. 经典架构(只记最常考的 ResNet 残差块)

ResNet 的核心是残差学习。下面代码实现了一个基础的残差块,Identity Mapping(恒等映射) 保证了深层网络至少不比浅层网络差,有效解决退化问题。

import torch
import torch.nn as nn
import torch.nn.functional as F

class ResBlock(nn.Module):
    """【面试核心】解决深层网络退化问题:Identity Mapping 至少不比前一层差"""
    def __init__(self, in_ch, out_ch, stride=1):
        super().__init__()
        self.conv1 = nn.Conv2d(in_ch, out_ch, 3, stride, 1, bias=False)
        self.bn1 = nn.BatchNorm2d(out_ch)
        self.conv2 = nn.Conv2d(out_ch, out_ch, 3, 1, 1, bias=False)
        self.bn2 = nn.BatchNorm2d(out_ch)
        # 短接处理通道/尺寸不一致
        self.shortcut = nn.Sequential()
        if stride != 1 or in_ch != out_ch:
            self.shortcut = nn.Sequential(
                nn.Conv2d(in_ch, out_ch, 1, stride, bias=False),
                nn.BatchNorm2d(out_ch)
            )
    def forward(self, x):
        residual = self.shortcut(x)
        out = F.relu(self.bn1(self.conv1(x)))
        out = self.bn2(self.conv2(out))
        return F.relu(out + residual)

其他经典架构一句话记住:

  • MobileNet:深度可分离卷积 = Depthwise 卷积 + Pointwise 卷积,参数量和计算量约下降到原来的 1/9。
  • Inception:在同一层并行使用多尺度卷积核,让网络自适应选择合适的感受野。
  • Transformer/ViT:ViT 是纯 Transformer 的视觉模型,但实际落地中经常与 CNN 结合,比如 Swin Transformer 就在传统 CNN 结构基础上引入自注意力机制。

3. 目标检测(🎯算法岗核心题)

单双阶段对比(一句话总结)

类型代表速度精度应用
One-stageYOLO/SSD略低实时检测、移动端
Two-stageFaster R-CNN医疗影像、精密质检

面试话术:为什么 Two-stage 精度更高?因为它先用 RPN 生成候选区域再分类,对前景/背景的筛选更精细;而 One-stage 直接在特征图上做密集预测,容易产生大量负样本。

NMS(非极大值抑制)

  • 标准 NMS 核心逻辑:按分类得分排序 → 抑制与最高分框 IOU 过大的冗余框(直接删除)。
  • 改进方案 Soft-NMS:不直接删除重叠框,而是降低其得分,从而缓解密集场景(如行人遮挡)下的漏检问题。

三、实战调优:从学生到工程师的跨越

1. 损失函数(⚠️类别不平衡/分割必调)

Focal Loss(目标检测背景远多于前景)

核心思想:降低易分类样本的损失权重,让模型更关注难分类样本。
关键参数:

  • α(alpha):平衡正负样本,通常取值 0.25~0.75。
  • γ(gamma):调节难易样本权重,常设为 2~5,值越大对难样本的关注度越高。
# 伪代码,展示 Focal Loss 核心计算
alpha = 0.25
gamma = 2.0
p_t = pred[target]  # 目标类别的预测概率
loss = -alpha * (1 - p_t) ** gamma * torch.log(p_t)

面试避坑:不要只说“用了 Focal Loss 能解决不平衡”,一定要能解释 gamma 的作用——当 gamma=0 时 Focal Loss 退化为带 alpha 的交叉熵,gamma 越大,模型对已经分对的样本“惩罚”越小,注意力更集中于难分样本。

Dice Loss(语义分割小目标)

直接优化 IOU(交并比),特别适合前景像素占比极小的场景。它的形式可以看作是一种衡量预测与标签重叠度的损失函数,相比交叉熵更能缓解类别不平衡问题。


2. 优化器(新手练手选 Adam,调优转 SGD)

优化器特点适用
Adam自适应学习率,收敛快新手练手、快速迭代、原型验证
SGD + Momentum稳定,最终精度更高落地调优、竞赛刷榜、追求极致性能

面试经验:为什么不一直用 Adam?因为 Adam 的自适应学习率可能导致模型在后期泛化能力不如 SGD,所以在追求最终精度时往往切换为 SGD + Momentum 进行微调。


四、工程部署:算法落地的最后一公里

1. 模型加速(🚀生产环境 3 件套)

  1. 量化:将 FP32 权重转为 INT8,推理速度提升 2~4 倍,内存占用降至原来的 1/4。PyTorch 提供 torch.quantization 模块,支持动态量化和 QAT(量化感知训练)。
  2. 知识蒸馏:使用大模型(教师网络)产生的软标签指导小模型(学生网络)学习,使小模型在精度上接近大模型,同时保留推理效率。
  3. TensorRT:NVIDIA 的推理优化引擎,通过算子融合、内存优化等方式进一步提速,是 GPU 生产部署的标配工具。

2. 性能调优检查清单(⚠️落地必查)

速度慢排查

  • IO 瓶颈:使用 num_workers 加载数据,必要时将数据预加载到内存。
  • 数据搬运频繁:减少 cpu() / gpu() 不必要的切换。
  • 预处理耗时:尽量批量处理,用 OpenCV 代替 PIL 进行图像操作。

精度低排查

  • 输入尺寸是否对齐训练尺寸(避免尺寸偏差导致特征不一致)。
  • 数据增强强度是否合理(过强可能导致目标被裁切消失,过弱则泛化不足)。
  • 类别不平衡问题:使用 Focal Loss、过采样、类别权重等手段处理。

五、常考计算题(避坑指南,不用背太多)

输出尺寸公式

当设计网络或分析感受野时,经常需要计算卷积输出尺寸。公式本身很简单,用代码表示一目了然:

H_out = floor((H_in + 2*P - K)/S) + 1
W_out 同理

其中:

  • H_in / W_in:输入高度 / 宽度
  • P:填充(padding)
  • K:卷积核大小
  • S:步长(stride)
  • floor:向下取整

面试示例:输入 224×224,3×3 卷积,步长 1,填充 1,输出尺寸是多少?→ 224×224(称为“same”卷积,因为输入输出尺寸相同)。


六、总结

计算机视觉远不止调包跑 YOLO 这么简单。从面试到落地,完整的知识体系应该包括:

  1. 底层功底 – 图像处理与特征工程,是调优和预处理的基础。
  2. 深度学习 – CNN 设计范式与经典架构,是算法岗面试的核心。
  3. 实战调优 – 损失函数、优化器、数据策略,决定你能不能把一个 baseline 做到可上线。
  4. 工程部署 – 量化、蒸馏、TensorRT,是算法价值变现的最后一步。
理论 + 实践结合:先看架构/算法原理,再跑开源代码复现,最后找小数据集(如 Kaggle 猫狗识别、红绿灯检测)动手练一练。这样面试时有理论、有项目、有细节,任何追问都能接住。

相关教程