
简介面向使用YOLOv5开展目标检测的学习者与开发者这份测试数据集聚焦图像中的人、猫、狗三类常见目标可用于检验模型训练效果、验证算法精度也可作为入门实验数据快速跑通数据标注与模型推理流程。压缩包为zip格式整体约53.53MB共501个文件包含200张jpg测试图片、100个xml标注文件及201个txt标签/说明文件图片与标注可配套使用适合直接用于YOLOv5测试或二次实验。目前已有770人学习下载资源体量轻便于个人电脑开展小规模检测实验。资源完整保留了原始信息可用于数据划分、格式转换或类别扩展是测试模型性能、对比预测结果的一份实用数据集。1. yolov5测试数据集一张测试图三行命令人猫狗全框出来有朋友往我这边丢了几百张照片说想用yolov5测试数据集跑一遍看看能不能把图像里的猫狗和人都框出来。结果他自己按教程跑完人的框很稳猫狗漏了一半。问题基本出在测试集的组织方式和检测参数上不是模型不行。这个标题做的事情很具体准备一套测试图片用yolov5模型对图像做推理识别出人、猫、狗三类目标并输出带坐标的检测结果。它解决的是两个问题——验证预训练模型在真实图片上的表现以及给后续训练自己的检测模型建立基线。适合刚跑通yolov5、想验证效果的人也适合要做行人检测加宠物识别的从业者。整个流程不需要训练不需要标注入手门槛比想象中低得多。2. 为什么这个测试可以零训练直接跑预训练权重、80类标签与detect推理链路2.1 COCO预训练权重里本来就有人、猫、狗类别索引对照yolov5官方发布的预训练权重是在COCO数据集上训练出来的COCO的80个类别里正好包含person、cat、dog这三类分类编号分别是0、16、17。所以拿官方yolov5s.pt这个权重直接对测试集做检测天然就能识别人猫狗完全不需要自己标注数据再训练一轮。这一步是很多人没想明白的地方——总以为要跑yolov5训练自己的数据集才叫用yolov5其实纯推理验证一条命令就能完成。有个坑必须提前讲清楚只有在使用官方预训练权重时类别索引才和COCO一一对应。如果你用的是别人在自建数据集上训练好的权重那类别编号完全取决于他训练时的data yaml配置可能第0类是人也可能第0类是别的。所以拿到一个.pt文件先别急着跑看一眼它配套的类别文件确认0、16、17是不是人猫狗。常见做法是把官方权重直接放在weights目录下然后命令行里用--weights yolov5s.pt引用跑测试集时再加一个--classes 0 16 17让检测器只输出这三类过滤掉汽车、餐桌之类无关框。2.2 yolov5推理链路从图片到输出框三个关键阶段理解了权重来源再来看模型内部是怎么把一张测试图变成一组框的。yolov5的推理流程大致分三段这对后面排查漏检和误检很重要。第一段是预处理detect.py会把输入图片等比缩放到默认640x640多余部分用灰色填充这个过程叫letterbox目的是不让图片变形第二段是网络前向backbone负责提特征neck做多尺度融合最后head在三个尺度的特征图上各预测一组候选框第三段是后处理把候选框解码、按置信度过滤、送进NMS去重最终输出满足条件的框和类别。这三段里最容易出问题的是第一段和第三段。比如你喂进来一张4000x3000的超大图它照样会被压成640x640再推理小目标被压缩后就只剩几个像素漏检很正常。反过来如果你想让模型看得更细直接把--img-size调到960或1280就能改善小目标召回。第三段里的置信度阈值和NMS阈值直接决定你看画出来的框是宁缺毋滥还是宁可错杀。另外如果你做目标检测调试时想看特征图和热力图来判断模型关注区域yolov5的hook也能在推理时拿到每一层feature map这个属于进阶验证手段后面章节会提到用法。2.3 测试集与验证集的分工为什么单独准备一套没见过的图片严格来说机器学习的评估集要分成验证集和测试集验证集用来调参、选模型测试集只在最后评估一次。但在这个标题的场景里没有训练环节我们用的预训练权重早就定型了所以测试集承担的是行为确认——确认模型在我们收集的真实图片上的表现能不能达到预期。它不需要太大一百张精心挑选的图片就比一千张随手爬的图更有说服力。这里有个业内常见的翻车点很多人拿网上随便下的图片做测试集结果图片里带水印、带边框、带拼图模型识别良莠不齐最后把误检漏检全怪到模型头上。我在准备测试集的时候会刻意排查掉这些脏数据同时保证图片在时间、地点、光线、拍摄设备上有一定变化这样的测试结果才能反映模型在真实场景下的水平。如果你后面打算继续做yolov5训练自己的数据集这套测试集也能直接拿来当最终评估集不用重新攒图。3. 准备测试数据集目录结构、图片命名和多样性检查清单3.1 测试集目录怎么组织detect.py的source参数才读得省心yolov5的detect.py接收--source参数它支持单张图片、整个目录、视频文件、摄像头和RTSP流。最常见的做法是准备一个纯图片目录比如data/test_imgs/把测试图片统一放进去然后--source直接指向这个目录。这里有一个我的习惯值得抄图片尽量摊平放不要嵌套多级子目录。虽然部分版本能递归遍历但摊平之后目录结构一眼能看清后续统计数量、排查缺失文件都方便。再一个硬约束是路径和文件名。测试集目录路径不要带中文图片文件名不要有空格、不要有中文统一用小写字母、数字、下划线命名。Windows和Linux在中文路径下的glob匹配偶尔会有编码问题报错信息特别隐晦排查起来很费时间。我一般会让文件名带上场景信息比如indoor_night_001.jpg、outdoor_day_002.jpg跑完检测后看文件名就能知道哪类场景漏检率高不用再翻原图。目录结构上强烈建议单独建一个runs输出目录不要让每次检测的默认输出runs/detect/exp、exp2越堆越多到后面根本分不清哪次是哪次。3.2 一个Python脚本快速体检测试集数量、格式、损坏文件收集完图片之后不要急着跑检测先写一个十几行的脚本把测试集体检一遍。我见过有人辛辛苦苦攒了三百张图跑detect.py时报Not found or empty dataset查了半天发现里面有几十张0字节的损坏文件还有几张是webp格式不在默认支持列表里。这个脚本用OpenCV读图片读不出来的直接剔除顺便统计尺寸分布代码很短但能省下大把排查时间。import cv2 import os from pathlib import Path img_dir Path(data/test_imgs) valid_ext {.jpg, .jpeg, .png, .bmp} total 0 broken [] sizes [] for p in img_dir.iterdir(): if p.suffix.lower() not in valid_ext: print(f[skip] unsupported format: {p.name}) continue total 1 img cv2.imread(str(p)) if img is None: broken.append(p.name) continue h, w img.shape[:2] sizes.append((w, h)) print(ftotal images: {total}) print(fbroken images: {len(broken)}) for name in broken: print(f {name}) if sizes: ws sorted([s[0] for s in sizes]) hs sorted([s[1] for s in sizes]) print(fmin width: {ws[0]}, max width: {ws[-1]}) print(fmin height: {hs[0]}, max height: {hs[-1]})逻辑说明脚本遍历测试目录下所有文件先按后缀过滤出jpg、jpeg、png、bmp四类yolov5默认支持的格式然后用cv2.imread尝试解码。imread返回None就说明文件损坏或格式伪装这种图片必须剔除否则detect.py读到一半可能报错。最后打印宽高分布是为了快速判断测试集中是否存在极端分辨率比如全景拼接图或者长截图这类图片的检测结果通常没有参考价值。参数说明valid_ext里的集合按你实际图片格式增减如果测试集里混有大量webp建议先批量转成jpg再放进来而不是去改detect.py的源码。sizes列表只统计了宽高如果你担心图片太小没意义可以再加一个面积判断比如w * h 200 * 200就直接踢掉。3.3 图片多样性想让测试结果有说服力的最小检查清单测试集不是图多就代表可靠真正有价值的是覆盖度。我在做目标检测测试集时心里有个最少检查清单照着配基本不会翻车。第一是场景维度室内和室外都要有。室内场景光线复杂有顶灯、窗户逆光猫狗经常趴在沙发角落室外场景有树荫、强光、移动车辆干扰人和宠物体型差异被环境放大。第二是目标尺度一张图里至少要包含一个占画面比例小于5%的人或动物专门用来探模型对小目标的底。第三是遮挡程度猫在桌子底下只露半截、人背对镜头侧脸入画这类图能暴露出模型对局部特征的依赖程度。第四是拍摄方向正面、侧面、俯拍各来几张因为yolov5对视角变化比较敏感。检查清单可以用一张表固下来配图时对着打钩检查项建议数量配图要点室内室外各占50张光线差异明显单人/多人各20张人数从1到5递增猫狗单独出现各30张别只拍头部特写猫狗与人同框20张模拟真实生活场景小目标15张目标占全图5%以下遮挡目标15张半身、侧身、局部这张表不是硬标准但它保证测试集能覆盖到最典型的目标检测退化场景。我早期做测试集时只关心数量攒了五百张全是大头猫特写结果换到客厅监控画面直接漏检成筛子从那以后配置图集就按这个思路走先把场景和尺度铺匀再谈数量。4. 跑通检测detect.py的核心参数逐一拆解与输出产物解读4.1 最小推理命令逐个参数拆开看测试集目录准备好了接下来就是最关键的detect.py推理命令。下面这行命令是我从头到尾跑这一套流程时最常用的一条覆盖了这个场景的所有核心需求。python detect.py \ --weights yolov5s.pt \ --source data/test_imgs \ --img-size 640 \ --conf-thres 0.25 \ --iou-thres 0.45 \ --classes 0 16 17 \ --save-txt \ --save-conf \ --project runs/detect \ --name people_pets \ --exist-ok参数说明--weights指定模型权重文件yolov5s.pt是官方轻量级模型如果机器性能允许可以换成yolov5m.pt检测精度会高一点点--source指向测试集目录这里可以用绝对路径也可以用相对路径但要注意工作目录得在yolov5项目根目录下--img-size是推理时的输入尺寸默认640对小目标不友好后面会讲怎么调--conf-thres是置信度阈值默认0.25大于它的框才保留调低会漏得少但误检多--iou-thres是NMS的IOU阈值默认0.45控制重叠框的合并力度--classes 0 16 17就是只输出人猫狗三个类别注意类别编号之间是空格不是逗号--save-txt和--save-conf搭配使用让结果以txt格式保存并附带置信度这个对后续数据分析至关重要--project和--name指定输出目录--exist-ok允许覆盖同名目录避免跑到exp2、exp3里找不着结果。跑完以后检测框会画在图片上保存到runs/detect/people_pets/下面每张测试图对应一个带框的jpg文件同时labels子目录里生成同名txt文件。如果刚才忘了加--save-txt那你就只能看到画了框的图片拿不到任何坐标数据所以这一条我每次都会带上。4.2 conf-thres超参数和模型选型yolov5s与yolov5m的精度时间权衡yolov5超参数里对推理结果影响最大的两个就是--conf-thres和--iou-thres它们跟训练超参数没关系完全是推理阶段的行为控制。conf-thres决定多低的置信度算一个目标iou-thres决定两个重叠框算不算同一个目标。这俩是跷跷板只调低conf而不动iou会在目标密集区域出现大量重复框只调高iou而不动conf又会出现一个小目标被切分成两半的框。模型选型也需要提前定。yolov5系列里s、m、l、x是同一个结构由宽度和深度系数缩放出来的s最轻最快x最重最准。在这个标题的人猫狗测试场景里测试集通常不大单张图片的推理时间s模型在主流消费级显卡上已经是毫秒级m模型也就翻一倍左右肉眼几乎无感。我的建议是显存大于6G就无脑试yolov5m它和s在小目标、遮挡场景下的差距是能直接画在框上给老板看的。如果测试集里有大量密集人群或远处的猫狗甚至可以上--img-size 960加上yolov5l代价是推理时间变成三到五倍。模型显存占用推理速度场景建议yolov5s低最快快速验证、CPU机器yolov5m中中等人猫狗测试首选yolov5l较高较慢小目标、密集场景4.3 输出解读保存图片与txt坐标文件的格式很多人跑通之后就盯着画了框的图片看觉得挺准然后就把txt文件晾在一边。这个习惯得改因为图片只能让你看见检测结果txt文件才记录了模型认为目标在哪儿、有多确定后续做统计分析全靠它。txt文件放在runs/detect/people_pets/labels/下文件名和原图一致每行代表一个目标。开了--save-conf时每行六个数类别编号、归一化中心点x、归一化中心点y、归一化宽度w、归一化高度h、置信度。坐标全部是0到1之间的小数画框的时候要乘回原图的宽和高。比如一行内容是16 0.4821 0.3567 0.1234 0.2345 0.92就表示图片中一只猫框中心在x方向48%位置、y方向35%位置宽度占全图12.34%高度占23.45%置信度92%。注意这里不是VOC的左上角右下角格式也不是COCO的像素坐标格式它是YOLO训练标签格式的推理版本。如果你后续要把结果转成COCO格式做评估写脚本时一定要先做这个坐标换算我见过有人直接拿归一化坐标当像素坐标用画出来的框全部缩在左上角。5. 踩坑记录测试集跑yolov5常见的5个翻车现场与排查方法5.1 中文路径和含空格文件名导致的路径找不到现象detect.py启动后报Not found or empty dataset或AssertionError: source is not a file/dir但明明目录里有图片。原因测试集路径或图片名包含中文、空格在Windows下配合个别Python版本容易出现路径解析不一致yolov5内部的glob匹配拿不到预期文件。解决把测试图片目录整个移到英文路径下比如D:\yolov5test\data\test_imgs图片统一重命名成纯英文加数字的形式跑之前用上一章那个体检脚本再确认一次能正常读到。这个坑最气人的是换了机器就消失必须从命名纪律上根治。5.2 CUDA out of memorybatch_size和超参数没对上现象推理跑到一半直接报RuntimeError: CUDA out of memory有时第一张图就崩。原因显存被打满通常不是单张图造成的而是--batch-size开太大或者电脑同时还在跑别的东西把显存占了再或者是显卡驱动和PyTorch版本不匹配导致显存分配异常。解决先在命令行加--batch-size 1强制单张推理然后用nvidia-smi看一下当前显存占用把其他占卡进程结束掉如果还在爆把--img-size从640降到512试试虽然会损失小目标召回但能确认是不是显存瓶颈。还有一个隐蔽情况是有两张显卡但只用device 0PyTorch默认只认当前一张不会自动负载均衡不用幻想着双卡能自动分摊。5.3 猫狗小目标漏检conf阈值调到多少才有后悔药现象测试集里半张图大小的猫能框出来角落里一只小狗完全没反应标签文件里那一行压根不存在。原因小目标经过32倍下采样之后在特征图上只占一两个格子特征信息丢失严重模型输出的置信度天然偏低比如只有0.12而默认conf-thres是0.25直接被后处理当噪声扔掉了。解决把--conf-thres调到0.1到0.15之间同时把--img-size提高到960给模型更多像素去看小目标。具体做法是跑两次对比一次用0.25一次用0.1观察新增出来的框是真实目标还是误检。如果0.1时多出来的框大多是对的那就是阈值问题如果多出来一堆乱框说明小目标信息在特征图上已经救不回来了得换更重的大模型或者做超分预处理。5.4 一只狗被双框高亮NMS阈值与类别混淆现象同一只狗被两个几乎完全重叠的框同时框住或者一个人被同时框成person和dog。原因yolov5默认NMS是逐类别执行而且不同类别的重叠框不会互相抑制。同一个目标如果检测头同时输出了dog和cat两类的高置信度预测默认情况下两个框都会保留视觉上就是一只狗头上顶着两个标签。如果同类别里出现双框则是NMS的iou-thres设得偏高重叠区域没达到抑制标准。解决命令行加--agnostic-nms让NMS跨类别做抑制同一个目标只保留最高置信度的类别同类别双框就把--iou-thres从0.45调到0.3。这类问题在光照剧烈变化的图片上几乎必现跑完看输出图的时候专门检查角落和逆光区域的重复框。5.5 拿不到坐标数据忘了--save-txt的后果现象检测结果图片画得满满的但所有目标检测项目或统计脚本都要用的坐标数据拿不到labels目录根本不存在。原因detect.py默认只保存画框图片--save-txt是个需要手动开启的独立开关而且它和--save-conf是分开的两个参数很多人加了--save-txt但没加--save-conftxt里就只有前五列没有置信度。解决命令行固定写上--save-txt --save-conf这一对别拆开。另外输出目录也要固定用--project和--name指定再补一个--exist-ok让每次检测覆盖上一次的结果不然程序自动生成exp2、exp3下次跑完你根本记不住哪个文件夹对应哪批测试集。这个属于纯操作习惯问题纠正一次后续就不会再犯。6. 进阶验证用标签文件统计测试结果反推置信度阈值该不该调跑完detect之后光看图片你会觉得效果还行但做目标检测评估不能靠感觉要把每一张图的检测结果量化出来。下面这个脚本读取labels目录下的所有txt统计每一类目标的检测总数、平均置信度和单张图片的目标数量分布五分钟就能定位出测试集到底是在哪类场景上翻了车。from pathlib import Path import numpy as np labels_dir Path(runs/detect/people_pets/labels) cls_names {0: person, 16: cat, 17: dog} stats {name: [] for name in cls_names.values()} per_image_counts [] for txt in labels_dir.glob(*.txt): dets [] for line in txt.read_text().strip().splitlines(): parts line.split() cls_id int(parts[0]) conf float(parts[5]) if len(parts) 6 else -1 cls_name cls_names.get(cls_id, fclass_{cls_id}) stats[cls_name].append(conf) dets.append(cls_name) per_image_counts.append((txt.stem, len(dets))) print( avg conf per class ) for name, confs in stats.items(): if confs: print(f{name}: count{len(confs)}, avg_conf{np.mean(confs):.3f}, min_conf{np.min(confs):.3f}) else: print(f{name}: no detection) print( images with most detections ) for name, cnt in sorted(per_image_counts, keylambda x: -x[1])[:5]: print(f{name}: {cnt})逻辑说明脚本按类别统计置信度的平均值和最小值如果person的平均置信度在0.7以上而cat的平均值只有0.3说明模型对猫的区分能力明显弱这时就需要把猫狗样本单独拉出来看是数据场景问题还是阈值问题。按图片统计检测数量是为了找出漏检重灾区——如果检测数量最多的前五张图全是密集人群而单目标图片检测数普遍为0可能不是模型问题而是测试集分布太偏。我自己跑测试集时有个血泪经验早期只看画框图片从来不看置信度分布结果把漏检全部归咎于模型调了半天--conf-thres也没解决。后来把txt统计脚本跑出来才发现漏检的图片集中在逆光室外场景模型给的置信度其实有0.35只是被默认0.25阈值下面的误检干扰了判断。从那以后每次跑完检测我都会先跑一遍统计脚本再决定要不要动阈值和输入分辨率。数据不会骗人希望这套方法也能帮到你。本文还有配套的精品资源点击获取