尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

手机识别数据集:COCO JSON转YOLO训练与数据校验实战

手机识别数据集:COCO JSON转YOLO训练与数据校验实战 简介面向手机识别场景的视觉数据集包含2628张真实拍摄的原始图片并已统一转换为COCO JSON标注格式。资源包共2000个文件即1997张JPG图片及3个JSON标注文件压缩包大小约82.97MB。当前已有688人学习浏览适合刚接触目标检测的学生、算法工程师以及手机质检或智能识别方向的开发者。JSON标注中提供类别与边界框坐标可直接用于YOLO、Faster R-CNN等主流模型训练与验证JPG图片覆盖不同角度、不同光线条件能够反映真实环境中的多样变化。借助这套数据可以快速进行数据划分与模型迭代节省手动标注时间同时也可作为迁移学习或模型微调的训练基础。1. 手机识别数据集为什么值得用 COCO JSON 作为标注格式手机识别数据集做到 2628 张原始图片这个量级标注格式选 COCO JSON 是很划算的事。很多人图省事直接用 YOLO 的文本标签等到要做数据拼接、按类别筛选、交给 CVAT 复核、或者换到 Detectron2 训练时才发现文本标签里除了类别和坐标什么都没有而 COCO JSON 一份文件就能把图片信息、标注框、类别和分割对象完整描述出来标注与训练生态都把它当通用交换格式。我一般按这样的路径落地先把 COCO JSON 的字段结构摸清确认每条标注可读、可用再转成 YOLO 直接能吃的训练集做一轮全量校验避免脏数据悄悄拉低精度最后用半自动标注把 2628 张滚大。这篇把每个环节的命令和参数都写清楚适合准备自己训练手机检测模型、或者拿到数据集后先做质检再接入训练流程的工程师。2. 解析 COCO JSON手机识别数据集标注的 5 个字段与 1 个 id 陷阱2.1 拿到 COCO JSON 后先看这 5 个字段COCO JSON 的顶层是一个 json 数组与字典混合的结构annotations 本身就是一个 json 数组。手机识别数据集里真正影响训练的是 images、annotations、categories 三个顶层级字段images 记录每张图的 id、宽高和文件名annotations 记录每个标注框挂在哪张图、属于哪个类别、框的坐标和大小categories 记录类别 id 与类别名的对应关系。info 和 licenses 多数时候只有元数据用途但不要随手删Detectron2 这类框架的加载逻辑会对缺失字段做兼容性检查删掉有时反而触发反序列化报错。用 json 格式化工具打开一份 instances.json看到的顶层结构跟下面这张表一致。字段类型是否必选在手机识别数据集里的作用infoobject可选版本、时间、数据集描述不参与训练licensesarray可选图片许可信息商用前需要核对imagesarray必选每张图的 id、file_name、width、heightannotationsarray必选每个目标框的 id、image_id、category_id、bbox 等categoriesarray必选类别 id 与名称的映射关系很多人拿到数据后第一件事是双击 json 文件用系统记事本打开几十 MB 的文件直接卡死还看不清层级。正确做法是用带格式化的编辑器或在线 json 格式化工具先看结构再用脚本做统计。下载下来的数据集如果只有 images 和 annotations 两个字段说明对方做过精简并不影响训练只要三件套齐全转换链路就能走通。2.2 用 json Python 脚本快速体检数据集拿到 json 文件先体检而不是直接肉眼翻。2628 张原始图片的标注文件通常在几 MB 到几十 MB编辑器打开会卡而且 json 数组层级深看错一个括号就要浪费半天。我一般先跑下面这段统计脚本确认三件事文件能不能正常解析、有没有空标注图片、类别分布是否均衡。import json from collections import Counter with open(phone_data/annotations/instances.json, r, encodingutf-8) as f: coco json.load(f) print(顶层字段:, list(coco.keys())) print(图片数量:, len(coco[images])) print(标注数量:, len(coco[annotations])) # 标注按图片聚合找出没有被标注的图片 ann_by_img Counter(a[image_id] for a in coco[annotations]) empty_imgs [img[id] for img in coco[images] if img[id] not in ann_by_img] print(空标注图片数:, len(empty_imgs)) # 类别分布判断数据集是否类别不均衡 cat_dist Counter(a[category_id] for a in coco[annotations]) print(类别分布:, dict(cat_dist))这段脚本解决两个问题。第一json.load 能过说明文件编码和语法没有问题后面所有处理才有基础第二空图片数量和类别分布决定后续数据划分和增强策略单类手机数据和多类手机数据在训练时的处理方式完全不一样。参数上注意两点encoding 用 utf-8如果文件带 BOM改成 utf-8-sig 再读file_name 在 json 里可能是绝对路径也可能是相对路径统一改成相对路径否则换一台机器路径就断。提示json.load 报错时不要急着改文件先把报错行号附近的逗号和括号检查一遍一半以上的问题出在手工编辑 json 时少了逗号或多了中括号。2.3 category_id 从 1 开始还是从 0 开始COCO 官方的 category_id 从 1 开始0 留给背景但 YOLO 系标签从 0 开始Detectron2 注册时又要求从 1 开始。手机识别数据集里只有一个类别 phone 时有的生成脚本写 1有的写 0这个差异直接决定后续转换脚本怎么写。正确做法是在转换脚本里动态建立映射读 categories 数组把原 id 映射成目标格式需要的连续 id而不是硬编码减 1 或加 1。下面这行逻辑在转换脚本里必须出现cat_mapping {c[id]: idx for idx, c in enumerate(coco[categories])} # 例如手机数据集的 categories 是 [{id: 5, name: phone}] # 这里会把它映射为 {5: 0}如果图省事写成 category_id - 1遇到 id 不连续或者从 0 起步的 json转换结果会整体错位而且这种错位不会报错只会让模型训练出来完全不可用。这个坑在 COCO JSON 转其他格式时出现频率最高后面第 3 章的转换脚本和第 4 章的校验脚本里都会围绕它做检查。3. 把手机识别数据集的 COCO JSON 转成 YOLO 格式并训练3.1 COCO 转 YOLO 的解析脚本bbox 归一化与 clamp手机识别数据集要训练检测模型最常见的做法是转成 YOLO 系列能直接加载的标签结构。无论后面接 yolov5 还是 yolov8这条链路都成立。下面用 json Python 写一个一次性脚本把 annotations 里的 bbox 转换成 YOLO 的「类别 中心点相对坐标」格式。import json from pathlib import Path def coco_to_yolo(json_path, out_dir): with open(json_path, r, encodingutf-8) as f: coco json.load(f) # category_id 重映射兼容从任意数字起步的 ids cat_mapping {c[id]: idx for idx, c in enumerate(coco[categories])} # 按 image_id 聚合所有标注 ann_map {} for a in coco[annotations]: ann_map.setdefault(a[image_id], []).append(a) out_dir Path(out_dir) out_dir.mkdir(parentsTrue, exist_okTrue) count 0 for img in coco[images]: w, h img[width], img[height] lines [] for ann in ann_map.get(img[id], []): x, y, bw, bh ann[bbox] # bbox 是 x,y,w,h转为中心点并归一化 cx (x bw / 2) / w cy (y bh / 2) / h nw bw / w nh bh / h # 截断到 [0,1]避免边界框越界导致训练崩溃 cx, cy min(max(cx, 0.0), 1.0), min(max(cy, 0.0), 1.0) nw, nh min(max(nw, 0.0), 1.0), min(max(nh, 0.0), 1.0) lines.append(f{cat_mapping[ann[category_id]]} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}) if lines: stem Path(img[file_name]).stem (out_dir / f{stem}.txt).write_text(\n.join(lines), encodingutf-8) count 1 print(f已生成 {count} 个标签文件)脚本逻辑不复杂但每一步都有讲究。img[width] 和 img[height] 必须取自 json 而不是重新读图片因为 json 记录的是标注当时的原始分辨率重新读可能受 EXIF 旋转影响产生不一致。clamp 这一段是给标注时手抖把框画出边界的样本兜底比训练时报索引越界再回头查要省事得多。cat_mapping 用 enumerate 而不是减 1避免第 2.3 节说的 id 错位问题。输出文件名的 stem 用 file_name 取前提是图片文件名在数据集中不重复如果存在同名文件需要把 image_id 拼进文件名例如 phone_000123_000001.txt。3.2 2628 张图的数据划分用随机 seed 固定训练集2628 张原始图片在深度学习里属于中小规模我的划分比例是 train 85%、val 15%不使用独立的 test 集等模型选型完成后从 val 里抽一部分做最终评估。固定随机种子切分保证每次实验拿到的训练集完全一致。from pathlib import Path from sklearn.model_selection import train_test_split imgs sorted(Path(phone_data/images).glob(*.jpg)) train_imgs, val_imgs train_test_split(imgs, test_size0.15, random_state42) print(len(train_imgs), len(val_imgs))random_state 必须固定否则每次运行切分结果不同换一次环境实验之间就不可比。另一个更容易忽略的点如果这 2628 张里有从视频连续帧抽出来的图相邻帧画面几乎一样随机切分会把同一段画面的相似帧同时分到 train 和 val验证指标会虚高。这种情况要先按视频片段分组再对组做切分而不是对单张图切分。判断方法是看训练集和验证集里是否存在相似度极高的样本如果 mAP 明显高于常规水平先怀疑数据泄漏而不是模型有多强。3.3 用 yolov8 训练自己数据集的 data.yaml 与命令行转好标签之后准备一份 data.yaml。手机识别数据集最常见的是单类 phone如果数据集作者把屏幕、充电口也标了就按实际类别写。path: /data/phone_dataset train: images/train val: images/val nc: 1 names: 0: phonedata.yaml 里的 train 和 val 是相对 path 的目录yolov8 会把 path、train、val 拼接成完整路径所以 path 一定要写对。names 的序号必须和标签文件里的第一个数字对应单类时也必须写否则训练会提示 nc 与 names 长度不一致。训练命令我习惯用 yolov8 的 CLI 而不是写 Python 脚本参数一目了然日志也好归档。yolo detect train dataphone.yaml modelyolov8s.pt \ epochs100 imgsz640 batch16 device0几个参数说明imgsz 640 对“手机”这种在图片里占 10% 到 60% 面积的目标足够不需要上 1280batch 16 按 8G 显存估的显存小就降到 8device0 指定第一张卡。训练日志里重点看 P、R、mAP50 三个指标不要只看 loss。yolov8 的 CLI 会默认记录所有配置跑完一条命令就能复现省掉自己写实验记录的功夫。3.4 验证参数看 P/R别只盯 mAP手机识别这种目标相对单一、背景变化不大的数据集mAP 50:95 会被 IoU 阈值拖低真正要重点看的是 P 和 R。P 高 R 低说明漏检多模型保守P 低 R 高说明误检多模型激进。手机这类目标的长宽比稳定对定位误差本来就敏感两个指标差太远时优先回标注端查问题不要在模型上硬调 conf。yolo detect val modelruns/detect/train/weights/best.pt \ dataphone.yaml imgsz640验证集必须和 3.2 划分的 val 保持一致不能从 train split 里再抽。如果 P/R 里有一条异常拿验证集预测结果逐张看图找出是哪一类图片在漏检或误检通常是暗光场景、超广角畸变、或者手机被手遮挡再针对这些场景补数据这才是小数据集迭代的正确节奏。4. 2628 张手机识别数据集的 JSON 校验与常见报错4.1 json 解析失败的三个来源既然这个数据集支持 COCO JSON第一步必然是读得进来。我遇到过的解析失败基本逃不出三类第一是编码问题文件带 BOM 或含中文内容直接 json.load 报 UnicodeDecodeError第二是结构缺字段工具后端在反序列化时对缺失字段特别敏感常见报错类似 failed to deserialize the json body into the target type: input: missing field height第三是 annotations 数组里混入 null 对象人工编辑 json 时最容易引入。先跑一条最简单的命令确认能否解析python -c import json; djson.load(open(instances.json, encodingutf-8-sig)); print(ok, len(d[images]))utf-8-sig 会跳过 BOM不少从 Windows 上导出的 json 用 utf-8 读取会报错换成 utf-8-sig 就通过。如果报 missing field不要靠猜把报错信息里提到的字段名在整个文件里搜一遍确认是否所有 annotation 对象都包含这个字段缺字段往往是生成脚本里某条分支漏写了。4.2 标注质量检查脚本越界、零宽高、类别错解析通过之后要对 2628 张里的每一条标注做质量检查。注意检测训练不会因为一两条脏标注直接报错但它们会静默拉低 mAP甚至让类别分布失衡。我用的检查脚本按 error 列表收集问题不边查边改先看汇总再决定怎么修。def validate_coco(coco): cats {c[id] for c in coco[categories]} images {i[id]: i for i in coco[images]} errors [] for i, a in enumerate(coco[annotations]): img images.get(a.get(image_id)) if img is None: errors.append(findex{i}: 找不到 image_id {a.get(image_id)}) continue x, y, w, h a[bbox] if w 0 or h 0: errors.append(findex{i}: 宽或高非正数 ({w}, {h})) if x 0 or y 0 or x w img[width] or y h img[height]: errors.append(findex{i}: bbox 越界) if a.get(category_id) not in cats: errors.append(findex{i}: 未知类别 {a.get(category_id)}) return errors检查项就是四类高频问题悬空的 image_id、零宽高、框越界、类别不在 categories 里。这四类问题在转换脚本里可能被 clamp 临时掩盖但根源不修每轮转换都会再踩一次。脚本之外再补一个手工维度用 json 格式化工具搜几个 image_id 对应的 file_name打开图片扫一眼框体和手机边缘的贴合程度。手机屏幕这类边缘锐利的目标标注框明显缩进或超出模型学到的边界就是模糊的。错误现象常见原因处理方式bbox 越界标注时缩放画布导致坐标溢出脚本中 clamp或回到标注工具修正w 或 h 为 0鼠标点选误保存成零宽框删除该 annotationcategory_id 不存在json 被手动编辑坏用 categories 重映射后重新导出图片无对应标注file_name 重名覆盖按 image_id 聚合检查并重建索引4.3 单类手机数据集训不动的两个原因2628 张如果是单类 phone模型本质上在做前景背景二分类。这种任务训不动的现象不是 loss 不降而是 val 上只剩背景框或者满屏都是前景框。常见原因有两个。第一是数据增强把手机缩得太小mosaic 拼接后目标面积小于 32 像素模型学到的是噪点而不是手机特征。排查方法是把增强后的训练样本可视化看增强后目标是否还完整如果只剩残块把 mosaic 的概率调低或者暂时关掉。第二是标注里混入大量手机占比极小的场景图正样本信息量不足模型无论怎么调参都学不到细节。这种情况要先做困难样本筛选把手机占比在 10% 到 60% 的样本抽出来看分布而不是盲目加大 batch 或换更大的模型。单类数据集的收益点几乎都在数据质量上这也是我把校验放在训练链路中间的原因。第 3 章训练完如果指标偏低先回第 4 章跑一遍校验脚本而不是马上换模型结构。5. 半自动标注补数据让手机识别数据集从 2628 张扩到更多5.1 用 best.pt 对新图片做预标注手机识别数据集从 2628 张继续扩最顺手的是半自动标注用训练出的 best.pt 对未标注图片做预测生成候选框再人工确认。这样既保住了 COCO JSON 的格式又让标注人力花在刀刃上。yolo predict modelruns/detect/train/weights/best.pt \ sourcenew_images/ imgsz640 conf0.25 save_txtTrue这里的 conf 和验证时不一样验证用 0.001 看全量召回预标注用 0.25 是为了少出无效框。save_txt 输出 YOLO 格式标签直接当底稿如果训练脚本更习惯 COCO JSON再写一段反向转换把 txt 和置信度写回 annotations同时保留原图的 width、height。5.2 用 CVAT 导入 COCO JSON 复核并导出人工复核我用 CVAT它原生支持导入 COCO JSON 1.0也支持导出同格式。新建任务时把 labels 定义成和数据集 categories 完全一致的名字比如数据集里是 phone 和 screen任务里写错一个字符导入就会失败。遥感图像标注、路测数据集团队也常用同一套流程CVAT 在这方面兼容性做得比较稳。复核时低置信度框优先看高置信度直接批量确认。导出的文件依然是 COCO JSON字段结构与原始数据集一致后续的校验脚本可以直接复用。5.3 合并标注后重新校验 image_id复核完导出的还是 COCO JSON要和原始 2628 张的 json 合并。合并时最容易踩的坑是 image_id 冲突原来的 id 可能是从 1 到 2628 递增新标注文件导出时也可能从同样范围开始。合并前给新数据统一加偏移量。new_id 100000 for i, img in enumerate(new_coco[images]): img[id] new_id i for a in new_coco[annotations]: # 原标注的 image_id 指向未偏移时的索引 a[image_id] new_id int(a[image_id])偏移之后用第 4 章的 validate_coco 再跑一遍全量校验重点看类别分布是否变化、有没有重复 id。确认无误后重新生成 data.yaml 并训练整个闭环从图片入库到模型更新最快一天一轮比全部从头标注快三到四倍而且每一轮产出的模型都会让下一轮预标注更准。本文还有配套的精品资源点击获取
返回列表