☰
Mapillary Vistas街景语义分割实战:从数据映射到模型定制全流程
2026/10/19 10:46:43 网站建设 项目流程

先交代一下背景。街景语义分割这类任务,这几年接到的需求一直没断过,而绝大多数项目的前提条件都绕不开公开数据集Mapillary Vistas。这数据集对做城市感知、自动驾驶、甚至智慧城市项目的人来说,基本算绕不过去的一个底座。标题里写“接代做”,实际干过这行的人都懂,这通常意味着不是简单跑个开箱demo,而是要针对客户的具体场景做模型定制、类别调整、精度调优,甚至从数据清洗到推理落地整套流程都包掉。

这类项目做多了,最深的体会是:Mapillary Vistas就是个“前期省心、后期费脑”的典型。省心是因为它覆盖面广、类别全、标注质量高,拿来当弱监督预训练、当骨干特征提取的底座都非常合适;费脑则是它66类的细粒度标签体系,直接套在任意业务场景里往往又大又笨,类别不平衡、混淆对、推理耗时这些问题全靠后期人工处理。这篇文章就把我实际做这类定制项目时从数据选型、类别设计、模型训练到踩坑排错的全过程整理出来,给准备接这类任务的人做个参考。

1. 项目需求拆解与常规误区

1.1 先搞清楚“代做”到底代的是什么

很多人一听“街景语义分割代做”,以为就是丢一个数据集进去、出一个mIoU指标就完事了。但真实项目里的需求形态,至少有四种完全不同的做法:

  • 完整重训:客户给一批自己的街景图,要求从头训一个模型,Mapillary Vistas只是拿来当预训练或辅助数据用。这种最吃机器和时间,动辄几十小时训练跑着是常态。
  • 类别扩展:客户已经在用某个17类或者8类的轻量分割模型,现在要扩到“人行道、路面标识、锥桶、栏杆”这些细粒度类别,就需要把Mapillary Vistas的标注体系映射到业务类别上做增量类别训练。
  • 单类精度冲刺:业务方只关心一辆车、一个人在画面里的分割质量,其他类别全都算背景。这时候用66类全量训练再谈精度纯属浪费,更合理的是用Mapillary Vistas预训练权重做迁移,把loss权重往目标类别上压。
  • 端侧/实时场景适配:自动驾驶边缘盒子、巡检机器人上对推理延迟有硬指标,但Mapillary Vistas的1024分辨率大图和66类输出天然不适合端侧直接跑,需要做类别软合并、模型蒸馏、量化剪枝这一整套流程。

我在接需求时,第一步永远是问清楚对方拿分割结果去干什么:是画可视化报告,还是进决策链路?这两者的质量要求天差地别。画图看个大概的,类别软合并做粗糙点无所谓;一旦进了决策链路,比如“路面标识”被分到“道路”里导致车身控制误判,那是要出大事故的。

1.2 为什么首选Mapillary Vistas做基座

市面上的街景分割数据集其实不少,Cityscapes是最常见的,但做定制项目时我还是更倾向于拿Mapillary Vistas打底。原因在于它的采集设备和环境多样性。

Cityscapes说到底是从车载摄像头上拍的,以德国城市为主,天气和场景相对单一。Mapillary Vistas则是来自众包采集的全景图片,包含不同国家、不同道路类型、不同季节、不同天气,甚至还有大量非车载视角的画面。它自带一个属性:全景图经过柱面投影展开后,物体形变比普通针孔相机拍出来的更剧烈。如果模型在这个数据上能扛住形变,换到普通摄像头场景时鲁棒性通常不会差。

另一个关键点是它的标签体系。Mapillary Vistas提供了66个细粒度类别,还能按层级关系聚合成大类别。这意味着我可以根据需要自由做类别映射,比如把“人行道”“非机动车道”“路肩”合并成一个宽泛的“可行驶区域”或者把“机动车道”“非机动车道”拆分得更细。Cityscapes想做这种自由映射就很别扭,它本身的类别粒度就卡在那里。

