ARTICLE DETAIL

资讯详情

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

手机识别数据集实战:2628张图片COCO标注转YOLO训练全流程

手机识别数据集实战:2628张图片COCO标注转YOLO训练全流程 简介这份手机识别数据集面向计算机视觉初学者、目标检测算法练习者以及需要手机类目样本的开发者用于训练和验证手机目标检测或图像分类模型。资源包共2000个文件以1997张jpg原始图片为主另附3个json标注文件压缩包约82.97MB图片命名包含IMG与pp等前缀覆盖多种拍摄场景与角度json文件采用coco格式可直接对接主流检测框架的数据加载流程。目前已有715人学习下载说明其在手机识别任务中具备一定参考价值。读者可借助这批原始图片与coco标注快速搭建训练集与验证集完成模型微调、数据增强或标注格式转换等实验省去自行采集与标注的时间成本适合作为课程设计、毕业项目或算法入门的实战素材。1. 手机识别数据集落地2628 张原始图片与 COCO JSON 标注到底怎么用手里有一批手机拍摄的原始照片想训练一个能识别手机的检测模型最卡脖子的往往不是网络结构而是标注。这份手机识别数据集给了 2628 张原始图片标注直接以 COCO JSON 格式提供意味着你不需要从零画框拿到手就能接进主流检测框架。它适合三类人一是想跑通目标检测全流程的新手二是需要快速验证模型结构或数据增强策略的算法工程师三是做手机检测相关应用、缺一份干净标注数据的从业者。文件名里那些IMG20211010...和mobile-phones-_jpg.rf...的命名说明图片来自真实拍摄场景不是合成图这对模型泛化是好事。下面按「数据长什么样 → 怎么转成训练格式 → 怎么训 → 坑在哪」的顺序拆开讲。2. COCO JSON 标注结构拆解先看懂再动手2.1 COCO 标注的四个核心字段COCO 格式的标注文件本质是一个大 JSON检测任务里你只需要盯住四个顶层字段images、annotations、categories、info。images记录每张图的id、file_name、width、heightannotations是每个标注框含image_id、category_id、bbox、area、iscrowdcategories定义类别手机识别通常只有一个类id可能是 1 或 0这点必须先确认否则训练时类别对不上。bbox的格式是[x, y, width, height]注意是左上角坐标加宽高不是[x1, y1, x2, y2]这是新手最容易翻车的地方。先用一段 Python 把标注读出来确认字段和类别import json # 换成你的标注文件路径 with open(annotations/instances.json, r, encodingutf-8) as f: coco json.load(f) print(图片数量:, len(coco[images])) print(标注数量:, len(coco[annotations])) print(类别:, coco[categories]) # 看第一条标注的 bbox 格式 first coco[annotations][0] print(bbox:, first[bbox], category_id:, first[category_id])这段代码的作用是先做数据体检。len(coco[images])应该接近 2628如果差很多说明标注文件不完整或图片有缺失。categories打印出来要确认类别数和id后面转 YOLO 时要用。bbox打印出来看数值范围如果出现负数或超出图片宽高说明标注有脏数据得先清洗。2.2 图片与标注的对应关系校验COCO 里图片靠file_name关联磁盘文件标注靠image_id关联图片。常见问题是标注文件里的file_name和实际图片文件名对不上比如多了前缀路径或扩展名大小写不一致。写个校验脚本把缺失和多余的都列出来import os img_dir images disk_files set(os.listdir(img_dir)) anno_files set(img[file_name] for img in coco[images]) missing anno_files - disk_files # 标注里有、磁盘上没有 extra disk_files - anno_files # 磁盘上有、标注里没有 print(标注有但图片缺失:, len(missing)) print(图片有但标注缺失:, len(extra)) print(示例缺失:, list(missing)[:5])missing不为空说明有标注找不到图训练时会直接报错extra不为空说明有图没标注可以留着做测试集或直接忽略。这一步花两分钟能省掉后面训练时反复排查的时间。我一般会把校验结果写进日志数据一换就重跑一遍。2.3 类别 id 与训练配置的映射手机识别通常是单类但 COCO 的category_id不一定是 0。YOLO 系列要求类别从 0 开始连续所以转换时必须做一次映射。假设categories里手机的id是 1那转换后所有框的类别都要减 1 变成 0。如果直接拿 COCO 的category_id去训 YOLO会出现类别索引越界或全部预测成背景的玄学现象。转换脚本里加一行映射表就能解决后面第 3 章会给完整代码。3. 转成 YOLO 训练格式转换脚本与参数说明3.1 为什么优先转 YOLO txt 而不是直接用 COCOCOCO JSON 适合做数据管理和评估但训练时很多框架读 COCO 的效率不如读 txt。YOLOv5、YOLOv8 默认吃的是每张图一个.txt每行class_id x_center y_center width height且坐标是归一化到 0~1 的。转成这种格式后训练时不用每次解析大 JSON数据加载更快也方便你直接看某个框对不对。常见做法是保留原始 COCO JSON 做备份另生成一份 YOLO 格式的目录结构。3.2 完整转换脚本下面这个脚本把 COCO JSON 转成 YOLO 的 images/labels 结构同时做类别映射和坐标归一化import json import os from PIL import Image coco_path annotations/instances.json out_img_dir yolo/images out_lbl_dir yolo/labels os.makedirs(out_img_dir, exist_okTrue) os.makedirs(out_lbl_dir, exist_okTrue) with open(coco_path, r, encodingutf-8) as f: coco json.load(f) # 建立 image_id - 图片信息 的索引 img_info {img[id]: img for img in coco[images]} # 类别 id 映射COCO 原始 id - 从 0 开始的连续 id cat_ids sorted(c[id] for c in coco[categories]) cat_map {cid: idx for idx, cid in enumerate(cat_ids)} print(类别映射:, cat_map) # 按 image_id 聚合标注 from collections import defaultdict anno_by_img defaultdict(list) for ann in coco[annotations]: anno_by_img[ann[image_id]].append(ann) for img_id, info in img_info.items(): w, h info[width], info[height] file_name info[file_name] # 复制或软链图片到 yolo/images src os.path.join(images, file_name) dst os.path.join(out_img_dir, file_name) if os.path.exists(src) and not os.path.exists(dst): os.symlink(os.path.abspath(src), dst) # 软链省空间也可用 shutil.copy # 写 label 文件 label_name os.path.splitext(file_name)[0] .txt with open(os.path.join(out_lbl_dir, label_name), w) as lf: for ann in anno_by_img.get(img_id, []): x, y, bw, bh ann[bbox] # 归一化并转中心点 xc (x bw / 2) / w yc (y bh / 2) / h nw bw / w nh bh / h cls cat_map[ann[category_id]] lf.write(f{cls} {xc:.6f} {yc:.6f} {nw:.6f} {nh:.6f}\n) print(转换完成)逻辑上分四步先建image_id到图片信息的索引避免循环里反复查再做类别 id 映射保证从 0 开始然后按image_id把标注聚合减少遍历最后逐图写 txt坐标从[x, y, w, h]转成归一化的中心点格式。参数上cat_map是关键如果你的数据集类别 id 本来就是 0映射后不变symlink那行如果系统不支持软链换成shutil.copy即可。归一化保留 6 位小数足够再多没必要。3.3 生成训练用的 data.yamlYOLO 训练需要一个 yaml 描述数据路径和类别path: ./yolo train: images val: images nc: 1 names: [phone]nc是类别数手机识别填 1names顺序必须和cat_map的值对应即索引 0 对应 phone。如果后面你加了别的类别这里要同步改。train和val这里先都指向 images正式训练前应该按 8:2 划分别拿训练集当验证集否则指标虚高上线就翻车。4. 训练与验证从 2628 张图跑出可用模型4.1 训练命令与关键参数以 YOLOv8 为例装好环境后一条命令就能起训yolo detect train \ data./yolo/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/phone \ nameexp1modelyolov8n.pt用预训练权重2628 张图不算多从头训容易过拟合迁移学习更稳。imgsz640是常见输入尺寸如果原图分辨率很高且手机目标小可以提到 960但显存和速度要权衡。batch16按显存调爆显存就降到 8。patience20表示 20 轮没提升就早停省时间。lr00.01是初始学习率小数据集可以降到 0.001 更稳。4.2 验证指标怎么看训练完看runs/phone/exp1下的结果重点看mAP50、mAP50-95和precision/recall。手机识别单类mAP50上 0.9 通常说明数据质量不错如果mAP50高但recall低说明漏检多可能是小目标或遮挡样本不够。混淆矩阵里如果背景被大量误检成手机检查标注里有没有把非手机区域框进去。验证时用yolo detect val指定同一份 data.yaml别手动改路径容易对不上。4.3 推理与结果导出训完直接推理一张图yolo detect predict \ modelruns/phone/exp1/weights/best.pt \ sourcetest.jpg \ conf0.25 \ saveTrueconf0.25是置信度阈值手机检测场景可以调到 0.4 减少误报。saveTrue会把画框结果存下来方便肉眼检查。如果发现框偏了多半是转换时坐标没归一化对回头查第 3 章的脚本。5. 避坑与排查标注和训练里最容易翻车的五件事5.1 现象训练 loss 一直不降mAP 接近 0原因通常是类别 id 没映射COCO 的category_id是 1YOLO 按 0 读导致所有框被当成无效类。解决回到第 3 章脚本确认cat_map输出data.yaml的names索引和它一致。5.2 现象报错「No labels found」原因多是 label 目录结构和 data.yaml 不匹配或者 txt 文件名和图片名没对上。YOLO 要求图片和同名 txt 在同一级或对应目录。解决检查yolo/labels下是否有和图片同名的.txtdata.yaml 里train路径指向的目录下要有images和labels两个子目录或者用train: images加labels自动推断。5.3 现象框位置整体偏移或缩放原因是 bbox 没归一化或者用了[x1,y1,x2,y2]当[x,y,w,h]。COCO 的 bbox 是左上角加宽高YOLO 要中心点加宽高再除以宽高。解决在转换脚本里打印一条转换前后的框和原图对照确认中心点落在目标上。5.4 现象验证集指标高实际推理漏检严重原因是训练集和验证集没分开或者验证集图片和训练集重复。2628 张图如果全拿去训验证指标没有意义。解决按 8:2 划分用脚本随机 split确保验证集图片不出现在训练集里。5.5 现象显存爆掉或训练极慢原因是imgsz或batch太大或者图片分辨率远超模型输入。解决先降batch到 8 或 4再考虑降imgsz。如果原图是 4000 像素宽训练前统一 resize 到 640 或 960别让数据加载成为瓶颈。6. 进阶技巧用 COCO 评估接口反查标注质量训完模型别急着收工用 COCO 官方评估接口跑一遍能反查出标注里的问题。COCO 的pycocotools支持按面积、类别统计如果某些尺寸的框 AP 特别低说明那类目标标注可能有问题。装好pycocotools后把预测结果转成 COCO 格式再评估from pycocotools.coco import COCO from pycocotools.cocoeval import COCOeval # 加载原始标注和模型预测结果预测需转成 COCO results 格式 coco_gt COCO(annotations/instances.json) coco_dt coco_gt.loadRes(predictions.json) e COCOeval(coco_gt, coco_dt, iouTypebbox) e.evaluate() e.accumulate() e.summarize() # 按面积看 AP定位小目标问题 for area in [small, medium, large]: e.params.areaRng [e.params.areaRng[0], e.params.areaRngLbl.index(area)] e.evaluate() e.accumulate() print(area, e.stats[0])这段代码的价值在于把整体指标拆到不同尺度。如果small的 AP 明显低于large说明小手机目标标注或增强不够可以针对性加 mosaic、copy-paste 增强。predictions.json需要你从 YOLO 输出转成 COCO 的[x,y,w,h,score,category_id]格式写个小转换函数即可。我一般会在第一次训练后就跑这个评估把低 AP 的类别和尺度记下来回头补标注或调增强比盲目加轮数有效得多。从那以后我每次拿到新数据集都强制先跑一遍 COCO 评估再决定训练策略省下的时间够多训好几轮。希望帮到你。本文还有配套的精品资源点击获取
返回列表