BDD100K数据集实战指南:从数据加载到模型训练的全流程解析

1次阅读
没有评论

共计 2756 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

背景介绍

BDD100K 是伯克利大学发布的大规模驾驶场景数据集,包含 10 万张高清图像(1280×720 分辨率),涵盖多样天气、光照和道路条件。其特点包括:

BDD100K 数据集实战指南:从数据加载到模型训练的全流程解析

  • 多任务标注:同时支持目标检测(2D 框)、语义分割、实例分割、车道线检测和全景分割
  • 地理多样性:采集自纽约、旧金山等不同地区
  • 时间跨度:包含白天、夜晚、黎明 / 黄昏等多种时段

在自动驾驶领域,BDD100K 已成为算法开发的基准数据集,特别适合研究复杂交通场景下的感知任务。

痛点分析

实际使用中发现开发者常遇到以下问题:

  1. 标注结构复杂:单张图片可能对应多个 JSON 字段(如物体检测框、车道线多边形)
  2. 内存消耗大:直接加载全部图像会导致 OOM(尤其是 batch 较大时)
  3. 标注转换困难:不同任务(如检测→分割)需要重新组织标注格式
  4. 数据分布不均:天气 / 时段类别存在长尾分布
  5. 预处理耗时:大尺寸图像的传统处理方式效率低下

技术方案

数据集目录结构

标准解压后的目录应包含:

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)

图像高效加载方案

  1. 延迟加载:仅在__getitem__时读取图片
  2. 分辨率控制:训练时统一 resize 到 800×450(保持长宽比)
  3. 格式优化:将图片预转换为.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

性能优化技巧

  1. 内存管理
  2. 使用 torch.utils.data.DataLoaderpin_memory=True加速 GPU 传输
  3. 设置 persistent_workers=True 减少进程频繁创建开销

  4. IO 优化

  5. 将小文件(如标注)打包成.tar
  6. 使用更快的图片解码库(如 turbojpeg)

  7. 批处理策略

  8. 动态 padding 替代固定尺寸 resize
  9. 使用 collate_fn 处理不同数量的标注框

常见问题解决方案

  1. 标注框越界:添加边界检查逻辑

    boxes = np.clip(boxes, 0, [img_width, img_height, img_width, img_height])

  2. 类别不平衡

  3. 使用WeightedRandomSampler
  4. 对稀少类别(如 traffic light)过采样

  5. GPU 显存不足

  6. 减小 batch size
  7. 使用梯度累积

延伸思考

  1. 如何设计多任务学习框架(同时处理检测 + 分割任务)?
  2. 针对夜间场景数据较少的情况,可以采取哪些数据增强策略?
  3. 如果将 BDD100K 与其他数据集(如 Cityscapes)联合训练,需要注意什么?

总结

通过本文介绍的方法,开发者可以高效地:

  1. 解析 BDD100K 复杂标注结构
  2. 实现高性能数据加载管道
  3. 合理优化训练资源

建议进一步尝试:

  • 将预处理流程移植到 DALI 加速库
  • 实验不同 backbone(如 Swin Transformer)在 BDD100K 上的表现
  • 开发针对恶劣天气条件的增强模块
正文完
 0
评论(没有评论)