1.3 这类项目最常见的交付物清单

定制项目交付的东西,不只是模型权重文件那么简单。快速明确交付边界能省掉后期大量扯皮:

  • 模型文件:包括训练好的权重、完整的配置文件、训练日志。
  • 推理脚本:能跑单张图、视频流、批量图片目录三种模式。
  • 可视化结果:至少包含叠加掩码图、纯掩码图、类别统计JSON。
  • 精度报告:按类别给出IoU、Precision、Recall,要一并给出验证集划分方式。
  • 中间产物:类别映射表、数据清洗脚本、预处理脚本,这些能让你在下一次迭代时不用重新解释自己当时怎么处理的数据。

有些客户还会要求解释某个类别的典型错误模式,比如“路灯为什么老是被分进电线杆”,这类分析报告做起来费时间,但在投标和验收阶段往往是加分项,也是展现技术深度的机会。

2. 数据集标签体系与预处理细节

2.1 数据规模与标注结构

Mapillary Vistas目前对外使用的常见版本包含25000张高质量精细标注的全景图,另外还有30000张左右的弱标注数据用于辅助训练。弱标注数据只有粗粒度的类别,没有实例级标注,质量也参差不齐,我通常只拿它做backbone预训练或半监督学习,不直接混入主训练集。精细标注的25000张里,官方默认划分train/val,通常取18000张左右做训练,2000张做验证,剩下的归入测试但标签不公开。这里的划分细节不同版本有差异,拿到数据后第一件事就是核对一下数据清单和官方README里的说明,别默认它的划分就适合你的需求。

每一张全景图官方给的标签文件包含三个PNG:

  • labels.png:以RGB颜色编码标注的语义类别,每个类别对应一个固定RGB值,用于人眼可视化。
  • labels_id.png:单通道索引图,每个像素直接存类别ID,范围0-65,这才是训练时真正要读的文件。
  • instance_id.png:单通道实例图,对每个独立物体实例做编号,比如两辆不同的车ID不同。语义分割用不到它,但做实例分割或追踪任务时它是宝贵标注。

训练时最常犯的一个错是拿labels.png这种RGB图放进CrossEntropyLoss里去算损失,因为RGB值是人为指定的三个通道组合,和类别空间没有任何有序关系,模型根本学不出正确的类别边界。正确做法永远是读labels_id.png,再把它映射成从0开始连续的trainId。

2.2 66类体系与层级聚合逻辑

Mapillary Vistas的66个类别,被官方组织成了16个物理分组:地面、植被、道路、建筑、车辆、交通标志、物体、行人和动物等。设计逻辑上它们分三层:

  • 一级类别比较粗,比如“manmade”把所有人工构筑物归在一起。
  • 二级类别就到了具体的语义级,比如“building”“garage”这类。
  • 三级类别最细,比如把“vehicle”细分成“car”“truck”“bus”“trailer”“motorcycle”等。

实际项目中我很少直接训66类,原因很简单:细粒度类别之间过于相似,比如“护栏”和“墙体”在远处看就是一条连续的灰色线,在近处才看得出结构差异。强行训练会导致这些小类互相抢占像素,模型整体指标反而被拉低。更合理的做法是设计一套目标类别映射,把66类收敛到客户真正关心的十几类甚至七八类。

我常用的一套自定义映射大致是:

  • 背景/未标注:0
  • 道路:包括road、lane marking中的部分行驶路面
  • 人行道:sidewalk、pedestrian area
  • 建筑:building、garage、car port这类
  • 车辆:car、truck、bus、trailer、motorcycle、bicycle
  • 行人:person、rider
  • 植被:vegetation、tree、brush、grass
  • 交通设施:traffic sign、traffic light、pole、banner这类
  • 天空:sky单独成类
  • 其他动态物体:动物、其他种类等全部并到背景

