ARTICLE DETAIL

资讯详情

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

4300张猫狗检测数据集:从YOLO训练到部署全流程解析

4300张猫狗检测数据集:从YOLO训练到部署全流程解析 去年有个朋友找我做宠物App的相册自动归类需求说简单也简单用户上传一张照片得知道里面是猫还是狗如果有两只得框出来。真正动手才发现模型结构不用我操心YOLO现成的预训练权重一抓一大把最花时间的是数据——清洗、标注、格式转换、测试集划分哪一步都在磨人。这套4300张猫狗检测数据集就是我在这个过程中整理并反复调优过的结果量级不大但足够把YOLO从训练、评估到部署的全流程走通一遍。如果你正准备训练自己的宠物识别模型或者刚接触YOLO数据集制作这篇文章会把数据集怎么构建、标注怎么做、训练参数怎么调、最后怎么部署到服务器上这些环节全部展开讲。我不会只丢给你一个下载链接而是把为什么做某些选择、踩过哪些坑都写清楚尤其是那些文档里通常不写的细节。1. 数据集定位与整体设计思路1.1 为什么是4300张而不是更多做目标检测的人都知道COCO、ImageNet这种量级的数据集动辄十几万张但那种规模不是普通个人项目能碰的。4300张的量级定位很明确它在“玩具级”几百张和“工业级”几万张以上之间刚好是个人开发者、小型团队或研究生课题里最常使用的量级区间。先说结论在二分类宠物识别场景下用YOLOv8m训练4300张图、每张平均1-2个目标正常能做到mAP50在93%上下mAP50-95在78%-84%之间。这个精度放到实际相册分类场景里已经够用了。如果只有几百张图类别不均衡、光照分布单一、背景重复的问题会很突出模型泛化能力基本靠运气。而几万张图的采集和标注成本个人很难承受。从信息量角度理解深度学习模型本质上是在学习数据分布。4300张图如果是精心挑选、确保场景多样性的它的信息覆盖度会远高于随意爬取的2万张重复图片。我见过不少用8万张低质量数据训出来的模型效果反而不如精心筛选的5000张。1.2 数据构成与目标分布我的数据分布是这样的纯猫图片2000张纯狗图片2000张猫狗同框图片300张总计4300张。同框图在纯猫纯狗之外的占比虽然不大但它非常关键——实际相册里经常出现多只宠物一起入镜的情况如果训练集里完全没有这类样本模型在同一张图有多个目标时很容易漏检。类别标签就两类cat和dog。做宠物识别时不要急着加第三类“其他动物”或“背景”因为背景负样本处理起来非常麻烦容易出现误检后面我会在常见问题部分专门讲这个坑。目标数量方面4300张图里我标注了差不多6100个目标框。平均每张图1.4个实例这个密度对猫狗场景来说是合理的。如果每张图目标太多比如一张图里有十几只狗标注成本和训练难度都会上升如果太少模型学不到多目标场景的处理能力。1.3 目录结构与存储格式我按YOLO标准格式组织文件这个结构可以直接喂给YOLOv5、YOLOv8甚至YOLOv10不需要额外转换catdog_dataset/ ├── images/ │ ├── train/ # 3440张 │ ├── val/ # 430张 │ └── test/ # 430张 ├── labels/ │ ├── train/ # 对应的txt标注 │ ├── val/ │ └── test/ ├── data.yaml └── README.md划分比例用的8:1:1。训练集3440张验证集430张测试集430张。测试集单独留出来非常有必要因为val集在训练过程中会被用来调参和早停模型或多或少会对val集产生一定适应性真正衡量最终效果必须用一次都没见过的test集。data.yaml内容如下path: D:/datasets/catdog_dataset train: images/train val: images/val test: images/test nc: 2 names: [cat, dog]这里有个容易被忽略的点path字段最好写绝对路径或者在训练命令里直接指定datacatdog_dataset/catdog.yaml。如果写相对路径换机器训练时经常出现找不到图片的问题排查起来特别浪费时间。2. 数据采集、清洗与预处理2.1 图片来源与合规性构建数据集的第一步是弄到图。我用的来源主要有三个公开数据集筛选、自己拍摄、以及公开渠道爬取后的人工筛选。公开数据集的优点是精度高但场景通常偏向实验室环境自拍图可以补充特定场景但数量有限爬取的图量大但质量参差不齐需要大量人工筛选。这里必须强调版权意识。如果数据集要用于商业项目尽量使用CC0协议或明确允许商用的来源仅做研究用途则范围稍宽一些。自拍部分是找了几位养宠物的朋友拍的涵盖室内、室外、白天、夜晚等各种环境这些真实场景图对提升模型泛化能力特别有帮助。爬图的时候不要只搜“cat photo”然后下载前几百张完事那样得到的基本是同一类风格的照片。要分关键词、分平台搜索比如“橘猫 阳台”“柯基 草地”“猫 夜间”“狗 雪地”等等。爬完之后做一个直方图相似度去重把几乎一样的图片全部排除掉。2.2 图片筛选标准清洗是比采集更耗时的环节。我筛图的标准大概有五六条整理出来供参考模糊图片必须淘汰。运动模糊、对焦不准、压缩过度的低清晰度图标注困难且训练无益。目标占比过小的图要谨慎。如果一只狗只占全图的2%不到属于小目标范畴初期训练可以先剔除后期如果想专门提升小目标能力再单独挑出来处理。重复度高的图只留一张。同一只猫连拍的几十张里选信息最丰富的那张。极端遮挡的图在初期阶段剔除比如只露一个猫尾巴尖的这种标注困难且容易成为噪声样本。分辨率低于320x320的图直接弃用小图即使放大到640训练也会很糊。筛选完你会发现爬来的10000张图能留下3000张就算不错。这个阶段辛苦点后面训练省心很多。我一个朋友图省事用爬来的图不过滤直接训练结果验证集mAP只有40%后来重新清洗后直接跳到85%数据质量对模型效果的影响就是这么立竿见影。2.3 数据增强策略4300张图不算多所以训练时一定要开启数据增强。YOLOv8默认的增强策略已经不错其中mosaic增强我印象深刻它把四张图拼成一张一次训练相当于同时看到四个场景对提升小目标检测能力、增强模型在部分遮挡情况下的鲁棒性都有帮助。我这么说吧mosaic增强的一个好处是让模型学会在上下文不完整时依旧能辨认目标。因为每张图被切割成四分之一后很多目标只露出一部分模型被迫去学习目标本身的关键特征而不是依赖背景和位置的先验。但mosaic增强不能全程开启。我在训练的最后20个epoch会把mosaic关掉这是从实际训练中验证过的经验。因为mosaic生成的是合成图像和真实单一图像的分布有偏差最后阶段完全用真实分布的数据微调能帮助模型收敛得更平滑。Ultralytics代码里也内置了这个逻辑如果自己写训练脚本别忘了做这一步。3. 标注规范与质量控制3.1 标签定义边界标注质量直接决定模型上限。同样的训练轮次标注严谨的数据集和标注随意的数据集最终mAP可以差10个百分点以上。这就像练字字帖本身就是错的怎么练都白搭。我定义了两条核心标注规范目标整体可见的部分都要框进边界框。比如猫身子在画面内、尾巴露出但能看到完整的头部和身体主体此时边界框覆盖整个可见区域。遮挡面积超过50%的个体可以跳过不标注。如果一只狗被沙发挡了一半只露了个头和前腿这种目标对训练没有明确帮助甚至会让模型学到错误的特征。这里有一个细节值得讨论半遮挡目标到底标不标我的原则是“不完整但可清晰辨认类别”的目标标“只有局部特征且可能造成歧义”的不标。比如露头的猫清晰可见耳朵胡须都在果断标如果只露出一条毛茸茸的尾巴分不清是猫是狗宁可不标也别误导模型。另外不要给猫狗以外的目标加标签。有些朋友顺手把飞过的鸟或者路过的仓鼠也框上了但类别列表里又没有对应的类这会让训练直接报错或者静默忽略白白浪费时间。3.2 标注工具选型标注工具我推荐两个CVAT和labelImg。CVAT是Web端工具功能全支持多人协同、自动标注、预标注导入适合500张以上的项目。labelImg是本地桌面工具轻量化适合快速上手。如果只是二分类任务labelImg完全够用。如果要做更复杂的多类别检测建议直接用CVAT。用CVAT时有个很实用的技巧先跑一个现成的YOLOv8s模型做预标注然后把预标注结果导入CVAT里人工修正。我叫它“半自动标注法”效率提升相当明显。我4300张图的标注量手动从头标估计要50到60个小时用了预标注加修正的方式压缩到25小时左右。预标注的框不一定标准但作为初始定位已经很接近人工只需要拖动边界框调整大小和位置。3.3 二次校验机制标注完之后不要急着训练。花一点时间做二次校验我用的方法是画框可视化检查。把标注结果渲染到图片上然后快速翻看重点关注几类问题框和目标位置有明显偏移目标大部分在框外框太小或太大只框住了猫头或者框是目标实际面积的三倍类别标错把猫标成了狗漏标目标图里有两只猫但只标了一只我这里可以分享一个笨但有效的办法写个小脚本统计每个label文件的目标数量和坐标分布。import os from collections import Counter label_dir labels/train classes Counter() clip_count 0 for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue with open(os.path.join(label_dir, fname), r) as f: lines f.read().strip().splitlines() for line in lines: parts line.split() if len(parts) ! 5: print(f格式错误: {fname}: {line}) continue cls int(parts[0]) x_center, y_center, w, h map(float, parts[1:]) if cls not in (0, 1): print(f非法类别: {fname}: {line}) if w 0 or h 0 or w 1 or h 1: print(f越界框: {fname}: {line}) classes[cls] 1 print(类别分布:, classes)这种统计能快速暴露两类问题一是坐标宽高是否在0到1范围内这个最常见的问题是把像素坐标当成了归一化坐标写进去二是类别分布是否均匀。我第一次标注完发现dog的实例数比cat少了将近20%后来专门补充了狗的数据。4. 基于YOLO的训练全流程4.1 模型选型与算力匹配YOLO版本的选择是个实际工程问题。我测试过YOLOv5和YOLOv8YOLOv5作为经典版本稳定可靠YOLOv8在检测头结构上做了优化实际测试下来YOLOv8m比YOLOv5m在猫狗场景的mAP50-95大约高2到3个点所以我最终选择YOLOv8m作为主力模型。不同型号的对比以YOLOv8为例模型参数量(M)GFLOPs推理速度(640输入)适用场景YOLOv8n3.28.7极快手机端、树莓派等边缘设备YOLOv8s11.228.6快边缘盒子、低配GPUYOLOv8m25.978.9适中中高端GPU服务器YOLOv8l43.7165.2较慢高精度要求、GPU充足YOLOv8x68.2257.8慢追求极致精度选择建议很直接如果你能用GPU且没有极端实时性要求从YOLOv8m开始。n和s在小数据集上很容易欠拟合l和x在这个数据量级上又容易过拟合m是平衡点。如果训练机只是CPU那就老老实实用YOLOv8s虽然精度会低一些但至少能出结果。4.2 训练超参数配置我的训练命令大致如下yolo detect train \ datacatdog.yaml \ modelyolov8m.pt \ epochs200 \ imgsz640 \ batch16 \ workers8 \ optimizerAdamW \ lr00.001 \ patience30 \ cacheTrue \ ampTrue \ projectcatdog_exp \ namem_run1几个关键参数解释一下epochs200但因为有早停机制patience30实际100轮左右就停了。小数据集不需要硬跑满200轮验证集损失连续30轮不降就及时止损。imgsz640是YOLO的默认基准实际推理时可以用640过拟合风险小。如果你的目标尺寸偏小比如远处拍的宠物可以把训练尺寸改成768甚至1024小目标检测会有可见改善。batch16在12GB显存下没问题。如果显存只有6GBbatch降到8不要强行追求大batch。optimizer用的AdamW。这里我要多说两句因为优化器选择直接影响收敛。AdamW在YOLOv8里是默认之一收敛快调参难度低。SGD则对学习率更敏感需要更多人工干预。初学者直接AdamW稳。训练过程中的关键监控点是训练损失和验证损失的曲线。正常情况是两个损失都在下降然后趋于平缓。如果验证损失先降后升而训练损失一直在降说明过拟合开始出现了早停机制会在这里触发。4.3 损失函数的直觉理解说到YOLO的损失函数新手容易被各种名词吓住我这里用大白话拆解一下。YOLO的损失主要由三部分构成分类损失、回归损失、以及分布焦点损失DFL。分类损失负责的是“框里这个东西到底是不是猫/狗”的判断用的是二元交叉熵BCE。回归损失负责“框的位置准不准”YOLOv8里是CIoU系列损失它不仅看预测框和真实框的重合面积还考虑了中心点距离、长宽比差异。DFL是YOLOv8引入的它把边界框坐标建模为离散分布目的是让框的预测更精细尤其对小目标位置的估计有帮助。理解这三部分有什么用很重要。训练时如果发现模型能识别目标但框的位置不准要关注回归损失如果模型框得很准但经常分类错误要关注分类损失。这比盲目调学习率有效率得多。4.4 训练曲线判读与权重选择训练结束后别急着用best.pt先看一下结果曲线。我希望看到的验证集曲线是这样的mAP50持续上升并逐渐平滑验证损失不再明显下降。如果mAP50在80%以下先不要重复加训练轮次应该回头检查数据或标注。权重选择主要看best.pt。Ultralytics的机制是监控验证损失或mAP保存最优模型。但如果你的验证集划分有偏差best.pt可能过拟合到某几类特定场景。稳妥的做法是训练到最后20轮用几个候选权重分别在test集上评估选择test集表现最好的。不要嫌麻烦这一步直接关系到模型真实效果。另外提一个训练中可能遇到的异常BN崩溃。现象是训练过程中loss突然变成nan或巨大数值前提是验证集表现急剧恶化。常见诱因是batch过小小于4或学习率过大导致BatchNorm统计量崩溃。解决手段包括调低学习率、增大batch、关闭AMP混合精度一般能很快恢复。5. 模型评估、导出与部署5.1 评估指标与验收标准模型评估不能只看mAP一个数字。mAP50和mAP50-95的区别要知道mAP50是IoU阈值0.5下的平均精度对框位置不敏感适合快速判断“模型认不认得目标”mAP50-95是在0.5到0.95的不同IoU阈值下加权平均更严格地衡量框定位精度。我的模型在test集上的表现参考如下指标数值mAP500.93mAP50-950.81Precision0.91Recall0.94F10.92这个结果已经不错。不过在实际落地时Precision和Recall的取舍要看具体场景。相册归类场景中误把狗识别成猫比漏识别更让用户不舒服。如果发现Precision偏低可以通过提高置信度阈值来压制误检。我用的是conf0.25做检测部署时可以调到0.4甚至0.5。还有一个重要操作看测试集上的PR曲线以及具体错误样例。直接打印预测框并保存图片到本地肉眼翻看是最直观的验收方式。表格里99的指标不如眼睁睁看几十张测试图的输出更让人放心。5.2 模型导出ONNX与TensorRT模型训练好了要上线跑不能直接在PyTorch环境里跑推理推理效率太低。我的导出链路是PyTorch权重 → ONNX → TensorRT Engine。ONNX导出很简单yolo export modelbest.pt formatonnx imgsz640 opset12ONNX的好处是通用性好可以部署到不同平台上。但ONNX在GPU上运行还是有额外开销想要极致推理速度下一步是转TensorRTtrtexec --onnxyolov8m.onnx --saveEngineyolov8m_fp16.engine --fp16 --memPoolSizeworkspace:2048转成TensorRT FP16后推理速度通常能提升1.5倍到2倍。如果对精度特别敏感可以跑FP32速度相应会慢一些。导出后记得做精度对比验证。TensorRT的FP16量化有时会造成精度轻微下降跑一遍测试集对比mAP如果下降不超过1个点可以接受。5.3 部署性能估算朋友当时问我的问题很典型T4显卡跑1080p每秒25帧的视频流YOLO 640分辨率能支持多少路同时检测这类问题在社区里反复出现因为简单问“支持多少路”很难直接回答——它取决于模型大小、是否用TensorRT、是否批处理、解码方式等。我说下自己的实测与估算经验。假设T4单卡、YOLOv8s、TensorRT FP16、640分辨率单张推理耗时约4到6毫秒。如果每路视频独立串行推理一路25帧每秒需要的推理时间是25乘以5毫秒等于125毫秒理论上单卡可以跑8路左右但GPU占用和显存带宽消耗都会逼近上限建议预留缓冲实际按5到6路规划比较稳。如果走批处理路线情况完全不同。把多路视频的帧按batch4或batch8合并推理GPU吞吐量能提升不少。实测batch8时T4跑YOLOv8s FP16大概能做到25到30路1080p流的实时检测。代价是延迟会增加因为要攒够批量才能一起推理但对视频监控这类非交互场景完全可接受。部署时还有一个细节视频解码和图像预处理也在吃CPU和显存不要全部堆给GPU。用NVIDIA的硬解码或者FFmpeg做GPU解码把CPU留给业务逻辑整体吞吐量比只优化模型推理更明显。5.4 实际部署中的工程注意点我在部署到服务器时遇到过一个经典问题服务端用OpenCV读取图片颜色通道是BGR直接喂给PyTorch的模型推理时颜色乱了结果模型检测率大幅下降。解决方法是推理前做通道转换或者用PIL读取RGB图。这个细节看起来很小但真出了bug排查很崩溃。另一个坑是图像缩放方式。YOLO要求输入是正方形而实际图片是16:9的横图居多直接resize会严重拉伸变形导致目标比例失真。正确处理是letterbox等比缩放后填充边缘保持目标比例不变。Ultralytics库内部已经实现了letterbox但如果你自己写推理脚本一定要记得这个处理。很多自作聪明直接resize导致的精度下降问题根源就在这里。6. 常见问题排查与避坑清单6.1 标注问题导致的漏检误检我训练时最典型的问题场景验证集mAP不错但怎么测都有特定图片漏检。把漏检图片打开看了很多次终于意识到是标注时漏标了目标。比如图里有一只黑色猫蹲在黑色沙发上因为对比度极低标注时人眼都差点看漏模型自然更难学。应对这种暗色目标我重新审视标注规范增加了“低对比度场景必须放大检查再标”的规则。同时改进了一个工作流训练一次后用模型预测训练集把所有置信度低于0.3的预测结果导出来人工复查这个过程中最容易发现漏标的样本。相当于用模型当第二标注员。6.2 类别不平衡与误检处理猫和狗样本整体还算均衡但特定子类别仍然可能失衡。比如橘猫样本特别多黑猫样本少模型学出来对黑猫的召回率就会明显低。同理柯基样本多而大型犬样本少也会导致大型犬识别率偏低。处理不平衡问题优先从数据和标注层面解决补充少样本类别的图片或者从已有图中挖掘更多该类别的目标框。有些开源工具可以做类别重加权但数据层面的补全永远比算法层面的补偿更可靠。如果实在补充不了数据可以调整损失函数里的类别权重让模型更关注样本少的类但效果有限。背景误检是另一个高频问题典型表现是沙发上的一团影子被模型当成猫。原因通常是训练集里缺少“只有背景没有目标”的负样本。对策是额外收集200到300张完全没有猫狗的室内照片加入训练集但注意不标注任何目标框。这一点前面提过负样本对目标检测的泛化能力非常关键。6.3 训练效果不达标的排查顺序如果你的模型训练出来mAP不理想我按排查优先级整理了一张清单顺序排查项说明1标注文件格式检查yolo格式坐标是否归一化2label与image是否一一对应缺失或多余都会报错或静默影响3图片尺寸与质量小图和模糊图占比过高吗4类别分布两个类样本量差距超过30%了吗5数据划分是否同源图片同时出现在train和val6增强配置mosaic关闭之后效果变化第六点值得展开说。如果训练的中后期不小心把mosaic的关闭时间提前了模型可能仍能正常收敛但精度上不去。另外有一种尴尬场景val集划分不合理同一次拍摄的连拍图被同时分到train和val导致val指标虚高真实场景跑起来完全不是那么回事。所以我强调测试集要专门留出并保证与训练集完全无相关性。6.4 部署环境与训练环境的精度差异训练好的模型在测试集上表现稳定部署到生产服务器却发生精度下滑这种坑我碰到不止一次。根源通常是部署时的预处理不一致要么没有做letterbox要么没有保持RGB通道顺序要么Resize的插值算法和训练时不匹配比如训练用的双线性插值而部署时用了最近邻。必须先固定推理pipeline把每一步记录下来与训练时的预处理对齐。对齐后再上量化工具。TensorRT的FP16对精度影响一般在可用范围内但如果你用INT8量化精度下降会更明显一定要量化后重新评估完整测试集而不是只看几个样例。部署运行时出现的推理速度瓶颈很多不是模型本身慢而是数据加载和传输包括图片解码、内存拷贝、结果后处理拖了后腿。建议专门用profiler测一下各阶段耗时往往会发现单纯模型推理只占40%时间另外60%都在图像解码和NMS后处理上。以我个人实际操作的体会来说做目标检测项目最贵的时间成本不是训练是数据准备和调试。4300张猫狗数据集从头到尾整理下来我花了大概两周的业余时间其中标注占了三分之一清洗筛图占了三分之一剩下的时间都消磨在“模型效果不对然后排查数据”的循环里。如果你是从零开始做类似项目建议把时间预算按这个比例规划。最后分享一个很小的技巧训练结束后用模型跑一遍家庭相册或者电脑里随便翻出来的宠物照片比看任何指标都能直观判断这个模型到底能不能用。真实场景的图可能光照、角度、画质都和数据集有偏差这一步检验比test集指标更有说服力。模型该调的继续调如果真实照片上的效果已能接受就果断收工部署上线。
返回列表