ARTICLE DETAIL

资讯详情

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

手机目标检测数据集构建与YOLO训练全流程实践

手机目标检测数据集构建与YOLO训练全流程实践 最近在整理一批手机检测相关的目标检测数据顺手把自己整个处理流程和踩坑记录都梳理了一遍。这份数据集一共2800张图片标注格式是YOLO专用的txt文件类别就是手机这一类主要用来训练手机目标检测模型。如果你正在做玩手机检测、课堂行为分析、工位违规识别、或者任何需要从画面里把手机框出来的视觉项目这份数据集的整理思路和训练配置可以直接拿来参考。先说一下为什么这个任务值得单独做一份数据集。手机这个物体在目标检测里看起来简单实际坑非常多。它尺寸小、形态多变、容易被身体遮挡而且不同场景下长得完全不一样。桌面上的手机、手里握着的手机、口袋边缘露出的手机、暗光环境下的手机画风差异极大。用通用COCO数据集的权重直接跑效果往往很差根本原因是COCO里手机这类小物体的样本占比不高模型根本没有充分学到手机的纹理特征。所以专门整理一份手机检测数据集针对单类目标做精调是解决这类业务问题最务实的路径。下面我把这份数据集的构成、YOLO格式规范、训练参数、以及整个过程中我实际遇到的问题完整写出来。内容比较多建议按顺序读急着上手的可以直接跳到第3节看训练配置。1. 项目整体设计与数据集构成解析1.1 为什么手机检测需要单独的数据集很多人第一反应是直接用现成的预训练模型。但实际试过就知道通用模型检测手机的效果非常不稳定。COCO数据集里手机属于小物体类样本占比少而且标注框很多是模糊的、边缘截断的。模型在COCO上学的手机特征更多是矩形物体的模糊印象而不是手机这个具体概念。我做这个项目的初衷很简单在一个教室场景的行为分析系统里需要准确识别学生是否在看手机。刚开始用yolov5s加COCO预训练权重跑误检率非常高一个黑色的充电宝、一本深色封面的笔记本、甚至反光的桌面都被框成手机。换了几个权重都一样问题就出在数据分布上。真实场景里手机出现的姿态、光线、遮挡情况和COCO里的样本差距太大。所以要解决这个问题必须建立自己的数据集。2800张图说多不多但对于单一类别检测任务来说只要场景覆盖足够完全够用。关键在于数据的多样性设计而不是单纯堆数量。1.2 数据集的场景覆盖与标注规范这批数据的场景覆盖主要按这几类来设计桌面平放、手持使用、放在口袋里露出一部分、开会时放在桌上、走路时拿在手里、以及少数自拍场景。从拍摄视角上来分有俯拍、平视、侧拍的监控视角。图片分辨率从720p到4K都有但统一在训练前做了resize处理这一点后面会详细说。标注规范上我只标注了一个类别class id固定为0。标注框采用常见的矩形框默认遵守YOLO格式的归一化坐标规则即每个目标用五个数字表示类别ID、中心点x坐标、中心点y坐标、框宽度、框高度。这五个数值全部归一化到0到1之间除以图片的宽高。这里有个经验之谈如果图片是1920x1080标注框中心点在(960, 540)宽300高600那么对应的txt内容就是0 0.5 0.5 0.15625 0.5556。这个换算逻辑新手经常算错特别是宽度和高度的归一化很多人误用了原图的宽高比导致训练时报错或者mAP异常低。标注工具方面我推荐用LabelImg或者X-AnyLabeling这类图形化工具导出格式选择YOLO格式即可。我自己用的是X-AnyLabeling因为它自带YOLO预标注功能可以先用一个已有的模型大致框出手机再人工修正2800张图的标注效率能提升40%左右。但注意预标注的框往往偏大把背景也包进去了这一步一定要人工逐张确认否则后续训练出来的框都会偏大尤其在密集场景下会导致两个手机框重叠严重。1.3 目录结构与文件命名约定一份规范的YOLO数据集文件组织方式会直接影响训练脚本的读取效率。我最终采用的目录结构如下phone_dataset/ ├── images/ │ ├── train/ # 2240张 │ └── val/ # 560张 ├── labels/ │ ├── train/ # 对应的2240个txt文件 │ └── val/ # 对应的560个txt文件 └── phone.yaml图片和标签通过文件名严格对应。比如img_0001.jpg对应的是labels/train/img_0001.txt。文件名的前后缀可以自定义但一定要保证图片和标签的主文件名完全一致否则训练时会报找不到标签的警告。关于划分比例我用的是8:2即2240张作为训练集、560张作为验证集。没有单独划分测试集因为验证集已经足够反映模型泛化能力。如果你的数据量超过一万张建议考虑7:2:1的三分法测试集在最终评估时用来做最后的无偏评估。但2800张这个量级8:2是更合理的选择训练数据多一点模型学到的特征更充分。# phone.yaml 内容示例 train: /data/phone_dataset/images/train val: /data/phone_dataset/images/val nc: 1 names: [phone]这里面有一个细节值得注意train和val指向的是images目录而不是labels目录。YOLO训练脚本会自动根据图片路径找到同级的labels目录前提是目录结构严格遵循images/train对labels/train的对应关系。如果你把labels放在别的自定义路径需要在训练脚本里额外指定否则一定报错。2. 数据清洗与格式校验实操2.1 标注质量检查的几种方法数据标注完成不代表可以直接训练。我第一次用这份数据集跑yolov5的时候mAP0.5只有0.62后来排查发现是标注质量出问题了。有一个批次的图片处理时出了错误框坐标超出了图片边界导致训练时模型学到了一堆无效信息。检查标注质量有几个实用方法。第一个方法是直接用Python脚本统计每个txt文件的目标数、坐标范围是否在0到1之间。这个方法最基础也最有效。坐标大于1的情况通常是标注工具导出bug或者人工操作时拉框超出了图片边缘。import os label_dir labels/train error_files [] for f in os.listdir(label_dir): if not f.endswith(.txt): continue with open(os.path.join(label_dir, f)) as fp: for line in fp: parts line.strip().split() if len(parts) ! 5: error_files.append((f, format error)) break cls, x, y, w, h parts[0], float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): error_files.append((f, out of range)) break if w 0.001 or h 0.001: error_files.append((f, too small)) break for item in error_files: print(item)第二个方法是可视化检查。直接把标注框画到图片上用OpenCV或者LabelImg自带的显示功能肉眼过一遍。尤其要看框是否紧贴物体边缘。我建议至少抽检20%的数据重点检查三类图片暗光环境、手部遮挡、多个手机同时出现的情况。第三类检查是类别平衡。单类数据集不存在类别不平衡问题但如果以后扩展成多类手机、平板、笔记本就要仔细统计每个类别的目标数量避免某些类别样本过少导致模型直接忽略它。2.2 数据清洗的实际操作记录我清洗时最常遇到的问题是标注框过大。很多预标注工具自动生成的框喜欢把手机周围的背景也框进去而手机这种物体本身细长稍微多点背景IoU就会差很远。清洗时设置一个可接受的范围框的宽高比在0.4到0.9之间手机竖屏时宽度小于高度为正常超出这个范围的基本都是错标。另一个问题是重复标注。同一个手机被标注了两次训练时模型就会迷茫不知道该预测哪个框。这种问题在目标密集的图片里容易出现。我用一个简单的IoU过滤脚本对所有框两两计算IoU超过0.7的就手工检查。def compute_iou(box1, box2): # box格式: [x_center, y_center, width, height] 归一化 x1_max box1[0] box1[2] / 2 x1_min box1[0] - box1[2] / 2 y1_max box1[1] box1[3] / 2 y1_min box1[1] - box1[3] / 2 x2_max box2[0] box2[2] / 2 x2_min box2[0] - box2[2] / 2 y2_max box2[1] box2[3] / 2 y2_min box2[1] - box2[3] / 2 inter_x max(0, min(x1_max, x2_max) - max(x1_min, x2_min)) inter_y max(0, min(y1_max, y2_max) - max(y1_min, y2_min)) inter_area inter_x * inter_y box1_area box1[2] * box1[3] box2_area box2[2] * box2[3] union_area box1_area box2_area - inter_area return inter_area / union_area if union_area 0 else 0清洗完这一轮我删掉了约90张有明显问题的图片又手动修正了约200个框。剩余2800张是能保证训练质量的数量。2.3 关于数据集扩增的思考目标检测的数据增强策略和分类任务不太一样。YOLO本身在训练时会做Mosaic、Copy-Paste、RandomAffine等在线增强所以离线扩充不必做太多。这里有一个原则先让模型在原始数据上过一遍如果明显过拟合训练loss很低但验证loss很高再考虑离线扩充。我在这份数据集上实测发现Mosaic增强对手机检测非常有效。手机经常出现在场景中的不同位置和大小Mosaic把四张图拼接成一张模型被迫学会在多种上下文里检测手机泛化能力明显提升。yolov5和yolov8默认开启Mosaic在超参数文件里mosaic1.0建议保持默认。如果确实需要离线扩充推荐做轻度旋转±15度以内和亮度变化。不要做水平翻转以外的强几何变换因为手机的形态是固定的翻转后虽然还是手机但一些纹理特征会被扭曲对模型学习不利。提示手机检测对亮度变化极度敏感。暗光环境下手机屏幕是主要特征亮光环境下手机外壳轮廓是主要特征。训练数据里最好包含这两种情况否则模型只能学到其中一种特征在另一种场景下直接失效。3. 训练配置与模型选型实录3.1 选yolov5s还是yolov8n这个问题我反复测试过最后两份模型都保留并验证了。yolov5s的优势是生态非常成熟部署工具链完善很多边缘端设备直接支持而且训练时的显存占用更友好。yolov8n在相同甚至更低算力下精度稍高尤其是小目标检测能力比v5s强但部署时需要额外确认推理框架版本是否支持。我的建议是如果你要部署到Jetson Nano、树莓派或者手机端优先考虑yolov5s兼容性问题少如果是在服务器上做推理或者用OpenVINO/TensorRT这类框架yolov8n是更好的选择。两种模型在2800张这种数据量下训练时间差异不大yolov8n稍快一些。还有一个选择是yolov8s如果你对精度要求高于速度可以用这个mAP会略高一点但推理时间大约是nano的1.6倍。对手机检测这种实时性要求高的任务一般不建议用超过s的版本。3.2 训练超参数与显存占用实测以yolov8n为例一份稳定且效果不错的配置如下yolo detect train \ --model yolov8n.pt \ --data phone.yaml \ --img 640 \ --batch 32 \ --epochs 100 \ --workers 8 \ --optimizer AdamW \ --lr0 0.001 \ --warmup_epochs 3 \ --project phone_train \ --name run1输入尺寸选了640。为什么不是1280因为手机虽是目标检测里偏小的物体但640在大多数场景下已经足够。我试过用960和1280mAP只提升了1.2个点左右但训练时间和推理时间分别增加了1.8倍和2.5倍。对一个实时检测任务来说这个性价比太低。如果你的业务场景画面特别大且手机占画面比例特别小比如教室全景、仓库全景可以用1280作为训练尺寸但推理时保持相同尺寸否则训练和推理的尺度不一致会掉点。batch size选了32。在单张RTX 3090 24G显存下这个值刚好能跑满stable diffusion级别的计算资源训练一个epoch大约需要40秒。显存不够的同学可以降到16但学习率也要相应调整可以按比例降一点比如0.001降到0.0005否则大batch和小batch之间的梯度更新幅度不一致模型容易震荡。学习率方面warmup_epochs设为3让模型在前3个epoch用较小学习率预热避免初始阶段梯度爆炸。优化器我用的是AdamW。以前习惯用SGDYOLO默认的SGD参数但实测下来AdamW在这个任务上收敛更快最终精度也略好。原因可能是手机检测的损失面比较复杂SGD需要精细调整动量参数而AdamW的自适应学习率省了很多调参工作。3.3 训练曲线观测与mAP指标解读训练过程中最需要盯的是三个指标Box Loss、Cls Loss、DFL Lossyolov8里叫Distribution Focal Loss。这三个loss在正常训练中应该稳步下降最后趋平。如果loss在训练到一半时突然反弹大概率是学习率过大或者batch size过小导致梯度不稳定。验证集指标里mAP0.5是判断模型是否可用的第一标准。这份数据集正常训练结束yolov8n的mAP0.5大概在0.93到0.96之间。如果低于0.85优先检查标注质量和数据划分。mAP0.5:0.95通常要低一些大概0.65到0.75这个指标更严格反映框位置的准确度。手机检测任务对框的精确位置要求不是极端苛刻一般mAP0.5达标就可以部署了。训练完成后我还做了TP/TN/FP/FN的详细统计。单类检测任务的混淆矩阵很简单但关键看FP的类型。如果FP主要集中在充电宝、笔记本、遥控器等类手机物体上说明数据集中这些负样本不够需要补充。如果FP集中在人手持非手机物体上说明需要增加这一类负样本。这是数据增强无法解决的问题只能靠补充数据。注意不要只盯着mAP数值看要统计模型出错时错的到底是什么。mAP只是总体分数真正的业务卡点往往藏在具体错误类型里。建议用验证集跑一遍混淆矩阵分析找出数量最多的那几类错误再决定下一步优化方向。4. 常见问题与排查技巧实录4.1 训练时loss为NaN的根源第一次训练时我在第20个epoch左右遇到了loss突然变成NaN的情况。排查思路和解决方法如下第一步检查是否有空标注的图片。训练集中如果有图片对应的txt文件为空0个目标某些版本的训练代码在loss计算时会除以零。用前面提到的检查脚本扫一遍把所有空txt文件找出来要么删掉对应图片要么给这些图片补充标注不能留空。第二步检查学习率。如果在warmup结束后的前几个epoch出现NaN通常是学习率过大。把lr0从0.001降到0.0005试试同时确认warmup_epochs至少为3。第三步检查异常像素值。个别图片如果包含损坏的像素数据比如全黑的纯色图、全白的纯色图在归一化后可能出现异常梯度。把这些图从训练集中剔除即可。4.2 小目标手机完全检测不到如果你训练的模型在远距离画面上漏掉大量手机但近距离表现尚可这就是典型的小目标检测问题。我的处理建议是分两步走。第一步是调高输入分辨率。从640升到960通常能直接提升小目标召回率。对手机检测来说960是一个性价比突破口。根据我实测960比640在mAP0.5:0.95上能提升2到3个点。第二步是调整anchor配置。yolov8的anchor是自动学习的理论上不需要手动设置。但如果你用的是老版本yolov5请用autoanchor重新计算anchor尺寸再手动填入模型配置。网上很多人忽略了这一步直接沿用COCO的anchor导致小物体召回率低得离谱。还有一个容易被忽略的点图片中手机太小的时候人工标注也容易标不准。一个30x30像素的框手工拖动时差1个像素IoU就掉了5%。这种噪声在小目标上会被放大建议小目标标注时放大图片到400%再拉框。4.3 验证效果好但实际场景一塌糊涂这是最让人头疼的问题也是踩过坑里最深的一个。模型在验证集上mAP高达0.94一到真实业务场景比如教室监控漏检和误检同时飙升。原因几乎都是train-val数据分布与真实场景不一致。我这份数据集当时主要采集了办公桌和实验室内景拿到教室环境后手机的数量、距离、背景差异都发生了变化。解决的办法不是调参而是补充真实场景数据。采集真实场景数据有几个技巧。可以在业务部署后做数据回流保存模型检测置信度低但人工确认是手机的片段定期加入训练集。这种主动学习的方式比一次性大规模采集效率高得多。我建议至少准备一周的真实场景片段逐帧抽帧、清洗、标注加进训练集后重训mAP一般能回升到0.9以上。4.4 数据增强参数的选择经验yolov5和yolov8的超参数文件里包含hsv_h、hsv_s、hsv_v、degrees、translate、scale、fliplr等增强参数。默认值通常适合COCO这种自然图像数据集但对手机检测需要调整。我使用这组增强参数跑出了最好的效果hsv_h: 0.015 # 色调变化幅度调低避免手机颜色失真 hsv_s: 0.6 # 饱和度变化保持默认 hsv_v: 0.5 # 亮度变化默认偏大我调低了 degrees: 5.0 # 旋转角度5度以内足够 translate: 0.2 # 平移幅度默认 scale: 0.8 # 缩放变化需要保持较大 fliplr: 0.5 # 水平翻转默认关键在degrees和hsv_v。手机通常垂直握持但偶尔有倾斜5度的旋转足以模拟日常摆姿太大反而让模型学到失真的形状。亮度上虽然手机检测依赖亮度特征但过强的亮度增强会让屏幕发白失真模型反而学不到屏幕纹理所以从默认的0.7降到了0.5。5. 部署与持续迭代的经验总结5.1 模型导出与端侧推理要点训练完成后导出格式取决于你的部署环境。如果是服务器推理直接导出ONNX格式配合onnxruntime或者TensorRT。如果是移动端或边缘设备导出TensorRT engine或者OpenVINO IR格式更合适。我的做法是先用ONNX做精度对齐验证结果没问题后再转成TensorRT避免跳过中间环节直接转换导致精度下降。TensorRT的精度校准是很多人忽略的步骤。你应该准备200到500张代表性图片作为校准集执行INT8量化校准不能随便拿几张图糊弄。我的实测里正确校准的INT8模型相比FP16只掉0.3%的mAP但推理速度几乎翻倍。如果直接跳过校准用默认配置mAP可能掉5%以上得不偿失。5.2 部署后的监控与数据回流机制部署不是终点。我强烈建议你在推理服务里加一层逻辑对置信度落在0.3到0.6之间的预测结果保存对应的原图并记录时间戳。这些模糊样本是模型改进的宝库。每周抽出50到80张人工标注后加入训练集重训一次。这样持续迭代两周后模型在真实场景里的表现会越来越稳。所谓数据回流其实就是把模型拿不准的样本收集起来。这个机制比任何调参技巧都重要。靠调参最多提升2个点而补充模型薄弱的真实样本往往一次就能提升5个点以上。5.3 关于负样本的补充做单类检测任务时负样本的重要性经常被低估。你训练用的正样本再丰富如果模型没见过假手机就一定会把假手机当成手机。我在这份数据集中加入了约150张负样本图片里面是充电宝、计算器、遥控器、深色封面的书、被手握着但看不清的物体等等。这些负样本对应的txt文件都是空的。在训练时YOLO会自动把负样本作为背景学习。别小看这150张图它们能大幅降低误检率。尤其是对充电宝和白纸板这类形态接近手机的物体正向样本学得再好也区分不了只有负样本直接告诉模型这个东西不是手机。我个人实际跑下来的体会是手机检测这个任务讲究的是一个资料库思维你不只是在调一个模型而是在积累一个越来越完整的数据资产。2800张的数据集可以帮你拿到95分的实验室成绩但要真正落地到生产环境靠的是数据回流、负样本扩充、以及定期重训这个闭环流程。最后提醒一下标注质量和场景覆盖永远是数据集的命脉模型结构反而没那么关键yolov5s和yolov8n在好数据上的差距通常不超过1%。把功夫下在数据上回报比调参高得多。
返回列表