共计 2756 个字符,预计需要花费 7 分钟才能阅读完成。
背景介绍
BDD100K 是伯克利大学发布的大规模驾驶场景数据集,包含 10 万张高清图像(1280×720 分辨率),涵盖多样天气、光照和道路条件。其特点包括:

- 多任务标注:同时支持目标检测(2D 框)、语义分割、实例分割、车道线检测和全景分割
- 地理多样性:采集自纽约、旧金山等不同地区
- 时间跨度:包含白天、夜晚、黎明 / 黄昏等多种时段
在自动驾驶领域,BDD100K 已成为算法开发的基准数据集,特别适合研究复杂交通场景下的感知任务。
痛点分析
实际使用中发现开发者常遇到以下问题:
- 标注结构复杂:单张图片可能对应多个 JSON 字段(如物体检测框、车道线多边形)
- 内存消耗大:直接加载全部图像会导致 OOM(尤其是 batch 较大时)
- 标注转换困难:不同任务(如检测→分割)需要重新组织标注格式
- 数据分布不均:天气 / 时段类别存在长尾分布
- 预处理耗时:大尺寸图像的传统处理方式效率低下
技术方案
数据集目录结构
标准解压后的目录应包含:
BDD100K/
├── images/ # 图片文件夹
│ ├── train/ # 训练集
│ ├── val/ # 验证集
│ └── test/ # 测试集
└── labels/ # 标注文件夹
├── det_20/ # 检测标注(COCO 格式)├── lane/ # 车道线标注
└── sem_seg/ # 语义分割掩膜
JSON 标注处理技巧
以物体检测为例,标注文件关键字段解析:
{
"name": "b1c66a42-6f7d68ca.jpg", # 图片文件名
"attributes": {
"weather": "rainy", # 天气标签
"scene": "highway", # 场景类型
"timeofday": "daytime" # 时间段
},
"labels": [ # 物体标注列表
{
"category": "car", # 类别名称
"box2d": { # 2D 框坐标
"x1": 712.12, "y1": 128.31,
"x2": 810.42, "y2": 185.12
}
}
]
}
建议使用 json.JSONDecoder 进行流式读取,避免一次性加载全部标注:
import json
with open('labels.json') as f:
for line in f: # 逐行读取
ann = json.loads(line)
process_annotation(ann)
图像高效加载方案
- 延迟加载:仅在__getitem__时读取图片
- 分辨率控制:训练时统一 resize 到 800×450(保持长宽比)
- 格式优化:将图片预转换为.pt 或.lmdb 格式加速读取
PyTorch 数据加载器实现
完整代码示例(含数据增强):
import torch
from torch.utils.data import Dataset
import albumentations as A
class BDD100KDataset(Dataset):
def __init__(self, img_dir, label_path, transform=None):
self.img_dir = img_dir
self.labels = self._load_labels(label_path)
self.transform = transform or A.Compose([A.Resize(800, 450),
A.HorizontalFlip(p=0.5),
A.RandomBrightnessContrast(p=0.2),
], bbox_params=A.BboxParams(format='pascal_voc'))
def _load_labels(self, path):
"""流式读取标注文件"""
labels = []
with open(path) as f:
for line in f:
labels.append(json.loads(line))
return labels
def __getitem__(self, idx):
ann = self.labels[idx]
img_path = os.path.join(self.img_dir, ann['name'])
img = cv2.imread(img_path) # 实际使用时建议用 Pillow
# 解析标注框
boxes = [[label['box2d']['x1'], label['box2d']['y1'],
label['box2d']['x2'], label['box2d']['y2']]
for label in ann['labels']
]
class_ids = [CLASS_DICT[label['category']] for label in ann['labels']]
# 应用数据增强
transformed = self.transform(
image=img,
bboxes=boxes,
class_labels=class_ids
)
# 转换为 Tensor
img_tensor = torch.from_numpy(transformed['image']).permute(2, 0, 1)
target = {'boxes': torch.tensor(transformed['bboxes'], dtype=torch.float32),
'labels': torch.tensor(transformed['class_labels'], dtype=torch.int64)
}
return img_tensor, target
性能优化技巧
- 内存管理:
- 使用
torch.utils.data.DataLoader的pin_memory=True加速 GPU 传输 -
设置
persistent_workers=True减少进程频繁创建开销 -
IO 优化:
- 将小文件(如标注)打包成.tar
-
使用更快的图片解码库(如 turbojpeg)
-
批处理策略:
- 动态 padding 替代固定尺寸 resize
- 使用
collate_fn处理不同数量的标注框
常见问题解决方案
-
标注框越界:添加边界检查逻辑
boxes = np.clip(boxes, 0, [img_width, img_height, img_width, img_height]) -
类别不平衡:
- 使用
WeightedRandomSampler -
对稀少类别(如 traffic light)过采样
-
GPU 显存不足:
- 减小 batch size
- 使用梯度累积
延伸思考
- 如何设计多任务学习框架(同时处理检测 + 分割任务)?
- 针对夜间场景数据较少的情况,可以采取哪些数据增强策略?
- 如果将 BDD100K 与其他数据集(如 Cityscapes)联合训练,需要注意什么?
总结
通过本文介绍的方法,开发者可以高效地:
- 解析 BDD100K 复杂标注结构
- 实现高性能数据加载管道
- 合理优化训练资源
建议进一步尝试:
- 将预处理流程移植到 DALI 加速库
- 实验不同 backbone(如 Swin Transformer)在 BDD100K 上的表现
- 开发针对恶劣天气条件的增强模块
正文完
