语义分割

简单思路

一、什么是语义分割?

任务定义:

对图像中的每一个像素进行分类,输出与图像同样大小的标签图,每个像素被分配一个语义类别(如 sky、cat、tree、grass)。

  • 只关注“类别”,不区分实例。
  • 所以如果图中有两只牛,语义分割只会把它们全都标成“cow”,不会区分“牛1”和“牛2”。
  • 见图一中右下角牛的分割:只是一个统一的“Cow”区域。

二、最直接的思路:滑动窗口(Sliding Window)

对图中每个像素都提一个 patch,送入 CNN 得出中心像素的类别预测。

流程如下(图二):

  1. 从图像中提取每个像素周围的 patch;
  2. 把 patch 输入 CNN,预测中心像素的类别;
  3. 重复这个过程,逐个像素预测;
  4. 拼接得到整张图的分割结果。

问题:

  • 极度低效! 重复计算同一片区域的卷积特征;
  • 类似于早期的“慢速 R-CNN”;
  • 只能作为概念启发,不实用。

三、主流方法:全卷积网络(Fully Convolutional Network, FCN)

用一个完全由卷积层组成的 CNN,直接对整张图进行像素级预测。

结构如下(图三):

  1. 输入图像大小为 3 \times H \times W;
  2. 使用一堆卷积层提取特征(没有 FC 层);
  3. 输出维度为 C \times H \times W,其中 C 是类别数;
  4. 对每个像素位置上那一列做 softmax,得到每个像素的类别分布;
  5. 使用每像素的交叉熵损失训练。

优点:

  • 没有重复计算:高效;
  • 结构简单、端到端训练;
  • 空间结构不丢失,可输出与输入等大的预测图。

四、实际挑战(感受野 + 计算效率)

1. 感受野问题:

深层网络中一个像素的预测依赖的输入区域叫做“感受野”。

  • 如果你仅堆叠 3 \times 3 的卷积,感受野增长很慢;
  • 2 层堆叠 → 感受野 5×5;
  • 3 层堆叠 → 感受野 7×7;
  • 所以需要很多层才能看到足够大范围。

但语义分割很多决策需要“全局上下文”,太小的感受野会影响效果。

2. 高分辨率图像计算开销大:

  • 为了精度,语义分割常对高分辨率图像操作;
  • 但每个像素都要分类,计算成本非常高;
  • 所以不能在原图尺度上全卷积堆太深。

3. :不考虑个体,只标类别,需要 instance segmentation 解决

五、后续发展(虽然 lecture未讲解)

  • 为了解决感受野问题,后续提出:
  • 空洞卷积(Dilated Convolution)
  • U-NetDeepLab 等架构使用 skip connection + 多尺度特征融合;
  • 为了解决高分辨率计算,使用:
  • Encoder-Decoder 架构
  • 图像下采样 + 上采样策略(如 Deconv、Upsample、Interpolation)

下采样与上采样

下采样(如池化、步长卷积) 把特征图变小了,但最后要预测每个像素的类别,所以我们必须 把特征图恢复到原图尺寸,这就需要上采样。下面总结一下讲解内容:

一、下采样的作用

  • 使用池化(Pooling)或步长卷积(Strided Convolution)将图像尺寸降低。
  • 优点:
  • 计算更快
  • 感受野更大,利于理解上下文

二、上采样的几种方式

方法1:最近邻上采样(Nearest Neighbor Upsampling)

  • 做法:直接把每个像素“复制”到多个位置,形成更大尺寸的图。
  • 特点:简单快速,但容易产生锯齿感、不平滑。

方法2:双线性插值(Bilinear Interpolation)

  • 做法:假设你要计算一个新像素的值,这个点落在原图中 4 个像素之间,就根据这四个点的值加权平均,权重由距离决定。
  • 效果:平滑,图像质量较好。
  • 公式含义

意思是:从周围四个整数像素中,通过线性权重组合出浮点坐标的值。

  • 适合:很多语义分割模型默认上采样方式。

方法3:三次插值(Bicubic Interpolation)

  • 做法:基于 16 个邻居点(4×4)做高阶插值,比双线性更复杂。
  • 特点:更平滑、效果更好,但计算更慢。
  • 常用场景:图像缩放处理,网络中偶尔也用。

方法4:最大非池化(Max Unpooling)

  • 原理
  • 下采样时用 最大池化,每个区域只保留最大值。
  • 把最大值 出现的位置记录下来
  • 上采样时:把特征放回“原来的最大值位置”,其余位置补 0。
  • 优点:保留位置信息,适合搭配最大池化使用。

三、选择上采样方式的经验法则

下采样方法 建议上采样方式
平均池化 / 步长卷积 最近邻 / 双线性 / 三次插值
最大池化 最大非池化(Max Unpooling)

总结:

下采样让我们计算更快、看得更远,上采样则把理解的结果还原到原图尺度。如何上采样,不止影响清晰度,也影响语义对齐和可学习性。


转置卷积(上采样)的机制

转置卷积(Transposed Convolution)详细解释,它是语义分割中最常用的可学习上采样方法之一。我们逐段拆解、结合图示来理解它的 动机、计算方式、命名由来与数学原理

一、为什么需要转置卷积(Transposed Convolution)?

我们做语义分割,需要输出 和输入图像等大小的像素标签。但:

  • CNN在下采样(通过池化、stride卷积)后会降低分辨率
  • 所以我们需要 上采样 操作,把低分辨率的特征图变回高分辨率;
  • 像双线性插值/最近邻上采样不能学习,没参数可调

这就引出了:转置卷积 = 有参数、可训练的上采样方法

二、转置卷积是如何运作的?

举例

  • 输入是一个 2×2 特征图,使用一个 3×3 的卷积核(filter),stride=2。
  • 对每个输入位置:
  1. 拿该位置的值乘以整个卷积核;
  2. 将乘完的结果 平移到输出图的对应位置
  3. 如果多个位置产生的输出区域有重叠,就把它们 加起来
  • 输出本来是 5×5,但为了得到 4×4,裁掉最上/最左的一行一列(称为 “修剪”)。

本质上,这个过程就是:每个输入点通过一个滑动窗口扩散出一个加权区域,多个区域之间重叠相加形成更大的输出图

三、换个角度:从一维举例(图2)

输入是 [a, b],filter 是 [x, y, z]。

  • a 点生成 [ax, ay, az]
  • b 点生成 [bx, by, bz],偏移后加入到输出中,中间有重叠的位置相加(az + bx)
  • 输出长度比输入大,实现了上采样。

这就是 1D 转置卷积最直观的过程。

四、为什么叫“转置”卷积?

普通卷积可表示成矩阵乘法:

  • 卷积操作 = 乘以一个稀疏的矩阵 X
  • 所以 y = X * a

转置卷积做的事:

  • 就是用同一个矩阵的 转置 Xᵀ 去做乘法:
  • y = Xᵀ * a

这就是为什么叫“transposed convolution”。

对应矩阵角度:转置卷积就是普通卷积的矩阵形式的转置

五、stride=1 和 stride>1 有啥不同?

当 stride = 1:

  • 普通卷积和转置卷积是对称的操作(几乎等价,只是padding规则略有不同)。

当 stride > 1:

  • 两者的稀疏模式完全不同;
  • 转置卷积无法再表示为某种常规卷积;
  • 这就体现出转置卷积的独特性:它不是普通卷积的简单反向操作,而是一种新的上采样方式

六、转置卷积和卷积反向传播的关系

  • 实际上,转置卷积的前向过程 = 普通卷积的反向传播过程
  • 所以它有一个合理的别名叫 “Backward Strided Convolution”

这个对称性意味着,我们在反向传播中能自动计算梯度,非常适合用于训练。

总结一句话:

转置卷积是一种参数可学习的上采样方法,本质是普通卷积矩阵的转置操作,允许从低分辨率特征图恢复成高分辨率输出,常用于语义分割、图像生成等任务。


上采样对比

上采样方法 是否可学习 原理简介 优点 缺点 常见用途
最近邻插值 将每个像素复制成更大的区域(如2x2) 简单、速度快 产生块状伪影(aliasing)、不平滑 图像预处理、基础上采样
双线性插值 用周围4个像素加权平均,权重按距离线性分布 平滑、连续 不可学习、不能表达复杂模式 语义分割中常用作初步上采样
三次插值(bicubic) 用周围16个像素构建三次函数,拟合出插值结果 更平滑、边缘过渡更自然 计算量更大、不适合GPU加速训练 图像编辑、resize 操作
Max Unpooling 记录max pooling时的最大位置,将值放回原位,其余位置填0 能恢复空间结构、可与下采样对齐 仅适用于max pooling、稀疏、信息可能丢失 语义分割中的SegNet结构
Transposed Convolution 用滤波器卷积输入,每次扩大后相加,等价于卷积矩阵的转置 可学习、能适应更复杂的上采样模式 可能引入“棋盘伪影”(checkerboard artifacts) FCN、UNet、GAN(如DCGAN)
Sub-pixel Convolution 低分辨率特征图先卷积产生多个通道,再“重排”成高分辨率图(如ESPCN) 学习性强,计算效率高 实现复杂,对框架支持要求高 超分辨率任务(SR)、轻量图像上采样任务
Learned Interpolation(可学习插值) 模拟插值操作但让插值权重可学习 灵活度高,可控性强 参数多,训练要求高 高质量图像重建、高级图像合成任务

推荐使用建议:

  • 想快速上采样但不需学习 → 选择最近邻或双线性;
  • 想保持结构对应关系 → 选择 Max Unpooling;
  • 想在训练中优化上采样质量 → 首选 Transposed Convolution
  • 做高端图像合成/超分辨率 → 尝试 Sub-pixel 或 Learned Interpolation。

语义分割 pipeline

语义分割的完整 Pipeline(以经典 FCN / DeepLab 为例)

1️输入图像

原始图像(比如 512 × 512 × 3)。

2️特征提取(Backbone 网络)

使用 CNN 提取图像的深层特征,常见的有:

  • VGG / ResNet / MobileNet / EfficientNet
  • 输出是低分辨率、高语义的特征图,例如 32 × 32 × 2048

3️空间维度恢复(上采样)

将低分辨率的特征图还原到原图大小,使用方法:

  • 最近邻插值(Nearest Neighbor)
  • 双线性插值(Bilinear Interpolation)
  • 转置卷积(Transposed Convolution)
  • 上采样 + 1×1 卷积(常用于 DeepLab)

4️融合细节(可选,提升边界准确性)

通过**跳跃连接(skip connections)**将低层的浅层特征与高层语义特征融合,常用于:

  • FCN(比如 FCN-8s 用了浅层和中层特征)
  • U-Net 使用大量跳跃连接

5️分类每个像素

对上采样后的特征图的每个像素点进行分类:

  • 输出为 H × W × C,其中 C 是类别数
  • 最后取 argmax 得到每个像素的类别标签

6️Loss & 训练

  • 使用 Cross-Entropy Loss 逐像素训练
  • 可加入 Dice Loss / IOU Loss 增强边界质量

整体流程总结成一句话:

输入图像 → CNN提特征 → 上采样恢复空间信息 → 融合低层细节 → 每个像素分类 → 输出语义标签图

举个例子(FCN):

  1. 输入一张猫图。
  2. ResNet 提出高语义的 7×7×2048 特征图。
  3. 用转置卷积上采样回 224×224×C。
  4. 对每个像素进行 softmax 分类(猫、狗、背景……)。
  5. 输出整张图的像素分类结果。

语义分割过度到实例分割

背景梳理

