新闻详情

新闻详情

首页 / 资讯中心 / 详情

BDD100K适配YOLOv5实战:数据转换、anchor重算与训练避坑指南

发布时间:2026/10/1 11:45:54来源:尧图网络
BDD100K适配YOLOv5实战:数据转换、anchor重算与训练避坑指南
简介本资源是在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的完整流程附带HTML版训练报告、4K实测视频链接及OneDrive预处理数据集直链显著降低复现实验门槛。1. 为什么在 BDD100K 上训 YOLOv5 不是“套个 config 就跑通”而是要重写数据流、重调 anchor、重验标签一致性BDD100K 是目前自动驾驶场景下最贴近真实道路的公开检测数据集之一它包含 10 万 张白天/夜间/雨雾/隧道等多天气、多时段、多摄像头视角的街景图像每张图带 10 类动态目标车、人、自行车、红绿灯、车道线等的像素级实例标注与框级检测标注。但直接把它的 JSON 标注喂给 YOLOv5 官方训练脚本99% 会卡在IndexError: list index out of range或ValueError: labels contain invalid class values—— 因为 BDD100K 的原始标注结构和 YOLOv5 所需的.txt格式之间存在三道硬断层类别 ID 映射错位、坐标系未归一化、多标签类型混存检测分割属性。这不是“数据格式不对”的小问题而是整个 pipeline 的输入契约被打破。我见过太多团队花 3 天调参却卡在第 1 个 epoch 的 lossnan最后发现只是把traffic light和traffic sign的 class id 写反了。本文不讲 YOLOv5 原理只讲怎么用最小改动、最大确定性在 BDD100K 上训出一个能上路验证的 baseline 检测模型——从原始 JSON 解析开始到验证 mAP0.5 是否可信为止。适合已跑通 COCO/YOLO 格式训练、但第一次接触 BDD100K 的算法工程师和嵌入式视觉开发者。2. 从 BDD100K 原始 JSON 到 YOLOv5 可读.txt必须重写的转换逻辑与 4 个关键过滤条件BDD100K 提供的标注是bdd100k_labels_images_train.json这类单文件内含 10 万 条frames记录每条frame包含labels数组每个label是一个 dict含category字符串、box2d{x1,y1,x2,y2}、attributes如trafficLightColor等字段。YOLOv5 要求的是每张图对应一个同名.txt文件每行class_id center_x center_y width height归一化到 [0,1]且class_id必须是连续整数0~N-1。二者之间没有现成工具链必须手写转换器。常见错误是直接json.load()后暴力遍历结果生成了 20 万行标注因同一帧含多个label但其中 37% 的box2d是nullBDD100K 允许部分目标只标分割掩码、不标框12% 的category是drivable area或laneYOLOv5 检测任务不支持面状目标还有 8% 的box2d坐标越界x10或x2width。这些必须在转换阶段硬过滤否则训练时 loss 爆炸或 NaN。2.1 核心转换逻辑只保留 8 类检测目标 强制坐标校验import json import os from pathlib import Path import cv2 # BDD100K 官方定义的 10 类但 YOLOv5 检测只取其中 8 类排除 drivable area, lane BDD_CATEGORIES { car: 0, truck: 1, bus: 2, person: 3, bicycle: 4, motorcycle: 5, rider: 6, traffic light: 7, traffic sign: 8, train: 9 } # YOLOv5 实际训练只用前 8 类0~7跳过 traffic sign(8) 和 train(9) YOLO_CLASSES [car, truck, bus, person, bicycle, motorcycle, rider, traffic light] YOLO_CLASS_MAP {cls: i for i, cls in enumerate(YOLO_CLASSES)} # {car:0, truck:1, ...} def convert_bdd_to_yolo(json_path: str, image_dir: str, output_dir: str): with open(json_path) as f: data json.load(f) for frame in data: img_name frame[name] # e.g., 0000f77c-321f4b5b.jpg img_path Path(image_dir) / img_name if not img_path.exists(): continue # 读取图像尺寸必须不能假设 1280x720 h, w cv2.imread(str(img_path)).shape[:2] yolo_lines [] for label in frame.get(labels, []): cat label.get(category) box2d label.get(box2d) # 【关键过滤1】跳过非检测类 未定义类别 if cat not in YOLO_CLASS_MAP: continue # 【关键过滤2】跳过无 box2d 或 box2d 为 null if not box2d or any(v is None for v in box2d.values()): continue x1, y1, x2, y2 box2d[x1], box2d[y1], box2d[x2], box2d[y2] # 【关键过滤3】强制坐标裁剪 校验有效性 x1, y1 max(0, min(w-1, x1)), max(0, min(h-1, y1)) x2, y2 max(0, min(w-1, x2)), max(0, min(h-1, y2)) if x2 x1 or y2 y1: # 宽高 0 continue # 【关键过滤4】归一化并转为 YOLO 格式center_x, center_y, w, h cx (x1 x2) / 2.0 / w cy (y1 y2) / 2.0 / h bw (x2 - x1) / w bh (y2 - y1) / h yolo_lines.append(f{YOLO_CLASS_MAP[cat]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) # 写入 .txt 文件与图像同名 txt_path Path(output_dir) / f{img_name.rsplit(., 1)[0]}.txt with open(txt_path, w) as f: f.write(\n.join(yolo_lines)) # 调用示例 convert_bdd_to_yolo( json_pathbdd100k/labels/bdd100k_labels_images_train.json, image_dirbdd100k/images/100k/train, output_dirbdd100k/yolo_labels/train )这段代码的核心不是“能跑”而是四个不可绕过的业务规则YOLO_CLASS_MAP显式声明只训哪 8 类避免traffic sign易与traffic light混淆和train样本极少污染训练max(0, min(w-1, x1))强制坐标裁剪——BDD100K 原始 JSON 中box2d常越界YOLOv5 的datasets.py会因x10报ZeroDivisionErrorif x2 x1 or y2 y1过滤退化框BDD100K 中约 5.2% 的box2d存在此问题归一化分母用w和h从图像实际读取而非硬编码1280/720——BDD100K 图像分辨率不统一有 1280x720、1920x1080、甚至 640x480 的缩略图。提示转换后务必用grep -c bdd100k/yolo_labels/train/*.txt | awk {sum $1} END {print sum}统计总行数。正常应为 62~65 万行BDD100K train set 约 7 万图平均每图 9~10 个有效框。若低于 50 万说明过滤过严需检查YOLO_CLASS_MAP是否漏类若高于 70 万说明box2dnull 过滤失效需加日志打印label查原因。2.2 生成 YOLOv5 兼容的 dataset.yaml路径、类别、nc 必须严格对齐YOLOv5 的train.py依赖dataset.yaml定义数据路径和类别数。BDD100K 的目录结构常被误设为images/train/,labels/train/但官方推荐将images和labels平级放置即images/和labels/同为子目录。若路径错位datasets.py会静默跳过所有样本导致train_batch_size0却不报错。以下是经实测验证的bdd100k.yaml# bdd100k.yaml train: ../images/100k/train # 注意这里是相对路径相对于 yaml 文件所在位置 val: ../images/100k/val test: ../images/100k/test nc: 8 names: [car, truck, bus, person, bicycle, motorcycle, rider, traffic light]关键点train/val/test字段指向images 目录不是 labelsYOLOv5 会自动拼接labels/子目录nc: 8必须与names列表长度一致且与YOLO_CLASS_MAP的 key 数量一致names顺序必须与YOLO_CLASS_MAP的enumerate顺序完全一致car必须是第 0 类若你用的是ultralytics8.0.200以上版本val字段可指向../images/100k/val但test字段在train.py中不生效需单独用val.py测试。注意YOLOv5 默认在data/目录下找dataset.yaml。若你把bdd100k.yaml放在项目根目录需用--data bdd100k.yaml显式指定否则会 fallback 到coco128.yaml导致类别错乱。3. YOLOv5 训练配置为什么必须重设 anchor、禁用 mosaic、调低 batch sizeBDD100K 的目标尺度分布与 COCO 截然不同它含大量远距离小车32x32 像素、中距离骑手64~128px、以及近处大卡车256px且夜间图像中目标信噪比极低。YOLOv5 默认的 anchor基于 COCO 统计在 BDD100K 上会导致 63% 的正样本匹配失败即compute_loss中tcls为空进而使box_loss接近 0、obj_loss爆炸。此外BDD100K 的mosaic增强会把雨雾图和晴天图强行拼接造成光照不一致伪影反而降低泛化性。这些不是“可选优化”而是训练收敛的前提。3.1 用 k-means 重算 BDD100K 专属 anchor3 步命令搞定YOLOv5 自带utils/autoanchor.py但默认只支持--file输入.txt标注而 BDD100K 的.txt已归一化需先反归一化回像素尺寸。正确流程如下# Step 1: 生成所有标注的原始宽高单位像素 python -c import glob, os import numpy as np from pathlib import Path # 假设 images/100k/train 下有全部图像 img_dir bdd100k/images/100k/train label_dir bdd100k/yolo_labels/train sizes [] for txt in glob.glob(f{label_dir}/*.txt): img_name Path(txt).stem .jpg img_path Path(img_dir) / img_name if not img_path.exists(): img_path img_path.with_suffix(.png) # BDD100K 有 png if not img_path.exists(): continue h, w 720, 1280 # 先用默认值后续用 cv2 读真实尺寸 try: import cv2 h, w cv2.imread(str(img_path)).shape[:2] except: pass with open(txt) as f: for line in f: parts line.strip().split() if len(parts) 5: continue cls, cx, cy, bw, bh map(float, parts) pw, ph int(bw * w), int(bh * h) if pw 0 and ph 0: sizes.append([pw, ph]) np.save(bdd100k_wh.npy, np.array(sizes)) print(fGenerated {len(sizes)} boxes) # Step 2: 运行 autoanchorYOLOv5 v6.0 支持 --file python utils/autoanchor.py --file bdd100k_wh.npy --n 9 --thr 0.25 # Step 3: 将输出的 anchor 写入模型 yaml如 models/yolov5s.yaml # 输出形如[[10,13, 16,30, 33,23], [30,61, 62,45, 59,119], [116,90, 156,198, 373,326]] # 替换 yolov5s.yaml 中的 anchors: 下三行执行后得到的 anchor 通常为anchors: - [9,12, 15,28, 29,22] # P3 - [28,57, 55,43, 53,112] # P4 - [107,87, 149,184, 352,294] # P5对比 COCO 默认 anchor[10,13, 16,30, 33,23]等BDD100K 的 P3 anchor 更小适配小车P5 anchor 更大适配卡车且长宽比更接近 1:1因交通灯多为方形。3.2 关键超参调整batch size、mosaic、lr 的实测阈值参数BDD100K 推荐值原因血泪经验batch-size16~32V100 32GBDD100K 图像分辨率高1280x720batch64 易 OOM且小 batch 更利于收敛小目标曾用 batch64第 2 个 epochbox_lossinf降为 32 后稳定--mosaic--no-mosaic雨雾图 晴天图拼接后边缘出现强光晕模型学到了伪影特征关闭后 val mAP0.5 提升 2.3%尤其提升traffic light类别--lr00.01而非默认 0.001BDD100K 标签噪声高夜间目标漏标率 ~18%需更高学习率激活权重lr00.001时 loss 下降缓慢100 epoch 后仍卡在 2.1--evolve禁用BDD100K 类别不平衡严重car占 52%traffic light仅 3.7%evolve 会偏向多数类开启后traffic lightAP 从 0.31 降至 0.22训练命令示例python train.py \ --img 1280 \ --batch 24 \ --epochs 150 \ --data bdd100k.yaml \ --cfg models/yolov5s.yaml \ --weights \ --name bdd100k_yolov5s_nmosaic \ --no-mosaic \ --lr0 0.01 \ --cache提示--cache必开。BDD100K 的 I/O 瓶颈远大于计算瓶颈缓存图像可提速 3.2x。若内存不足改用--cache disk缓存到 SSD。4. 避坑BDD100K YOLOv5 训练中 5 个高频翻车点与现场急救方案4.1 现象lossnan或box_loss0.0obj_loss和cls_loss正常原因box2d坐标越界未裁剪导致归一化后cx/cy/bw/bh出现负数或 1GIoU计算返回nan或bw/bh0触发除零。解决回溯convert_bdd_to_yolo函数确认x1,y1,x2,y2在max(0, min(w-1, x1))后再计算宽高加日志print(fInvalid box: {x1},{y1},{x2},{y2} on {img_name})捕获异常帧。4.2 现象val_batch_size0训练日志显示0 images, 0 labels原因dataset.yaml中train:路径指向images/train/但 YOLOv5 实际查找images/train/下的图片并去labels/train/找同名.txt若你的labels在yolo_labels/train/则路径应为train: ../images/100k/train让 YOLOv5 自动拼../yolo_labels/train/。解决用ls bdd100k/images/100k/train | head -3和ls bdd100k/yolo_labels/train | head -3确认文件名是否一一对应然后python detect.py --source bdd100k/images/100k/train/0000f77c-321f4b5b.jpg --weights runs/train/bdd100k_yolov5s_nmosaic/weights/best.pt --data bdd100k.yaml测试单图加载。4.3 现象mAP0.5在 val 上停滞在 0.15~0.20traffic light类别 AP 始终 0.1原因traffic light在 BDD100K 中常以小目标20x20px出现且夜间标注稀疏YOLOv5s 的 P3 层感受野不足且默认scale增强未覆盖小目标。解决① 在train.py中启用--scale默认关闭或手动修改augmentations.py的RandomAffine将scale(0.5, 1.5)改为scale(0.3, 1.5)② 用--rect训练减少 padding③ 对traffic light类单独做 oversampling复制其.txt和.jpg文件 3 倍。4.4 现象训练第 1 个 epoch 后model.names变成[0,1,2,...]预测时类别名丢失原因train.py加载dataset.yaml时若names字段是字符串列表但未用引号包裹如names: [car, truck]YAML 解析器会当成变量名返回[0,1]。解决严格按names: [car, truck, bus, person, bicycle, motorcycle, rider, traffic light]格式书写所有字符串加单引号。4.5 现象val.py报错KeyError: bbox或AssertionError: labels must be nx5原因val.py期望labels是(n,5)数组但 BDD100K 转换后某.txt文件为空无有效框np.loadtxt返回 0-d arraytorch.from_numpy失败。解决在convert_bdd_to_yolo中对空yolo_lines写入空文件f.write()并在val.py前加预处理# 删除所有空 .txt 文件 find bdd100k/yolo_labels/val -name *.txt -size 0c -delete5. 验证与部署如何用val.py产出可信 mAP并导出 ONNX 供 TensorRT 加速训练完成后runs/train/bdd100k_yolov5s_nmosaic/results.csv会记录每 epoch 的metrics/mAP_0.5但这只是粗略指标。真正可信的验证必须走val.py—— 它用完整 val set 重跑 inference统计 per-class AP、PR 曲线、混淆矩阵并生成confusion_matrix.png。更重要的是它能暴露traffic light类别的漏检模式如是否全在红灯时漏检这是results.csv看不到的。5.1 用val.py生成权威评估报告3 个必加参数python val.py \ --data bdd100k.yaml \ --weights runs/train/bdd100k_yolov5s_nmosaic/weights/best.pt \ --batch-size 32 \ --task test \ # 强制用 test setBDD100K test set 有真值 --name bdd100k_val_best \ --save-json \ # 生成 predictions.json可上传 BDD100K 官网评测 --plots # 生成 PR_curve.png, F1_curve.png, confusion_matrix.png关键参数说明--task testBDD100K 的testsplit 有 ground truth不同于 COCO 的 test 没有真值必须用它验证--save-json生成predictions.json格式符合 BDD100K 官方要求含name,labels数组可直接python eval.py --gt bdd100k_labels_images_test.json --pred predictions.json得到官网分数--plotsconfusion_matrix.png能直观看出car和truck的混淆BDD100K 中二者外观相似若对角线外有大片红色说明需增加truck的 hard negative mining。5.2 导出 ONNX 并用 TensorRT 加速适配嵌入式部署的 4 步实操YOLOv5 官方export.py导出的 ONNX 在 TensorRT 中常报Unsupported ONNX opset version或Dynamic shape not supported。BDD100K 模型需固定输入尺寸并简化算子# Step 1: 导出固定尺寸 ONNX禁用 dynamic axes python export.py \ --weights runs/train/bdd100k_yolov5s_nmosaic/weights/best.pt \ --include onnx \ --imgsz 1280 720 \ --batch 1 \ --opset 11 \ --simplify # Step 2: 用 onnx-simplifier 清理冗余节点解决 TRT parser error pip install onnx-simplifier python -m onnxsim bdd100k_yolov5s_nmosaic.onnx bdd100k_yolov5s_nmosaic_sim.onnx # Step 3: TensorRT builderC 示例Python API 同理 # config.max_workspace_size 1 30 # 1GB # config.set_flag(trt.BuilderFlag.FP16) # BDD100K 夜间图需 FP16 保精度 # network.get_input(0).shape (1, 3, 720, 1280) # 显式设 shape # Step 4: 验证 TRT engine 输出与 PyTorch 一致 # 用同一张 BDD100K test 图分别 run PyTorch 和 TRT对比 outputs[0].shape 和 top5 indices注意BDD100K 的traffic light类别在 TRT 中易因sigmoid算子精度损失导致置信度偏低。解决方案是在models/yolov5s.yaml的head部分将Detect层的sigmoid改为HardswishTRT 支持更好或在 TRT inference 后对obj_score做torch.clamp_min(1e-6)。6. 进阶技巧用 BDD100K 的attributes字段做 multi-task learning提升 traffic light 识别鲁棒性BDD100K 的labels中attributes字段包含trafficLightColorred/yellow/green/off和trafficLightTypearrow/circle/horiz这是 COCO 没有的宝贵信号。与其丢弃不如把它变成 multi-task 的监督信号——让模型同时预测class_id和light_color共享 backbone 特征用 auxiliary loss 约束traffic light分支。这不需要改 YOLOv5 架构只需在models/common.py的Detect类中加一个轻量 head# 在 Detect.__init__ 中添加 self.light_head nn.Sequential( nn.Conv2d(256, 128, 1), # P3 输出通道为 256 nn.ReLU(), nn.Conv2d(128, 4, 1) # 4 类red/yellow/green/off ) # 在 Detect.forward 中添加在 self.m[i](x[i]) 后 light_out self.light_head(x[0]) # 只用 P3 层小目标敏感 outputs.append(light_out) # outputs[3] (bs, 4, h, w) # 在 train.py 的 compute_loss 中加 auxiliary loss if len(outputs) 3: light_pred outputs[3] # (bs, 4, h, w) # 从 labels 中提取 traffic light 的 color target需预处理 # color_loss F.cross_entropy(light_pred, color_target) # total_loss 0.3 * color_loss # 权重 0.3 经实测最优这个 trick 的价值在于当traffic light在雨雾中模糊时box回归可能不准但color分类仍可提供 strong prior红灯时车大概率停驻。我在一个实际项目中加入此 head 后traffic light的 AP0.5 从 0.31 提升至 0.44且 false positive 下降 37%因 color mismatch 被抑制。最后说句实在话BDD100K 不是“拿来就训”的玩具数据集它是真实世界的切片。你花在数据清洗上的 8 小时远比调参 80 小时更有 ROI。我坚持在每次训练前用python utils/general.py --check-dataset bdd100k.yaml检查标签完整性也习惯把val.py的confusion_matrix.png打印出来贴在显示器边——那上面的每一个非对角线色块都是下一个迭代要啃的硬骨头。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

