计算机视觉核心技术全景:从图像增广到语义分割


计算机视觉核心技术全景:从图像增广到语义分割

深度学习在计算机视觉领域已经形成了一套完整的技术栈。本文从工程实践角度,系统梳理图像分类、目标检测、语义分割、风格迁移等核心方向的关键技术,带你建立完整的知识体系。


一、图像增广:用数据”欺骗”模型

为什么需要图像增广?

模型过拟合的根本原因是训练数据不够多样。图像增广(Image Augmentation)通过对训练图像随机变换,制造出”假的新样本”,让模型学到更鲁棒的特征,而不是记住特定的像素排列。

AlexNet 的成功在很大程度上要归功于图像增广。

常用增广方法

几何变换: 翻转、随机裁剪是最常用的。左右翻转不改变物体类别,是低成本、高收益的增广手段。

import torchvisiontrain_augs = torchvision.transforms.Compose([    torchvision.transforms.RandomHorizontalFlip(),         # 随机左右翻转    torchvision.transforms.RandomResizedCrop(             # 随机裁剪并缩放        (200200), scale=(0.11), ratio=(0.52)),    torchvision.transforms.ToTensor(),])

颜色扰动: 随机改变亮度、对比度、饱和度和色调,降低模型对光照条件的敏感性。

color_aug = torchvision.transforms.ColorJitter(    brightness=0.5, contrast=0.5, saturation=0.5, hue=0.5)

组合增广: 实践中通常叠加多种方法:

augs = torchvision.transforms.Compose([    torchvision.transforms.RandomHorizontalFlip(),    color_aug,    shape_aug,])

关键原则

  • 训练时增广,预测时不增广。 预测需要确定性结果,随机操作会导致同一张图像每次输出不同。
  • 增广只在训练集上应用;测试集使用确定性预处理(Resize + CenterCrop + Normalize)。

二、迁移学习与微调:站在巨人的肩膀上

问题背景

假设你要分类 100 种椅子,每种只有 1000 张图片——这比 ImageNet 小 100 倍以上。从零训练复杂模型必然过拟合,而微调(Fine-tuning)能解决这个问题。

迁移学习的核心思想

在 ImageNet 上预训练的模型已经学会了识别边缘、纹理、形状这类通用特征,这些特征对任何视觉任务都有价值。微调就是:借用别人学到的特征提取能力,只重新训练适配自己任务的输出层。

微调四步走

  1. 加载在源数据集(如 ImageNet)上预训练好的模型;
  2. 替换输出层,改为目标类别数;
  3. 用小学习率更新原有参数;
  4. 用大学习率从头训练新输出层。
# 加载预训练 ResNet-18finetune_net = torchvision.models.resnet18(pretrained=True)# 替换输出层为 2 类(热狗 / 非热狗)finetune_net.fc = nn.Linear(finetune_net.fc.in_features, 2)nn.init.xavier_uniform_(finetune_net.fc.weight)# 输出层学习率设为其他层的 10 倍trainer = torch.optim.SGD([    {'params': [p for n, p in finetune_net.named_parameters()if n notin ["fc.weight""fc.bias"]]},    {'params': finetune_net.fc.parameters(), 'lr': learning_rate * 10}], lr=learning_rate, weight_decay=0.001)

效果对比

在热狗识别任务上,微调模型(测试准确率 94.3%)显著优于从零训练(85.9%),而训练速度也更快。

结论: 只要目标数据集与源数据集有相关性,微调几乎总是优于从零训练。


三、目标检测基础:边界框、锚框与 IoU

从分类到检测

图像分类只关心”图里有什么”,目标检测还要回答”在哪里”。位置信息通常用边界框(Bounding Box)表示,有两种常用格式:

  • 左上-右下格式
  • 中心-宽高格式

两种格式可以互转:

defbox_corner_to_center(boxes):    x1, y1, x2, y2 = boxes[:, 0], boxes[:, 1], boxes[:, 2], boxes[:, 3]    cx = (x1 + x2) / 2    cy = (y1 + y2) / 2    w = x2 - x1    h = y2 - y1return torch.stack((cx, cy, w, h), axis=-1)

锚框:候选区域的”模板”

目标检测的核心策略是:先撒一批候选框(锚框),再对每个候选框分类和修正位置。

以每个像素为中心,按不同缩放比  和宽高比 ,生成锚框:

为控制数量,实践中只用  或  参与组合,每个像素生成  个锚框。

交并比(IoU):衡量相似度

IoU 是两个边界框相交面积与相并面积之比,取值 

  • IoU = 0:完全不重叠
  • IoU = 1:完全重合
  • 实践中通常用 IoU > 0.5 作为”正样本”阈值

非极大值抑制(NMS)

模型预测时会产生大量重叠的边界框。NMS 的逻辑:

  1. 按置信度降序排列所有预测框;
  2. 取置信度最高的框  作为保留框;
  3. 移除所有与  的 IoU 超过阈值  的框;
  4. 对剩余框重复上述过程。
defnms(boxes, scores, iou_threshold):    B = torch.argsort(scores, dim=-1, descending=True)    keep = []while B.numel() > 0:        i = B[0]        keep.append(i)if B.numel() == 1break        iou = box_iou(boxes[i, :].reshape(-14),                      boxes[B[1:], :].reshape(-14)).reshape(-1)        inds = torch.nonzero(iou <= iou_threshold).reshape(-1)        B = B[inds + 1]return torch.tensor(keep, device=boxes.device)

四、多尺度检测:同时看大和小

尺度问题

一张图里可能既有小到几像素的远处行人,也有占据半张图的近处汽车。单一尺度的锚框无法兼顾。

解决方案:特征金字塔

卷积神经网络天然产生多尺度特征图:

  • 浅层特征图:分辨率高,感受野小 → 擅长检测小目标
  • 深层特征图:分辨率低,感受野大 → 擅长检测大目标

在不同尺度的特征图上分别生成锚框,小特征图用大锚框,大特征图用小锚框,就能覆盖各种大小的目标。

# 在 4×4 的特征图上检测小目标(锚框尺度 0.15)display_anchors(fmap_w=4, fmap_h=4, s=[0.15])# 在 2×2 的特征图上检测中等目标(锚框尺度 0.4)display_anchors(fmap_w=2, fmap_h=2, s=[0.4])# 在 1×1 的特征图上检测大目标(锚框尺度 0.8)display_anchors(fmap_w=1, fmap_h=1, s=[0.8])

五、单发多框检测(SSD):快速目标检测

设计思路

SSD(Single Shot MultiBox Detector)将多尺度检测思想落地成一个端到端的模型:

  1. 基础网络(如 VGG/ResNet)提取图像特征;
  2. 多个特征块逐步降采样,形成多尺度特征图;
  3. 在每个尺度的特征图上并行预测:类别 + 边界框偏移量。

核心模块

类别预测层: 用  卷积,输出通道数为  个锚框, 个类别含背景):

defcls_predictor(num_inputs, num_anchors, num_classes):return nn.Conv2d(num_inputs, num_anchors * (num_classes + 1),                     kernel_size=3, padding=1)

边界框预测层: 每个锚框预测 4 个偏移量:

defbbox_predictor(num_inputs, num_anchors):return nn.Conv2d(num_inputs, num_anchors * 4, kernel_size=3, padding=1)

降采样块: 两个  卷积 +  最大池化,高宽减半,感受野扩大:

defdown_sample_blk(in_channels, out_channels):    blk = []for _ in range(2):        blk.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))        blk.append(nn.BatchNorm2d(out_channels))        blk.append(nn.ReLU())        in_channels = out_channels    blk.append(nn.MaxPool2d(2))return nn.Sequential(*blk)

