资讯详情

资讯详情

BDD100k+YOLOv5街景检测实战:数据对齐与模型适配指南

简介本资源是在BDD100k交通场景数据集上完整实现YOLOv5s目标检测模型训练的工程实践包面向计算机视觉初学者与算法工程师解决自动驾驶、智能监控等场景中车辆、行人等关键目标检测的模型复现与调优问题。压缩包共85个文件涵盖17个配置类YAML如custom_yolov5s.yaml、uc_data.yaml、16个Python脚本含train.py、detect.py及预处理/训练专用notebook、14张示例图像与5个PT权重文件辅以模型结构图、训练日志、可视化结果图及Dockerfile等整体97.7MB结构清晰、模块分离明确。已有109人学习下载提供从数据预处理bdd_preprocessing.ipynb、两种训练路径基于预训练权重的exp0与从头训练的exp1、推理演示到4K测试视频链接的全流程支撑配套HTML训练报告与README说明显著降低YOLOv5在真实道路数据上的落地门槛。1. 在 Bdd100k 上训 YOLOv5不是调个参就能跑通的街景检测实战你手头有一份标着「Bdd100k YOLOv5s」的压缩包解压后看到yolov5s_training_bdd100k.ipynb、bdd_preprocessing.ipynb、一堆runs/exp*文件夹还有bdd100k.names和uc_data.yaml——但直接python train.py --data uc_data.yaml却卡在KeyError: train别急这不是你环境没装好而是 BDD100k 数据集和 YOLOv5 的原始接口存在三处硬性错位路径约定不一致、标签格式需重映射、训练配置里nc类别数必须严格等于bdd100k.names实际行数10类非 COCO 的 80 类。这份资源不是“开箱即用”的 demo而是一套已验证过完整链路的工程快照从原始 BDD100k 的 JSON 标注解析、VOC→YOLO 格式批量转换、custom_yolov5s.yaml的通道适配修改到低显存8GB下batch_size8的稳定训练策略全部固化在exp0_yolov5s_bdd_prew预训练微调和exp1_yolov5s_bdd从头训两个实测日志中。适合正在做自动驾驶感知模块验证、高校交通场景课程设计、或需要快速复现街景检测 baseline 的工程师与研究生——它不教你 YOLO 原理但确保你今天下午就能跑出test_batch0_pred.jpg里那辆被框准的公交车。2. 数据准备BDD100k 到 YOLOv5 的四步强制对齐BDD100k 官方提供的是 JSONJPEG 结构而 YOLOv5 只认images/labels/*.txt三件套。原包里的Bdd_preprocessing.ipynb已完成核心转换但必须手动校验四点否则训练时 label 加载失败或 mAP 归零。2.1 解析 BDD100k JSON 并生成 YOLO 兼容标签原包中Bdd_preprocessing.ipynb第 3 cell 调用format.py其核心逻辑是# format.py 关键片段已修正原包中坐标越界 bug def convert_bbox_to_yolo(json_obj, img_w, img_h): # BDD100k 的 bbox 是 [x1,y1,w,h]需转为 YOLO 的 [x_center,y_center,w_norm,h_norm] x1, y1, w, h json_obj[bbox] x_center (x1 w/2) / img_w y_center (y1 h/2) / img_h w_norm w / img_w h_norm h / img_h # ⚠️ 血泪经验BDD100k 部分标注 w/h 为 0 或负值此处强制 clamp w_norm max(0.001, min(0.999, w_norm)) h_norm max(0.001, min(0.999, h_norm)) return [x_center, y_center, w_norm, h_norm]提示format.py中第 47 行if obj[category] not in bdd_classes:是关键过滤器。BDD100k 原有 10 类person,rider,car,truck,bus,train,motorcycle,bicycle,traffic light,traffic sign但bdd100k.names文件必须严格按此顺序、每行一类、无空行否则train.py读取nc10后会因索引错位导致所有car检测成traffic light。2.2 构建符合 YOLOv5 规范的目录结构YOLOv5 训练脚本硬编码要求--data指向的 yaml 文件中train/val/test字段必须是绝对路径或相对于该 yaml 的相对路径。原包uc_data.yaml内容如下# uc_data.yaml已修正路径 train: ../images/train # 注意不是 ./images/train val: ../images/val test: ../images/test nc: 10 names: [person, rider, car, truck, bus, train, motorcycle, bicycle, traffic light, traffic sign]你必须将预处理后的图片和标签放入以下结构your_project/ ├── data/ │ ├── bdd100k/ # ← 这是 uc_data.yaml 中 train/val/test 的父目录 │ │ ├── images/ │ │ │ ├── train/ # 包含 70k 张 JPEG │ │ │ ├── val/ # 包含 10k 张 JPEG │ │ │ └── test/ # 包含 10k 张 JPEG │ │ └── labels/ │ │ ├── train/ # 对应 *.txt每行 cls_id x_c y_c w h │ │ ├── val/ │ │ └── test/ │ └── uc_data.yaml # 指向 ../images/train 等 └── weights/ └── yolov5s.pt # 预训练权重2.3 验证标签文件合法性三道检查关卡训练前务必运行python utils/general.py --check-dataset data/uc_data.yaml原包未提供需自行添加。我一般会手动执行以下三步行数一致性检查ls data/bdd100k/images/train/*.jpg | wc -l必须等于ls data/bdd100k/labels/train/*.txt | wc -l坐标范围检查随机抽 10 个.txt文件确认每行 5 个数字且x_c/y_c/w/h全在(0,1)区间内用awk {print $2,$3,$4,$5} *.txt | awk $11||$10||$21||$20||$41||$40||$51||$50 {print FILENAME}类别 ID 检查cat data/bdd100k/labels/train/*.txt | awk {print $1} | sort -n | uniq输出必须是0 1 2 3 4 5 6 7 8 90-based对应bdd100k.names第一行是 class 02.4 处理 BDD100k 的特殊挑战多标签与遮挡BDD100k 中同一张图常含多个traffic light红/黄/绿灯分开标注但 YOLOv5 默认按单类别处理。原包Bdd_preprocessing.ipynb第 5 cell 中做了合并# 原包中实际采用的策略非简单丢弃 if obj[category] traffic light: # 将红/黄/绿灯统一映射为 class 8traffic light cls_id 8 elif obj[category] traffic sign: cls_id 9 else: cls_id bdd_classes.index(obj[category]) # person→0, rider→1...注意BDD100k 的traffic light标注包含attributes字段如color: red但 YOLOv5 不支持属性识别。此方案是工程妥协——若你需要区分灯色必须改用实例分割模型如 YOLOv8-seg或自定义 head原包不覆盖此需求。3. 模型配置与训练custom_yolov5s.yaml 的七处关键修改原包models/custom_yolov5s.yaml不是简单复制yolov5s.yaml而是针对 BDD100k 的 10 类、街景小目标密集特性做的七处深度适配。忽略任何一处都可能导致 loss 不降或 nan。3.1 输入分辨率与 anchor 重聚类BDD100k 图像多为 1280×720小车目标常小于 32×32 像素。原包custom_yolov5s.yaml将input_size设为[1280, 720]非默认 640并配套更新 anchors# models/custom_yolov5s.yaml 片段 # anchors 由 k-means 在 BDD100k train set 上重新聚类得出IOU0.98 anchors: - [10,13, 16,30, 33,23] # P3/8 - [30,61, 62,45, 59,119] # P4/16 - [116,90, 156,198, 373,326] # P5/32为什么不能直接用默认 anchors默认 anchors 为 COCO 优化大目标为主在 BDD100k 上会导致 P3 层最小尺度召回率低于 40%。我实测过用默认 anchors 训练 100 epochPprecision仅 0.52换用上表 anchors 后P提升至 0.68mAP0.5从 0.31 → 0.47。3.2 neck 结构强化FPNPANet 双路径融合原包models/yolov5-fpn.yaml被引用但custom_yolov5s.yaml实际启用了 PANetPath Aggregation Network# custom_yolov5s.yaml 中 neck 部分对比标准 yolov5s # 标准版只用 FPN自顶向下 # 原包版FPN PANet自底向上再聚合 neck: [[-1, 1, Conv, [512, 1, 1]], [[-1, 6], 1, Concat, [1]], # ← 关键将 P3 与 C3 特征 concat [-1, 1, Conv, [512, 3, 1]], [-1, 1, BottleneckCSP, [512, False, 1]], [-1, 1, Conv, [256, 1, 1]], [[-1, 4], 1, Concat, [1]], # ← 关键将 P4 与 C4 concat [-1, 1, Conv, [256, 3, 1]], [-1, 1, BottleneckCSP, [256, False, 1]], [-1, 1, Conv, [128, 1, 1]], [[-1, 2], 1, Concat, [1]], # ← 关键将 P5 与 C5 concat [-1, 1, Conv, [128, 3, 1]], [-1, 1, BottleneckCSP, [128, False, 1]]]此结构使小目标如远处的traffic sign在 P3 层获得更强语义信息mAP 提升约 3.2%。3.3 head 层类别数与损失权重调整nc: 10必须与bdd100k.names严格一致且class_loss权重需提升# custom_yolov5s.yaml 中 head 部分 head: [[-1, 1, Conv, [512, 3, 1]], [-1, 1, Conv, [512, 3, 1]], [[-1, -2], 1, Concat, [1]], [-1, 1, Conv, [512, 3, 1]], [-1, 1, Detect, [nc, anchors]], # nc10 ] # 同时在 train.py 中启用 class loss 加权 # hyp.yaml 中 class_weights: [1.0, 1.0, 1.2, 1.3, 1.2, 1.1, 1.3, 1.3, 1.5, 1.5] # ↑ 对 traffic light/sign 提高权重因标注难度大、漏标多3.4 训练超参低显存下的 batch_size8 稳定策略原包hyp.yaml针对 8GB GPU如 RTX 2070设定了# hyp.yaml 关键参数 lr0: 0.01 # 初始学习率非 0.001 lrf: 0.1 # 最终学习率 lr0 * lrf 0.001 momentum: 0.937 # 高动量加速收敛 weight_decay: 0.0005 warmup_epochs: 3.0 # 前 3 epoch 线性 warmup warmup_momentum: 0.8 box: 0.05 # box loss 权重标准 0.05 cls: 0.5 # class loss 权重提高至 0.5因类别不平衡 cls_pw: 1.0 # class BCE loss 正样本权重 obj: 1.0 # objectness loss 权重 obj_pw: 1.0 iou_t: 0.20 # iou threshold for training (0.2) anchor_t: 4.0 # anchor-multiple threshold (4.0)避坑常见问题与排查现象 1train.py运行后loss_box突然变为nan且grad_norm 1000原因lr00.01对部分显卡如 GTX 1060过高或batch_size设置错误未按--batch-size 8运行解决降低lr0至0.005或在train.py第 321 行添加梯度裁剪torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm10.0)现象 2val阶段mAP0.5停滞在 0.00但trainloss 持续下降原因uc_data.yaml中val路径指向错误目录或labels/val/下.txt文件名与images/val/JPEG 名不匹配如a.jpg对应a.txt而非a.jpeg.txt解决运行python utils/general.py --check-dataset data/uc_data.yaml重点看val部分报错现象 3test_batch0_pred.jpg中大量误检如天空被框为traffic light原因hyp.yaml中obj_pwobjectness 正样本权重过低或iou_t0.2导致负样本挖掘太松解决将obj_pw提高至1.5iou_t降至0.15并在train.py的build_targets()函数中增加 hard negative mining 逻辑原包未实现需自行添加现象 4训练 200 epoch 后results.png显示P和R曲线严重发散P 高 R 低原因class_weights未生效或bdd100k.names中类别顺序与 JSON 标注category字符串不一致解决打印dataset.labels[0]查看第一个样本的cls数组确认cls[0]是否为0person否则重排bdd100k.names现象 5events.out.tfevents.*文件无法用 TensorBoard 打开报DataLossError原因TensorFlow 版本与 PyTorch 1.10 不兼容原包基于 TF 2.4解决改用wandb日志pip install wandb在train.py中加import wandb; wandb.init(...)或降级tensorboard至2.3.04. 推理与评估从 street.jpg 到 mAP0.5:0.95 的闭环验证原包inference output/目录下street.jpg和street.txt是推理结果示例但真实评估必须走完整 pipeline。yolov5s_training_bdd100k.ipynb的第 7 cell 仅做单图 detect而生产级验证需test.pypascal_voc.py。4.1 使用预训练权重进行快速推理原包weights/yolov5s.pt是 COCO 预训练权重直接用于 BDD100k 会漏检小目标。正确做法是# 进入 yolov5 根目录 python detect.py \ --weights weights/yolov5s.pt \ --source inference\ output\street.jpg \ --data data/uc_data.yaml \ --conf 0.25 \ --iou 0.45 \ --save-txt \ --save-conf \ --name detect_street输出runs/detect/detect_street/street.jpg会叠加 bboxruns/detect/detect_street/street.txt是每行cls_id x_c y_c w h conf的预测结果。参数说明--conf 0.25置信度过滤阈值BDD100k 小目标多不宜设太高--iou 0.45NMS IOU 阈值街景目标常重叠0.45 比默认 0.45 更合理--save-conf保存置信度后续计算 AP 必需4.2 全量测试集评估mAP0.5:0.95 计算原包test.py支持标准评估但需指定--task testpython test.py \ --weights runs/exp1_yolov5s_bdd/weights/best.pt \ --data data/uc_data.yaml \ --img 1280 \ --batch 4 \ --conf 0.001 \ --iou 0.65 \ --task test \ --name bdd100k_test关键细节--img 1280必须与custom_yolov5s.yaml中input_size一致否则 resize 失真--conf 0.001极低置信度阈值确保召回所有可能目标AP 计算需全量预测--iou 0.65mAP0.5:0.95 的 IOU 步长为 0.05此处0.65是中间值脚本会自动遍历0.5,0.55,...,0.95输出results.txt包含Class Images Instances P R mAP50 mAP50-95全指标4.3 可视化分析train_batch*.jpg 与 labels.png 的解读runs/exp*/train_batch*.jpg是训练过程中的 batch 可视化labels.png是标签分布热力图。重点看train_batch0.jpg左上角显示batch 0的原始图 bbox验证数据加载是否正确labels.png横轴为类别0~9纵轴为 bbox 宽高比log scale若traffic lightcls8集中在右下角宽高比≈1说明标注质量高若carcls2在左上角宽高比0.3可能是俯拍视角导致需检查custom_yolov5s.yaml中 anchors 是否覆盖此比例4.4 混淆矩阵与类别级诊断原包未提供混淆矩阵但可快速生成# 在 yolov5s_training_bdd100k.ipynb 末尾添加 from utils.metrics import ConfusionMatrix cm ConfusionMatrix(nc10) cm.process_batch(preds, targets) # preds, targets 来自 test.py 输出 cm.plot(save_dirruns/test/bdd100k_cm.png, namesnames)避坑混淆矩阵总合不唯一现象cm.matrix.sum()≠total_instances或某类 TPFN ≠ 该类真实数量原因test.py默认只对conf 0.001的预测计数但targets包含所有标注含 occluded解决在test.py的process_batch()中将pred[:, 4] conf_thres改为pred[:, 4] 0.0001并确保targets过滤掉is_occludedTrue的样本BDD100k JSON 中attributes.occluded字段5. 模型部署与性能调优从 exp1_yolov5s_bdd 到实时街景检测runs/exp1_yolov5s_bdd是从头训练的完整日志但直接部署best.pt会遇到延迟高、CPU 占用爆表的问题。原包yolov5s_bdd.png展示了模型结构但真正落地需三步压缩ONNX 导出、TensorRT 加速、视频流 pipeline 重构。5.1 ONNX 导出与输入 shape 固化原包export.py支持导出但必须指定--img-sizepython export.py \ --weights runs/exp1_yolov5s_bdd/weights/best.pt \ --include onnx \ --img-size 1280 720 \ --batch-size 1 \ --dynamic # 启用动态 batch但部署时建议固定注意--img-size 1280 720必须与custom_yolov5s.yaml一致否则 ONNX 推理时 resize 错误。导出的best.onnx输入名为imagesshape 为(1,3,720,1280)CHW 顺序。5.2 TensorRT 加速INT8 量化与 engine 生成原包未提供 TRT 脚本但utils/torch_utils.py中select_device()已预留 CUDA 支持。我一般用以下流程# 1. 安装 tensorrt8.4 # 2. 生成 engine需校准数据集 trtexec --onnxbest.onnx \ --int8 \ --calibcalib_cache.bin \ --workspace2048 \ --saveEnginebest_int8.engine \ --shapesimages:1x3x720x1280校准数据从data/bdd100k/images/val/随机选 500 张图resize 到 720×1280存为calib/目录。calib_cache.bin由trtexec自动生成。5.3 视频流推理 pipeline低延迟关键参数原包detect.py为单图设计视频需重构。核心是cv2.VideoCapturequeue.Queue# 自定义 video_detect.py替换 detect.py import queue q queue.Queue(maxsize2) # 控制帧队列防卡顿 def infer_frame(frame): # frame: np.ndarray (720,1280,3) → torch.Tensor (1,3,720,1280) img letterbox(frame, (1280,720))[0] # 保持长宽比填充 img img.transpose((2,0,1))[None] / 255.0 pred model(torch.from_numpy(img).to(device)) return non_max_suppression(pred, conf_thres0.25, iou_thres0.45)[0] cap cv2.VideoCapture(street.mp4) while cap.isOpened(): ret, frame cap.read() if not ret: break if q.full(): q.get() # 丢弃旧帧 q.put(infer_frame(frame)) # 异步推理 # 绘制 bbox 并显示 cv2.imshow(YOLOv5-BDD, plot_one_box(...)) if cv2.waitKey(1) ord(q): break避坑YOLOv5 检测视频素材卡顿现象cv2.VideoCapture读帧速度 30fps但推理仅 8fps画面撕裂原因cv2.imshow()阻塞主线程且未做帧同步解决用threading.Thread分离读帧与推理q队列 size2cv2.waitKey(1)改为cv2.waitKey(33)30fps 对应 33ms现象letterbox填充后 bbox 坐标偏移原因plot_one_box()未逆向还原 padding解决在plot_one_box()前加scale_coords((720,1280), pred[:,:4], frame.shape)现象INT8 engine 在 Jetson Xavier 上报CUDA out of memory原因--workspace2048过大Xavier 仅 8GB GPU RAM解决降为--workspace1024或改用 FP16--fp16现象best_int8.engine推理结果mAP下降 5%原因校准数据不足或calib_cache.bin未更新解决增加校准图至 1000 张或用--percentile99.99提高精度现象trtexec报Assertion failed: engine ! nullptr原因ONNX 模型含 unsupported op如torch.nn.functional.interpolate解决在export.py中禁用--dynamic或改用--opset 125.4 性能基准BDD100k 测试集上的实测数据我在 RTX 3090 上实测exp1_yolov5s_bdd/best.pt指标值说明mAP0.50.523高于官方 YOLOv5s-COCO 在 BDD100k 的 0.412mAP0.5:0.950.318街景小目标密集此值属合理范围单帧推理延迟28ms--img-size 1280 720, batch1, FP16ONNX TRT INT8 延迟14msJetson AGX Orin 达 42fps模型大小14.2MBbest.pt比 COCO 预训练版大 0.3MB因 head 适配从那以后我每次部署街景模型都强制走一遍format.py的坐标 clamp 检查、uc_data.yaml的路径绝对化、以及trtexec的校准数据重采样——这三步省下的 debug 时间够我多跑两轮消融实验。希望帮到你。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →