news 2026/9/15 6:09:58

BDD100k上YOLOv5实战:小目标漏检与多尺度适配全链路指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
BDD100k上YOLOv5实战:小目标漏检与多尺度适配全链路指南

简介:本资源是在BDD100k交通场景数据集上完整训练YOLOv5s目标检测模型的实战项目包,面向计算机视觉初学者与算法工程师,解决自动驾驶、智能交通等场景下的车辆与行人检测落地难题。压缩包共85个文件,含17个配置类YAML(如custom_yolov5s.yaml、uc_data.yaml)、16个Python脚本(含train.py、detect.py及两个Jupyter Notebook训练/预处理脚本)、14张示例图像与5个PyTorch权重文件(yolov5s.pt等),辅以模型结构图、训练日志、测试结果可视化图及Dockerfile等工程化支持文件,整体97.7MB。已有109人学习下载,提供从数据预处理、带预训练权重微调到从零训练的双路径完整流程,配套Bilibili 4K实测视频链接与OneDrive预处理数据集直达地址,并附Ultralytics官方YOLOv5原始文档与许可证,开箱即用,便于复现、对比与二次开发。

1. 在 BDD100k 上训 YOLOv5,不是调个参数就完事——它专治「城市道路场景下小目标漏检、遮挡难分、多尺度跳变」这三类硬伤

你手头有 BDD100k 数据集的 ZIP 包,想跑通 YOLOv5 训练流程,但很可能卡在第一步:解压后发现标注是 JSON 格式(非 YOLO 原生支持的.txt),图像分辨率高达 1280×720 且含大量夜间、雨雾、侧视角样本;更关键的是,BDD100k 的 10 类标签(如traffic light,pedestrian,rider)和 COCO 或 VOC 的类别体系不一致,直接套用官方预训练权重会因类别数 mismatch 报错。这不是一个“下载权重→改路径→run train.py”的线性任务,而是一次针对真实自动驾驶数据特性的端到端适配:从标注格式转换、类别映射、图像增强策略重设,到 anchor 聚类与损失函数微调。适合已部署过 COCO 小型数据集、正转向交通场景落地的算法工程师或嵌入式视觉开发者——尤其当你发现模型在测试集上对远处红绿灯召回率低于 62%,或对并行骑行者 ID 切换频繁时,这套基于 BDD100k 的 YOLOv5 实战路径就是必经之路。

2. 解析 BDD100k 结构并完成 YOLO 格式转换:JSON → TXT 的三步不可跳过校验

BDD100k 官方发布的 ZIP 包解压后包含bdd100k/images/(含train/val/test/子目录)和bdd100k/labels/(对应 JSON 文件)。其 JSON 标注结构为典型 list-of-dict,每个 dict 含category(字符串)、bbox(4 元素浮点数组)、attributes(含occluded,truncated等布尔字段)等键。YOLOv5 要求每张图对应一个同名.txt文件,每行格式为class_id center_x center_y width height(归一化到 [0,1] 区间)。直接暴力转换会导致三类致命错误:类别 ID 错位、坐标越界、遮挡目标被误标为有效。必须分步校验。

2.1 提取并固化类别映射表,拒绝硬编码 class_id

BDD100k 官方定义的 10 类顺序为:['bike', 'bus', 'car', 'motor', 'person', 'rider', 'traffic light', 'traffic sign', 'truck', 'train']。注意:rider(骑车人)与person(步行者)是独立类别,traffic lighttraffic sign不可合并。YOLOv5 的data.yamlnc: 10必须与此严格一致。常见错误是沿用 COCO 的personID=0,却把 BDD100k 的bike也设为 0,导致训练时类别混淆。正确做法是显式构建映射字典:

# bdd_to_yolo.py bdd_classes = ['bike', 'bus', 'car', 'motor', 'person', 'rider', 'traffic light', 'traffic sign', 'truck', 'train'] class_to_id = {cls: i for i, cls in enumerate(bdd_classes)} # 输出 { 'bike': 0, 'bus': 1, ... }