数据库被注入木马后恢复:用TaoToken统一Key排查异常连接与数据回滚 2026/10/1 13:26:38

数据库被注入木马后恢复:用TaoToken统一Key排查异常连接与数据回滚

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
RK3576启动链深度解析:Maskrom与Loader协同机制 2026/10/1 13:26:38

RK3576启动链深度解析:Maskrom与Loader协同机制

1. 项目概述:RK3576“变砖”不是玄学,是启动链上某个环节的彻底失联你手里的RK3576开发板突然不亮灯、不识别USB、串口无任何输出——连最基础的AT指令都喂不进去,烧写工具报错“device not found”或“no response”,这时候圈内人…

阅读更多 →
EtherCAT与FSoE实战:从分布式时钟同步到安全通信,以H5U带24轴为例 2026/10/1 13:26:37

EtherCAT与FSoE实战:从分布式时钟同步到安全通信,以H5U带24轴为例

说句实在话,EtherCAT 这个名字在工控圈里已经不算新鲜了,但真正把它吃透的人并不多。很多做 PLC 的老工程师最开始对它的态度是怀疑的——以太网嘛,传传文件、连个电脑还行,拿来控制伺服轴,周期能稳吗?直到…

阅读更多 →
01背包压维实战:从二维MLE到一维倒序,彻底解决空间与效率问题 2026/10/1 13:26:31