在前面我们已经讲了:

  • 目标检测(Object Detection):识别每个物体实例,并用一个 边界框 包起来(如 Faster R-CNN);
  • 语义分割(Semantic Segmentation):为 每个像素 分配一个类别,但 不区分实例,例如两只猫会被标成同一个类。

新的问题

语义分割虽然像素级别很精细,但:

  • 它不知道这张图中有几只猫;
  • 也不能区分哪一块像素属于哪只猫。

所以我们会想:有没有可能又有像素级的精度,又能分辨出“这是猫1”,“那是猫2”?

——这就引出了下一个任务:实例分割(Instance Segmentation)

Thing vs Stuff 的分类思想

作者解释,目标实例分割更适用于“事物(thing)”,不适合“东西(stuff)”,因为:

分类 含义 举例
Thing(事物) 可以明确数清楚有几个,是离散对象,可以识别每个单独实例 狗、猫、人、杯子
Stuff(东西) 没有明确边界、数量不清楚、也无意义去数,属于“连续背景” 天空、草地、海、水、路

因此:

  • 实例分割适合处理 Thing 类别
  • 而语义分割更适合处理 Stuff 类别

关键点总结

  1. 语义分割不能区分实例,只关心类别
  2. 实例分割是下一步目标,它解决“谁是谁”的问题;
  3. 在做视觉任务时要先考虑:你面对的是 thing 还是 stuff?

实例分割(基于backbone 和RPN)

为什么需要实例分割?

  • 语义分割:可以给每个像素贴标签,但不能区分同类中的不同物体(比如两只狗都标成“dog”,无法区分谁是谁)。
  • 目标检测:可以检测不同实例(用边框框出来),但没有像素级的精细轮廓。
  • 实例分割结合了两者优点:既能区分不同实例,又能输出精细的分割边界。

实例分割的完整 Pipeline(以 Mask R-CNN 为例)

输入图像

[Backbone] → 特征图

[RPN] → 一堆 RoI(目标区域)

[RoI Align]

┌────────────┬─────────────┬────────────┐
| 分类 Head │ 回归 Head │ Mask Head │
└────────────┴─────────────┴────────────┘
→ 类别 → 框位置 → 每个 RoI 的掩码

1️主干网络(Backbone)

  • 用于提取图像的基础特征图
  • 常用:ResNet + FPN(特征金字塔网络)
  • 输出:多尺度的 feature map,用于后续任务模块共享使用

2️区域提案网络(Region Proposal Network, RPN)

  • 在特征图上滑动窗口,预测**物体区域(RoI)**的候选框(bounding boxes)
  • 输出一批 RoI proposals(比如 300 个)

3️RoI Align(区域对齐操作)

  • 将每个 RoI 区域从主干特征图上裁剪出来,并进行尺寸统一(例如裁成 14×14×C)

4️多任务分支(任务 Head)

Head 类型 功能 输出
分类头 对该 RoI 属于哪个类别分类 C 类别分数
回归头 精修该 RoI 的边界框位置 4*C(每类对应 4 个坐标值)
Mask 头 预测每个 RoI 的分割掩码 C × 28×28(每类一个 28×28 的mask)

5️损失函数联合训练

  • 总 loss = 分类 loss + 回归 loss + mask loss(只对正样本 RoI 计算)

总结:

实例分割 = 通用主干网络 + RPN + 多任务 Head(分类 / 框 / mask)

每个 RoI 对应一次独立的预测。整个过程是端到端训练的。

训练方式

  • 对每个候选框,训练:
  • 分类(属于哪个类) → 分类损失
  • 回归(精细调框的位置) → 回归损失
  • 分割(前景 vs 背景) → 掩码损失
  • 掩码的监督信号来源于训练图像中已知的实例分割标签(对每个框内对象有像素级标注)。

优点

  • 结构清晰,利用 Faster R-CNN 结构,仅添加一个小分支就能做分割。
  • 可用于物体检测中的“thing”类(即可区分实例的类别,如人、狗、猫等)。
  • 预测的 mask 细节丰富,能精确覆盖对象轮廓。