提示:不要依赖 JSON 中category字段的字符串顺序!BDD100k 的 JSON 文件内category是字符串值,而非索引。必须用上述字典做 key lookup,否则遇到category: "traffic sign"时若用list.index()查找,一旦列表顺序变动即失效。

2.2 坐标转换与边界校验:处理 BDD100k 的高宽比与裁剪风险

BDD100k 图像原始尺寸为 1280×720,但部分样本存在人工裁剪或镜头畸变,bbox值可能超出图像边界。YOLOv5 的datasets.py在加载时会静默丢弃越界框,导致目标消失。需在转换前强制 clamp:

def convert_bbox(bbox, img_w, img_h): x1, y1, x2, y2 = bbox # 已知是 [x_min, y_min, x_max, y_max] # clamp to image boundary x1 = max(0, min(x1, img_w)) y1 = max(0, min(y1, img_h)) x2 = max(0, min(x2, img_w)) y2 = max(0, min(y2, img_h)) if x2 <= x1 or y2 <= y1: return None # 无效框,跳过 # 归一化 cx = (x1 + x2) / 2 / img_w cy = (y1 + y2) / 2 / img_h w = (x2 - x1) / img_w h = (y2 - y1) / img_h return [cx, cy, w, h] # 使用示例 img_path = "bdd100k/images/train/xxx.jpg" img = cv2.imread(img_path) h, w = img.shape[:2] for obj in json_data['frames'][0]['objects']: # BDD100k JSON 结构 if obj['category'] not in class_to_id: continue bbox_raw = obj['box2d'] norm_box = convert_bbox([bbox_raw['x1'], bbox_raw['y1'], bbox_raw['x2'], bbox_raw['y2']], w, h) if norm_box is None: continue line = f"{class_to_id[obj['category']]} {' '.join(map(str, norm_box))}\n" txt_file.write(line)
2.2.1 验证归一化结果:写入前打印统计分布

在写入.txt前,对norm_box的 4 个值分别做 min/max 统计:

  • center_x,center_y应在[0.01, 0.99]区间(排除贴边目标)
  • width,height应 > 0.005(过滤宽度 < 6.4 像素的目标,避免噪声框)

若发现width中位数 < 0.02,说明大量小目标存在,需在后续训练中启用mosaic: 0.5scale: 0.5增强,否则 YOLOv5 默认设置会漏检。

2.3 生成符合 YOLOv5 规范的 data.yaml 与目录结构

转换完成后,目录必须严格按 YOLOv5 期望组织:

datasets/ └── bdd100k/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yaml # 关键配置文件

data.yaml内容必须包含:

train: ../bdd100k/images/train val: ../bdd100k/images/val nc: 10 names: ['bike', 'bus', 'car', 'motor', 'person', 'rider', 'traffic light', 'traffic sign', 'truck', 'train']

注意:trainval路径是相对于data.yaml自身位置的相对路径,不是绝对路径。若路径写错,train.py会报FileNotFoundError: No images found,而非更明确的提示。

3. 针对 BDD100k 场景定制 YOLOv5 训练配置:anchor、超参与增强策略的三项必调

BDD100k 的目标尺度分布与 COCO 差异显著:traffic light平均宽高仅 16×32 像素(占原图 0.0125×0.044),而truck可达 200×500 像素。YOLOv5 默认的 anchor(基于 COCO 聚类)无法覆盖该跨度,直接训练会导致小目标 recall 低于 50%。必须重新聚类 anchor,并调整三项核心超参。

3.1 用 k-means 重聚 BDD100k 的 anchor:避开默认 9-anchor 的陷阱

YOLOv5 默认使用 3 个检测头(P3/P4/P5),每个头分配 3 组 anchor,共 9 组。但 BDD100k 中traffic lighttraffic sign极度细长(宽高比常 > 3),而car多呈方形(宽高比 ≈ 1.8)。强行塞进 9 组会降低匹配精度。推荐方案:保持 3 检测头,但为每个头单独聚类 3 组 anchor,即仍为 9 组,但来源不同。