这套映射出来后,训练类别数从66降到8-10个,模型收敛速度、单类IoU、推理速度都会明显改善。代价就是丢失细节,但绝大多数业务只关心宏观区域分割,接受度很高。

2.3 类别不平衡到底有多严重

街景数据天然存在严重的类别不均衡:天空、建筑、道路这三类占掉大半图像面积,而行人、自行车、摩托车、交通锥这些小目标占比可能连1%都不到。按像素数算CrossEntropy的话,模型会偏向学那些大块区域,小目标类别基本学不出来。

解决策略我从经验出发,分成三个梯度:

  • 最基础的做法是算每个类别的像素频率,做类别权重反比,loss里给稀有类别更高权重。
  • 进阶做法是用OHEM策略,在每批样本里只选loss最高的那些像素参与反向传播,让模型把重点放在困难像素上而不会被简单背景的梯度淹没。
  • 更有效的是多尺度+大输入图像训练,因为小目标在低分辨率下几乎已经消失在背景里,模型根本没有像素信息可学。

实践证明,三者叠加使用效果最稳。只做权重反比容易出现“模型为了照顾小目标把大片背景误判成小目标”的过冲现象,而OHEM可以天然约束这种过冲。

2.4 预处理流水线里的隐藏坑

数据预处理阶段最容易翻车的是labels_id和trainId的索引对应关系。Mapillary Vistas的labels_id里存的是0-65的原始索引,但其中有一些类别编号不连续。直接把0-65丢给模型当类别数会踩两类问题:

  • 某些索引对应的原始类别在labels.png里是空洞、未标注区域,占比不小,它会显著干扰边界学习和loss统计。
  • 不同业务场景要合并的类别不一样,直接在原始索引空间里合并很容易把“应该合并的两类”和“不该合并的中间ID”搞混。

所以我每次都会在数据加载阶段单独做一张颜色转trainId的映射表,先读入labels.png的RGB值,再通过查询表转成自定义类别ID。虽然读取RGB PNG会比直接读索引图多花一些IO时间,但换来的是永不出错的类别映射逻辑。完整示例代码大致是这样:

import numpy as np from PIL import Image # 定义业务类别与RGB的对应关系,key为业务类别id,value为该类别包含的原始RGB元组列表 class_rgb_map = { 0: [(0, 0, 0)], # 背景/未标注 1: [(128, 64, 128)], # 道路 2: [(244, 35, 232)], # 人行道 3: [(70, 70, 70)], # 建筑 4: [(220, 20, 60)], # 车辆 5: [(119, 11, 32)], # 行人 6: [(107, 142, 35)], # 植被 7: [(70, 130, 180)], # 天空 } # 建立反向查表:原始RGB -> 业务类别id rgb2cls = {} for cls_id, colors in class_rgb_map.items(): for rgb in colors: rgb2cls[rgb] = cls_id def convert_labels_png_to_train_id(labels_png_path): img = Image.open(labels_png_path).convert('RGB') arr = np.array(img) h, w, _ = arr.shape out = np.zeros((h, w), dtype=np.uint8) # 向量化映射:把每个像素的RGB打包成tuple后查字典 flat = arr.reshape(-1, 3) keys = tuple(map(tuple, flat)) # 默认把所有未映射到的类别归为背景0 out_flat = np.array([rgb2cls.get(k, 0) for k in keys], dtype=np.uint8) return out_flat.reshape(h, w)

这段脚本是给新手参考的简化版本,直接按像素循环查字典速度很慢。真跑全量数据集时,建议用numpy的索引方式一次建一张256x256x256的LUT表,把RGB直接映射到trainId,速度能提升几十倍。工作流里我一般会提前把全部标签离线转换好存成npy或者uint8的PNG,训练时不再做实时映射,省掉一个明显的IO瓶颈。

3. 模型选型与训练策略

3.1 网络结构怎么选才不亏

