2. 语义分割基础
在进入 Jetson 平台的部署实战之前,必须先厘清语义分割这一任务的基本面貌。很多初学者容易将语义分割与目标检测、实例分割混为一谈,导致在模型选型、输出解析和后处理逻辑上出现方向性错误。本章将从任务定义出发,系统梳理语义分割与相邻视觉任务的边界,介绍主流数据集与评价指标,为后续在 Jetson 上部署分割模型打下坚实的认知基础。
核心原理:从像素到语义的映射
语义分割(Semantic Segmentation)的本质是对图像中的每一个像素赋予一个语义类别标签。与目标检测输出矩形框不同,语义分割的输出是一张与输入图像尺寸相同的"标签图"(Label Map),其中每个像素位置的值代表该像素所属的类别编号。例如,在一张街景图像中,所有属于"道路"的像素都会被标记为类别 0,所有"行人"像素标记为类别 1,以此类推。
从数学角度看,语义分割可以形式化为一个逐像素分类问题。给定输入图像 \( I \in \mathbb{R}^{H \times W \times 3} \),模型输出一个概率张量 \( P \in \mathbb{R}^{H \times W \times C} \),其中 \( C \) 是类别总数。每个位置 \( (i,j) \) 上的向量 \( P[i,j,:] \) 经过 Softmax 归一化后,表示该像素属于各个类别的概率。最终预测标签为 \( \hat{y}_{i,j} = \arg\max_c P[i,j,c] \)。
在 Jetson 平台上部署语义分割模型时,这个 argmax 操作通常被放在后处理阶段完成。因为模型输出的原始张量是浮点型的概率值,而最终需要的是整数型的标签图,两者之间的转换涉及数据类型的转换和内存布局的调整,这在嵌入式平台上需要特别注意效率。
与目标检测、实例分割的本质区别
理解三种视觉任务的差异,是选择模型和设计后处理流程的前提。下表从多个维度进行了对比:
| 对比维度 | 目标检测 | 实例分割 | 语义分割 |
|---|---|---|---|
| 输出粒度 | 物体级(边界框) | 实例级(掩码) | 像素级(类别) |
| 是否区分个体 | 是(每个框独立) | 是(每个实例独立掩码) | 否(同类像素合并) |
| 输出形式 | (x, y, w, h, cls, conf) | 掩码 + 类别 + 置信度 | H×W 标签图 |
| 后处理复杂度 | NMS 去重 | NMS + 掩码裁剪 | argmax + 可视化 |
| 典型模型 | YOLO, SSD, Faster R-CNN | Mask R-CNN, YOLACT | DeepLab, UNet, PSPNet |
| Jetson 部署难点 | 框的坐标解码 | 掩码上采样 | 高分辨率特征图内存占用 |
一个关键的区别在于:语义分割不区分同一类别的不同个体。例如,画面中有三个人,语义分割会将所有"人"像素标记为同一个类别编号,而实例分割会分别标记为 person_1、person_2、person_3。这个差异直接影响了模型输出的通道数和后处理逻辑。在 Jetson 部署时,如果业务场景只需要知道"哪里有道路、哪里有障碍物",语义分割就足够;如果需要"跟踪第一个人、避开第二个人",则需要实例分割。
常见数据集与评价指标
在 Jetson 上部署模型之前,通常需要先在标准数据集上评估模型性能。以下是语义分割领域最常用的数据集:
- PASCAL VOC 2012:包含 20 个物体类 + 1 个背景类,共 21 类。图像分辨率较低(约 500×375),适合快速验证模型结构。该数据集规模较小(约 1.5K 训练图),常用于学术研究和模型原型验证。
- Cityscapes:专注于城市街景理解,包含 19 个类别(道路、行人、车辆、建筑等)。图像分辨率为 2048×1024,标注精细,是自动驾驶场景的基准数据集。在 Jetson 上部署时,通常需要将输入分辨率降至 1024×512 或更低以满足实时性要求。
- ADE20K:包含 150 个类别,覆盖室内外场景,场景多样性高。该数据集对模型的泛化能力要求较高,适合评估模型的场景理解能力。
- COCO-Stuff:在 COCO 数据集基础上增加了"stuff"类(天空、草地等),共 171 类。适合需要区分物体与背景材质的应用场景。
评价指标方面,最核心的两个指标是 mIoU(Mean Intersection over Union)和 PA(Pixel Accuracy)。
mIoU 的计算方式为:对于每个类别 \( c \),计算预测结果与真实标签的交集面积与并集面积之比,然后对所有类别取平均。公式如下:
mIoU = (1/C) * Σ_c [ TP_c / (TP_c + FP_c + FN_c) ]
其中 \( TP_c \) 表示类别 \( c \) 的真阳性像素数,\( FP_c \) 为假阳性,\( FN_c \) 为假阴性。mIoU 对类别不平衡不敏感,是语义分割最权威的评价指标。例如,在 Cityscapes 上,优秀的模型 mIoU 通常在 75-82% 之间。
PA 的计算则简单得多:所有预测正确的像素数除以总像素数。公式为:
PA = Σ_c TP_c / Σ_c (TP_c + FN_c)
PA 的缺点是当某个类别占主导地位时(如背景占 90% 像素),即使模型完全忽略小类别,PA 也可能很高。因此,在 Jetson 部署时,建议同时关注 mIoU 和 PA,并针对业务场景中的关键类别单独计算 IoU。
部署视角的指标解读:在 Jetson 上评估模型时,除了 mIoU 和 PA,还必须关注 推理帧率(FPS) 和 显存占用。一个 mIoU 为 78% 但只有 5 FPS 的模型,在实时视频分析场景中可能不如一个 mIoU 为 72% 但有 25 FPS 的模型实用。建议在 Jetson 上使用 TensorRT 加速后,重新测量这些指标,因为 TensorRT 的层融合和精度校准(FP16/INT8)会同时影响速度和精度。
案例拆解:Cityscapes 模型在 Jetson 上的评估流程
假设我们需要在 Jetson Orin Nano 上部署一个语义分割模型,用于识别道路、行人和车辆。以下是完整的评估与决策流程:
背景与约束:设备为 Jetson Orin Nano 8GB 版本,输入视频流为 1080p@30fps,但允许将输入分辨率降至 960×544 以换取速度。业务要求 mIoU ≥ 70%,帧率 ≥ 15 FPS。
初始现象:直接使用 PyTorch 的 DeepLabV3+(ResNet-50 骨干)在 Jetson 上推理,输入 960×544 时帧率仅为 4.2 FPS,显存占用 2.1GB,mIoU 为 76.5%。显然帧率不达标。
分析过程:通过 profiling 工具发现,瓶颈在于 ResNet-50 的 4 倍下采样层和 ASPP 模块的空洞卷积在 CUDA 上效率不高。同时,PyTorch 的 eager 模式存在大量 kernel launch 开销。
实际操作步骤:
- 将模型导出为 ONNX 格式,使用 TensorRT 进行 FP16 精度优化。转换后帧率提升至 11.8 FPS,显存降至 1.2GB,mIoU 略微下降至 75.8%。
- 进一步尝试 INT8 量化,使用 Cityscapes 验证集 200 张图作为校准数据。INT8 后帧率达到 19.6 FPS,显存 0.8GB,但 mIoU 降至 71.2%,仍满足 ≥70% 的要求。
- 为了提升 INT8 精度,将输入分辨率从 960×544 降至 832×480,mIoU 回升至 72.5%,帧率提升至 22.3 FPS。
结果对比:最终方案(TensorRT INT8 + 832×480)相比初始方案,帧率提升 5.3 倍,显存降低 62%,mIoU 下降 4 个百分点,但仍在业务容忍范围内。
风险与代价:INT8 量化在光照剧烈变化或罕见类别出现时可能出现精度骤降。为此,我们在后处理中增加了一个简单的置信度过滤:当某个像素的最大类别概率低于 0.5 时,将其标记为"未知"类别,避免错误输出。
复盘经验:在 Jetson 上部署语义分割,不要盲目追求高分辨率输入。优先使用 TensorRT 的 FP16 作为基线,再根据精度余量决定是否启用 INT8。同时,后处理中的 argmax 和颜色映射应使用 CUDA 核函数或 TensorRT 的插件实现,避免在 CPU 上进行逐像素循环。
常见误区与总结复盘
在语义分割的 Jetson 部署中,以下误区需要特别注意:
误区一:忽略类别不平衡问题。在 Cityscapes 中,"道路"类别可能占 30% 像素,而"摩托车"可能不足 1%。如果只关注 PA,模型可能完全忽略摩托车。正确做法是使用 mIoU 作为主要指标,并单独检查每个类别的 IoU。
误区二:后处理在 CPU 上逐像素循环。对于 960×544 的输出,逐像素 argmax 在 CPU 上需要约 15ms,这几乎占用了 1/3 的帧预算。正确做法是使用 CUDA 的 atomicMax 或 TensorRT 的 TopK 层在 GPU 上完成。
经验提醒:在 Jetson 上,语义分割模型的输出张量通常是 [1, C, H, W] 的浮点格式。在转换为可视化图像时,建议使用预计算的 lookup table 将类别 ID 映射为 RGB 颜色,避免在运行时进行复杂的颜色计算。同时,如果只需要标签图而不需要可视化,可以直接输出 uint8 类型的标签图,减少内存拷贝。