损失函数

SSD 的损失 = 类别损失(交叉熵)+ 偏移量损失( 范数):

负样本(背景锚框)不参与偏移量损失的计算,通过掩码(mask)实现。

一个 256×256 的 TinySSD 会生成多少锚框?


六、R-CNN 系列:精度优先的两阶段检测

R-CNN:思路清晰但太慢

R-CNN(2014)将检测拆成两步:

  1. 选择性搜索生成约 2000 个候选区域;
  2. 对每个区域分别用 CNN 提取特征 → SVM 分类 + 回归框位置。

致命缺点: 2000 次独立 CNN 前向传播,速度极慢。

Fast R-CNN:共享特征图

Fast R-CNN(2015)改进:只对整张图做一次 CNN 前向传播,在输出特征图上标记各候选区域的位置,再用 RoI Pooling 将不同大小的候选区域统一为固定尺寸:

# RoI Pooling:将任意大小的 RoI 统一为 2×2torchvision.ops.roi_pool(X, rois, output_size=(22), spatial_scale=0.1)

RoI Pooling 将  的区域划分为  的子网格,每格取最大值,输出形状固定为 

Faster R-CNN:去掉选择性搜索

Faster R-CNN(2015)将候选区域生成网络化,用区域提议网络(RPN)替代选择性搜索,整个模型端到端训练。RPN 在特征图每个位置生成锚框,预测”是否含目标”和位置偏移,筛选出高质量候选区域。