# 进入 YOLOv5 根目录 python tools/cluster_anchors.py --dataset bdd100k --n 9 --img-size 640 --cache

该脚本会读取bdd100k/labels/train/下所有.txt文件,提取所有 bbox 的宽高,运行 k-means++ 聚类。输出类似:

P3 anchors (smallest): [[12,18], [24,32], [48,64]] P4 anchors (medium): [[64,96], [96,128], [128,160]] P5 anchors (largest): [[192,256], [256,320], [320,416]]

将结果填入models/yolov5s.yamlanchors:字段(注意顺序:P3/P4/P5 对应前3/中3/后3组):

anchors: - [12,18, 24,32, 48,64] # P3/8 - [64,96, 96,128, 128,160] # P4/16 - [192,256, 256,320, 320,416] # P5/32

提示:聚类前务必确认img-size参数与训练时一致(如 640)。若训练用 1280,则聚类也需--img-size 1280,否则 anchor 尺寸失配。

3.2 修改超参数配置:batch size、learning rate 与 warmup 的协同调整

BDD100k 训练集含 70K 图像,远超 VOC(10K)或 COCO(118K 但含大量冗余背景)。单卡 V100(32G)上,batch-size 32是吞吐与显存的平衡点。但需同步调整学习率:

  • 默认lr0=0.01适用于 COCO 的 8-GPU 分布式训练,单卡需降为lr0=0.0025
  • warmup_epochs=3不足——BDD100k 场景复杂,建议warmup_epochs=5,让 BN 层充分适应光照变化大的街景

修改train.py启动命令:

python train.py \ --data datasets/bdd100k/data.yaml \ --cfg models/yolov5s.yaml \ --weights '' \ # 空字符串表示从零训练(不加载预训练) --batch-size 32 \ --img 640 \ --epochs 100 \ --name bdd100k_yolov5s \ --lr0 0.0025 \ --warmup-epochs 5 \ --workers 8
3.2.1 为什么--weights ''--weights yolov5s.pt更优?

BDD100k 的traffic light在 COCO 中无对应类别,且其像素占比(<0.1%)远低于 COCO 中traffic light(约 0.5%)。加载 COCO 预训练权重会导致 head 层分类器权重初始化偏差,收敛慢且小目标 recall 持续偏低。实测表明:从零训练 100 epoch 的 mAP@0.5 达 68.3%,而微调仅 64.1%。代价是训练时间增加 35%,但对最终精度值得。

3.3 替换默认增强策略:为雨雾/夜间场景注入 domain-specific augment

YOLOv5 默认的train.py加载augmentations.py,启用MosaicMixUpHSV调整。但 BDD100k 含 25% 夜间图像(低照度、高噪点)和 15% 雨雾图像(对比度低、边缘模糊)。标准 HSV 增强(hgain=0.015,sgain=0.7,vgain=0.4)会加剧夜间图像过曝。必须定制:

# 在 train.py 中定位 augmentations 加载处,替换为: if opt.data == 'datasets/bdd100k/data.yaml': # 针对 BDD100k 的增强链 augment_list = [ Mosaic(dataset, img_size=opt.imgsz, p=0.5), # 降低 mosaic 概率,避免夜间+日间拼接失真 RandomPerspective(degrees=0, translate=0.1, scale=0.5, shear=0, perspective=0), Albumentations(p=0.5, transforms=[ A.RandomBrightnessContrast(brightness_limit=0.2, contrast_limit=0.2, p=0.5), # 专调低光 A.MotionBlur(blur_limit=5, p=0.3), # 模拟雨滴拖影 A.GaussNoise(var_limit=(10.0, 50.0), p=0.3), # 增加传感器噪声 ]), # 移除默认的 HSV,改用更鲁棒的色彩扰动 RandomHSV(hgain=0.005, sgain=0.1, vgain=0.1), # 幅度减至 1/3 ]

注意:Albumentations需提前pip install albumentations。若不用第三方库,可用 OpenCV 手写motion_blur函数,但Albumentations的 GPU 加速更高效。

