
简介面向计算机视觉初学者和中高级算法工程师这套成人与小孩识别数据集包含1738张真实场景原始图片模型识别率可达70.9%可直接用于二分类目标检测或图像分类任务的训练与验证适配智能安防、客流统计、儿童看护等实用场景。压缩包共1741个文件其中1738张jpg原始图片与3个coco json格式标注文件对应良好文件命名简洁便于用脚本批量划分训练集、验证集coco json属于主流标注格式能被YOLO、MMDetection、Detectron2等常用框架直接读取。整体91.49MB轻量易下载对个人实验或课堂教学都足够友好。目前已有2000人学习下载资源能有效减少数据采集和标注时间用户可直接聚焦模型调优与部署也适合作为毕业设计、算法竞赛或产品验证的基础数据集在此基础上扩展样本或微调即可快速落地。1. 成人小孩数据集、1738张图、70.9%识别率这个东西到底能做什么假设你正在做儿童手表的安全告警或者门店里的客流画像分析核心需求只有一个从摄像头画面里分清楚哪个是成人、哪个是小孩。这个标题指向的正是一份能直接派上用场的标注数据1738张原始图片标注格式为COCO JSON目标检测模型训练之后能识别成人和小孩官方基线的识别率停在70.9%。很多人看到“70.9%”第一反应是不高但先别急着下结论。这个数字大概率指的是COCO评估协议下的mAP0.5也就是IoU阈值取0.5时的平均精确度它和平时说的“识别准确率”完全是两套指标。更重要的是1738张图属于典型的小型数据集70.9%意味着只要预训练权重选得对、训练策略正常指标还有不少上升空间但直接拿它上线做正式产品又不够稳。它最适合的位置是迁移学习的起点用来验证算法链路、检查标注质量、跑通一套从JSON到模型权重的完整流程。这篇文章我就按自己复现这类数据集的路径来写先拆COCO JSON标注结构再给一条从标注到训练的最小实现路线接着聊三条提升识别率的常用调优方向然后放上我踩过的一些坑和对应排查方法最后给出一套可以反复使用的验证思路。2. COCO JSON标注格式拆解五个顶层字段和bbox、area的细节2.1 COCO JSON的五个顶层字段先搞懂再打开文件拿到一份COCO格式标注第一件事不是急着开训练而是先看JSON结构。COCO JSON标准结构里有五个顶层字段info、licenses、images、annotations、categories。info和licenses是元信息记录数据来源、版权和版本训练时用不到但留着没坏处。images是一个数组每个元素对应一张图片字段一般包括id、file_name、width、height有些还带license和coco_url。这里的id是图片的唯一编号后面annotations里的image_id就是指向它的。annotations是训练真正要读的数组。每个元素代表一个目标框关键字段有id、image_id、category_id、bbox、area可能有segmentation和iscrowd。bbox是四个数的列表格式是[x, y, width, height]x和y是目标框左上角的像素坐标width和height是框的宽和高。新手最常见的翻车点是把它和[center_x, center_y, w, h]搞混导致转标签时框偏移半个身位。categories里定义类别列表每个类别是一个对象常见字段为id、name以及可选的supercategory。对这份数据来说你大概率会看到两个类别成人adult和小孩child但具体id和名称需要你打开文件确认不要想当然地以为是1和2。很多人上来就问“json用什么打开”最常见的做法是直接用VS Code打开JSON文件结构清晰语法高亮文件不大时体验很好。如果你只是临时看一眼也可以用浏览器里的在线JSON视图工具但注意不要把数据传到不可信的第三方站点。正经操作里我都会用Python的json模块去读它因为后续统计、清洗、转换都要依赖代码这是最稳定的路径也能顺便确认编码问题。下面这个脚本可以直接用来摸清数据集家底。import json from collections import Counter with open(coco_annotations.json, r, encodingutf-8) as f: coco json.load(f) cat_id_to_name {cat[id]: cat[name] for cat in coco[categories]} print(类别列表:, cat_id_to_name) cat_counts Counter(ann[category_id] for ann in coco[annotations]) for cat_id, cnt in cat_counts.items(): print(f{cat_id_to_name[cat_id]}: {cnt} 个标注框) image_ids {img[id] for img in coco[images]} annotated_image_ids {ann[image_id] for ann in coco[annotations]} empty_images image_ids - annotated_image_ids print(f空标注图片数: {len(empty_images)}) print(f总图片数: {len(coco[images])}) print(f总标注框数: {len(coco[annotations])})这段代码做了三件事。第一把categories列表转成id到名字的字典方便后面打印。第二用Counter统计每个category_id出现的次数也就是成人框和小孩框分别有多少。第三比较images里的id集合和annotations里的image_id集合找出哪些图片没有被标注。空标注图片在训练时会拉低batch的loss表现如果数量多就要检查标注过程是不是漏了文件。参数说明json.load读出来的数据是Python字典和列表结构内存占用不算大1738张图的标注文件通常只有几十MB直接用load足够。如果以后遇到几十万标注的COCO文件我会改用ijson做流式读取否则内存会吃紧。2.2 annotations里的bbox与area为什么area不等于w*h很多人会忽略area字段或者直接用w去乘以h来算面积。COCO原版协议里area指的是“分割区域的面积”而不是bbox面积。如果标注里没有segmentation字段一般会用bbox面积代替但严谨的做法是读取JSON里已经写好的area值而不是重新计算。因为在polygon手工标注的场景下bbox面积会明显高估实际对象大小在小目标评估上会带来偏差。另一个容易翻车的是bbox坐标类型。COCO标注规范允许坐标是浮点数手工标注过程中经常出现小数经过插值工具导出后更常见。转成YOLO等格式时如果你直接round成整数框会偏移几个像素对大目标可能无感但对只有几百像素的小孩目标IoU损失就明显了。我一般会在转换脚本里保留六位小数不用提前取整。还需要关注isegmentation和iscrowd。大部分检测数据集里segmentation可能是空数组或一个polygoniscrowd为0。如果iscrowd为1说明这个区域是一群重叠目标检测模型通常不建议直接学习这种标签。拿到JSON后要顺手过滤掉iscrowd为1的标注否则训练出来的模型会在人群场景里疯狂漏检。2.3 用Python快速检查类别与图片数量至少确认三件事再往下走在训练之前我建议多做一步检查确认图片路径有没有指错。COCO JSON里的file_name通常是相对路径比如“img_001.jpg”而你的实际图片可能放在images目录下。如果路径对不上训练时根本找不到图片模型自然无法收敛。检查脚本里可以加一段os.path.exists把不存在的路径集中打印出来。另外我更关注类别间的目标大小差异。可以用bbox的宽高算一个粗略的平均尺寸然后按成人组和小孩组分开看。如果小孩目标的平均尺寸显著小于成人后面就要重点考虑小目标增强策略。这一步虽然简单但能帮你提前判断后面调参的重点不至于把时间浪费在无用功上。3. 用1738张图端到端训练一个成人与小孩检测模型从JSON到模型权重的最小流程3.1 选型思考为什么先拿YOLO跑通而不是直接上MMDetection手上有COCO JSON格式标注很多人第一反应是上MMDetection毕竟它原生支持COCO数据格式和评估协议。但我的习惯是先拿Ultralytics YOLO跑通原因很现实YOLO的训练流程短默认超参数调得好自带验证脚本新手和老手都能快速看到结果。最关键的是YOLO的训练格式相对简单一个图片对应一个txt标签转换成本很低。MMDetection等后续对精度有更细致要求再回来补因为它的配置体系复杂调参成本高一次性踩进去容易劝退。这里不是否定MMDetection。如果你最终部署链路就是mm系列或者需要复现论文里的详细指标那直接在MMDetection上做是合理的。但绝大多数业务场景YOLO在工业界的成熟度、推理速度和部署便利性都更好。所以下文以YOLOv8为例这套流程也适用于最新的Ultralytics版本命令基本不变。3.2 把COCO JSON转成YOLO训练格式目录结构、转换脚本与三个坑YOLO训练需要的数据结构很简单一张图片对应一个txt标签文件txt每一行格式为“类别id(从0开始) 归一化的中心x 归一化的中心y 归一化的宽 归一化的高”。所以转换脚本必须完成两件事一是把COCO JSON里的bbox从[x, y, w, h]左上角格式转成[center_x, center_y, w, h]并除以图片宽高做归一化二是把category_id映射成连续的从0开始的类别id。你手上的JSON里成人和小孩的id可能是1和2也可能不是转换前先跑一遍统计脚本确认。import os import json coco_json_path coco_annotations.json images_dir images labels_dir labels os.makedirs(labels_dir, exist_okTrue) with open(coco_json_path, r, encodingutf-8) as f: coco json.load(f) img_id_to_info {img[id]: img for img in coco[images]} cat_id_map {1: 0, 2: 1} # 假设成人1小孩2按实际JSON调整 for ann in coco[annotations]: if ann.get(iscrowd, 0) 1: continue img_info img_id_to_info[ann[image_id]] file_name img_info[file_name] label_file os.path.join(labels_dir, os.path.splitext(file_name)[0] .txt) cat_id cat_id_map.get(ann[category_id]) if cat_id is None: print(f警告: 未知的category_id {ann[category_id]}跳过) continue x, y, w, h ann[bbox] img_w img_info[width] img_h img_info[height] if x 0 or y 0 or x w img_w or y h img_h: x max(0, x) y max(0, y) w min(img_w - x, w) h min(img_h - y, h) if w 5 or h 5: continue center_x (x w / 2) / img_w center_y (y h / 2) / img_h norm_w w / img_w norm_h h / img_h with open(label_file, a, encodingutf-8) as f: f.write(f{cat_id} {center_x:.6f} {center_y:.6f} {norm_w:.6f} {norm_h:.6f}\n)这段脚本有几个地方值得单独说明。第一iscrowd为1的标注被直接跳过因为这类密集重叠目标不适合作为检测框学习。第二越界框被clip回图像边界而不是一删了之clip之后如果宽或高小于5像素就直接丢掉这类框属于无效目标。第三写标签用了追加模式“a”但要注意重复运行脚本会重复写行我一般会在转换前先清空labels目录或者接口改成“w”并在每个标注文件首次写入时打开避免脏数据。第四cat_id_map里没有的category_id会打印警告并跳过不会静默出错。接下来写data.yaml这是Ultralytics YOLO的训练入口。# data.yaml path: ./custom_data train: images val: images nc: 2 names: 0: adult 1: child这里把train和val都指向images目录是为了快速验证全流程能跑通。正式做实验时我会按8比2划分训练集和验证集把val指向val_images。train和val用同一批图片会让mAP虚高不能作为发布指标。目录结构也需要跟yaml里的path对齐否则会报图片路径找不到的错误。3.3 训练命令和关键超参数从复现基线到逐步调优Ultralytics YOLO的训练命令一行就能跑yolo detect train datadata.yaml modelyolov8s.pt epochs60 imgsz640 batch16 lr00.01我推荐用yolov8s.pt而不是yolov8n.pt因为模型太小在只有1738张图的小数据集上特征学习能力不足yolov8m也可以上但显存占用更大训练时间更长。imgsz取640是常见的平衡点如果小孩目标特别小可以试1280但训练时间会增加不少。epochs取60到100配合Ultralytics自带的早停机制避免过拟合。训练日志会打印box_loss、cls_loss、dfl_loss以及每个epoch的mAP50和mAP50-95。如果复现出来的mAP50能达到70%左右说明流程基本正确后面调参就有的放矢。如果明显偏低先回去检查转换脚本的坐标归一化再检查图片路径和标注数量这两处出问题的概率最高。别忘了Ultralytics的模型权重是COCO预训练权重成人这个类别在预训练模型里其实已经有一定的特征响应迁移到你的数据上会容易很多。4. 识别率卡在70.9%上不去数据增强、预训练权重和类别不平衡三把钥匙4.1 预训练权重1738张图根本不够从零训如果你一时手滑用了modelyolov8s.yaml而不是yolov8s.pt相当于从随机初始化开始训练。我的经验是1738张图、两个类别从零开始训的结果很可能跌到50%甚至更低。原因很直接神经网络的特征提取层需要海量数据来学习边缘、纹理、形状这些基础概念这点样本量完全不够。正确做法一定是加载COCO预训练权重YOLOv8的.pt文件都在COCO上预训练过。虽然COCO里没有明确的“儿童”类别但人的轮廓特征已经被预训练模型学到你的数据集只需要微调分类头就能把成人、小孩区分开。如果你用的是其他框架比如MMDetection也同样要找到在COCO上预训练的权重文件。迁移学习对成人小孩这种粗粒度分类尤其有效因为两类之间的视觉相似度很高模型不需要重新学“人是什么”只需要学“大人和小孩在体型、比例上的差异”。这也是为什么即便数据量不大识别率仍然能到70%以上。4.2 类别不平衡成人框远多于小孩框时的处理行人相关数据集最常见的问题就是成人样本多、小孩样本少因为小孩出现在画面里的频率天然就低。前面统计脚本跑完如果成人框数量是小孩的三倍以上就需要专门处理。最简单的做法是给少样本类提高loss权重Ultralytics里可以调整cls_loss_weight参数但实际经验中手动设置类别权重不如过采样方式稳。我一般会先在标注层面做处理如果小孩样本不足可以把包含小孩的图片在训练时重复一遍或者用复制粘贴增强把小孩目标单独抠出来贴到其他背景上生成新样本。这一步虽然笨但对模型在小目标上的recall影响非常明显。还有一个思路是调整图像尺度小孩目标通常比较小如果正常采样时随机选取的图片里小孩占比很低可以按一定概率优先采样含小孩的图片。这里提醒一句不要为了平衡类别而盲目删除成人样本。成人样本里的背景多样性是模型学到泛化特征的保障删太多会让模型在白天黑夜等复杂场景下误检率上升。我建议优先保数据多样性再考虑类别均衡。4.3 数据增强让模型对小孩目标更鲁棒YOLO默认自带Mosaic、仿射变换、色彩抖动等增强但针对小目标需要额外交互。在Ultralytics训练参数里可以调hsv_h、hsv_s、hsv_v控制色彩泛化scale控制尺度扰动fliplr控制随机水平翻转。场景里如果有对称目标fliplr开0.5没问题但如果你的图片里有文字或不对称物体建议关闭否则会引入伪样本。最需要谨慎的是Mosaic增强。它把四张图拼成一张小目标会被进一步缩小导致本来只有20像素的小孩目标直接变成不可见。如果你的图画幅很大、目标很小我建议把mosaic系数从默认的1.0降低到0.5甚至关掉改用自己的仿射增强组合。如果你想做更细的控制可以用Albumentations写一个自定义pipeline配合YOLO的collate_fn逻辑把RandomBrightnessContrast、CLAHE、RandomSizedBBoxSafeCrop等操作加进去。这一步会比调默认参数复杂但往往能在小目标上多拿两个点。数据增强属于那种“调好了涨点调崩了翻车”的模块建议每次只改一个参数跑完一次完整训练再决定下一步。5. 避坑COCO JSON标注和训练流程里的4个典型错误5.1 现象训练loss直接变NaN原因bbox坐标越界或宽高为负数解决转换前做合法性校验我第一次跑这个数据集时第12个epoch的loss突然变成NaN看着训练进度倒退回去心里很慌。查到最后是有几张图片的bbox坐标是负数转成YOLO之后center_x和center_y变成了负值模型在反向传播时算出异常梯度。COCO标注理论上是非负的但实际人工标注或导出工具经常出现坐标超出图像边界的情况。解决方法是写一个清洗函数先把越界框clip到图像边界再过滤掉宽高小于1像素或面积过小的框。这个检查必须在转换脚本里做而不是等到训练时才发现。5.2 现象模型只识别成人不识别小孩原因类别ID映射错了解决让脚本打印完整映射表另一个坑出现在类别映射上。我一度假设category_id是1表示成人、2表示小孩但某个实际版本的JSON里小孩的id是3成人是2。结果就是小孩样本全部被当成成人模型眼里只有一种目标。解决办法是不要硬编码映射而是在统计脚本里把categories列表完整打印出来确认name和id的对应关系之后再写映射字典。这个坑虽然蠢但很容易犯尤其是当你手里的JSON文件来源比较多时每个版本的类别顺序都可能不一样。5.3 现象可视化时框全部往下偏原因归一化用的图片尺寸和实际图片不一致解决统一图片尺寸有一次我转换时使用img_info里的width和height但实际图片被前处理脚本改成了正方形分辨率。YOLO读取图片后会按实际尺寸缩放标签里的归一化坐标却是按原图尺寸算的于是所有框都偏了。解决方法是始终保持图片和JSON中的width、height完全一致或者在转换前用PIL重新读取图片尺寸覆盖掉JSON里的记录。总结一句话相信实际图片不要盲信JSON字典里的数值。5.4 现象验证时某个类别mAP为0原因划分时类别样本没覆盖解决分层抽样如果你按原始顺序切分训练集和验证集有可能验证集里没有小孩样本导致该类别mAP为0总mAP直接拉低。这种情况看起来像模型不行其实是数据划分问题。解决办法是采用分层抽样按类别比例保证大人和孩子在每个集里都有一定分布。我的做法是在划分前先按含小孩的图片ID做一个集合然后在这个集合内按比例抽取验证集再在剩余图片里补充成人样本。这样跑出来的指标才有参考价值。6. 从70.9%往更高走验证流程和一整套可复用的调参清单要判断这个数据集和你的模型到底值多少分单次划分训练是不够的。我的习惯是在1738张图上做5折交叉验证每次用80%训练、20%验证跑5次取mAP0.5的均值。这样做出来的指标比单次划分稳定得多也能暴露某些折里小目标特别多、或特定场景缺失的问题。如果你时间紧至少要做两次随机不同种子的划分看看结果波动范围大不大。如果两次相差超过3个点就说明数据集划分本身不够稳定不能拿一次成绩跟别人比较。调参不需要一上来就搜索一堆超参数。先固定一套基线然后一次只改一个维度不然你根本不知道是哪个变动拉低了指标。我通常的优先级排序是先确认预训练权重合理再过滤低质量标注框然后处理类别不平衡接着调imgsz到960或1280观察小目标变化最后开启测试时增强TTA。TTA在YOLO里只需要在predict时开启能稳定加1到2个点但推理速度会变慢适合离线评估不适合实时线上。调参项常见取值对结果的影响imgsz640/960/1280值越大对小目标越有利但训练显存和时间成本上升epochs60/100/200小数据集建议配合早停防过拟合lr00.01/0.001迁移学习用0.01从头训练用0.001batch16/32batch越大训练越稳定显存不够时降低fliplr0.5/0.0场景里有文字或不对称目标时关闭mosaic1.0/0.5小目标多时降低防止目标被缩小拼接class_weight自动/手动类别不平衡时手动调高小孩样本权重最后说一个比较玄学的点如果常规调参都试过了识别率还是卡在73%左右不妨回过头去看数据本身。我曾经遇到过17%的标注框把小孩的半条胳膊排除在外导致目标框比实际大一圈模型拟合时怎么都不对。后来把这些框手工修正了一遍mAP直接涨了3个点。所以在调参疲劳的时候回到标注质量上找问题往往比继续堆参数更有效。我的习惯是每一轮训练前先跑一遍统计脚本训练后按model_v{epoch}_{mAP50}.pt格式保存权重这样即使某次调参翻车也有后悔药可以回滚。这套流程把这个数据集的潜力基本榨干之后你会发现自己对COCO JSON格式、数据增强和指标验证的理解也跟着上了一个台阶希望帮到你。本文还有配套的精品资源点击获取