简介这份资源面向计算机视觉方向的学习者与工程实践者提供在 Bdd100k 自动驾驶数据集上训练 YOLOv5s 目标检测模型的完整工程包适合已掌握 Python 与深度学习基础、希望上手真实道路场景检测的开发者。压缩包共 85 个文件、约 97.7MB以 yaml 配置、py 源码、pt 权重、ipynb 笔记本及 jpg/png 可视化结果为主另含 sh 脚本、Dockerfile 与说明文档覆盖模型定义、数据配置、训练与推理全流程。资源内含预训练权重、预处理后的 Bdd100k 数据集链接、从零训练与基于预训练权重训练两套实验记录以及模型架构图与 4K 测试视频演示便于对照复现训练曲线与检测效果。目前已有 109 人学习下载可作为自动驾驶感知入门与 YOLOv5 迁移训练的实操参考。1. 从 Bdd100k 到 YOLOv5为什么这套组合值得你花一个周末跑通如果你手头只有 COCO 或 VOC 的预训练权重却要面对真实道路场景——逆光、雨夜、密集车流、被遮挡的行人——你会发现模型掉点掉得莫名其妙。Bdd100k 恰好补上这块短板它包含 10 万段行车视频抽帧、覆盖晴天/雨天/夜间/黄昏、标注了车辆、行人、交通灯、交通标志等 10 类目标是目前少有的带「天气时段」维度的大规模驾驶场景检测数据集。而 YOLOv5 在工程侧的优势不用多说单阶段、推理快、训练脚本开箱即用、导出 ONNX/TensorRT 链路成熟。把两者拼起来你得到的是一个能直接往车载或路侧设备上搬的对象检测模型。这篇笔记面向的是想自己动手跑一遍的工程师——从数据格式转换、配置文件改写、训练参数调优到踩过的坑和验证方法全部按可复现的步骤写清楚。2. 数据落地把 Bdd100k 转成 YOLOv5 能吃的格式2.1 先搞清楚 Bdd100k 的标注长什么样Bdd100k 官方提供的是 JSON 标注文件图像和标注分开存放。检测任务的标注文件通常叫bdd100k_labels_images_train.json和bdd100k_labels_images_val.json每个条目包含图像名、属性天气、时段、场景以及一组labels每个 label 里有category、box2dx1,y1,x2,y2等字段。注意两点一是坐标是绝对像素值不是归一化值二是类别名和 YOLOv5 默认的 COCO 类别完全不同需要自己建立映射表。常见做法是先把 JSON 解析成每张图一个 txt 的中间格式再统一转成 YOLO 的class cx cy w h归一化格式。我一般会写一个转换脚本一次到位避免中间文件堆积。2.2 转换脚本从 JSON 到 YOLO txt 的完整实现import json import os from pathlib import Path from PIL import Image # Bdd100k 原始类别到 YOLO 索引的映射按需增删 CATEGORY_MAP { car: 0, bus: 1, truck: 2, person: 3, bicycle: 4, motorcycle: 5, traffic light: 6, traffic sign: 7, train: 8, rider: 9, } def convert(json_path, img_dir, out_dir): with open(json_path, r) as f: data json.load(f) out_dir Path(out_dir) out_dir.mkdir(parentsTrue, exist_okTrue) for item in data: img_name item[name] img_path Path(img_dir) / img_name if not img_path.exists(): continue w, h Image.open(img_path).size lines [] for label in item.get(labels, []): cat label.get(category) if cat not in CATEGORY_MAP: continue box label.get(box2d) if box is None: continue x1, y1, x2, y2 box[x1], box[y1], box[x2], box[y2] # 过滤掉宽高为 0 的脏标注 if x2 x1 or y2 y1: continue cx (x1 x2) / 2.0 / w cy (y1 y2) / 2.0 / h bw (x2 - x1) / w bh (y2 - y1) / h # 裁剪到 [0,1]防止越界 cx, cy min(max(cx, 0), 1), min(max(cy, 0), 1) bw, bh min(max(bw, 0), 1), min(max(bh, 0), 1) lines.append(f{CATEGORY_MAP[cat]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) txt_name Path(img_name).with_suffix(.txt).name with open(out_dir / txt_name, w) as f: f.write(\n.join(lines)) if __name__ __main__: convert(bdd100k_labels_images_train.json, images/100k/train, labels/train) convert(bdd100k_labels_images_val.json, images/100k/val, labels/val)逻辑说明脚本逐条读取 JSON用 PIL 拿到图像真实宽高做归一化这是必须的——Bdd100k 图像尺寸并不完全统一硬编码 1280×720 会在部分图上产生偏移。参数方面CATEGORY_MAP决定了你最终模型的输出类别数删掉不用的类别比如train能减少类别不平衡带来的干扰。if x2 x1这类过滤是血泪经验原始标注里存在少量零面积框不清理会让训练时 loss 出现 NaN。2.3 目录结构与 data.yaml 的对应关系YOLOv5 对目录结构有约定转换完成后建议整理成下面这样bdd100k_yolo/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── bdd100k.yamlbdd100k.yaml内容如下path: /data/bdd100k_yolo train: images/train val: images/val nc: 10 names: [car, bus, truck, person, bicycle, motorcycle, traffic light, traffic sign, train, rider]注意nc必须和CATEGORY_MAP的类别数严格一致names的顺序也要和索引对应。我见过有人改了映射表却忘了改 yaml训练不报错但类别全乱验证时 mAP 低得离谱还找不到原因。3. 训练配置YOLOv5 在 Bdd100k 上的参数怎么设3.1 模型选型s/m/l 怎么挑YOLOv5 提供 n/s/m/l/x 五个尺度。Bdd100k 训练集约 7 万张验证集 1 万张类别 10 类属于中等规模。我的建议是如果你只是验证流程用yolov5s跑通即可如果要落地到边缘设备yolov5s或yolov5m是性价比最高的选择追求精度且算力充足再上l。x在 Bdd100k 上收益递减明显训练时间却翻倍不太划算。从官方预训练权重起步能显著加快收敛。命令里用--weights yolov5s.pt即可注意预训练权重是 COCO 80 类加载时 YOLOv5 会自动跳过分类头不匹配的层这是它脚本内置的逻辑不用手动改。3.2 关键训练命令与参数逐条解释python train.py \ --img 640 \ --batch 16 \ --epochs 100 \ --data bdd100k.yaml \ --weights yolov5s.pt \ --cfg models/yolov5s.yaml \ --hyp data/hyps/hyp.scratch-low.yaml \ --name bdd100k_s \ --cache逐条说明--img 640是输入分辨率Bdd100k 里小目标远处交通灯、行人不少如果你显存够可以提到 960 或 1280mAP 通常有 2~4 个点的提升但 batch 要相应调小。--batch 16在单卡 16G 显存下比较稳显存不够就降到 8 并配合--accumulate做梯度累积。--epochs 100是经验值Bdd100k 上 80~120 轮基本收敛看results.csv里 mAP 曲线走平就可以停。--hyp选hyp.scratch-low.yaml是因为从预训练迁移时学习率不宜过高这个配置的初始 lr 和 warmup 更适合微调场景。--cache会把图像缓存到内存7 万张图大约占 20~30G 内存内存不够就别加否则会被 OOM kill。3.3 数据增强Bdd100k 场景下哪些该开、哪些该关YOLOv5 的 hyp 文件里控制增强的参数很多针对 Bdd100k 我一般这样调参数默认值建议值原因mosaic1.01.0驾驶场景目标密集mosaic 提升小目标召回fliplr0.50.5水平翻转合理交通场景左右对称flipud0.00.0上下翻转会让天空跑到地面语义错误hsv_h0.0150.015色调扰动帮助适应不同时段光照hsv_v0.40.5夜间/逆光场景多亮度扰动可以加大mixup0.00.1轻微 mixup 有助于抑制过拟合注意flipud千万别开这是驾驶数据集的常识。另外 Bdd100k 本身已经覆盖多种天气不需要再额外做雨雾模拟过度增强反而会让模型在晴天场景下降点。4. 训练过程排查loss 不降、mAP 不动、显存爆炸怎么办4.1 现象训练前几个 epoch loss 就是 nan原因通常是标注里有非法值。Bdd100k 原始 JSON 中存在少量宽高为负或坐标越界的框转换时没过滤干净归一化后出现负数或大于 1 的值YOLOv5 计算 CIoU loss 时就会产生 nan。解决办法在转换脚本里加严格校验除了前面写的x2 x1过滤还要检查cx, cy, bw, bh是否都在(0, 1]区间内超出就丢弃该框。另外可以在训练命令里加--rect关闭矩形推理减少 padding 带来的坐标异常。4.2 现象mAP 卡在 0.2 左右上不去先检查类别映射是否和 yaml 一致。我遇到过把rider和person索引写反的情况模型学出来的框位置对但类别全错mAP 自然低。排查方法是跑val.py后看混淆矩阵如果某两类互相混淆严重基本就是映射问题。如果映射没问题再看学习率。从 COCO 预训练迁移到 Bdd100k初始 lr 建议在 0.01 左右太高会导致预训练特征被破坏。可以先用--epochs 5做一次 lr 范围测试看 loss 下降最陡的区间。4.3 现象训练到一半显存突然爆掉这通常是--cache加上 dataloader 的 prefetch 导致的。YOLOv5 默认workers8每个 worker 都会拷贝一份缓存数据内存和显存都会涨。解决办法是把--workers降到 4或者去掉--cache改用--cache disk。另外如果开了--multi-scale每轮图像尺寸随机变化某些大尺寸 batch 会瞬间吃满显存训练不稳定时可以先关掉。4.4 现象验证集 mAP 比训练集低很多Bdd100k 的验证集和训练集在场景分布上并不完全一致比如夜间样本比例不同。如果差距超过 15 个点说明过拟合了。可以加大--weight_decay到 0.0005或者把dropout打开在 hyp 里设dropout: 0.1。另一个容易被忽略的点是Bdd100k 验证集里有些图像标注不完整漏标这会导致 mAP 被低估属于数据集本身的噪声不用过度调参去拟合。5. 验证与导出怎么确认模型真的能用5.1 用 val.py 看逐类指标别只看总 mAPpython val.py \ --data bdd100k.yaml \ --weights runs/train/bdd100k_s/weights/best.pt \ --img 640 \ --task val \ --save-json跑完后重点看per-class那一栏。Bdd100k 里traffic light和traffic sign因为目标小、密集mAP 通常比car低 20 个点以上这是正常的。如果person的 mAP 异常低检查一下是不是把rider误标成了person这两个类别在骑行场景里容易混。5.2 导出 ONNX 并做一次推理对齐python export.py \ --weights runs/train/bdd100k_s/weights/best.pt \ --include onnx \ --img 640 \ --batch 1 \ --simplify导出后务必用onnxruntime跑一张测试图和 PyTorch 的输出做数值对比。我一般会算两个输出的最大绝对误差正常应该在 1e-4 以内。如果误差大检查--simplify是否生效以及导出时的 opset 版本是否和推理引擎匹配。这一步是后悔药等到部署时才发现导出有问题回头查成本很高。5.3 一个快速验证技巧用视频抽帧做时序一致性检查单张图的 mAP 好看不代表视频里稳定。我习惯用ffmpeg从一段行车记录仪视频里抽 100 帧批量推理后看同一目标在连续帧里的框是否跳动。如果跳动超过 10 个像素说明模型对运动模糊或光照变化敏感可以考虑在训练时加入--multi-scale和更强的 HSV 扰动。这个检查花不了十分钟但能提前暴露很多部署阶段才会发现的问题。6. 进阶技巧把 Bdd100k 的天气标签用起来Bdd100k 每个样本都带weather和timeofday属性大多数人转换时直接丢掉了其实这是做场景自适应训练的免费资源。我的做法是在转换脚本里额外输出一个meta.json记录每张图的天气和时段训练时按这些属性做分层采样。具体操作先统计训练集里night和rainy的样本占比如果低于 15%就在 dataloader 里对这些样本做 oversampling。YOLOv5 本身不支持按属性采样但可以写一个简单的WeightedRandomSampler替换默认的 sampler。代码不复杂核心是给每个样本算一个权重稀有场景权重高常见场景权重低。另一个用法是分场景验证。把验证集按timeofday拆成day和night两个子集分别跑val.py。如果夜间 mAP 比白天低 30 个点以上说明模型对低光照泛化不足这时候再针对性做亮度增强或引入夜间专用数据比盲目调参有效得多。我自己的习惯是每次在 Bdd100k 上训完一个模型先不看总 mAP而是先看夜间和雨天的分项指标。这两个场景过了模型才敢往车上搬。这套流程我踩过不少坑从标注转换的脏数据到导出对齐的数值误差每一步都有翻车的可能但跑通之后你会发现 Bdd100k YOLOv5 是目前驾驶场景检测里最省心的组合之一。希望帮到你。本文还有配套的精品资源点击获取