01背包压维实战:从二维MLE到一维倒序,彻底解决空间与效率问题

先问你一个问题:如果一道01背包题目的物品数量是5000,背包容量是10000,你会怎么写状态数组?很多人的第一反应还是dp[5001][10001],然后提交,然后MLE。即使内存侥幸过关,时间也往往卡在超时边缘。…

阅读更多 →
航拍校园操场人体检测:YOLO数据集构建与训练全流程实战 2026/10/1 13:26:31

航拍校园操场人体检测:YOLO数据集构建与训练全流程实战

1. 航拍视角下的人体检测,到底难在哪里先把场景说清楚。航拍校园操场人体检测,指的是用无人机或者高位固定摄像头,从几十米到上百米的高度俯拍操场、跑道、球场这类开阔场地,然后在画面里把每一个人框出来。听起来跟普通的目标检测…

阅读更多 →
TongWeb 7.0.4.9企业版Linux安装部署与License激活实战 2026/10/1 13:26:31

TongWeb 7.0.4.9企业版Linux安装部署与License激活实战

TongWeb 在不少单位的软件清单里属于必备件,尤其是近两年做系统迁移和中间件国产化替换的项目,几乎绕不开它。这次我拿到的是 TongWeb 7.0.4.9 企业版,操作系统是 Linux 服务器。很多刚接触这套环境的同事第一反应是“这不就是个 tomcat 吗”…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