街景语义分割的主流选择有三个方向:DeepLabV3+系列、Transformer系列的SegFormer/UPerNet、以及高分辨率网络HRNet。三者各有各的脾气。

DeepLabV3+配ResNet骨干,非常成熟稳定,部署生态也最好。它的空洞卷积能在不损失分辨率的情况下扩大感受野,对大块的“建筑物、天空、道路”这类上下文要求高的区域处理得很好。缺点是Transformer时代后精度天花板略低,想在Mapillary Vistas上刷高mIoU需要把输入分辨率拉很高,显存压力大。

SegFormer这类纯Transformer方案全局建模能力强,对街景里长距离依赖(比如一条连续的栏杆、延伸到远处的道路边线)很有效。它不需要位置编码,并且层级式设计直接输出多尺度特征,分割头不用额外做FPN。缺点是训练时对数据量和优化器要求敏感,小数据上容易掉点;推理时部分设备上TensorRT支持不如纯CNN成熟。

HRNet全程保持高分辨率特征,对小目标和细长结构特别友好,行人和电线杆这类目标能保留更多细节。代价是计算量大、显存占用高、训练速度慢,适合对细节有执念且算力充足的场景。

我做项目的保守选择是:如果客户只要求能跑、精度靠谱、部署方便,默认DeepLabV3+ ResNet101;如果客户想在榜单上冲一下或者场景特别复杂,用UPerNet配ConvNeXt或InternImage这种增强型骨干;HRNet只留给那些明确要处理“行人姿态边缘、细小横杆”等细节类别的项目。

3.2 输入分辨率与训练批次的具体建议

输入分辨率直接决定分割结果的精细度。Mapillary Vistas原始图是全景展开图,宽高比通常是2:1左右,常见尺寸是1024x512或者2048x1024。直接整图训练多数显卡吃不消,需要裁剪策略。

我的经验数值是:单卡训练时用768x768或者1024x512的随机裁剪,配合多尺度增强,效果远好于用512x512这种小尺寸。分辨率上不去的话,小目标类别IoU会掉得很明显,尤其“自行车”这类宽度可能只有20像素的物体。到了推理阶段,再用滑窗或者切分策略跑更大尺寸,比如把2048x1024切成四块各1024x512,分别推理再拼接。

批次大小上,语义分割任务batch size在8-16之间最稳。Batch太小,BatchNorm统计量不稳定,特别是全景图里大块类别比例差异大时,小batch的均值方差抖动得很厉害。如果显存只够跑batch 2或4,建议直接用同步BN替代普通BN,或者换成GroupNorm这类不依赖batch统计量的归一化层。

3.3 Loss设计:别只盯着CrossEntropy

单用CrossEntropy在街景分割上基本到了天花板就会遇到两个问题:一个是类别不均衡导致稀有类学不动,另一个是边界区域像素往往模糊、难以判断,模型容易在边界上犹豫不决。

我常用的组合是主损失用CrossEntropy加上OHEM策略,辅助损失加一个Dice Loss或者Focal Loss。其中Dice Loss对前景小目标的作用最直观,它直接优化区域重叠率而非逐像素分类准确率,即便目标只占图面0.5%,梯度信号也不会被淹没。实际复现时一般按0.9的CE权重加0.1的Dice权重搭配,效果最稳定。你要是直接把Dice权重调到0.5以上,训练初期loss会震荡得非常厉害,因为小目标稍微预测偏一点Dice就骤降,数值上很不友好。

Focal Loss在小目标检测里常用,语义分割里用它会有一个副作用:对简单大块区域的梯度压得太低,导致模型收敛速度变慢。如果只是想提升小目标,Dice比Focal更直观。想用Focal的话,建议把gamma控制在1.5以内。

3.4 学习率调度与训练时长估算

