600张猴子图片训练YOLOv8目标检测实战全流程
简介:目标检测是计算机视觉的核心任务之一,而YOLO系列以其高效的单阶段检测架构被广泛用于实时场景。在实际项目中,高质量标注数据是模型效果的基石,尤其在数据集规模有限时,数据预处理与标注格式的规范性直接影响训练收敛与泛化能力。本文以600张雨林灵长类图像为例,系统讲解从YOLO格式数据集整理、类别分布分析到标注质量检查的完整流程,并围绕训练参数配置、冻结主干微调策略、针对性数据增强及小目标检测优化等关键环节展开实践解析。同时涵盖模型评估、混淆矩阵分析、ONNX导出与FastAPI部署方法,帮助读者在小型自定义数据集上构建可靠的目标检测服务,适用于野生动物监测、生态研究等场景。
1. 拿到600张猴子数据的那一刻,我先做了这几件事
这个数据集的名字很长:YOLO算法热带雨林灵长类动物目标检测数据集-600张-标注类别为秃头僧面猴-披毛吼猴-赤猴-松鼠猴.zip。说实话,第一次看到这个压缩包的时候,我脑子里冒出来的第一个问题不是"模型能训练到什么精度",而是"600张图训出来的猴脸检测,到底敢不敢拿出去用"。
用过YOLO系列做目标检测的人都知道,公开数据集里关于灵长类动物的标注资源少得可怜。COCO里面顶多有几个"zebra""elephant"这种大型动物类别,像秃头僧面猴(Pithecia irrorata)、披毛吼猴(Alouatta palliata)、赤猴(Erythrocebus patas)、松鼠猴(Saimiri sciureus)这种具体到物种级别的检测任务,基本只能靠自建数据。所以这个数据集的价值不在于"大",而在于"专"——它直接填补了一个细分场景的空白。
拿到zip之后,我的操作顺序是这样的:先不急着解压训练,而是把整个包的结构、标注格式、类别分布、图像尺寸全部摸清楚。这一步花了大概半小时,但这半小时决定了后面训练是走正路还是绕弯路。下面我把整个从解压到出模型的过程完整拆开讲,包括哪些地方容易踩坑、哪些参数值得调、哪些坑我已经帮你试过了。
2. 数据集的真实构成与YOLO格式细节
2.1 解压后第一眼:目录结构与文件分布
用解压命令解开之后,典型的YOLO格式数据集一般是这样的:
unzip YOLO算法热带雨林灵长类动物目标检测数据集-600张-标注类别为秃头僧面猴-披毛吼猴-赤猴-松鼠猴.zip -d monkey_dataset cd monkey_dataset解开后的目录通常包含:
monkey_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── classes.txt ├── data.yaml └── README.txt如果你拿到的数据包不是这个结构,比如只有单独的images和labels文件夹,或者图片和标注文件混合放在一起,那说明数据集还需要自己划分。600张图不算多,划分的比例我建议采用70%/20%/10%左右,也就是420张训练、120张验证、60张测试。也可以用80/10/10,但考虑到数据量本身不大,验证集稍微多一点有助于观察过拟合趋势。
2.2 YOLO标注文件长什么样
每个图片对应一个同名的txt文件,放在labels目录下,每一行代表一个目标框:
class_id cx cy w h这里有个新手特别容易忽略的点:YOLO格式中cx cy w h全部是归一化到0到1之间的相对坐标,centroid x、centroid y 是目标框中心点相对图片宽高的比例,w、h是目标框宽高相对图片宽高的比例。不是像素坐标,不是左上角坐标,是归一化中心点坐标。
举个具体例子,一张1920x1080的图片里有一只松鼠猴,标注框左上角在 (480, 270),宽420,高300,那么对应的txt内容应该是:
3 0.660 0.389 0.219 0.278计算过程就是:
- cx = (480 + 210) / 1920 = 690 / 1920 = 0.359
- cy = (270 + 150) / 1080 = 420 / 1080 = 0.389
- w = 420 / 1920 = 0.219
- h = 300 / 1080 = 0.278
上面的例子是我随手写的演示值。检查你自己的数据集时,用这种方式验算几个标注框,确认坐标系是准的。如果出现cx + w/2 > 1或者cy + h/2 > 1的情况,说明有标注框超出了图像边界,训练的时候YOLO会忽略这些框或者报warning,需要提前清洗。
2.3 classes.txt和data.yaml:别小看这两个文件
classes.txt是类别清单,一行一个类别名,行号就是类别id:
秃头僧面猴 披毛吼猴 赤猴 松鼠猴注意,类别id从0开始。上面的顺序如果是秃头僧面猴=0、披毛吼猴=1、赤猴=2、松鼠猴=3,那么标注文件里0就指秃头僧面猴,3指松鼠猴——对应关系是由classes.txt的顺序决定的。
data.yaml是ultralytics YOLOv5/v8训练时用的配置文件,基本内容:
path: /path/to/monkey_dataset train: images/train val: images/val test: images/test nc: 4 names: ['秃头僧面猴', '披毛吼猴', '赤猴', '松鼠猴']这里path建议写绝对路径,避免相对路径在不同环境下产生歧义。
2.4 类别标注的命名差异问题
如果你之前用过LableImg、LabelMe这类工具,导出的时候可能会生成voc格式的xml或者json,需要转换成YOLO txt格式。转换的时候,类别的顺序千万不能乱。我试过一次类名顺序和文件内容对不上,导致"秃头僧面猴"被模型学习成了"松鼠猴",训练过程中loss倒是正常下降,验证集上看起来也不错,但一到实际预测就全乱了。后来查了半天才意识到是类别id映射错了。处理多个来源的数据时,建议先写一个小脚本统一重命名类别,再合并。
还要提醒一点:从网上爬图或者从其他数据集转来的图片,文件名可能是中文、带空格、或者各种奇怪的编码。YOLO训练时对文件路径里的中文兼容性在不同版本的ultralytics中表现不一样,稳妥的做法是把所有图片和标注统一重命名为纯英文+数字的格式,比如:
import os import shutil base_dir = 'monkey_dataset' # 示例:将所有jpg统一编号重命名 for split in ['train', 'val', 'test']: img_dir = os.path.join(base_dir, 'images', split) for i, name in enumerate(os.listdir(img_dir)): if name.lower().endswith('.jpg'): new_name = f'{split}_{i:04d}.jpg' os.rename( os.path.join(img_dir, name), os.path.join(img_dir, new_name) ) # 对应的labels文件也要改 old_label = os.path.join(base_dir, 'labels', split, name.replace('.jpg', '.txt')) new_label = os.path.join(base_dir, 'labels', split, new_name.replace('.jpg', '.txt')) if os.path.exists(old_label): os.rename(old_label, new_label)虽然ultralytics最新版本对中文路径兼容性好了不少,但没必要在这种地方浪费调试时间,干净的路径能省掉一堆莫名其妙的报错。
3. 训练前必须完成的标注质量检查
3.1 可视化验证:光看数据统计不够
600张图说多不多,但真要一张张肉眼检查也费劲。我的做法是分三步走。
第一步,写脚本统计每个类别在训练集中的目标框数量、平均框宽高、宽高比分布。第二步,随机抽样生成可视化标注结果的图,直接在原图上画框,检查标注框是否贴合目标、有没有漏标或错标的明显问题。第三步,检查是否有空的标注文件和重复的样本。
可视化标注框的脚本可以这样写:
import cv2 import os import random def draw_yolo_boxes(img_path, label_path, class_names): img = cv2.imread(img_path) h, w = img.shape[:2] with open(label_path, 'r') as f: lines = f.readlines() for line in lines: parts = line.strip().split() cls_id = int(parts[0]) cx, cy, bw, bh = map(float, parts[1:]) x1 = int((cx - bw / 2) * w) y1 = int((cy - bh / 2) * h) x2 = int((cx + bw / 2) * w) y2 = int((cy + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, class_names[cls_id], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) return img class_names = ['秃头僧面猴', '披毛吼猴', '赤猴', '松鼠猴'] img_dir = 'monkey_dataset/images/train' label_dir = 'monkey_dataset/labels/train' # 随机抽20张 imgs = os.listdir(img_dir) random.shuffle(imgs) for name in imgs[:20]: img_path = os.path.join(img_dir, name) label_path = os.path.join(label_dir, name.replace('.jpg', '.txt')) result = draw_yolo_boxes(img_path, label_path, class_names) cv2.imshow('check', result) cv2.waitKey(0)看框的时候重点观察两件事:一是框有没有明显偏离目标中心,二是类别标得对不对。特别是四种猴子里,披毛吼猴的毛色偏深、体型较大,赤猴身上有红色毛发特征,秃头僧面猴的脸部无毛区比较明显,松鼠猴体型小、尾巴长。如果一张图里有多个目标,检查标注是否齐全,漏标是小数据集中最常见的质量问题。
3.2 常见标注错误类型与处理
我在实际检查这个数据集时遇到过几类问题,这里直接把它们列出来:
- 漏标:同一张图里只有部分目标被框了,另一只猴没标。这会导致训练时没标注的猴子成了"隐式背景",模型学着学着容易把它当成负样本。
- 类别混淆:赤猴和松鼠猴体型差别大,一般不会标错,但远距离小目标上,毛色特征不清晰时,秃头僧面猴和披毛吼猴可能被误标。
- 框太大或太小:只框了身体没框尾巴,或者把背景大片区域框进去。YOLO训练对框的大小有一定容忍度,但极端情况会影响anchor匹配的稳定性。
- 重复标注:同一个目标被标注了多次,生成两个几乎重叠的框,训练时会产生重复loss贡献。
针对漏标和错标,没别的办法,只能回到标注工具里修正。常用的是LabelImg(voc模式导出再转)或Label Studio,也可以用ultralytics自带的标注工具。如果时间紧,至少把训练集中明显有问题的样本挑出来修正,验证集尽量保证干净,否则评估阶段的mAP根本不可信。
3.3 类别不平衡的摸底
我快速统计了一下数据集里的类别分布,发现不同猴类数量差异可能很大。比如说松鼠猴通常成群出现,一张图里可能有三四只,而秃头僧面猴往往是独居或成小群,单张图里只有一两个目标。这两者目标的绝对数量可能差出好几倍。
类别不平衡在小数据集上会比较麻烦。模型会偏向学样本量多的类别,导致少样本类别召回率偏低。应对方法有两个层面。第一个层面是训练策略层面,可以在loss里给少样本类别更高的权重,YOLOv8里可以直接在data.yaml里配置weight参数,或者最简单的方式是ab上采样少样本类别的样本。第二个层面是数据层面,如果条件允许,可以针对少样本类别增加一些图像增强,尤其是水平翻转、小幅旋转和HSV颜色抖动,这些对猴脸和毛色的畸变影响不大。
4. 从零训练:600张图怎么配置才不白费
4.1 基础训练命令与参数选择
我这里用ultralytics YOLOv8来做示例,因为目前这套工具链最成熟,训练推理一条龙,而且对新手友好。600张图属于典型的小数据集,模型选择上我推荐优先试YOLOv8s,而不是最大的YOLOv8x。数据量不够的情况下,大模型几乎必然过拟合,参数量多但学不到足够的泛化特征,训练时间还长,没意义。
基础训练命令:
yolo detect train \ data=monkey_dataset/data.yaml \ model=yolov8s.pt \ epochs=300 \ imgsz=640 \ batch=16 \ patience=50 \ project=monkey_yolo \ name=run1 \ optimizer=AdamW \ lr0=0.001 \ cos_lr=True逐项解释一下这些参数的含义,因为很多人直接复制别人的配置不去理解,出了问题根本不知道怎么调:
model=yolov8s.pt:这是用COCO预训练的权重。在小数据集上,从预训练权重开始是绝对正确的事。域虽然不同(COCO里没有猴子类别),但低层特征如边缘、纹理、颜色块的信息是可迁移的,能显著加速收敛,也能在一定程度上缓解数据量不足的问题。epochs=300:600张图如果从头训,300轮完全够用甚至偏多。配合patience=50早停,实际可能100轮左右就停了。imgsz=640:YOLOv8默认就是640。雨林场景的猴类目标往往是中远距离的小目标,如果图片分辨率较高(比如3000x2000),可以考虑把imgsz调到960甚至1280来提升小目标召回率,但代价是训练时间变长、显存需求变大。后面会专门讲小目标问题。batch=16:如果你的显卡只有8GB显存,需要降到8或者4。batch太小时BN层的统计可能不稳定,这时候可以配合在数据加载上做更多增强。optimizer=AdamW, lr0=0.001:小数据集上AdamW比SGD更容易收敛,SGD需要更多轮次且对学习率更敏感。等模型在验证集上稳定之后,可以考虑切到SGD再微调几个epoch,某些场景能再涨一点精度。cos_lr=True:余弦退火学习率在小数据集上有效减少了后期振荡。
4.2 为什么先冻结主干再全量微调更稳妥
这是一个非常关键的经验:不要一开始就全量微调,而是先冻结backbone,只训练head参数,后面再解冻全量微调。
原因其实很好理解。COCO预训练权重里backbone已经学会了通用的低级视觉特征(边缘、角点、颜色、纹理),这些特征在任何目标检测任务里都是有用的。但COCO的分类头权重是针对80个类别的,对这些猴类而言没有任何先验信息。如果一上来就全量微调,反向传播会同时大幅度更新backbone和head,可能导致backbone原本学好的通用特征被破坏——这种效应在数据量越少的时候越明显,术语叫灾难性遗忘,也就是"新任务没学好,旧知识全忘光"。
具体操作分成两段:
第一阶段,冻结backbone(前10层左右),只训练detect head,用小学习率如lr0=0.0005跑50-80轮。
yolo detect train \ data=monkey_dataset/data.yaml \ model=yolov8s.pt \ epochs=80 \ imgsz=640 \ batch=16 \ freeze=10 \ optimizer=AdamW \ lr0=0.0005第二阶段,解冻全部层,用较低的学习率如lr0=0.0001再训练100-200轮,这个时候模型在充分适应猴子数据的同时,也有机会调整backbone的部分参数来适配雨林场景的复杂背景。
实际效果上,这个两阶段训练法在600张小数据集上通常比直接全量训练高出2到4个百分点的mAP,而且训练过程更稳定,很少出现loss突然飙升的情况。
4.3 数据增强:小数据集的命根子
600张图对目标检测来说属于"紧巴巴"的量,数据增强就不再是锦上添花,而是必须的基础配置。YOLOv8默认开启了一部分增强:mosaic、random_perspective、hsv_h/s/v扰动等,但为了适配雨林灵长类这个场景,我建议做如下调整。
雨林图片的特点是什么?光线暗、对比度低、绿色和深褐色占主导、枝叶遮挡多、目标颜色可以和背景融为一体。所以针对性的增强策略是:
- 提高hsv_h的范围:让模型不依赖"偏绿"这个背景先验,比如
hsv_h=0.02。 - 增大hsv_s和hsv_v:模拟不同光照条件,我一般设
hsv_s=0.9, hsv_v=0.5。 - 增大random_perspective的scale和translate:让模型适应目标在画面中不同位置和不同尺度的变化,
scale=0.5, translate=0.2。 - 增加flipud:上下翻转对猴子检测通常没影响,但雨林场景里猴子的姿态本来就多样,加上它能增加样本多样性。
- mosaic保持开启:mosaic把4张图拼成一张,能够有效增加单张图上的目标数量,小数据集里这是一个重要的增广手段。但注意mosaic在训练后期可以关闭,或者降低概率,因为拼图产生的目标分布和真实场景分布不完全一致。
YOLOv8里这些参数直接写在训练命令里:
yolo detect train \ data=monkey_dataset/data.yaml \ model=yolov8s.pt \ epochs=200 \ imgsz=640 \ batch=16 \ optimizer=AdamW \ lr0=0.0001 \ hsv_h=0.02 \ hsv_s=0.9 \ hsv_v=0.5 \ translate=0.2 \ scale=0.5 \ flipud=0.54.4 小目标检测:雨林猴类不可避免的痛点
猴类检测有一个天然难题:猴子喜欢待在树冠层,离拍摄者远,所以画面里的目标往往很小。YOLOv8在COCO上对小目标的检测能力已经比YOLOv5强了不少(因为引入了更多细粒度的特征融合),但对于600张图的小数据集来说,小目标问题依然严峻。
如果你发现验证集上小目标(像素面积小于32x32)的AP远低于中大型目标,有几个方案可以尝试:
第一个方案最简单:把imgsz从640提高到960或1280。图像分辨率高了,小目标在feature map上对应的像素点就多,检测器能提取到更多特征。代价是训练时间和显存翻倍。我有一次在自定义数据集上把imgsz从640提到960,小目标AP直接涨了7个点,代价是训练时间多了两倍。这个提升非常可观。
第二个方案是从数据层面解决。如果原始图片中猴类的目标框平均尺寸很小,可以考虑在预处理阶段对图片做切块。比如把1920x1080的图切成四个960x540的patch,每块单独检测,训练时相当于把目标放大了。这种做法在小目标检测中很常见,但需要注意patch之间的目标划分逻辑,防止切开后目标被截断。
第四个方向是换模型结构,比如使用YOLOv8的P2输出层或者像YOLOv5的P2分支,专门增强小目标检测。不过这种改动通常需要改yaml配置并重新训练,600张数据的条件下收益不一定稳定,建议先把前两个方案试完再考虑这个复杂性。
5. 训练完,别急着欢呼:评估与部署环节的隐藏问题
5.1 从结果文件里读出真实水平
训练完成后,项目中会生成很多结果,最关键的三个指标是mAP50、mAP50-95和混淆矩阵。mAP50是IOU阈值0.5下的平均精度,对"框得大概准不准"更宽容;mAP50-95是0.5到0.95每隔0.05取一个阈值然后平均,更严格,也更接近实际部署时对框精度的要求。小数据集上mAP50达到0.85以上,mAP50-95到0.6以上,就已经是不错的成绩了。
但这里我要强调一个很多人忽略的点:验证集上的mAP只能作为参考,不能完全代表实际野外场景的表现。因为你用的验证集图像和训练集很可能来自同一个数据采集批次,光照条件、相机型号、拍摄高度都高度相似。模型可能学到的是"这个特定拍摄条件下的猴子"而不是"热带雨林里的猴子"。判断模型泛化能力的唯一标准是拿一批全新的、不在数据集里的图片来测试。
5.2 混淆矩阵:找"谁和谁容易被认错"
训练结束后,ultralytics会在runs/detect/run1/下生成confusion_matrix.png。这张图我对所有数据集都会认真看一遍。灵长类数据里最容易出现混淆的地方通常是:
- 披毛吼猴被识别成秃头僧面猴:因为两者毛色都偏深,远距离下头部特征不明显。
- 松鼠猴被漏检:因为松鼠猴体型最小,且经常在高处密集树冠中活动。
- 赤猴和松鼠猴的混淆:赤猴的幼体和松鼠猴体型相近。
如果混淆矩阵显示某两个类别之间误检率高,有两个处理方向。第一个方向是回顾标注质量,看是不是有标签错标导致类别边界模糊。第二个方向是考虑是否能合并类别——如果你的业务场景不需要细分到物种级别,那么把毛色相近的类别合并为"猴类"反而是更务实的方案。但既然数据集的定位就是四种猴类分别检测,一般不建议合并,还是要通过增加数据和精标来解决。
5.3 导出与推理:ONNX、TensorRT和实际效果
训练得到的最佳权重可以导出为不同格式用于部署。最基本的是导出ONNX:
yolo export model=monkey_yolo/run1/weights/best.pt format=onnx opset=12导出后的ONNX文件可以在CPU上跑,也可以转成TensorRT在NVIDIA GPU上跑。如果你要在Jetson或者其他边缘设备上部署,TensorRT是更好的选择,推理速度可以提升到毫秒级。
推理测试时,我会选一些场景有难度的图,比如猴子在阴影里、猴子的身体大部分被树叶遮挡、多个猴目标密集在一起。命令行测试:
yolo predict model=monkey_yolo/run1/weights/best.pt source=test_images/ save=True conf=0.25conf=0.25是置信度阈值,实际部署时根据你的误检容忍度来调。如果检测场景中允许漏检但不能有误报,就把conf调高到0.4甚至0.5;如果要求尽可能多的检出目标,可以降到0.15然后配合NMS处理。这个平衡没有标准答案,完全取决于业务需求。
5.4 处理"训练时loss很低,但测试时一团糟"的过拟合
小数据集训练中最常见的现象之一就是过拟合:训练集loss很低、验证集mAP也算正常,但拿到真实场景的新图片上一测,各种误检漏检。
过拟合的典型特征在训练曲线里能看到:训练loss和验证loss在训练后期明显分叉,train loss持续下降而val loss反而上升。如果出现这种情况,优先考虑的操作:
- 增加更大的数据增强(比如mixup、copy-paste等)。
- 降低模型容量:从YOLOv8s换成YOLOv8n。
- 增加正则化:调大
weight_decay,比如从默认0.0005调到0.001。 - 早停:直接把训练轮次限制在验证loss最低点附近。
- 收集更多的数据(这是根本方案,如果实际场景允许的话)。
如果你有时间和算力,还可以做一次简单的消融实验:用三组配置分别训练(默认增强、增强拉满、增强拉满+更小模型),对比验证集mAP和少量真实样本上的推理效果,选出泛化能力最好的那一组。
6. 把模型部署成实用的API服务
6.1 在FastAPI上部署一个检测服务
训练好模型之后的下一步通常是把它接到业务流程里。不管你是要做生态监测、动物行为分析,还是景区里的猴群数量统计,部署成一个HTTP接口是更通用的方式。这里我给出一个在FastAPI上部署YOLOv8检测服务的最小实现,亲测有效:
from fastapi import FastAPI, File, UploadFile from ultralytics import YOLO import numpy as np import cv2 app = FastAPI() model = YOLO('monkey_yolo/run1/weights/best.pt') CLASS_NAMES = ['秃头僧面猴', '披毛吼猴', '赤猴', '松鼠猴'] @app.post('/detect') async def detect(file: UploadFile = File(...)): # 读取上传的图片 img_bytes = await file.read() img_array = np.frombuffer(img_bytes, dtype=np.uint8) img = cv2.imdecode(img_array, cv2.IMREAD_COLOR) # 推理 results = model(img, conf=0.25, iou=0.5) boxes = [] for r in results: for box in r.boxes: x1, y1, x2, y2 = box.xyxy[0].tolist() conf = float(box.conf[0]) cls_id = int(box.cls[0]) boxes.append({ 'bbox': [int(x1), int(y1), int(x2), int(y2)], 'confidence': round(conf, 4), 'class_name': CLASS_NAMES[cls_id], 'class_id': cls_id }) return { 'num_objects': len(boxes), 'detections': boxes, 'class_count': { name: sum(1 for b in boxes if b['class_name'] == name) for name in CLASS_NAMES } } # 用 uvicorn main:app --host 0.0.0.0 --port 8000 启动一个值得注意的细节是:在API服务里,model(img, conf=0.25, iou=0.5)中传入的image可以是numpy array,也可以是路径字符串。如果你传的是numpy array,ultralytics不会重复做文件I/O,效率更高。如果要做高并发,建议把模型初始化为全局变量,不要在每个请求里重新加载。
6.2 部署时相关的性能优化点
实际部署中,单帧检测的延迟往往不是瓶颈,瓶颈是视频流场景的多路并发和图像预处理。几个实操方向:
- 使用
model.predict(source=..., stream=True)来处理视频流,避免每帧都重建内存。 - 在GPU部署时用
half=True开半精度推理,显存占用减半、速度提升明显,精度损失通常很小。 - 如果输入是视频帧,可以先做帧差或者运动检测,只有画面变化明显的帧才送进检测器,减少无效推理。
6.3 面向真实自然场景的稳定性提醒
雨林场景部署有一个容易忽略的问题:相机抖动和运动模糊。如果在移动的无人机或者晃动严重的固定摄像头上推理,模糊帧会导致检测框抖动厉害。实用的做法是检测前加一个图像清晰度筛选,比如用Laplacian方差判断帧是否模糊,低于阈值的帧直接丢弃或等待更清晰的帧。
另外,雨林的强光、逆光、晨昏交界时段的色温变化也会影响检测效果。如果你采集的数据集中包含各种光照条件下的图片,模型的鲁棒性会好很多。我建议在部署后的一两周内持续收集误检错检样本,定期补充进训练集做微调,这个"部署后反馈闭环"比任何训练技巧都重要。
7. 个人经验:600张数据集的三个"保命"建议
最后分享几条实操心得,是从这类小规模专用数据集上摸爬滚打出来的经验。
第一,验证集千万不能用训练集同帧的视频截帧。我踩过这个坑。之前做一个野生动物检测项目,采集的是连续视频流,直接按时间顺序截帧后划分训练验证集,结果很多"验证"图片和"训练"图片是同一只猴子的不同帧,目标位置变化很小。验证集mAP高达0.93,实际一到新场景直接跌到0.4。正确的做法是:尽量让同一个体、同一次拍摄来源的图像只出现在训练集或验证集中,否则验证分数会虚高,模型泛化能力远没有你想的那么好。
第二,宁可训练集图片少几张,也要保证每张图的标注质量。600张图里如果有20%的标注框对不齐目标,模型学到的特征边界是模糊的。用2到3个小时把全部标注做一次可视化检查并修正明显问题,比盲目增加训练轮次带来的收益大得多。我通常把可视化检查脚本和训练脚本放到同一个项目目录里,每次拿到新数据先检查再训练,形成固定流程。
第三,小数据集的AI项目,真正的核心竞争力是数据迭代能力。模型训练只需要几个小时,但把模型放到真实场景中发现的错误案例收集回来、通过半自动标注工具处理、合并进训练集再训练,这个闭环的速度才决定最终效果。YOLO系列模型已经到了一个相对成熟的阶段,不是靠调参就能变出质的飞跃,而是靠高质量数据和快速迭代把精度一点一点啃上去。
如果你正在用这批数据做雨林灵长类的检测研究或应用开发,希望整个从解压到部署的流程能帮你少走一些弯路。猴子是不会站在那里等你的模型的,但训练和部署的每一条弯路,都是自己去爬过才知道深浅。
本文还有配套的精品资源,点击获取
