手机检测这个方向,我前前后后折腾了小半年。最开始以为无非就是把训练集丢进YOLO里跑几十个epoch,结果真上手才发现,坑全藏在数据上——通用数据集里手机目标太小、和咖啡杯长得像、还有各种反光,模型精度根本压不上去。所以我干脆自己攒了一套2800张图的手机检测数据集,全程用YOLO格式标注和训练,从采集、清洗、标注到调参,踩过的坑和试出来的经验都在这篇里,给想自己做手机识别、玩手机检测或者目标检测入门的朋友做个参考。
这套东西能干什么?往小了说,可以识别画面里有没有手机、手机在哪;往大了说,靠着这套数据,你可以延伸出"自习室玩手机检测""工位手机使用统计""无人零售柜手机伪支付识别"这类具体场景应用。不管你是0基础纯小白,还是已经跑过YOLOv5想换YOLOv8/v11试试的人,这里的实操步骤和坑位记录应该都能帮到你。2800张听着不多,但要是分布合理、标注规范,配合数据增强,小模型也能做出可用性不错的检测效果。
1. 项目背景与数据集定位
1.1 通用数据集为什么不够用
很多人一上来就喜欢拿COCO数据集里的cell phone类别直接训练,或者用现成的预训练权重直接推理。我最初也这么干过,结论是:在小场景下勉强能用,放到真实场景里很拉胯。原因很简单,COCO里手机目标通常占据画面较大面积,比如一个人举着手机接电话的照片;而真实监控视角下的手机检测,往往是目标很小,可能就占图像的2%到5%,甚至更小。小目标在YOLO的深层特征图里信息已经快消失殆尽了,自然漏检严重。
还有一个问题是外观多样性。手机有直板、折叠、全面屏、刘海屏,颜色从黑到白到各种渐变色,屏幕内容有亮有暗,这还没算上手机壳、反光、遮挡。COCO里的手机标注可能二三十张,覆盖不了这么大变化范围。专门做手机检测数据集,就是为了把"手机"这个类别在目标尺度、角度、光照、遮挡情况上的分布拉满,让模型真正学到"手机"的本质特征,而不是某个特定场景下的表象。
1.2 2800张的规模到底够不够
说实话,2800张图放在目标检测里属于小规模数据集。如果只看数量,肯定比不过几万张的大数据集。但关键在于你的任务复杂度。手机这个类别是"单一的刚性物体",形状相对固定,不像行人那样姿态千变万化,也不像车辆有那么多车型差异。单一类别、小目标、场景可枚举的情况下,2800张经过合理划分,训练一个YOLOv8s或者YOLOv8n是完全够用的。
我见过的经验做法是:先用小模型快速验证数据质量,如果精度达到预期,再扩充数据或换大模型。2800张数据配合在线数据增强,等价于几万张的效果。而且规模小有规模小的好处:训练快、迭代快,你可以在一天之内实验多种超参组合。后面我们在训练章节会专门说怎么把2800张的价值压榨干净。
2. 数据集的采集与构建细节
2.1 图像来源与多样性设计
构建数据集的第一步不是急着拍照或爬图,而是先想清楚你的检测场景。我给自己的定位是"课堂/办公场景下的手机使用检测",所以图像采集围绕这个核心展开。大概做了几类来源的混合:
- 公开数据集中的手机相关图片,比如COCO、Open Images里的手机样本,跑一遍预训练模型粗筛后人工复核。
- 自己用手机、相机按不同角度拍摄的实景图,覆盖桌面、手持、口袋遮挡、屏幕亮灭、远近不同距离。
- 摄像头视角的模拟图,因为最终部署多半是监控视角,特意用支架模拟1.5米到3米高度俯拍。
- 网络公开图片中合适的部分,做了版权确认后选取,主要是补充不同型号手机的外观差异。
多样性设计上有几个容易被忽略的点。一是一定要控制手机品牌和型号的偏向。如果训练集里全是iPhone,模型很容易把白色边框、三摄模组当成特征,换安卓机就直接失效。我手动统计过标注框的配色占比,把白色、黑色、蓝色、金色、红色的手机尽量均衡开。二是屏幕状态要让"亮屏"和"灭屏"接近1比1,因为亮屏时屏幕内容会干扰模型,灭屏时靠机身轮廓判断更难。三是加入部分遮挡和模糊样本,模拟快速移动和手部遮挡的瞬间。
2.2 标注规范与YOLO格式转换
标注工具我用的LabelImg和X-AnyLabeling,前者是老牌开源工具,YOLO格式直接支持,适合少量精标;后者界面更现代,支持自动标注辅助,适合批量处理。不管用什么工具,标注规范必须先定死,不然返工到崩溃。我的规范是:
- 标注目标是"完整的可见手机",包括屏幕和机身,但不包括充电线、耳机、手机支架。
- 如果手机被手遮挡,只要超过30%的面积可见就要框出完整外边框;遮挡超过70%则跳过不标。
- 多个手机同时出现时全部标注,不因为"显眼"而漏标。
- 完全看不清是手机的区域,宁可丢弃该图也不硬标。
YOLO格式核心就是把归一化的中心点坐标和宽高存进txt文件,每行格式是class_id x_center y_center width height。这里特别容易踩坑的是宽高计算,假设标注框在像素坐标系下的左上角是(x1,y1),右下角是(x2,y2),图片宽高是width, height,那么:
x_center = ((x1 + x2) / 2) / width y_center = ((y1 + y2) / 2) / height box_width = (x2 - x1) / width box_height = (y2 - y1) / height注意所有值都要归一化到0到1之间。用LabelImg导出YOLO格式时工具会帮你算好,但用脚本批量处理时经常有人忘了归一化,训练时loss直接NaN,查半天才发现坐标值超出0到1范围。我自己写过一个转换脚本,从VOC格式XML转YOLO,核心逻辑对应关系就在上面这个公式,跑完随机抽查了几百张,人工对了一遍边界框,确保没有坐标错位。
2.3 数据集划分与目录结构
数据集按8比1比1划分成训练集、验证集、测试集。划分前我做了个去重操作——用感知哈希算法计算图像相似度,把高度相似的图片找出来分到同一个子集,避免测试集里出现训练集的"孪生兄弟",否则指标虚高没有参考意义。划分后,目录结构按照ultralytics项目约定做:
mobile-phone-dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/img和label的文件名一一对应,相同前缀。检查方法很简单,写个Python脚本遍历一下两边的文件列表,前缀集合一致就行。很多训练报错"Label not found"就是文件名对不上,多半是扩展名不一致或者批量操作时改了文件名。
3. 基于YOLOv8/YOLOv11的训练实践
3.1 环境配置:从0开始的保姆级步骤
我是从纯小白状态一步步摸过来的,所以这一节会尽量写得细。先说环境,系统用的Ubuntu 22.04,显卡是一块RTX 3090,显存24GB。如果只有CPU或者小显存,后面会给出替代方案。整体需要装的东西就三样:Python、PyTorch、ultralytics库。
第一步装Python。推荐装Python 3.10或者3.11,直接用Anaconda创建独立环境最省心:
conda create -n yolo-env python=3.10 conda activate yolo-env第二步装PyTorch。去PyTorch官网按CUDA版本选择合适的安装命令。比如CUDA 11.8环境下:
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118实在不确定CUDA版本的,可以先nvidia-smi看一眼驱动支持的CUDA版本,再决定。CPU环境就把这条命令换成pip install torch torchvision torchaudio即可,但训练速度会慢一个数量级。
第三步装ultralytics:
pip install ultralytics装完后输入yolo命令,如果弹出类似命令行工具的使用帮助,环境就通了。网上流传的很多"环境配置教程"其实在坑人,让你手动装一堆依赖,实际上ultralytics会把缺的依赖自动帮你补上。我唯一遇到的一个坑是OpenCV版本冲突,彻底删掉环境重建后就好了。如果你只是做目标检测,建议别额外装一堆预发布版或者测试版依赖,直接稳定版本够用。
3.2 模型选择与参数设置
环境好了,该选模型了。YOLOv8和YOLOv11是ultralytics官方主力支持的两个系列,两者结构上一个用C2f模块,一个在C3k2、C2PSA等模块上做了变化,v11的改进点主要体现在特征提取效率和推理速度的平衡上。我自己用同一份数据集测过,v8s和v11s的精度差异很小,v11的推理延迟略有优势。所以这里给的建议是:追求极致速度选v8n或v11n,追求精度选v8s或v11s,再往上m、l、x在小数据集上容易过拟合,没有性价比。
训练前需要写一个YAML配置文件,指向你的数据集路径和类别信息。我命名为phone.yaml,内容如下:
path: /data/mobile-phone-dataset train: images/train val: images/val test: images/test nc: 1 names: 0: phone这个文件里最容易写错的就是路径。path要和下面train、val组合出完整的绝对路径,很多人直接填相对路径然后换工作目录就找不到了。建议直接用绝对路径,省事,也方便后面部署。
训练命令可以写成一行:
yolo detect train data=phone.yaml model=yolov8s.pt epochs=200 imgsz=640 batch=16 patience=30 device=0参数含义逐个说:epochs是迭代轮次,我设置200轮,配合早停机制patience=30(30轮没有更好就停);imgsz是训练图像缩放尺寸,这里是640;batch根据显存大小调整,24GB显存跑s模型batch=16是稳的,8GB显存建议改成8;device=0指定GPU。
需要注意的是,这里加载的yolov8s.pt是COCO预训练权重,迁移学习能大幅减少收敛时间,特别适合小数据集。如果你完全从头训练,2800张数据很难训出像样的效果。
3.3 训练过程与关键指标解读
训练起来后,终端会实时打印损失值和指标。外行只看mAP,但关键要看另外几个数:box_loss是边界框回归损失,持续下降说明定位在变好;cls_loss是分类损失,持续下降说明认得更准了;dfl_loss是分布式焦点损失,和个人没太大关系,稳定即可。我最开始练的时候,cls_loss掉到0.2就不动了,mAP卡在78%左右,后来排查发现是标注里混了几张很模糊的图,模型硬学学不进去,删掉后马上涨到86%以上。
训练结束后,验证阶段会输出一张confusion_matrix.png,对单类别检测来说,核心就是看对角线。因为单类别,误检会把phone分到background,看background列的值就知道误检占比了。还会输出results.png,包含PR曲线和各类损失变化趋势,这个图建议看一遍,基本能反映训练是否正常——如果PR曲线在召回率大于0.8的地方依然能保持高精度,说明模型表现不错;要是曲线掉得早,大概率是小目标漏检或者背景误检太严重。
部署导出的关键步骤也顺便说一下,训练完成后用export.py导出模型:
yolo export model=best.pt format=onnx然后用TensorRT进一步优化,能明显提速。我在一张T4卡上测试过,640分辨率下单张图片推理时间大约8到15毫秒,具体看批处理大小。如果想做实时视频流检测,建议先用ONNX或TensorRT版本,纯PyTorch的推理速度应付不了多路视频。
4. 常见问题与排查技巧实录
4.1 小手机目标频繁漏检怎么办
这个问题在手机检测里实在太常见了。你从监控画面里人眼能看清手机,但框就是不出现。排查顺序:先看输入分辨率。imgsz=640意味着图像被缩放到640x640,如果原图是1920x1080,画面里的手机可能只有十几个像素宽,缩放后直接变成像素点,模型没法识别。实测下来,imgsz提高到960或者1280,小目标召回率能上升10个百分点以上,但显存占用和推理时间也会同步上升。
除了放大输入,还可以在YOLO里开启多尺度训练scale=0.5(默认已经开启,训练时每轮随机缩放50%到150%),让模型见过不同尺度的手机。更高级的玩法是重新设计anchor,但因为YOLOv8本身用的是无锚框检测头,anchor维度不是手调的重点。如果实在漏得厉害,还有一个思路是图像切分——把大图切成4块分别检测再合并结果,速度会慢,但硬条件不变时这是最直接的提精办法。
4.2 标注质量对模型的影响有多大
小数据集最怕标注不干净。我踩过最深的坑是:用自动标注工具生成了一批框,没有逐张验收就丢进训练集。结果模型把充电器、电子手表全部认成手机,因为自动标注器把那些电子设备的框打到了手机类别里。最后我把所有框在小图上可视化出来,逐张过了一遍,才排查出几十张坏样本。
推荐一个高效质检方法:训练一个临时模型,用它在训练集上做预测,然后对比预测框和真实标注框的IoU。IoU低于0.3的样本拉出来人工看,一般情况下,不是标注框画小了,就是标错了物体。这个流程比人眼逐张看快得多。我用过后,训练集里大概清理掉了5%的脏数据,mAP直接涨了三个点。数据在精不在多,这个教训三百张图不够体现,但2800张时候不良反应会很明显。
4.3 误检背景物体如何压制
手机检测的误检通常集中在两类:一是人手或者其他电子设备,二是桌面上的书本、杯子远看像手机。前者是特征混淆,后者是尺度问题。解决手段有三个层次。
层次一:加负样本。把大量没有手机的画面(教室空桌面、办公环境、人拿着书、喝水的场景)单独作为背景图放进训练集。YOLO支持通过background目录来加无目标图片,或者把所有背景图标注成没有对象。这个做法简单但有效,我从308张背景图加到800张后,误检率肉眼可见下降。
层次二:调整置信度阈值。推理时把conf-thresh从默认的0.25提高到0.35或0.4,误检数量显著减少,同时召回率下降有限。实际部署时我会用一个比较激进的高阈值,然后在业务逻辑里要求连续多帧命中才算有效,这样既稳又准。
层次三:后处理。因为手机检测往往伴随时间连续性,比如"玩手机"行为至少持续数秒,所以可以用滑窗统计,短时出现的孤立检出直接丢弃。这种方法虽然土,但在工程上比加一堆复杂模块还靠谱。
4.4 从训练到部署的完整路径与心得
最后一个实用心得:从第一天开始就把验证集当"考试题"供起来。我见过太多人反复用验证集调参,偶尔看一眼测试集,结果模型泛化能力被高估。正确做法是,训练阶段只看验证集,所有实验做完后,最后才用测试集给一个最终分数,防止信息泄漏。2800张数据本身就少,如果验证集被污染,整个调参过程就失去了度量衡。
部署时还要注意硬件差异。我们实验室的T4 GPU在TensorRT优化后表现不错,但换到Jetson Nano这种边缘设备,模型大小和算子支持都要重新评估。YOLOv8n的FP16模型可以跑实时,但s模型就要考虑剪枝或蒸馏了。这也是为什么我一直强调小模型的可用性——外来数据再漂亮,部署时跑不动都是零。
手机上检测、桌面上检测,这些场景各有各的脾气。但万变不离其宗:数据分布决定上限,标注质量决定下限,模型和调度是把上限尽量往前推。我自己走过最多弯路的就是贪数据量、图省事用自动标注不加复核,被现实狠狠教育后,还是老老实实回到"精细化数据+稳健小模型"这条路上。后面我打算把这个数据集扩充到监控视角下的夜间红外场景,那边又得重新采集一批样本了——这个坑,留给下次再填。