ARTICLE DETAIL

资讯详情

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

YOLO猫狗检测数据集:4300张图片标注与训练全流程解析

YOLO猫狗检测数据集:4300张图片标注与训练全流程解析 做目标检测的人多少都有过这种经历——想跑通一个YOLO项目模型代码网上随手就是一大堆真正卡住你的往往是数据。要么图片尺寸乱七八糟要么标注格式对不上要么类别分布稀碎最后模型没训几次人先崩溃了。我整理并分享的这套猫狗检测数据集有4300张图片完整适配YOLO系列训练流程标注文件、目录结构、数据划分脚本都给你备齐不管是入门练手还是跑算法对比拿过去解压就能开工。这套数据集适合三类人看看刚上手YOLO、想跑通完整训练流程的新手需要快速验证模型改进效果的算法工程师以及做宠物识别、智能家居、安防监控相关项目需要一份干净数据做预研的开发者。文章后面对数据集结构、标注格式、训练脚本、常见坑都会展开讲跟着操作一遍你自己也能独立整理出一份可用的目标检测数据集。1. 数据集设计与思路拆解1.1 为什么是4300张这个规模很多人在收集数据时有个误区总觉得越多越好。但实际上目标检测数据集的规模要和使用场景匹配。COCO数据集118K张图、80个类别那是为了刷榜单、做通用大模型用的单类平均下来也就一千多张。而猫狗检测是典型的二分类检测任务类别少、目标主体明确深度模型在这个规模上完全能学到稳定的特征。4300张这个量级配合合理的划分训练、验证、测试各有充足样本既能保证模型收敛又不会因为数据量太大拉长训练时间。我自己测试用YOLOv8n在单张消费级显卡上跑100个epoch训练时间可以控制在半小时到一小时以内。这个时间窗口非常适合反复调参一个晚上能迭代好几轮模型。1.2 为什么选用YOLO标注格式格式选择是整个数据集设计里最关键的决策。早期做检测常用Pascal VOCXML标注和COCOJSON标注这两种格式可读性好但使用前都得做一步转换。转换脚本很容易出问题坐标归一化、类别id映射任何一个环节对不上训练就直接报错或者损失不下降。YOLO格式是每张图片对应一个同名txt文件每行五个值类别id、归一化后的中心点x、中心点y、框宽度、框高度。说实话这个格式刚开始看会觉得反直觉因为没有任何语义信息但它省去了JSON解析和XML遍历的开销天然适配YOLO从v3到v8所有版本的训练入口。部署时只需要把txt和图片放到约定目录配上data.yaml就能跑通省掉的时间比什么都值。1.3 数据设计里的几个关键决策这个数据集在设计初期有几个明确原则。第一类别只设置cat和dog两个不做品种细分因为细分类会显著增加标注成本而且对目标检测这类任务来说“检测到并定位宠物”比“识别出具体品种”适用范围更广。第二图片场景尽量多样室内、室外、强光、弱光、白猫黑猫、大狗小狗甚至猫狗同框的照片都保留了一部分。第三对遮挡、模糊、目标极小的样本做了筛选而非一律删除因为数据集的目的不只是让模型在“好看”的图上拿高分还要暴露真实场景里的难题。我见过太多“精心清洗”过的数据集所有图片都清晰、正立、目标居中训练出来的模型在测试集上mAP高得吓人一到真实场景就拉胯。差异就出在训练数据没有覆盖真实分布。2. 数据集构成与目录结构解析2.1 目录组织一套可以一直沿用的规范先看整体目录这是最容易让新手迷惑的地方。数据集解压后结构如下cat_dog_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── data.yaml └── split_data.pyimages和labels严格一一对应图片叫IMG_2048.jpg标注就叫IMG_2048.txt。我划分的比例是train约3400张、val约600张、test约300张接近8:1:1。这里的核心逻辑是模型只在train上学习val用来调参和早停test只在最终评估时使用一次。很多人图省事把val和test混在一起最后模型泛化能力行不行心里完全没底。2.2 data.yaml的写法与坑点data.yaml是整个训练流程的总入口YOLO各版本都认这个文件。内容如下path: /path/to/cat_dog_dataset train: images/train val: images/val test: images/test nc: 2 names: [cat, dog]这里有几个容易踩的坑。第一path建议写绝对路径因为不同用户放置目录的位置不一样相对路径换机器之后很容易失效。第二train、val的路径是相对于path的目录不要层层套叠写成images/train/再往上翻。第三names列表顺序必须和标注txt里的类别id严格一致0对应cat、1对应dog一旦写反模型倒是能训练但推理时类别名就彻底对不上了部署环节排查起来会非常头疼。2.3 标注文件的具体形态每张图对应一个同名txt比如IMG_2048.jpg对应IMG_2048.txt。打开一个标注文件内容是这种形式0 0.4321 0.3852 0.2143 0.3017 1 0.6217 0.5605 0.1600 0.2108 1 0.7839 0.4381 0.1286 0.2763第一列是类别id后面四个值是归一化坐标都用图片宽高做了缩放取值必然在0到1之间。这里要特别提醒一句YOLO坐标是中心点加宽高的表示不是以前XML时代习惯的左上角加右下角。如果你用labelImg导出的VOC格式做转换左上加宽高最容易出错的换算公式是x_center (xmin xmax) / 2 / width。中心点坐标忘记除以图片宽高是新手最常见的低级错误。3. 数据集的制作流程与实操要点3.1 图片采集与清洗数据质量从源头决定数据集制作的第一步是图片采集。这一环节很多人当成体力活直接外包但清洗才是真正决定数据集质量的关键。我整理图片时给自己定了三条硬性标准分辨率低于320的不要因为训练时YOLO会自动缩放到640低分辨率图喂进去只会贡献噪声完全重复的不要相似度极高的连拍图也要通过感知哈希筛一遍另外拍摄时间跨度尽量大覆盖不同季节、不同光线场景避免模型学到特定时段的颜色偏移。如果图片来源是网络爬取还要注意版权和批量下载时的图片损坏问题。爬图过程中经常遇到只下载了半个文件的jpg训练时读取不到就跳过但会影响梯度更新的稳定性最好的办法是解码验证一遍能用PIL打开才保留。3.2 标注过程与坐标转换实操标注阶段建议用labelImg或者anylabeling输出VOC格式再写脚本转成YOLO也可以直接用支持YOLO格式导出的工具。这里最耗时间的是对“难例”的判断目标被花盆挡住一半要不要标我的原则是只要人能大致判断出类别就按实际可见范围标注目标被遮挡超过70%的果断放弃。猫狗这类毛色与背景高度相似的样本必须放大图片逐像素确认边界不然模型训练完背景误检会非常严重。转换坐标的脚本核心逻辑如下import os import xml.etree.ElementTree as ET def voc_to_yolo(x1, y1, x2, y2, img_w, img_h): dw 1.0 / img_w dh 1.0 / img_h x (x1 x2) / 2.0 * dw y (y1 y2) / 2.0 * dh w (x2 - x1) * dw h (y2 - y1) * dh return round(x, 6), round(y, 6), round(w, 6), round(h, 6) def convert_annotation(xml_file, txt_file): tree ET.parse(xml_file) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) with open(txt_file, w) as f: for obj in root.iter(object): cls obj.find(name).text if cls not in classes: continue cls_id classes.index(cls) xmlbox obj.find(bndbox) x1 float(xmlbox.find(xmin).text) y1 float(xmlbox.find(ymin).text) x2 float(xmlbox.find(xmax).text) y2 float(xmlbox.find(ymax).text) b voc_to_yolo(x1, y1, x2, y2, img_w, img_h) f.write(f{cls_id} { .join(map(str, b))}\n)注意x2和y2是实际右下角坐标从XML读取后通常要做减一处理公式里的分母是原图宽高而不是416或640。这些细节错了坐标就全部偏移而且YOLO训练阶段不会报任何错误只会表现为mAP异常。3.3 数据划分与统计验证划分数据不能随便shuffle完就结束。我划分的原则是同一个场景、同一个摄像头拍出的连拍图片必须分到同一边。比如一段视频抽帧出来的20张连续画面如果同时出现在train和test里测试结果就会虚高。模型表面看起来泛化能力强其实它只是记住了眼前的场景。我用的方法比较简单提取图片名中的场景标识做哈希再按哈希值分桶保证同一场景绝不跨界。划分完做一次统计验证检查每一类的标注框数量、每张图片平均目标数、标注框面积分布。如果发现狗类框的数量是猫的两倍就要考虑是真实场景如此还是采集有偏差必要时补采。这一步很多人嫌麻烦跳过但等到训练完发现模型对猫的召回率特别低再回头找原因就费劲多了。4. 把数据集跑进YOLO的完整流程4.1 环境搭建与预训练权重选择训练之前先把YOLO环境准备好。我用的是ultralytics仓库一条pip install ultralytics就解决了。这里给个建议优先去官方仓库下载对应版本的预训练权重。YOLOv8系列一般选yolov8n.pt或yolov8s.pt一个是轻量版一个是标准版。像这种数据规模不大、类别简单的任务yolov8n在训练速度和显存占用上都非常友好6G显存的卡也能轻松跑起来。预训练权重的作用是让模型用在大规模数据集上学习到的特征作为起点而不是从零开始初始化卷积核。这样收敛会快一大截前几个epoch的loss下降速度差异肉眼可见。如果网络条件不太方便也要想尽办法提前把权重文件准备好训练到一半发现没有权重再临时下载纯属浪费时间。4.2 训练命令与关键参数解析把data.yaml放到项目目录后执行yolo detect train \ datacat_dog_dataset/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ patience15 \ project./runs几个参数展开说一下。imgsz640是默认值不用动除非你的图片普遍很小或者显存紧张降到416可以加快训练但会损失小目标召回率。patience15是早停参数连续15个epoch验证集mAP没有提升就自动停止能省不少时间。batch要根据显存动态调整6G显存跑16比较稳大显存可以提到32甚至64。训练过程中观察train/loss和val/loss两条曲线正常情况两者都在下降并且差距不大。如果val/loss不降反升基本就是过拟合或者学习率太大可以考虑加数据增强、或者把初始学习率从0.01调低到0.005。4.3 训练结果解读与模型导出训练完有两个重要的产物weights/best.pt和weights/last.pt。best.pt是验证集上表现最好的权重也是最终要用的模型。results目录里的pr_curve.png和confusion_matrix.png建议一定打开看看。混淆矩阵里最能暴露问题的是背景误检部分如果背景类别列上出现明显的值说明模型把非目标物体认成了猫狗大概率是标注时负样本边界没切干净。导出成ONNX做部署命令如下yolo export modelruns/detect/train/weights/best.pt formatonnx imgsz640导出时留意opset版本和输入维度旧版本的部署端框架对动态轴支持不好最好固定输入尺寸。我习惯在导出命令里显式加上imgsz640避免后续转TensorRT或者OpenVINO时多一道麻烦。5. 实测中的常见问题与排查技巧5.1 训练损失不下降先查标注文件新手最容易遇到的情况是loss从第一个epoch开始就纹丝不动。这种问题十有八九出在标注文件上。常见有三类问题坐标值超出0到1区间比如分母用错了图宽txt里有空行或者多余空格解析器读到空内容直接跳过样本类别id超出nc设定的范围模型试图访问不存在的类别索引。排查方法很简单写一个校验脚本遍历所有txt文件检查坐标范围、行数、类别id是否合法import os def check_label(txt_path, nc2): with open(txt_path, r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: return False, 字段数量不为5 cls int(parts[0]) if cls nc or cls 0: return False, f类别id越界: {cls} for v in parts[1:]: if not (0 float(v) 1): return False, f坐标越界: {v} return True, OK4300张图的标注文件跑校验脚本几秒钟就能出结果比肉眼查快得多。5.2 验证集mAP虚高测试集却很惨这是数据集划分不当的典型症状。之前提到过连拍帧被拆散到train和test的问题我确实亲测踩过。解决办法就是按场景分桶避免任何一组时间上连续的图片跨越数据集边界。另外还要检查整份数据里有没有重复图片直接对全量图片计算感知哈希相似度超过0.95的做删减处理。还有一种情况是测试集图片本身和训练集的光照风格差异太大。比如训练集大多是晴天户外测试集却集中在室内暖光灯环境。这种分布偏移单靠随机划分解决不了需要在划分前按场景、光照、环境做分层抽样确保每个子集都有足够的多样性。5.3 BN崩溃与异常loss曲线YOLO训练中偶尔会出现loss尖峰或者batch normalization统计量异常的情况。这问题多出在batch太小、学习率太大或者数据里有大量尺寸极端的目标。当你图片里有一些超长条形物体时标注框的宽高比会非常夸张归一化坐标在宽高比畸变的情况下容易造成梯度异常。实际应对上把batch调大到不低于8初始学习率用默认值别乱调问题基本能规避。如果已经出现了BN崩溃先把训练中断将best.pt重新作为预训练权重适当降低学习率后重新启动一般都能恢复稳定训练不用从头再来。6. 数据集的后续扩展与真实体会数据集的迭代是个长期活一次标注完成不意味着工作结束。我实测过程中会不断把模型在真实场景里漏检、误检的图片补充进来。这类困难样本对模型提升的作用比盲目增加普通图片大得多。我通常的做法是每一版模型在测试阶段专门收集一批它犯错的图手工标注后重新划分形成数据集的新版本每轮迭代模型的短板都能补强一点。另外可以把这套猫狗检测数据集往多个方向扩展。加上更多类别做宠物品种细粒度识别转成COCO格式用于对比实验或者结合OpenCV做简单的实时摄像头检测。我个人使用下来的体会是一份干净、结构规范、类别均衡的数据集在调试YOLO模型时带来的收益往往比闷头调三个月超参数还大。数据准备看似零碎繁琐但它决定了后面所有工作的上限这一环花的时间一分都省不掉。
返回列表