SegFormer类Transformer训练时需要用AdamW,配合poly学习率衰减,power设为0.9或1.0,初始学习率3e-5到6e-5为常见区间。CNN类比如DeepLabV3+可以用SGD动量0.9加poly策略,初始学习率0.01到0.02。两者在最开始的两三个epoch都要加warmup,把学习率从很小的值线性升上去,避免模型甫一接触大梯度就震荡发散。

训练时长这块,25000张图如果跑500个epoch,单张V100或A100上DeepLabV3+ ResNet101、batch size 8、输入768,大约需要两到三天。如果时间有限,我会先用弱标注数据做一轮自监督预训练,再用精细数据微调,整体时长能压缩三分之一,精度还往往比直接训练更高。

4. 从数据到推理的完整落地流程

4.1 Step 1:数据清单核对与类别映射

拿到Mapillary Vistas压缩包后,第一件事是解压并确认目录结构。常见结构类似:

mapillary-vistas/ training/ images/ labels/ instances/ panoptic/ validation/ images/ labels/ instances/ panoptic/

先把training与validation数量核对一遍,确认和官方说明一致。随后按2.4节的方式生成一个全量类别映射表,这一步会生成两类文件:一个记录“原始类别ID -> 业务类别ID”的JSON,一份离线转换好的trainId标签图。完成后跑一个简单的统计脚本,输出每个类别在train和val里的像素占比。如果某个业务类别在train里样本数太少且val为空,需要提前处理,别等到训练完才发现验证集某个类别直接报零。

4.2 Step 2:训练配置文件实例

下面的配置是参考我跑过一个8类定制项目的记录整理而成,结构上是典型的单卡训练模板,直接抄作业时按自己设备改batch size就行。

model: name: deeplabv3plus backbone: resnet101 output_stride: 8 num_classes: 8 dataset: root: ./data/mapillary_vistas train_split: training val_split: validation crop_size: [768, 768] scale_range: [0.5, 2.0] hflip: true brightness: 0.4 contrast: 0.4 saturation: 0.4 train: batch_size: 8 epochs: 400 optimizer: sgd lr: 0.02 momentum: 0.9 weight_decay: 0.0001 lr_policy: poly power: 0.9 warmup_epochs: 3 loss: ce_weight: 0.9 dice_weight: 0.1 ohem_ratio: 0.3 ema_decay: 0.999 val: interval: 10 metrics: [miou, category_iou] inference: stride: 768 tta: hflip: true scales: [0.75, 1.0, 1.25]

几个关键参数的说明:

  • output_stride选8而不是16,会让最后的特征图分辨率更高,小目标细节保留更多,代价是显存加大。显存不够时优先降到16。
  • scale_range到0.5和2.0是为了模拟全景图里物体远近差异巨大的情况。
  • ohem_ratio 0.3代表每张图只对loss最高的30%像素做反向传播,能有效聚焦难例。
  • ema_decay设置0.999,相当于给权重做滑动平均,推理时用ema权重而非训练中最后一步的权重,通常能稳定提升1到2个mIoU点。

4.3 Step 3:训练与验证

训练日志里除了loss,每间隔10个epoch记录mIoU和每个类别的IoU。我习惯在训练输出里单独打印每个类别的IoU,而不是只看一个平均分。原因很简单:平均mIoU被道路、建筑这种大类别撑得很高,往往在0.85以上,而行人IoU可能只有0.5,业务上恰恰最关心行人类别。

验证时有一个细节很多人会忽略:滑窗推理的overlap设置。全景图切成crop时,相邻窗口之间保留一定重叠区域,能减少边缘拼接伪影。重叠比例一般取crop的20%左右,也就是768x768的窗口步长设640左右,重叠128像素。拼接时可以使用高斯权重融合,对重叠区域按距离加权平均,效果比直接硬拼接平滑得多。

4.4 Step 4:推理脚本与后处理

