简介一套面向飞机目标检测的数据集适合目标检测算法研究者和计算机视觉初学者直接用于训练与验证。数据采用Pascal VOC与YOLO两种主流标注格式标注类别只有airplane非常适合开展单类别目标检测实验、模型精度对比以及参数调优。无论是高校课程设计、科研实验还是工业视觉中的飞机目标识别都能把这类标准标注数据作为训练基础。压缩包文件总数为两千个其中以XML标注文件为主体附加一个说明文本文件包体大小约一百零七点三七兆据资源描述数据集包含七千九百三十余张飞机图片的标注信息airplane类别累计标注框数为两万三千五百六十八个标注工具采用LabelImg标注规则为对目标画矩形框。目前已有两百零一人学习下载适合需要扩充飞机目标样本、快速搭建目标检测训练流程的开发者。下载后可直接获得VOC格式的XML文件与YOLO格式的TXT文件配合对应图片即可接入主流检测框架省去手工格式转换和标注类别统计随包说明文本可帮助理解标注规则与数据组织方式提升数据集使用效率也适合作为飞机目标检测入门和基准实验的材料。1. 为什么是这 7930 张飞机图目标检测数据集的门道先在“格式”上做目标检测最怕的不是模型训练不出来而是数据集拿到手先卡在“格式不对”。这份标题里的“7930张VOCYOLO格式.zip”一眼就是冲着解决这个痛点来的7930 张已标注的飞机图片同时给你 VOC 和 YOLO 两套标注——不用再拿着 LabelImg 一张张画框也不用写脚本在 XML 和 txt 之间来回折腾格式转换。对正在练手 YOLO 系列、或者想快速验收一个检测流程的人来说这是一份能直接喂进训练脚本的数据集省掉的是目标检测里最脏最累的“数据准备”阶段。但“能直接用”不代表没有坑。VOC 和 YOLO 的标注虽然描述同一批框坐标体系、类别编号、文件组织方式完全不同直接混用会翻车。这篇文章就沿着“数据集是什么 → 怎么落地跑通 → 坑在哪 → 参数怎么调 → 还能怎么进阶”这条线把这 7930 张飞机的用法讲透。2. 先分清 VOC 与 YOLO同 7930 张图两套完全不同的坐标系2.1 目录结构的“双轨制”是怎么组织的拿到 zip 压缩包解压后你会看到典型的双目录结构。VOC 风格的组织方式脱胎于 PASCAL VOC 挑战赛目录固定为Annotations存放 XML 标注、JPEGImages存放原始图片、ImageSets/Main存放划分好的 train/val/test 文本列表YOLO 风格则是图片目录与labels目录平级txt 标注文件与图片同名同路径前缀。常见做法是压缩包内部把这俩都保留形成类似下面的结构aircraft_dataset/ ├── VOC/ │ ├── Annotations/ │ │ ├── 000001.xml │ │ ├── 000002.xml │ │ └── ... │ ├── JPEGImages/ │ │ ├── 000001.jpg │ │ ├── 000002.jpg │ │ └── ... │ └── ImageSets/ │ └── Main/ │ ├── train.txt │ ├── val.txt │ └── test.txt └── YOLO/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/VOC 目录里的ImageSets/Main是容易被忽略的部分。很多新手以为 VOC 格式只要有 XML 就够了实际上训练脚本比如老版 YOLOv3、YOLOv5 的 VOC 支持脚本是从train.txt这类列表文件里读取参与训练的样本名而不是扫描整个Annotations目录。如果压缩包里没有这个目录你仍然需要自己生成——但大多数发行版都会放好毕竟train.txt就一行一个不带后缀的文件名生成成本极低。YOLO 目录的images与labels必须严格同名对应。训练时脚本根据图片路径去找同名 txt找不到就是空标签找错就是标注错位。这里只是提个醒后面避坑章节会细说。2.2 标注内容的本质差异绝对坐标 vs 归一化坐标VOC 的 XML 标注记录的是目标的绝对像素坐标一个bndbox里有xmin、ymin、xmax、ymax四个整数值直接对应图片上的像素位置。解析这种 XML 不需要做任何数学变换但麻烦之处在于标注里还有difficult、truncated、pose这类附加属性转换格式时如果不管这些字段某些按 VOC 规则统计 mAP 的脚本会计算出不同结果。YOLO 的 txt 标注则是完全不同的逻辑。每一行代表一个目标五个值依次是class_id、x_center、y_center、width、height后四个值全部除以图片宽高做归一化落点在 0 到 1 之间。这套设计的直接好处是训练时不管输入图片被 resize 成 640 还是 1280标注都不需要重新计算。代价是肉眼不可读你打开某个 txt 看到的是一串小数无法直接判断有没有标错。一个典型的 XML 里某个飞机的标注可能是xmin120, ymin80, xmax350, ymax240对应到 YOLO txt 里如果是 640x480 的图就变成0 0.3671875 0.3333333 0.359375 0.3333333。做转换脚本时最容易犯的错是把归一化坐标当像素坐标直接交差训练出来的模型 loss 大得离谱检测框乱飞。2.3 两种格式的适用场景与选型理由VOC 格式的好处是通用且历史悠久。Faster R-CNN、SSD、老版 Detectron 等框架的官方数据加载器都保留了 VOC 解析接口甚至到今天torchvision.datasets.VOCDetection还能直接读。做数据对比实验、复现论文里的 benchmarkVOC 是无脑选择。YOLO 格式则是为 YOLO 系列训练定制的Ultralytics YOLO 家族v5/v8/v11原生只认这种 txt 归一化格式。你如果拿 VOC XML 去喂给 YOLOv8 的训练脚本脚本不会直接报错但你需要自己写 XML 解析器或者先转成 txt。标题里同时给两种格式的意义就在这里你用老框架做验证时走 VOC上 YOLO 训练时直接用现成 txt省去写转换脚本这步。需要留意的是“VOC 格式”与“VOC 数据集类别体系”不是一回事。这份飞机数据集里的类别很可能只有airplane一类而经典 VOC 数据集有 20 类。转换到 YOLO 后类别 ID 是 0打开标注文件你看到的行首数字永远是 0这是正常的。后面训练时配置data.yaml里的nc: 1和names: [airplane]即可不需要管 VOC 那套 20 类的类别索引表。3. 跑通全流程解压、核对、配置、训练一次到位3.1 Linux 下解压 zip 的正确姿势这份数据集以 zip 包分发压缩包名里有空格和中文括号终端操作时必须给文件名加引号或是用 Tab 补全否则命令行会把空格当分隔符拆出多个参数。Windows 下直接右键“全部解压缩”最省事Linux 服务器上我一般这么做cd /data/aircraft_dataset/ unzip 【目标检测数据集】飞机数据集7930张VOCYOLO格式.zip -d aircraft_dataset/解压完成后不要急着看图片先看一眼解压后根目录文件数和大小是否与压缩包内信息一致。用du -sh看总大小用find统计文件数du -sh aircraft_dataset/ find aircraft_dataset/ -name *.jpg | wc -l find aircraft_dataset/ -name *.xml | wc -l find aircraft_dataset/ -name *.txt | wc -l如果 jpg 数量是 7930XML 数量应该也是 7930YOLO 目录下的 txt 数量同样对应。对不上就直接说明压缩包不完整或解压出错别在缺文件的数据集上开始训练。zip 包传输过程损坏很常见遇到数量对不上时优先重新下载并校验。提示unzip默认遇到重名文件会交互式询问是否覆盖脚本自动化时加-o覆盖加-q安静模式避免大量输出刷屏。3.2 先看数据长什么样可视化检查标注质量任何数据集到手先花十分钟看图与标注这个时间省不得。常见做法是写一个快速可视化脚本把 VOC 的 XML 框画回图片上确认框的位置准确、没有大面积偏移和类别错标。下列代码读取 XML 并在原图画框import cv2 import xml.etree.ElementTree as ET def draw_voc_boxes(image_path, xml_path): img cv2.imread(image_path) tree ET.parse(xml_path) root tree.getroot() for obj in root.findall(object): name obj.find(name).text bndbox obj.find(bndbox) xmin int(bndbox.find(xmin).text) ymin int(bndbox.find(ymin).text) xmax int(bndbox.find(xmax).text) ymax int(bndbox.find(ymax).text) cv2.rectangle(img, (xmin, ymin), (xmax, ymax), (0, 255, 0), 2) cv2.putText(img, name, (xmin, ymin - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 1) return img img_with_boxes draw_voc_boxes( aircraft_dataset/VOC/JPEGImages/000001.jpg, aircraft_dataset/VOC/Annotations/000001.xml, ) cv2.imwrite(check_000001.jpg, img_with_boxes)这段代码的逻辑很直白解析 XML 里的bndbox坐标用 OpenCV 把矩形画到图上。你可以改成一个循环随机抽 30 到 50 张图批量生成可视化结果再整体浏览一遍重点关注三类异常框比飞机大很多背景被包进来了、框只框住飞机的一部分、框明显偏移到背景上。这些异常如果不处理就直接训练模型学到的框会偏大或偏小。抽查还有助于核对类别名的写法。如果 XML 里类别是airplane但数据说明文档里写的是plane说明数据源可能混入了不一致的标注需要统一。直到这一步确认没问题再继续往下配置训练。3.3 用现成 YOLO 目录直接训练data.yaml 是关键如果压缩包的 YOLO 目录已经划分好了 train/val/test你的工作会轻松很多。Ultralytics YOLOv8 训练前需要一个 YAML 配置文件指明图片路径、类别数和类别名。我在aircraft_dataset/下创建一个aircraft.yamlpath: /data/aircraft_dataset/YOLO train: images/train val: images/val test: images/test nc: 1 names: [airplane]这里path是 YOLO 目录的绝对路径也可以写成相对路径但训练时建议用绝对路径避免工作目录切换后路径找不到。train和val是相对于path子路径nc是类别数——这份飞机数据只有一类目标所以是 1。names列表的顺序必须和标签 txt 里的 class_id 一一对应这没啥玄学只是顺序错了模型训练不会报错但多了个标签名对不上号。然后启动训练yolo detect train \ modelyolov8n.pt \ dataaircraft.yaml \ epochs100 \ imgsz640 \ batch16如果是 YOLOv5 环境则用python train.py --data aircraft.yaml --weights yolov5s.pt --epochs 100 --batch-size 16。两条命令做的事情本质一样读取 YAML 配置把训练集图片与对应标注配对送入模型迭代。第一次跑的时候注意看命令行输出里的类别数应该显示1而不是80如果是 80检查是不是误加载了 COCO 预训练权重而没改数据配置文件。3.4 从 VOC 转换到 YOLO别手写直接复用现成脚本虽然压缩包里自带 YOLO 标注但我仍建议你留一份自己的 VOC 转 YOLO 脚本在项目仓库里。原因有三个一是当你后续想要补充数据比如自己用 LabelImg、X-AnyLabeling 新标注一批飞机图你不会想手动转格式二是当这份数据集的 txt 有损坏时你能从 XML 反推恢复三是转换逻辑本来就不复杂会了之后对两个格式的理解会加深一层。import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_file, class_names): tree ET.parse(xml_file) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_names: continue cls_id class_names.index(name) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) return \n.join(lines) class_names [airplane] xml_dir aircraft_dataset/VOC/Annotations txt_dir converted_labels os.makedirs(txt_dir, exist_okTrue) for xml_name in os.listdir(xml_dir): if not xml_name.endswith(.xml): continue txt_name os.path.splitext(xml_name)[0] .txt content voc_to_yolo(os.path.join(xml_dir, xml_name), class_names) with open(os.path.join(txt_dir, txt_name), w) as f: f.write(content)逻辑不复杂从size标签读图片宽高遍历所有object把bndbox的绝对坐标换算成归一化的中心点坐标与宽高。需要留意的是坐标值全部做了浮点除法务必保留 6 位小数。归一化坐标精度不足会导致小目标框的宽高在训练时被量化出误差飞机这类小目标对这点尤其敏感。转换完成后做一个自检随机挑 5 个 txt检查行数是否等于对应 XML 里的object数量检查所有坐标值是否在 [0, 1] 区间内负值或大于 1 的值都说明算错了。还有一点容易被忽略class_names列表必须与你最终训练配置的names保持完全一致顺序也不能错否则类别 ID 就会错位。4. 飞机数据集的五个典型翻车现场与排查方案4.1 解压后 XML 与 JPG 文件名大小写不一致现象Linux 下训练时提示找不到图片文件但明明图片就在目录里。用ls查看发现文件名是.JPG大写后缀而 XML 和标注 txt 里记录的是.jpg小写后缀。原因数据集在 Windows 上打包制作时文件系统不区分大小写部分图片可能被不同工具处理成混合大小写的后缀解压到 Linux 后大小写敏感的 ext4 文件系统立刻暴露了这个问题。解决批量统一后缀。把JPEGImages下所有.JPG和.jpeg改名为.jpg同时同步修改 XML 里的filename节点内容。简单命令如下cd aircraft_dataset/VOC/JPEGImages/ for f in *.JPG; do mv $f ${f%.JPG}.jpg; done改完后用 Python 再跑一遍核对确保Annotations里每个 XML 的filename值都能在JPEGImages里找到对应文件。4.2 YOLO 标注文件存在但对应图片缺失现象训练启动后日志里出现大量WARNING: ignoring corrupt/non-existent image或者某个路径反复报 Not Foundloss 数值却还在下降容易让人误以为一切正常。原因数据划分时类目管理混乱train 列表包含的图片名与 labels 目录里实际存在的文件不一致。手写划分脚本时最常见的失误是只遍历了 labels 目录生成训练列表没回去比对 images 目录。解决训练前做一个完整的文件配对检查。写一个脚本遍历所有 txt 标注检查同名 .jpg 是否存在于 images 目录同时反向检查一遍把不匹配的文件打印出来。缺图就把 txt 删掉缺标注就把图片移出训练集。飞机这类单类别数据集一张错配的样本就可能导致整体 mAP 掉一个点。4.3 VOC 转 YOLO 时 XML 里存在重复或空 object 节点现象转换脚本生成的 txt 行了数比图片里实际飞机数少或者训练时某个 batch 的 target 数量为 0loss 突然跳变。原因数据源在标注阶段有漏操作部分 XML 里存在object节点但内部bndbox为空或者同一个目标被重复标注了两次。解决在转换脚本里加一轮健壮性校验——遇到bndbox坐标解析失败的 object 直接跳过并打印文件名遇到两个框的 IoU 超过 0.95 的保留置信度更高的一方。这类清洗在原数据集作者未做的情况下需要你自己补上。用一张已经画好框的图与清洗后的标注叠加对比是判断清洗效果的最快手段。4.4 类别不匹配XML 里是 airplaneYOLO txt 里是 99现象做迁移学习时加载yolov8n.pt预训练权重后训练正常但验证时所有框都被过滤mAP 显示 0。打开部分 txt 一看行首的类别 ID 不是 0。原因某些标注工具的类别 ID 是全局编号而非数据集内编号。当类别在全局列表里排第 100 位时ID 写成 99但你的 data.yaml 中nc1类别 ID 范围只允许 0超出的 ID 被训练脚本当作无效类别丢弃。解决转换时不要保留原始 ID统一按class_names列表的索引重新编号。这类问题最让人头疼的地方是训练过程不完全报错只是结果不对所以验证阶段必须打印一批标注文件的 class ID 分布确认全部落在 [0, nc) 区间内。4.5 数据集里没有背景图导致误检率偏高现象模型训练完在测试集上 mAP 不错但拿真实场景的图一测把云层、建筑、路面标线都误检成飞机需要把置信度阈值从默认的 0.25 提到 0.6 以上才能勉强用。原因7930 张图里如果全部是“含飞机的正样本”图模型没有见过不带飞机的背景负样本学到的判断标准会宽松得离谱。正负样本不均衡是目标检测里的经典坑飞机这类在天空中目标尤其容易被云层干扰。解决从训练集中划出一部分不含任何飞机的背景图加入 val 和 test 集验证时用负样本误检率作为另一项指标。如果整个数据集没有背景图就需要外部补充一些无飞机的天空或机场场景图。这里提醒一点不是所有目标检测数据集都天然包含负样本能看到负样本的数据集往往制作时更用心也更接近实际部署场景。5. 把 7930 张飞机数据训练到好用必调参数与评估口径5.1 先从模型选型说起n、s、m、l 怎么选7930 张图的数据量级属于“中等偏下”。COCO 数据集的规模约 12 万张你的数据只有它的 1/15。这种情况下一上来就用 YOLOv8x 或 YOLOv11x 是大忌——参数量太大数据不足模型学到的细节有限训练结果往往不如小模型。常见选择是在yolov8n与yolov8s之间权衡显存有限、追求推理速度选n对精度有更高要求且显存 8GB 以上选s。更务实的做法是先跑n模型快速验证数据质量确认标注没问题后再切到s或m。这个迭代顺序能帮你避开“数据有问题却拿着大模型跑了十几个小时”的尴尬场面。你拥有的是定长数据而不是无限数据流先小后大是止损策略。5.2 训练参数里的五个关键旋钮imgsz是最影响精度的一个参数。默认 640但如果原图分辨率较高比如飞机图片普遍超过 1280 像素把imgsz调到 960 或 1280 能让小目标保留更多特征。代价是显存占用近似平方增长batch需要相应调低。针对飞机这种经常以小目标形态出现的对象我会优先尝试 960。batch受限于显存显存不够时就调低它。12GB 显存跑s模型 640 分辨率batch16较稳上到 1280 分辨率建议降到batch8或更小。batch越小梯度估计越不稳定但配合适当的 learning rate 调整可以接受。epochs放在这个数据量级上我一般设 100 到 150 之间。训练集只有几千张的话跑 300 epochs 大概率过拟合验证集 mAP 后期反而下降。训练完看results.png里 val 曲线的拐点才是最可靠的。更稳妥的做法是开启早停yolo detect train \ modelyolov8s.pt \ dataaircraft.yaml \ epochs200 \ imgsz960 \ batch12 \ patience30 \ save_period10patience30表示连续 30 轮验证集指标没有提升就自动停止省时间省电。save_period10每 10 轮保存一次权重相当于中间状态的后悔药后面要回滚到某个 epoch 的模型做对比就有依据了。优化器选型。默认的AdamW在中小数据集上通常比SGD收敛更快、调参更省心。lr0初始学习率默认 0.01如果 loss 初始就爆降到 0.001 试试。这两个参数只在训练日志出现异常时才需要动数据质量过关的情况下保持默认即可。提示YOLOv8 训练日志里每轮输出的box_loss、cls_loss与dfl_loss都有训练集和验证集两组。主要看验证集那组曲线是否平稳下降并在某点后开始反弹反弹就说明过拟合开始取反弹前的权重做最终模型。5.3 推理与评估阶段的置信度和 NMS 设置模型训练完验证不是只看一个 mAP 数字。先跑验证集得到 Precision、Recall、mAP50、mAP50-95 四个指标。针对飞机检测这类误检代价较高的场景把云层当飞机会严重影响告警准确率精度比召回更重要允许少量漏检但不能满天误报。推理阶段最常调的是conf_thres置信度阈值。默认 0.25 适合泛用场景飞机检测我一般从 0.35 起调误检多就往上加漏检多就往下减。目标检测调参有个规律从 0.25 到 0.5 之间每调 0.05误检数量可能减半而召回只降 1% 到 2%。这个区间值得多做几轮测试。NMS 的iou_thres决定两个重叠框是否合并。默认 0.45 在飞机这类稀疏目标上适用如果出现同一架飞机被同时输出多个框的情况适当降到 0.3 可以有效抑制。马赛克增强在训练时会让模型对彼此靠近的目标产生更高的响应这在飞机编队图片里很常见。评估代码建议保存一份yolo detect val \ modelruns/detect/train/weights/best.pt \ dataaircraft.yaml \ conf_thres0.35 \ iou_thres0.45 \ save_jsonTruesave_jsonTrue会输出 COCO 格式的详细评估结果包含每一类的 AP 与 AR。单类别数据集看不出分类差别但你能从 AP50 与 AP50-95 的差距判断小目标检测的瓶颈——差距越大说明框的定位精度越差优先提高imgsz而不是增加训练轮数。5.4 小目标检测是飞机数据集的核心难点飞机检测的一大实际痛点是目标太小。在 1280x720 的航拍图中一架地面飞机可能只有 20x20 像素在 640x640 的训练分辨率下缩小到 10x10 像素特征几乎消失。验证集 mAP50 可能尚可但 mAP50-95 会非常难看。想提升小目标表现有几个立竿见影的手段一是imgsz从 640 提到 960 甚至 1280前面已说二是在yolov8n的配置上加一层 P2 检测头Ultralytics 支持在模型 YAML 里设置p2True开启更浅层次的特征图用于小目标检测三是用裁剪策略把大图按滑窗切成若干小块再分别检测最后合并结果。滑窗切割是这个数据集后期真正挖出精度的方向。7930 张图如果原图分辨率高切成小图后样本数量成倍增长小目标被放大训练和推理效果都有提升。代价是推理时间线性增长。对飞机检测这种实时性要求不高的场景值得做对需要实时跑视频流的场景则要慎重。6. 数据增强与迁移学习的进阶用法当 7930 张飞机图已经训出 baseline接下来的收益主要来自数据增强策略的精细化调整而不是继续堆 epochs。YOLOv8 的数据增强在训练时默认开启 Mosaic、随机仿射变换、HSV 扰动等但这些参数对飞机场景未必最优需要针对性做调整。Mosaic 增强会把四张图拼成一张训练图对小目标效果好但对飞机这种常以单体或编队出现的对象拼接出的场景不自然且容易截断飞机。考虑降低mosaic的概率或者只在训练前 70% 的 epoch 启用。Ultralytics 支持训练中按 epoch 动态关闭某些增强修改配置文件里的mosaic参数为 0.5 或者写回调函数实现。我的习惯是前 50 epoch 用 Mosaic 增强让模型见多识广后 50 epoch 关闭它让模型适应真实分布验证集 mAP 通常能涨 1 到 3 个点。翻转与旋转增强对飞机这类方向性较强的目标要谨慎处理。水平翻转飞机问题不大但把飞机旋转 90 度后地面停放的飞机和空中飞行的飞机在视觉语义上完全不同旋转增强可能会破坏朝向这一隐含特征。默认的degrees0.0保持不旋转fliplr0.5水平翻转概率按需保留垂直翻转不建议开。HSV 颜色增强在这类数据集中可以加大一些。航拍图片的光照、色温变化很大把 HSV 的饱和度变化区间hsv_s从默认的 0.7 调到 1.0让模型对色彩变化更鲁棒减少真实场景中不同光照下的误检。但小心飞机的机身颜色本身是一个强特征调得太大比如把白色飞机变成蓝色反而会让模型学到错误的颜色关联。迁移学习的深度利用同样值得做。初始权重用yolov8s.ptCOCO 预训练这是一个好的起步但你可以走得更远找一个在遥感图像或航拍数据集上预训练过的模型权重在这个基础上继续微调。COCO 预训练权重里没有足够的“俯视视角小目标”特征而遥感预训练权重正好有。这类权重在开源社区里能找到加载方式与普通预训练权重完全一样替换model参数即可。调数据增强这块我的建议是一改一测别同时动三四个参数否则无法定位是哪个改动带来了提升。记录每次实验的 mAP50 与 mAP50-95形成一张自己的实验记录表。数据有限时每次实验都值得做留存方便后续回溯复现。最后提醒一点7930 张飞机数据训出的模型只能保证这类数据分布下的表现换机场、换拍摄高度、换天气后建议补充少量新数据再微调一轮。我习惯把模型的记录信息写在权重文件名里诸如yolov8s_aircraft_aug_mosaic0.5_960_150ep.pt这样过几个月回来找模型也不会黑匣子化。过程留痕、参数留档、数据留底是目标检测这条路上最朴素也最有效的经验。希望帮到你。本文还有配套的精品资源点击获取
