1. 为什么我要做这个数据集系列
做目标检测这行的人都有一个共识:模型结构翻来覆去就那些,真正拉开差距的是数据。YOLO系列从v5一路迭代到v8、v9、v10,甚至社区里已经在讨论v26这种概念版本,但不管版本号怎么跳,你喂给它的数据质量决定了模型能力的上限。我见过太多人花两周调网络结构,结果mAP涨了不到一个点;也见过有人只是把标注框重新清洗了一遍,同样的YOLOv8配置直接涨了五个点。这就是数据的威力。
这个系列我打算做成一个长期更新的合集,每期精选10个数据集,覆盖不同的应用场景和难度层级。第03期选出来的这10个,是我最近半年在多个实际项目中反复用过、或者深度验证过的。它们有的适合入门练手,有的直接能上工业级项目,有的则是特定垂直领域的稀缺资源。不管你是刚配好Anaconda环境准备跑第一个YOLOv8训练的新手,还是已经在做小目标检测、实例分割甚至三维目标检测的老手,这一期里应该都能找到对你有用的东西。
先说一下我的筛选标准,免得你觉得我是随便凑数。第一,标注质量必须过关,我实际抽检过至少20%的样本,框的贴合度和类别一致性要达标;第二,场景要有代表性,不能全是COCO那种通用数据集,得有垂直领域的硬货;第三,获取门槛不能太高,要么直接能下载,要么有清晰的申请流程,不需要你折腾半天环境还拿不到数据。这三个标准筛下来,最终留下了这10个。
2. 第03期精选数据集逐个体检
2.1 农田无人机语义检测数据集
这个数据集是我今年做农业项目时挖到的,专门针对无人机航拍场景下的农田语义检测。它包含约8000张高分辨率航拍图,标注覆盖了作物行、田埂、灌溉设施、杂草区域等类别。和普通的航拍数据集不同,它的拍摄高度集中在30到80米之间,这个高度区间恰好是大多数农业无人机作业的典型范围,所以训练出来的模型直接部署到实际作业设备上,迁移损失非常小。
标注格式原生是COCO格式,但你完全可以用脚本转成YOLO需要的txt格式。我实测下来,转格式的时候要注意一个坑:这个数据集的图片尺寸不统一,有4000x3000的,也有5472x3648的,直接resize到640会丢失大量小目标信息。我的做法是先用滑动窗口切图,切成1024x1024的patch,重叠率设20%,然后再转YOLO格式。这样处理之后,小目标的召回率比直接resize高了将近18个百分点。
注意:切图的时候一定要保留原始图片的坐标映射关系,否则后面做推理结果还原的时候会对不上。我一般会在文件名里嵌入patch的左上角坐标,格式是
原图名_x0_y0.jpg,这样后处理脚本直接解析文件名就能还原。
2.2 烟草病虫害检测数据集
烟草种植区的病虫害检测是一个很典型的细粒度目标检测问题。这个数据集包含约12000张田间拍摄的烟草叶片图像,标注了蚜虫、烟青虫、黑胫病斑、赤星病斑等8个类别。难点在于病虫害的形态差异很大,同一种病害在早期和晚期的视觉特征完全不同,而且田间光照条件极其多变。
我用YOLOv8m在这个数据集上跑过一轮基线,原始mAP50只有0.62左右。后来做了两件事把指标拉到了0.79:一是用Mosaic增强的时候把尺度抖动范围从默认的0.5到1.5扩大到0.3到2.0,让模型见到更多尺度变化;二是针对病斑这类小目标,把检测头的anchor尺寸重新聚类了一遍。这个数据集特别适合用来练习小目标检测的调优技巧,因为它的目标尺寸分布非常极端,大的病斑能占图片三分之一,小的蚜虫只有十几个像素。
2.3 泥石流滑坡目标检测数据集
地质灾害监测是目标检测一个比较冷门但需求很刚性的方向。这个数据集收集了西南山区多个监测点位的边坡影像,标注了泥石流堆积体、滑坡后壁、裂缝、松散堆积物等类别。总共约5000张图,分辨率从1080P到4K不等。
这个数据集的特殊之处在于,它的负样本比例很高。大概有40%的图片是纯背景,没有任何标注目标。很多人拿到之后第一反应是把这些负样本删掉,但我建议你保留。地质灾害场景里,误报的代价非常高,模型必须学会区分“看起来像滑坡但其实是正常山体”的情况。我训练的时候会把这些负样本按1:3的比例混入正样本,让模型在训练阶段就见到足够的困难负例。实测下来,保留负样本的模型在实地测试中的误报率比删掉负样本的低了将近一半。
2.4 燃气管道图像数据集
城市地下燃气管道的巡检是一个高风险场景,这个数据集包含管道内窥镜拍摄的图像和地面标识桩的图像,标注了管道腐蚀、接口渗漏、标识桩破损、第三方施工侵入等类别。数据量不算大,大概3000张左右,但每一张都经过专业巡检人员复核,标注精度非常高。
这个数据集我主要用来做两件事:一是训练管道缺陷检测模型,二是做数据增强的实验。因为它的标注质量高但样本量少,非常适合测试各种增强策略的效果。我试过用Copy-Paste增强把缺陷目标复制到正常管道背景上,扩充了大概3倍的数据量,mAP从0.71提升到了0.83。但要注意,Copy-Paste的时候要匹配光照方向和透视关系,否则生成的图片会有明显的违和感,模型反而学不到有用的特征。
2.5 鸟类目标检测数据集
鸟类检测在生态监测和机场驱鸟两个场景下都有强需求。这个数据集包含约15000张鸟类图像,覆盖了200多个鸟种,标注了鸟类的边界框和关键点(头部、尾部、双翅)。关键点标注是这个数据集的亮点,你可以用它来训练姿态估计模型,也可以只用边界框做纯检测。
我拿这个数据集做过一个比较有意思的实验:用YOLOv8的pose分支同时做检测和姿态估计,然后在推理阶段用姿态信息过滤掉误检。比如有些背景纹理被误检成鸟,但它的关键点分布不符合鸟类的解剖结构,就可以直接滤掉。这个后处理策略在测试集上把误报率降低了约30%。如果你只做检测不做姿态,也可以把关键点信息用来做数据增强的约束条件,比如旋转增强的时候保证关键点的相对位置合理。
2.6 小目标检测专用数据集
小目标检测是YOLO应用中最头疼的问题之一。这个数据集专门为小目标检测设计,包含约20000张图像,目标尺寸集中在8x8到32x32像素之间,覆盖了航拍车辆、监控行人、遥感舰船等场景。它的标注策略和普通数据集不同,对于密集小目标区域,标注人员用了点标注加辅助框的方式,确保每个目标都被标出来。
用这个数据集训练的时候,输入分辨率是关键。我试过640、1024、1536三个档位,640下mAP50只有0.41,1024下到了0.58,1536下能到0.64。但1536的推理速度在单卡上只有不到15FPS,实际部署要考虑硬件条件。我的建议是训练用1536,推理用1024加切片推理(SAHI),这样能在精度和速度之间取得比较好的平衡。另外这个数据集的目标太密集,NMS的IoU阈值要调低,我一般设0.3到0.4之间,默认的0.45会漏掉大量相邻目标。
2.7 三维目标检测数据集
三维目标检测和二维检测的逻辑完全不同,这个数据集包含激光雷达点云和对应的RGB图像,标注了车辆、行人、骑行者等类别的三维边界框。数据量约10000帧,每帧都有点云和图像的时间同步。虽然YOLO本身是二维检测器,但你可以用这个数据集做多模态融合的实验,比如把点云投影到图像平面生成深度图,作为YOLO的额外输入通道。
我试过用YOLOv8加一个深度分支,把点云投影的深度信息作为第四通道输入,在KITTI风格的评测下,三维检测的精度比纯图像方案高了约12%。但这个方案的计算开销也上去了,推理时间增加了约40%。如果你的场景对实时性要求不高,这个思路值得一试。另外这个数据集也可以用来做二维检测的预训练,因为它的图像标注质量很高,而且场景多样性好。
2.8 遥感旋转目标检测数据集
遥感图像里的目标往往不是水平放置的,飞机、舰船、车辆都有各种朝向。这个数据集包含约8000张遥感图像,标注了旋转边界框,覆盖了飞机、舰船、油罐、桥梁等类别。原生格式是DOTA格式,你需要用专门的工具转成YOLO能用的格式。
这里要重点说一下,YOLOv8原生不支持旋转框检测,你需要用YOLOv8-OBB版本或者MMRotate这样的框架。我一开始用MMRotate跑DOTA数据集,环境配置折腾了整整两天,各种版本冲突。后来换成YOLOv8-OBB,虽然功能没有MMRotate那么全,但胜在环境干净、训练稳定。转格式的时候要注意,DOTA的标注是8个点的多边形,YOLO-OBB需要的是中心点加宽高加角度的格式,转换脚本里角度定义要和框架保持一致,否则训练出来的框全是歪的。
2.9 人脸检测数据集
人脸检测是目标检测里最成熟的方向之一,但这个数据集有它的独特价值:它专注于复杂场景下的人脸检测,包含大量遮挡、侧脸、小尺寸人脸、极端光照的样本。数据量约30000张,标注了人脸的五个关键点。
我用这个数据集做过YOLOv8的人脸检测基线,在WIDER FACE的验证集上Easy难度能到0.94,Medium到0.91,Hard到0.82。Hard难度的提升空间还很大,主要瓶颈在小尺寸和严重遮挡的人脸。我的调优经验是,针对这个数据集,把YOLOv8的P2层特征图利用起来非常关键,因为P2层的感受野更小,对小脸更敏感。但P2层会显著增加计算量,你需要权衡。
2.10 通用目标检测数据集
最后一个是一个通用目标检测数据集,包含约50000张图像,覆盖80个常见类别,标注格式原生就是YOLO格式,拿来就能用。它的特点是场景分布非常均匀,室内室外、白天夜晚、不同天气都有覆盖。我一般用它来做两件事:一是新模型的快速验证,二是作为其他垂直领域数据集的预训练基础。
这个数据集的质量在开源数据集里属于中上水平,标注框的贴合度不错,但也有一些明显的漏标。我建议你在使用前先跑一遍标注一致性检查,用现有的YOLO模型做推理,把高置信度但无标注的区域挑出来人工复核。我这么干的时候发现了大概3%的漏标,修正之后模型在验证集上的表现有可感知的提升。
3. 数据集处理与YOLO训练实操流程
3.1 从下载到YOLO格式的完整转换
拿到一个数据集之后,第一步永远是搞清楚它的目录结构和标注格式。我见过太多人直接开始写训练脚本,结果跑了一半发现标注没转对,白白浪费几个小时。我的标准流程是这样的:先看数据集根目录下有没有README或者标注说明文件,确认标注格式是COCO、VOC、YOLO还是自定义格式;然后用tree命令或者文件管理器看一下目录层级,确认图片和标注文件的对应关系;最后抽10张图,用LabelImg或者VSCode的YOLO插件打开,肉眼确认标注框的位置是否正确。
格式转换的核心逻辑其实很简单:不管原始格式是什么,最终都要转成每张图片对应一个txt文件,每行是类别id 中心x 中心y 宽 高,所有坐标都归一化到0到1之间。COCO格式转YOLO的脚本网上很多,但要注意COCO的bbox是x_min y_min width height,转的时候要先算中心点再归一化。VOC格式是x_min y_min x_max y_max,转的时候先算宽高再算中心点。这些细节看起来简单,但写脚本的时候一不留神就会搞错。
# COCO转YOLO的核心代码片段 import json from pathlib import Path def coco_to_yolo(coco_json, output_dir, img_width, img_height): with open(coco_json) as f: data = json.load(f) # 建立类别id到连续id的映射 categories = {cat['id']: idx for idx, cat in enumerate(data['categories'])} for ann in data['annotations']: img_id = ann['image_id'] cat_id = categories[ann['category_id']] x, y, w, h = ann['bbox'] # 计算归一化中心点和宽高 cx = (x + w / 2) / img_width cy = (y + h / 2) / img_height nw = w / img_width nh = h / img_height # 写入txt文件 txt_path = Path(output_dir) / f"{img_id:012d}.txt" with open(txt_path, 'a') as f: f.write(f"{cat_id} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}\n")提示:转换完成后一定要做一次反向验证,随机抽20张图,把YOLO格式的标注画回图片上,肉眼确认框的位置和类别都对。这一步花不了十分钟,但能帮你避免后面几个小时的无效训练。
3.2 YOLOv8训练配置的关键参数
YOLOv8的训练配置看起来简单,但有几个参数对结果影响巨大。我拿一个实际项目举例,数据集是上面提到的烟草病虫害数据集,12000张图,8个类别,用YOLOv8m训练。
首先是imgsz,默认640。但这个数据集里小目标多,我试了640、896、1024三个档位,最终选了1024。显存占用从8G涨到了14G,但mAP50从0.68涨到了0.76。如果你的显存不够,可以用rect模式训练,把图片按长边缩放到imgsz,短边按比例缩放,这样能减少padding带来的无效计算。
然后是batch,这个要根据显存来定。1024的imgsz下,24G显存的卡可以跑到batch=16,12G的卡只能跑到batch=8。如果显存不够又不想降imgsz,可以用梯度累积,batch=8配合accumulate=2等效于batch=16。但要注意,梯度累积会稍微影响BN层的统计量,如果效果有下降,可以把BN换成SyncBN或者GroupNorm。
学习率方面,YOLOv8默认的lr0=0.01在大多数情况下是合理的,但如果你的数据集很小(少于5000张),建议降到0.001到0.005之间,否则容易过拟合。我一般会先用默认参数跑50个epoch看loss曲线,如果训练loss下降很快但验证loss开始上升,就把学习率降一半再跑。
# YOLOv8训练配置示例 model: yolov8m.pt data: tobacco.yaml epochs: 200 imgsz: 1024 batch: 8 accumulate: 2 lr0: 0.005 lrf: 0.01 momentum: 0.937 weight_decay: 0.0005 warmup_epochs: 3 mosaic: 1.0 mixup: 0.1 copy_paste: 0.1 degrees: 10.0 translate: 0.1 scale: 0.5 shear: 2.0 perspective: 0.0 flipud: 0.0 fliplr: 0.5 hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.43.3 数据增强策略的取舍
数据增强是提升YOLO性能最划算的手段,但用错了反而会掉点。我的原则是:增强策略必须匹配实际部署场景的变化维度。比如你做的是固定摄像头的监控场景,那翻转、旋转这些增强就要慎用,因为实际推理时不会出现翻转的图片。但如果你做的是无人机航拍,那旋转增强就非常必要,因为无人机可以在任意角度拍摄。
Mosaic增强是YOLOv8默认开启的,它把四张图拼成一张,能显著提升小目标的检测能力。但Mosaic有一个副作用:它会让模型对目标的位置分布产生偏差,因为拼接后的目标总是出现在图片的四个象限附近。我的做法是在训练的最后20个epoch关掉Mosaic,让模型在真实分布上做最后的微调。这个技巧在多个数据集上都帮我涨了1到2个点。
Mixup和Copy-Paste是更激进的增强,适合数据量少或者类别不平衡的场景。Mixup把两张图按透明度混合,能提升模型的泛化能力,但会模糊目标的边界,对小目标不友好。Copy-Paste把目标复制到其他背景上,对稀有类别特别有效,但要注意背景的语义合理性,别把船复制到沙漠里。
3.4 训练过程监控与早停策略
YOLOv8训练的时候会输出一堆指标,但真正需要盯的就几个:train/box_loss、train/cls_loss、val/box_loss、val/cls_loss、metrics/mAP50、metrics/mAP50-95。我的经验是,如果train/box_loss持续下降但val/box_loss开始上升,说明过拟合了,要么加数据增强,要么降学习率,要么直接早停。
早停的patience参数我一般设30到50。设太小容易在指标波动的时候误停,设太大又浪费时间。我通常会同时看mAP50和mAP50-95,如果连续30个epoch这两个指标都没有创新高,就手动停掉。另外,YOLOv8的best.pt保存的是验证集上表现最好的权重,但有时候last.pt在测试集上反而更好,所以两个都要留着,最后在独立的测试集上对比一下。
注意:验证集和测试集一定要严格分开,而且测试集在训练过程中绝对不能碰。我见过有人把测试集当验证集用,调出来的模型在真实场景里一塌糊涂。正确的做法是:训练集70%,验证集15%,测试集15%,测试集只在最后评估的时候用一次。
4. 常见问题与排查技巧实录
4.1 标注格式转换的典型错误
标注转换是问题最多的环节,我整理了一个速查表,覆盖了最常见的几种错误。
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 训练loss不下降 | 类别id从1开始而非0 | 检查txt文件第一列 | 所有类别id减1 |
| 框全部偏左上 | 坐标未归一化 | 检查数值是否在0-1之间 | 除以图片宽高 |
| 框宽高颠倒 | 宽高顺序写反 | 对比原始标注格式 | 确认是xywh还是xyXY |
| 部分图片无标注 | 图片和txt文件名不匹配 | 对比文件名列表 | 统一命名规则 |
| 类别混乱 | 类别映射不一致 | 检查data.yaml的names | 重新生成映射表 |
我踩过最坑的一次是COCO转YOLO的时候,忘了处理iscrowd字段。COCO里有些标注是iscrowd=1,表示这是一群目标而不是单个目标,这种标注在YOLO里应该被忽略或者特殊处理。我当时没管,结果模型学了一堆模糊的大框,mAP掉了将近10个点。后来在转换脚本里加了过滤条件,只保留iscrowd=0的标注,问题就解决了。
4.2 训练不收敛的排查思路
训练不收敛的原因很多,我一般按这个顺序排查:先看数据,再看配置,最后看代码。数据方面,检查标注有没有越界(坐标小于0或大于1)、有没有空标注文件、有没有类别id超出范围。配置方面,检查学习率是不是太大、batch是不是太小、warmup是不是不够。代码方面,检查数据加载的预处理有没有问题、损失函数有没有用对。
有一个很隐蔽的问题是图片损坏。有些数据集里的图片下载不完整,用肉眼看不出来,但用OpenCV读取的时候会返回None。YOLO的训练脚本遇到这种图片可能会静默跳过,导致实际训练的数据量比预期少。我的做法是在训练前跑一个脚本,用cv2.imread遍历所有图片,把读取失败的图片和对应的标注文件都删掉。
import cv2 from pathlib import Path def check_images(img_dir): bad_files = [] for img_path in Path(img_dir).glob('*.jpg'): img = cv2.imread(str(img_path)) if img is None: bad_files.append(img_path) # 同时删除对应的标注文件 txt_path = img_path.with_suffix('.txt') if txt_path.exists(): txt_path.unlink() return bad_files4.3 小目标检测的专项调优
小目标检测是问得最多的问题,我单独说一下。除了前面提到的提高输入分辨率、用P2层特征、切片推理之外,还有几个技巧值得一试。
第一个是调整anchor。YOLOv8虽然是无anchor的,但它的检测头还是有先验的尺度分布。如果你的数据集里目标尺寸和COCO差异很大,可以在训练前用k-means重新聚类一下,把聚类结果写到配置里。我试过在遥感数据集上重新聚类,mAP50涨了3个点。
第二个是修改损失函数。小目标的IoU计算对位置偏移非常敏感,同样的像素偏移,小目标的IoU下降比大目标快得多。可以用WIoU或者EIoU替代默认的CIoU,这两种损失对小目标的梯度更友好。我在小目标数据集上对比过,WIoU比CIoU的mAP50-95高了约2个点。
第三个是后处理。小目标的置信度普遍偏低,默认的conf=0.25会漏掉很多真实目标。我一般会把推理时的conf降到0.1,然后用类别相关的阈值做二次过滤。比如车辆类可以设0.3,行人设0.15,这样能在召回和精度之间取得更好的平衡。
4.4 从训练到部署的衔接问题
训练出来的模型最终要部署到实际场景,这里有几个容易忽略的问题。首先是输入尺寸,训练用1024不代表推理也要用1024。如果部署设备的算力有限,可以在推理时用640,但精度会下降。我的做法是训练用1024,导出ONNX的时候用640,然后在验证集上对比一下精度损失,如果可接受就用640部署。
其次是预处理的一致性。训练时的归一化、通道顺序、颜色空间,推理时必须完全一致。我见过有人训练用RGB,推理用BGR,结果模型完全失效。YOLOv8的导出脚本会自动处理这些,但如果你自己写推理代码,一定要仔细核对。
最后是NMS的参数。训练时的NMS参数和推理时可能不同,特别是做切片推理的时候,切片之间的重叠区域会产生重复检测,需要调大NMS的IoU阈值或者用NMS的变体(如Soft-NMS)。我一般会在部署前用一批真实场景的图片做端到端测试,把NMS参数调到最优。
5. 数据集使用的经验与建议
5.1 数据集组合的策略
单一数据集训练出来的模型往往泛化能力有限,我通常会组合2到3个数据集一起训练。组合的时候要注意类别对齐,不同数据集的类别定义可能不同,比如有的数据集把“轿车”和“卡车”分开,有的合并成“车辆”。我的做法是建一个统一的类别表,把各个数据集的类别映射过去,映射不上的类别要么合并要么丢弃。
组合的另一个问题是数据量不平衡。如果一个数据集有50000张图,另一个只有2000张,直接混合训练会让模型偏向大数据集。我的做法是给每个数据集设一个采样权重,小数据集的权重调高,大数据集的权重调低,让每个epoch里各个数据集的样本量大致均衡。YOLOv8的data.yaml里可以配置多个数据路径,但采样权重需要自己写脚本控制。
5.2 标注质量的快速评估
拿到一个新数据集,怎么快速判断标注质量?我的方法是:先用一个在COCO上预训练的YOLOv8模型跑一遍推理,把置信度高于0.5但和标注框IoU低于0.3的检测结果挑出来。这些就是潜在的漏标或者错标。然后人工复核这些样本,如果错误率超过5%,这个数据集就需要重新清洗。
另一个方法是看标注框的尺寸分布。如果某个类别的框尺寸方差特别大,说明标注标准不统一,有的人标得紧,有的人标得松。这种数据集训练出来的模型,框的贴合度会不稳定。我一般会统一标注标准,要么都标紧(只框目标主体),要么都标松(包含部分背景),不能混着来。
5.3 数据集的持续迭代
数据集不是一次性的工作,而是一个持续迭代的过程。模型部署之后,会遇到训练集里没有的场景,这些bad case就是下一轮迭代的数据来源。我的做法是建一个bad case收集管道,把线上推理置信度低或者人工复核发现错误的样本自动收集起来,定期做标注补充。
补充数据的时候要注意,新数据和旧数据的分布不能差异太大,否则模型会遗忘旧知识。我一般会把新数据和旧数据按1:3的比例混合,然后用较小的学习率做微调。如果新数据的分布和旧数据差异很大,比如从白天场景扩展到夜间场景,那就需要更大的学习率和更多的训练轮次。
提示:每次迭代都要保留一个固定的测试集,这个测试集不参与训练也不参与验证,只用来做版本对比。这样你才能客观地判断新版本是不是真的比旧版本好。
5.4 数据集使用的合规注意事项
最后说一下合规问题。使用公开数据集的时候,一定要看清楚它的许可证。有些数据集只允许学术研究使用,不能商用;有些数据集要求你在发表论文时引用特定的文献;还有些数据集对衍生作品的分发有限制。我一般会在项目文档里记录每个数据集的来源和许可证,避免后面出问题。
如果是自己标注的数据集,要注意隐私保护。特别是人脸、车牌这类敏感信息,要么做脱敏处理,要么确保标注和使用符合相关规范。我做人脸检测项目的时候,所有训练数据都做了模糊化处理,只保留检测框的位置信息,不保留原始人脸图像。
这一期整理的10个数据集,覆盖了从农业到安防、从二维到三维、从通用到垂直的多个方向。每个数据集我都实际跑过训练,上面提到的参数和技巧都是实测有效的。数据集的选择和使用没有绝对的标准答案,关键是要匹配你的实际场景和部署条件。我个人的经验是,与其花时间找“完美”的数据集,不如把手头的数据集吃透,把标注质量做好,把增强策略调对,这些基本功比什么都重要。