ARTICLE DETAIL

资讯详情

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

593张图像小样本YOLO训练:玩手机打电话行为检测落地实战

593张图像小样本YOLO训练:玩手机打电话行为检测落地实战 简介这是一份面向目标检测学习者的手机使用行为识别数据集聚焦“玩手机”与“打电话”两类典型场景适合正在入门或进阶YOLO系列算法的开发者用于模型训练与验证。数据集共593张图像每张均配有标注已按训练与验证需求划分完毕可直接投入yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等主流框架使用。压缩包内共1780个文件包含593个jpg图像、593个txt格式的YOLO标注、593个xml格式的VOC标注以及1个yaml配置文件整体约20.46MB两种标注格式分别存放YOLO格式采用归一化中心点与宽高坐标便于直接读取训练。目前已有191人学习下载。对于需要快速搭建检测流程的读者可省去数据采集与标注环节直接用于类别训练、精度对比与推理测试是验证算法效果的实用素材。1. 从 593 张“玩手机打电话”图像说起小样本行为检测到底能不能落地手上有一份 593 张图像、带标签的“玩手机 / 打电话”数据集第一反应往往是这么点数据能训出能用的 YOLO 模型吗我在工厂安全帽检测、加油站打电话识别这类项目里反复遇到过同样的疑问。结论先放这儿593 张图像做通用检测确实偏少但如果场景收敛、类别只有两三类、拍摄角度相对固定它完全能训出一个可上线跑推理的模型关键在于你怎么切分、怎么扩增、怎么选预训练权重。这个标题拆开看是四件事YOLO 算法、手机这个目标载体、玩手机与打电话两种行为、593 张带标签图像。它解决的是“特定区域内人员违规使用手机”的自动识别问题典型落地场景是考场、加油站、驾驶舱、涉密车间。适合谁看手上有类似小数据集、想跑通 YOLO 训练到部署全流程的算法工程师和嵌入式开发者。下面我按数据、训练、调参、踩坑、进阶的顺序把这条链路讲透。2. 593 张图像怎么变成能训的数据集切分、清洗与标签校验2.1 先搞清楚你的标签是“检测框”还是“行为类”“玩手机”和“打电话”这两个类别在标注层面有两种完全不同的做法。第一种是框住手机本身类别写 phone行为靠手机位置和人体姿态间接推断第二种是框住人类别直接写 play_phone、call。593 张这个量级我一般推荐第二种因为行为类直接对应业务语义后处理简单不用再写一套“手机框 人体框”的关联逻辑。但第二种有个硬伤打电话和玩手机在视觉上高度重叠都是手举到头部或胸前。如果你的数据里这两类样本比例悬殊模型会严重偏向多数类。先跑一遍统计import os from collections import Counter label_dir labels/train counter Counter() 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: cls line.strip().split()[0] counter[cls] 1 print(counter) # 例如 Counter({0: 412, 1: 181})这段代码统计每个类别 ID 出现的次数。YOLO 标签格式是class_id x_center y_center width height全部归一化到 0~1。如果发现某一类少于总框数的 15%要么补数据要么在训练时用类别权重补偿。参数上class_id从 0 开始别和背景类混淆——YOLO 没有独立背景类背景由负样本隐式学习。2.2 593 张的切分比例与“防泄漏”原则小数据集最怕的是同一段视频抽帧后随机切分导致训练集和验证集里出现几乎相同的画面验证指标虚高。我一般这样做先按拍摄来源不同人、不同时间段、不同设备分组再按组切分比例 8:1:1。593 张大概分成 474 训练、59 验证、60 测试。# 假设原始图像和标签平铺在一个目录先按来源前缀分组 python split_by_group.py --src images --ratio 0.8 0.1 0.1 --group-regex ^(.*?)_\d--group-regex用来从文件名提取分组键比如personA_001.jpg和personA_002.jpg归为同一组。这样切分后验证集里的画面在训练集里不会出现“孪生兄弟”。如果数据来源单一、无法分组那就退而求其次用感知哈希去重把相似度高于阈值的图像只保留一张。2.3 标签校验三个必查项标注错误在小数据集里是致命的593 张里错 20 张mAP 能掉好几个点。我固定查三样坐标越界、宽高为零、类别 ID 超范围。def validate_label(path, num_classes2): errors [] with open(path) as f: for i, line in enumerate(f): parts line.strip().split() if len(parts) ! 5: errors.append(fline {i}: 字段数不对) continue c, x, y, w, h int(parts[0]), *map(float, parts[1:]) if c num_classes: errors.append(fline {i}: 类别 {c} 越界) if not (0 x 1 and 0 y 1): errors.append(fline {i}: 中心点越界) if w 0 or h 0 or w 1 or h 1: errors.append(fline {i}: 宽高异常) return errors坐标越界通常来自标注工具导出时的坐标系不一致宽高为零多半是误触。类别 ID 越界在合并多个数据集时特别常见比如你把一个只有 phone 类的数据集和一个有 play_phone/call 的数据集混在一起ID 就冲突了。校验完把有问题的图像和标签一起移出训练集别只删标签。3. 用 YOLOv8 在 593 张图上跑通训练配置、命令与参数含义3.1 选 v8 还是 v5小数据集的预训练权重差异热词里“yolov8训练自己的数据集”出现频率很高我自己的选择也是 v8 起步。原因不是 v8 一定比 v5 准而是 v8 的默认增强策略对小数据集更友好且ultralytics这套接口把训练、验证、导出串成了一条命令。593 张这个量级我建议从yolov8n.pt或yolov8s.pt开始n 更快、s 更稳别一上来就上 m 或 l参数量大了在小数据上过拟合风险陡增。预训练权重的作用是提供通用边缘、纹理特征让模型不用从零学“什么是手机轮廓”。如果你的场景里手机都是特定型号、特定角度预训练权重的收益会打折但依然比随机初始化强。常见做法是先用 COCO 预训练权重训 50 轮观察验证集曲线再决定要不要换更大的骨干。3.2 一份能直接抄的 data.yaml 与训练命令YOLO 训练靠一个 YAML 描述数据路径和类别# data.yaml path: /home/user/phone_dataset train: images/train val: images/val test: images/test nc: 2 names: 0: play_phone 1: callpath是数据集根目录train/val/test是相对路径。nc是类别数必须和标签里的最大 class_id 1 一致。names的顺序就是 class_id 的顺序写反了模型会把打电话认成玩手机。训练命令yolo detect train \ modelyolov8s.pt \ datadata.yaml \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience30 \ augmentTrue \ cacheTrue \ projectruns/phone \ nameexp1逐项说epochs150对小数据集够用配合patience30早停验证集 30 轮不涨就停。imgsz640是默认值如果你的图像分辨率远高于此可以提到 960但显存和速度要权衡。batch16在 8G 显存上跑 yolov8s 基本安全爆显存就降到 8。lr00.01是初始学习率小数据集我有时会降到 0.005 减少震荡。lrf0.01是最终学习率因子配合余弦退火。cacheTrue把图像缓存到内存593 张完全放得下能明显加快每轮速度。3.3 训练过程中该盯哪几条曲线runs/phone/exp1下会生成results.csv和一堆曲线图。我重点看三条train/box_loss是否持续下降、val/box_loss是否在某个点后反弹、metrics/mAP50-95是否还在爬。如果 train loss 降但 val loss 早早反弹就是过拟合该加增强或减模型容量。如果两条 loss 都不降先查学习率是不是太大或者标签是不是根本没对上图像。# 快速看最后 10 轮指标 tail -n 10 runs/phone/exp1/results.csvresults.csv的列名包含epoch, train/box_loss, val/box_loss, metrics/mAP50, metrics/mAP50-95等。mAP50 到 0.8 以上、mAP50-95 到 0.5 以上在 593 张这个量级就算不错了。如果 mAP50 高但 mAP50-95 低说明框的位置不够准可以检查标注框是否贴合目标边缘。4. 小数据集训练的避坑清单从过拟合到类别混淆4.1 现象验证集 mAP 很高一上测试集就崩原因切分时没有按来源分组验证集和训练集画面高度相似模型记住了背景而不是目标。解决回到 2.2 节的分组切分或者用感知哈希去重后重新切。我踩过这个坑验证集 0.92、测试集 0.61排查半天才发现是同一段视频的相邻帧被分到了两边。4.2 现象打电话被大量误判成玩手机原因两类视觉特征重叠且训练样本里 play_phone 远多于 call模型倾向于把模糊样本判给多数类。解决先做类别平衡对 call 类做针对性扩增旋转、亮度扰动、局部裁剪再在损失里给 call 类更高权重。YOLOv8 不直接暴露类别权重参数可以通过复制 call 类样本、或在data.yaml里用过采样实现。4.3 现象训练 loss 震荡剧烈mAP 忽高忽低原因学习率偏大或 batch 太小导致梯度噪声大。解决把lr0降到 0.005batch尽量提到显存允许的最大值同时开cos_lrTrue让学习率平滑衰减。593 张图用 batch16 时一个 epoch 只有约 30 个 iteration梯度噪声本来就大学习率保守一点更稳。4.4 现象模型把“手持手机但没在玩”也判成玩手机原因标注时只框了人没有区分“手持”和“贴耳/低头看屏”的姿态差异。解决要么在标注规范里明确“玩手机”必须包含低头看屏或手指操作的动作要么引入关键点辅助判断。纯检测框很难区分“拿着”和“在用”这是行为检测的固有边界必要时上姿态估计做二次过滤。4.5 现象导出 ONNX 后推理结果和 PyTorch 不一致原因预处理不一致比如 PyTorch 推理时用了 letterbox导出后忘了同步或者归一化参数不同。解决导出时用yolo export modelbest.pt formatonnx imgsz640推理端严格按 letterbox 缩放并保持 0~1 归一化。我一般会拿同一张图分别跑 PyTorch 和 ONNX比对输出框的坐标误差在 1 像素内才算通过。5. 从 593 张到可部署模型增强策略、量化与推理验证5.1 小数据集的增强组合别开太猛YOLOv8 默认开了 mosaic、HSV 扰动、翻转等。593 张这个量级mosaic 能显著提升泛化但也会让单张图里的目标变小、变密如果原始场景里人本来就小mosaic 后可能小到看不清。我的做法是前 100 轮开 mosaic后 50 轮关掉让模型在接近真实分布的图像上收尾。关闭方式是在训练命令里加close_mosaic50表示最后 50 轮关闭。yolo detect train modelyolov8s.pt datadata.yaml epochs150 close_mosaic50 ...HSV 扰动里hsv_h0.015, hsv_s0.7, hsv_v0.4是默认值。如果场景光照稳定可以把hsv_v降到 0.2避免模型对亮度过度敏感。翻转方面fliplr0.5默认开但“打电话”这个动作左右手有语义差异吗一般没有可以保留。flipud默认关因为上下翻转不符合真实拍摄。5.2 用验证集做阈值扫描别用默认 0.25YOLO 推理默认置信度阈值 0.25、NMS IoU 0.45。这两个值在行为检测里往往不是最优。我一般拿验证集跑一遍扫 0.1 到 0.6 的置信度阈值看哪个点的 F1 最高。from ultralytics import YOLO import numpy as np model YOLO(runs/phone/exp1/weights/best.pt) results model.val(datadata.yaml, conf0.001, iou0.6) # 低阈值多召回 # 再根据 results 里的 precision-recall 曲线选 F1 最大点conf0.001是为了让验证时保留尽可能多的预测框方便后续画 PR 曲线。实际部署时用选出来的阈值比如 0.35。如果业务对误报容忍度低比如自动处罚阈值往高调如果只是提醒阈值可以低一点保召回。5.3 量化与边缘部署INT8 能省多少如果目标是手机端或边缘盒子导出 INT8 量化模型能显著降延迟。YOLOv8 支持导出 OpenVINO、TensorRT、TFLite 等格式。以 TFLite INT8 为例yolo export modelbest.pt formattflite int8True datadata.yaml imgsz640int8True需要提供校准数据datadata.yaml就是校准集来源。量化后模型大小约为 FP32 的四分之一推理速度在支持 INT8 的硬件上能快 2~3 倍。代价是 mAP 通常掉 1~3 个点593 张训出来的模型本身精度就不算高量化前先确认 FP32 的 mAP 有足够余量。我一般要求量化后 mAP50 不低于 0.75 才上线。5.4 一个具体的验证习惯拿“最难的 10 张”做回归每次改完增强、阈值或量化我都会固定拿 10 张“最难”的图跑一遍——这些图通常是遮挡严重、光照极端、两类行为模糊的样本。把它们单独放一个目录写个脚本批量推理并保存可视化结果yolo detect predict modelbest.pt sourcehard_cases/ saveTrue conf0.35结果存在runs/detect/predict下我逐张看框的位置和类别。如果这 10 张里错超过 2 张说明这次改动引入了退化回滚。这个习惯帮我避免了好几次“指标涨了但实际更差”的翻车。593 张的数据集模型容量有限任何改动都可能牵一发动全身固定难例回归是最省事的后悔药。希望帮到你。本文还有配套的精品资源点击获取
返回列表