ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

1738张图片70.9%识别率:成人和小孩检测数据集实战指南

1738张图片70.9%识别率:成人和小孩检测数据集实战指南 简介本资源为面向计算机视觉初学者与目标检测开发者的成人和小孩识别数据集适用于行人属性分析、人群计数、智能安防等场景的模型训练与验证。包内共2000个文件以1738个txt标注文件、261张jpg原始图片及1个yaml配置文件为主标注采用yolov11格式可直接接入主流检测框架进行训练压缩包整体约91.35MB目录结构清晰便于按类别检索。该数据集在成人与小孩两类目标上的识别率约为70.9%可作为基线参考帮助读者快速验证模型效果并对比调参。目前已有112人学习下载适合需要快速搭建实验环境、补充训练样本或开展课程设计的中初级开发者参考使用。1. 1738 张原始图片、70.9% 识别率成人和小孩检测数据集到底能不能直接上生产手里只有 1738 张原始图片标注是 yolov11 格式官方给的识别率是 70.9%任务是区分成人和小孩——这个数据集第一眼看上去像是「能跑但不敢用」的典型。我拿到这类数据集时不会先看 mAP 曲线而是先问三个问题70.9% 是在什么划分下测出来的、成人和小孩的类间差异靠什么特征支撑、1738 张够不够撑起一个二分类检测头。这篇文章就是围绕这三个问题展开把「这是什么、能不能用、怎么复现、坑在哪」一次讲透。适合两类人看一类是手上已经有一批带标注的图片想快速验证成人和小孩检测能不能落地另一类是准备自己采数据、自己标想先搞清楚 1738 张这个量级到底意味着什么。我不会把它写成数据集说明书而是按我实际跑这类小数据集的顺序从格式校验、划分、训练参数到误检排查一步步走。yolov11 在这个任务上不是万能钥匙70.9% 也不是终点关键是你要知道这 70.9% 是怎么来的、还能往哪推。2. 先搞清楚 1738 张和 70.9% 这两个数字的真实含义2.1 成人和小孩检测为什么比通用目标检测更难成人和小孩在检测任务里属于「同类不同尺度」的问题。两者都是人整体轮廓、衣着分布、姿态空间高度重叠模型要区分的不是「有没有人」而是「这个人的身高比例、头部占身体的比例、肢体长度落在哪个区间」。这就导致一个很尴尬的局面如果标注框只框了上半身成人上半身和小孩上半身的像素分布几乎无法区分如果框了全身小孩在画面里往往只占几十个像素又掉进了小目标检测的坑。我见过太多人拿 COCO 预训练的 yolov11 直接微调结果模型学到的其实是「大框成人、小框小孩」这种捷径。在测试集上如果小孩恰好都离镜头远指标会虚高一旦换成小孩站在前排的近景识别率立刻掉到 50% 以下。70.9% 这个数字本身不可怕可怕的是你不知道它是不是靠这种尺度捷径刷出来的。所以第一步不是训练而是把数据集里成人和小孩的框面积分布画出来看两类是否存在系统性尺度差异。2.2 1738 张原始图片在二分类检测里的真实容量1738 张听起来不多但对于「成人 vs 小孩」这种只有两个类、且场景相对固定的任务它并不是完全不够用。关键看两点单张图里平均有多少个目标框以及场景多样性有多高。如果 1738 张里每张平均 2 到 3 个人总框数在 4000 上下按 8:1:1 划分验证集大概 400 张、测试集 170 张左右这个量级做一次可信的评估是够的但做交叉验证就会很勉强。真正决定上限的是场景覆盖。如果这 1738 张全部来自同一个商场入口、同一个光照条件、同一个摄像头角度那模型学到的就是「这个摄像头下的人」换个场景直接翻车。我一般会先做一次场景聚类按分辨率、亮度均值、拍摄角度粗分几组看每组有多少张。如果某一组少于 100 张就要警惕模型在这类场景上没有泛化能力。这一步不需要写复杂代码用 OpenCV 批量算一下亮度直方图和图像尺寸就能看出端倪。2.3 yolov11 格式标注的目录结构和校验要点yolov11 沿用 YOLO 系列的标注格式每张图片对应一个同名 txt每行是class_id x_center y_center width height坐标全部归一化到 0 到 1。目录通常是images/train、images/val、labels/train、labels/val这样的结构配一个 data.yaml 指明路径和类别名。拿到数据集第一件事不是训练而是校验因为标注错误在小数据集里会被放大。import os from pathlib import Path def check_yolo_dataset(root, num_classes2): 校验 YOLO 格式数据集坐标范围、类别 id、空标注、图片标注配对 img_dir Path(root) / images lbl_dir Path(root) / labels problems [] total_boxes 0 empty_labels 0 for img_path in img_dir.rglob(*): if img_path.suffix.lower() not in (.jpg, .jpeg, .png): continue # 找同名 label 文件 rel img_path.relative_to(img_dir) lbl_path lbl_dir / rel.with_suffix(.txt) if not lbl_path.exists(): problems.append(f缺标注: {rel}) continue lines lbl_path.read_text().strip().splitlines() if not lines: empty_labels 1 continue for i, line in enumerate(lines): parts line.split() if len(parts) ! 5: problems.append(f字段数错误 {rel}:{i}) continue cid int(parts[0]) coords [float(x) for x in parts[1:]] if cid 0 or cid num_classes: problems.append(f类别越界 {rel}:{i} cid{cid}) if any(c 0 or c 1 for c in coords): problems.append(f坐标越界 {rel}:{i} {coords}) if coords[2] 0 or coords[3] 0: problems.append(f宽高非正 {rel}:{i}) total_boxes 1 print(f总框数: {total_boxes}, 空标注文件: {empty_labels}, 问题数: {len(problems)}) for p in problems[:20]: print( , p) return problems check_yolo_dataset(./adult_child_dataset, num_classes2)这段脚本做四件事检查图片和标注是否一一对应、类别 id 是否在 0 到 1 之间、归一化坐标是否越界、宽高是否为正。参数num_classes2对应成人和小孩两类如果你的 data.yaml 里类别顺序是[adult, child]那 0 就是成人、1 就是小孩。跑完如果问题数超过总框数的 1%我建议先修标注再训练否则模型会去拟合这些脏数据。空标注文件要单独看如果一张图里确实没有人空 txt 是合法的但如果本该有人却空了那就是漏标。3. 用 yolov11 在本地跑通成人和小孩检测的最小流程3.1 环境配置和 data.yaml 的正确写法yolov11 的环境依赖 ultralytics 这个包我一般用 conda 建一个干净环境避免和系统里的 torch 版本打架。常见做法是 Python 3.10 加 PyTorch 2.x然后 pip 装 ultralytics。装完先跑yolo checks确认 CUDA 和版本都对得上这一步能省掉后面一半的玄学报错。conda create -n yolo11 python3.10 -y conda activate yolo11 pip install ultralytics yolo checksdata.yaml 是整个训练的入口写错一个路径就会报「no labels found」。我一般写成绝对路径避免相对路径在不同工作目录下失效。path: /data/adult_child_dataset train: images/train val: images/val test: images/test names: 0: adult 1: childpath是数据集根目录train/val/test是相对 path 的子路径names的顺序必须和标注里的 class_id 严格对应。这里最容易翻车的是 names 顺序写反导致成人被当成小孩训练最后指标看着还行但语义全错。写完 yaml 后用 ultralytics 自带的检查跑一遍确认能找到图片和标注。3.2 从预训练权重微调到 70.9% 的参数设置小数据集微调的核心矛盾是学习率太大模型遗忘预训练特征太小又学不动新类。我一般分两段先冻结 backbone 训 10 个 epoch 让检测头适应新类再解冻全网络用较小学习率训 50 到 100 个 epoch。输入尺寸不要一上来就 640如果小孩目标偏小可以提到 960 甚至 1280但显存要跟上。yolo detect train \ modelyolo11s.pt \ data/data/adult_child_dataset/data.yaml \ epochs100 \ imgsz960 \ batch16 \ lr00.001 \ lrf0.01 \ warmup_epochs3 \ freeze10 \ patience20 \ projectruns/adult_child \ nameexp1modelyolo11s.pt是官方预训练权重s 版本在精度和速度之间比较平衡imgsz960是为了让小孩目标保留更多像素freeze10冻结前 10 层适合小数据集防止过拟合patience20表示 20 个 epoch 指标不涨就早停。跑完第一轮后我会看results.csv里的metrics/mAP50-95和每一类的metrics/mAP50如果成人高、小孩低说明模型在小孩上欠拟合下一步要么加小孩样本要么调 anchor 或输入尺寸。3.3 训练日志里必须盯住的三个指标训练不是跑完看一个总数就完事。我盯三个东西第一是每一类的 mAP50成人和小孩分开看如果差距超过 15 个点说明类别不平衡或特征混淆第二是train/box_loss和val/box_loss的走势如果训练 loss 一直降但验证 loss 抬头就是过拟合要加数据增强或减模型容量第三是混淆矩阵看成人被误判成小孩的比例这个数字比总 mAP 更能说明问题。import pandas as pd df pd.read_csv(runs/adult_child/exp1/results.csv) df.columns [c.strip() for c in df.columns] # 看每一类 mAP50 随 epoch 的变化 cols [c for c in df.columns if mAP50 in c and 95 not in c] print(df[[epoch] cols].tail(10))这段代码把 results.csv 读进来打印最后 10 个 epoch 的每类 mAP50。如果小孩那一列长期低于成人 20 个点以上别急着调参先回去看标注里小孩框是不是普遍偏小、有没有漏标。很多时候指标问题本质是数据问题调参只是掩盖。4. 70.9% 识别率背后的评估陷阱和提升路径4.1 70.9% 是 mAP50 还是准确率差别很大「识别率 70.9%」这个说法本身就很模糊。在目标检测里可能是 mAP50、mAP50-95也可能是按图片算的准确率一张图里所有人都判对才算对。这三个数字能差出 20 个点。如果是 mAP50-95 到 70.9%那这个数据集质量相当不错如果是按图片准确率算的 70.9%换算成 mAP50 可能只有 50 出头。拿到数据集后第一件事是用统一的评估脚本重新测一遍别直接信标题里的数字。yolo detect val \ modelruns/adult_child/exp1/weights/best.pt \ data/data/adult_child_dataset/data.yaml \ imgsz960 \ splittest跑完看输出里的mAP50、mAP50-95和每一类的Precision/Recall。如果 Recall 明显低于 Precision说明漏检多小孩可能被漏掉如果 Precision 低说明误检多成人被误判成小孩。这两个方向的优化手段完全不同先定位再动手。4.2 小孩样本偏少时的三类补偿手段成人和小孩数据集最常见的问题就是小孩样本少。补偿手段有三类一是数据层面对含小孩的图片做复制和增强但要注意增强不能改变身高比例这类关键特征所以随机缩放要慎用二是损失层面给小孩类更高的分类损失权重三是后处理层面对小孩类降低置信度阈值用更多候选框换召回。# 在 data.yaml 同级目录建一个增强配置训练时用 --augment 或自定义 # 这里演示用 albumentations 做离线增强只对含小孩的图做水平翻转和亮度扰动 import cv2, albumentations as A transform A.Compose([ A.HorizontalFlip(p0.5), A.RandomBrightnessContrast(p0.3), ], bbox_paramsA.BboxParams(formatyolo, label_fields[cls])) def augment_child_images(img_path, lbl_path, out_img, out_lbl): img cv2.imread(img_path) h, w img.shape[:2] boxes, cls [], [] for line in open(lbl_path): c, x, y, bw, bh line.split() boxes.append([float(x), float(y), float(bw), float(bh)]) cls.append(int(c)) res transform(imageimg, bboxesboxes, clscls) cv2.imwrite(out_img, res[image]) with open(out_lbl, w) as f: for b, c in zip(res[bboxes], res[cls]): f.write(f{c} {b[0]:.6f} {b[1]:.6f} {b[2]:.6f} {b[3]:.6f}\n)这段增强只做水平翻转和亮度对比度扰动刻意避开了随机缩放和裁剪因为这两类操作会破坏成人和小孩之间最关键的尺度比例特征。参数p0.5和p0.3是概率别调太高小数据集上过度增强等于引入噪声。增强后要把新图和新标注放进训练集验证集和测试集保持原始分布不动。4.3 用混淆矩阵定位成人误判成小孩的具体场景混淆矩阵是排查这类问题最直接的工具。yolov11 训练完会在 runs 目录下生成confusion_matrix.png和归一化版本。我一般重点看两格成人被判成背景漏检、成人被判成小孩误分类。如果成人误判成小孩的比例高通常是两类框的尺度分布重叠严重模型没有学到真正的区分特征。from ultralytics import YOLO model YOLO(runs/adult_child/exp1/weights/best.pt) metrics model.val(data/data/adult_child_dataset/data.yaml, splittest) print(metrics.confusion_matrix.matrix)打印出来的矩阵行是真实类、列是预测类最后一行一列是背景。看成人行里小孩列的数字如果占总成人样本的 10% 以上就要考虑在标注规范上做区分比如统一要求框全身而不是半身或者引入姿态关键点辅助。这一步没有捷径只能回到数据本身。5. 成人和小孩检测的避坑清单5 个我踩过的坑5.1 坑一names 顺序写反导致语义全错现象训练 loss 正常下降mAP 也有 60 多但可视化推理时成人框标成 child、小孩框标成 adult。原因data.yaml 里 names 写成了0: child, 1: adult而标注文件里 0 其实是成人。解决训练前用校验脚本统计每个 class_id 对应的框面积均值成人框面积通常明显大于小孩对不上就说明顺序反了改 yaml 后重新训练。5.2 坑二验证集里小孩样本太少导致指标虚高现象验证集 mAP50 有 75%换到测试集掉到 55%。原因划分时没做分层抽样验证集里小孩只有十几张评估结果方差极大。解决按类别做分层划分保证验证集和测试集里小孩框数量不低于总小孩框的 10%划分脚本里用sklearn.model_selection.train_test_split的 stratify 参数按「是否含小孩」分层。5.3 坑三输入尺寸设太小小孩直接消失现象训练时 mAP 还行推理时远处的小孩完全检测不到。原因imgsz 设成 640原图里小孩只有 30 来个像素缩放到 640 后只剩十几个像素低于模型有效感受野。解决把 imgsz 提到 960 或 1280或者对原图做切块推理。提尺寸前先算显存batch 要相应调小。5.4 坑四过度增强把尺度特征破坏掉现象加了随机缩放和随机裁剪后验证指标不升反降。原因成人和小孩的核心区分特征就是身体尺度比例随机缩放直接把这个特征抹掉了模型学到的是增强后的噪声。解决关掉 RandomScale 和 RandomCrop只保留翻转、亮度、轻微色彩扰动这类不改变几何比例的增强。5.5 坑五直接信标题里的 70.9% 不做复测现象拿数据集直接汇报 70.9%被问细节时说不清评估协议。原因标题里的识别率没有说明是 mAP50 还是图片准确率、在哪个 split 上测的。解决用自己的评估脚本在固定测试集上重跑一遍记录 mAP50、mAP50-95、每类 Precision/Recall汇报时写清楚协议。这一步是职业习惯不是不信任数据。6. 把 70.9% 往上推的进阶技巧分层评估加难例回流想把成人和小孩检测从 70.9% 往上推靠调参的空间已经不大真正有效的是分层评估加难例回流。我一般会把测试集按目标尺度分成三档小孩框面积小于 32×32 像素的算小目标、32 到 96 的中等、大于 96 的大目标然后分别算每档的 mAP。这样你就能看出模型到底卡在哪一档而不是被一个总数糊弄。import numpy as np from ultralytics import YOLO model YOLO(runs/adult_child/exp1/weights/best.pt) results model.val(data/data/adult_child_dataset/data.yaml, splittest) # 按框面积分档统计需要结合验证时的预测结果 # 这里用 GT 框面积做分档示例 import glob small, medium, large [], [], [] for lbl in glob.glob(/data/adult_child_dataset/labels/test/*.txt): for line in open(lbl): c, x, y, w, h line.split() area float(w) * float(h) # 归一化面积 if area 0.01: small.append(c) elif area 0.09: medium.append(c) else: large.append(c) print(f小目标框数: {len(small)}, 中等: {len(medium)}, 大目标: {len(large)})分档之后如果发现小目标档的 mAP 只有 40 出头而大目标有 80那提升路径就很明确要么提高输入分辨率要么用切块推理要么在训练时对小目标做过采样。难例回流是指把测试集里误检和漏检的图片挑出来人工复核标注后加进训练集再训一轮。这个循环做两到三次通常能把 mAP50 推高 5 到 10 个点。分档归一化面积区间常见问题优先手段小目标 0.01漏检多、召回低提高 imgsz、切块推理中等0.01 - 0.09类别混淆难例回流、调分类损失大目标 0.09基本饱和无需额外处理最后说个我自己的习惯每次拿到一个新数据集我都会先用 100 张图跑一个 10 epoch 的快速基线看 loss 能不能正常下降、可视化框有没有明显错位。这个 10 分钟的小实验能提前暴露 80% 的格式和标注问题比闷头训 100 epoch 再回头查要省事得多。成人和小孩这个任务不难难的是数据里的细节把细节抠干净70.9% 只是个起点。希望帮到你。本文还有配套的精品资源点击获取
返回列表