Mask R-CNN:像素级精度

Mask R-CNN(2017)在 Faster R-CNN 基础上增加了像素级分割分支

  • RoI Align(双线性插值)替代 RoI Pooling,避免量化误差;
  • 额外输出每个候选区域的像素级 mask。
模型
提议区域生成
特征提取
特点
R-CNN
选择性搜索
每个 RoI 单独提取
准确但极慢
Fast R-CNN
选择性搜索
共享特征图
速度大幅提升
Faster R-CNN
RPN(端到端)
共享特征图
速度和精度兼顾
Mask R-CNN
RPN
共享特征图 + RoI Align
支持实例分割

七、转置卷积:特征图的”放大镜”

为什么需要转置卷积?

普通卷积会缩小特征图(下采样)。语义分割需要输出与输入等大的像素级预测,必须把特征图放大回去(上采样)。转置卷积就是专门做这件事的。

转置卷积怎么算?

普通卷积:输入元素通过卷积核”汇聚”到输出的一个位置。转置卷积:输入的每个元素乘以卷积核,结果”广播”到输出的一个区域,所有区域叠加求和。

deftrans_conv(X, K):    h, w = K.shape    Y = torch.zeros((X.shape[0] + h - 1, X.shape[1] + w - 1))for i in range(X.shape[0]):for j in range(X.shape[1]):            Y[i: i + h, j: j + w] += X[i, j] * Kreturn Y

对于  输入和  卷积核,输出为 

与矩阵转置的关系

普通卷积可以用矩阵乘法表示:转置卷积对应:

这就是”转置卷积”名称的由来:它交换了卷积层正向传播和反向传播的方向。

# PyTorch 中使用转置卷积tconv = nn.ConvTranspose2d(11, kernel_size=2, stride=2, bias=False)

步幅为 、填充为 、卷积核为  时,输出尺寸恰好是输入的  倍。


八、全卷积网络(FCN):逐像素分类

核心思路

FCN(Fully Convolutional Network,2015)用于语义分割,把每个像素都分类:

  1. 用预训练 CNN(如 ResNet-18)提取图像特征(特征图高宽为输入的 1/32);
  2. 用  卷积将通道数变换为类别数
  3. 用转置卷积上采样 32 倍,恢复到原图尺寸。
# 截取 ResNet-18 去掉最后的分类层net = nn.Sequential(*list(pretrained_net.children())[:-2])# 添加 1×1 卷积:通道数 → 类别数net.add_module('final_conv', nn.Conv2d(512, num_classes, kernel_size=1))# 添加转置卷积:上采样 32 倍net.add_module('transpose_conv',    nn.ConvTranspose2d(num_classes, num_classes,                       kernel_size=64, padding=16, stride=32))

双线性插值初始化

转置卷积的权重用双线性插值初始化,效果远好于随机初始化:

defbilinear_kernel(in_channels, out_channels, kernel_size):    factor = (kernel_size + 1) // 2    center = factor - 1if kernel_size % 2 == 1else factor - 0.5    og = (torch.arange(kernel_size).reshape(-11),          torch.arange(kernel_size).reshape(1-1))    filt = (1 - torch.abs(og[0] - center) / factor) * \           (1 - torch.abs(og[1] - center) / factor)    weight = torch.zeros((in_channels, out_channels, kernel_size, kernel_size))    weight[range(in_channels), range(out_channels), :, :] = filtreturn weightW = bilinear_kernel(num_classes, num_classes, 64)net.transpose_conv.weight.data.copy_(W)

