4、感知数据流设计:目标检测、语义分割、实例分割的数据流拓扑

好,咱们接着聊感知数据流。这一章我打算把目标检测、语义分割、实例分割这三条线的数据流拓扑彻底讲透。说实话,很多同学在学端到端时,容易把感知模块当成一个黑盒往里灌数据。但实际做项目时,数据流怎么走、谁先谁后、中间要不要做对齐,这些细节直接决定了你的系统能不能稳定跑起来。

4.1 三条感知任务的核心差异

先理清概念。目标检测、语义分割、实例分割,它们虽然都叫感知,但输出的数据形态完全不同。

  • 目标检测:输出的是一个个边界框(Bounding Box),每个框带一个类别标签和置信度。说白了,就是告诉系统「那里有辆车,置信度0.95」。
  • 语义分割:输出的是像素级的分类图。每个像素都被分配一个类别,比如路面、车道线、行人。但它分不清同一类里的不同个体——两辆挨着的车,在语义分割图里是同一片红色。
  • 实例分割:比语义分割更进一步。它不仅要给每个像素分类,还要区分出不同的个体。同样是车,实例分割能告诉你「这是车A,这是车B」。

我当年刚入行时,觉得语义分割和实例分割差不多,直到有一次在高速场景下做融合,发现语义分割把两辆并排的车当成了一堵墙,规控模块直接报了紧急制动。嗯,从那以后我再也不敢把这两个概念混为一谈了。

4.2 目标检测的数据流拓扑

目标检测的数据流,我个人习惯把它分成三个阶段:特征提取 → 候选区域生成 → 后处理

先看特征提取。输入是一张图像(比如 1280×720×3),经过 backbone 网络(ResNet、EfficientNet 之类的)提取特征图。这一步没什么特别的,但要注意特征图的分辨率。我建议保留至少 1/8 原图大小的特征图,否则小目标(比如远处的行人)很容易漏检。

然后是候选区域生成。这里分两派:

  • 两阶段法(Faster R-CNN 为代表):先由 RPN 网络生成一堆候选框,再对每个框做分类和回归。数据流是串行的,精度高但慢。
  • 单阶段法(YOLO、SSD 为代表):直接在特征图上划分网格,每个网格预测几个框。数据流是并行的,速度快但小目标容易丢。

最后是后处理。核心就是 NMS(非极大值抑制)。这一步其实很关键,我见过不少同学在 NMS 的 IoU 阈值上踩坑。阈值设高了,重复框多;设低了,会把挨着的两辆车合并成一个。我的经验是:城区场景用 0.5,高速场景用 0.7。为什么?城区车多且密集,阈值低一点能保留更多框;高速上车少,阈值高一点能减少误检。

数据流拓扑示意(目标检测)

输入图像 (1280x720x3)
    ↓
Backbone 特征提取 (特征图 160x90x256)
    ↓
检测头 (分类 + 回归)
    ↓
NMS 后处理
    ↓
输出: [x1, y1, x2, y2, class, confidence] 列表

4.3 语义分割的数据流拓扑

语义分割的数据流,说白了就是一个「编码器-解码器」结构。编码器负责下采样提取语义信息,解码器负责上采样恢复分辨率。

这里有个坑:下采样太狠,小物体就没了。我在项目中遇到过,用 MobileNet 做编码器,下采样到 1/32 原图大小,结果车道线断成了好几截。后来我改用 DeepLabV3+ 的 ASPP 模块,多尺度特征融合一下,效果好了很多。

语义分割的输出是一张单通道的类别图。比如有 10 个类别,每个像素的值就是 0~9 的整数。但注意,这个输出通常要经过 argmax 操作,把每个像素的 softmax 概率转成具体的类别 ID。

小技巧:如果你在做端到端训练,建议保留 softmax 概率图而不是 argmax 后的类别图。因为概率图保留了不确定性信息,规控模块可以利用这个信息做更安全的决策。比如某个像素的类别概率是 0.6,说明模型不太确定,那规控就应该保守一点。

数据流拓扑长这样:

输入图像 (1280x720x3)
    ↓
编码器 (下采样至 40x23x512)
    ↓
ASPP / 特征金字塔 (多尺度融合)
    ↓
解码器 (上采样至 1280x720)
    ↓
Softmax + Argmax
    ↓
输出: 类别图 (1280x720, 每个像素 0~9)

4.4 实例分割的数据流拓扑

实例分割是三者中最复杂的。目前主流方案有两种:Mask R-CNN 系列基于 Transformer 的方法(如 Mask2Former)

拿 Mask R-CNN 举例,它的数据流是:

  1. 先走目标检测的流程,生成候选框。
  2. 对每个候选框做 RoI Align,把不同大小的框统一成固定尺寸(比如 14×14)。
  3. 然后并行跑两个分支:一个做分类和框回归,另一个做像素级的 mask 预测。

你想想看,这里的数据流其实有个瓶颈——RoI Align 是串行的。如果一张图里有 100 个候选框,就要做 100 次 RoI Align。这在实时性要求高的场景下很要命。

我建议的做法是:控制候选框数量。训练时可以用 256 个框,但推理时我一般只保留前 100 个置信度最高的框。再多的话,延迟就上去了,而且很多低置信度的框其实都是噪声。

注意:实例分割的输出数据量很大。一张 1280×720 的图像,如果有 50 个实例,每个实例对应一个 1280×720 的 mask(二值图),那光 mask 数据就有 50×1280×720 ≈ 4600 万个像素。这在传输到下游模块时,带宽压力非常大。我建议只保留实例的轮廓点(polygon)或者压缩后的 mask,而不是原始的二值图。

数据流拓扑:

输入图像 (1280x720x3)
    ↓
Backbone 特征提取
    ↓
RPN 生成候选框 (Top-100)
    ↓
RoI Align (统一尺寸 14x14)
    ↓
┌─────────────────┬─────────────────┐
│ 分类 + 框回归    │ Mask 预测        │
│ (全连接层)       │ (全卷积网络)     │
└─────────────────┴─────────────────┘
    ↓                    ↓
类别 + 边界框        二值 mask (28x28)
    ↓                    ↓
输出: 实例列表 (每个实例: 类别, 框, mask)

4.5 三条数据流的对齐与融合

在实际的端到端系统中,这三条数据流往往是并行跑的。但问题来了——它们的输出怎么对齐?

举个例子。目标检测输出的是「车」的边界框,语义分割输出的是「路面」的像素区域,实例分割输出的是「那辆红色车」的 mask。这三个输出在空间上是有重叠的,但它们的坐标系、分辨率、时间戳可能都不一样。

我的做法是:统一到鸟瞰图(BEV)坐标系下。先把所有感知结果通过相机内外参投影到 BEV 空间,然后再做融合。这样目标检测的框、语义分割的区域、实例分割的 mask 就都在同一个空间里了。

但这里有个细节要注意——时间对齐。不同感知模块的处理速度不一样。目标检测可能 30ms 出一帧,语义分割 50ms 出一帧,实例分割 80ms 出一帧。如果你不做时间对齐,规控模块拿到的就是不同时刻的感知结果,那决策就会乱套。

我建议在感知模块后面加一个时间同步缓冲区。缓冲区里存最近 100ms 内的所有感知结果,然后以规控模块的触发时刻为准,取时间戳最接近的那一组数据。说白了,就是「谁先到就用谁,但保证时间差不超过 50ms」。

总结一下三条数据流的关键点

任务 输出格式 主要瓶颈 我的建议
目标检测 边界框列表 NMS 阈值 城区 0.5,高速 0.7
语义分割 像素类别图 下采样倍数 保留 softmax 概率图
实例分割 实例 mask 列表 RoI Align 串行 推理时只取 Top-100 框

好了,这一章的内容就到这里。下一章我会讲融合数据流的设计,到时候咱们再聊聊怎么把这三条数据流真正拧成一股绳。记住,感知数据流的设计没有银弹,关键是根据你的场景和硬件资源做取舍。你想想看,是不是这个理?