尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

YOLOv8宠物识别实战:4300张猫狗检测数据集训练全流程解析

YOLOv8宠物识别实战:4300张猫狗检测数据集训练全流程解析 做宠物识别项目有一阵子了最近整理出一个猫狗检测数据集4300张YOLO宠物识别数据集正好拿来把YOLOv8的整套训练流程重新过了一遍。这个数据集虽然不是什么几十万张的大规模语料但胜在干净、类别集中只有cat和dog两个目标标注也已经是YOLO格式特别适合用来快速验证检测流程、跑通模型训练、做部署性能测试。不管你是刚开始学YOLO的新手还是想快速做一个宠物识别Demo的老手这套数据都值得在手里过一遍。下面我从数据格式、训练参数、踩坑记录到部署推理完整展开聊聊。1. 先盘一盘这个宠物识别数据集1.1 4300张图片到底能干什么4300张图在目标检测领域不算多但对“猫狗识别”这种二分类检测任务来说是性价比很高的量级。像COCO这种数据集有十几万张图训练一次成本高、周期长很多新手电脑跑一轮要一整天而4300张图用YOLOv8n在普通独立显卡上训练一百个epoch大概几十分钟到两小时就能跑完正好卡在“够用”和“跑得动”之间。实际场景里宠物检测的需求非常具体智能宠物喂食机需要判断靠近的是猫还是狗从而决定是否投喂专用粮智能猫砂盆要识别猫的进出动作家用安防摄像头要区分宠物活动和陌生人甚至自动驾驶的辅助刹车系统也要识别突然窜出的猫狗来触发预警。这些任务的共同点是不需要通用目标检测那么宽的类别覆盖面只需要把“宠物”这个目标抓准检测框够稳。所以用这样一个专用数据集起步远比一开始就在COCO上搞全类别训练更聚焦。4300张里猫和狗的目标框数量大致平衡不同品种、毛色、姿态、室内外光照都有覆盖还有不少小目标和遮挡样本。我在第一次跑实验时没有额外增强直接训出来mAP50能到0.90以上用作快速验证、算法竞品对比、前端演示都够了。当然如果你要做的是极端场景——比如只有猫头的特写、夜间红外图像、宠物在剧烈跑动中的运动模糊——那这个数据集的覆盖面肯定不够需要针对性补充素材这我在后面会讲到。1.2 为什么选YOLO标注格式YOLO格式之所以成为社区主流核心是它把目标框做成了“归一化坐标”跟图片分辨率无关。一份标注文件就是一个和图片同名的txt每行代表一个目标五个数字依次是类别索引、框中心点x坐标、中心点y坐标、框宽、框高全部归一化到0~1之间。这样做的好处是模型训练时你随便改imgsz从416到640到1280标注不需要重写。要是用VOC的XML或者COCO的JSON改一次输入尺寸就要重新算一遍坐标或者跑一次转换脚本麻烦是一回事最容易出错的还是坐标转换和类别索引对不上。YOLO格式很好地规避了这两个坑这也是Ultralytics全家桶、各种第三方工具链普遍默认支持它的原因。我见过不少朋友把数据从JSON转成YOLO时报错最常见的就是归一化坐标越界或者类别编号从1而不是从0开始。所以拿到这个数据集最重要的一件事是先确认标注文件里的类别索引和data.yaml里的names顺序一致0是cat还是dog必须盯清楚。这个“顺序一致性”是所有目标检测训练流程里最隐蔽也最致命的细节出了问题模型不会报错只会给你一个看似正常实则废掉的权重。1.3 数据集的预期结构拿到手之后目录结构应该是这样pet_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── pet_dataset.yamltrain和val大约按8:2分。我建议训练前先看一眼train和val各自包含多少个txt确认每个图片都有对应标签避免后期训练时验证集全是空标签导致mAP算不出来。另一个习惯是统计一下每张图的平均目标数正常宠物照片一张大概1到2个框如果某张图出现了十几个框往往是多人混着宠物拍照或者数据漏标要单独抽查。数据集的标注框总数大概在5000多个平均每张图1.2个目标左右。这个数量的好处是正样本密度适中模型训练时既能学到目标特征又不会因为一张图里堆了太多目标导致loss波动剧烈。你在后期做数据增强时也会有比较大的操作空间不至于一增强就把框切坏。2. 数据入坑第一课吃透YOLO标注格式细节2.1 标注文件逐行解读与坐标换算打开任意一个txt内容大概长这样0 0.5241 0.4820 0.1920 0.4680 1 0.8123 0.5931 0.0845 0.1762第一行意思是类别0假设是cat的目标框中心点在图片水平52.41%、垂直48.20%的位置框宽占整张图宽度的19.20%高占整张图高度的46.80%。这种坐标方式不看原图时完全没法脑补位置所以想人工核验必须用一个脚本把归一化坐标还原成像素坐标画出来。换算公式很简单x1 int((x_center - width / 2) * img_w) y1 int((y_center - height / 2) * img_h) x2 int((x_center width / 2) * img_w) y2 int((y_center height / 2) * img_h)x1和y1是左上角x2和y2是右下角。注意归一化坐标里的width和height是“框在图片中的比例”不是像素值。如果你手里正好有一套VOC格式的像素坐标想转成YOLO就用反推公式换过去四舍五入保留6位小数足够。这里还要特别提醒一点YOLO格式的类别索引从0开始。如果数据集中有两个类别索引就是0和1不会出现2。有的转换脚本会把背景算成一个类别导致类别索引整体加1拿到的txt里第一列全变成1和2训练时模型就会懵。这个错误在数据可视化阶段就能发现所以前面说“先看再训”不是浪费时间是在给你省后面几小时的debug时间。2.2 实操写个脚本可视化检查所有标注下载完数据我做的第一件事不是急着开训而是写脚本把训练集和验证集的所有标注框画到图片上按类别换颜色批量保存成带框预览图。这一步花不了十分钟但能帮你发现格式问题。我给一段可以直接跑的检查脚本import cv2 import os def draw_labels(img_dir, label_dir, save_dir, class_names): os.makedirs(save_dir, exist_okTrue) for img_name in os.listdir(img_dir): if not img_name.endswith((.jpg, .jpeg, .png)): continue txt_path os.path.join(label_dir, os.path.splitext(img_name)[0] .txt) if not os.path.exists(txt_path): print(f[警告] 缺少标签: {img_name}) continue img cv2.imread(os.path.join(img_dir, img_name)) h, w img.shape[:2] with open(txt_path) as f: for line in f: parts list(map(float, line.strip().split())) if len(parts) ! 5: print(f[警告] 标注格式错误: {txt_path} - {line.strip()}) continue cls, xc, yc, bw, bh parts x1 int((xc - bw / 2) * w) y1 int((yc - bh / 2) * h) x2 int((xc bw / 2) * w) y2 int((yc bh / 2) * h) color (0, 255, 0) if int(cls) 0 else (0, 0, 255) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.putText(img, class_names[int(cls)], (x1, max(0, y1 - 8)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) cv2.imwrite(os.path.join(save_dir, img_name), img) draw_labels(pet_dataset/images/train, pet_dataset/labels/train, preview_train, [cat, dog])跑完之后随机抽几十张预览图看框是不是贴紧宠物身体、有没有错标、有没有把人的半条胳膊当成狗腿框进去。我做数据标注外包的时候就发现最难处理的往往是黑色狗在暗色背景下的轮廓以及猫蜷成一团时框容易过大。这类问题靠算法很难自动清洗人工抽看是最靠谱的。如果有人觉得逐张看太累也可以按文件名随机抽200张批量拼图一张大图上放十几张小图扫一眼就能覆盖不少样本。关键是这个过程要放在训练之前不要在训完一轮之后才回来翻数据。2.3 数据清洗三步走可视化之后再做三件基础清洗第一删除损坏图片。有些图片文件后缀是jpg但实际内容是坏的用OpenCV读完是None。训练时这种图会让进程直接报错或者被跳过排查起来很隐蔽。可以写几句代码遍历图片目录读不出来的直接移到一个bad文件夹。第二剔除异常标注。解析所有txt凡是坐标小于0、大于1、或者宽度高度为0的都是脏数据。尤其是归一化坐标出现了“宽度大于1”的情况一定是从其他格式转换时分子分母搞反了这类框会导致loss瞬间变大。第三感知哈希去重。数据集里经常混着同一张照片的不同分辨率副本如果不去重训练集和验证集里可能出现完全相同的图片造成mAP虚高部署后泛化能力下降。用dhash算法计算每个图片的指纹再按汉明距离过滤近似重复图保留清晰度高的那张。这一步对从各种渠道拼凑的数据集尤其重要我见过某个数据集里同一个狗狗照片被复制了三十多次训出来的模型对那只狗过拟合严重换个环境完全失灵。3. 用这个数据集训一个YOLOv8检测模型3.1 环境准备与目录组织训练环境用Ultralytics的官方框架就可以了安装特别简单pip install ultralytics然后按前面的目录结构放好数据此时代码和海量配置都不需要管Ultralytics会自动根据目录去读图片和同名txt。出于管理方便我习惯在这个数据集目录下单独放一个data.yaml内容如下path: ./pet_dataset train: images/train val: images/val names: 0: cat 1: dog有人会把nc: 2也写进去实际上Ultralytics会根据names的长度自动推断写不写都不影响。但names顺序一定要和标注里的class_id一致一旦写成0是dog、1是cat模型训练完预测时会自动把猫说成狗这是新手最容易犯的低级错误。检查方法很简单随便打开一个txt看第一列数字到底是0多还是1多再配合可视化脚本里按类别画出的框颜色就能确认对应关系。3.2 data.yaml和训练命令怎么下目录就绪后可以直接用这条命令开训yolo detect train datapet_dataset.yaml modelyolov8n.pt epochs100 imgsz640 batch16 device0 patience20逐项说下参数怎么选modelyolov8n.pt选n是nano版本参数量最小约320万适合快速验证和低功耗部署。如果你的显卡是8GB显存以上直接用yolov8s.pt或者yolov8m.pt精度会有明显提升。imgsz640训练分辨率YOLOv8的默认值。宠物这种中大型目标640够了如果数据里有很多小狗小猫的远距离小目标可以上调到960或者1280。batch16根据显存调整。8GB显存跑yolov8nbatch16很稳batch32可能爆。显存不够就减半batch过小会导致梯度噪声大配合warmup epochs才知道。epochs100对4300张图来说100轮是够的。我实际用到80轮mAP就稳定了设100是给早停留缓冲。patience20验证集指标连续20轮不提升就提前停止防止过拟合还能省时间。这个参数对小数据集特别重要4300张从第40轮开始就可能过拟合。多卡环境可以device0,1单卡就是device0CPU训练强烈不建议一个epoch慢到怀疑人生。这里说的modelyolov8n.pt其实是预训练权重它是在COCO数据集上训好的。用它做初始化而不是从零训练好处是模型已经具备通用的图像特征提取能力比如边缘、纹理、形状结构你在这个基础上微调猫狗特征会远快于随机初始化参数。这也是小数据集能训出不错效果的根本原因。3.3 训练进程观察与结果指标怎么看训练开始后终端会实时打印每个epoch的box_loss、cls_loss、dfl_loss以及precision、recall、mAP50、mAP50-95。我一般重点盯mAP50和验证集loss。mAP50表示预测框和真实框的IoU在0.5以上算作正确检测的平均精度宠物检测这种二分类任务mAP50到0.9以上就已经很好用了。mAP50-95会更严格它把所有IoU阈值从0.5到0.95按0.05步长都算一遍取平均这个指标更能反映框的贴合程度但数值会低很多0.6到0.7对我来说就是健康水平。训练结束后会在runs/detect/train目录下生成一批文件best.pt是验证集指标最好的权重last.pt是最后一轮的权重confusion_matrix.png能直观看出猫狗互相误检的情况results.png是损失曲线、准确率和召回率全程趋势还有F1_curve和PR_curve可以用来判断置信度阈值设多少比较合适。看到mAP50很高先别急着高兴拿best.pt对几张验证集图片跑一下推理看看框的贴合程度和置信度。很多时候指标不错但实际框松垮是因为数据集里的小目标占了多数而mAP50对框的紧贴程度并不敏感。我见过一个项目mAP50到了0.95但部署后发现图片上的框总是比宠物大一圈就是因为标注习惯就是“把宠物连同周边环境一起框进去”数据标注标准直接决定了模型输出的框风格。4. 训练排查实录宠物检测常见的坑4.1 训练Loss不降或爆NaN这个我有亲身经历。有一回用类似数据集训练跑到第30轮loss突然变成NaN后面全部白跑。排查下来原因有几种第一标注文件某一行混入了nan或inf值。模型读入后反向传播梯度是NaN网络权重直接毁掉。这种数据从哪来大多是标签转换脚本在除零或解析空行时生成。解决办法是在数据清洗阶段就过滤所有无法float()的行。第二学习率过大。默认lr00.01在数据集小时还可以但有时候数据噪声大0.01太激进。降到0.005甚至0.001后训练马上稳住。第三图片本身损坏。个别jpg解码出来的数组尺寸异常OpenCV能读但数组有NaN这是极少见的情况排查时把异常图片逐张找出来删掉就行。另外训练时频繁出现“WARNING: corrupt image”这种日志也不要直接忽略。Ultralytics会自动跳过损坏图片但如果跳过的太多一个epoch的实际有效样本量骤降训练结果会莫名其妙地差。确保干净的数据进训练比什么都重要。从损失函数的角度多说一句YOLOv8的损失由box_loss、cls_loss和dfl_loss三部分组成box_loss常用CIoU这一类度量指标来衡量预测框和真实框的重合度。如果某一张图的标注框本身就是错的比如框一个角落或框住两只猫CIoU会给到一个难以收敛的梯度方向反映到整体loss上就是波动变大。所以训练出现异常波动时优先怀疑数据而不是怀疑模型。4.2 mAP0和低级标注错误训练完mAP50显示0这几乎是每个新手都遇到的问题而且九成是低级错误。优先级排查思路如下第一步检查data.yaml的names顺序是否和标注txt里的类别索引一致。比如标注文件里0对应catnames里0也必须是cat一旦对应错模型学到的和文章预期的完全拧着mAP崩成0。第二步检查验证集图片是否都有对应标签。我踩过一个坑训练集标签完整但验证集的labels目录里却少了十几张图的txtUltralytics训练时不会因此报错但验证阶段这些没有标签的图片会被统计为假正例直接把mAP拉低。第三步检查加载的best.pt是不是真的best。训练提前停止或者跑的历史路径里可能残留了旧的best.pt加载错文件后推理效果完全说不通。用训练日志里最后打印的验证指标和best.pt再测一次判断是不是选错权重。还有一种情况是conf和iou设置不当。Ultralytics推理时默认conf0.25如果照片里宠物确实是小目标且拍摄模糊置信度低于阈值就会显示没有任何检测框。这时把conf降到0.1再看看不是模型没训好是阈值挡住了结果。4.3 检测不准的几种场景与针对性优化宠物检测任务里我发现最常翻车的场景就三类第一类小目标。宠物在很远的距离拍照框只有几十个像素。YOLOv8默认在640分辨率下有几个检测层但对特别小的目标依然容易漏检。解决方向有两个训练和推理把imgsz都提到1280或者把图像切片后再推理。增大imgsz最直接代价是显存占用和推理耗时翻倍实测下来mAP50能提升3到5个点。第二类严重遮挡。猫躲在草丛里只露半张脸、狗趴在沙发角落被抱枕挡住一半。这类靠单纯增加样本量很难覆盖全部情况更有效的是重度数据增强用Mosaic把四张图拼成一张让模型学会在遮挡情况下利用局部特征MixUp方法也可以试试宠物图像互相混合后模型更抗噪。第三类光照变化。夜间的猫眼反光、逆光条件下的毛发细节几乎全丢。最优解法是补充红外或者夜间图像素材凑不齐的话就调高HSV色彩增强里的亮度区间扰动相当于人为模拟各种光线条件。我实测把hsv_h、hsv_s、hsv_v各调高10%雨天和黄昏场景的召回率有明显改善。4.4 类别数量不平衡怎么办拿到数据集第一步就应该统计一下两个类别的样本数量。如果cat样本是dog的三倍训练出的模型会天然更倾向于预测猫dog的召回率就会吃亏。处理不平衡有几个常用手段最简单的做法是统计数量后做欠采样把多的那一类随机抽掉一部分让两边数量尽量接近不想丢弃数据就过采样把少的图片通过翻转、缩放、亮度调整生成副本。更高级一点的是在loss层面动手但目前YOLO框架里对类别权重支持比较有限。我一般推荐先欠采样跑一版再用全量数据配合数据增强跑一版对比mAP后来决定最终方案。还有一个容易忽略的点不均衡不仅发生在类别之间也发生在“目标大小”之间。如果数据里全是近距离大头照那模型对远景小目标几乎无感如果全是全身照那对半身特写又不够敏感。所以抽样检查时最好把目标框面积分布也统计出来看看是不是有明显断层在扩充数据时主动补足短板的尺寸区间。5. 从训练到部署顺便聊聊推理性能5.1 数据增强帮你把4300张“变大”4300张原生图片听起来少但Ultralytics训练时默认开启很多在线增强参数默认值作用hsv_h0.015色调扰动hsv_s0.7饱和度扰动hsv_v0.4亮度扰动fliplr0.5水平翻转mosaic1.0四图拼接scale0.5尺度缩放translate0.1平移你不用自己去生成新图模型每读一个batch都会基于原图重新做这些变换实际相当于用了几倍乃至十几倍的有效样本。Mosaic对新手的理解门槛稍高简单说就是把四张训练图按比例缩放到同一个画布上重新组合目标框同步换算到新图上。这个策略能显著提升小目标和遮挡的鲁棒性正是猫狗检测最需要的两种能力。如果默认增强还满足不了任务可以借助albumentations扩展更强变换。比如RandomBrightnessContrast、CoarseDropout模拟遮挡效果、ToGray模拟灰度图预处理一致性和速度上都比直接在Ultralytics源码里改增强参数更灵活。我自己的做法是把源图在训练前用albumentations离线扩充一轮再配合在线增强喂给模型双保险。有人说数据增强就是“无中生有”其实它更像是对真实环境变化的提前演练。宠物检测在落地时面临的相机位置、镜头焦距、光线色温、摄像头传感器差异都能用增强参数模拟一个大概。增强参数不是越大越好调得太过会让模型学到一些现实中不存在的纹理扭曲反而降低精度。5.2 模型导出ONNX和TensorRT训练完best.pt部署场景一般不会再直接用PyTorch权重而是转成更轻量的推理格式。Ultralytics集成了一条命令yolo export modelbest.pt formatonnx imgsz640 opset12导出成ONNX后可以接C推理框架也可以在NVIDIA显卡上再转成TensorRT的engine格式获得FP16推理加速。PyTorch动态图和TensorRT静态图的最大区别是engine针对你的输入shape、显卡算子做了极致优化单帧延迟能压到很低。转换engine的常见做法是通过TensorRT的Python API或者trtexec工具加载ONNX后设置工作空间、精度为FP16如果显卡支持INT8还可以进一步用校准数据压缩体积。这里不展开每一步但你要知道onnx是一个便于移植的中间格式而engine文件绑定特定显卡架构换机器要重新导出。有个细节是导出时如果指定了imgsz640那推理时输入尺寸也必须是640x640否则预处理阶段的resize比例会对不上。如果你希望同一个模型适配多种分辨率导出时不要固定死尺寸或者导出两个engine分别用于720p和1080p画面这样工程上更灵活。5.3 T4显卡能撑多少路视频流有朋友问过“T4跑YOLO 640分辨率检测1080p 25帧每秒能支持多少路”这个问题没有标准答案但可以算出一个靠谱区间。首先明确瓶颈通常是视频解码、图像预处理、模型推理、后处理这几步的总耗时其中模型推理占比最大。以YOLOv8n FP16为例在T4上单帧640x640的推理耗时大约3到6毫秒换成yolov8s大概是8到15毫秒。假设单帧延迟5毫秒那么模型部分每秒最多约200帧。但实际部署中解码头会占CPU资源多路视频流还会产生显存竞争很难达到理论饱和工程上一般按理论算力的1/4到1/3预留余量。所以结论是一张T4用YOLOv8n跑1080p 25fps流大约能支撑30到50路用YOLOv8s的话会降到15到25路。这是在不做跳帧、不做ROI裁剪、不改batch推理的情况下的保守数字。想往上提有几个成熟方向把视频解码放到GPU硬解上、使用批处理推理一次喂入多帧、对画面做ROI裁剪只检测宠物可能出现的位置。我实际做项目时还会给检测加一个时间戳复用的逻辑宠物没离开画面时用历史结果填充能大幅降低真实算力需求。很多项目“看起来目标检测很流畅”背后靠的其实是这种工程层面的取舍单纯堆算力是最笨的解法。如果在算力评估阶段你需要更精确的数字建议先在目标显卡上跑一个自己的压测脚本用摄像头或者视频文件模拟真实码流记录推理耗时和显存占用再按“峰值延迟不超过单帧间隔一半”的标准来规划路数。6. 训练之外这个数据集还能怎么扩展6.1 加一个新类别其实不难如果你想在这个猫狗数据集基础上加一个新类别比如兔子或者鸟不需要重头训练。操作步骤是准备好新类别的图片和标注追加到images和labels目录里把data.yaml的names加上新类权重继续用yolov8n.pt做预训练初始化重新跑训练。这里面有个实际建议因为预训练权重是在包含80类目标的COCO上训出来的其中原本就有猫和狗的语义信息所以即便只有4300张原图迁移学习的成本也不高。新增类别的图片数量如果只有两三百张训练时最好把原始猫狗的图片也一起放进训练集避免模型“忘记”旧类别。这种“灾难性遗忘”在小数据集微调时特别常见加回来的旧数据越多遗忘越慢。6.2 从检测到计数和轨迹跟踪宠物检测框稳定之后你可以继续基于检测结果做两件很实用的事数量统计和轨迹跟踪。数量统计最简单只要统计当前帧里出现的检测框数量就能得到一个近似值再结合时间窗口做去重可以输出“院子里现在有两只猫一只狗”这样的结论。轨迹跟踪则可以引入ByteTrack或者DeepSORT这类简单方案用检测框的中心点做关联给每只宠物分配一个临时ID。有了ID之后进一步做行为识别——比如猫在猫砂盆停留时间、狗在门口的徘徊次数——就都有了底层数据支撑。这个数据集的单帧检测能力作为这些上层应用的前置模块完全是够用的。7. 一些支付得起的经验总结最后还是说点个人习惯。拿到任何数据集我都不急着开训先花半小时把标注可视化、统计分布、清洗脏数据这三件事做完。这个猫狗检测数据集虽然已经比较规整但我每次还是会在训练前单独跑一遍“坐标越界检查”因为一次转发、一次坐标转换失误带来的返工时间远超省下来的那几分钟。另外训练到一半如果发现验证集loss一直不降我习惯去看一下train和val的图片风格差异而不是盲目调学习率。很多时候问题不在算法而在数据本身。比如train里室内场景居多、val里全是户外草坪模型学到的背景特征在验证集上完全不适用这种情况下调什么参数都白搭补充对应场景的数据才是正解。最后一个小技巧是训练时把patience调小一点让它早停然后去翻翻早停时训练了多少轮、验证集指标曲线的拐点在哪。这个信息比闷头跑满100轮有用得多。你会在曲线里看到模型在第40轮就已经收敛后面全是无效振荡这时就该回去调数据增强或者换更大模型而不是加epoch。这个猫狗检测数据集很适合作为YOLO入门练习和宠物识别Demo的起点你在这个基础上加一个新类别、换成自己的宠物照片流程是一模一样的。把数据吃透模型自然就稳了。
返回列表