资讯动态

飞机型号识别数据集实战:从YOLOv8检测到细粒度分类的完整流程

发布时间:2026/10/12 20:45:48 来源:尧图企业网站定制
简介这份飞机型号识别数据集面向从事目标检测与细粒度图像分类的算法研究者、学生及军工爱好者聚焦军机与民航机型的自动识别任务。数据采集自俄罗斯机场覆盖苏霍伊、米格、安东诺夫、伊尔、雅克、图波列夫等46类军民飞机可用于训练与验证检测模型对相似机型的区分能力。资源包共2001个文件含1000张jpg可见光RGB图像、1000个xml标注文件及1个说明txt图像尺寸1024x768标注由labelimg生成压缩包约196.35MBjpg与xml一一对应便于直接接入YOLO、Faster R-CNN等框架。目前已有267人学习下载。该批次为系列第一批采集地点与类别均与其他批次不同适合作为算法研究的基线数据也可结合02、03、04等批次扩充类别与场景多样性提升模型泛化表现。1. 飞机型号识别数据集从“能框住”到“能叫出名字”的那道坎很多人第一次做飞机检测都会卡在同一个地方模型能把天空里的飞机框出来但框完就结束了它不知道那是歼-20、F-16 还是波音 737。如果你手上只有通用目标检测数据集比如 COCO里面确实有 airplane 这一类但所有飞机都挤在同一个标签下型号信息完全丢失。飞机型号识别数据集要解决的就是“分类粒度”这件事——它不只是告诉你“这里有飞机”而是告诉你“这里有一架什么型号的飞机”。这类数据集通常同时服务两个任务飞机目标检测定位和飞机分类型号判别。军机识别场景对粒度要求更高因为不同型号之间的外形差异可能只体现在进气道、翼尖挂架、座舱盖形状这些局部区域。适合谁用做遥感目标检测的、做机场场面监控的、做航空摄影自动标注的以及想拿一个“类内差异小、类间差异大”的细粒度数据集练手的工程师。后面我会按“数据集怎么读 → 检测怎么训 → 型号怎么分 → 坑在哪”这条线把能复现的步骤和参数讲清楚。2. 飞机型号识别数据集的结构拆解与读取方式2.1 检测标注和分类标注到底差在哪飞机型号识别数据集一般有两种组织形态。第一种是纯检测格式每张图对应一个标注文件里面是类别 x_center y_center width height这种归一化坐标型号直接作为类别名。第二种是“检测框 分类标签”分离检测部分只标 airplane另外用一个 CSV 或 JSON 记录每个框对应的型号。前者训练简单后者灵活但读取麻烦。我一般优先选第一种因为 YOLO 系列直接吃这种格式不需要额外写数据加载器。但要注意如果型号类别超过 30 类而每类样本又很少检测头会很难收敛。这时候常见做法是把“飞机”作为一个粗类先训检测再裁框送分类网络。下面这段代码是读取 YOLO 格式标注并统计类别分布的用来判断你的数据集能不能直接训检测。import os from collections import Counter label_dir labels/train counter Counter() for txt in os.listdir(label_dir): if not txt.endswith(.txt): continue with open(os.path.join(label_dir, txt), r) as f: for line in f: parts line.strip().split() if len(parts) 5: counter[parts[0]] 1 # 第一列是类别索引 for cls_id, num in counter.most_common(): print(fclass {cls_id}: {num} boxes)逻辑说明遍历所有标注文件按类别索引统计框数量。参数说明label_dir换成你的实际路径如果类别是字符串而不是索引parts[0]直接就是型号名。跑完你会看到类似class 0: 1200、class 7: 15的结果。如果某些型号少于 50 个框检测阶段基本学不动建议合并或走分类分支。2.2 用 Python 把数据集转成 YOLO 可训练目录拿到原始数据后第一件事是统一目录结构。YOLO 要求images/train、labels/train、images/val、labels/val分开并且图片和标注同名。很多飞机型号识别数据集给的是 VOC XML需要转。下面这个脚本处理 VOC 到 YOLO 的转换同时生成data.yaml。import xml.etree.ElementTree as ET import os, shutil classes [airplane] # 如果型号作为类别这里换成型号列表 xml_dir Annotations img_dir JPEGImages out_img dataset/images/train out_lbl dataset/labels/train os.makedirs(out_img, exist_okTrue) os.makedirs(out_lbl, exist_okTrue) for xml_file in os.listdir(xml_dir): tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(cls_name) bbox obj.find(bndbox) x1 float(bbox.find(xmin).text) y1 float(bbox.find(ymin).text) x2 float(bbox.find(xmax).text) y2 float(bbox.find(ymax).text) # 转成归一化中心点宽高 cx (x1 x2) / 2 / w cy (y1 y2) / 2 / h bw (x2 - x1) / w bh (y2 - y1) / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) if lines: img_name xml_file.replace(.xml, .jpg) shutil.copy(os.path.join(img_dir, img_name), os.path.join(out_img, img_name)) with open(os.path.join(out_lbl, xml_file.replace(.xml, .txt)), w) as f: f.write(\n.join(lines))逻辑说明解析每个 XML提取宽高和框坐标做归一化后写入同名 txt。参数说明classes列表决定哪些类别保留不在列表里的目标直接丢弃cx/cy/bw/bh必须除以图像宽高否则 YOLO 读进去会报坐标越界。转换完记得检查有没有图片没对应标注或者标注为空的情况。2.3 类别不平衡时先别急着训检测飞机型号识别数据集里民航常见型号样本多军机稀有型号样本少这是常态。我见过一个数据集波音 737 有 3000 多个框而某型预警机只有 40 个框。直接训检测模型会把稀有型号全预测成常见型号。这时候有两个选择一是把稀有型号合并成“其他军机”一个大类二是走“检测 裁剪分类”两阶段。前者损失粒度后者保留粒度但工程量大。我的习惯是如果稀有型号少于 100 个框先合并如果 100 到 300 之间可以训检测但要把copy_paste和mosaic增强开大同时用类别权重。YOLOv8 之后的数据配置里可以写cls_pw或者用focal_loss但最稳的还是过采样。下面这段是给稀有类别做简单过采样的逻辑。import os, random, shutil rare_ids {7, 12} # 稀有类别索引 src_img dataset/images/train src_lbl dataset/labels/train dst_img dataset/images/train_oversample dst_lbl dataset/labels/train_oversample os.makedirs(dst_img, exist_okTrue) os.makedirs(dst_lbl, exist_okTrue) for txt in os.listdir(src_lbl): with open(os.path.join(src_lbl, txt)) as f: lines f.readlines() has_rare any(line.split()[0] in rare_ids for line in lines if line.strip()) # 稀有样本复制 3 份普通样本复制 1 份 times 3 if has_rare else 1 for i in range(times): shutil.copy(os.path.join(src_img, txt.replace(.txt, .jpg)), os.path.join(dst_img, f{i}_ txt.replace(.txt, .jpg))) shutil.copy(os.path.join(src_lbl, txt), os.path.join(dst_lbl, f{i}_ txt))逻辑说明包含稀有类别的图片复制多份文件名加前缀避免冲突。参数说明rare_ids换成你统计出来的稀有类别索引times3可以调但别超过 5否则过拟合明显。过采样后训练集变大epochs可以适当减少。3. 用 YOLOv8 跑通飞机检测的最小训练流程3.1 环境配置和 data.yaml 的四个必填项YOLOv8 的环境配置现在很成熟pip install ultralytics就能跑。但飞机检测有几个特殊点图像分辨率高、小目标多、背景单一天空或地面。我一般会先确认 CUDA 可用然后写data.yaml。这个文件里path、train、val、names四个字段必须对少一个都会报错。path: /data/aircraft train: images/train_oversample val: images/val names: 0: airplane 1: fighter 2: bomber 3: transport 4: helicopter逻辑说明path是数据集根目录train和val是相对路径。参数说明names的键必须是连续整数从 0 开始如果型号作为类别这里就写型号名。注意val不要用过采样后的目录否则验证指标虚高。3.2 训练命令和三个关键参数最小训练命令很简单但飞机检测有几个参数必须调。下面这条命令是我在单卡 24G 显存上跑 640 分辨率、batch 16 的配置。yolo detect train \ data/data/aircraft/data.yaml \ modelyolov8s.pt \ epochs120 \ imgsz640 \ batch16 \ lr00.01 \ patience30 \ mosaic1.0 \ close_mosaic20 \ projectruns/aircraft \ nameexp1逻辑说明modelyolov8s.pt是预训练权重飞机检测数据量不大时比从头训稳。参数说明lr00.01是初始学习率如果 loss 震荡就降到 0.005close_mosaic20表示最后 20 个 epoch 关闭 mosaic让模型适应真实分布patience30是早停耐心值。飞机小目标多的时候imgsz可以提到 1024但显存不够就保持 640。3.3 训练过程看什么指标跑起来之后终端会打印box_loss、cls_loss、dfl_loss和 mAP。飞机检测最需要盯的是cls_loss因为它直接反映型号分类对不对。如果box_loss降但cls_loss不降说明框准了但型号分不开这时候要么加分类分支要么检查标注里型号有没有标错。另一个指标是mAP50-95飞机这种形状规整的目标mAP50通常能到 0.9 以上但mAP50-95可能只有 0.6 左右这是正常的因为框的定位精度要求高。我一般会在训练中途用验证集跑一次预测看混淆矩阵。如果常见型号和稀有型号混在一起就回到 2.3 节做过采样。如果所有型号都混那可能是分辨率不够飞机型号的区分特征在 640 下看不清需要裁图或提高输入尺寸。4. 型号分类分支检测框裁出来之后怎么训4.1 裁框生成分类数据集检测训完之后用最优权重对训练集和验证集做推理把每个框裁出来按型号存到不同文件夹。这一步是两阶段方案的核心。下面代码用 YOLO 推理并保存裁剪图。from ultralytics import YOLO import cv2, os model YOLO(runs/aircraft/exp1/weights/best.pt) img_dir dataset/images/train out_dir cls_dataset/train os.makedirs(out_dir, exist_okTrue) for img_name in os.listdir(img_dir): img_path os.path.join(img_dir, img_name) results model(img_path, conf0.5, iou0.5)[0] img cv2.imread(img_path) for i, box in enumerate(results.boxes): cls_id int(box.cls) x1, y1, x2, y2 map(int, box.xyxy[0]) crop img[y1:y2, x1:x2] if crop.size 0: continue cls_dir os.path.join(out_dir, str(cls_id)) os.makedirs(cls_dir, exist_okTrue) cv2.imwrite(os.path.join(cls_dir, f{img_name}_{i}.jpg), crop)逻辑说明对每张图推理按类别索引建文件夹保存裁剪图。参数说明conf0.5过滤低置信度框iou0.5做 NMS。注意这里用的是检测模型预测的类别如果检测阶段只有 airplane 一类那所有裁剪图都在同一个文件夹需要另外用标注里的型号信息来分文件夹。4.2 用轻量分类网络训型号裁剪图通常不大224x224 足够。我一般用 ResNet18 或 MobileNetV3因为型号分类的特征比较局部不需要太深的网络。训练命令用 torchvision 或 timm 都行下面给一个最小训练循环。import torch from torchvision import datasets, models, transforms transform transforms.Compose([ transforms.Resize((224, 224)), transforms.RandomHorizontalFlip(), transforms.ToTensor(), ]) train_ds datasets.ImageFolder(cls_dataset/train, transformtransform) loader torch.utils.data.DataLoader(train_ds, batch_size32, shuffleTrue) model models.resnet18(pretrainedTrue) model.fc torch.nn.Linear(model.fc.in_features, len(train_ds.classes)) model model.cuda() opt torch.optim.Adam(model.parameters(), lr1e-3) loss_fn torch.nn.CrossEntropyLoss() for epoch in range(20): model.train() for x, y in loader: x, y x.cuda(), y.cuda() opt.zero_grad() loss loss_fn(model(x), y) loss.backward() opt.step() print(fepoch {epoch}, loss {loss.item():.4f})逻辑说明标准分类训练循环最后全连接层改成型号数。参数说明lr1e-3对预训练模型合适如果从零训要降到 1e-2 并加 warmupbatch_size32根据显存调。型号分类的难点是类间差异小可以加RandomResizedCrop和ColorJitter增强。4.3 检测和分类怎么串起来推理两阶段推理就是先检测再裁剪分类。实际部署时检测模型输出框裁剪后送分类模型最后把型号标签贴回框上。这里有一个坑检测框可能包含多个飞机或者框偏了导致裁剪图里飞机不完整。我一般会把检测框向外扩 10%再送分类。另外分类置信度低于 0.6 时可以回退到“未知型号”不要硬报一个错型号。5. 飞机型号识别数据集避坑5 个血泪教训5.1 现象mAP 很高但实际预测全是同一型号原因类别不平衡导致模型学到“只要像飞机就报最常见型号”。解决按 2.3 节做过采样或者在损失里加类别权重。验证时不要只看 mAP要看混淆矩阵和每类召回率。5.2 现象小目标飞机漏检严重原因飞机在遥感图里可能只有 20x20 像素YOLO 下采样 32 倍后特征几乎消失。解决提高imgsz到 1024 或 1280或者用切片推理SAHI。如果显存不够用yolov8n加高分辨率比yolov8l加低分辨率更有效。5.3 现象验证集 loss 突然飙升原因close_mosaic设置太晚模型在最后阶段还在看拼接图验证集是原图分布不一致。解决close_mosaic设成总 epoch 的 10% 到 15%比如 120 epoch 就设 15。另外检查val目录有没有混入训练集图片。5.4 现象型号分类把民航和军机搞混原因裁剪图里包含了天空、地面等背景分类网络学了背景而不是飞机本身。解决裁剪时把框缩紧一点或者用分割模型先抠飞机。另一个办法是在分类训练时加RandomErasing强迫网络看局部。5.5 现象推理速度慢达不到实时原因两阶段推理串行检测和分类各跑一次。解决用 TensorRT 或 ONNX Runtime 加速检测和分类可以放在同一个 GPU stream 里。如果对实时要求高直接训一个多任务模型检测头加分类头共享 backbone。6. 进阶用开放词汇检测扩展未知型号飞机型号识别数据集再全也覆盖不了所有型号。新服役的机型、涂装变化、遮挡严重的情况闭集检测器会直接漏掉或报错。我最近在试的一个方向是用开放词汇检测Open-Vocabulary Detection做兜底先用闭集模型检测常见型号对低置信度或“未知”的框用 CLIP 类模型和型号文本描述做匹配。具体做法是准备一个型号描述库比如“双发窄体客机翼尖小翼波音 737”这种文本。对每个检测框裁剪图用 CLIP 算图像特征和所有文本特征的相似度取最高分作为型号。这个方法不需要重新训练但推理延迟会增加。我一般只在离线分析或非实时场景用。验证这个方案有没有效可以拿一个闭集模型没见过的型号比如某型新涂装飞机看 CLIP 能不能匹配到正确描述。如果匹配错了就调整文本描述加入更多外形关键词。这个技巧帮我省了很多重新标注和重训的时间但前提是你的检测框要准框偏了 CLIP 也救不回来。我自己的习惯是每拿到一个新数据集先跑一遍类别分布再决定是单阶段还是两阶段。飞机型号识别这件事数据比模型重要标注粒度比网络深度重要。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