最终交付的推理脚本至少响应两种输入:单张图片和批量目录。核心流程是读图、归一化、前向得到logits、argmax得到类别、再映射回可视化RGB图。多尺度TTA时,把原图分别放到0.75、1.0、1.25三个尺度上推理,将softmax概率图缩放到原始尺寸后取平均,最终argmax。TTA能稳提1到3个点,但推理耗时乘好几倍,不适合实时场景,只适合交付离线处理任务。

后处理里CRF这类传统方法在街景分割上现在用得越来越少,因为深度模型的输出已经比较平滑,CRF带来的提升大多小于0.5个点,而且推理耗时暴增。更值得做的是类别级形态学后处理:比如对“道路”类做连通域分析,去除孤立小斑块;对“行人”类做轻微膨胀,防止人体边缘出现空洞。这类规则式后处理在业务里很实用,因为业务方往往对“误检成路边石块的行人”这种结果零容忍。

5. 常见问题与排查技巧实录

5.1 训练loss正常下降但验证mIoU上不去

这类问题出现率极高,原因通常不在模型,而在验证集上的类别映射或预处理逻辑与训练集不一致。最常见的是读取验证标签时用了错误的编码方式,导致某个业务类别在验证标签里全部变成了背景。排查时我会先打印几个验证样本的标签类别分布直方图,核对每个类别的像素占比是否和训练集同级别。如果验证里某个类占比是0,检查标签读取和映射逻辑的代码路径有没有和训练分支分开写。

5.2 小目标类别IoU长期为0

训练很久后“自行车”或者“红绿灯”甚至不出现,大概率是这批小目标在裁剪时被随机裁掉了。输入图尺寸768x768,原图里行人和自行车本来就只占很小一块,随机crop时很有可能会错过所有含小目标的区域。一个简单有效的补救措施是把crop改成针对小目标的多尺度采样:先跑一遍目标检测或者用类别分布的启发式规则,定位含稀有类的区域,在这些区域周围多crop几次,形成对小目标过采样。另一个兜底手段是直接缩放到0.5倍再训练,让每个crop覆盖更大的原始视野,小目标被包含进来的概率会高很多。

5.3 训练中显存溢出

全景图大尺寸加高分辨率crop,显存很容易爆。优先建议按顺序试:降低batch size到4或2、把output_stride从8改成16、用AMP混合精度训练、把backbone从ResNet101换ResNet50。如果batch size已经降到2还是爆,检查一下数据加载管线是否把原始大图也一并加载进显存了,有些实现会在DataLoader里保留原图用于可视化,这很占显存。

另一个容易被忽略的点是SyncBN:当batch size只有2时,多卡的同步BN也不一定救得回来,因为每张卡的batch只有2,统计量依然不稳定。这种时候与其硬调BN,不如换成GroupNorm,把特征图分组归一化,完全不受batch大小影响,效果在分割任务里基本持平。

5.4 推理速度不达标

Mapillary Vistas训出来的模型往往偏重,直接部署到端侧时帧率很难看。优化思路按性价比排序:类别数从66降到你业务真正需要的8类,输出logits少一个数量级,速度提升明显;把分辨率从1024降低到512并配合TensorRT的FP16推理;backbone蒸馏,用ResNet18或轻量Transformer当学生模型,拿大模型logits做蒸馏。实测下来,66类降到8类加512分辨率这两步,通常能把推理耗时压到原来的四分之一。

5.5 问题与排查速查表

现象可能原因处理方案
train loss下降但val mIoU停滞验证集类别映射不一致打印验证集类别直方图,核实映射代码
小目标类别IoU为0随机crop覆盖不到小目标稀有类过采样+多尺度缩放增强
显存溢出crop过大或batch过大降分辨率先跑通,再逐步提高
推理速度慢类别数多、分辨率高、模型重类别裁剪、TensorRT FP16、轻量模型蒸馏
边界出现锯齿和空洞输入分辨率不足或后处理缺失提高crop尺寸、加连通域过滤和膨胀后处理
两类别互相混淆语义相似且特征弱增加同类别共同出现的样本,细化标注权重

