ARTICLE DETAIL

资讯详情

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

YOLO手机检测数据集全解析:2800张图片从标注到部署实战

YOLO手机检测数据集全解析:2800张图片从标注到部署实战 做目标检测这几年我手上过过不少数据集但专门为“手机”这个目标整理一套2800张YOLO格式数据集的经历还是值得单独写一篇聊聊。手机这个目标看起来简单不就是个矩形嘛可真要落到具体场景——比如流水线上的手机质检、会议场景里识别谁在玩手机、回收设备对手机外观做预筛——你会发现它比想象中难搞反光、暗光、遮挡、小目标、颜色和环境高度相似……这批2800张数据刚好踩在这些痛点上。1. 为什么手机检测值得单独做一套数据集先说场景不然你可能会问手机检测有什么好做的人脸检测都能做手机不是更简单恰恰相反普通拍摄环境里手机确实不难检测但真正需要算法的地方条件都不友好。生产线质检手机从传送带上经过角度多变有时是背面朝上有时是侧面还要在快速移动中检测有没有漏装后盖、有没有贴膜气泡。会议/考场行为分析摄像头挂在墙角距离远手机在画面里可能只有几十个像素还要遮挡人员手部动作。回收设备预筛手机回收柜机需要识别放入的设备是不是手机尺寸、形态、屏幕是否碎裂背景光线往往很杂乱。短视频内容审核检测画面中是否出现手机作为“教人玩手机”“反诈宣传”等内容分类的前置条件手机在这里是个语义属性不是物理目标。桌面感知与手势交互一些智能桌面设备需要知道手机是否放在指定区域这属于固定视角、固定距离下的高精度检测。这些场景有一个共同点数据获取容易标注麻烦而且公开数据集几乎找不到现成的“手机专用”目标检测集。COCO里虽然有手机类别cell phone但数量占比很低场景也偏日常随手拍用在工业场景或者俯拍场景下泛化效果很差。这也是我整理这套2800张数据集的原因要解决的是手机检测的专用化问题而不是通用目标检测里的一个附属类别。1.1 手机目标“看着简单、干着难”的数据特点手机检测难在哪儿先看它和行人、车辆这类常规目标检测对象的差别维度行人/车辆手机形态一致性行人姿态多变但长宽比相对固定手机横竖屏切换长宽比从0.5到2.0不等颜色分布衣服多样但与环境对比明显黑色、深色手机占比高容易“藏”进暗色环境反射特性漫反射为主玻璃屏幕和金属边框强反光亮斑会吃掉部分目标尺度分布近处大、远处小但很少极小在会议场景中经常只有二三十个像素上下文干扰行人背后有车辆、树干扰手、充电宝、平板、计算器都长得像手机明白了这些特点再去看数据集该怎么拍、怎么标就有方向了。我的原则很简单宁可场景杂一点也不要全拍成“手机居中、全屏、无遮挡”的理想图。理想图训出来的模型在测试集上mAP能到0.99但一上真实场景就掉到没法看。所以我在这2800张里故意塞了不少“难例”黑色手机放在黑色桌面上、手机背面朝上混在笔记本旁边、隔着玻璃膜拍摄、侧面斜角拍摄、部分被手遮挡、屏幕反光到几乎看不见边框……这些图在训练时会让loss曲线暂时难看一点但最终模型的鲁棒性完全不是“干净数据集”能比的。提示判断一套数据集好不好先别看标注数量先看hard example的比例。如果一套数据里所有目标都清晰、居中、完整那它大概率只能做演示不能落地。2. 2800张数据集的构成与标注规范这一节把数据集本身的细节说清楚。我整理数据集时按“训练集80%、验证集10%、测试集10%”的比例切分也就是训练集2240张、验证集280张、测试集280张。有人习惯只分训练集和验证集但手机检测这类小目标场景测试集能帮你发现“验证集上被反复调参调过拟合了”的问题所以我还是留出了固定测试集。2.1 图像来源与场景分布这批图像的来源比较杂既有手机实拍也有从公开视频帧里裁剪出来的还有一小部分是模拟渲染图。混合来源有个好处让模型学到的是“手机”这个类别的本质特征而不是某个摄像头、某种光线条件下的过拟合特征。场景分布上我大致分成四类手持场景人手握手机打电话、刷视频、自拍约占总量的35%。这类图的核心是“人手手机”的上下文后面训练时也容易出问题我会在第四章细说。桌面/静态场景手机平放、斜靠在支架上、插在充电座上约30%。这是回收柜机、桌面感知这类落地场景的主要形态。随身/多目标场景手机在包里露出一角、口袋中露出一半、桌上同时有3到5台手机约20%。多目标场景主要用来训练模型处理密集目标。极端条件场景夜间、逆光、强反光、隔着玻璃、动态模糊约15%。这些图是让模型“不那么容易崩”的保险。每张图的平均目标数是1.8个最多的一张有11台手机。小目标长边小于32像素占比大概在22%左右中目标和大目标各占约40%和38%。这个分布不算极端但足够让模型接触到不同尺度的目标。2.2 YOLO标注格式与目录组织数据集采用YOLO txt格式和YOLOv5/v8/v11都能直接对接。每张图片对应一个同名txt文件txt里的每一行是一个目标格式是class_id cx cy w h其中cx、cy是归一化后的中心点坐标w、h是归一化后的宽高取值范围都是0到1。比如一张1080x1920的图片里手机中心在(540, 960)、宽300、高600标注就是0 0.5 0.5 0.2778 0.3125我用Python脚本统一检查过一遍标注最容易犯的错是坐标算出来超出[0,1]范围比如目标贴边时cx w/2 1。这种标注在训练时会让loss突然变大甚至引发梯度异常。检查脚本很简单from pathlib import Path for label_file in Path(labels).rglob(*.txt): for line in label_file.read_text().strip().splitlines(): parts list(map(float, line.split())) if len(parts) ! 5: print(f格式错误: {label_file}) cls, cx, cy, w, h parts if not (0 cx 1 and 0 cy 1 and 0 w 1 and 0 h 1): print(f坐标越界: {label_file}: {line})目录结构按Ultralytics的标准来组织phone_dataset/ ├── images/ │ ├── train/ # 2240张 │ ├── val/ # 280张 │ └── test/ # 280张 ├── labels/ │ ├── train/ # 2240个txt │ ├── val/ # 280个txt │ └── test/ # 280个txt └── phone.yaml # 数据集配置文件phone.yaml内容如下path: /path/to/phone_dataset train: images/train val: images/val test: images/test nc: 1 names: 0: phone2.3 类别设计的一个关键决策这套数据集我坚持做成了单类别只有phone这一类。你可能觉得奇怪既然要落地到回收设备、会议行为分析为什么不顺便标上hand、table、screen这些相关对象原因有二。第一类别越多标注成本和质量控制难度呈指数上升2800张单类别标注我可以做到每个框都检查一遍加上hand之后质量就没保证了。第二很多下游任务其实只需要知道“手机在哪里”至于关联分析完全可以用后处理规则去做——比如检测到手机框和人体手部关键点的高度重叠再判断是否手持。如果你确实需要多类别我建议在训练之后做增量扩展而不是把第一版数据集搞复杂。我在第五章会讲怎么在这个数据集基础上加类别。2.4 数据清洗与边界处理数据集整理到一半时我踩过一个小坑有些图的标注框和物体轮廓严重不贴合比如屏幕高亮区域大标注框把屏幕亮斑整个包了进去甚至框到了桌面反光上。这类“标注框过大”的问题对训练非常不利因为模型学到的是“手机一块亮区域”而不是“手机一个物理实体”。清洗方法我用的是半自动方案。先跑一个预训练的YOLO模型在全部图上做预测然后把“人工标注框”和“模型预测框”的IoU较低的样本逐一抽出来人查。这个策略很适合小数据集2800张图真正需要人工复查的也就两三百张比全部重新标注快得多。另一个边界问题是贴边目标。正常拍照很少有手机被画面边缘切一半的情况但监控视角俯拍时经常出现手机半截露在画面外。这类目标我不建议全删保留一部分可以让模型对“画面边缘被截断的目标”有容忍度。但要注意比例控制在5%以内否则模型会把“残缺手机”也当成正常完整手机来学最后推理时反而对完整手机不敏感。3. 从零训练YOLO手机检测模型实操全流程数据集准备好了接下来就是训练。这节我把完整流程走一遍包括环境、参数、验证以及每个关键选择背后的原因。3.1 环境准备与预训练权重选择我推荐用Ultralytics YOLOv8或者更新的YOLO版本原因很简单API简洁、文档全、导出部署工具链成熟对新手也友好。环境核心依赖是PyTorch和ultralytics包pip install ultralytics torch torchvision硬件方面我的实测经验是2800张图、640分辨率、batch 16一张8G显存的RTX 3060/4060就能训完单模型训练时间大约2到4小时。没有必要为了这个量级专门上多卡。关键的选择在于起始权重。很多人从零开始训练即weights或者随机初始化这在只有2800张图的情况下是自找麻烦。目标检测模型的特征提取器backbone在ImageNet或大规模检测数据上已经学好了通用视觉特征迁移学习能让你省掉大量训练时间而且泛化更好。我的建议是起始权重适用场景实测参考yolov8n.pt基线测试、边缘设备部署、快速迭代mAP50约0.90推理快yolov8s.pt精度优先且算力够用mAP50约0.93推理速度适中yolov8m.pt追求极致精度、不在乎部署体积mAP50约0.94显存占用翻倍追求最快迭代速度用yolov8n.pt或yolo11n.pt权重小、训练快作为基线足够追求精度上限用yolov8s.pt甚至yolov8m.pt。手机检测的目标本身不算极难s模型在640分辨率下mAP50通常能到0.93以上m模型提升有限但推理速度明显变慢如果你要部署到手机、Jetson这类边缘设备直接选n或s别再往上加了。3.2 数据集配置与训练参数训练命令我实测下来最稳的一组参数是这样的yolo detect train \ data/path/to/phone_dataset/phone.yaml \ modelyolov8n.pt \ epochs120 \ imgsz640 \ batch16 \ lr00.01 \ patience30 \ seed42逐项说下理由imgsz640YOLO默认就是640但这套数据里有22%的小目标如果你觉得小目标漏检严重可以提到768或960。代价是训练时间和显存占用上升。我做实验时640下mAP50大概0.90提到960后涨到0.93但训练时间翻了一倍实际部署若用边缘设备还会掉帧所以部署场景我反而坚持640。epochs1202800张图其实不多官方COCO训练通常300轮但小数据集很容易过拟合120轮配合早停足够。patience30的意思是连续30轮验证集指标不涨就自动停我大部分训练都在80到100轮内结束。lr00.01这是SDG风格的学习率如果你换用AdamW建议降到0.001。别一上来就用0.1这种激进值小数据集配大学习率非常容易出现loss直接发散后面我会再提“BN崩溃”的坑。seed42固定随机种子保证可复现。调参的时候如果不固定种子你无法判断指标变化到底是参数带来的还是随机性带来的这是很多人忽略的细节。开始训练后你要重点盯训练日志里box_loss、cls_loss、dfl_loss三条曲线。正常的趋势是loss逐步下降然后趋于平缓如果出现突然跳高或者NaN大概率是学习率太大或者标注数据有问题。我会在第四章展开讲排查。3.3 结果验证不看mAP这些指标更说明问题训练结束后在runs/detect/train目录下会生成results.csv、混淆矩阵、PR曲线等结果。很多人只看mAP50但我在手机检测这个场景里还会额外关注三个东西一是小目标上的召回率。用val命令或者脚本按GT框的面积分桶统计召回率如果长边小于32像素的目标召回率明显偏低说明训练分辨率不够或者需要数据增强来补充小目标。二是PR曲线的“拐点”位置。PR曲线越靠近右上角越好但如果曲线在召回率高的时候精确率掉得特别快说明误报很多。这种情况我遇到过模型把黑色充电宝当成手机了后面靠加负样本解决。三是不同置信度阈值下的表现。手机检测下游任务往往对置信度阈值有硬性要求——比如生产线系统只接受置信度大于0.5的检测结果。你用yolo detect val时通过conf参数改变阈值看指标变化这比一个孤零零的mAP更贴近生产现实。我通常还用下面这段命令做一次完整的预测测试把每张图的检测结果画出来检查小图和难例的实际表现而不只是看数字yolo detect predict \ modelruns/detect/train/weights/best.pt \ source/path/to/phone_dataset/images/test \ saveTrue \ conf0.25 \ imgsz640画出来的图上要重点看三类样本黑色手机在暗背景的、屏幕强反光的、部分被遮挡的。如果这类样本上检测框抖动或者丢失优先回数据侧补充。注意验证集mAP高不代表真场景可用。如果你做的是会议行为分析一定要拿一段真实的会议录像测一下因为录像里的画面噪声、运动模糊和数据集里的静态图差别很大。我在第四章会讲一个我踩过的具体例子。4. 手机检测训练的翻车高发区与排查经验这一章是我最想写的部分。2800张图看起来不多但训练过程中遇到的那些坑几乎和数据集大小无关和“手机检测”这个任务本身强相关。4.1 小目标漏检一个完整的排查链路我第一次用这套数据集的子集训练时验证集mAP50有0.96一眼看上去很不错。结果拿到一段监控视频里测试手机在画面里大概只有40x80像素模型几乎全漏了。当时我的第一反应是“参数没调好”来回试了epochs、batch、学习率效果都不明显。后来静下心来按链路排查先看测试图来源监控视频是1080p的我训练图原图是720p和1080p混合视频帧缩到640后小手机目标只有40x80像素确实很小。按目标尺度分桶统计召回率写了个脚本按GT的短边把测试集目标分成32、32-96、96三个区间一看就明白了——小于32的那一桶召回率只有56%而大于96的桶有98%。显存不够时先降batch再升分辨率为了试960分辨率我把batch从16降到8训练时间长了但小目标那一桶涨到68%。再用数据增强解决剩余的gap我加大了Ultralytics自带的scale增强参数让训练时目标随机缩放范围更大最终小目标召回率到了74%。这个排查链路的价值在于第一步就先确定问题“分布在哪里”而不是盲目调参。如果你遇到小目标漏检建议也先做分桶统计再决定应该调分辨率、调增强还是换模型头。问题出在哪里我后来分析了一下一是训练图里虽然有小目标但占比还不够多二是小目标在640分辨率下下采样到20x20的特征图上本来就只有少数几个网格点覆盖特征信息太弱。解决办法我有三个按优先级排序提高训练分辨率从640提到960小目标对应的特征点数明显变多做小目标数据增强用Ultralytics自带的augment参数做随机裁剪缩放相当于把小目标在训练过程里“放大”了让模型看到换更强的小目标检测头比如给模型加一个针对小目标的检测层或者用基于RepVGG的改进版本。不过这类改动会牺牲推理速度我一般不作为首选。4.2 把“手”学成“手机”上下文特征的干扰这个是手机检测最经典的坑。手持场景的图像占了我数据集的35%人手握着手机时检测框经常把整只手也框进去甚至在没有手机的时候把手检测成手机。原因不难理解模型在训练时发现“手手机”几乎总是成对出现于是把手也当成手机的强特征了。你去看它提取的特征图靠近手腕的区域响应度很高。我有个做会议行为分析的朋友一开始模型误报率特别高一查发现是把人抬手抓挠的动作当成手机了。解决思路不是去改网络而是改数据分布加入“只有手、没有手机”的负样本图片。让模型知道“手”这个上下文可以单独出现并不意味着一定有手机加入“手机在口袋/包里露出一角、但没有手”的图片。打破“手机必然和手一起出现”的关联标注时严格用最小外接矩形框住手机本体不要把手指握持的部分框进来。我在2800张的原始分布里补充了大约150张纯手部负样本做法是把phone.yaml里增加一个负样本目录图片不打标注。Ultralytics支持这种无标注文件图片它们只参与背景损失计算。加了负样本之后误报率下降了大概40%。4.3 无目标误报与混淆矩阵的“总合不唯一”训练报告里有个现象会让不少初学者困惑混淆矩阵的每一行加起来不是100%或者不同类别相加不等于总数。我在做手机检测时也遇到过网上关于“yolo混淆矩阵总合不唯一”的讨论很多。这里要说明白YOLO的混淆矩阵并不是一个标准的多分类混淆矩阵它的行和列分别对应“GT属于这一类”和“预测属于这一类”但是一张图里可能出现多个目标、同一个目标也可能被重复预测所以行列合计并不必然相等。而且Ultralytics默认还会在右下角加一个“background”单元格表示被正确忽略的背景区域其数值可能很大导致看起来矩阵“不闭合”。我的经验是别纠结于矩阵总合是不是唯一重点看对角线数字和“background”那行。如果phone这一类对角线召回足够高而背景那一格吃掉了大量误报说明模型决策边界合理。真正需要警惕的情况是检测结果里出现大量置信度很高的无目标框。这种通常不是数据问题而是推理时conf阈值设得太低。我在大量测试后发现手机检测场景把推理阈值设在0.3到0.5之间比较合理低于0.3误报明显增多高于0.5小目标和遮挡目标丢得厉害。4.4 训练中BN崩溃一个容易被忽视的细节热词里反复出现“yolo训练中bn崩溃”这个词对老手来说可能不陌生训练过程中BatchNorm层的统计量running mean和running variance出现NaN或者极端值导致loss爆炸、模型整个废掉。我在手机检测这个小数据集上遇到过两次排查下来都是学习率设置不当导致的。小数据集训练时BN层的统计量本来就不稳定如果学习率大再加上batch太小很容易骑上“失稳”这个临界点。另外标注数据里如果混入了坐标越界的gt框也会间接触发这种问题。如果你也遇到BN崩溃或训练loss发散按这个顺序排查把lr0调到0.005以下batch提高到至少8检查所有txt标注有没有坐标大于1或者小于0的用我前面的Python脚本跑一遍检查是否某些图片的宽高信息和标注不匹配比如原图被resize过但标注没跟着改如果还是炸检查显卡驱动和PyTorch版本个别CUDA版本确实存在BN层的数值稳定性问题。提示BN崩溃的问题十个有九个是学习率或数据标注的锅不要一上来就去改网络结构。先把训练配置和输入数据查干净通常就解决了。5. 数据集的扩展方向与部署落地最后聊聊这套2800张数据集的后续路径。单类别手机检测只是一个起点实际项目中它几乎总是被嵌入一个更大的流程。5.1 负样本与多类别扩展如果你需要多类别检测最自然的扩展是加上我们之前在类别设计里提到的相关对象hand、table、laptop、tablet。但我会提醒一句加类别之后原有手机检测的性能几乎一定会下降因为模型要在类别之间做决策原来可以“无脑把所有像手机的东西都检出来”现在要先判断到底属于谁。我的建议是采用分阶段策略先用这套单类别手机数据集把手机检测模型训到够好单独再训一个轻量的分类器对手机框内的图像二次分类比如判断屏幕是否亮着、手机品牌分类器可以用MobileNet或EfficientNet效果比直接做多类别检测更好也更省训练数据如果一定要多类别检测给每个新类别补充至少500张标注图再合并训练。负样本在这里同样重要。生产环境中很容易出现“像手机但不是手机”的物体充电宝、平板、计算器、遥控器、香皂盒……每发现一类就补充一批负样本图。我后来把负样本库扩到了800张手机检测的线上误报率又压下去一截。5.2 从训练到部署导出ONNX与边缘端推理模型训好之后要落地最常走的路径是导出ONNX再转向具体推理引擎。Ultralytics一条命令就能导出yolo export modelbest.pt formatonnx imgsz640 opset12如果目标设备是手机或Jetson还可以继续转TensorRT或NCNN。这里给个实测参数参考yolov8n在640分辨率下导出ONNX后单张推理时间在Jetson Orin Nano上大约6到12毫秒在iPhone上用CoreML跑大约20到30毫秒完全够实时。部署时有一个容易踩的坑训练时如果用了mosaic增强部署时推理图的尺寸比例变化会让小目标的检测精度下降。Ultralytics默认mosaic1.0训练时每张图都是四图拼接这会让模型适应各种宽高比的输入但某些ONNX推理引擎只在固定的640x640输入尺寸下优化过如果你喂入不同尺寸速度反而更差。所以部署时我一般固定成训练分辨率并且用letterbox补边不做自适应resize。5.3 用蒸馏和伪标签把小数据集的效果再榨一榨2800张图不是特别多但配合一些trick还能再挖出潜力。我自己试过两条路都有效伪标签半监督用训练好的模型去标注一批完全没有标注的手机图片置信度大于0.85的框当成新标注加进训练集。相当于模型自己给自己“出题”然后再“做题”。实测加5000张无标注图模型在小目标上的召回率又提升了3到5个百分点。前提是你要人工抽检一下伪标签质量防止错误累积。大模型蒸馏用更大的YOLO模型比如v8x或CLIP这类视觉语言模型对同一批图生成软标签再用yolov8n去逼近软标签做知识蒸馏。原理上就是“让老师模型把比硬标签更丰富的分布信息传给小模型”。Ultralytics目前对蒸馏支持还不是开箱即用需要改一点训练脚本但收益在小目标场景里挺明显。顺带一提如果你做的是“检测语义”结合的需求比如检测到手机之后还想知道画面里手机的品牌可以像热词里提到的“yolo加clip”那样YOLO先出框CLIP在框内做零样本分类不增加新的数据集标注成本就能获得开放词表能力。这个思路在手机回收场景里非常好用——你可以随时加一个“碎屏”“带壳”“亮屏”之类的属性词不用重新训练检测头。5.4 集成进业务系统时的两个小建议模型本身不是终点集成时有两个细节很容易被忽略。一是检测结果的时序平滑。视频流场景里单帧检测偶尔会丢一两帧直接拿单帧结果去触发业务逻辑会带来抖动。我习惯对连续几帧的检测框做IoU匹配只有连续N帧都能匹配上的目标才算“确认”这样误触发率能降到原来的三分之一。代价是引入一两帧的延迟对绝大多数业务来说完全可接受。二是明确输出坐标系。如果你要把检测框坐标传给机械臂、PTZ摄像头等下游硬件记得统一坐标基准。训练时的坐标是相对于输入图像的归一化坐标而硬件往往需要的是像素坐标或实际物理坐标。中间差一步换算不处理好模型精度再高也白搭。写到这里手机检测数据集从数据构成、训练流程到落地经验基本都覆盖了。如果让我用一个词总结这套2800张数据集的使用心得我会选“场景设计”。数据量在目标检测里不是决定性因素你能不能把真实落地时的光线、角度、遮挡和上下文干扰装进一个不大的数据集里才是模型上线后能不能站住脚的根本。希望你拿到类似的数据集时也能先在“场景设计”上多花点功夫——这比我上面写的任何一条命令都重要。
返回列表