限制

  • 主要用于“thing”类,不能很好处理“stuff”类(比如天空、草地等无法实例化的类别)。
  • 属于两阶段方法,速度上不如单阶段方法(如 YOLO)。

最新发展

  • Justin提到最近(几周前)刚有一个 真正成功的单阶段实例分割方法 被提出,但还不够成熟。

一些更复杂的分割任务

1. Panoptic Segmentation(全景分割)

  • 目标:同时完成语义分割和实例分割。
  • 方法:为图像中的所有像素进行分类。
  • 对“things”(可以数的物体,如人、牛等),不仅要标注类别,还要区分每一个实例
  • 对“stuff”(不可数背景,如天、树、草),只需标注类别,不分实例。
  • 意义:语义分割不区分实例,实例分割不处理stuff,而全景分割解决两者统一的问题。

2. Human Keypoints(人体关键点检测)

  • 目标:识别人身体上的关键部位坐标,用于估计姿态(pose)。
  • 方法
  • 检测图像中的人 → 分配每人一个 17个关键点(如鼻子、肩膀、膝盖等)。
  • 关键点位置以热图(heatmap)方式表示,可用CNN来回归这些热图。
  • 扩展:通过为 Mask R-CNN 添加一个新 head 来实现关键点预测。

3. General Idea: Per-Region Heads

  • 无论是掩膜预测(Mask)、关键点预测(Keypoint)、边界框分类回归,本质上都可以看作是在 Faster R-CNN 的框架中对每个 Region 添加一个 head。
  • 统一结构:每个 region 通过 RoI Pooling → 提取 feature → 输入不同的 head 模块 → 输出对应类型的预测(分类/边框/掩膜/关键点等)。

4. Dense Captioning(密集图像描述)

  • 目标:为图像中多个不同区域生成自然语言描述。
  • 方法
  • 在每个检测区域上附加一个 语言模型(如 LSTM)→ 生成对应描述。
  • 效果:不仅检测出图像中的对象,还能“说出”它是干什么的,比如“man sitting on a table”,“white laptop on table”。

5. 3D Shape Prediction(3D形状预测)

  • 目标:不仅检测对象,还预测其完整的三维形状
  • 方法
  • 在物体检测器上再接一个 head,用于输出每个对象的 3D 表征(如体素、点云、网格)。
  • 是正在研究的热门方向,下一讲会专门讲解如何处理 3D 网格。

总结:

对当前视觉任务家族的大盘点,从最初的目标检测、分割,到更丰富的目标理解(关键点、描述、三维重建)。核心思路是——只要在已有的检测网络中加入合适的“头部”结构,任何复杂的视觉任务都可以统一到一个 pipeline 里进行端到端学习。这个范式极大地提升了灵活性和性能,是现代计算机视觉的关键路线之一。

在已有的 目标检测网络(如 Faster R-CNN 或 Mask R-CNN)的基础上,我们可以通过添加不同功能的模块(head),来实现不同的计算机视觉任务。这些模块叫做“head”,每个 head 可以做不同的事,比如:

  • 分类 head:判断是狗还是猫
  • 边框 head:预测物体的边界框位置
  • 掩膜 head:做实例分割
  • 关键点 head:预测人体关节
  • 语言生成 head:做图像描述
  • 3D 预测 head:输出物体的三维结构

这些任务以前可能要分别设计不同的网络,现在只需要在**统一的主干网络(backbone)+ 提案网络(RPN)**基础上,添加一个或多个“任务模块(head)”即可。这就是:

不同的视觉任务统一到一个 pipeline 里(共享前面的大部分网络),而不同任务的输出由不同的 head 控制

这样就可以实现一个多任务学习系统,端到端训练,效率高、可扩展强。换句话说,只要检测网络搭好了,添加不同“脑袋”就能解决不同问题。