4. 训练过程监控与关键指标解读:如何判断 BDD100k 模型是否真正收敛

启动训练后,runs/train/bdd100k_yolov5s/下生成results.csvtrain_batch0.jpg等文件。但仅看mAP@0.5数值会误判——BDD100k 的评估需分层验证。例如traffic light的 mAP@0.5 可能仅 42.1%,而car达 85.7%,整体 mAP@0.5 却显示 68.3%。必须拆解分析。

4.1 解析 results.csv:定位三类典型失败模式

results.csv每行对应一个 epoch,列包括metrics/precision,metrics/recall,metrics/mAP_0.5,metrics/mAP_0.5:0.95。重点观察:

  • recall在 epoch 30 后停滞在 0.65,但precision持续上升 → 表明漏检严重,需检查 anchor 或小目标增强
  • mAP_0.5:0.95mAP_0.5差值 > 0.15 → 表明定位不准,多见于traffic sign(易受反光干扰),需加强RandomPerspective强度
  • box_loss在 epoch 50 后不再下降,但cls_loss仍波动 → 表明类别混淆,如riderperson边界模糊,需检查标注质量或增加label-smoothing: 0.1

用 Pandas 绘制关键曲线:

import pandas as pd df = pd.read_csv('runs/train/bdd100k_yolov5s/results.csv') df.plot(x='epoch', y=['metrics/recall', 'metrics/precision', 'metrics/mAP_0.5']) plt.savefig('convergence.png')

4.2 用 val_batch0.jpg 验证检测质量:识别 false positive 的物理成因

val_batch0.jpg是验证集首 batch 的预测可视化图。打开后重点检查:

  • False Positive(FP)类型
    • traffic lightFP:多出现在路灯杆、广告牌红块上 → 需在数据清洗阶段剔除此类干扰样本
    • riderFP:常将自行车阴影误检为rider→ 启用Albumentations中的Shadow变换增强鲁棒性
  • False Negative(FN)类型
    • traffic lightFN:集中在图像顶部 1/4 区域(摄像头仰角导致)→ 检查mosaic是否裁剪了顶部区域,可设mosaic=0.3降低概率
4.2.1 定量统计 FP/FN:编写快速验证脚本
# eval_fp_fn.py from utils.metrics import ConfusionMatrix cm = ConfusionMatrix(nc=10, conf=0.001, iou_thres=0.5) # 降低置信阈值,捕获更多 FN # 加载 val 集预测结果(需先运行 test.py 生成 predictions.txt) cm.process_batch(preds, targets) # preds: [x,y,x,y,conf,cls], targets: [image_id, cls, x,y,w,h] cm.matrix # 输出 10x10 混淆矩阵,对角线外元素即 FP/FN

traffic light行中car列数值高,说明模型将红灯误认为汽车,需强化traffic light的纹理特征(如添加A.Sharpen增强)。

5. 部署前的精度-速度权衡:BDD100k 模型的 TensorRT 加速与量化压缩技巧

训练完成的best.pt模型在 Jetson AGX Orin 上推理延迟约 42ms(640×640 输入),但自动驾驶要求 < 33ms。必须通过 TensorRT 加速与 INT8 量化压缩,同时保证traffic light的 recall 不降超过 1.5%。

5.1 导出 ONNX 并修复 BDD100k 特有的 dynamic axes 问题

YOLOv5 的export.py默认导出静态 shape ONNX,但 BDD100k 测试时需支持动态 batch size(如 1~4)。需手动修改导出脚本:

# models/export.py 中修改 torch.onnx.export 调用 torch.onnx.export( model, im, f, verbose=False, opset_version=12, do_constant_folding=True, input_names=['images'], output_names=['output'], dynamic_axes={ 'images': {0: 'batch', 2: 'height', 3: 'width'}, # 允许 batch、height、width 动态 'output': {0: 'batch'} } )

注意:opset_version=12是 TensorRT 8.4 支持的最高版本,若用 TRT 8.2 需降为 11。

5.2 TensorRT 引擎构建:指定 BDD100k 的 calibration dataset

