3、车载数据集构建:BDD100K与SODA10M数据集解析、针对车载场景的标注规范、数据清洗与不平衡处理

做车载感知这几年,我最大的体会是:算法模型只占30%,剩下70%的功夫全在数据上。你想想看,一个在Cityscapes上跑得飞快的YOLO,放到车载场景里可能直接翻车——为什么?因为车载场景太特殊了,光照、遮挡、小目标、极端天气,这些在公开数据集里往往被弱化了。

今天我们就来聊聊车载数据集怎么构建。我会结合BDD100K和SODA10M这两个主流数据集,讲讲标注规范、数据清洗,以及最让人头疼的不平衡处理。

3.1 BDD100K与SODA10M:两个主流车载数据集

先说说BDD100K。这个数据集是伯克利发布的,10万张图片,涵盖了白天、夜晚、雨天、雪天、雾天等各种场景。我个人习惯把它当作车载感知的入门级基准。为什么?因为它的标注相对规整,类别也全——10大类,包括car、bus、truck、bicycle、motor、person、rider、traffic light、traffic sign、train。

但BDD100K有个问题:小目标太少。比如远处的行人、被遮挡的交通标志,这些在BDD100K里占比不高。而车载场景恰恰最需要关注这些小目标——你想想,一个站在50米外的行人,如果模型漏检了,后果是什么?

再说SODA10M。这个数据集是中科院自动化所发布的,1000万张图片,规模是BDD100K的100倍。它的特点是场景多样性极强,尤其是中国路况——电动车、三轮车、逆行、加塞,这些在BDD100K里几乎看不到。我在项目中遇到过,用BDD100K训练的模型,到了中国城市道路上,对电动车的召回率直接掉了15个点。后来加了SODA10M的数据,才把这个问题解决。

两个数据集的核心差异,我整理了一张表:

维度 BDD100K SODA10M
图片数量 10万 1000万
场景覆盖 欧美为主,天气多样 中国路况,极端场景丰富
小目标占比 较低 较高
标注质量 高,人工校验 中等,部分自动标注
适用场景 通用车载感知 复杂交通环境
我的建议:如果做通用车载感知,先用BDD100K做预训练,再用SODA10M做微调。这样既能保证基础精度,又能提升对复杂场景的适应能力。

3.2 针对车载场景的标注规范

标注规范这事,说白了就是定义清楚“什么是你要检测的”。车载场景和通用目标检测不一样,有几个特殊点需要注意。

3.2.1 类别定义要细

通用检测里,一个“car”就完了。但在车载场景里,car要拆成sedan、SUV、van、truck、bus。为什么?因为不同车型的尺寸、形状、运动特性都不一样。我记得有一次,模型把一辆大货车当成了car,结果在跟车距离判断上出了大问题。所以,类别粒度越细,下游任务越安全

3.2.2 遮挡与截断的处理

车载场景里,遮挡是常态。一辆车被另一辆车挡住一半,或者行人被路灯杆挡住,这些都要标注。我见过一些团队,为了省事,只标注完整的目标。结果模型在遮挡场景下直接摆烂——漏检率飙升。

标注规范里要明确:遮挡超过50%的目标,标注为“遮挡”子类。这样模型可以学到“即使只看到一半,这也是一个目标”。

3.2.3 小目标的标注策略

小目标(比如远处的交通标志、行人)在车载场景里特别重要。但小目标在图像里可能只有几十个像素,标注员很容易漏掉。我的做法是:强制标注所有像素面积大于20x20的目标。低于这个阈值的,可以忽略,因为YOLO系列对小目标的检测能力有限,强行标注反而会引入噪声。

注意:小目标的标注框要尽量贴合目标边缘,不要留太多背景。我曾经因为标注框太大,导致模型学到的特征里混入了大量背景信息,精度反而下降了。

3.3 数据清洗:别让脏数据毁了你的模型

数据清洗,说白了就是把垃圾数据扔掉。车载数据集里常见的脏数据有这几类:

  • 模糊图片:运动模糊、对焦不准,这些图片模型学不到有效特征。
  • 重复图片:连续帧里高度相似的图片,会造成数据冗余。
  • 标注错误:框不对、类别标错、漏标,这些是最大的坑。
  • 极端光照:过曝或过暗的图片,模型很难处理。

我一般用三步走策略:

  1. 自动清洗:用Laplacian算子检测模糊度,低于阈值的直接删除。用感知哈希算法检测重复图片,保留一张即可。
  2. 人工抽检:随机抽5%的图片,人工检查标注质量。如果错误率超过2%,整批数据打回重标。
  3. 模型辅助:用预训练模型跑一遍,把置信度低于0.3的检测结果标出来,人工确认是否是漏标。
避坑指南:我曾经因为偷懒,跳过了数据清洗,直接用原始数据训练。结果模型在验证集上精度很高,但一上路就各种漏检。后来发现,训练集里混入了大量白天晴天的图片,模型根本没学会处理雨天场景。所以,数据清洗不是可选项,是必选项。

3.4 不平衡处理:让模型学会“雨露均沾”

不平衡问题,是车载数据集里最头疼的。你想想看,一辆车在路上跑,90%的时间都是正常行驶,只有10%的时间会遇到行人、自行车、交通标志。如果直接拿原始数据训练,模型会变成“car检测器”——对car的精度很高,但对其他类别的召回率惨不忍睹。

不平衡处理,我常用的方法有这几种:

3.4.1 重采样

简单粗暴,但有效。对少数类(比如行人、自行车)进行过采样,对多数类(比如car)进行欠采样。但要注意,过采样不能简单复制,否则模型会过拟合。我一般用数据增强的方式过采样——对少数类图片做随机裁剪、旋转、颜色抖动,生成新的样本。

3.4.2 类别权重

在损失函数里给不同类别加权重。比如,car的权重设为1,行人的权重设为5。这样模型在训练时会更关注行人。YOLOv5的损失函数里就支持类别权重,直接设置就行。

# YOLOv5 类别权重设置示例
class_weights = [1.0, 5.0, 3.0, 2.0, 4.0]  # 对应 car, person, bicycle, traffic_light, traffic_sign
model.class_weights = torch.tensor(class_weights).to(device)

3.4.3 困难样本挖掘

这是我最喜欢的方法。先用模型跑一遍训练集,找出那些预测错误的样本——比如把行人误检为car,或者漏检了远处的交通标志。把这些困难样本挑出来,单独训练一个epoch。这样模型就能“补课”,学会处理那些它不擅长的场景。

小技巧:困难样本挖掘可以和在线难例挖掘(OHEM)结合。在YOLO的训练过程中,动态调整每个batch里困难样本的比例。我试过,能提升2-3个点的mAP。

3.5 实战建议:从数据到模型的闭环

最后,我想分享一个实战中的闭环思路。数据集的构建不是一次性的,而是迭代的。你训练一个模型,上路测试,发现某些场景表现不好。这时候,你要回到数据集,补充这些场景的数据,重新标注、清洗、训练。如此循环,模型才会越来越强。

我现在的团队,每个月都会做一次数据复盘。把模型在实车测试中漏检的案例收集起来,分析是数据问题还是模型问题。如果是数据问题,就补充数据;如果是模型问题,就调整网络结构。这样持续优化,半年下来,模型的mAP从0.72提升到了0.85。

嗯,数据集的构建就聊到这里。下一章,我们会讲数据增强——怎么用有限的数据,生成无限的变化。到时候再细聊。