ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

成人和小孩检测数据集实战:从1738张YOLOv9标注到70.9%识别率提升

成人和小孩检测数据集实战:从1738张YOLOv9标注到70.9%识别率提升 简介这份成人与小孩图像数据集面向计算机视觉入门与目标检测实践者尤其适合正在做YOLO系列模型训练、需要二分类人物属性识别素材的开发者与学习者。数据集共1738张原始图片全部按yolov9格式完成标注可直接接入YOLOv9训练流程省去自行标注与格式转换的时间成本。压缩包内共2000个文件以1738个txt标注文件、261个jpg图像文件及1个yaml配置文件为主yaml用于定义数据集路径与类别信息txt与jpg一一对应便于快速划分训练集与验证集。资源包整体约91.41MB体积适中下载与本地训练负担较小。据描述该数据集在成人与小孩识别任务上的识别率约为70.9%可作为基线参考帮助读者评估模型效果并针对性调参。目前已有167人学习下载适合想快速验证YOLOv9训练流程、积累人物属性识别经验的中初级用户参考使用。1. 1738 张原始图片、70.9% 识别率成人和小孩检测数据集到底能不能直接上项目拿到一个标注好的成人和小孩数据集1738 张原始图片yolov9 格式标注标称识别率 70.9%第一反应通常不是兴奋而是先算一笔账这个量级够不够训一个能用的模型70.9% 是在什么条件下测出来的yolov9 格式的标注能不能直接喂给 yolov8 或者别的检测器。我见过太多人拿到数据集直接开训跑完发现验证集 mAP 只有 0.4 出头回头查才发现标注框大量漏标、类别定义混乱、训练集和验证集里同一个人出现在两边。成人和小孩的检测本身不算难难的是小孩这个类别——身高矮、遮挡多、姿态变化大、经常被大人抱着或者只露出半个身子这些都会把识别率往下拽。这篇文章不讲空泛的数据集介绍而是把 1738 张 yolov9 格式标注的成人和小孩数据集从检查、清洗、转换到训练、调参、评估的完整路径拆开告诉你 70.9% 这个数字背后可能是什么以及怎么把它往上推。适合手里已经拿到类似数据集、准备做家庭场景监控、儿童看护辅助、公共场所人流分析这类应用的工程师也适合刚接触目标检测、想拿一个真实数据集练手的新手。2. 先搞清楚 1738 张图片和 yolov9 标注到底给了你什么2.1 成人和小孩两类目标的标注特点成人和小孩在检测任务里通常被定义为两个类别但这两个类别的视觉边界并不像猫和狗那么清晰。一个 16 岁的少年算成人还是小孩一个蹲着的大人会不会被标成小孩这些在标注阶段如果没有明确的规则就会变成模型训练时的噪声。1738 张图片里如果小孩样本只占 20% 到 30%那实际可用于学习小孩特征的正样本可能只有三四百张这对一个需要区分姿态和比例的类别来说偏少。常见做法是先把标注文件全部解析一遍统计每个类别的实例数量和每张图的平均目标数心里先有个底。yolov9 格式的标注本质上是每张图片对应一个 txt 文件每行五个值类别索引、归一化中心点 x、归一化中心点 y、归一化宽度、归一化高度。这个格式和 yolov5、yolov8 是兼容的所以拿到 yolov9 标注不等于只能训 yolov9你可以直接用来训 yolov8甚至转成 COCO 格式给别的框架用。但要注意类别索引的映射关系有些数据集把 adult 设为 0、child 设为 1有些反过来如果配置文件里的 names 顺序和标注文件不一致训练出来的模型会把两个类别完全搞反。2.2 用脚本统计类别分布和标注质量在训练之前我一般会写一个检查脚本把标注文件全部读一遍输出类别分布、每类目标数、宽高比分布以及有没有越界框或者零面积框。下面这段代码可以直接跑只需要把路径换成你自己的。import os import glob from collections import Counter # 标注文件夹路径假设图片和 txt 在同一目录下按同名对应 label_dir ./labels image_dir ./images class_names {0: adult, 1: child} # 根据你的 data.yaml 修改 counter Counter() bad_boxes [] zero_area [] aspect_ratios [] for txt_path in glob.glob(os.path.join(label_dir, *.txt)): with open(txt_path, r) as f: lines f.readlines() for line in lines: parts line.strip().split() if len(parts) ! 5: bad_boxes.append((txt_path, line.strip())) continue cls_id int(parts[0]) x, y, w, h map(float, parts[1:]) counter[class_names.get(cls_id, funknown_{cls_id})] 1 if w 0 or h 0: zero_area.append((txt_path, line.strip())) if x - w/2 0 or x w/2 1 or y - h/2 0 or y h/2 1: bad_boxes.append((txt_path, line.strip())) if h 0: aspect_ratios.append(w / h) print(类别分布:, dict(counter)) print(异常框数量:, len(bad_boxes)) print(零面积框数量:, len(zero_area)) print(宽高比范围: {:.2f} ~ {:.2f}.format(min(aspect_ratios), max(aspect_ratios)))这段脚本做了四件事统计每个类别的实例总数、找出格式不对的行、找出宽高为零的框、找出超出图像边界的框。类别分布能告诉你小孩样本是不是太少异常框数量能告诉你标注质量的下限。如果异常框超过总框数的 2%建议先清洗再训练否则模型会学到一些莫名其妙的定位模式。宽高比范围可以帮你判断先验框anchor需不需要重新聚类如果大部分框的宽高比集中在 0.3 到 0.6 之间而默认 anchor 覆盖的是 0.5 到 2.0那检测效果会明显打折。2.3 划分训练集和验证集时最容易忽略的坑1738 张图片如果随机划分很容易出现同一个人同时出现在训练集和验证集的情况尤其是从视频里抽帧得到的数据集。这种泄漏会让验证集指标虚高你以为模型学到了特征其实它只是记住了那个人。我一般会按场景或者按视频来源划分同一段视频的帧只放在一个集合里。如果数据集没有提供来源信息至少要用图片哈希或者感知哈希做一次去重把近似重复的图片归到同一侧。import hashlib from PIL import Image import imagehash def file_hash(path): return hashlib.md5(open(path, rb).read()).hexdigest() def phash(path): return str(imagehash.phash(Image.open(path))) # 先按精确哈希去重再用感知哈希找近似重复 hashes {} for img in glob.glob(os.path.join(image_dir, *.jpg)): h phash(img) hashes.setdefault(h, []).append(img) duplicates {k: v for k, v in hashes.items() if len(v) 1} print(近似重复组数:, len(duplicates))感知哈希能把视觉上几乎一样的图片归到一组比如同一个人连续几帧的截图。把这些组整体分到训练集或者验证集才能得到真实的泛化指标。这一步做完你可能会发现 1738 张里实际独立场景只有一千出头那 70.9% 的识别率是在什么划分下测出来的就值得追问了。3. 把 yolov9 标注转成可训练配置并跑通第一轮3.1 data.yaml 的写法和类别顺序对齐yolov9 官方仓库的训练配置和 yolov5、yolov8 基本一致核心是一个 data.yaml 文件里面指定训练、验证、测试图片的路径类别数量以及类别名称列表。类别名称的顺序必须和标注文件里的类别索引严格对应否则训练出来的模型会把 adult 和 child 完全颠倒。# data.yaml train: ./images/train val: ./images/val test: ./images/test nc: 2 names: 0: adult 1: child这里 nc 是类别数names 下面的数字是索引。如果你在 2.2 节的统计脚本里发现 unknown 类别说明标注文件里出现了 0 和 1 以外的索引需要先修正。常见情况是有些标注工具默认从 1 开始编号或者把背景类也写进去了。修正方法很简单把超出范围的索引统一映射到正确的类别或者直接删除这些行。3.2 用 yolov9 训练的最小命令和关键参数假设你已经把图片和标注按 train、val、test 分好目录结构是 images/train、labels/train 这样对应。yolov9 的训练入口通常是 train.py 或者通过 ultralytics 风格的接口调用。下面给出一个最小可跑的命令行示例。python train.py \ --data data.yaml \ --weights yolov9-c.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --device 0 \ --workers 4 \ --name adult_child_exp1参数逐个说--img 640 是输入分辨率1738 张图片如果原图分辨率很高可以先缩到 640 训练速度快且对小目标检测够用--batch 16 在单卡 8G 显存下比较稳如果显存不够降到 8--epochs 100 对一千多张图片来说通常够收敛但要注意观察验证集指标有没有过拟合--workers 4 是数据加载线程数根据 CPU 核心数调整。第一次跑建议先用小分辨率和小 epoch 验证流程通不通比如 --img 320 --epochs 10确认没有报错再上完整训练。如果用的是 ultralytics 风格的接口命令会更简洁yolo detect train datadata.yaml modelyolov9c.pt epochs100 imgsz640 batch16两种方式本质一样选你环境里已经装好的那个。训练开始后重点看三个输出box_loss、cls_loss 和验证集的 mAP50。如果 box_loss 下降但 cls_loss 不降说明定位在学但分类分不开可能是小孩和成人的特征太接近需要检查标注里有没有把大人标成小孩的情况。3.3 第一轮训练后怎么读指标训练结束后会在 runs 目录下生成结果重点看 confusion_matrix.png 和 results.csv。混淆矩阵能直接告诉你 adult 和 child 之间有没有大量互错。如果 child 被大量预测成 adult而 adult 的召回很高说明模型倾向于把矮个子也当成大人这时候要么增加小孩样本要么在损失函数里给 child 类别更高的权重。70.9% 这个识别率如果指的是 mAP50那在两类目标检测里属于中等偏下还有不少提升空间。如果指的是准确率accuracy那定义就不太一样了目标检测里很少用单纯的 accuracy更常见的是 mAP50 或者 mAP50-95。拿到数据集时最好先确认这个 70.9% 的评估协议是什么是在多少张图上测的阈值取了多少否则这个数字没法直接比较。4. 把 70.9% 往上推数据增强、类别平衡和推理调参4.1 针对小孩样本的增强策略小孩样本少、姿态多、遮挡严重通用的随机翻转和缩放不够用。我一般会针对 child 类别做几件事第一用 mosaic 增强把四张图拼成一张增加小孩出现在不同上下文里的概率第二用 copy-paste 增强把小孩实例复制到其他背景上但要注意粘贴的位置要合理不能把小孩贴到天花板上第三调整尺度增强的范围让模型多看到小尺寸的小孩。yolov9 的增强参数通常在 hyp 文件里配置关键几个是 mosaic、mixup、copy_paste、scale。下面是一个针对小目标偏多的配置片段。# hyp_adult_child.yaml mosaic: 1.0 mixup: 0.1 copy_paste: 0.3 scale: 0.6 degrees: 5.0 translate: 0.1 fliplr: 0.5 flipud: 0.0 hsv_h: 0.015 hsv_s: 0.7 hsv_v: 0.4mosaic 设为 1.0 表示每张图都做拼接mixup 0.1 是轻微混合copy_paste 0.3 表示 30% 的概率做实例复制粘贴。scale 0.6 表示随机缩放范围是 0.4 到 1.6 倍比默认的 0.5 更宽能让模型看到更多尺寸变化。degrees 5.0 是轻微旋转小孩的姿态变化通常不需要大角度旋转太大的旋转反而会引入不自然的样本。flipud 设为 0 是因为上下翻转在真实场景里很少出现开了反而增加噪声。4.2 类别不平衡的损失加权如果统计发现 child 实例只有 adult 的三分之一可以在损失函数里给 child 更高的分类权重。yolov9 默认的分类损失是 BCE可以通过修改数据集配置或者训练脚本里的类别权重参数来实现。一种简单做法是在 data.yaml 里加一行 class_weights但不同版本的 yolov9 支持程度不一样更稳妥的方式是在训练脚本里手动调整。# 在损失计算前给不同类别赋权重 class_weights torch.tensor([1.0, 2.5]).to(device) # adult 权重 1.0child 权重 2.5 # 在 BCE 损失里传入 weight 参数 criterion nn.BCEWithLogitsLoss(pos_weightclass_weights)这里的 pos_weight 是正样本权重child 设为 2.5 意味着模型对 child 的分类错误惩罚更重。这个值不要设太大超过 5 容易导致训练不稳定出现大量误检。可以先从 2.0 开始试观察验证集上 child 的召回有没有提升同时看 adult 的精度有没有明显下降。4.3 推理阶段的置信度和 NMS 调参训练完模型推理时的置信度阈值和 NMS 的 IoU 阈值对最终识别率影响很大。默认 conf 0.25、iou 0.45 在成人和小孩检测里不一定最优。如果小孩漏检多可以把 conf 降到 0.15 到 0.2让更多候选框进入 NMS如果误检多就提高 conf。NMS 的 iou 阈值如果设得太低两个挨着的人会被合并成一个框尤其是大人抱着小孩的场景iou 设到 0.5 到 0.6 更合适。yolo detect predict modelruns/train/adult_child_exp1/weights/best.pt \ source./test_images \ conf0.2 \ iou0.55 \ saveTrue这段命令用训练好的 best.pt 对测试图片做推理conf 0.2 比默认低iou 0.55 比默认高。跑完之后人工看一批结果重点看小孩被漏检的情况和大人小孩挨在一起时框有没有合并。如果发现某个场景下识别率明显低比如夜间或者逆光那说明数据集里这类样本太少需要针对性补充。5. 避坑成人和小孩检测里最容易翻车的五个地方5.1 标注里把青少年标成小孩导致类别边界模糊现象是模型在验证集上 adult 和 child 的混淆矩阵里互错比例很高尤其是身高在 1.4 到 1.6 米之间的目标。原因是标注阶段没有明确的年龄或身高规则不同标注员对小孩的定义不一致。解决方法是回看标注规范如果数据集没有提供就自己定一个可操作的规则比如以头部占全身比例或者以参考物高度来判断然后重新检查边界样本。如果无法重新标注至少在训练时把这类模糊样本的损失权重降低。5.2 从视频抽帧导致训练集和验证集泄漏现象是验证集 mAP 很高但拿真实新视频一测就崩。原因是同一段视频的相邻帧被随机分到了训练集和验证集模型记住了背景和人物外观。解决方法是用 2.3 节的感知哈希做去重按视频来源划分数据集。如果数据集已经混在一起至少把验证集里的图片在训练集里做一次近似搜索把重复的删掉。5.3 图片分辨率不一致导致训练时大量黑边现象是训练时 loss 震荡验证集指标上不去。原因是 1738 张图片里分辨率差异很大有的 1920x1080有的 640x480直接 resize 到 640x640 会引入大量黑边或者拉伸变形。解决方法是先统计图片尺寸分布如果长宽比差异大用 letterbox 填充而不是直接拉伸。yolov9 默认会做 letterbox但如果你自己预处理过图片要确认没有破坏这个机制。5.4 小孩被遮挡时标注框只标了可见部分现象是模型对遮挡小孩的召回很低经常漏检。原因是标注时只标了可见的身体部分导致模型学到的 child 特征偏向于完整身体。解决方法是检查标注规范遮挡超过 50% 的目标是否应该标、怎么标。如果数据集里大量遮挡样本只标了局部可以在训练时用 cutout 或者 random erasing 增强让模型适应不完整目标。5.5 70.9% 的评估协议不明确导致优化方向错误现象是花了很多时间调参指标提升不明显。原因是不知道 70.9% 是在什么条件下测的可能是在训练集上测的也可能是 mAP50 但 IoU 阈值设得很低。解决方法是自己重新跑一遍基线评估固定验证集、固定 conf 和 iou得到自己的基线数字然后所有优化都跟这个基线比。不要拿别人的 70.9% 当目标要拿你自己的基线当目标。6. 用混淆矩阵和误检样本反推数据集该怎么补训练完一轮之后最有价值的不是 mAP 数字而是混淆矩阵和误检样本的可视化。我一般会把验证集里所有 child 被预测成 adult 的图片挑出来按置信度从高到低排看前 20 张。如果这些图片里小孩的身高确实接近成人那说明类别定义本身有问题补数据也没用得改标注规则。如果这些图片里小孩明显矮小但被误判那说明模型对尺度不敏感需要增加小目标增强或者调整 anchor。另一个技巧是把误检样本按场景分组比如室内、室外、白天、夜间、单人、多人。如果某个场景下误检率明显高就针对这个场景补 50 到 100 张图重新标注后加入训练集。1738 张的基数下补 100 张针对性样本通常能带来 2 到 5 个点的 mAP 提升比盲目加数据有效得多。# 按场景分组统计误检率 import pandas as pd # 假设你有一个 csv 记录了每张图的场景标签和预测结果 df pd.read_csv(val_results.csv) grouped df.groupby(scene).agg( total(image_id, count), false_positive(is_fp, sum), false_negative(is_fn, sum) ) grouped[fp_rate] grouped[false_positive] / grouped[total] grouped[fn_rate] grouped[false_negative] / grouped[total] print(grouped.sort_values(fn_rate, ascendingFalse))这段代码按场景统计误检率和漏检率输出排序后你能直接看到哪个场景最差。优先补漏检率高的场景因为漏检通常比误检更影响实际使用。补数据的时候注意新样本的标注质量和原有数据集保持一致否则引入新的噪声反而会拉低指标。最后说一个我自己的习惯每次拿到新数据集先花半天做统计和可视化不要急着开训。这半天能帮你避开后面几天的无效调参。成人和小孩检测这个方向数据质量比模型结构重要得多1738 张如果标注干净、类别平衡70.9% 只是起点如果标注混乱再大的模型也救不回来。希望帮到你。本文还有配套的精品资源点击获取
返回列表