FCN 在 Pascal VOC 数据集上训练 5 轮,测试准确率可达 85%+。


九、神经风格迁移:让 AI 成为画家

问题定义

给定一张内容图像(如风景照)和一张风格图像(如梵高油画),生成一张既保留内容又具有风格的合成图像。

三种损失函数

内容损失: 合成图像与内容图像在深层特征上的均方误差:

风格损失: 用格拉姆矩阵(Gram Matrix)捕捉风格特征之间的相关性:

格拉姆矩阵的直觉: 是通道  和通道  的特征相关度,代表了”哪些纹理同时出现”——这正是风格的本质。

全变分损失: 减少高频噪点,让相邻像素更平滑:

总损失:

训练过程

风格迁移与常规训练不同:模型参数固定(预训练 VGG),被优化的是合成图像本身

classSynthesizedImage(nn.Module):def__init__(self, img_shape, **kwargs):        super().__init__(**kwargs)        self.weight = nn.Parameter(torch.rand(*img_shape))  # 图像像素即参数defforward(self):return self.weight

用 Adam 优化器迭代 500 步,不断更新合成图像的像素值。


十、Kaggle 实战:模型调优的工程技巧

ImageNet 子集上的狗品种识别

在 Kaggle 的狗品种识别比赛(120 类)中,数据集是 ImageNet 子集,图像尺寸大且不统一。关键策略:

数据增广(训练时):

transform_train = torchvision.transforms.Compose([    torchvision.transforms.RandomResizedCrop(224, scale=(0.081.0),                                             ratio=(3.0/4.04.0/3.0)),    torchvision.transforms.RandomHorizontalFlip(),    torchvision.transforms.ColorJitter(brightness=0.4, contrast=0.4, saturation=0.4),    torchvision.transforms.ToTensor(),    torchvision.transforms.Normalize([0.4850.4560.406],                                     [0.2290.2240.225])])

微调策略: 冻结 ResNet-34 的所有层,只训练新增的两层全连接网络:

defget_net(devices):    finetune_net = nn.Sequential()    finetune_net.features = torchvision.models.resnet34(pretrained=True)    finetune_net.output_new = nn.Sequential(        nn.Linear(1000256), nn.ReLU(), nn.Linear(256120))    finetune_net = finetune_net.to(devices[0])for param in finetune_net.features.parameters():        param.requires_grad = False# 冻结特征提取部分return finetune_net

这种”特征提取”策略(冻结主干,只训练头部)大幅节省计算资源,在小数据集上尤为有效。


十一、技术路线图总结

输入图像    │    ├─ 图像分类 ──────────────── 微调预训练模型    │    ├─ 目标检测    │     ├─ 边界框 + 锚框 + IoU + NMS(基础组件)    │     ├─ 多尺度特征(特征金字塔思想)    │     ├─ SSD(单阶段,速度快)    │     └─ R-CNN / Fast / Faster / Mask(两阶段,精度高)    │    ├─ 语义分割    │     ├─ 转置卷积(上采样核心操作)    │     └─ FCN(像素级分类)    │    └─ 风格迁移          └─ 内容损失 + 风格损失(Gram矩阵)+ 全变分损失
任务
代表模型
核心技术
图像分类
ResNet + 微调
迁移学习、图像增广
目标检测(快速)
SSD
多尺度锚框、端到端训练
目标检测(精准)
Faster R-CNN
RPN、RoI Pooling
语义分割
FCN
转置卷积、双线性插值
实例分割
Mask R-CNN
RoI Align、像素级 Mask
风格迁移
Neural Style
Gram 矩阵、多层损失

小结

计算机视觉的核心技术链条非常清晰:

  1. 数据层面:图像增广 + 迁移学习,解决数据不足的问题;
  2. 检测层面:锚框 + IoU + NMS 是基础,SSD 和 R-CNN 系列代表快/准两条路线;
  3. 像素层面:转置卷积实现上采样,FCN 把分类推广到逐像素的语义分割;
  4. 创意层面:风格迁移把优化对象从参数改为图像本身,展示了深度学习的另一面。

理解这条链条,你就掌握了计算机视觉工程实践的核心框架。