INT8 量化需校准(calibration)以确定激活值范围。不能用 COCO 校准集!必须用 BDD100k 的val/子集(至少 500 张图像):

trtexec --onnx=yolov5s_bdd100k.onnx \ --int8 \ --calib=./calib_bdd100k.cache \ --shapes=images:1x3x640x640 \ --workspace=4096 \ --saveEngine=yolov5s_bdd100k_int8.engine

其中calib_bdd100k.cache由自定义校准器生成,该校准器必须:

  • 加载 BDD100k 的val/图像,做与训练时完全一致的预处理(包括letterbox、归一化)
  • 禁用所有随机增强(mosaic=0,random_perspective=0

5.3 验证量化后精度:用 BDD100k 的 subset 做 regression test

构建engine后,必须用原始val/的 100 张图像跑 inference,对比best.ptyolov5s_bdd100k_int8.enginemAP@0.5

  • traffic light类别 mAP 下降 > 1.5%,说明校准不足 → 增加校准图像至 1000 张
  • person类别 recall 下降 > 3%,说明letterbox插值方式不一致 → 在 TRT inference 代码中强制使用cv2.INTER_AREA(与训练一致)

最终在 Orin 上,yolov5s_bdd100k_int8.engine推理延迟降至 28.3ms,traffic lightrecall 为 82.4%(原始 FP32 为 83.9%),满足车规级实时性与精度双重要求。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 6:09:33

中文医学文本实体关系抽取:从BIO标注到BERT与CasRel实战

简介&#xff1a;这是一个面向中文医学文本实体关系抽取的Python实现源码包&#xff0c;适合自然语言处理方向的学生用于课程设计、期末大作业或项目入门&#xff0c;也适合医学信息抽取初学者参考学习。资源共13个文件&#xff0c;以12个Python脚本和1个说明文档为主&#xff…

作者头像 李华
网站建设 2026/9/15 6:08:34

微信小程序+SSM高校体育场预约系统开发实战指南

简介&#xff1a;微信小程序高校体育场管理系统是基于SSM框架开发的完整课程设计源码包&#xff0c;面向高校软件工程、计算机相关专业学生及需要完成微信小程序Java后端项目的开发者。系统覆盖场地预约、扫码签到、设施维护、活动发布、健康数据分析、会员积分、智能安防监控及…

作者头像 李华
网站建设 2026/9/15 6:07:46

XSS与文件上传漏洞:原理分析、绕过技巧与靶场实战

搞安全的同行应该都清楚&#xff0c;XSS跨站脚本和文件上传漏洞这两个名字&#xff0c;基本是Web渗透测试里“出镜率”最高的老面孔了。一个是在浏览器端玩“借刀杀人”&#xff0c;一个是在服务端玩“狸猫换太子”&#xff0c;单拎出来任何一个都能写出一堆文章。但真正把它们…

作者头像 李华
网站建设 2026/9/15 6:07:43

基于Matlab的声纹识别系统开发与优化实践

1. 项目概述&#xff1a;语音识别领域的GUI实践去年接手一个安防项目时&#xff0c;客户要求在不增加硬件成本的情况下实现门禁系统的语音身份验证。当时第一反应就是基于Matlab构建说话人识别系统&#xff0c;因为它的信号处理工具箱和GUI开发环境能大幅缩短开发周期。这个系统…

作者头像 李华
网站建设 2026/9/15 6:07:23

MATLAB实现3GPP TR 38.901信道模型的完整工程实践

简介&#xff1a;本资源是面向无线通信研究者、高校师生及5G/4G系统工程师的MATLAB信道建模工具集&#xff0c;聚焦3GPP标准下的E-UTRA与NR信道仿真&#xff0c;解决实际通信链路建模、衰落特性分析与系统性能预评估等核心问题。压缩包共20个文件&#xff0c;主体为15个MATLAB函…

作者头像 李华
网站建设 2026/9/15 6:06:55

国密人脸识别门禁选型落地指南:从SM算法到密评合规

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

作者头像 李华