
简介面向目标检测任务的一套飞机目标检测数据集压缩包内提供7931张JPEG图片及一一对应的Pascal VOC格式XML标注与YOLO格式TXT标注全图仅含airplane一个类别矩形框总数23568个由labelImg工具严格绘制。数据集已按两种主流格式整理可直接接入YOLO、Faster R-CNN、SSD等常见检测框架训练省去自行转换标注的繁琐步骤。包体共2000个文件以xml标注文件为主1999个另有txt说明文件整体大小约107.37MB结构简洁适合目标检测入门练习、算法验证及特定场景模型微调。目前已有201人浏览学习适合需要快速获取规范标注飞机数据的开发者。标注仅负责提供准确合理的框不承诺模型精度使用时请结合实际训练目标评估。1. 飞机目标检测数据集7930张图能解决什么VOC与YOLO两种格式怎么选做目标检测训练的人手里最缺的往往不是模型是数据。想训练一个能数停机坪飞机、监控机场进出港或者做遥感巡检的检测模型翻遍开源数据集要么是COCO里飞机样本太少要么是DOTA这类遥感数据集标注格式太绕。这个飞机数据集正好卡在这个需求上7930张图标配VOC和YOLO两种主流标注格式拿回来不用自己转换就能直接喂给训练脚本。它解决的核心问题就是冷启动不用再从零标注几千张图也不用纠结XML和txt之间的格式转换省掉的是最枯燥的标注和对齐环节。适合的人是两类一是刚接触目标检测、需要一个规整数据集跑通YOLO训练流程的从业者二是已经做过检测、缺一个现成航空数据做迁移学习或验证模型的工程师。如果你是这两种人这7930张图值得认真用起来。2. 拆开数据集看门道VOC与YOLO目录结构、标注文件格式与读取校验拿到zip先别急着解压出图。我见过太多人解压后直接把路径塞进训练脚本结果跑起来才发现图片和标注对不上白白浪费半个晚上。第一步不是训练而是把目录结构、标注格式、划分文件三件事核清楚这决定了后面是一次跑通还是反复翻车。2.1 解压后的目录结构两份数据各自的组织方式先解压再看结构。zip解压这类老问题是常客有的压缩包顶层套一层同名目录有的把标注和图片分两个zip压缩解压时如果不加注意目录层级一刀就把训练脚本的路径判断搞乱了。我一般会先把解压结果列出来mkdir -p airplane_dataset unzip 飞机数据集7930张VOCYOLO格式.zip -d airplane_dataset cd airplane_dataset find . -maxdepth 3 -type d | sort如果出现所有文件跑到了airplane_dataset/airplane_dataset/这种嵌套目录里就先把外层目录纠正过来否则后面 data.yaml 里的 path 和 images 目录根路径之间会差一层。这一步用小命令花两分钟省下来的是一小时排错时间。VOC格式通常长这样沿用 Pascal VOC 的经典目录约定VOC2007/ ├── JPEGImages/ # 全部jpg原图 ├── Annotations/ # 与图片同名的xml标注 └── ImageSets/ └── Main/ # train.txt / val.txt / test.txtYOLO格式则按 ultralytics 的训练约定组织VOC_YOLO/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/两份数据共享同一批7930张图区别是标注载体完全不同。VOC把标注写成xml图片和划分文件彼此独立YOLO把每张图的标注写进同名txt并且用目录层级直接表达训练、验证、测试集合。用哪套取决于你手上的训练代码ultralytics 系的 yolo 训练脚本吃 YOLO 目录格式而一些老代码或自己写的多阶段训练流程只认 VOC。选型原则就一条读你的训练代码的默认数据加载器别反过来让代码迁就你的数据。如果两边都能跑我推荐优先用 YOLO 格式少一层 ImageSets 解析省心很多。另外关于 zip 本身有个小提醒7930 张原始图片加标注的压缩包解压后体积往往有数GB。训练前把数据集放到 SSD 上否则数据加载会成为瓶颈每轮 epoch 的耗时会被磁盘读取拖长。如果解压时提示文件损坏或密码保护先用unzip -t做完整性测试别等到训练读不出来再懊恼。zip 解压失败这种事用 7z 或 unzip 重解一次往往就解决了。2.2 标注文件的字段含义从XML像素框到txt的归一化坐标随便找一张 VOC 标注打开看核心是这几段annotation filename000213.jpg/filename size width1920/width height1080/height depth3/depth /size object nameairplane/name bndbox xmin103/xmin ymin204/ymin xmax412/xmax ymax318/ymax /bndbox /object /annotationxml 里写清楚了五件事文件名、图片原始宽高、目标类别名、目标框的左上角坐标xmin, ymin和右下角坐标xmax, ymax。注意这里的坐标是图片上的绝对像素值不是归一化的。width 和 height 告诉任何训练代码应该用哪个尺寸来做归一化分母缺失或不一致都会导致框画歪。对应同一张图的 YOLO 格式 txt 只有一行0 0.134 0.241 0.161 0.106五个字段的顺序是类别编号、归一化的框中心 x、归一化的框中心 y、归一化的框宽、归一化的框高。换算关系是这样的x_center (xmin xmax) / 2 / width y_center (ymin ymax) / 2 / height box_w (xmax - xmin) / width box_h (ymax - ymin) / height这里就埋了第一个坑Pascal VOC 的坐标是 1 索引的像素坐标也就是像素格的索引从 1 开始而 YOLO 的归一化坐标假设图片左上是 (0,0)。严谨的转换应该在 xmin 和 ymin 上减 1即用 (xmin-1) 和 (ymin-1) 参与计算差值仍用 xmax-xmin。对大目标差 1 个像素无所谓对小飞机这种只有十几像素的目标一个像素的偏差就会明显影响定位精度。这个坑后面还会展开说。2.3 用Python校验图片、标注、划分文件三者必须对齐训练前第一件事不是写训练配置而是跑校验脚本。我的惯例是写一个一劳永逸的 check 脚本查三件事有没有图片没有标注、有没有标注没有图片、划分文件里写的名字在不在标注目录里。对 VOC 侧这样查import os from pathlib import Path import xml.etree.ElementTree as ET dataset_root Path(airplane_dataset/VOC2007) # 1. 图片和标注能否一一对上 image_names {p.name for p in (dataset_root / JPEGImages).glob(*.jpg)} annotation_names {p.stem for p in (dataset_root / Annotations).glob(*.xml)} img_no_anno image_names - annotation_names anno_no_img annotation_names - image_names print(有图无标注:, len(img_no_anno)) print(有标注无图:, len(anno_no_img)) # 2. 划分文件里的条目是否都存在于Annotations main_dir dataset_root / ImageSets / Main for split_name in [train.txt, val.txt, test.txt]: split_file main_dir / split_name if not split_file.exists(): print(f缺失划分文件: {split_name}) continue names [line.strip() for line in split_file.read_text().splitlines() if line.strip()] missing [n for n in names if n not in annotation_names] print(f{split_name}: {len(names)} 条, 缺标注 {len(missing)} 条)跑出来后如果“有图无标注”和“有标注无图”都是 0三个划分文件也都对得上VOC 这一侧才算安全。如果图片里混杂了 png 或 jpegglob 只匹配 jpg 会漏可以改成用后缀集合匹配image_names {p.stem for p in (dataset_root / JPEGImages).iterdir() if p.suffix.lower() in {.jpg, .jpeg, .png}}YOLO 侧同样要核重点查两件事每行字段数是否为 5归一化坐标是否越界from pathlib import Path for split in [train, val, test]: label_dir Path(fairplane_dataset/VOC_YOLO/labels/{split}) if not label_dir.exists(): print(f缺失 labels/{split} 目录) continue bad_lines [] for label_file in label_dir.glob(*.txt): for line in label_file.read_text().splitlines(): parts line.split() if len(parts) ! 5: bad_lines.append((label_file.name, 字段数不是5, line)) continue cls_id, x, y, w, h parts try: x, y, w, h float(x), float(y), float(w), float(h) except ValueError: bad_lines.append((label_file.name, 坐标非数值, line)) continue if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): bad_lines.append((label_file.name, 归一化坐标越界, line)) print(f{split}: 异常行 {len(bad_lines)}) for name, reason, line in bad_lines[:10]: print( , name, reason, line)这个脚本跑一遍最多五分钟但它能挡住后面两小时的无效训练。常见的问题是某几张图片没有对应标注导致训练时被静默跳过或者某一行坐标写成小数百分数导致检测框位置全错。校验不是洁癖是给训练前设一道闸。3. 用YOLO格式直接落地训练data.yaml配置与关键训练参数校验通过后最常见、最稳的做法是用 YOLO 格式这套目录组织直接训练。ultralytics 的 detect 接口、老一点的 yolov5 的 repo、以及不少工业落地框架都吃这套 images/labels 目录约定。不需要再额外写解析器只要把 data.yaml 写对训练就能起来。这一章就从 data.yaml 讲到训练参数再讲训练日志怎么看。3.1 先确认类别映射一份data.yaml怎么定义数据先别急着写 yaml。第一步是统计这个数据集里到底有几个类别编号。虽然很多飞机数据集是单一类别 airplane但有的会细分出客机、直升机、军用机甚至用 0 代表飞机、1 代表背景团块。直接把 names 写成单类可能让训练白跑一轮。用一段三行的脚本把 labels 目录里所有 txt 的第一列收集起来from pathlib import Path label_root Path(airplane_dataset/VOC_YOLO/labels) class_set set() for label_file in label_root.rglob(*.txt): for line in label_file.read_text().splitlines(): if line.strip(): class_set.add(line.split()[0]) print(出现过的类别编号:, sorted(class_set))得到结果后把类别编号和真实类别名对应起来。假设统计结果是只有 0 这一种那么 data.yaml 这样写# airplane.yaml path: /home/work/airplane_dataset/VOC_YOLO # 改成你的实际绝对路径 train: images/train val: images/val test: images/test names: 0: airplane这里三个参数容易踩坑第一path 必须写绝对路径相对路径在部分环境里会解析到你启动训练的那个终端目录而不是 yaml 所在目录导致找不到图片第二train、val、test 都是相对 path 的目录不是文件第三names 的编号必须和 txt 里的第一列严格一致遗漏一个编号训练时会报 class index out of range。如果你计划做迁移学习val 这一项不能留空早停和 mAP 评估都依赖它。test 是可选的但建议填上训练完做一次真正的泛化验证。统计完类别编号再顺手看一眼每类目标的数量和框面积分布。这个动作能提前暴露类别不均衡和极端小目标问题如果某个类只有几十个框而其他类有上万mAP 会被大头类绑架如果框面积普遍小于 32x32 像素你就应该知道 imgsz 必须往高调。对飞机这种长宽比固定的目标还可以绘制一下 box 宽高比分布帮助判断是否适合用 anchor-based 的旧版 YOLO如果你用的是 ultralytics 新版本这个分布更多只是参考。3.2 训练命令这些参数对飞机检测尤其重要data.yaml 就位后起训练。如果你的机器还没装 ultralytics 依赖先花两分钟把环境配好pip install ultralytics。装完验证命令行可用再跑训练不然报错时你会分不清是数据集问题还是环境问题。以当前 ultralytics 系工具为准一条命令就能跑yolo detect train \ data/home/work/airplane_dataset/VOC_YOLO/data.yaml \ modelyolo11n.pt \ epochs100 \ imgsz640 \ batch16 \ patience20 \ project./runs \ nameairplane_det逐项说参数。modelyolo11n.pt 用的是预训练权重做起点而不是从头随机初始化这在小数据集上基本是决定性的7930 张图靠随机初始化想训到可用效果很难预训练权重里已经有通用视觉特征微调后很快能收敛。epochs 设 100 轮对这个规模的数据集偏充裕配合 patience20 做早停验证指标连续 20 轮不涨就自动终止不会空耗算力。imgsz640 是绝大多数检测任务的默认分辨率但对飞机场景要警惕遥感图或高位俯拍图里的飞机往往只有几十甚至十几个像素640 分辨率会把小目标直接抹成色块。如果跑完一轮发现 mAP50-95 始终上不去把 imgsz 提到 960 试试代价是训练和推理变慢收益是中小目标召回率明显提升这一步在后续踩坑里还会细说。batch16 是给你的显卡一个起步参考值。显存不够时优先降 batch 而不是降 imgsz——降 batch 只是加大梯度噪声降 imgsz 直接丢掉目标细节。patience 设 20 轮是比较稳的保守值设太小比如 5容易在收敛早期就被误杀。如果训练曲线波动大可以再考虑把 cos_lrTrue 打开让学习率按余弦曲线衰减收敛更平滑。顺手列一下我在飞机检测任务上常用的参数速查表参数作用我的常用值imgsz输入分辨率小目标场景提高它比堆数据更有效640起步小目标调到960batch每批图片数显存不足先降batch16patience验证指标不涨多少轮早停20cos_lr余弦退火让训练曲线平滑短训不开长训开augment数据增强强度飞机翻转不影响语义默认开启训练结束后推理也很简单顺手把 best.pt 路径扔给 predict 即可yolo detect predict modelruns/detect/airplane_det/weights/best.pt \ source./test_imgs \ conf0.25conf 是置信度阈值干净的高空影像可以设高一点地面或遮挡场景就调低。常见场景里 0.25 起步你的业务对误检敏感就提到 0.5。3.3 训练日志怎么看loss、mAP与过拟合信号训练跑起来后终端每轮会打印一堆指标新手容易盯着看却看不出门道。关键就四样train_loss、val_loss、mAP50、mAP50-95。最健康的曲线是前 20 轮 train 和 val 的 loss 同步下降mAP50 稳步抬升mAP50-95 跟着走。如果 train_loss 一路降val_loss 降到某一点后掉头向上同时 mAP50 开始横盘甚至回落就是过拟合信号这时候优先做三件事打开数据增强、调早停耐心、或者干脆接受当前 best.pt。yolo 的损失是分类损失加边界框回归损失加置信度损失的加权组合执行时不用逐个拆开盯只要关注总 loss 的相对变化即可。还有一个常见认知错位把 mAP50 当成唯一指标。实际飞行器检测任务更看重 mAP50-95它把 IoU 阈值从 0.5 一直算到 0.95 再求平均能反映框的定位精度。如果你的业务后续要做 tracking 或精确测距mAP50-95 比 mAP50 重要得多。训练完成后用 best.pt 做验证而不是用 last.pt很多人因为没用 best.pt 而白跑一批测试。4. 避坑与排查路径失效、标签错位、类别漏检的5个真实坑这一章写的是我处理类似飞机数据集时踩过的几个高频坑。每个坑按现象、原因、解决的顺序讲方便你在排错时直接对照。虽然这个数据及给了你现成的两种格式但坑往往藏在格式与训练流程的接缝处。4.1 坑一图片路径失效训练时一个epoch只有几十张图现象训练日志里出现大片的 WARNING提示 no labels found 或 image not found一个 epoch 跑完只有几十张图正常应该每轮数百张。 原因最多见的是解压后目录嵌套不一致。比如 data.yaml 的 path 指向 /home/work/airplane_dataset而实际文件名在 /home/work/airplane_dataset/data/VOC_YOLO 里把 images 目录路径暴露成 /home/work/airplane_dataset/images自然找不到任何图。另一种原因是划分文件里写的图片名带了子目录前缀而 train 目录里是裸文件名。 解决先用 find 确认目录深度再写一个三行命令核对图片和标签数量是否匹配find airplane_dataset/VOC_YOLO/images/train -name *.jpg | wc -l find airplane_dataset/VOC_YOLO/labels/train -name *.txt | wc -l两个数字差得多就从目录结构查起别急着改模型。把 path 改成实际路径之后再跑一次基本能排除掉这一类问题。4.2 坑二VOC转YOLO坐标偏移一个像素现象训练 loss 收敛得不错但拿到测试图上一看框整体向左上或右下偏移了几个像素小飞机目标是偏移一半。 原因VOC 转 YOLO 时把像素坐标当成了 0 索引。前面说过 Pascal VOC 的 xmin、ymin 是像素格索引从 1 开始转换时正确的做法是 x_center 用 (xmin-1xmax-1)/2 或者等价地 (xminxmax-1)/2宽用 (xmax-xmin)。很多网上的旧转换脚本直接把 (xminxmax)/2 拿来用对几十上百像素的大框影响可忽略对只有十几个像素的小框就是灾难。 解决不要手算写一小段转换函数然后在小图上人工验证。几十行的转换脚本不值得省关键是要画框验证而不是直接信任数字。我一般会随机挑五张图把 yolo txt 还原成像素框画到原图上人工过一遍框是否包住机身、是否偏了半格。这一步叫“标注可视化检查”是数据集质检里投入产出比最高的动作。如果发现整体偏移就检查 x_center 计算公式里的减一逻辑而不是怀疑训练参数。4.3 坑三类别编号跳跃导致训练报错现象训练跑到一半报错提示 class index X is out of range或者 loss 里出现 NaN。 原因标签 txt 的类别编号不是从 0 开始的连续整数。比如这个数据集里出现了 0、1、3编号 3 越过了 names 里定义的 2ultralytics 的加载器直接拒绝。还有的情况是类别编号写成了 0 和 1但 names 里错把主类写了 1。 解决统计类别集合重建一个干净的映射表。操作方法就是 3.1 那个统计脚本跑一遍拿到所有编号后把一个新字典写进训练脚本把旧编号一一映射到 0..N-1并同步检查划分文件里编号是否一致。这个操作建议用脚本批量完成不要手动改 txt7930 张图手动修不现实。4.4 坑四划分文件没固定随机种子val和train交集过大现象训练时 val mAP 很高训练完换到独立测试集一测性能明显下降差值大得反常。 原因划分 train 和 val 时用了随机函数但没有固定随机种子同一批图在不同次运行里被分进不同集合或者更糟划分逻辑只做了随机打乱而没有按图片文件名去重导致同一架飞机的多张相似帧同时躺在 train 和 val 里验证集失真。 解决重新生成划分文件用固定种子并按文件名前缀做组级划分而不是单图级划分。比如同一架次拍摄的图通常共享一个前缀或目录先按前缀分组再把整个组划到 train 或 val确保验证集不蹭训练集的数据。对 7930 张图来说推荐的划分比例是约 8:2或者按你的业务对误检率的要求适当加大验证集。划分完重新跑一次 2.3 的校验脚本确认两个集合没有文件名交集。4.5 坑五小目标漏检mAP50还可以但mAP50-95低现象大飞机基本全能检出远处的小飞机漏一片mAP50 看起来还行但 mAP50-95 一直不涨实际业务里漏检的恰恰是那一堆小目标。 原因两个因素叠加。一是输入分辨率不够640 分辨率下十几个像素的小飞机在缩放时信息被压没了二是数据增强里的 mosaic 和 scale augmentation 会进一步把目标缩小小目标雪上加霜。飞机检测场景有个典型矛盾既要 mosaic 提升背景多样性又要避免目标被缩太狠。 解决先给 imgsz 提到 960训练和推理一起改保证尺度一致。如果显存不够用 tiling 策略把大图切成几块分别推理再合并结果这也是工业上处理遥感大图的常用做法。数据增强方面在 ultralytics 配置里关掉或降低 scale augmentation 的最大下采样倍数或者只对这个数据集跑一次消融手动对比开启和关闭的 mAP。还有个笨办法但非常有效把漏检的小目标单独裁出来做一遍复制粘贴增强给模型补几个难例样本。这些小目标的处理方式没有银弹只能一个变量一个变量试。5. 进阶用法数据增强、迁移学习与验证怎么配出稳的飞机检测模型训练如果已经跑通这个数据集的价值还可以再挖一层。飞机目标检测有个先天优势刚体目标语义不受水平翻转影响不像文字检测那样翻转会改变含义。所以你的增强方案里翻转、小角度旋转、亮度扰动都可以放心开。遥感或俯拍场景再加一个随机裁剪等于白送一组新样本。要控制的是 scale 增强别把目标缩得比模型特征层的最小感受野还小否则模型学到的只是“一个点”而非“一架飞机”。迁移学习的正确姿势也不是直接拿 coco 预训练权重无脑微调。如果手头有在遥感大图或航拍数据上训过的权重把它们作为起点收敛速度和最终精度都会明显更好。7930 张图不算少但距离复杂机场场景的满血泛化还差一个数量级好的起点权重弥足珍贵。如果只用通用权重建议把冻结的前几层适当放宽让底层特征能适配高空影像的纹理。最后分享一个我坚持了很久的习惯每次训练前随机抽 20 张图做标注可视化。把 gt 框画上去人眼扫一遍比任何指标都提前暴露数据集问题。就拿这个飞机数据集来说如果框把机头切掉了或者把两架重叠的飞机框在一起模型再努力也学不对。这个动作每次都帮我省下几小时无效训练也是我做检测项目最后一道保险。希望帮到你。本文还有配套的精品资源点击获取