简介这份资源是面向深度学习目标检测方向的无人机识别数据集适合正在做无人机检测项目、课程设计或算法对比实验的研究者与开发者使用。数据集同时提供YOLO与VOC两种标注格式可无缝接入YOLOv5至YOLOv10等YOLO系列算法也能用于Faster R-CNN、SSD等模型的训练与验证帮助使用者省去自行采集与标注的成本。压缩包内共2000个文件以1999个txt标签文件和1个yaml类别配置文件为主txt对应每张图片的目标框标注yaml则指定类别信息与数据路径整体约814.16MB图片与标签已按训练集、验证集、测试集划分完毕开箱即可投入训练。目前已有340人学习下载配套博文对数据集细节做了进一步说明便于快速了解类别分布与使用方式适合作为无人机识别任务的基线数据或算法性能对比的统一评测集。1. 无人机识别数据集9229 张图、双格式标签拿到手就能开训做低空目标检测的同行大概都有过这种体验模型结构调了一周学习率换了三套mAP 死活上不去最后发现是数据集里一半的框标歪了。无人机识别这个方向尤其明显——目标小、背景杂、天上飞的鸟和四旋翼在低分辨率下几乎一个样标注质量直接决定模型上限。这次拆的是一份无人机识别目标检测数据集9229 张图同时给了 YOLO 的 txt 标签和 VOC 的 xml 标签还附带指定类别信息的 yaml 文件图片和标签已经按训练集、验证集、测试集切好。换句话说YOLOv5 到 YOLOv10 这一串算法改个 data 路径就能直接跑不用自己再写划分脚本。适合两类人一类是想快速验证检测 pipeline 的工程同学另一类是做鸟类目标检测、移动小目标检测、遥感目标检测需要一份干净基线数据来对比实验的。下面按「这份数据长什么样 → 怎么接进 YOLO → 怎么接进 VOC 系 → 坑在哪 → 怎么验证训得对不对」的顺序拆开讲。2. 数据集结构与格式解析txt、xml、yaml 三件套怎么配合2.1 目录组织与文件命名规律从项目正文给出的文件名看标签文件是Drone_1.txt、Drone_4235.txt、Drone_3936.txt这种「类别前缀 数字编号」的形式编号不连续说明它是从原始大池子里抽出来、重命名过的。这种命名方式有个好处图片和标签靠同名对应Drone_4235.jpg配Drone_4235.txt不用维护额外的映射表。常见做法是把数据整理成下面这种结构YOLO 系和 VOC 系都能兼容drone_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── annotations/ # VOC 格式 xml │ ├── train/ │ ├── val/ │ └── test/ └── drone.yaml这里要注意一点YOLO 的 txt 和 VOC 的 xml 是两套坐标系。txt 是归一化的class cx cy w h值都在 0~1 之间xml 是绝对像素的xmin ymin xmax ymax。同一张图两种标签必须指向同一个目标框否则你拿 txt 训完再用 xml 评估数字对不上还以为是模型问题。我一般会抽 5~10 张图把两种标签都画出来叠在原图上肉眼比对确认框位置一致再往下走。2.2 YOLO txt 标签格式与类别映射YOLO 格式每行五个字段第一个是类别索引后四个是归一化坐标。假设这份数据只有「无人机」一个类那类别索引就是 0。用 Python 快速校验一遍标签合法性的脚本如下import os import glob # 标签目录按你的实际路径改 label_dir drone_dataset/labels/train img_dir drone_dataset/images/train bad_files [] for txt_path in glob.glob(os.path.join(label_dir, *.txt)): stem os.path.splitext(os.path.basename(txt_path))[0] # 1. 检查是否有同名图片 img_exists any( os.path.exists(os.path.join(img_dir, stem ext)) for ext in [.jpg, .jpeg, .png] ) if not img_exists: bad_files.append((txt_path, no matching image)) continue # 2. 检查每行字段数与数值范围 with open(txt_path) as f: for line_no, line in enumerate(f, 1): parts line.strip().split() if len(parts) ! 5: bad_files.append((txt_path, fline {line_no} field count {len(parts)})) continue cls, cx, cy, w, h parts vals list(map(float, [cx, cy, w, h])) if any(v 0 or v 1 for v in vals): bad_files.append((txt_path, fline {line_no} out of range {vals})) if float(w) 0 or float(h) 0: bad_files.append((txt_path, fline {line_no} zero size)) print(fchecked, bad count {len(bad_files)}) for item in bad_files[:20]: print(item)逻辑说明先做「图片-标签」配对检查再逐行验证字段数和归一化范围。参数上label_dir和img_dir要指向同一划分train 对 train别交叉。w或h为 0 的框是典型的标注事故训练时会被算成负样本直接拖低召回。跑完如果bad count不为 0先修数据再谈调参这是血泪经验。2.3 yaml 配置文件与 VOC xml 的用途yaml 文件是 YOLO 系训练的入口通常长这样path: ./drone_dataset train: images/train val: images/val test: images/test nc: 1 names: 0: dronenc是类别数names是索引到类名的映射必须和 txt 里的类别索引严格对应。如果这份数据实际有多个类比如无人机和鸟nc和names要同步改漏一个就会出现「训练不报错但类别全错」的玄学现象。VOC 的 xml 则主要给 Faster R-CNN、SSD 这类框架用每个 xml 里包含filename、size、若干object含name和bndbox。用 xml 之前建议先统计一下所有name取值确认没有拼写不一致drone/Drone/UAV混用是常见坑。3. 接入 YOLOv5~YOLOv10从环境到首轮训练3.1 环境配置与依赖版本YOLO 系现在主流走 Ultralytics 这一套环境配置本身不复杂坑主要在版本匹配。常见做法是建独立虚拟环境Python 3.9~3.11 都行torch 按显卡 CUDA 版本装。下面是一套通用流程# 1. 建环境 conda create -n drone_yolo python3.10 -y conda activate drone_yolo # 2. 装 torch按你的 CUDA 版本选这里以 cu118 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 3. 装 ultralytics pip install ultralytics # 4. 验证 yolo checksyolo checks会打印 torch、CUDA、设备信息确认 GPU 被识别到再往下。如果这里显示 CPU后面训练会慢到怀疑人生。参数上--index-url里的 cu118 要换成你驱动支持的版本装错了会出现「import torch 成功但 cuda.is_available() 为 False」。3.2 用命令行启动首轮训练数据按第 2 章的目录摆好、yaml 改好之后一条命令就能起训yolo detect train \ datadrone_dataset/drone.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ projectruns/drone \ namebaseline逐项说明data指向 yamlmodel用预训练权重小目标场景建议从yolov8s起步n太小吃不饱imgsz640是常规值无人机目标偏小的话可以试 960 或 1280但显存要跟上batch16按显存调爆显存就减半project和name决定结果落盘位置。首轮训练的目的不是刷高指标而是确认整条链路通——loss 在降、验证集能出框、runs/drone/baseline/weights/best.pt能生成这三件事齐了再谈调优。3.3 用 Python API 做自定义评估命令行跑通后评估和推理建议用 Python API方便接自己的后处理from ultralytics import YOLO # 加载训练好的权重 model YOLO(runs/drone/baseline/weights/best.pt) # 在测试集上评估 metrics model.val(datadrone_dataset/drone.yaml, splittest) print(mAP50:, metrics.box.map50) print(mAP50-95:, metrics.box.map) # 单图推理并保存可视化 results model.predict(drone_dataset/images/test/Drone_4235.jpg, conf0.25, saveTrue) for r in results: print(boxes:, r.boxes.xyxy.shape[0])逻辑说明val的splittest确保用的是测试集而不是验证集很多人默认跑 val 然后拿这个数字当最终指标属于自欺欺人。conf0.25是推理置信度阈值评估阶段用默认即可部署时再按业务调。r.boxes.xyxy.shape[0]能快速看单图检出数量配合saveTrue出的可视化图肉眼判断漏检和误检。3.4 接入 Faster R-CNN / SSD 的 VOC 路径如果要用 xml 训 Faster R-CNN 或 SSD主流做法是转成 COCO 或直接读 VOC。以 torchvision 的 Faster R-CNN 为例需要自己写 Dataset 读 xmlimport os import torch import xml.etree.ElementTree as ET from PIL import Image from torch.utils.data import Dataset class DroneVOCDataset(Dataset): def __init__(self, img_dir, ann_dir, transformsNone): self.img_dir img_dir self.ann_dir ann_dir self.transforms transforms self.ids [os.path.splitext(f)[0] for f in os.listdir(ann_dir) if f.endswith(.xml)] def __getitem__(self, idx): stem self.ids[idx] img Image.open(os.path.join(self.img_dir, stem .jpg)).convert(RGB) tree ET.parse(os.path.join(self.ann_dir, stem .xml)) boxes, labels [], [] for obj in tree.findall(object): # 类别名到索引的映射按你的 names 改 labels.append(0) bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) boxes.append([xmin, ymin, xmax, ymax]) target { boxes: torch.tensor(boxes, dtypetorch.float32), labels: torch.tensor(labels, dtypetorch.int64), } if self.transforms: img self.transforms(img) return img, target def __len__(self): return len(self.ids)逻辑说明ids从 xml 文件名反推保证图片和标注配对labels这里硬编码为 0多类场景要按name查表。注意 torchvision 检测模型要求 boxes 是[xmin, ymin, xmax, ymax]绝对坐标和 VOC 一致所以不用像 YOLO 那样归一化。参数上transforms里别加随机裁剪小目标被裁掉就没了。4. 避坑与排查标注、划分、训练三类高频翻车4.1 图片与标签数量对不上现象训练启动时报No labels found或某张图被跳过。原因图片和标签文件名不一致或者扩展名大小写不同.JPGvs.jpg。解决跑第 2.2 节的校验脚本把bad_files里的配对问题逐个修掉批量重命名时统一转小写。4.2 训练集和验证集出现同一目标现象验证集 mAP 高得离谱换测试集直接掉十几个点。原因划分时按图片随机切但同一段视频抽帧的相似图被分到了 train 和 val等于变相泄漏。解决如果数据来自视频按视频源或时间戳划分而不是按帧随机已经切好的这份数据建议抽查 val 和 train 里有没有视觉上几乎一样的图。4.3 类别索引与 names 错位现象训练不报错但推理时框的位置对、类别名全错。原因txt 里类别索引是 1yaml 里names从 0 开始或者多类数据里索引顺序和 names 不一致。解决统计所有 txt 第一列的唯一值和 yaml 的names键逐一对照数量对不上就改 yaml。4.4 小目标在 640 分辨率下消失现象大无人机能检出远处小点全漏。原因下采样后小目标特征被吞掉。解决把imgsz提到 960 或 1280或改用带 P2 检测头的模型配置同时检查标注里有没有大量宽高小于 8 像素的框这种框在 640 下基本学不到。4.5 显存爆掉但 batch 已经很小现象batch4还 OOM。原因imgsz太大或 dataloader 的workers开太多导致内存涨。解决先降imgsz再降workers最后才动batch用nvidia-smi实时看显存占用别凭感觉调。5. 验证与进阶怎么确认这份数据真的训得动训完一轮别只看终端最后那行 mAP。我一般会走一套固定验证流程确认模型和数据都正常。第一步看训练曲线runs/drone/baseline/results.png里 box_loss、cls_loss、mAP50 三条线正常情况 loss 单调下降、mAP 单调上升如果 loss 震荡剧烈多半是学习率或 batch 问题。第二步跑混淆矩阵confusion_matrix.png能看出有没有把背景误判成目标无人机场景里云、鸟、建筑边缘是主要干扰源。第三步抽测试集里最难的一批图——目标最小、背景最杂的那些——单独推理看漏检集中在什么尺度。进阶用法上这份数据同时有 txt 和 xml很适合做格式转换的对照实验。比如把 xml 转成 YOLO txt和自带的 txt 比对能验证转换脚本的正确性import xml.etree.ElementTree as ET from PIL import Image def voc_to_yolo(xml_path, img_path, class_map): tree ET.parse(xml_path) root tree.getroot() w int(root.find(size/width).text) h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text cls class_map[name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 转成归一化中心点 宽高 cx (xmin xmax) / 2 / w cy (ymin ymax) / 2 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) return \n.join(lines) # 用法class_map 按你的 names 建 cmap {drone: 0} print(voc_to_yolo(annotations/train/Drone_1.xml, images/train/Drone_1.jpg, cmap))逻辑说明VOC 的绝对坐标除以图宽高得到归一化值中心点用(xminxmax)/2算。参数上class_map必须和 yaml 的names一致否则类别索引错位。转换完拿几张图和自带 txt 对比数值对得上说明两套标签同源对不上就要查是哪边标错了。另一个值得做的验证是跨模型一致性同一份数据YOLOv8 和 Faster R-CNN 各训一版如果两者 mAP 差距在合理范围内通常 3~8 个点说明数据本身没有系统性偏差如果差出 20 个点大概率是某一套标签格式没接对。这套交叉验证我踩过坑之后就一直保留比单看一个模型的数字靠谱得多。从那以后我每次拿到新数据集都强制先跑一遍配对校验和标签范围检查再抽图可视化比对最后才开训。这三步花不了半小时能省掉后面几天的无效调参。希望帮到你。本文还有配套的精品资源点击获取