简介:一份面向无人机俯视视角的车辆与行人目标检测数据集,专门为 YOLO 系列算法训练而整理,适用于安防监控、智慧交通、低空巡检等场景中的目标检测研究与实践。压缩包共 2000 个文件,整体约 960.43MB,其中 112 张 jpg 为无人机俯拍原图,1887 个 txt 为对应的 YOLO 格式标注文件,1 个 yaml 为数据配置文件;目录已预先划分为 train、val、test 三个子集,data.yaml 中定义了 car 与 person 两类目标及对应图像路径,组织清晰、便于直接调用。使用者拿到后无需重新整理数据格式,即可直接基于 YOLOv5、YOLOv7、YOLOv8 等主流框架启动训练,快速验证模型效果,尤其适合需要无人机视角训练数据做算法对比、模型微调或毕业设计的中高级开发者和研究人员。目前已有 1321 人浏览学习,下载后可立即聚焦网络结构与参数优化,节省大量采集与标注的时间成本。
1. 无人机俯视视角下的目标检测,卡点从来不在模型而在数据
从 300 米高度往下看,一辆轿车只有 20×40 像素,一个行人更是十几个像素的灰度块。很多人在 VisDrone、UAVDT 这类公开数据集上跑 YOLOv5 感觉“不收敛”或者“mAP 上不去”,问题往往出在锚框尺度和标注风格上,而不是网络结构。这套 “vis-drone-yolov5-dataset-2” 数据集就是从无人机俯视视频帧里抽出来的子集,标注只保留 car 和 person 两类,已经按 train、val、test 分好目录,并带了可直接加载的 data.yaml。对于要做毕业设计、算法对比或者模型快速验证的工程师来说,省掉的是整理标签和划分数据集的机械时间,可以直接把精力放在训练参数和小目标策略上。下面按“数据格式 → 配置解读 → 训练调参 → 推理验证”的顺序拆开讲。
2. VisDrone 原始标注到 YOLO 格式的转换与目录结构
2.1 为什么直接用 VisDrone 原生标注不行
VisDrone 官方数据集的标注是bbox_left, bbox_top, bbox_width, bbox_height, score, category, truncation, occlusion八个字段的 txt 文件,类别有 10 种:pedestrian、people、bicycle、car、van、truck、tricycle、awning-tricycle、bus、motor。但 YOLOv5 期望的标注格式是归一化的class_id, x_center, y_center, width, height,前四个值都是 0~1 的小数,最后没有类别以外的附加信息。
常见做法是先按 VisDrone 官方提供的visdrone2yolo.py脚本做一次字段映射。这个数据集已经帮你完成了这步,并且做了一次类别合并——把 van、truck、bus 等车辆类统一归到car,把 pedestrian、people 归到person。这一步对实际工程很重要,因为俯视视角下车辆互相遮挡严重,细分车型会引入大量标注噪声,二分类反而更容易让模型聚焦在“运动物体”的轮廓特征上。文件名的frame_003596_jpg.rf.65b4d825ed3c6fc222d449c5eab7a546.jpg这种带.rf.随机哈希后缀的命名,说明这批图经过 Roboflow 平台的导出处理,标签文件路径与图片路径一一对应,不需要额外做文件名匹配。
2.2 数据集目录的完整铺成
拿到压缩包解压后,目录结构应该是这样:
vis-drone-yolov5-dataset-2/ ├── train/ │ ├── images/ │ │ ├── frame_003596_jpg.rf.65b4d825ed3c6fc222d449c5eab7a546.jpg │ │ └── ... │ └── labels/ │ ├── frame_003596_jpg.rf.65b4d825ed3c6fc222d449c5eab7a546.txt │ └── ... ├── valid/ │ ├── images/ │ └── labels/ ├── test/ │ ├── images/ │ └── labels/ └── data.yaml注意valid目录名是完整拼写,不是 YOLOv5 早期版本里常见的val。如果你把 YOLOv5 仓库的coco128.yaml拿来对比,会发现官方示例里用的就是val,而 Roboflow 导出的数据集统一用valid。这对训练没有影响,因为data.yaml里明确指定了路径,YOLOv5 在train.py里会直接读data_dict['val']的值去拼接图片路径,不关心目录本身叫val还是valid。唯一的坑是:如果后来你手动把valid改成val,yaml 忘了同步,训练会直接报 FileNotFoundError。
2.3 data.yaml 逐行拆解
该数据集自带的 data.yaml 内容如下:
names: ['car', 'person'] train: ./train/images val: ./valid/images test: ./test/images这个 yaml 是“相对路径 + 图像目录”的写法,YOLOv5 支持二者混合使用。加载时data_dict.yaml经过check_dataset函数处理后,会把相对路径基于当前工作目录解析成绝对路径,然后自动检查每个集合的图片数量和标注数量是否一致。names列表的索引就是标注 txt 文件里的第一个数字,0 代表 car,1 代表 person——这个顺序不能改,否则训练出来的类别名会错位。
test字段在 YOLOv5 的train.py里默认不会被读取,只有跑val.py并指定--data指向该 yaml 时,才可能用到 test 目录。YOLOv7 和 YOLOv8 的兼容性也在这个层面:三套框架都支持读取包含train、val、names三个关键字段的 yaml 文件,YOLOv8 还会忽略未知字段,所以这个配置文件从 v5 切到 v8 时不需要改动。
3. 训练前的数据校验与标签质量检查
3.1 环境准备与依赖版本
YOLOv5 官方仓库在 2023 年后主分支锁定为 v7.0 版本,requirements.txt里核心依赖是torch>=1.8.0、opencv-python>=4.1.2、numpy>=1.21.0。如果你是新机器,建议直接建一个新的 conda 环境:
conda create -n yolo python=3.9 -y conda activate yolo git clone https://github.com/ultralytics/yolov5 # 国内网络下也可以直接用 release 包 cd yolov5 pip install -r requirements.txt安装完成后,先确认 CUDA 是否真的可用:训练之前跑python -c "import torch; print(torch.cuda.is_available())"。如果输出 False,说明你装的 PyTorch 是 CPU 版本,需要到 pytorch.org 用pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118重装。我见过很多人卡在这一步,后面训练日志里显示设备是 CPU,一个 epoch 跑几十分钟,直接劝退。这套数据集只有 1000 多张图,用 CPU 硬跑理论上可以出结果,但一是不划算,二是超参数调优的迭代速度太慢,不推荐。
3.2 用脚本统计标注分布
在跑训练之前,我一般会先写一个脚本统计每个 split 的类别数量、图片尺寸分布、标注框面积分布,提前发现数据集的问题,而不是等训练完看曲线再猜。以下脚本适用这套数据:
import os from collections import Counter from pathlib import Path for split in ["train", "valid", "test"]: label_dir = Path(f"{split}/labels") size_counter = Counter() class_counter = Counter() total_boxes = 0 for txt_path in label_dir.glob("*.txt"): with open(txt_path, "r") as f: lines = f.readlines() total_boxes += len(lines) for line in lines: parts = line.strip().split() class_counter[int(parts[0])] += 1 # 计算标注框在归一化坐标系下的面积占比 w, h = float(parts[3]), float(parts[4]) size_counter["small" if w * h < 0.01 else "medium"] += 1 print(f"{split}: images={len(list(label_dir.glob('*.txt')))} boxes={total_boxes}") print(f" classes={dict(class_counter)} sizes={dict(size_counter)}")脚本逻辑很简单:遍历labels目录下每个 txt 文件,读取每一行标注,按类别统计数量,同时用框宽乘框高算出面积占比,小于 1% 的视为小目标。对无人机俯视场景,你会看到 small 类占比超过 80%——这是预期结果,不必惊慌,后面调锚框和训练参数时会专门处理。这里有个隐藏信息:len(list(label_dir.glob('*.txt')))与images目录下的.jpg数量必须完全一致。如果哪张图缺失标签文件,YOLOv5 训练时会在LoadImagesAndLabels里触发警告跳过该图,但如果标签缺失超过 10%,模型会在训练后期出现明显的类别偏好偏斜。
3.3 常见标注问题与快速修复
俯视数据集常见的标注问题有三类:一是框没框住完整车身,尤其是车头方向与相机径向一致时,目标会变成细长条;二是密集场景下遮挡目标漏标;三是坐标值出现负数或超过 1 的越界值。
# 快速查找越界标注,适用于 YOLO 格式 txt awk '{ if ($3 < 0 || $4 < 0 || $5 < 0 || $6 < 0 || $3 > 1 || $4 > 1 || $5 > 1 || $6 > 1) print FILENAME }' $(find . -name "*.txt" -path "*/labels/*") | head -20这段命令用 awk 对每个 txt 文件的第 3~6 列做范围检查,一旦发现有小于 0 或大于 1 的值,就打印文件名。这里第 1、2 列是类别 id 和 score(score 固定为 1,YOLO 格式不读取),第 3、4 列是中心点坐标,第 5、6 列是宽高。如果输出有文件,说明标注在 Roboflow 导出时发生了坐标溢出,最稳妥的修复方式是把越界的值 clamp 回 0~1 区间。对于漂浮的极端值,直接删除对应行反而会让该类别学习到错误的分布先验,不如保留边界框。
4. 模型训练核心参数调优,锚框与图像尺寸是关键
4.1 训练命令与参数直觉
本数据集可以直接用以下命令开始训练(这里以 YOLOv5 7.0 为例):
python train.py \ --data /your/path/to/vis-drone-yolov5-dataset-2/data.yaml \ --weights yolov5s.pt \ --img 1280 \ --batch 16 \ --epochs 100 \ --workers 4 \ --device 0 \ --project ./runs/uav \ --name car_person_v2参数说明:--img 1280是把训练图像缩放到 1280×1280,这是俯视小目标场景下最重要的一个参数——默认的 640 对 20×40 像素的小目标太不友好,上采样到 1280 后,一个车宽能占到 40×80 像素,锚框匹配成功率明显提高。代价是显存占用涨约 4 倍,如果你的显卡是 8GB 显存,建议把 batch 降到 8。--batch 16表示每个 step 用 16 张图,--workers 4是 dataloader 的进程数,设置为 CPU 核心数的一半左右效果较好,太高反而会触发磁盘 IO 瓶颈。
train.py会自动从 yaml 的names字段读取类别数,不需要你显式传--nc。如果你传了--weights yolov5l.pt这类预训练权重,模型会保留 COCO 80 类分类头的全部参数,然后只把最后一层卷积替换为 2 类输出——这个过程叫“迁移学习”。YOLOv5 7.0 的做法是冻结前 10 层主干权重 50 个 epoch,防止小数据量训练时微调破坏 ImageNet 预训练特征,如果你要修改这个策略,可以去train.py里搜freeze参数。
4.2 锚框:重新聚类还是用默认值
YOLOv5 的kmeans_anchors方法在训练开始前会自动基于你的标注框做聚类,得到的锚框会覆盖在数据集的标注框分布上。但实际跑下来你会发现,默认的自动聚类有个前提:它使用--img 640下的归一化框坐标做聚类。当--img 1280时,标注框面积占比不变,但像素尺寸放大,这时自动聚类结果会更偏向大框,对小目标的锚框感知能力会下降。
我常用的处理方式是先单独跑一次自动聚类查看结果:
python utils/autoanchor.py --cfg models/yolov5s.yaml --data /your/path/to/vis-drone-yolov5-dataset-2/data.yaml这个脚本会输出当前数据集的标注框长宽比分布、最佳召回率,以及重新聚类的 9 组锚框尺寸。对于俯视视角,你大概率会看到大量宽高比在 0.8~1.2 之间的小框——因为俯视下车辆从正上方看近似正方形,这一点和 COCO 数据集里以横向矩形为主的分布差异很大。把脚本输出的新锚框写回models/yolov5s.yaml的anchors字段,然后再训练 100 轮,mAP 通常能提升 2~3 个点。如果你用的是 YOLOv8 或 YOLOv11,锚框自动学习已经内置在 loss 计算里,不需要这步。
4.3 超参数文件的选择与调整
YOLOv5 的data/hyps/hyp.scratch-low.yaml是 7.0 版本默认的超参数,里面最关键的是三组:lr0(初始学习率 0.01)、mosaic(Mosaic 增强概率 1.0)、fl_gamma(focal loss 的 gamma 值 0.0)。俯视小目标场景,我会做如下调整:
| 参数 | 默认值 | 建议值 | 理由 |
|---|---|---|---|
hsv_h | 0.015 | 0.005 | 俯视数据主要靠轮廓特征,颜色增强过大容易引入噪声 |
scale | 0.5 | 0.8 | 加大随机缩放范围,模拟不同飞行高度下的尺度变化 |
fliplr | 0.5 | 0.3 | 无人机视频帧里车头朝向有统计偏差,左右翻转太频繁会混淆方向 |
mosaic | 1.0 | 0.8 | 小目标场景 Mosaic 必须开,但 1.0 会导致每个 batch 全是拼接图,失去原始比例信息 |
修改超参数文件后训练命令不变,只需追加--hyp data/hyps/hyp.scratch-low.yaml。要注意的是,YOLOv5 每个 epoch 结束时会记录当前超参数到runs/uav/car_person_v2/hyp.yaml,它会覆盖你传入的配置,所以对比实验时要把每次的hyp.yaml单独保存,否则后跑的实验会覆盖之前的记录。
4.4 训练日志怎么看
先看results.csv里的三列趋势:train/box_loss、val/box_loss和metrics/mAP_0.5。正常的训练曲线是 train loss 持续下降、val loss 在某个 epoch 后进入平台期,mAP 缓慢上升。如果你的 val loss 从第 30 个 epoch 开始反弹,说明过拟合,需要加--weight_decay 0.0005或者更早地降低学习率;如果你的 mAP 前 10 个 epoch 都是 0,先检查标签文件中的类别 id 是否与 yaml 的names顺序匹配,再检查--img是否太大导致大量小目标在缩放后丢失——把--img 640跑 5 个 epoch 看一眼 baseline,比在 1280 下反复调参更高效。
从 YOLOv5 换到 YOLOv7 时注意一点:v7 的--img参数必须能被 64 整除,否则网络前向会报尺寸错误。YOLOv8 则没有这个限制,且它的--batch默认 -1 表示自动寻找最佳 batch size,无人机场景下它的表现略优于 v5,但推理速度比 v5 慢约 20%,做嵌入式部署选 v5s 更合适。
5. TTA 与切片推理组合拳,把俯视小目标召回率拉满
5.1 用 SAHI 做切片式推理
即使训练时用了 1280 分辨率,模型在推理时对整张大图的直接预测仍然可能漏掉极端小目标。这里的技巧是使用 SAHI(Slicing Aided Hyper Inference)库,把大图切成带重叠的 patch,每个 patch 独立推理后再做 NMS 合并。
from sahi.model import Yolov5DetectionModel from sahi.predict import get_sliced_prediction model = Yolov5DetectionModel( model_path="runs/uav/car_person_v2/weights/best.pt", confidence_threshold=0.25, device="cuda:0", ) result = get_sliced_prediction( "drone_frame_1024.jpg", model, slice_height=640, slice_width=640, overlap_height_ratio=0.2, overlap_width_ratio=0.2, )slice_height和slice_width设为 640,是因为模型在 640 输入下的小目标检测能力最稳定;overlap_height_ratio设为 0.2,是让相邻切片有 128 像素的重叠,避免目标正好被切片边界切开。切完后的检测框坐标会被自动映射回原图坐标,不需要手动换算。实际效果上,SAHI 对 20×30 像素级别的目标,mAP 能提升 8% 左右,代价是推理时间变成原来的 4~5 倍。
5.2 阈值调整与 TTA 的取舍
先跑一次验证集得到精确率和召回率的平衡点,再决定推理阈值。对小目标场景,我通常把confidence_threshold从 0.25 降到 0.15,同时把 NMS 的iou_threshold从 0.45 提升到 0.6,因为小目标框重叠面积大,默认阈值容易把一组正确的检测框合并成一次误检。YOLOv5 的 TTA 是对输入做 3 种缩放加水平翻转共 6 次推理后取平均,对小目标有稳定的提升作用,但推理时间翻 6 倍且不适合视频流的逐帧处理,离线分析推荐开,实时推理不推荐。
最后验证模型泛化能力时,别只看 mAP,还要检查runs/uav/car_person_v2/val_batch0_pred.jpg里的可视化——重点看中等密度区域的漏检情况和密集停车场的重复检测框。如果重复框过多,把 NMS 的 iou 阈值往下调;如果远处目标整体漏检,说明训练分辨率还不够,用 1536 分辨率重训一轮对比 mAP 曲线,这是最直接的收敛信号。
本文还有配套的精品资源,点击获取