6. 定制项目中容易忽略的交付细节

6.1 业务类别映射表要由对方签字确认

这是踩过最大的坑之一。训练前我把Mapillary Vistas的66类映射成10类,感觉顺理成章,但客户验收时拿着他们自己对“人行道”的定义来对照,发现我把“路肩”也并进了人行道,而业务方的路肩属于机动车道的缓冲区,不能画成人行道。训练都跑完了才返工,非常浪费时间。正确做法是一开始就把映射表列成一个可视化对照文档,标出每个业务类别源自哪些原始类别,让客户逐行确认再动工。

6.2 单类精度与整体精度的取舍

客户经常会同时提出两个互相矛盾的需求:希望整体mIoU不低于0.85,又要求“行人”单类IoU不低于0.7。这两个目标很难同时满足,整体mIoU被大类别主导,强行提升行人IoU往往会牺牲道路和天空的精度。接需求时遇到这种情况,我会直接说明约束关系,引导对方选择:是保整体效果还是保少数关键类别。然后在训练里把关键类别权重调高并单独汇报该类别的IoU曲线,而不是用一个平均数掩盖问题。诚实沟通反而是项目顺利验收的关键。

6.3 数据版本与实验可复现性

Mapillary Vistas版权条款允许研究使用,但商用时需要逐条确认授权边界,这一点建议在项目开始前就查清最新条款。另外项目过程中我通常对数据、标签映射、训练配置、模型权重分别做版本记录,每次都留下一个可复现的配置文件。几次迭代下来,哪个配置跑出过最好结果一目了然,客户要求复现某个历史版本时也不至于手忙脚乱。

6.4 模型鲁棒性的快速验证

只在一个验证集上刷高mIoU还不够,街景分割项目经常会遇到来自不同城市或者不同季节的图片。我习惯在交付前跑一个“泛化测试集”快速验证,从网上公开的街景视频里截取一些完全不同环境的画面,跑一次推理人工检查。模型如果在一个从未参与训练的城市画面上出现大片的错误区域,说明泛化能力堪忧,需要在数据增强里加入更多光照、天气变化再来一轮训练。这一步成本不高,却能在验收前提前暴露很多问题。

一些实际操作中的体会

这类街景分割定制项目做多了,我自己沉淀下来的经验就两条。

第一条,永远先跑通最小可用管线再谈优化。很多人上来就追求精度,模型结构换成最新Transformer、loss叠加五六种、数据增强拉满,结果前期调试周期异常漫长,最后连一个可靠的baseline都没有。巷子里走的踏实路径,是先以ResNet50加DeepLabV3+和仅水平翻转的简单增强跑出一个能交付的最低精度模型,把数据处理、验证逻辑、推理部署全部验证无误后,再引入更重的backbone和复杂增强策略逐步提升。踩过几次坑之后我对这点体会很深——大多数翻车都不是模型不行,而是数据和代码流程里有低级错误。

第二条,善用Mapillary Vistas的层级标签做软合并。不同项目里客户关心的类别可以差很远,但底层特征其实是共通的。在这个项目里学到“道路、人行道、路肩”的区分能力,换一个项目可能直接迁移到“可行驶区域”的判定任务上。我在多项目间复用时,通常只把最后一层分割头换掉,前几层的backbone直接沿用之前训练的权重,新任务往往几个epoch就能收敛到可用的水平,省下大把训练资源。

街景语义分割这个方向,后续往深度估计、实例分割、视频时序一致性这些方向扩展的潜力也很大。同一个数据集上的标注,做深度估计时可以直接复用语义边界的先验信息;做视频分割时,又可以用时序信息来抹平单帧预测的闪烁。如果手头有Mapillary Vistas的标注,先用它练好一个强分割模型,后面不管接到什么周边需求,都能顺势接得住。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询