ARTICLE DETAIL

资讯详情

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

YOLOv8猫狗检测实战:4300张数据集与训练踩坑全记录

YOLOv8猫狗检测实战:4300张数据集与训练踩坑全记录 做目标检测实操的人都有一个共同感受真正卡住你的往往不是模型有多新、论文看了多少而是手头有没有一份干净好用的数据。前段时间我整理了一套猫狗检测数据集一共4300张标注好的宠物图片格式直接对齐YOLO训练所需拿来就能训宠物识别模型。为了把这套数据的价值发挥到最大我专门跑了一轮完整的YOLOv8训练流程从数据检查、目录整理、参数配置到踩坑修复都过了一遍。这篇文章就围绕这套4300张宠物识别数据集的真实内容、训练方法和扩展思路展开适合正在找数据集做毕设、刚入门目标检测、或者想快速验证YOLO整套流程的同学参考。1. 这份4300张的宠物识别数据集动手前先看清家底1.1 量级与类别分布猫狗样本的平衡情况数据集一共4300张图片覆盖猫和狗两个类别。很多人在拿到数据集后第一件事就是直接开训这是不对的。我的习惯是先做一次类别统计搞清楚两个类别各占多少因为类别极度不平衡会让模型严重偏向多数类在验证集上看似还行一到真实场景就露馅。我写了一个简单脚本统计标签分布import os from collections import Counter label_dir labels/train counts Counter() invalid_count 0 for txt in os.listdir(label_dir): with open(os.path.join(label_dir, txt)) as f: lines f.readlines() if not lines: invalid_count 1 for line in lines: parts line.split() if len(parts) ! 5: invalid_count 1 continue cls int(float(parts[0])) counts[cls] 1 print(类别统计:, counts) print(空标签或异常标签文件数:, invalid_count)从整体上看这套数据的猫狗比例大致均衡狗略多一点属于可接受范围。即便比例稍有偏差也可以在训练阶段通过权重调整或者采样策略来处理不会对模型造成致命的偏向。1.2 图片来源与场景分布真实场景比“证件照”值钱得多这套数据集的图片大多来自日常拍摄场景家里客厅、小区道路、公园草地、宠物医院等而不是纯白底的商品图。这一点对训练目标检测模型来说非常关键。检测模型要学的是“猫在沙发上、狗在草丛里”这种带背景干扰的语义特征而不是“一个物体孤零零站在画面中间”。背景越多样模型的泛化能力越强。另外图片里包含了不少姿态变化和遮挡情况侧躺的猫、背对镜头的狗、被主人抱在怀里的宠物、半截身子被桌子挡住的猫。这些样本虽然在标注时更费劲但对模型抗遮挡能力的提升帮助很大。一张图只有一个目标的占比不小但多目标同框的图也有这直接决定模型能不能学会“一张图里同时检测出三只猫”。1.3 标注格式YOLO标准的txt文件长什么样这套数据集的标注文件遵循YOLO格式每张jpg图片对应一个同名的txt文件。txt文件里的每一行代表一个目标框格式是class_id x_center y_center width height这里需要特别强调x_center、y_center、width、height四个值全部是归一化坐标取值范围在0到1之间不是像素坐标。归一化的好处是不管图片是800像素还是2000像素标注都不受影响训练时模型会自动处理不同分辨率。比如一个标签文件里有这么一行0 0.442708 0.531250 0.229167 0.593750意思是类别0假设是猫目标中心点在图片的44.27%宽度、53.12%高度位置框的宽度占整张图片宽度的22.92%高度占整张图片高度的59.38%。这里有一道浅显的换算题如果图片宽度是960像素那么框的实际宽度就是960×0.229167≈220像素。理解这个换算关系非常重要因为后面做标签检查、数据清洗时很多异常问题都要靠这个公式反向推断。1.4 目录结构标准YOLO训练格式我拿到数据集后第一件事就是把目录整理成YOLO官方训练器认识的格式。标准结构如下pet-dataset/ ├── images/ │ ├── train/ │ │ ├── cat_001.jpg │ │ ├── dog_001.jpg │ │ └── ... │ └── val/ │ ├── cat_015.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── cat_001.txt │ │ ├── dog_001.txt │ │ └── ... │ └── val/ │ ├── cat_015.txt │ └── ... └── data.yaml如果你的原始数据集没有预先划分train和val就需要自己动手切分。我通常按9:1的比例做随机划分测试集不单独留因为YOLO训练时val既承担验证又承担测试的角色。划分的时候务必固定随机种子保证可复现。2. 用这套数据训练YOLOv8猫狗检测模型从环境到命令2.1 环境准备别在这些小事上浪费时间训练YOLOv8最省心的路径是直接用ultralytics这个Python库它把模型定义、训练器、数据加载、评估工具全部封装好了。安装命令很简单pip install ultralytics建议Python版本在3.9以上PyTorch版本在2.0以上。显卡驱动和CUDA务必提前确认好因为这些基础环境问题一旦出错排查起来比训练本身还耗时。我习惯在干净的环境里操作不要在一个已经装了几十个包的Python环境里直接装深度学习库依赖冲突会让人崩溃。推荐用conda建一个独立环境conda create -n yolo python3.10 conda activate yolo pip install ultralytics2.2 编写data.yaml训练的核心配置文件data.yaml是YOLO训练最关键的文件模型全靠它找到图片、标签和类别定义。我给这套猫狗数据集写的配置如下# data.yaml path: /your/absolute/path/pet-dataset train: images/train val: images/val nc: 2 names: 0: cat 1: dog有几个细节需要特别注意path字段必须写绝对路径或者相对路径的前缀路径train和val填写相对于path的路径。names列表的顺序必须和标签文件里的class_id一一对应。如果标签文件里0是猫names里第0个位置就必须是cat写反了就是灾难这个坑后面单独讲。nc表示类别总数这里是2。多写或者少写都会在训练时报错。2.3 训练主命令参数怎么选才合理我用的训练命令如下yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs120 \ batch16 \ imgsz640 \ optimizerAdamW \ lr00.001 \ projectruns \ namecat_dog_v8n \ seed42逐个解释关键参数的选择逻辑modelyolov8n.ptn代表nano是YOLOv8系列里参数量最小的版本。为什么选它而不是yolov8x原因很简单4300张图片的量级对模型容量是有约束的。大模型在数据量不够的情况下非常容易过拟合训练集上mAP能到99%验证集上却惨不忍睹。小模型反而学得更稳训练速度也快适合这套数据量。epochs120目标检测模型在这个数据量下120轮足够收敛。跑完可以看训练曲线如果val loss在最后20轮还在明显下降再适当增加。batch16这是根据显存来的。yolov8n是轻量模型batch16在6GB显存左右的卡上可以跑。如果你的显卡只有4GB就降到8甚至4。batch越小梯度的噪声越大训练稳定性会差一些所以尽量往大了开。imgsz640YOLOv8默认训练分辨率是640x640。这个值决定了模型最终能检测到多小的目标。如果后续要检测大图上的小宠物建议用736或832但代价是训练速度和显存占用都会上涨。2.4 显存占用估算开训前就算清楚很多刚接触YOLO的同学在训练报错OOM显存不足之后才手忙脚乱。其实完全可以在开训前做个粗估。yolov8n在imgsz640时模型权重本身只占不到30MB真正的显存大头是中间层的激活值和梯度。一个实用的经验值yolov8n imgsz640 batch16大约需要6GB显存batch8时大约4GB如果降低到imgsz480batch16大约只需要3.5GB。如果你的显卡只有8GB建议直接采用batch16 imgsz640的组合既能让模型看到足够丰富的上下文信息又不会爆显存。如果显存实在不够优先降batch而不是降imgsz因为分辨率对检测精度的直接影响比batch大小更大。2.5 训练输出产物跑完你该关注哪些文件训练结束后ultralytics会在project/name目录下生成一堆文件我最关心的有这几个文件/目录作用我的使用习惯weights/best.pt验证集上mAP最优的权重最终推理、部署都用它weights/last.pt最后一个epoch的权重继续训练时用它作预训练results.png训练曲线总览快速判断有没有过拟合confusion_matrix.png混淆矩阵可视化定位类别混淆问题train_batch0.jpg训练集增强后的batch样本检查数据增强是否合理3. 模型训完了怎么判断它能不能用3.1 训练曲线判读loss曲线和mAP曲线背后的信息打开results.png第一件事不是看mAP而是看train_loss和val_loss两条曲线的走势。这四张loss曲线分别对应box回归损失、分类损失、DFL损失。如果三条val曲线在训练后期和train曲线之间出现明显拉开说明已经开始过拟合。此时哪怕mAP还在微涨继续训练的意义也不大应该回退到验证集mAP最高的那个epoch也就是用best.pt。我遇到的情况是前20轮两类loss快速下降中间60轮稳步下降最后40轮趋于平稳。这说明120轮的设置比较稳妥既给了模型充分的学习时间又没拖到过拟合爆发。3.2 mAP指标到底该怎么看训练日志里会显示mAP50和mAP50-95两个值很多初学者搞不清楚它们的区别mAP50IoU阈值0.5下计算的平均精度。只要预测框和真实框有50%以上的重叠就算检测成功。这个指标衡量的是“目标有没有找到”。mAP50-95IoU从0.5到0.95之间取多个阈值分别计算AP再取平均。这个指标对框的定位精度要求极高更严格。用生活化的比喻mAP50看的是“你抓到猫了没有”mAP50-95看的是“你圈的那个框有多准”。日常demo可以只看mAP50如果要做工程项目mAP50-95才是真正决定系统能不能上线的指标。我训练的结果大致在mAP50接近0.95mAP50-95在0.8左右。这个水平对4300张图片的数据集来说已经相当健康。3.3 用没见过的图片做实测指标再好都是统计意义上的我习惯在训练结束后跑到网上下载几张完全没参与训练的宠物图片或者直接拿手机拍我自己家猫用训练好的模型推理yolo predict \ modelruns/cat_dog_v8n/weights/best.pt \ source./test_images \ conf0.25 \ saveTrueconf是置信度阈值低于这个值的检测结果会被过滤掉。实际部署时conf可以适当提高到0.5减少误检但调试阶段用0.25可以看到模型更全面的表现包括一些低置信度的预测方便发现潜在问题。实测过程中我还会故意放进一些难样本逆光拍的猫、只露出半个头的狗、趴在猫爬架高处的猫。如果这些都能稳定检出说明模型学到的是“猫狗的本质特征”而不是只会识别特定角度的模板。3.4 检查单张图片的预测完整度对于检测模型还有一个容易忽略的点每张图到底检出了几个目标。如果预测结果的框数量明显少于真实目标数说明模型存在漏检。可以写一段脚本对比每张图片的真实标签目标数和预测目标数快速找出系统性漏检的场景比如“猫在远处的小目标”或是“黑白猫在黑背景里”。这个检查能直观看出现在这套数据可能在哪些场景下掉点为我后续扩充数据指明方向。4. 实际训练过程里我踩过的坑完整排查链路4.1 标签里有非法坐标训练直接nan第一次训练跑到第9个epochloss变成了nan整个模型直接崩掉。我第一反应是学习率过高把学习率从0.001降到了0.0001重跑还是nan。后来逐行检查训练日志发现问题根本不是学习率而是数据源头出了问题。排查过程是这样的我先写脚本扫描全部标签文件检查是否存在空文件、类别id越界、以及坐标值明显超过[0,1]区间的情况。扫描结果发现两个异常一是某个txt文件里宽度直接写成了0这意味着框没有面积损失函数对它计算时会产生除零问题二是有一个文件的x_center写成了2.13超出了归一化范围极坐标框在特征图映射时到处都是错位。修复方式是对标签做一次全量清洗清除非法行并对超过边界的坐标做裁剪import os def clean_label(txt_path): with open(txt_path) as f: lines f.readlines() cleaned [] for line in lines: parts line.split() if len(parts) ! 5: continue cls, x, y, w, h map(float, parts) if w 0 or h 0: continue # 裁剪到[0,1]区间 x min(max(x, 0.0), 1.0) y min(max(y, 0.0), 1.0) w min(max(w, 0.0), 1.0 - x) h min(max(h, 0.0), 1.0 - y) if w 0 or h 0: continue cleaned.append(f{int(cls)} {x:.6f} {y:.6f} {w:.6f} {h:.6f}) with open(txt_path, w) as f: f.write(\n.join(cleaned)) label_dir labels/train for name in os.listdir(label_dir): if name.endswith(.txt): clean_label(os.path.join(label_dir, name))清洗后重新训练nan问题彻底消失。这个坑在从网络上下载的各种数据处理脚本生成的数据集里非常普遍。很多数据集的标签是用脚本自动化生成的没有任何质量审核环节有相当概率存在坐标越界、空框、类别id溢出等问题。4.2 EXIF方向信息导致标签错位还有一个隐蔽的坑来自手机拍摄图片的EXIF方向信息。手机拍照片时相机会把方向信息写进EXIF头而图片本身的像素方向不变。这就导致一个问题如果你用图片浏览器打开看到的是正着的猫但是当你用OpenCV或者其他图像库直接加载这张图时实际读到的是旋转了90度或者180度的画面标注框自然就对不上了。我一个哥们儿曾经用一套手机直拍的数据集训练YOLO模型输出结果完全离谱。排查到根因时发现问题出在他预处理阶段没有处理EXIF方向信息。而据说有些自动标注工具在导出标签时也可能基于已经被旋转过的画面计算坐标让偏移变得更难发现。解决方式简单粗暴把所有图片先做一次标准化用PIL的ImageOps.exif_transpose把方向信息重新编码到像素层面然后重新保存from PIL import Image, ImageOps img Image.open(problem_photo.jpg) img ImageOps.exif_transpose(img) img.save(fixed_photo.jpg, exifimg.getexif())处理后不管原图EXIF方向信息是什么读取到的像素方向都是一致的。这里提供一个快速自查方法从数据集中随机挑几张明显有方向问题的图片在专业绘图软件里和用OpenCV分别打开对比是否一致。一致则说明EXIF问题不复存在。4.3 类别顺序写反模型“指猫为狗”这个坑最隐蔽也是最容易让人精神内耗的。data.yaml里names列表的顺序必须严格对应标签文件里的class_id。如果原始数据集的标注脚本把0定义为dog、1定义为cat而你在data.yaml里写成了0对应cat、1对应dog那么模型在数学上依然能正常收敛训练指标甚至非常漂亮但是实际推理时所有检测结果都会反转。排查过程是这样的训练完成后我在验证集上抽查了推理结果发现模型把猫全部标成狗把狗全部标成猫。第一反应是模型坏了后来仔细对照data.yaml和标签文件才发现是类别定义顺序错了。这个坑的通用排查方法训练前随机抽取30个标签文件打印每个文件第一行的类别id然后和图片实际内容做人工比对确认类别映射正确后再开训。这五分钟检查能避免一整轮无效训练。4.4 模型整体偏置数据不平衡带来的隐患虽然这套数据集整体做了基本平衡但如果你在迭代过程中增删了样本就可能破坏平衡。比如你为了增强某一类样本复制了500张猫的图片数据量变成猫2400、狗1900模型就会逐渐偏向猫。处理这种不平衡有几种做法在损失函数层面给少数类提高权重采用欠采样/过采样策略做有针对性的数据增强只对少数类做更强的变换让它“看起来像更多张图”。我实际操作中发现最有效的方式其实最简单训练前先统计类别占比然后适当复制少数类样本。这不优雅但管用。4.5 混淆矩阵的正确读法训练完成后生成的混淆矩阵很多人只会看对角线。对角线代表分类正确的比例但要特别注意猫和狗之间的混淆项。如果混淆矩阵里狗被误判成猫的比例偏高除了类别不平衡往往还和图片本身特征有关很多宠物狗的长毛造型确实和猫有相似之处。看懂并分析这个矩阵对后续数据扩充很有指导意义可以针对性收集“容易混淆”的样本而不是盲目增加普通样本。5. 4300张只是起点如何系统性扩充这套数据5.1 数据增强不是简单的“翻转旋转”YOLOv8内置了一套非常强的数据增强策略包括Mosaic、MixUp、随机透视变换、HSV色彩扰动、随机翻转等。Mosaic会把4张训练图片拼成一张让模型在小目标检测和遮挡场景下有更好的表现。MixUp则是把两张图按比例混合目标框也跟着混合相当于免费送了一批“过渡样本”。但增强也不是越猛越好。增强过强会导致训练集和真实数据分布偏离越来越远模型在验证集上反而掉点。我的经验是使用默认增强基本就够只在训练轮数增加时适当调整不要一上来就手动叠加一堆额外增强。5.2 半自动标注扩展自己的数据如果你觉得4300张不够想扩充自己的场景数据完全不需要从零手工标注。我的工作流是这样的用这套数据集训练出一个baseline模型收集目标场景的图片比如夜间监控画面、宠物医院柜台照片用训练好的模型对这批图片自动预测生成初步标签人工检查和修正自动预测的框把修正后的样本并回训练集再训一轮。这个流程下一个人的精力一天可以清理一千张图。相比于纯手工标注效率能提升一个量级。关键是迭代过程中每轮的模型都比上一轮强大所以后续自动生成的标签质量会越来越高。5.3 向更大的公开数据集借力除了自建数据还可以借力公开数据集里的猫狗类别。比如COCO数据集里包含cat和dog两个类别Open Images里也有大量宠物图片。把这些类别的图片和标签提取出来和自己已有的数据合并可以在不动手拍照的前提下快速扩充数据规模。具体做法就是把COCO格式的标签转换到YOLO格式。这里有一个现成的公式YOLO格式的目标中心点坐标x_left width/2框宽width同理中心点y坐标y_top height/2框高height最后把所有值除以对应图片实际宽度和高度完成归一化。合并后建议重新做一次类别分布统计和标签清洗严格按第4章提到的流程走一遍。5.4 真实场景下的边界在哪里坦然认识这套数据的局限性这套4300张数据集用来跑通流程、做毕业设计、做产品原型完全够用。但如果要做一个上线的宠物识别服务你得正视它的几个边界品种多样性有限。数据集中常见宠物品种较多但小众品种某些巨型犬、无毛猫的样本覆盖不够。极端姿势样本少。纯俯视、纯仰视、高速运动模糊下的宠物在这套数据里占比不高。夜间或弱光场景缺乏。大部分图片都是日间正常光照下的拍摄。多个宠物互相遮挡比如两只猫挤在一起的复杂交互场景模型表现会明显下降。面对这些边界我的建议是把这套数据当作“地基模型”真正落地时围绕第5.2节的方法在你的真实部署场景里定向补充数据。这样才能确保模型在你的具体环境里面表现稳定。最后再聊一点个人经验。4300张这个量级对入门学习和毕设验证来说属于比较理想的起点。数据量不大训练一轮的时间可控可以反复试错。我在实际使用中的顺序是先用它把所有流程跑通确认模型选型和训练参数合理然后再拿着自己收集的新场景图片做半自动标注补充效果提升非常直观。有一个习惯建议大家从第一天就养成拿到任何数据集先别急着开训花十五分钟做一次标签正确性和分布统计再随机挑几张图把标签画上去人工检查。这套流程我在每次训练前都会做一遍看起来很琐碎但每一次都替我省掉了后面排查问题的几个小时。数据检查的时间永远花得比训练和调参时间更值。
返回列表