
简介这是一份面向无人机俯视视角下车辆与行人检测的YOLOv5格式数据集适用于YOLOv5、YOLOv7、YOLOv8等主流算法目标使用者为需要航拍场景目标检测数据的开发者或科研人员。压缩包共2000个文件包括1887个TXT标注文件、112张JPG图像和1个data.yaml配置文件包体约960MB其中TXT为YOLO格式的标注信息JPG为实际检测图像。YAML文件已配置好类别names以及train、valid、test路径目录结构清晰下载后可直接放入YOLO系列框架训练无需手动划分数据集或编写配置文件能显著节省前期准备时间。同时该数据集针对无人机俯视视角能覆盖目标尺度变化与密集场景适合无人机巡检、智能交通等应用场景。目前已有1325人学习/下载可帮助快速搭建可用的车辆行人检测模型。1. 无人机俯视视角下的目标检测这份数据集到底解决了什么做无人机巡检、安防监控或者交通流量统计的同行大概率都遇到过同一个尴尬模型在地面视角的数据集上跑得好好的一换到无人机俯视视角mAP 直接掉十几个点。原因不复杂——俯视视角下目标尺度小、分布密集、遮挡严重和日常街景完全是两个分布。这份 YOLOv5 无人机俯视视角下的车辆和行人目标检测数据集就是冲着这个问题来的。数据集本身是 VisDrone 风格的裁剪结果1000 多张俯拍图像只保留 car 和 person 两个类别已经按 train、val、test 划分好目录附带的 data.yaml 里路径和类别都配好了。拿到手不需要再做 Roboflow 导出、格式转换、目录整理这些重复劳动解压之后直接喂给 yolov5、yolov7 或 yolov8 就能开始训练。适合谁两类人最对口一是刚接触无人机视觉、想快速跑通一条 YOLO 训练链路的新手这份数据集的目录结构和配置文件就是现成模板二是已经在做车辆和行人检测、但手上缺俯视视角样本的工程师拿它做迁移学习或者小目标检测的起点数据非常合适。下面我不讲虚的直接拆数据结构、训练命令和踩过的坑。2. 数据集结构拆解VisDrone 到 YOLO 的目录与标签格式2.1 VisDrone 原版标注格式为什么必须转成 YOLO 格式VisDrone 是无人机视觉检测领域被引用最多的公开数据集之一原始标注是 txt 文件每一行的格式是bbox_left, bbox_top, bbox_width, bbox_height, score, object_category, truncation, occlusion前四个值是像素坐标下的左上角 x、左上角 y、框宽、框高第五个是置信度分数第六个是目标类别编号最后两个是截断和遮挡标记。VisDrone 原版里有 car、van、truck、bus、pedestrian、person 等十几个类别坐标体系是像素左上角原点。YOLO 系列要求的标签格式完全不同。每一行是class_id x_center y_center width height五个数值都要归一化到 0 到 1 之间。也就是说坐标从「左上角 宽高」变成「中心点 宽高」并且要除以图像宽高。格式差异背后藏着两个容易踩的坑第一个是坐标换算我一般用下面这段 Python 验证def visdrone_to_yolo(bbox_left, bbox_top, bbox_width, bbox_height, img_w, img_h): x_center (bbox_left bbox_width / 2) / img_w y_center (bbox_top bbox_height / 2) / img_h w bbox_width / img_w h bbox_height / img_h return x_center, y_center, w, h这个函数的逻辑很简单先把左上角坐标偏移到中心点再各自除以图像宽高完成归一化。参数 img_w 和 img_h 是原图分辨率必须和实际图片尺寸严格一致。如果图片是 1920x1080 但这里传成了 1280x720所有框的位置会整体偏移小目标场景下偏移二三十个像素就足以让检测框完全错位。第二个坑是类别映射。VisDrone 原版的类别编号和这份数据集的 names 列表不是一回事这份数据集的 data.yaml 里 names 是[car, person]也就是 car 对应索引 0person 对应索引 1。如果拿 VisDrone 原始标注没做映射直接训练模型会把所有 car 学成别的类别预测结果全乱。提示任何数据集到手先随机抽三张图把标签框画出来人工核对一遍颜色区分清楚再谈训练。这一步救过我很多次。2.2 目录结构与 data.yaml拿到手先做三件事这份数据集的目录已经按 YOLO 惯例排好vis-drone-yolov5-dataset-2/ ├── train/ │ ├── images/ │ └── labels/ ├── valid/ │ ├── images/ │ └── labels/ ├── test/ │ ├── images/ │ └── labels/ └── data.yamlimages 下放图片labels 下放同名 txt 标签这是 YOLO 系列共同约定的目录结构。注意 valid 目录名不是 valyolov5 和 yolov8 解析 data.yaml 时读的是配置里的路径字段目录叫什么是自由的。data.yaml 内容如下names: [car, person] train: ./train/images val: ./valid/images test: ./test/imagestrain、val、test 三个字段指向各自划分的图片目录标签目录不需要写在 yaml 里YOLO 加载时会自动把 images 替换成 labels。这个隐式规则是新手最容易忽略的点——如果目录结构不是 images/labels 配对而是把标签和图片混放在同一个文件夹里dataloader 会直接报找不到标签文件或者静默跳过所有图片训练出来的模型什么也检测不到。拿到手我会强制自己走三遍检查每一遍都在真实项目里救回过一次训练。第一遍检查图片和标签的文件名是否一一对应for img in train/images/*.jpg; do base$(basename $img .jpg) if [ ! -f train/labels/$base.txt ]; then echo missing label for: $base fi done这段脚本的逻辑是遍历 train/images 下所有 jpg用 basename 剥掉扩展名得到文件名主干再去 labels 目录下找同名 txt找不到就打印提示。有的数据集里会混进几张没标注的图YOLO 训练时会跳过无标签图片不报错但到 val 阶段图片和标签数量对不上mAP 统计异常排查起来非常费时间。第二遍统计标签行数分布确认没有大面积空标签import os from collections import Counter label_dir train/labels counter Counter() for f in os.listdir(label_dir): if not f.endswith(.txt): continue with open(os.path.join(label_dir, f), r) as fp: lines [line for line in fp.readlines() if line.strip()] counter[len(lines)] 1 print(dict(sorted(counter.items())))这段代码按每个标签文件的标注行数做分布统计输出类似{1: 300, 2: 450, 3: 200, 0: 50}。出现大量 0 行文件要分情况判断无人机俯视一个空旷停车场可能真的只有一辆车但如果 0 行比例超过 5%就要怀疑是标注导出环节漏了文件。空标签图在训练时会被当作纯背景比例过高会让模型变得保守预测置信度普遍偏低甚至对真目标也不敢给出高分。第三遍确认 data.yaml 路径可解析。原配置用的相对路径./train/images这个点号是以 data.yaml 文件所在目录为基准的。如果把 data.yaml 单独复制到别处或者从其他目录执行训练命令相对路径就会错位。稳妥做法是改成绝对路径或者保证训练时的当前工作目录正确。这条看着细但非常多人在换机器跑训练时栽在这里报错信息还很晦涩容易误判成数据集损坏。2.3 标签文件逐行解读归一化坐标的换算逻辑标签每一行对应一个真实标注框格式是class x_center y_center width height。拿一个真实标签举例0 0.627083 0.502778 0.018750 0.012037 0 0.558333 0.402778 0.012500 0.010185 1 0.700000 0.511111 0.006250 0.008333第一行第一个数字 0 表示 car后面四个是归一化坐标。假设原图是 1920x1080把第一行换回像素坐标img_w, img_h 1920, 1080 x_c, y_c, w, h 0.627083, 0.502778, 0.018750, 0.012037 x1 (x_c - w / 2) * img_w y1 (y_c - h / 2) * img_h x2 (x_c w / 2) * img_w y2 (y_c h / 2) * img_h print(int(x1), int(y1), int(x2), int(y2))换算逻辑中心点横坐标减半宽再乘图像宽度得到左上角 x纵坐标同理得到 y加号得到右下角。这里容易被忽略的一点是YOLO 归一化是相对整张原始图像不是相对 letterbox 填充后的可视区域。训练时 YOLO 内部对图像做 letterbox 缩放但不改标签标签坐标在原始分辨率下依然有效只有画可视化框时才需要换算回像素坐标。第三行的目标框宽度只有 0.006250乘 1920 后约 12 个像素这是典型的俯视视角小目标。YOLOv5 默认输入分辨率 640意味着这个 12 像素的目标在特征图上只占不到 4 个像素后面所有小目标检测难题都源于此。3. 从零训练YOLOv5 和 YOLOv8 读取这份数据集的完整命令3.1 环境准备与依赖版本训练前先把环境装利索。踩过一次环境坑之后我现在都用 conda 单独建环境不碰系统里的 Pythonconda create -n yolo python3.8 conda activate yolo pip install torch1.13.1 torchvision0.14.1 --index-url https://download.pytorch.org/whl/cu117 git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt几个选择说明一下。torch 版本我刻意锁在 1.13.1yolov5 官方 release 对 torch 版本有兼容范围1.13 配 CUDA 11.7 是经过大量用户验证的稳定组合。--index-url指定 PyTorch 官方 wheel 源避免 pip 默认源装到 CPU 版本。装之前先跑nvidia-smi看一眼驱动支持的最高 CUDA 版本如果驱动支持 11.8可以把 URL 里的 cu117 换成 cu118。如果打算用 yolov8一条命令解决pip install ultralyticsultralytics 包把训练、验证、推理全部封装起来依赖 torch、torchvision 和 opencv。注意 yolov8 对 numpy 版本有要求如果报 numpy 相关错误pip install numpy1.26.4基本能解决。装完先验证 GPU 是否真的可用这一步不能省python -c import torch; print(torch.__version__, torch.cuda.is_available())输出 True 才说明 CUDA 版 torch 装对了。我有过一次教训装完 torch 发现是 CPU 版训练跑了一个多小时进度条慢得离谱查日志才发现 devicecpu。浪费的不只是时间还有对训练节奏的判断。注意如果 torch.cuda.is_available() 输出 False训练会静默回退到 CPU跑完一个 epoch 才发现就晚了第一时间检查 CUDA 轮子是否装对。3.2 训练命令与关键超参数说明目录和数据都没问题后训练命令非常直接。yolov5python train.py \ --data ../vis-drone-yolov5-dataset-2/data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --cacheyolov8 对应写法yolo detect train \ data../vis-drone-yolov5-dataset-2/data.yaml \ modelyolov8s.pt \ imgsz640 \ batch16 \ epochs100 \ cacheTrue逐个参数讲边界。--img 640是输入分辨率图像会先等比缩放再填充到 640x640。俯视场景目标小理论上把 img 提到 1280 能显著改善小目标召回但显存占用约翻四倍8G 显存下 batch 16 就跑不动了。我的习惯是先用 640 跑通全流程确认数据链路没问题再看显存余量决定要不要上 1280。--batch 16在 8G 显存下配 640 是安全值。显存不够优先降 batch 而不是降分辨率因为分辨率对检测效果的影响比 batch 大得多。--epochs 100对这个体量的数据够用如果最后 20 个 epoch val mAP 还在持续上涨可以加大到 150。--weights yolov5s.pt是 COCO 预训练权重迁移学习能显著加速收敛。第一次运行会自动下载网络不好可能失败建议手动下载放到项目目录。--cache把图片缓存进内存1000 多张图完全放得下省掉每轮 epoch 的磁盘读取时间内存小于 16G 时建议去掉。还有一个容易被忽略的参数是--hyp。yolov5 默认的 hyp.scratch-low.yaml 偏保守适合数据量不大的场景。训练时 mosaic 增强默认开启对小目标有一定帮助YOLOv5 会在训练后期自动关闭 mosaic这是内置调度逻辑不用额外干预。autoanchor 也在默认开启日志里出现AutoAnchor相关提示属于正常现象说明模型在根据当前数据集重新聚类 anchor这对俯视数据是有利的。训练启动后日志重点看三列box_loss、obj_loss 和 val mAP。前几个 epoch mAP 一直是 0 很正常模型还没形成有效检测框。训练结束会在 runs/detect/exp 目录下生成 best.pt 和 last.ptbest.pt 按 val mAP 自动挑选部署只用 best.pt。3.3 验证与推理看检测效果的正确姿势训练完第一件事是验证不是直接部署python val.py \ --data ../vis-drone-yolov5-dataset-2/data.yaml \ --weights runs/detect/exp/weights/best.pt \ --img 640输出里有两个关键指标mAP0.5 和 mAP0.5:0.95。mAP0.5 是 IoU 阈值 0.5 下的平均精度工程上最常用mAP0.5:0.95 是 0.5 到 0.95 每间隔 0.05 的均值学术报告更看重对框的定位精度要求更严格。验证结束会在 runs/detect/val 下生成混淆矩阵和 PR 曲线图PR 曲线能直观看出每个类别在不同置信度下的表现比只看 mAP 数字更有价值。推理跑测试集python detect.py \ --weights runs/detect/exp/weights/best.pt \ --source test/images/ \ --img 640 \ --conf 0.25 \ --save-txt \ --save-conf--conf 0.25是置信度阈值。俯视场景小目标多模型输出置信度普遍偏低0.25 会滤掉一部分真目标建议试 0.15 对比一下找回的数量。--save-txt保存检测结果到 txt 文件--save-conf在每行结果后附带置信度方便后面统计分析。可视化结果图保存在 runs/detect/exp 下重点看停车场和路口这两类密集场景验证模型能不能把紧密相邻的车辆分开。如果两辆并排的车只检出一个框后续要考虑 NMS 阈值调整或者换更强的模型结构。4. 避坑手册无人机俯视数据集训练的五个典型问题4.1 小目标漏检严重anchor 尺度不对现象密集停车场画面里模型只检出不到一半的车辆行人几乎全漏但大目标检测正常。原因YOLOv5 默认 anchor 是从 COCO 数据集统计出来的。COCO 里目标通常占画面比例较大anchor 尺度整体偏大。无人机俯视数据里大量目标只有十几个像素在 640 输入下对应特征图不到 4 个像素默认 anchor 根本覆盖不到这个尺度。解决让 YOLOv5 重新统计 anchor。yolov5 训练前会自动跑 k-means 聚类日志里出现AutoAnchor: ... anchors/target说明自动 anchor 已经在工作。如果聚出来后小尺度 anchor 依然不足把输入分辨率提高到 1280小目标占特征图的比例直接翻倍这是见效最快的手段。还不够就换带 P2 检测头的模型结构P2 特征图分辨率更高专门针对小目标设计。4.2 letterbox 缩放把目标缩没了现象训练 loss 正常下降但 val mAP 偏低模型检出的框普遍偏小或者对某些分辨率异常的图反复震荡。原因俯视图通常是 1920x1080 甚至更高分辨率letterbox 到 640 时图里的车可能只剩 10 个像素模型很难学到有效特征。更隐蔽的情况是有人用 resize 而不是 letterbox把图像直接拉伸到 640x640目标形状畸变模型学到的全是变形特征。解决确认数据加载用的是 letterbox 而不是 resize。yolov5 和 yolov8 默认都是 letterbox但如果是自己写的加载脚本很容易在 cv2.resize 时忘了保持宽高比。推理阶段同样要注意对原图推理时要记录 padding 和缩放比例检测框映射回原图坐标时把这两项加回去否则框的位置会整体偏移越靠近图像边缘偏移越明显。4.3 类别不平衡car 多 person 少现象car 的 AP 能到 0.8 以上person 的 AP 只有 0.1 到 0.2模型对行人基本不敏感。原因数据集中 car 的标注数量远多于 person训练时正样本比例失衡损失函数被 car 主导模型把有限的学习能力全分给了多数类。解决两个方向同时做。第一是调损失权重yolov5 的--cls参数控制分类损失系数默认 0.5可以试提高到 1.0 甚至 2.0让模型更关注稀疏类别。yolov8 类似可以在配置里调整 cls 权重。第二是数据增强对 person 类做复制粘贴增强把行人目标贴到空旷背景区域增加有效正样本。注意粘贴后标签坐标要同步更新一个常见翻车是只贴了图没改标签模型学到的是「框里是重复纹理」效果反而更差。4.4 数据泄漏train 和 val 里有相似帧现象val mAP 异常高比如 0.95 以上但部署到新场景效果很差mAP 掉一半甚至更多。原因VisDrone 是视频抽帧数据集相邻帧之间只有轻微位移。如果划分时随机打乱同一段视频里的相邻帧可能同时出现在 train 和 val模型等于提前见过答案。val 集评估的是「记忆」而不是「泛化」。解决按视频片段或场景划分而不是按单帧随机划分。检查方法很直接看 train 和 val 里是否存在文件名前缀相同、序号相邻的图。这份数据集的帧文件名带 frame 编号如果 train 里有 frame_003596、val 里有 frame_003597这就是泄漏。解决方法是把 val 里的相邻帧换掉或者按时间段整体挪动保证两个集合没有任何场景重叠。4.5 标注噪声错标和漏标怎么处理现象训练 loss 后期降不下去mAP 震荡不稳某个类别的 AP 突然掉点或者长时间不涨。原因俯视视角下目标太小标注时容易漏掉远处的车辆也容易把两辆紧挨的车标成一个框。这些噪声标签在训练初期影响不大后期会持续拉高 loss让模型在置信度和定位之间反复横跳。解决拿训练好的模型对训练集做一次回测把预测框和标注框做 IoU 匹配。找出 IoU 低于 0.3 且模型置信度很高的标注框这些大概率是错标反过来模型高置信度预测但附近没有任何标注的区域大概率是漏标。清洗规则不要太激进每张图人工看一眼再决定批量删除会把有效样本误伤。我一般清洗两轮第一轮删明显错标第二轮修正偏移较大的框重训一次 mAP 通常能涨 2 到 5 个点。5. 进阶玩法用切片推理把小目标检测精度再提一档5.1 SAHI 切片推理实战当 640 输入下目标只有 12 像素时一个立竿见影的优化是切片推理。SAHI 框架把原图切成若干个 640x640 的块每块独立推理再把结果拼回原图目标在每一块里的相对尺寸变大检测难度直接降一个量级。from sahi import AutoDetectionModel from sahi.predict import get_prediction detection_model AutoDetectionModel.from_pretrained( model_typeyolov5, model_pathruns/detect/exp/weights/best.pt, confidence_threshold0.2, image_size640, ) result get_prediction( test/images/frame_003596.jpg, detection_model, slice_height640, slice_width640, overlap_height_ratio0.2, overlap_width_ratio0.2, )slice_height和slice_width控制切片大小overlap_height_ratio和overlap_width_ratio控制重叠比例。重叠参数必须有目标被切在边缘时容易漏检20% 重叠能明显缓解。切片推理的代价是耗时随切片数线性增长一张 1920x1080 的图切成 6 块速度慢约 6 倍适合离线分析场景不适合实时部署。5.2 部署前的导出与验证模型验收后部署先用官方导出脚本转 ONNXpython export.py --weights runs/detect/exp/weights/best.pt --include onnx --img 640导出后用 onnxruntime 做一次推理验证。预处理顺序是最容易出错的地方OpenCV 读进来是 BGR 要转 RGBHWC 要转 CHW像素值要除以 255 归一化任何一步错了输出都是乱的。这一步通过后再考虑 TensorRT 量化精度损失能控制在 1 个点以内。5.3 一个固化的检查习惯现在每接到新数据集我都强制走一遍流程抽三张图把标签画回原图人工过眼跑标签分布统计按场景检查 train/val 泄漏最后才开训练。训练完用 best.pt 回测训练集挑出高置信度错标清洗一轮。这套流程看起来繁琐但每次都在训练前拦住问题比训练到半夜发现 loss 曲线不对再返工划算得多。从那以后我每次训练前都强制走一遍这套流程切片推理也一定先跑出 baseline 再对比不叠加没验证的技巧。这份数据集的压缩包是 vis-drone-yolov5-dataset-2.zip按项目名检索就能找到解压即训。希望这份拆解和踩坑记录能帮到你。本文还有配套的精品资源点击获取