ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

YOLO飞机检测数据集实战:VOC格式转换与模型训练全指南

YOLO飞机检测数据集实战:VOC格式转换与模型训练全指南 简介YOLO飞机检测数据集是基于PASCAL VOC 2012定制而成的单类别目标检测资源适合需要训练和验证飞机检测模型的开发者与研究者。整套压缩包共2149个文件大小约56.85MB其中包括716张jpg原图、716个xml详细标注和717个txt格式边界框标签XML标注提供类别、边界框及轮廓细节TXT则为YOLO训练常用的坐标格式省去手动转换标注的步骤。标注信息统一只针对“aeroplane”类别原始影像覆盖不同角度、光线与复杂背景可直接配合Darknet等YOLO框架完成数据划分与模型训练也可用于航空监控、无人机避障、机场安全巡检等场景的算法验证。文件命名沿用VOC编号目录结构清晰便于与原始PASCAL数据集对照查证。目前已有1256人学习下载这套干净纯粹的飞机样本集能帮助初学者快速上手YOLO流程也为进阶研究者提供了稳定可靠的单类检测基准数据。1. YOLO飞机检测数据集aeroplane_VOCtrainval2012一份拿来就能训的单一目标数据做目标检测的同行应该都有过这种经历为了验证一个检测思路先得花两天时间爬图、打标、转格式等数据能喂给YOLO了最初的热情也消耗得差不多了。YOLO飞机检测数据集 aeroplane_VOCtrainval2012.zip 解决的就是这个痛点——它把 PASCAL VOC 2012 trainval 中所有 aeroplane 类别的图片和标注提取出来整理成 YOLO 可直接消费的格式或半成品 VOC 格式解压后就能进训练流程。这个数据集适合三类人刚入门 YOLO 想跑通完整训练链路的新手、需要在单一类别上快速验证网络改动的老手以及机场巡检、遥感目标检测等方向的预研工程师。它最大的价值不是数据量大而是标注质量有保证、类别单一、背景多样非常适合用来做检测器的“标定基准”。2. aeroplane样本的数据构成与目标特征为什么 VOC 的飞机比爬来的图更值得信2.1 VOC trainval 2012 的飞机样本是怎么组织的PASCAL VOC 2012 的 trainval 包含约 1.7 万张图像涵盖 20 个类别。aeroplane 这个类别在其中的样本量大约在 600 到 900 张之间具体数量取决于你拿的是 trainval 还是 trainval 的拆分。每张图片对应一个 XML 标注文件文件名与图片名一致放在 JPEGImages 和 Annotations 两个目录下。XML 里记录的不是坐标本身而是物体在原始图片中的像素坐标——左上角 xmin、ymin 和右下角 xmax、ymax。这里有个容易忽略的点VOC 的 XML 里还包含 truncated目标被图像边界截断、difficult难以辨认和 occluded被遮挡三个属性。这三个属性在转 YOLO 格式时如果没有处理会把一批质量很差的标注混进训练集。我的习惯是把 difficult1 的样本直接过滤掉把 truncated1 的样本保留但检查边界坐标因为这些目标往往框不准。VOC 的标注是针对整张图的没有像 COCO 那样的 segmentation 信息。对于飞机这种刚性物体矩形框足够用。如果你做的是旋转框检测比如用 mmrotate这个数据集还需要额外生成旋转框标注VOC 原始格式不直接支持。2.2 单类别飞机检测的特点尺度、遮挡和背景干扰飞机检测跟通用目标检测最大的区别在于尺度变化极其剧烈。一张机场俯视图里一架停场波音 737 可能只占几十个像素一张起飞抓拍里飞机机头可能撑满整个画面。VOC 里的飞机样本覆盖了这两个极端这对 YOLO 的 anchor 设计和多尺度训练是个很好的压力测试。另一个特点是背景干扰。VOC 的 aeroplane 图片不少是在航展、跑道、停机坪拍的背景里有大量类似飞机的结构物——油罐车、候机楼玻璃幕墙、地面标线。单类别检测器的误检往往不是把猫狗认成飞机而是把机翼形状的物体、地面上的航空器阴影认成飞机。这个数据集能帮你把这类误检暴露出来而这恰恰是很多自采数据集做不到的——自采数据往往背景太干净。还有一个实际工程问题飞机样本在 VOC 里大量出现“多目标同框”一张图里有 5 到 10 架飞机很常见而且互相遮挡、重叠。这对 NMS 阈值和后处理策略的调优非常有用。2.3 解压后先做数据体检样本数与标注框分布统计拿到 zip 之后不要急着训练先做一次数据体检。我一般会写一个脚本统计三件事图片总数、标注框总数、框的宽高分布。这样能提前发现解压失败、XML 缺失、坐标异常等问题。import os import xml.etree.ElementTree as ET from collections import Counter # 假设解压后目录结构为 VOCdevkit/VOC2012 img_dir VOCdevkit/VOC2012/JPEGImages ann_dir VOCdevkit/VOC2012/Annotations img_files [f for f in os.listdir(img_dir) if f.endswith(.jpg)] ann_files [f for f in os.listdir(ann_dir) if f.endswith(.xml)] print(f图片数量: {len(img_files)}) print(f标注数量: {len(ann_files)}) print(f无标注的图片: {len(set(img_files) - set(a.replace(.xml, .jpg) for a in ann_files))}) box_count 0 size_counter Counter() for ann in ann_files: tree ET.parse(os.path.join(ann_dir, ann)) root tree.getroot() for obj in root.findall(object): difficult int(obj.findtext(difficult, 0)) if difficult 1: continue bndbox obj.find(bndbox) xmin int(bndbox.findtext(xmin)) ymin int(bndbox.findtext(ymin)) xmax int(bndbox.findtext(xmax)) ymax int(bndbox.findtext(ymax)) w xmax - xmin h ymax - ymin size_counter[(w // 50 * 50, h // 50 * 50)] 1 box_count 1 print(f有效标注框数量: {box_count}) print(f标注框尺寸分布(宽取整到50, 高取整到50): {size_counter.most_common(10)})这段代码先把图片和 XML 的数量对齐找出“有图无标注”的废样本然后遍历所有 XML跳过 difficult 样本统计有效框的数量和尺寸分布。逻辑上要注意的是VOC 的 XML 里有多个 object 节点每个节点才是一个目标框统计时别只取第一个。宽高分布的用处是后面配置 YOLO 的 anchor 或判断是否需要使用多尺度训练——如果大部分框集中在 50×50 到 150×150 区间你的输入尺寸就不需要开太大640 足够如果大量框超过 300×300建议 imgsz 开到 960。数据体检这一步跑完你才知道这个 zip 能不能直接进训练。我见过不止一次网络上下的 VOC 提取包解压后图片被压缩过、EXIF 信息被清掉这些不影响训练但会影响后续部署时的图像预处理一致性。3. 把VOC格式转成YOLO格式转换脚本、类别映射与数据集划分3.1 先确认zip里是原始VOC还是已经转好的YOLO格式网上流传的 aeroplane_VOCtrainval2012.zip 有两种形态一种是直接从 VOCdevkit 里把 aeroplane 相关的图片和 XML 抽出来保留 VOC 目录结构另一种是已经由作者跑过转换脚本直接给你 images 和 labels 两个文件夹外加一个 data.yaml。这两种形态的处理方式完全不同所以解压后第一步不是写脚本而是看目录结构。已经转好的 YOLO 格式目录下一定有 labels 文件夹里面是 txt 文件每行格式为“class_id cx cy w h”坐标是归一化浮点数。如果只有 Annotations 和 JPEGImages那就是原始 VOC 格式需要自己转。分辨方法很简单# 在解压目录下执行 find . -type d -maxdepth 2 # 若输出中包含 labels 目录说明是YOLO格式 # 若只有 Annotations 和 JPEGImages说明是VOC原始格式3.2 VOC标注XML转YOLO txt的Python脚本如果是原始 VOC 格式就用下面这个脚本转换。它同时做三件事提取坐标、跳过 difficult 样本、按比例划分训练验证集。import os import random import xml.etree.ElementTree as ET # 配置路径 voc_root VOCdevkit/VOC2012 img_dir os.path.join(voc_root, JPEGImages) ann_dir os.path.join(voc_root, Annotations) out_img_dir aeroplane_yolo/images out_lbl_dir aeroplane_yolo/labels os.makedirs(out_img_dir, exist_okTrue) os.makedirs(out_lbl_dir, exist_okTrue) # 单类别数据集aeroplane 的类别 id 固定为 0 class_id 0 train_ratio 0.85 random.seed(42) # 收集图片信息 # 注意这里只处理包含aeroplane标注的图片 image_list [] for ann_file in os.listdir(ann_dir): if not ann_file.endswith(.xml): continue tree ET.parse(os.path.join(ann_dir, ann_file)) root tree.getroot() # 检查这张图是否包含aeroplane has_aeroplane False boxes [] for obj in root.findall(object): name obj.findtext(name) difficult int(obj.findtext(difficult, 0)) if name aeroplane and difficult 0: has_aeroplane True bndbox obj.find(bndbox) xmin float(bndbox.findtext(xmin)) ymin float(bndbox.findtext(ymin)) xmax float(bndbox.findtext(xmax)) ymax float(bndbox.findtext(ymax)) boxes.append((xmin, ymin, xmax, ymax)) if not has_aeroplane: continue filename root.findtext(filename) # VOC2012的filename有的带.jpg后缀有的不带统一处理 if not filename.endswith(.jpg): filename .jpg image_list.append((ann_file.replace(.xml, ), boxes, filename)) # 划分训练集和验证集 random.shuffle(image_list) split_idx int(len(image_list) * train_ratio) train_list image_list[:split_idx] val_list image_list[split_idx:] # 写train和val的图片路径列表供YOLO训练时引用 with open(aeroplane_yolo/train.txt, w) as f: for item in train_list: f.write(os.path.join(out_img_dir, item[2]) \n) with open(aeroplane_yolo/val.txt, w) as f: for item in val_list: f.write(os.path.join(out_img_dir, item[2]) \n) # 转标注文件 for item in image_list: stem, boxes, filename item # 复制图片到images目录 src_img os.path.join(img_dir, filename) dst_img os.path.join(out_img_dir, filename) if os.path.exists(src_img): os.system(fcp {src_img} {dst_img}) # 获取图片尺寸用于归一化 # 用XML里的size节点比读图片更快 tree ET.parse(os.path.join(ann_dir, stem .xml)) root tree.getroot() size root.find(size) img_w float(size.findtext(width)) img_h float(size.findtext(height)) # 写YOLO格式的txt lbl_path os.path.join(out_lbl_dir, stem .txt) with open(lbl_path, w) as f: for (xmin, ymin, xmax, ymax) in boxes: # 坐标转归一化中心点 宽高 x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 对越界坐标做裁剪防止训练崩溃 x_center max(0, min(1, x_center)) y_center max(0, min(1, y_center)) w max(0, min(1, w)) h max(0, min(1, h)) f.write(f{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n) print(f转换完成: 训练集 {len(train_list)} 张, 验证集 {len(val_list)} 张)这个脚本有四个关键点。第一只保留 difficult0 的 aeroplane 样本其他类别直接跳过这样生成的是纯单类别数据集。第二图片尺寸从 XML 的 size 节点读取而不是用 PIL 打开图片批量处理时速度快很多。第三坐标归一化后做了一次越界裁剪这个动作防止后面训练时 YOLO 在 loss 计算里遇到负数坐标直接 nan。第四train/val 划分按图片做不是按标注框做避免同一张图既进训练又进验证。3.3 归一化坐标的精度问题和类别编号的映射关系归一化坐标的精度直接影响小目标检测效果。YOLO 格式里坐标是浮点数如果只保留 2 位小数比如 0.12 而不是 0.123456一个 640×640 输入里相当于 6 个像素的误差对于小飞机目标可能直接把框偏出半个机身。脚本里用.6f保留 6 位小数折算到 640 分辨率下精度约 0.001 像素完全够用。类别编号需要特别注意这个数据集是单类别的aeroplane 的 class id 一定是 0不是 1。很多人从多类别数据集迁移过来习惯性把编号写成 1训练时 loss 能跑但不收敛val 结果惨不忍睹。data.yaml 里必须写nc: 1和names: [aeroplane]且标签 txt 的每行第一个数字必须是 0。3.4 划分train/val/test按图片做而非按标注做有些人划分数据集时直接按文件名单数双数分这在单场景数据里没问题但 VOC 的飞机图片有的来自同一事件连拍相邻帧高度相似。如果这样的序列同时落在训练集和验证集你的 val loss 会虚低看起来效果很好换到真实场景直接翻车。我一般用随机打散而不是简单交替划分并且在划分前先把同一场景的连拍抽出来看一遍。VOC 的图片文件名里有 scene 信息比如2008_000001.jpg前四位是年份中间是场景编号同一场景的飞机角度、光照、背景都接近。稳妥做法是按场景编号分组划分而不是按单张划分。不过 aeroplane_VOCtrainval2012 这类提取包在文件名上不一定保留完整的 scene 规则所以退而求其次用随机种子固定打散就行。# 按场景分组划分的简化实现 # 思路从文件名提取场景前缀保证同场景图片在同一集合 from collections import defaultdict scene_groups defaultdict(list) for item in image_list: # 假设文件名形如 2008_000001.jpg取前9位作为场景ID scene_id item[2][:9] scene_groups[scene_id].append(item) # 按场景划分 all_scenes list(scene_groups.keys()) random.shuffle(all_scenes) train_scenes all_scenes[:int(len(all_scenes) * 0.85)] val_scenes all_scenes[int(len(all_scenes) * 0.85):] train_list [] val_list [] for sc in train_scenes: train_list.extend(scene_groups[sc]) for sc in val_scenes: val_list.extend(scene_groups[sc])这段代码是按场景 ID 分组后再划分能有效避免连拍画面泄漏。实际使用时如果发现场景 ID 规则不适用可以直接用随机打散但要在后面训练时重点观察 val loss 和训练 loss 的差距——如果差距小于 0.02基本可以怀疑有泄漏。4. 用YOLOv8在自己的数据上训练飞机检测模型配置与参数调优4.1 写data.yaml路径、类别数和类别名的正确姿势训练前需要一份 data.yaml 告诉 YOLO 数据在哪、有几类、分别叫什么。注意这里的路径是 YOLO 运行时的工作目录相对路径或绝对路径不是 zip 里的路径。很多人解压后移动了文件夹忘了改 yaml 里的路径结果训练一启动就报找不到图片。# aeroplane_data.yaml path: /home/user/datasets/aeroplane_yolo # 数据集根目录 train: images # 训练图片目录相对path val: images # 验证图片目录 # test: images # 有独立测试集时取消注释 nc: 1 names: 0: aeroplane这里有个细节train 和 val 都指向 images 目录因为划分信息是通过 train.txt/val.txt 传给 YOLO 的。如果你不想用 train.txt也可以把 train 写成train.txt的路径YOLO 会自动读取里面的图片列表。我习惯用目录加文件列表混合的方式train: train.txt这样训练集和验证集的划分完全由我控制不受目录结构调整影响。names 字段的写法要跟标签文件的 class id 严格对应。这个数据集只有 id 0所以在 yaml 里 0 对应 aeroplane。如果你自己扩充了数据加了别的飞机类型比如直升机、无人机记得同步更新 nc 和 names否则类别编号错位会导致训练出来的模型把所有目标都识别成第一个类别。4.2 训练命令与关键参数从模型选型到超参设置环境配置好之后训练命令本身不长但参数的含义和取舍值得说清楚。以 YOLOv8 为例# 训练YOLOv8n输入尺寸640批次大小16训练100轮 yolo train \ modelyolov8n.pt \ dataaeroplane_data.yaml \ imgsz640 \ batch16 \ epochs100 \ patience20 \ device0 \ workers4 \ project./runs \ nameaeroplane_v8n这些参数里最值得调的是 batch 和 imgsz。batch 大小受显存限制在 V100 上可以开到 64在 8GB 显存的消费卡上 16 左右比较稳。batch 太小小于 8时 BN 层的统计量不稳定容易出现 loss 震荡。imgsz 决定输入分辨率。这个数据集的飞机有大量小目标如果框的平均尺寸在 50×50 以下建议把 imgsz 开到 960代价是训练时间翻倍。如果框的平均尺寸在 100×100 以上640 就够。怎么判断回看第 2.3 节的尺寸分布统计结果。epochs 设 100 是起步值。VOC aeroplane 只有几百张图50 轮左右就能收敛100 轮足够。patience 设为 20意思是连续 20 轮 val loss 不下降就提前停止防止过拟合。4.3 预训练权重怎么选yolov8n.pt到yolov8x.pt的取舍用 COCO 预训练权重做初始化是这个数据集训练效果好的关键。COCO 里有 airplane 类别编号 4跟 aeroplane 是同一个东西。预训练权重已经学会了飞机的纹理、轮廓、机翼特征迁移到这个数据集上只需要微调最后的检测头。权重选择遵循一个原则模型参数量越大微调需要的数据越多。这个数据集只有几百张图用 yolov8x 大概率过拟合val mAP 可能反而比 yolov8n 低。我的习惯是先用 yolov8n 跑通流程看 val mAP 是否能到 80 以上如果模型容量不够、漏检严重再换 yolov8s 或 yolov8m。# 对比实验分别在n/s/m三个尺寸上训练用同一份验证集评估 yolo train modelyolov8s.pt dataaeroplane_data.yaml imgsz640 batch16 epochs100 patience20 device0 yolo train modelyolov8m.pt dataaeroplane_data.yaml imgsz640 batch16 epochs100 patience20 device0对比实验跑完用 val 集的 mAP50 和 mAP50-95 两个指标一起看。mAP50 高但 mAP50-95 低说明模型对精准定位能力弱框偏了但 IoU 勉强过 0.5。这两个数差距大时优先检查标注质量很多框本身就不准。5. 飞机检测数据集训练的避坑指南从解压到推理的5个常见翻车点5.1 zip解压后多一层嵌套目录训练路径直接报错现象解压出来的不是 images 和 labels 平铺而是aeroplane_VOCtrainval2012/aeroplane_VOCtrainval2012/images这种双层嵌套。data.yaml 里写path: /data/aeroplane_yolo训练时提示image not found。原因打包的人在 zip 里额外包了一层同名文件夹。这不是数据集本身的问题是打包习惯导致。YOLO 读取图片时会在 train 目录下逐张查找多一层目录它不会自动递归。解决把里层目录整个提到外层或者改 data.yaml 的 path 指向里层目录。我一般直接提目录避免后面做部署时路径拗口。# 把嵌套目录提升一层 mv aeroplane_VOCtrainval2012/aeroplane_VOCtrainval2012/* ./ rmdir aeroplane_VOCtrainval2012/aeroplane_VOCtrainval20125.2 图片里根本没有飞机空标签样本的处理方式现象训练过程中 loss 不稳定验证的时候发现部分图片没有对应的 txt 标签文件或者 txt 文件是 0 字节。原因这个数据集是从 VOC 里筛出来的理论上每张图都有至少一个 aeroplane 标注。但有些提取脚本按“XML 文件名”筛选而不是按“XML 内容是否含 aeroplane”筛选导致一些不含飞机的图片混了进来。解决清洗数据把没有标签的图片从训练集里剔除。注意不是把所有 0 标签图片删掉而是检查它们是否真的属于 aeroplane 样本。# 找出没有标签文件的图片 cd aeroplane_yolo for img in images/*.jpg; do stem$(basename $img .jpg) if [ ! -f labels/$stem.txt ]; then echo missing label: $img fi done如果确实有标签文件但内容为空用脚本检查一下原始 XML 是不是所有目标都是 difficult1 被过滤了。这种情况下要么从原始 VOC 里找回这部分图片要么直接把这几个样本丢弃。数量不多时直接丢弃省事。5.3 边界框坐标越界或为负归一化前的数据清洗现象训练时出现nan loss或者某个 epoch 的 loss 突然爆炸val 时 mAP 一直是 0。原因VOC 原始标注里个别框超出了图片边界。比如 xmax 比图片宽度还大或者 xmin 为负数。直接在归一化时不加处理算出的 w 和 cx 会大于 1 或小于 0YOLO 的 loss 计算里对负坐标做 log 或平方运算就出 nan。解决第 3.2 节的脚本里已经做了裁剪把归一化后的坐标强制限制到 [0,1] 区间。但这种“裁剪”属于补救更稳妥的做法是转换时发现越界就打印警告手工检查那些框是不是标注错误。# 越界检测在转换阶段打印异常框 if xmin 0 or ymin 0 or xmax img_w or ymax img_h: print(f警告: {ann_file} 中有越界框: f({xmin}, {ymin}, {xmax}, {ymax}), 图片尺寸 ({img_w}, {img_h}))越界框的处理要分情况如果只是边界超出几个像素裁剪后直接能用如果超出超过 50% 面积基本是标注人员手滑画错这类样本建议剔除留着只会让模型学习错误的框回归目标。5.4 混淆矩阵总和不是1别慌这是计数矩阵不是概率矩阵现象训练结束后跑yolo val生成的混淆矩阵里所有数字加起来远大于 1有人以为矩阵没归一化或者数据有问题。原因混淆矩阵显示的是“样本数”不是“比例”。每一行代表真实类别每一列代表预测类别单元格里是该类别下的图片数量或目标框数量。如果一张图里有 5 架飞机且全部被正确检出那在 aeroplane→aeroplane 的格子里会记 5 次。总和当然不是 1。解决看混淆矩阵的正确方式是对角线格子的数值是否显著大于其他格子。如果 aeroplane→background 这一格数值很高说明漏检严重如果 background→aeroplane 很高说明误检严重。不要纠结总和要看相对值。5.5 训练过程BN崩溃小数据集上常见的loss炸掉问题现象训练到 20 轮左右loss 突然从 3.0 跳到 100 甚至变成 nan重启训练仍然在类似轮次复现。原因BNBatch Normalization层的统计量在小 batch 下不稳定。这个数据集只有几百张图如果 batch 设成 4 或者 8BN 计算均值和方差时样本太少一个极端样本就可能把统计量带偏。加上预训练权重迁移过来的 BN 参数跟这个数据集的分布不完全匹配容易在某个阶段崩溃。解决把 batch 提到 16 以上或者关闭 BN 的动量更新不推荐影响收敛速度。另一个常用手段是降低初始学习率从默认的 0.01 降到 0.001让 BN 参数缓慢适应新分布。# 用更保守的学习率重新训练 yolo train \ modelyolov8n.pt \ dataaeroplane_data.yaml \ imgsz640 \ batch16 \ epochs100 \ lr00.001 \ patience20 \ device0BN 崩溃还有个特征不是每次训练都崩跟随机种子有关。如果重启后换了随机种子能跑通但结果不稳定说明数据集规模对当前模型容量来说偏小考虑加数据增强YOLOv8 默认开了 mosaic但在这个小数据集上 mosaic 也可能引入不稳定必要时关闭 mosaic 试试。6. 跑通之后怎么验证和进阶混淆矩阵、PR曲线与增量训练6.1 用yolo val拿到mAP50和mAP50-95判断模型真实水平训练完成后用验证集做一次完整评估。这一步不是走形式而是看两个数mAP50 反映“能不能找到飞机”mAP50-95 反映“框得准不准”。# 用训练出的best.pt做验证 yolo val \ modelruns/aeroplane_v8n/weights/best.pt \ dataaeroplane_data.yaml \ imgsz640 \ batch16输出里重点看三个字段mAP50、mAP50-95、Precision。以这个数据集的经验值来说YOLOv8n 在 640 输入下 mAP50 应该能到 90 以上mAP50-95 在 65 到 75 之间。如果 mAP50 低于 80先别调模型回去查数据——大概率是标注框本身就有大量错位或者训练集和验证集划分出现泄漏。6.2 看混淆矩阵和PR曲线哪里误检、哪里漏检yolo val跑完会在runs/aeroplane_v8n目录下生成混淆矩阵图和 PR 曲线图。我每次训练完先看 PR 曲线在哪个置信度区间掉下来。如果曲线在 0.9 附近才开始陡降说明模型对飞机有很高的置信度但有一些 hard example 永远检测不到——这时加数据比调阈值有效。如果曲线从 0.5 就开始慢慢下滑说明模型整体置信度低需要加强特征提取能力比如换大模型或加训练轮数。混淆矩阵里如果 background→aeroplane 那格是 0但同时 aeroplane→background 很高说明模型过于保守宁可漏检也不误检。这在飞机检测场景里不一定坏事——机场运行安全里漏检比误检危险得多。但如果你想做的是航拍图像里的飞机计数这个结果就不可接受需要降低置信度阈值。6.3 进阶在VOC基础上加入自采机场图片做增量训练这个数据集最实在的用法是当底座在上面叠加自己的数据做增量训练。VOC aeroplane 提供了丰富的尺度变化和背景多样性但它是 2012 年的数据机场场景近十年变化很大——新机型的涂装、无人机、廊桥结构这些 VOC 里都没有。自采数据不需要多200 到 300 张标注图就能明显改善模型在目标场景的表现。增量训练的做法把自采图片的标注转成同一种 YOLO 格式放到同一个 images 和 labels 目录下重新划分 train/val 后用yolov8n.pt从头训练。注意不要用之前训练好的 best.pt 继续resume因为新数据的加入会改变类别分布resume 容易在旧模型的基础上固话错误特征。我一般会把自采数据按 1:2 的比例混入 VOC 数据保证模型不全靠新数据漂移。还有一招如果部署目标是边缘设备比如 Jetson训练完把模型导出成 TensorRT 格式的时候会做 INT8 量化量化误差对飞机这种小目标影响很大。建议导出前用验证集里的小目标子集测试量化精度损失如果 mAP 掉了超过 3 个点就用 FP16 部署别强上 INT8。跑完这几个步骤你对这个数据集的掌握程度就超过大多数直接下载就训练的人了。我自己做飞机检测项目时始终保持一个习惯所有的训练实验记录都留一份带参数的命令行包括数据集版本和解压方式。飞机检测的坑不在模型结构而在数据细节版本记不住就是黑匣子复现不出来比训练不收敛更让人头疼。希望这些经验帮到你。本文还有配套的精品资源点击获取
返回列表