
简介这是一份面向目标检测学习者和开发者的YOLOv8猴子检测资源包整合了6000余张猴子图像数据集与配套检测权重适合进行猴子检测任务训练、模型微调及算法对比。数据集已按标准方式划分好train、val、test并附带data.yaml配置文件标签采用txt格式可直接用于YOLOv5、YOLOv7、YOLOv8、YOLOv9等主流算法训练大幅省去数据整理和格式转换的繁琐步骤。压缩包共2000个文件其中1984个为标签txt文件还包含多个说明文档、PDF参考材料及YAML配置整体大小约515.15MB目录结构清晰便于快速定位所需内容。目前已有276人学习下载。资源内提供了数据集检测效果参考说明读者既能直接使用权重进行推理验证也能基于完整数据集从零训练同时通过说明文档理解数据处理与模型配置细节提升实验效率。1. 猴子检测不是冷门需求yolov8权重数据集到底能省多少事做动物园行为分析、野生动物监测、甚至实验室猴笼监控的人大概率都会卡在同一个地方算法好选数据集难找。自己标一张猴子图片就要两三分钟标到六百张就得一整天更别说动辄几千张还要划分训练集、验证集和测试集。这份资源直接给出了yolov8的猴子检测权重和配套数据集包含6000多张已标注图片txt格式标签还附带划分好的train、val、test目录和现成的data.yaml文件。也就是说你不需要从零收集图片不需要自己写划分脚本也不用手动改标签格式。下载下来装好ultralytics环境改一下data.yaml里的路径就能直接跑yolov5、yolov7、yolov8、yolov9训练。适合的人群很明确要做猴子目标检测但不想在数据准备上耗两周的从业者或者毕设选题是动物检测、想尽快跑通全流程的学生。这篇笔记把数据集结构、训练参数、权重加载和踩坑点全部拆开讲清楚。2. 资源拆解6000多张猴子数据集的结构与data.yaml配置2.1 数据集目录与文件格式train/val/test划分和txt标签这份数据集的核心价值在于它已经按YOLO系列的标准格式整理好了。打开目录会看到典型的三个子文件夹images和labels每个下面又分train、val、test三个子目录。图片是jpg格式标签是txt格式。每个txt文件名和对应图片名完全一致比如IMG_001.jpg对应IMG_001.txt。txt里每一行代表一个目标框格式是class x_center y_center width height四个坐标值都除以图片宽高做了归一化取值范围在0到1之间。这种格式是yolov5以后所有版本通用的所以官方仓库里的训练脚本能直接读。常见的一个误解是以为只有一个Monkey类就不需要仔细检查标签。实际上标签文件的路径、命名、换行符哪怕有一处不规范训练时就会报错或者静默跳过某些图片。我每次拿到新数据集第一件事不是急着训练而是先统计一下每个目录下图片和标签的数量是否一致以及检查txt文件里坐标值有没有超过1或者小于0的情况。一个快速脚本就能完成import os def check_dataset(img_dir, lbl_dir): imgs {f.split(.)[0] for f in os.listdir(img_dir)} lbls {f.split(.)[0] for f in os.listdir(lbl_dir)} missing imgs - lbls extra lbls - imgs print(f图片数: {len(imgs)}, 标签数: {len(lbls)}) print(f缺标签: {len(missing)}, 多标签: {len(extra)}) bad 0 for name in lbls: with open(os.path.join(lbl_dir, name .txt)) as f: for line in f: parts line.strip().split() if len(parts) ! 5: bad 1 continue cls, x, y, w, h parts if not (0 float(x) 1 and 0 float(y) 1 and float(w) 0 and float(h) 0): bad 1 print(f格式异常标签数: {bad}) check_dataset(images/train, labels/train)这个脚本先比对图片和标签的文件名集合再逐行校验标签的格式和坐标范围。如果bad数大于0说明原始标注里有脏数据训练前必须处理。参数上要注意的是脚本假设图片和标签的子目录一一对应如果你把labels/train和images/train放错层级这里就会直接暴露出来比等到训练跑一半再崩要省心得多。2.2 data.yaml逐行解析nc、names与路径写法数据集根目录下有一个data.yaml文件这个文件是所有YOLO训练脚本都会读取的配置文件。原始内容很短nc: 1 names: - Monkey只有nc和names两行路径配置反而没有写全。这里就是最容易被新手忽略的坑yolov8和yolov5默认会读训练命令里的data参数指定的yaml文件但yaml里需要通过train:、val:、test:字段告诉模型去哪里找图片。如果这三个字段缺失ultralytics会尝试在当前目录下找名为datasets的文件夹找不到就报错。我一般会改成相对路径格式这样拷贝到任何机器上都不用改动绝对路径。修改后的data.yaml如下train: datasets/monkey/images/train val: datasets/monkey/images/val test: datasets/monkey/images/test nc: 1 names: - Monkey这里的关键是train和val字段指向的是图片目录而不是标签目录训练时会根据同名的txt去对应的labels目录下找标签。test字段可以缺省验证时用val就够了。另一个容易忽略的点是路径分隔符在Windows上写反斜杠偶尔会出现转义问题建议统一用正斜杠。如果数据集和训练脚本不在同一级目录最稳妥的方式是写绝对路径或者把datasets目录放在运行训练命令的当前目录下。2.3 数据集怎么检查统计图片数、标签分布与坏样本除了格式检查还需要确认每个类别的样本均衡性。这份数据集只有一个Monkey类所以不存在类别不平衡问题但需要关注的是目标框的尺寸分布。猴子有大有小远距离拍摄时目标可能只有几十个像素训练时如果不做处理小目标框对loss的贡献会被大目标稀释导致漏检。用以下脚本统计标签框的宽高分布import os import numpy as np lbl_dir labels/train w [] h [] for f in os.listdir(lbl_dir): with open(os.path.join(lbl_dir, f)) as fp: for line in fp: _, _, _, bw, bh line.strip().split() w.append(float(bw)) h.append(float(bh)) w np.array(w) h np.array(h) print(f平均宽: {w.mean():.4f}, 平均高: {h.mean():.4f}) print(f宽0.1占比: {(w 0.1).mean()*100:.1f}%, 高0.1占比: {(h 0.1).mean()*100:.1f}%)如果小目标占比超过50%我一般会建议直接用yolov8的原生结构它本身对小目标有优化不要擅自改anchor。统计结果也决定了imgsz参数设多少当大量目标框宽度小于图片宽度的10%时输入尺寸低于640会进一步压缩目标信息损失严重所以训练分辨率建议不低于640。这份数据集的原始图片来源较杂但txt标签已经归一化直接用上面的脚本能看到分布情况再做针对性调整。3. 用yolov8训练猴子检测从环境到命令的完整流程3.1 环境准备ultralytics安装与CPU/GPU选择训练yolov8需要安装ultralytics这个Python包。它把训练、验证、导出封装成了非常简洁的接口。正常做法是用pip安装pip install ultralytics安装后可以在命令行输入yolo验证是否可用。CPU版本和GPU版本的区别在于是否安装PyTorch的CUDA支持。如果你只有CPU直接用pip安装的torch就是CPU版本也能训练但速度会慢得让人怀疑人生。6000多张图片、640分辨率训练100个epochCPU上跑可能要十个小时以上GPU则视型号而定GTX1660Ti大概三四小时RTX30系更快。环境上最容易翻车的是PyTorch版本和CUDA版本不匹配。常见做法是先看显卡驱动支持的CUDA版本再装对应版本的PyTorch。nvidia-smi pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118这里cu118对应CUDA 11.8如果你的驱动支持更高版本可以用cu121。注意ultralytics对torch版本有一定要求太老的torch会报缺符号错误。装完后用python -c import torch; print(torch.cuda.is_available())验证一下输出True才是真正用上了GPU。很多人在这里卡住以为装了CUDA版torch就万事大吉实际上还得看torch能否和GPU通信缺一步都会导致训练时自动退回CPU。3.2 训练命令与参数含义epochs、imgsz、batch、workers数据集就绪后训练命令非常直观yolo detect train \ datadatasets/monkey/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ workers4 \ projectruns \ namemonkey_detect每个参数都有讲究。model指定预训练权重yolov8n.pt是从COCO数据集上预训练出来的纳秒级轻量模型用它做微调比从随机权重开始收敛快得多。epochs设100对单类数据集通常足够如果看到val_loss连续20个epoch不下降就可以停了。batch大小取决于显存16在8GB显存上是安全的12GB显存可以开到24或32。workers负责数据加载的线程数在Linux上设4到8Windows上设0或2因为Windows的多进程数据加载有坑。project和name决定输出目录训练完的权重会放在runs/monkey_detect/weights/下best.pt和last.pt分别对应验证集最优和最后一个epoch的权重。从yolov5转到yolov8的注意区别是yolov8的命令行参数不再支持--device 0这种写法而是用device0。也不要再传--multi-scaleyolov8已经默认做了轻微的多尺度增强。训练过程中终端会每1个epoch打印一次mAP50和mAP50-95这两个指标是主要观测对象。如果mAP50快速接近0.95说明数据太简单或过拟合如果一直在0.5以下需要回头检查标签和数据划分。3.3 模型选型yolov5/v7/v8/v9都能训该用哪个这份数据集的标签格式兼容yolov5、yolov7、yolov8、yolov9但不同版本在精度和速度上的取舍不一样。先明确场景猴子检测通常是固定摄像头监控对速度不是极端敏感更看重召回率和稳定性。yolov8n是最轻的选择适合低算力边缘设备yolov8s是性价比最高的选择mAP比n高3到5个点推理速度依然能到每秒几十帧yolov8m和l则适合服务器端高精度场景。到底用哪个我一般用yolov8s起手先跑通流程再对比yolov8m。如果要用yolov5命令会变成python train.py \ --data datasets/monkey/data.yaml \ --weights yolov5s.pt \ --epochs 100 \ --batch-size 16 \ --img 640yolov5需要单独克隆仓库并安装依赖不像yolov8一条pip install搞定。yolov7和yolov9的情况类似它们各自的代码仓库独立数据格式虽然通用但训练入口脚本参数名略有不同。yolov8的优势在于ultralytics统一封装了训练、验证、导出、推理不需要在不同仓库之间切来切去。yolov9的架构在理论上更先进但对这份只有单类6000多张的数据集增益并不明显而且部署时需要额外转ONNX处理。综合来看如果你不是有明确的部署要求必须用yolov5或yolov7直接选yolov8s做基准后续再横向换模型。4. 权重文件使用加载预训练权重做推理与迁移学习4.1 推理测试用训练好的best.pt检测单张图片训练完成后项目的实际需求是拿权重去做推理。使用ultralytics的API最简单几步就能跑通from ultralytics import YOLO model YOLO(runs/monkey_detect/weights/best.pt) results model.predict(sourcetest.jpg, conf0.25, saveTrue, device0)这里的conf参数控制置信度阈值0.25是默认值适合猴子这类目标明确的场景。如果场景中有很多猴子背影或遮挡0.25会漏掉一些低置信度的目标可以降到0.15如果误检太多再调高到0.4。saveTrue会把画完框的结果保存到runs/detect/目录下。如果不想保存图片想拿到坐标做后续业务逻辑可以这样boxes results[0].boxes.xyxy.cpu().numpy() scores results[0].boxes.conf.cpu().numpy() for box, score in zip(boxes, scores): x1, y1, x2, y2 box.astype(int) print(f猴: ({x1}, {y1})-({x2}, {y2}) 置信度: {score:.3f})调用名称在yolov8的API里需要注意xyxy是按原始图片像素坐标输出的左上右下角坐标不需要手动反归一化因为模型内部已经处理了。这一点和直接用yolov5的detect.py不太一样很多从v5迁过来的人会误以为输出还是归一化坐标结果把像素坐标当比例用了。4.2 迁移学习在猴子数据集上微调yolov8n.pt如果你收到这份资源时不想从零训练而是想在别人训好的权重基础上继续训练也不难。但要注意一个关键点权重文件的类别数和你的数据集类别数必须一致。这份资源的best.pt是只检测Monkey一个类的权重如果你的最终任务也是单类猴子那直接用best.pt作为预训练权重没问题如果你的任务还包含其他动物就不能直接微调这个权重而要用yolov8s.pt这种COCO预训练权重因为它有80个类但微调后会自动调整类别头。用已有权重继续训练的命令yolo detect train \ datadatasets/monkey/data.yaml \ modelruns/monkey_detect/weights/best.pt \ epochs50 \ imgsz640 \ batch16这么做的意义在于数据量不足时从更强先验出发能更快收敛。但这个场景下数据集已经有6000多张从COCO预训练权重开始比从猴子权重开始更稳妥因为猴子权重可能已经过拟合原有训练集再接新数据容易忘记旧特征。我一般会做两组实验一组用yolov8s.pt一组用best.pt对比验证集mAP选高的那个。如果差异在1个点以内就用yolov8s.pt因为泛化能力通常更好。4.3 导出模型格式ONNX与量化注意点部署到RK3588、HI3516CV610这类边缘设备时需要把PyTorch权重导出为ONNX再转成对应平台的模型格式。导出命令yolo export modelruns/monkey_detect/weights/best.pt formatonnx imgsz640 opset11imgsz要和你训练时的分辨率一致不要训练用640导出用480否则特征图尺寸对不上运行时表现会明显变差。opset默认11部分边缘平台要求12或13具体查平台文档。导出后可以用onnxruntime验证一下输出是否和PyTorch一致import onnxruntime as ort import numpy as np sess ort.InferenceSession(best.onnx) input_name sess.get_inputs()[0].name input_shape sess.get_inputs()[0].shape # 假设输入是1x3x640x640 dummy np.random.randn(1, 3, 640, 640).astype(np.float32) outputs sess.run(None, {input_name: dummy}) print(outputs[0].shape)在猴类检测这种单目标任务中导出时最容易出问题的是动态尺寸支持。ultralytics默认导出固定shape如果你的部署场景需要不同分辨率的输入需要加dynamicTrue参数。但注意动态shape在部分NPU上不支持所以先确认平台能力再决定。量化时优先选FP16INT8量化要提供校准集否则在猴子这种纹理丰富的目标上精度掉得厉害。5. 避坑与常见问题训练猴子数据集时最容易翻车的五个点5.1 标签坐标归一化错误导致loss爆炸现象训练开始后loss数值一开始就巨大从10以上起步然后要么震荡不降要么直接变成NaN。原因这份数据集的txt标签虽然已经归一化但如果你自己补充过数据或者用labelImg导出的坐标是未归一化的像素值混入了原数据集后模型在训练时拿到的框坐标范围不一致。labelImg默认导出的是像素坐标而YOLO需要的是除以图片宽高后的0到1之间的值。解决把补标的数据重新做一次归一化再合并。常见做法是写一个转换脚本逐行读取原始标签除以对应图片的宽和高。不要手动改数字6000多张图片里混三四个错误标签就够让训练不稳定。合并前用前文的检查脚本跑一遍确保所有坐标都在0到1之间。5.2 类别编号对不上Monkey是0不是1现象训练正常但推理时置信度很高却一个框都画不出来或者画出的框位置奇怪。原因data.yaml里names列表顺序决定了类别编号nc: 1表示只有一个类那个类的索引是0。如果你的标签文件里写的是1 x y w h而names里只有Monkey那么类别1就超出范围了。很多从LabelImg导出的人默认第一个类从0开始但习惯上可能手写成了1训练时就会报class index out of range或者静默忽略。解决用脚本批量检查标签文件第一列的值确认只有一个值且是0import os lbl_dir labels/train classes set() for f in os.listdir(lbl_dir): with open(os.path.join(lbl_dir, f)) as fp: for line in fp: classes.add(line.strip().split()[0]) print(classes)打印结果必须包含0如果出现1说明标签有问题需要把所有第一列改成0。这类错误很隐蔽因为yolov5某些版本会把它当成背景类训练模型能训出来但效果差。从那以后我每次拿到新数据集都会先跑这个检查再慌不忙开训练。5.3 显存不足batch与imgsz的取舍现象CUDA out of memory报错或者训练刚开始几分钟就崩了。原因batch设置过大或者imgsz设成了1280。猴子数据集图片尺寸不一如果原始图片较大ultralytics会自动缩放填充到imgsz但显存占用和imgsz的平方成正比。在8GB显存上yolov8s的batch16和imgsz640是极限如果还开了多尺度增强临时显存峰值会再高一点。解决先降batch到8甚至4再降imgsz到512。注意imgsz降到512会影响小目标检测所以优先降batch。另一种做法是开梯度累积ultralytics没有直接参数但可以通过Python训练循环自定义。实际项目中我一般直接把batch设为8imgsz保持640牺牲一点训练速度换取稳定。如果不小心用了Windows且workers0导致的假性OOM把workers设为2再试。5.4 标注框太小小目标漏检怎么调现象mAP50看起来还行但实际跑API测试时远距离的猴子完全检测不到只有近景的能框出来。原因猴群行为分析中摄像头视角广很多猴子在画面里只占几十个像素。默认的训练配置对32x32像素以下的目标不友好而且数据集的标签统计显示小目标占比高但没有做针对性处理。解决把imgsz从640提升到960或1280让小目标在输入图片中占据更大区域。显存不够就用yolov8n配合1280尺寸。另一个办法是开启mosaic增强yolov8默认已经开了但可以调整复制粘贴增强的强度。如果要上难度可以改成yolov8-tiny这里就不再赘述。注意提升imgsz后训练时间和显存占用都会增长先在小规模跑10个epoch验证再正式训。5.5 验证集mAP虚高shuffle与种子问题现象验证集mAP到了0.99但放在新场景测试效果很差像是学到了背景。原因数据划分时train和val来自同一场景的连续帧两张相邻图片内容高度相似模型相当于在背题。这种问题尤其在按文件夹划分时最容易出现如果原数据集划分不当val里面有大量和train几乎一样的图。解决在数据划分阶段按视频片段或按时间段划分而不是随机划分。对于这份现成的数据集先看一下train和val的图片文件名是否有连续编号如果是大概率有数据泄漏。可以考虑把train和val重新洗牌但更好的做法是保留原始划分但在训练时把val的比例扩大并人工抽查几个坏case。关于随机种子ultralytics里可以通过seed42固定否则每次训练结果不同不利于调参。如果你发现mAP异常时高多半不是模型强而是数据划分太天真。6. 让猴子检测更稳WBF融合与按类别调参的实战技巧6.1 用WBF融合提升召回猴子检测一个典型痛点是遮挡严重猴群挤在一起时NMS会把重叠的框误删。单个模型的召回率往往不够。常见做法是训练两个不同backbone的模型比如yolov8s和yolov8m然后用加权框融合WBF合并输出。WBF与NMS不同它会把重叠框的坐标加权平均而不是直接删掉低置信度框对密集遮挡场景提升明显。from collections import defaultdict def wbf(boxes_list, scores_list, iou_thresh0.55): # boxes_list: 每张图片的多组框, 每组shape(N,4) xyxy # scores_list: 多组置信度 all_boxes [] for boxes, scores in zip(boxes_list, scores_list): for b, s in zip(boxes, scores): all_boxes.append([b, s]) # 按置信度排序 all_boxes.sort(keylambda x: x[1], reverseTrue) fused [] used [False] * len(all_boxes) for i in range(len(all_boxes)): if used[i]: continue # 找所有与当前框IOU大于阈值的框 cluster [i] used[i] True for j in range(i1, len(all_boxes)): if used[j]: continue iou compute_iou(all_boxes[i][0], all_boxes[j][0]) if iou iou_thresh: cluster.append(j) used[j] True # 加权平均坐标 total_score sum(all_boxes[k][1] for k in cluster) new_box [0, 0, 0, 0] for k in cluster: w all_boxes[k][1] / total_score new_box[0] all_boxes[k][0][0] * w new_box[1] all_boxes[k][0][1] * w new_box[2] all_boxes[k][0][2] * w new_box[3] all_boxes[k][0][3] * w fused.append((new_box, total_score / len(cluster))) return fused这里的iou_thresh是一个关键参数猴子密集时0.55能保留更多框稀疏场景可以调到0.7。注意wbf之后还需要再做一次NMS过滤掉置信度过低的融合结果因为wbf本身不会过滤类别无关的噪声。6.2 针对猴子遮挡场景调NMS与置信度yolov8默认NMS的iou阈值是0.7在猴子场景下这个值偏严。猴子身体互相遮挡时两个真实目标的框重叠度甚至超过0.8默认阈值会把其中一个当成另一个的多余框删掉。我一般预测时手动设置iou阈值from ultralytics import YOLO model YOLO(best.pt) results model.predict(sourcecrowd.jpg, conf0.2, iou0.5, agnostic_nmsFalse)iou从0.7降到0.5意思是两个框重叠50%以上才认为多余这样能保留更多真实目标。但代价是误检增加如果背景杂乱需要配合agnostic_nmsTrue来跨类别抑制。单类场景下agnostic_nms无所谓多类时它会把所有类别的框放在一起做NMS适合类间重叠大的情况。6.3 一键复现的验证脚本在交付或复现时一个能快速验证权重和数据集是否配套的脚本很有价值。我通常把它写成一个独立文件放在项目根目录import os import subprocess from ultralytics import YOLO def validate(): # 1. 检查数据划分完整性 for split in [train, val, test]: img_dir fdatasets/monkey/images/{split} lbl_dir fdatasets/monkey/labels/{split} if not os.path.exists(img_dir) or not os.path.exists(lbl_dir): raise FileNotFoundError(f{split}目录缺失) # 2. 快速验证权重能否加载 model YOLO(runs/monkey_detect/weights/best.pt) # 3. 跑一次验证集推理, 打印mAP metrics model.val(datadatasets/monkey/data.yaml, splitval) print(fmAP50: {metrics.box.map50:.3f}) print(fmAP50-95: {metrics.box.map:.3f}) if __name__ __main__: validate()这个脚本把三轮排查压缩成一次执行适合接手别人项目时先跑通再改代码。验证时注意metrics.box.map50的命名在yolov8的返回值里map50是mAP0.5map是mAP0.5:0.95别写反。脚本里没有用绝对路径是因为我习惯在项目根目录下运行如果你把脚本放别处记得调整路径。使用这份猴子检测资源时我最深刻的一个教训是数据集的标签格式看起来统一但总有几个文件编码或换行符是有问题的尤其是从压缩包解压后经过工具链转换的标签很容易出现不可见字符。从那以后我每次开始训练前都会强制用脚本对全部标签做一遍数值范围、类别编号、文件名匹配的完整校验再跑一个1 epoch的训练做冒烟测试看到loss下降才放开训练。这套流程下来后面遇到的大多数问题都变成了参数调整的琐事而不是返工数据。希望这份拆解能帮你在猴子检测上少走几步弯路。本文还有配套的精品资源点击获取