简介:这份资源是面向无人机俯视视角目标检测任务的YOLO格式数据集,适合从事车辆与行人检测的算法工程师、研究生及竞赛选手使用,可直接用于yolov5、yolov7、yolov8等主流框架的模型训练与验证。压缩包共2000个文件,包含1648个txt标注文件、351张jpg图像和1个yaml配置文件,整体约850.13MB,标注与图像一一对应,覆盖car与person两个类别。数据集已按train、valid、test完成划分,并附带data.yaml,其中names为['car','person'],各子集路径指向对应images目录,开箱即可接入训练流程,省去自行清洗与划分的繁琐工作。目前已有1681人学习下载,说明其在无人机视觉场景中具备一定参考价值。借助该数据集,读者可快速复现俯视视角下的车辆与行人检测实验,对比不同YOLO版本的精度与速度表现,并在此基础上调整anchor、数据增强策略或迁移至自有航拍数据,是入门与进阶无人机目标检测的实用素材。
1. 无人机俯拍下的车辆与行人检测:为什么通用数据集一上机就翻车
把 YOLOv5 直接套到无人机俯视场景,十有八九第一轮验证就会给你泼冷水。地面监控数据集里行人占几十个像素、车辆横平竖直,而无人机在 50 到 120 米高度俯拍时,车辆变成巴掌大的矩形块,行人只剩一个头顶加肩膀的椭圆点,尺度、视角、遮挡关系全变了。vis-drone-yolov5-dataset-1.zip 这类数据集要解决的就是这个错位:它把俯视视角下的车辆和行人单独标注出来,让 YOLOv5 在无人机航拍域里重新收敛。这篇笔记面向已经跑通过 YOLOv5 官方 COCO 流程、准备把模型搬到无人机视觉感知链路上的工程师,从数据集结构、标签格式转换、训练参数到部署量化,把能复现的步骤和踩过的坑一次讲清。如果你正在做无人机航拍工地巡检、交通流量统计或者移动小目标检测,这套流程可以直接照搬。
2. 拆开 vis-drone-yolov5-dataset-1.zip:目录结构、标签格式与类别定义
拿到一个无人机俯视数据集,先别急着写训练脚本。我一般会花二十分钟把压缩包解干净,用tree和几行 Python 把目录、图片尺寸、标签分布摸一遍。这一步决定了后面要不要做格式转换、要不要重设 anchor、要不要按高度分层采样。vis-drone-yolov5-dataset-1.zip 从命名看是面向 YOLOv5 的无人机视觉数据集,常见组织方式是 images/labels 双目录加 data.yaml,但不同来源的包差异很大,必须实测确认。
2.1 解压后先跑一遍目录体检
# 解压到独立目录,避免污染其他数据集 mkdir -p ~/datasets/vis_drone && cd ~/datasets/vis_drone unzip ~/downloads/vis-drone-yolov5-dataset-1.zip -d . # 看顶层结构,确认是 images/labels 还是 train/val 分目录 find . -maxdepth 2 -type d | sort # 统计图片数量与格式 find . -type f \( -name "*.jpg" -o -name "*.png" -o -name "*.jpeg" \) | wc -l find . -type f -name "*.jpg" | head -5这段命令做三件事:确认解压后的目录层级、统计图片总量、抽样看文件命名规律。如果输出里出现images/train、images/val、labels/train、labels/val四组目录,说明数据集已经按 YOLOv5 标准切分好;如果只有扁平的images和labels,就需要自己写切分脚本。图片格式优先看是不是 jpg,png 会拖慢 dataloader,必要时批量转 jpg。
2.2 用 Python 核对标签与类别
import os, glob from collections import Counter root = os.path.expanduser("~/datasets/vis_drone") label_files = glob.glob(os.path.join(root, "**", "*.txt"), recursive=True) # 过滤掉 data.yaml 之类的非标签文件,YOLO 标签每行至少 5 列 label_files = [f for f in label_files if os.path.basename(f) != "data.yaml"] cls_counter = Counter() box_areas = [] for lf in label_files: with open(lf) as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue c, x, y, w, h = int(parts[0]), *map(float, parts[1:]) cls_counter[c] += 1 box_areas.append(w * h) # 归一化面积,用于判断小目标占比 print("类别分布:", dict(cls_counter)) print("标签文件数:", len(label_files)) print("目标框总数:", sum(cls_counter.values())) print("平均归一化面积:", sum(box_areas) / len(box_areas)) print("面积小于 0.001 的框占比:", sum(1 for a in box_areas if a < 0.001) / len(box_areas))逻辑说明:YOLO 标签每行是class x_center y_center width height,全部归一化到 0 到 1。cls_counter告诉你类别是否平衡,无人机数据集常见问题是行人样本远少于车辆。box_areas用来量化小目标比例,归一化面积小于 0.001 基本就是俯拍小目标,后面 anchor 和输入分辨率都要围绕它调。参数上,如果类别只有 0 和 1,data.yaml 里nc: 2,names: ['vehicle', 'pedestrian']顺序必须和标签里的 class id 严格对应,错一位整个训练就废了。
2.3 data.yaml 与类别映射的确认
# data.yaml 常见写法,路径按实际解压位置改 path: /home/user/datasets/vis_drone train: images/train val: images/val nc: 2 names: ['vehicle', 'pedestrian']如果压缩包里没有 data.yaml,就按上面模板自己建。path用绝对路径最稳,相对路径在 YOLOv5 不同版本里解析基准不一致,容易翻车。names的顺序不是随便写的,它对应标签文件里的 class id,0 对应列表第一个。改完用python -c "import yaml; print(yaml.safe_load(open('data.yaml')))"验证一遍语法,YAML 缩进错一格就会静默读成 None。
3. 用 YOLOv5 在本地跑通无人机数据集的最小训练命令
数据集体检完,下一步是让训练真正跑起来。YOLOv5 的仓库结构、依赖安装网上资料很多,这里只讲和无人机俯视数据强相关的部分:输入分辨率、anchor 重聚类、batch 与显存的关系。很多人直接拿默认--img 640开跑,结果小目标召回率惨不忍睹,问题就出在分辨率没跟着目标尺度走。
3.1 环境与依赖的快速确认
git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt # 验证 torch 和 cuda 是否可用 python -c "import torch; print(torch.__version__, torch.cuda.is_available())"这段是标准起手式。torch.cuda.is_available()返回 False 时先别怀疑代码,检查显卡驱动和 CUDA 版本匹配。YOLOv5 对 torch 版本比较宽容,但 2.x 和 1.x 在部分算子上有差异,团队协作时把版本写进 requirements 锁死。无人机数据集图片分辨率通常较高,dataloader 的--workers建议设成 CPU 核数的 0.7 倍左右,设太高反而因为 IO 争抢变慢。
3.2 针对俯视小目标重聚类 anchor
# 用训练集标签重新聚类 anchor,k 设为 9 对应 3 个尺度各 3 个 anchor python utils/autanchor.py --data data.yaml --img-size 960 --thr 4.0 --n 9逻辑说明:autanchor.py会读取 data.yaml 指向的训练标签,用 k-means 聚出 9 组宽高。无人机俯拍目标普遍偏小且长宽比接近 1:1,默认 COCO anchor 偏大,直接套用会导致正样本匹配过少。--img-size要和后面训练用的分辨率一致,--thr是 anchor 与目标框的宽高比阈值,俯视场景建议放宽到 4.0。跑完把输出的 anchor 写进模型配置文件,或者训练时用--anchors指定。参数改完记得重新生成一次,别用缓存。
3.3 最小可跑训练命令与参数解释
python train.py \ --data data.yaml \ --weights yolov5s.pt \ --img 960 \ --batch 16 \ --epochs 100 \ --hyp data/hyps/hyp.scratch-low.yaml \ --workers 8 \ --project runs/drone \ --name exp1逐参数说明:--img 960是俯视小目标的关键,640 下行人可能只剩 8 像素,960 能保留更多细节,代价是显存翻倍,batch 要相应下调。--batch 16是 8G 显存跑 960 分辨率的保守值,显存够可以上 24 或 32。--hyp选 low 增强版本,无人机俯拍本身视角变化有限,过强的 mosaic 和 mixup 反而引入不真实样本,low 版本更稳。--weights yolov5s.pt用预训练权重加速收敛,如果类别和 COCO 差异极大也可以从 scratch 开始,但收敛慢很多。训练启动后盯前 10 个 epoch 的mAP@0.5和box_loss,如果 loss 不降,先查标签路径和类别映射,而不是调学习率。
4. 无人机俯视检测的避坑与排查:五条血泪记录
这一章全是踩过的坑,每条按现象、原因、解决写。无人机数据集和通用数据集最大的区别在于视角和尺度,很多在 COCO 上不是问题的地方,在这里会集中爆发。
4.1 现象:mAP 卡在 0.1 不动,loss 缓慢下降
原因:标签类别顺序和 data.yaml 的 names 不一致,或者图片和标签文件名没对上。YOLOv5 对缺失标签的图片会当负样本处理,如果一半图片找不到标签,模型学到的全是背景。解决:写脚本核对 images 和 labels 的文件名 stem 是否一一对应,用diff <(ls images/train | sed 's/\..*//' | sort) <(ls labels/train | sed 's/\..*//' | sort)快速定位。类别顺序用 2.2 的脚本打印确认。
4.2 现象:验证集 mAP 正常,实际无人机视频推理全是漏检
原因:训练集和验证集来自同一批航拍片段,分布太接近,模型没学到跨高度、跨光照的泛化能力。解决:按飞行高度或光照条件分层切分数据集,而不是随机切。如果数据集本身没标注高度,用图片的 EXIF 或文件名里的高度信息分组,保证验证集包含训练时没见过的飞行高度。这一步在数据准备阶段做,训练开始后就来不及了。
4.3 现象:训练到 50 epoch 后显存溢出
原因:YOLOv5 的 dataloader 在长训练中会累积缓存,加上无人机图片分辨率高,显存碎片化。解决:把--workers降到 4,加--noval每隔几个 epoch 再验证,或者用torch.cuda.empty_cache()在自定义回调里定期清理。更彻底的办法是降低--img到 800,配合更小的 anchor,精度损失有限但显存稳定。
4.4 现象:小目标召回率极低,大目标正常
原因:anchor 没重聚类,默认 anchor 匹配不到小目标;或者--img太小,小目标在下采样后信息丢失。解决:按 3.2 重聚类 anchor,把--img提到 960 或 1280。如果显存不够,用--rect矩形训练减少 padding,或者把模型换成 yolov5m 增加容量。注意提高分辨率后要同步调大--batch的梯度累积步数,保持等效 batch size。
4.5 现象:推理速度在边缘设备上只有个位数 FPS
原因:直接用 PyTorch 权重在 Jetson 或 RK3568 上跑,没做量化和图优化。解决:先导出 ONNX,再用 TensorRT 或 RKNN 工具链量化。YOLOv5 官方export.py支持--include onnx,导出时--img和--batch要和部署一致。量化后 mAP 通常掉 1 到 3 个点,用验证集重新测一遍,掉太多就改用 FP16 而不是 INT8。
5. 从训练到部署:量化、验证与一个提点技巧
训练收敛只是上半场,无人机视觉感知的落地瓶颈在边缘端推理。这一章讲怎么把 vis-drone-yolov5-dataset-1.zip 训出来的模型压到能上机的程度,以及一个我常用的验证技巧。
5.1 导出 ONNX 与量化验证
# 导出 ONNX,opset 12 兼容性最好 python export.py --weights runs/drone/exp1/weights/best.pt --include onnx --img 960 --batch 1 --opset 12 # 用 onnxruntime 验证导出模型和原模型输出一致性 python -c " import onnxruntime as ort, numpy as np sess = ort.InferenceSession('best.onnx') x = np.random.randn(1, 3, 960, 960).astype(np.float32) out = sess.run(None, {sess.get_inputs()[0].name: x}) print('输出形状:', [o.shape for o in out]) "逻辑说明:--opset 12是 TensorRT 和 RKNN 都支持的版本,opset 太高部分工具链不认。--batch 1是边缘部署的常见 batch,导出时 batch 维度固定,后面改起来麻烦。onnxruntime 验证这一步别省,导出过程可能因为自定义算子静默出错,输出形状对不上就说明导出有问题。参数上,如果部署平台支持动态 batch,导出时用--dynamic,但会牺牲部分推理速度。
5.2 用视频抽帧做端到端验证
import cv2, torch model = torch.hub.load('ultralytics/yolov5', 'custom', path='runs/drone/exp1/weights/best.pt') model.conf = 0.35 # 俯视小目标置信度阈值适当降低 model.iou = 0.45 cap = cv2.VideoCapture('drone_flight.mp4') frame_id = 0 while cap.isOpened(): ret, frame = cap.read() if not ret: break if frame_id % 10 == 0: # 每 10 帧抽一帧,降低验证成本 results = model(frame) results.save(save_dir='runs/verify') frame_id += 1 cap.release()这段脚本把训练好的模型直接套到无人机视频上,conf设 0.35 是因为俯视小目标得分普遍偏低,设 0.5 会漏掉大量行人。iou0.45 是 NMS 阈值,俯拍车辆密集时适当调低能减少漏检。每 10 帧抽一帧是为了快速看整体效果,正式验证要逐帧跑并统计。验证时重点看三类失败:小目标漏检、密集场景粘连、运动模糊导致的误检。
5.3 一个提点技巧:按目标尺度分层评估
我习惯在验证阶段把目标按归一化面积分成小、中、大三档,分别统计 mAP。YOLOv5 默认只给整体 mAP,俯视场景里小目标才是关键,整体 mAP 会被大目标拉高,掩盖小目标的糟糕表现。做法是在验证脚本里加一个按面积分桶的统计,面积小于 0.001 算小目标,0.001 到 0.01 算中,大于 0.01 算大。如果小目标 mAP 比整体低 20 个点以上,说明分辨率或 anchor 还有优化空间。这个习惯帮我省了很多次盲目调参的时间,也让我在交付前能明确告诉团队模型的能力边界。希望帮到你。
本文还有配套的精品资源,点击获取