简介YOLOv5测试数据集聚焦图像中的人、猫和狗三类目标检测适合正在学习目标检测或基于YOLOv5调试模型的开发者用于验证模型效果、评估检测精度及开展对比实验。资源共501个文件压缩包约53.53MB包含200张jpg图片、100个xml标注文件和201个txt标签文件其中xml为VOC格式标注txt对应YOLO训练所需的规范化标签两者可配合图片直接用于模型测试或格式转换学习。数据规模适中便于快速下载、反复实验也适合在算力有限的个人电脑上运行。目前已有770人学习下载可作为课程设计、毕设实验或算法复现时的辅助测试集。由于保留了原始图像和标注信息使用时可快速对比不同权重文件的识别结果也能帮助理解从标注到训练再到推理的完整流程为后续优化模型提供依据。1. 测试数据集验证 yolov5 模型先别急着跑 detect.py手头有个训练好的 yolov5 权重想拿一批照片试试它能不能把人、猫、狗分清楚——这个动作看起来就是一条detect.py命令的事但绝大多数人第一次都栽在“测试数据集”这四个字上。要么拿训练集里的图片凑数跑出来的 mAP 虚高得不敢信要么从网上下了一堆没标注的猫图狗图跑完连个对错都不知道。这篇就围绕 yolov5 测试集该长什么样、怎么组织、标签从哪来、跑完怎么评估这一整条链路来写目标只有一个让你手头这批图像能真实反映模型在人、猫、狗三类上的水平。新手照着目录结构和命令一步步来就行熟手可以直接跳到第三章的参数说明和第五章的避坑清单。2. 测试数据集从哪来三类来源与目录组织方式2.1 来源一自己标注一批聚焦场景的图像最可靠的方式是从实际业务场景里攒图比如监控画面、手机相册、宠物摄像头截图。凑够 200 到 500 张就可以关键是覆盖要全人要有全身、半身、侧身、遮挡猫和狗要有不同品种、不同姿态、不同光线。这些图不用多但要能代表你真正要用的场景。用 LabelImg 或 X-AnyLabeling 一张张框格式选 YOLO默认会生成同名.txt标注文件。注意测试集的图像要和训练集没有任何重叠。哪怕同一条视频里截的帧训练用奇数帧、测试用偶数帧都不行——相邻帧太像测出来指标会虚高。自己标注的另一个好处是能顺手把难例标记出来。比如那只趴在深色沙发上的黑猫标的时候你就会多看一眼这种图像放到测试集里往往就是模型翻车的重灾区。2.2 来源二公开数据集的验证集或测试集切片不想标就从公开数据集里切。COCO 的val2017里有大量 person 类别猫狗也有但数量偏少Open Images v6 的验证集更均衡类别细分到 domestic cat 和 dog。还有一种常见做法是直接找 kaggle 上的“dogs-vs-cats”这类数据集但要注意很多老牌数据集只有二分类标签或只有单类目标拿来做三类检测的测试集需要自己过滤和重写标注。结构上测试集和训练集的目录完全一致就行——images放图labels放同名.txt。yolov5 的 DataLoader 不关心你的目录叫什么只要求图片路径和标注路径能对上。2.3 目录脚本把图片和标注自动对齐并拆成测试集我一般会把数据集统一整理成这样一个结构datasets/ └── test/ ├── images/ │ ├── 001.jpg │ └── 002.jpg └── labels/ ├── 001.txt └── 002.txt下面这个脚本可以把一个杂乱目录里的图片和同名标注文件挑出来确保一一对应import os import shutil from pathlib import Path src_images Path(raw_images) src_labels Path(raw_labels) dst_images Path(datasets/test/images) dst_labels Path(datasets/test/labels) dst_images.mkdir(parentsTrue, exist_okTrue) dst_labels.mkdir(parentsTrue, exist_okTrue) count 0 for img_path in src_images.glob(*.jpg): label_path src_labels / (img_path.stem .txt) if label_path.exists(): shutil.copy(img_path, dst_images / img_path.name) shutil.copy(label_path, dst_labels / label_path.name) count 1 else: print(f跳过无标注图像: {img_path.name}) print(f已就绪 {count} 张测试图像)这段逻辑很简单但值得拆开说一遍img_path.stem拿的是不带后缀的文件名用它去拼标注路径如果标注文件不存在说明这张图没标过直接跳过并打印提示。跑完这个脚本test目录里的图片和标注就是一一对应的后续跑val.py或detect.py都不会遇到“找不到标注”的报错。2.4 标签格式与类别映射person、cat、dog 的 ID 必须固定YOLO 标注格式每行是class_id x_center y_center width height其中坐标是相对于图片宽高的归一化值。假如你的模型是在 COCO 上预训练的person 是第 0 类cat 是第 15 类dog 是第 16 类。如果你用安全帽等自定义数据集练的模型类别 ID 可能完全不一样——这时看标注文件里的第一个数对照训练时的data.yaml就能确认。转换脚本里最容易出错的就是类别映射。比如从 COCO 标注 JSON 转 YOLO要写一个字典category_map { 1: 0, # person - 0 15: 1, # cat - 1 16: 2, # dog - 2 }如果漏了映射直接把 COCO 的类别 ID 写进标注文件模型会把人检测成猫。这个问题在线上的标注工具里经常发生所以每次拿到新的测试集第一件事是随机抽三张图、打印标注内容、人工核对一遍。3. 跑通 detect.py最小命令与四个必调参数3.1 先确认环境与权重路径在写任何命令之前确认三件事yolov5 仓库是否完整、Python 依赖是否装好、权重文件存在哪。我常用的检查命令是python -c import torch; print(torch.__version__) ls yolov5/ ls runs/train/exp/weights/best.pt如果 torch 版本正常且能看到best.pt就可以开始推理了。没装环境的同学先走一遍pip install -r requirements.txt这一步会装好 opencv、numpy、torch 等一整套依赖。注意 PyTorch 的安装建议单独用官方命令装 GPU 版requirements.txt 里的默认版本可能不带 CUDA 支持。显卡检测可以通过python -c import torch; print(torch.cuda.is_available())来做输出 True 再往下走。3.2 最小推理命令假设测试图片放在datasets/test/images里权重是best.pt模型是 yolov5spython detect.py \ --weights runs/train/exp/weights/best.pt \ --source datasets/test/images \ --data dataset.yaml \ --conf-thres 0.25 \ --iou-thres 0.45 \ --save-txt \ --project runs/detect \ --name test_output这条命令的每个参数都值得单独说一遍。--weights指定权重路径--source可以是目录、单张图片或视频文件目录会自动遍历所有图片--data指向dataset.yaml里面有类别 names 列表推理结果标注框上的类别名就是从这里读的--conf-thres是置信度阈值低于这个值的检测框会被丢弃--save-txt把检测结果保存为 YOLO 格式的 txt 文件方便后续脚本处理。跑完之后runs/detect/test_output里能看到带标注框的图像和labels子目录里的检测结果。3.3 为什么我会把 conf-thres 调低到 0.1 做测试正式评估模型的时候--conf-thres不建议用 0.25我一般会调低到 0.1。原因很简单测试集评估是看模型“会不会”而不是“敢不敢”。阈值设高了漏检全部被归因为“置信度不足”但你分辨不出是模型真的没学会这个类别还是只是不够自信。python detect.py \ --weights runs/train/exp/weights/best.pt \ --source datasets/test/images \ --data dataset.yaml \ --conf-thres 0.1 \ --iou-thres 0.45 \ --save-txt \ --project runs/detect \ --name test_conf01--iou-thres的作用是 NMS 时去除重叠框。人猫狗检测里最常见的现象是一只猫的背影和正面各出一个框两个框 IoU 很高NMS 会保留置信度高的那个。这个值一般不动0.45 到 0.5 之间都是安全范围。太低了会把挨在一起的两个人并成一个框太高了会出现大量重复框肉眼评估时特别影响判断。3.4 结果整理从 detect 的输出目录里统计每类检测数量跑完 detect 之后用一段小脚本统计每张图检测到了什么比一张张翻图效率高得多from pathlib import Path label_dir Path(runs/detect/test_conf01/labels) class_count {person: 0, cat: 0, dog: 0} total_images 0 for label_file in label_dir.glob(*.txt): if label_file.stat().st_size 0: continue total_images 1 for line in label_file.read_text().strip().splitlines(): class_id int(line.split()[0]) if class_id 0: class_count[person] 1 elif class_id 1: class_count[cat] 1 elif class_id 2: class_count[dog] 1 print(f检测到目标的图像数: {total_images}) print(class_count)这段脚本读的是--save-txt生成的检测结果每行第一个数字是类别 ID后面是归一化坐标。统计出来的数字能快速告诉你如果你的测试集里各种类的真实数量大致已知检测出来的数量明显偏少说明这个类存在系统性漏检需要回训练阶段补数据或调损失权重。4. 用 val.py 算 mAP 和混淆矩阵模型行不行数字说了算4.1 评估集与测试集的边界val.py 到底能不能用测试集跑yolov5 自带的val.py是验证脚本但这不代表它只能跑验证集。--data参数指向的 yaml 文件决定了图片路径指向哪里你完全可以把它指向测试集目录只是要确保测试集的标注格式和类别定义与配置文件一致。这个做法在工程上叫“用测试集做一次终评”目的是拿到 mAP、Precision、Recall 这些硬指标而不是靠肉眼翻图。4.2 准备 test.yaml 并运行评估写一个专门的测试集配置# test.yaml path: datasets/test train: images # 不存在也没关系val.py 不读 train 字段 val: images names: 0: person 1: cat 2: dog然后运行python val.py \ --weights runs/train/exp/weights/best.pt \ --data test.yaml \ --conf-thres 0.001 \ --iou-thres 0.6 \ --project runs/val \ --name test_eval--conf-thres 0.001是评估时的标准做法。mAP 计算的是不同置信度阈值下的平均精度如果阈值设太高低置信度的正确框不会进入 PR 曲线mAP 数值就会偏低。--iou-thres 0.6是判断“预测框是否命中真实框”的 IoU 标准0.5 更宽松0.75 更严格。用 0.6 居中来看既能反映定位质量又不会因为严苛标准掩盖类别识别能力的问题。跑完会生成results.csv里面有每个类别的 Precision、Recall 和 mAP50。4.3 三类指标怎么解读别只看 mAP 一个数mAP 是三个类别的平均但如果猫的 AP 高、狗的 AP 低mAP 可能是 0.75看起来还行。所以务必要单独看每一类的 AP 值。confusion matrix 在runs/val/test_eval/confusion_matrix.png里横轴是真实类别纵轴是预测类别对角线越亮越好。最容易翻车的情况是 background 那一行很亮说明模型把背景误检成了目标或者 cat 和 dog 互相混淆说明模型捕抓到的特征还不够区分这两种动物。4.4 和 detect.py 结果对照val.py 说好detect 说差问题出在哪很多时候会出现一个诡异现象val.py 算出 mAP 0.85但拿一张测试图跑 detect.py看着什么也没框出来。先别怀疑模型大概率是两次推理用的阈值不一样。val.py 用了 0.001 的置信度阈值detect.py 用了 0.25——对难例来说0.2 的置信度在 val.py 里算命中在 detect.py 里被丢掉了。解决办法是在做最终演示或落地时单独跑一次低阈值的 detect 看效果不要直接拿评估阶段的阈值去做推理。5. 避坑测试集最容易在五个地方悄悄翻车5.1 图像尺寸不一致导致小目标漏检现象测试集里混着 1920x1080 的高清大图和 320x240 的缩略图模型在大图上表现很好小图上一只猫的检测框直接消失。原因yolov5 推理时会先把图像等比例缩放到 640x640小图放大的过程会有信息损失猫脸原本就只有 20 个像素放大后糊成一团。解决统一测试集的图像尺寸下限。低于 640x640 的图片要么放弃要么先做超分处理再放进测试集高清大图则注意 yolov5 会自动做 letterbox不需要手动裁剪。5.2 标注坐标越界导致训练评估指标失真现象val.py 跑到某个 epoch 突然报IndexError或者指标从 0.8 掉到 0.3。原因标注框的 x_center width / 2 超过 1.0或者 y_center height / 2 超过 1.0。这些越界框在训练时会被 Ignore但 val.py 计算 IoU 时不处理导致评估异常。解决清洗标注数据用脚本把所有越界框裁剪回 [0, 1] 范围import shutil from pathlib import Path label_dir Path(datasets/test/labels) backup_dir Path(datasets/test/labels_backup) backup_dir.mkdir(exist_okTrue) for label_file in label_dir.glob(*.txt): lines label_file.read_text().strip().splitlines() cleaned [] for line in lines: parts line.split() if len(parts) ! 5: continue cid, cx, cy, w, h int(parts[0]), float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) cx min(max(cx, 0.0), 1.0) cy min(max(cy, 0.0), 1.0) w min(w, 1.0) h min(h, 1.0) cleaned.append(f{cid} {cx} {cy} {w} {h}) if len(cleaned) ! len(lines): shutil.copy(label_file, backup_dir / label_file.name) label_file.write_text(\n.join(cleaned))这段脚本先把原始标注备份到labels_backup再逐行检查坐标把越界的裁剪到合法范围。注意只改了坐标类别 ID 没动。如果一个标注文件里某些行格式不对比如缺列直接丢弃那行并备份原文件。5.3 类别 ID 映射错误导致张冠李戴现象检测结果里一个明明是人框子上却写着 dog。原因测试集的标注文件里 class ID 用的是 COCO 官方编号但模型训练时的data.yaml里 person 在第 0 位、dog 在第 2 位。比如 COCO 里 dog 的 ID 是 16训练时类别表里第 16 位是别的类。解决建立清晰的类别映射文件并在每次拿到新数据集时检查前三个标注文件的类别 ID 是否在预期范围内for f in $(ls datasets/test/labels/*.txt | head -3); do echo $f; cat $f; done看到输出里的第一个数字是 0、1、2并且和data.yaml的 names 顺序对得上再往下跑。5.4 eval 时开了数据增强导致指标虚高现象每次跑 val.py 结果都不一样有时候 mAP 0.79有时候 0.83浮动 4 个点。原因val.py默认开了--augment增强评估。数据增强能提升模型对变化场景的鲁棒性但用在测试集上会让结果不稳定而且不同硬件上增强的随机性也会带来差异。解决普通评估完全不需要增强关掉它再跑python val.py --weights best.pt --data test.yaml --no-augment这样每次结果可复现。--no-augment之后如果发现 mAP 下降了不要慌——这是正常现象增强评估和正式评估本来就是两个标准。5.5 混合来源的图片色彩空间不一致现象测试集里手机拍的照片颜色正常监控截图偏绿视频抽帧偏灰模型在偏色图上的检测框明显变少。原因yolov5 对颜色变化有一定鲁棒性但训练集如果以自然光照片为主遇到红外监控或强偏色场景特征分布发生偏移。解决在测试集的组织阶段就按来源分类存放或者对评估结果按来源分组统计。如果偏色图像占比超过 20%说明实际场景需要额外做颜色增强再训练。6. 进阶技巧按置信度分桶挑出模型的弱点精准补数据模型评估完之后不要急着收工。把检测结果按置信度分成三桶0.1 到 0.3、0.3 到 0.7、0.7 以上。低置信度桶里的检测框就是模型“会但不敢确定”的对象也是最有挖掘价值的困难样本。from pathlib import Path label_dir Path(runs/detect/test_conf01/labels) image_dir Path(datasets/test/images) buckets {low: [], mid: [], high: []} for label_file in label_dir.glob(*.txt): if label_file.stat().st_size 0: continue image_name label_file.stem .jpg scores [] for line in label_file.read_text().strip().splitlines(): scores.append(float(line.split()[5])) # detect.py 输出中第 6 个字段是置信度 avg_score sum(scores) / len(scores) if avg_score 0.3: buckets[low].append(image_name) elif avg_score 0.7: buckets[mid].append(image_name) else: buckets[high].append(image_name) for bucket, images in buckets.items(): print(f{bucket}: {len(images)} 张)detect.py的--save-txt输出的 label 文件和 YOLO 标注格式不同追加了置信度字段所以下标 5 的位置是分数。根据这个列表把低置信度桶里的图像挑出来分析它们的共同特征——是光线暗、遮挡严重还是目标过小然后针对这些特征去补训练数据比盲目加一堆图片效率高得多。跑完这轮流程你手里就有了三样东西一套可以复用的测试集、一份完整可复现的评估命令、一张按置信度划分的困难样本清单。下次不管是调超参数还是换模型结构都可以在同一条评估链路上对比效果。我自己每次迭代模型第一件事就是把测试集和评估命令固定下来再动手改训练配置——省下来的时间远比写这套流程的时间多。希望这些经验能帮你少走点弯路。本文还有配套的精品资源点击获取