简介面向无人机航拍与俯视目标检测场景这套数据集提供5756张真实俯视影像聚焦三轮车与遮阳伞/遮阳蓬三轮车两类小目标标注框总数达20277个覆盖不同光照、角度与街道环境适合用于小目标检测模型训练与算法验证。压缩包共2000个文件内含5756张JPG图片及其对应的VOC格式xml与YOLO格式txt双套标注压缩后整体大小333.84MB。目前已有228人学习/下载。需注意航拍小目标尺寸小、特征弱训练得到的mAP往往偏低属正常现象旨在保证目标可被有效检出数据集部分样本经过增强下载前建议参考博文预览图片确认效果。无论是入门航拍检测还是改进小目标网络这份标注规范、类别明确的数据包都能直接投入训练省去自行标注的时间。1. 俯视场景航拍小目标检测三轮车和遮阳伞车为什么让模型整体翻车很多人第一次跑俯视航拍小目标数据的真实体验是训练 loss 掉得赏心悦目验证集 mAP 却像被钉死了一样。三轮车、遮阳伞车在航拍图里往往只占二三十个像素下采样几次后特征图里连一个完整点都凑不齐。这个 .7z 数据集一共 5756 张、2 类别同时给出 VOC 和 YOLO 两种标注格式专门解决俯视视角 小目标 目标稠密这个三角难题。它适合三类人做无人机巡检、做厂区和路口俯视监控以及在小目标检测调优里反复碰壁的检测工程师。下面我按自己的操作习惯把这份数据从解压、结构检查、坐标换算、训练参数到调优验证完整过一遍步骤尽量写成可以直接复现的命令。2. 拆开这份 5756 张的数据集两个类别的边界、双格式结构和小目标难点2.1 三轮车和遮阳伞车先搞清楚标注边界再训练标题里的“三轮车遮阳伞车”我按两个类别处理一类是三轮车本体另一类是装了遮阳伞、带篷顶的三轮车也就是常说的伞车。很多人在这一步就翻车因为拿到数据不先读标注直接跑训练等模型开始把伞和车身拆得四分五裂时才回头补课徒增返工成本。我拿到一份新数据集的固定动作是随机抽 20 张图叠加标注框连图带框看一遍。重点看四个问题车和伞是合框还是分框。合框的语义是“伞车”分框则会变成两个独立检测目标。前者训练简单后者对模型更有挑战因为伞和车的轮廓往往贴在一起模型要额外学“分开”的能力。目标太小、标注员看不清时框是贴边还是留白。贴边会导致 GT 偏小留白会混入背景两种误差在小目标场景比大目标更致命。密集停放的三轮车如果框互相重叠训练时的 NMS 会遭殃模型很难学会区分两个贴在一起的目标。类别统计是否均衡。用脚本数一下每个类别的实例数量如果伞车远多于三轮车训练时要对少类加权。统计类别可以直接读 VOC 的 XML这类脚本写起来很快import xml.etree.ElementTree as ET from pathlib import Path ann_dir Path(dataset/annotations) counts {} for xml_file in ann_dir.glob(*.xml): tree ET.parse(xml_file) for obj in tree.findall(object): name obj.findtext(name) counts[name] counts.get(name, 0) 1 print(counts)这段代码的核心是用ET.parse逐个打开 XML遍历object节点取name字段计数。如果你发现解压后的包没有annotations目录说明它可能只保留了 YOLO 的 txt统计就要换成读 txt 的cls字段原理一样。这一步输出的数字决定了后面训练时要不要调cls损失权重也决定后续第 5 章里类别不平衡那条坑要不要提前处理。2.2 VOC 和 YOLO 双格式目录结构与坐标系统换算既然标题同时写了 VOC 和 YOLO说明包里至少有两套标注。VOC 是 XML 树YOLO 是纯文本二者的差别不是格式外观而是坐标基准完全不同。VOC 用像素绝对值YOLO 用归一化浮点值训练前必须搞清你手里到底哪个目录对应哪套格式。常见的目录结构一般是三个顶层目录images/放图片labels/放 YOLO 的 txtannotations/放 VOC 的 XML。train 和 val 可能预先分好也可能混在一起自己切。解压后第一件事是列出目录树确认图片数量和标注数量对得上别急著开训。VOC 和 YOLO 的字段对应关系可以直接拿这张表对照字段含义VOC XMLYOLO txt类别nametricycle/name行首数字如 0左上角 xxmin无左上角 yymin无右下角 xxmax无右下角 yymax无中心点 x由 xmin/xmax 算得cx中心点 y由 ymin/ymax 算得cy宽度xmax - xminw高度ymax - yminh换算公式写成代码也就几行cx (xmin xmax) / 2 / img_ww (xmax - xmin) / img_w竖直方向同理。关键在img_w和img_h必须来自真实图片我从不在 XML 里读取宽高哪怕 XML 里本身就写了width和height。因为标注时图片被缩放、旋转过会导致 XML 里的尺寸和实际文件不一致这是坐标越界最常见的前置原因。5756 张图配 2 个类别这个规模对俯视小目标检测来说属于“够做工程验证”的量级。它能帮你稳定跑通一套 baseline、验证增强和调参方向但想一口气达到量产精度通常还要自己再补训练数据。不要把这份数据当万能药把它当成一个起点更现实。2.3 俯视视角为什么三轮车和遮阳伞天然是小目标重灾区COCO 里小目标的常见定义是像素面积小于 32×32或者占原图面积不到 0.1%。在无人机俯视图里一辆三轮车加遮阳伞的投影可能只有 40×30 像素正好踩在小目标区间里。更麻烦的是俯视场景叠了三层 debuff第一层是尺度变化大。无人机高度差个十几米目标在图上就从 80 像素缩到 20 像素模型的多尺度能力不够就会顾此失彼。第二层是目标密集且互相粘连。路口车辆排队停靠时三轮车和伞车紧挨在一起标注框大量重叠NMS 阈值稍微不对两个目标就被压成一个。第三层是缺少立面信息。平视检测能靠车轮、车身侧面辨识车辆俯视只有车顶和伞面颜色和阴影成了主要线索逆光过曝时特征直接消失。这也是为什么俯视小目标检测的调优路径和平视场景差异很大。很多在平视数据集上有效的操作——比如大幅缩小输入图、依赖全局上下文——在俯视小目标上是负优化。后面第 4 章会专门展开参数层面的差异。3. 用 YOLO 格式跑通训练解压 .7z、检查标注、划分数据、写 yaml 开训3.1 解压 .7zWindows 和 Linux 下的命令与路径警告标题里 .7z 是 7-Zip 压缩格式。Windows 上装 7-Zip 后右键解压就能用Linux 下需要 p7zip。解压时最常见的问题是中文路径和空格训练脚本一旦遇到带中文的目录轻则报找不到文件重则读出一堆乱码文件名。我一般直接指定纯英文输出目录# Linux / macOS 下安装并解压 sudo apt install -y p7zip-full 7z x 三轮车遮阳伞车检测数据集.7z -o/home/ubuntu/dataset参数说明x表示解压并保留原始目录结构-o指定输出目录注意-o和路径之间不能加空格。解压完成后先du -sh /home/ubuntu/dataset看容量再tree -L 2看层级确认 images、labels、annotations 三个顶层目录是否存在避免脚本里写错路径。Windows 上如果解压时报 “CRC ERROR”说明压缩包不完整重新下载或换 7-Zip 原版再试别用那种带广告的第三方解压软件硬解容易解出半截文件。3.2 检查标注坐标跑一个脚本过滤坏文件再训练很多人解压完直接训练等到 loss 异常才回头查标注浪费的时间比写检查脚本多得多。我会先花两分钟把 labels 目录全部的 txt 扫一遍确认坐标格式没坏。from pathlib import Path label_dir Path(dataset/labels) bad_count 0 for txt in label_dir.rglob(*.txt): for line in txt.read_text().strip().splitlines(): parts line.split() if len(parts) ! 5: print(f字段数不对: {txt.name}: {line}) bad_count 1 continue cls, cx, cy, w, h map(float, parts) if not (0 cx 1 and 0 cy 1 and 0 w 1 and 0 h 1): print(f坐标越界: {txt.name}: {line}) bad_count 1 print(f异常标注 {bad_count} 条)这段脚本的逻辑很直白YOLO 标注每行必须 5 个字段分别是类别 id、中心点 x/y、宽高全部是 0~1 归一化浮点数。脚本同时检查字段数和归一化范围任何越界都打印出来。如果异常文件很多基本可以断定 VOC 转 YOLO 时图片宽高读错了或者 txt 文件本身是直接从其他格式硬改的要回去重新跑转换。异常少就单独删掉对应文件别让它们进数据集。3.3 划分 train/val一条脚本完成 8:2 切分如果解压出来的包没有预划分我习惯按 8:2 随机划分。划分的绝对原则是图片和同名 txt 必须成对出现在同一侧且验证集要保留足够的少数类样本。下面的脚本用固定随机种子保证可复现。import random from pathlib import Path import shutil random.seed(42) src_images Path(dataset/images_all) src_labels Path(dataset/labels_all) val_ratio 0.2 image_files list(src_images.rglob(*.jpg)) val_names set(random.sample([f.stem for f in image_files], int(len(image_files) * val_ratio))) for split in (train, val): (Path(dataset/images) / split).mkdir(parentsTrue, exist_okTrue) (Path(dataset/labels) / split).mkdir(parentsTrue, exist_okTrue) for img in image_files: txt src_labels / f{img.stem}.txt if not txt.exists(): print(f缺标签: {img.name}) continue dest val if img.stem in val_names else train shutil.copy(img, Path(dataset/images) / dest / img.name) shutil.copy(txt, Path(dataset/labels) / dest / txt.name) print(划分完成)代码要点先收集所有 jpg 的文件主名按 20% 抽验证集名单再逐个图片查找同名的 txt缺标签的图片直接跳过并打印。如果一张图有图无标签宁可不进训练集也不要带着空标签硬训那会让模型把无目标区域学成背景负样本反过来压制真目标。划分完再数一遍 train 和 val 的图片数确认比例和预期一致。3.4 写 data.yaml 并启动训练小目标首选 imgsz1280Ultralytics 系的训练入口是 data.yaml 加一条 yolo 命令。yaml 里固定写路径、类别数、类别名类别顺序必须和 label txt 里的数字 id 一一对应。path: /home/ubuntu/dataset train: images/train val: images/val nc: 2 names: 0: tricycle 1: umbrella_tricycle训练命令yolo taskdetect modetrain \ modelyolov8s.pt \ datadataset.yaml \ imgsz1280 \ batch-1 \ epochs100几个参数我单独解释参数建议值理由imgsz1280小目标在低分辨率下特征被下采样吃掉1280 是性价比最高的一档batch-1 或显存允许的最大值小目标训练需要尽可能大的批损失梯度才稳定epochs100 起俯视小目标收敛慢50 轮通常不够看趋势model预训练权重从随机权重开始等于白训 20 轮去官方 release 下载对应版本即可训练完成后验证一下yolo taskdetect modeval \ modelruns/detect/train/weights/best.pt \ datadataset.yaml \ imgsz1280这里要留意best.pt是按 val 集 mAP 挑的权重不是最后一个 epoch。如果验证集上 mAP 因为小目标居多是 0 或极低别立刻怀疑数据先跳到第 4 章看 imgsz 和增强参数。4. 小目标检测的调参逻辑从输入分辨率到损失函数逐个看收益4.1 输入分辨率是第一收益点为什么 640 到 1280 差了一个量级小目标检测的收益来源排序我的经验是标注质量 输入分辨率 模型容量 损失函数。很多人上来就换模型、换 loss忽略 imgsz 的性价比这是最可惜的浪费。原因在于检测头的感受野与下采样倍数。YOLO 系列检测头通常作用在 8/16/32 倍下采样的特征图上一个 32×32 的小目标经过 32 倍下采样后在最后一级特征图上只剩 1×1 像素。对于俯视的三轮车这 1 个像素是背景和车身的混合监督信号稀薄得可以忽略。把 imgsz 从 640 提到 1280等于把所有目标的特征尺寸翻倍这是结构性的提升不是玄学。代价是显存翻两倍甚至更多。如果显存吃不下 1280就退一步用 960或者把模型换成 nano 档做基线验证。我见过不少人在 640 分辨率下反复折腾模型结构AP 始终卡在个位数一改 imgsz 立刻起来了。这个坑值得每个做小目标优化的人先踩一次。4.2 mosaic 和 fliplr俯视场景下要重新审视的增强参数数据增强里mosaic 对小目标一直是双刃剑。裁剪拼接时小目标被切到 patch 边缘的概率很高标签也跟着被裁掉或缩小模型会学到一堆残缺目标。俯视场景本身目标就小开满mosaic1.0经常是 AP 上不去的原因之一。常见做法是小目标数据集把 mosaic 降到 0.5 左右甚至直接关掉同时用scale增强模拟无人机高度变化。水平翻转fliplr要不要保留取决于场景里车的朝向是否敏感。俯视路口如果左右车道都有车翻转没问题但如果数据本身就集中在单侧车道翻转会引入错误语义。我一般保留fliplr0.5先跑一个 epoch 看 loss 是否稳定再决定。另外补一点hsv_h、hsv_s这类颜色增强对航拍图也有效尤其是逆光场景。但别加太猛俯视目标靠颜色区分色相偏太多会直接把类别搞混。4.3 预训练权重、冻结训练和训练轮数先学轮廓再学细节这个数据集 5756 张量不算大从随机初始化开始训会非常吃力。强烈建议用 COCO 预训练权重起步下载对应版本的.pt文件放到工作目录训练时把model指向它即可。前 10 个 epoch 我习惯冻结 backbone只训检测头。这一步能避免 backbone 一开始就被稀疏的小目标梯度冲乱也让 loss 收敛更慢但更稳。Ultralytics 里用freeze10参数实现。边喂边看验证集 AP等 AP 涨不动再把全部层解冻用lr00.0001的小学习率微调。训练轮数上俯视小目标一般 100 轮起步。如果 100 轮还在涨继续加如果 50 轮 mAP 纹丝不动先别加轮数回头查 imgsz 和标注质量。训练过程像黑匣子但输入端的毛病再多轮数也救不回来。4.4 损失函数和混淆矩阵的常见误解为什么矩阵总和不是 100%换损失函数是大家最爱做的小目标玄学实验。实际情况是YOLOv8 之后的原生 loss 已经把框回归和分类平衡得不错自己改 Loss 复杂度高、收益不确定我很少在第一轮实验里动它。与其改 loss不如先用confusion_matrix_normalized.png看模型错在哪。很多人看到混淆矩阵“总和不等于 1”就以为代码坏了其实一个目标被同时漏检又误检到别的类别时贡献会被分散到多格还有一部分目标被 NMS 直接压掉根本进不了矩阵。所以看矩阵重点是对角线占比、以及“背景”列里有多少漏检不用纠结行和加起来是不是 1。如果漏检集中在背景列说明模型根本没看到目标优先加分辨率或切图如果错误主要是三轮车和遮阳伞之间互相混说明两类特征太近考虑合并类目或补样本。这比盯着一两个 epoch 的 loss 曲线有用得多。5. 踩坑记录跑这个数据集常见的五个事故现场5.1 现象训练几十轮验证集 AP 一直是 0有一次我用默认配置跑一个小目标数据集损失掉得很漂亮结果 AP 全 0。原因说出来很简单imgsz 默认 640目标在图上只有 20 像素下采样 32 倍后特征图里啥都没有模型从头到尾都在学空气。解决就两步imgsz 提到 1280重训如果显存不够把模型换小一号或者先开多尺度。这个坑几乎是俯视小目标数据集的“新手村必刷副本”别觉得自己不会踩。5.2 现象VOC 转 YOLO 后框全飘了loss 曲线乱跳如果我不需要 YOLO 格式的这个包而是自己的 VOC 数据要转过来最常翻车的环节就是读 XML 时把图片宽高搞反。XML 里width和height都在但有人读取时用错变量导致所有 y 方向的中心点和高度算错。血泪经验是转完一定要叠加原图画框检查 20 张图别信脚本输出的数字。解决转换脚本里强制用 PIL 打开图片重新取img.size不要直接信任 XML 里的宽高这一步能挡掉八成的坐标错误。5.3 现象.7z 解压后部分 txt 是空文件或路径带中文导致脚本读不到Windows 上用部分国产解压工具解压 .7z 时碰到文件名带中文容易出现编码乱码轻则文件名变问号重则标注文件损坏。解决Linux 上用 p7zipWindows 上用 7-Zip 原版解压过程中留意输出有没有 warning解压完跑一遍 3.2 的检查脚本把所有 0 字节 txt 列出来找到对应图片看它是真实空标注背景图还是文件损坏。空标注在某些数据集中合法但在训练之前要确认它是故意的。5.4 现象模型把所有目标都预测成遮阳伞车这就是类别不平衡的典型症状。三轮车和遮阳伞车在航拍里大小相近但三轮车数量更少标注框也更小模型为了降低总损失倾向把置信度压在多数类上。解决先统计各个类别的 box 数量把少数类在训练时提高cls权重或者对三轮车类别做过采样把它附近的样本多喂几次。我一般先调cls权重改数据增强成本高且容易引入新噪声留着最后当后悔药再用。5.5 现象逆光、过曝的图上什么都检不出航拍图里大太阳直射时三轮车的蓝色车斗和地面反光混在一起遮阳伞的阴影又跟路面融为一体对比度低到人眼都费劲。这是数据层面的事模型再大也救不回来。解决训练时加对比度增强对 val 集里这类图单独统计一次 AP确认问题到底集中在哪个光照段如果失败样本集中在逆光反向思路是做个简单的 CLAHE 预处理再做推理而不是盲目调模型。6. 进阶把小目标 AP 再往上推的验证技巧6.1 用 SAHI 做切图推理先确认特征还在不在训练完如果对小目标 AP 还不满意先别急着换模型用 SAHI 做切图推理往往马上见效。原理是把大图切成带重叠的 patch比如 640×640 重叠 0.2每个 patch 单独跑模型再把框映射回原图坐标并合并。小目标在 patch 里相对尺寸变大等效于白赚一档分辨率。sahi predict --source val_image.jpg \ --model_type yolov8 \ --model_path runs/detect/train/weights/best.pt \ --slice_size 640 \ --overlap_ratio 0.2 \ --image_size 1280参数说明slice_size越小目标越大但推理时间越长overlap_ratio0.2 通常够用拼缝处漏检多就调到 0.3image_size是 patch 输入尺寸别超过训练时的 imgsz 太多。SAHI 不是银弹密集场景会有重复框需要调 NMS速度也慢但它能帮你快速验证“小目标到底还有多少可分特征”。6.2 用混淆矩阵和 PR 曲线定下一轮改进方向训练完别只看 mAP 一个数。打开runs/detect/train/confusion_matrix_normalized.png如果漏检集中在背景列说明模型根本没看到目标优先加分辨率或切图如果错误主要是三轮车和遮阳伞之间互相混说明两类语义太近考虑合并类目或补样本。PR 曲线则能看出置信度阈值该往哪调高召回低精确时就把 conf 阈值抬高反过来就降。我现在的习惯是拿到俯视小目标数据集先跑一版 imgsz1280 的基线然后看混淆矩阵再决定要不要上 SAHI、要不要换更强的检测头而不是一上来就堆模型。做小目标检测先让特征能被模型看见再谈模型能力这条路最省时间。希望帮到你。本文还有配套的精品资源点击获取