ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

YOLOv7打电话检测实战:双格式数据集与训练部署全解析

YOLOv7打电话检测实战:双格式数据集与训练部署全解析 简介YOLOv7打电话行为检测项目面向计算机视觉开发者与边缘设备部署场景适合需要快速落地手持电话识别功能的工程人员及高校研究者。压缩包提供训练好的权重、完整训练代码以及配套数据集可直接加载权重进行图片/视频推理也可基于PyTorch框架继续训练优化。数据集图片涵盖多种光线、角度与距离下的手持电话姿态jpg原图与txt、xml两种标注格式相互对应既满足YOLO系列训练要求也兼容VOC格式迁移学习。资源共2000个文件包含1383张jpg图片、1321个txt标签、1077个xml标签另有训练/评估所用的py脚本、yaml配置、pt权重文件及说明文档文件类型覆盖数据、标注、模型与代码结构清晰便于按目录快速定位数据、训练脚本或权重。整包约703MB已有725人学习下载适用于手机使用监管、驾驶行为分析等场景的模型搭建与算法验证。1. 打电话检测的现实场景为什么这份 YOLOv7 权重和双格式标签数据集值得复现做监控行为识别的人都有同感YOLOv7 打电话检测听着不难真正自己跑一遍数据采集和标注能占掉一半时间。这份资源把训练好的模型和打电话数据集一起打包标签同时给 txt 和 xml 两种格式分别放在两个文件夹里。核心价值就一句话——「有没有人在打电话」这件事不需要从零打标图片、视频和摄像头流都能直接检出。它适合三类人刚接触目标检测、想用真实业务场景练手的学生做工地安全、司机行为规范这类监控应用的开发以及已经有 YOLO 基础、想换一个高质量数据集验证自己部署流程的人。接下来我按数据格式、训练参数、踩坑记录和推理部署四个方向把这份资源完整拆一遍。2. 数据集与标签结构txt/xml 双格式怎么对齐训练前先想清楚2.1 先看懂资源里的数据组织打开压缩包模型相关的文件是 common.py、loss.py、datasets.py、yolo.py、train.py、train_aux.py 这一套数据集的标签按说明分为 txt 和 xml 两种格式分别放在两个文件夹里。我拆过的目标检测资源里这种双格式处理算比较贴心的YOLO 训练时只认 txt而标注工具 LabelImg 默认保存 xml很多人第一次接触时就是死在「两种格式哪个给训练用」上。常见目录结构是下面这样你拿到资源后可以比照一下dataset/ ├── images/ │ ├── 0001.jpg │ └── 0002.jpg ├── labels_txt/ │ ├── 0001.txt │ └── 0002.txt └── labels_xml/ ├── 0001.xml └── 0002.xmlimages 放原始图片labels_txt 放 YOLO 训练真正使用的标注文件labels_xml 放 VOC 风格的 XML 标注。实际训练时一般把 labels_txt 重命名成 labels让 YOLOv7 的 datasets.py 能在图片同级的 labels 目录下找到对应 txt。不要直接改 XML 后缀当 txt 用那样一定翻车两个格式字段结构完全不同下面细说。2.2 两种标签格式的字段差异和映射关系YOLO 的 txt 每行对应一个目标一行五列含义分别是类别索引、目标中心点的 x 坐标、中心点的 y 坐标、目标的宽度、目标的高度。四个坐标值都是相对于图片宽高的归一化数值范围通常在 0 到 1 之间。打电话检测里类别一般只有一个所以类索引绝大部分是 0。VOC 风格的 xml 则完全不一样。它用object节点描述一个目标name存类别名比如 phone_call真正的坐标在bndbox里四个值 xmin、ymin、xmax、ymax 是像素绝对坐标。举个例子一张 640×480 的监控截图里手机目标框左上角是 (134, 90)右下角是 (216, 190)在 xml 里就写死这四个整数。但同样的目标按 YOLO 格式表示就要先换算成中心点再做归一化格式坐标含义是否归一化每行内容YOLO txtx_center y_center width height是class_id x_center y_center width heightVOC xmlbndbox: xmin ymin xmax ymax否name bndbox 节点换算关系是x_center (xmin xmax) / 2 / 图片宽y_center (ymin ymax) / 2 / 图片高目标宽 (xmax - xmin) / 图片宽目标高 (ymax - ymin) / 图片高。注意分母是整张图的宽高不是目标的宽高新手在这一步最容易把宽高搞反。资源里同时提供两种格式最大的价值是你可以相互校验。我拿到 txt 后会随机挑几张图把 txt 坐标画回原图看框准不准如果出现错位再用 xml 反查原始坐标就能定位是标注问题还是转换问题。这种方法比直接看数字靠谱得多毕竟打电话场景里手和手机经常半遮挡框稍微偏一点训练出来的模型就很容易把手机漏掉。这里还要强调一个「类名统一」的坑xml 里的name标签有可能是 phone、call、phone_call 好几个叫法而 txt 里的 class_id 是纯数字转换时必须通过 class_map 这个字典把所有 xml 里的类别名映射到同一个数字。否则同一个 0 类别在不同图片里指代的对象不一致训练时模型会彻底混乱表现就是 loss 一路下降但验证 mAP 始终为零。2.3 写脚本把 xml 批量转成 YOLO 训练格式虽然资源已经帮你转好了 txt但你要扩展自己的数据时这个转换脚本是绕不开的。下面这个脚本是我常用的改法用 Python 解析 xml再写到 txtimport xml.etree.ElementTree as ET import os import cv2 def xml_to_yolo(xml_folder, txt_folder, img_folder, class_map): os.makedirs(txt_folder, exist_okTrue) for xml_file in os.listdir(xml_folder): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_folder, xml_file)) root tree.getroot() # 用 xml 里的 filename 字段找原图注意可能带子路径 img_name root.find(filename).text img cv2.imread(os.path.join(img_folder, img_name)) h, w img.shape[:2] txt_name xml_file.replace(.xml, .txt) with open(os.path.join(txt_folder, txt_name), w) as f: for obj in root.iter(object): name obj.find(name).text if name not in class_map: continue box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 中心点归一化分母是原图宽高 x_center (xmin xmax) / 2.0 / w y_center (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h # 过滤反向框和零宽高训练时会让 loss 变成 NaN if bw 0 or bh 0 or x_center 0 or y_center 0: continue f.write(f{class_map[name]} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}\n) if __name__ __main__: xml_to_yolo(labels_xml, labels_txt, images, {phone_call: 0})脚本逻辑分四步先遍历 xml 文件按文件名找到对应原图读取原图宽高作为归一化分母然后解析每个object节点里的类别名和 bndbox 坐标再按公式把绝对坐标转成中心点加宽高的归一化数值最后按 YOLO 格式写入 txt。参数方面img_folder必须指向原图目录脚本要从图里读宽高路径不对会直接报错class_map是类别名到索引的映射打电话检测只有 phone_call所以对上 0 就行。如果后面要加「玩手机」「低头」这类行为类别名要按顺序补齐训练时 data 文件里的 names 顺序必须跟这个 class_map 完全一致这是目标检测里最典型的标签错位问题。跑完脚本后我建议再做一个回读校验从生成的 txt 里读框用 OpenCV 画到原图上肉眼过一遍。重点看三个位置手指遮挡电话的位置、远处小目标、两张图拼接造成的大宽高比。这些区域最容易出现坐标换算错误早发现比训练到一半再排查省事。3. 训练流程与参数train.py 和 train_aux.py 怎么选关键参数别用默认值3.1 从文件清单先确认代码基础资源包里有 common.py、loss.py、datasets.py、yolo.py、train.py、train_aux.py这套文件是 YOLOv7 训练的核心骨架。datasets.py 负责图片和标签的加载与增强common.py 里是模型基础算子像 RepConv、SPPCSPC 这些结构都在这里yolo.py 负责组装主干网络和检测头loss.py 计算各类损失train.py 和 train_aux.py 是两个不同的训练入口。yolov7.pdf 专门讲模型网络结构训练前翻一遍能帮你在调参时少走很多弯路。这里要特别提醒很多人拿到资源包只看权重和数据集不看这几个 py 文件结果在新机器上跑的时候报 No module named yolo。YOLOv7 的 Python 代码是在仓库根目录运行的train.py 和 detect.py 会直接 import 同目录的 common、yolo 这些文件所以别把权重和数据集单独拷走要带着整个目录结构一起解压。我见过不止一个人只把runs目录拷出来想直接 detect结果 import 报错又费了半天时间重新下载整个仓库。依赖方面这套代码采用 PyTorch 框架Python 文件也都是基于 PyTorch 写的。常见做法是先用 pip 安装 torch、torchvision、opencv-python、numpy、pyyaml 这些基础库再安装 requirements 里的依赖。版本上不需要追求最新PyTorch 1.7 以上的稳定版都能跑关键要保证 torch 和 torchvision 版本配套。3.2 配置数据文件类别数量、图片路径、labels 目录YOLOv7 训练前要准备一个数据配置文件常见叫 call.yaml。打电话检测只有一类最简配置是这样train: dataset/images val: dataset/images nc: 1 names: [phone_call]train 和 val 填图片目录路径注意不是填 txt 路径nc 是类别数量打电话检测就是 1names 是类别名列表顺序必须和 txt 里的 class_id 对应。如果 txt 里类别是 0那 names[0] 就是 phone_call写反了训练时 loss 不报错但验证 mAP 永远是 0。还要补充一点YOLOv7 的 datasets.py 默认按图片文件名找同名的 txt 文件并且要求 txt 路径是图片路径把 images 替换成 labels 后的结果。所以如果你把原图和标签放在同一个文件夹里会直接找不到标签。常见做法是把 labels_txt 这个文件夹重命名成 labels放到和 images 同级的目录保持这样的结构dataset/ ├── images/ │ ├── 0001.jpg │ └── 0002.jpg └── labels/ ├── 0001.txt └── 0002.txt有人会问 xml 标签放哪里xml 在这里只作为编辑和查看的中间格式训练时不参与加载。我给客户的交付规范通常是xml 保留在原始标注文件夹里备份用txt 负责给训练吃。两份并存正好互相留底万一 txt 被程序清掉了还能从 xml 重新生成算是给自己留了一颗后悔药。3.3 训练命令两个入口的分工和关键参数train.py 是标准训练入口适合大多数常规场景train_aux.py 是带辅助检测头的训练入口适合小目标偏多的场景。打电话检测里手机在监控画面中往往只有几十像素甚至更小我用下来更推荐 train_aux.py。它在主干网络里额外加辅助分支对小目标更友好代价是训练时间变长、显存占用更高。先看 train.py 的启动命令python train.py --data data/call.yaml --cfg cfg/training/yolov7.yaml --weights yolov7.pt --batch-size 16 --img 640 640 --epochs 100 --name call --device 0拆一下参数--data指向刚才创建的 call.yaml--cfg是模型结构文件打电话检测用默认的 yolov7.yaml 就行--weights是预训练权重如果不想从头训练就填官方 yolov7.pt--batch-size是每轮迭代的图片数量--img 640 640是训练分辨率两个值分别为宽和高--epochs是训练轮数--name是输出目录名训练好的权重会存到 runs/train/call/weights/ 下。关键要区分 best.pt 和 last.ptbest.pt 按验证集 mAP 最优保存last.pt 是最后一轮权重。打电话检测这种目标很小的场景最后一轮不一定是最优解经常出现验证集已经收敛、后面又震荡的情况所以后续部署优先用 best.pt。如果显存不够比如 8G 显存跑 batch-size 16 会直接崩我一般降到 8 或 4同时把--workers设为 4让数据加载不要拖慢 GPU。还有一个容易被忽略的参数是--hyp它指定超参数文件默认是 data/hyp.scratch.pth。需要调学习率时直接改这个文件里的 lr0、lrf比改训练代码更快。电话检测的训练集通常只有几百到几千张学习率改到 0.001 上下比较稳用默认的 0.01 也不是不行但收敛曲线会抖得厉害。train_aux.py 的命令基本一致python train_aux.py --data data/call.yaml --cfg cfg/training/yolov7.yaml --weights yolov7.pt --batch-size 16 --img 640 640 --epochs 100 --name call-aux注意 train_aux.py 训练出来的权重结构里带有 aux 分支但推理接口是兼容的detect.py 能直接加载不需要额外改代码。中途想续训加--resume参数并指定 runs/train/call/weights/last.pt 就能接着跑学习率和当前 epoch 都会从上次状态恢复这是 YOLOv7 自带的一个很实用的功能。4. 复现中的避坑与排查五个最容易翻车的地方每条都是血泪经验4.1 训练 Loss 变成 NaN 或者一直不降现象训练刚开始几十个 iteration终端里 loss 就打印出 nan或者 loss 一直在 8、9 附近死活不降。val 阶段出来的 mAP 全是 0。原因最常见的是标签坐标越界。txt 里的归一化坐标大于 1或者出现了负数宽高训练时损失函数里出现 log(0) 或无效框梯度直接爆掉。第二种原因是学习率设得太大尤其是用 batch-size 4 这种小 batch 时默认学习率相对过大也会 NaN。解决先把所有 txt 扫描一遍过滤掉 x_center、y_center 不在 0 到 1 之间、w 或 h 小于等于 0 的行可以用上一章的转换脚本顺手做。然后看超参数文件里 lr0 是不是 0.01如果是打电话检测这个小数据集可以降到 0.001。最后再确认类别索引没有越界nc1 时 txt 里不能出现 1、2 这类索引。这三步走完NaN 基本能消掉。4.2 验证 mAP 一直是 0但训练 loss 看起来正常现象训练正常跑完 100 个 epochloss 曲线平滑下降但每次验证时 Precision、Recall、mAP 全部为 0检测结果图上一张框都没有。原因十有八九是类别不匹配。训练数据的 txt 里类别索引是 0表示 phone_call但 call.yaml 里 names 写成了[0]或者类别顺序写错导致模型学到的东西和验证标签对不上。另一个常见原因是 xml 转 txt 时xml 里的类别名是 phone而 class_map 里写的是 phone_call实际没有转换出任何 txt但脚本没报错。解决用代码把数据集里的 txt 全部读出来统计出现过的类别索引集合确认它们从 0 开始连续分布。同时检查 call.yaml 的 names确保 names[0] 和 txt 里索引 0 对应的语义一致。再用 detect.py 拿训练集里的一张图测一下如果连训练集视频数据都检测不到说明模型学到的是背景需要回炉检查数据加载过程。4.3 train_aux.py 直接加载普通权重报错现象用 train_aux.py 训练--weights填的是 train.py 训练出来的 best.pt结果启动时报 model 权重键名不匹配或者缺少 aux head 对应的参数。原因train_aux.py 对应的模型结构带了辅助分支而 train.py 训练出的模型没有这些 aux 结构权重文件里的 key 对不上属于结构不一致不是文件损坏。解决两种方式一是让 train_aux.py 从头训练--weights 并配合官方 COCO 预训练权重让模型先学会通用特征二是直接用资源里已经训练好的权重确认它本身是普通版还是 aux 版再选择对应的训练入口。判断方法很简单加载权重后打印 model.state_dict 的 keys看里面有没有aux字样。以后要混用记得先看 README 说明别默认两个入口权重互通。4.4 显存不足batch-size 调到 4 还是崩现象启动训练后没几秒报 CUDA out of memory把 batch-size 从 16 降到 8再降到 4还是崩。原因打电话检测的数据图片如果原图分辨率很高比如 1920×1080 的监控截图datasets.py 在做增强时会先加载原图再随机缩放显存开销比 640×640 的训练分辨率大得多。另外如果开了多卡--device 0,1会把模型均匀分布到各卡只要其中一张卡显存小也会崩。解决先固定--device 0只占一块卡。再把--img从 640 640 降到 416 416对电话这种中等大小目标影响不大。batch-size 保持 8配合梯度累积把实际大 batch 的效果保住。YOLOv7 官方训练脚本里没有直接的梯度累积参数手工改的话每 4 个 step 做一次 optimizer.step 就行。还有一个很实用的小技巧是给数据中心增加独立的缓存目录避免 dataloader 反复读大图导致内存居高不下。4.5 推理时什么都检测不到置信度全黑现象模型训练完了用 best.pt 跑 detect.py出来的结果图一个框都没有或者只在角落画一个置信度 0.05 的框基本等于没用。原因一是训练集全部是「人拿着手机在打电话」的正样本一张不含目标的负样本都没有模型学成了只要手里没手机就全图无目标这其实是过拟合在打电话这个单一姿态上。二是推理时的置信度阈值太高默认 0.25打电话动作里手机被手挡住大部分目标模糊真实置信度本来就只有 0.1 到 0.2。解决在训练集里加入一些「正常走路、没有打电话」的图片作为负样本不需要打标空 txt 即可让模型学到背景多样性。推理时把--conf 0.1试一遍看能不能捞回一批目标。如果 0.1 下框出来了但杂乱再用 NMS 阈值把重复框压下去。数据增强上也可以把 mosaic 和 mixup 打开打电话检测的图片里手部遮挡严重增强能帮模型学会看局部特征。5. 部署与推理把训练好的打电话检测模型接到图片、视频和摄像头流5.1 用 detect.py 验证 best.pt 和 last.pt 的差别训练完成后推理验证我习惯用最优权重而不是最后一轮权重。命令很直接python detect.py --weights runs/train/call/weights/best.pt --source test.jpg --conf 0.4 --img-size 640--weights指定权重文件--source是输入来源--conf是置信度阈值--img-size是推理分辨率。输出结果默认写到 runs/detect/exp 下带框的图片会被保存下来。实际部署时建议分别拿 best.pt 和 last.pt 在同一个测试集上过一遍。我遇到过 best.pt 在验证集上 mAP 略高但对模糊监控帧的反感度更高last.pt 反而更稳。原因在于 best.pt 是按 mAP 挑的可能对个别难例不够鲁棒。所以部署前至少准备 100 张没见过的场景图两个权重都跑一遍肉眼对比结果再决定留哪个。detect.py 里也可以直接开--save-txt把检测框坐标落盘配合后来接业务系统时使用。它的输出格式和标签 txt 类似也是 class_id、中心点、宽高的归一化坐标只是最后多了置信度一列。5.2 source 参数的四种写法本地摄像头和 RTSP 流detect.py 的--source很灵活同一个参数按不同写法决定输入类型。这是最常用的四种写法含义示例test.jpg单张图片--source test.jpgvideos/文件夹下所有图片/视频--source videos/0本地摄像头索引--source 0rtsp://ip:554/stream1RTSP 网络流--source rtsp://192.168.1.64/stream1接本地摄像头最常见的问题是索引漂移明明插的是 0 号 USB 摄像头但系统把集成摄像头当成了 0插拔后索引会变。先跑ls /dev/video*认清楚再填对索引。接 RTSP 流时YOLOv7 的 detect.py 会逐帧解码网络延迟大或带宽不足时经常出现画面卡顿、检测结果一帧慢一帧。这个场景里不要把 source 直接填 RTSP 地址跑 detect.py更稳的做法是在本地开一个缓存管道先把 RTSP 拉到本地编码再用--source local.mp4去做检测。打电话检测这类监控业务用后一种方案部署起来不容易被网络抖动拖垮。5.3 推理加速开启 half 精度与分辨率取舍PyTorch 模型部署到实际视频流上遇到的第一件事就是帧率不够。YOLOv7 的 detect.py 里可以直接加--half 1模型和输入都会转成 FP16 精度推理显存带宽占用减半大多数 NVIDIA 显卡上能获得接近翻倍的帧率提升。python detect.py --weights runs/train/call/weights/best.pt --source 0 --conf 0.4 --half注意并不是所有卡都支持 FP16。老一点的 Tesla P100、GTX 10 系可以部分旧架构或 CPU 推理就不要开开了反而更慢。如果是 CPU 部署--img-size 320比--half实在代价是远处小目标可能漏检。分辨率的取舍上监控画面里打电话场景有两种典型情况一种是摄像头正对工位人基本在画面中央640 足够另一种是走廊、闸机这类广角画面手机只有十几个像素这时把--img-size 960提上去召回率立刻有变化。帧率会下降但推流端可以用 mingguojian 这类硬编组件配合不赘述。从这份资源的训练权重看它本身在 640 分辨率下已经收敛得不错先跑通再优化尺寸不要一开始就盲目开 1280。6. NMS 与分辨率的搭配一个让打电话小目标不再漏检的经验值打电话检测和普通物体检测最大的不同在于手机经常只有几十像素大而且贴在脸上、手上天然容易被 NMS 误杀。绝大多数人第一次部署用的都是默认配置 conf 0.25、iou 0.45、img 640。这三个默认值在通用检测上问题不大但放到打电话场景里漏检率会明显偏高。我的做法是按目标尺寸分两档调。摄像头距离人三米以上或者画面宽度超过 1280 像素时先别急着拉高分辨率而是把 NMS 的 IoU 阈值从默认 0.45 降到 0.3同时把 conf 阈值从 0.25 降到 0.15。为什么要降 IoU因为打电话动作里手和手机高度重合两个候选框的 IoU 经常轻松超过 0.4默认阈值下后产生的框会被直接抑制掉其中可能就有一个真正框住手机的高质量框。IoU 降到 0.3 后重叠区域更大才会被杀小目标保住的机会大很多。如果画面是近距离特写目标占画面比例大反而可以调回 0.45避免输出一堆重复框。分辨率的取舍也类似摄像头是 1080P 以上的监控枪机我一般用--img 960保持长边清晰如果是清晰度只有 720P 的老设备把分辨率拉到 1280 也换不来有用信息质感本来就丢不如靠数据增强弥补。这套参数我是在一次工地行为识别项目中调出来的。当时默认参数下远处三个人同时打电话只检出一个人把 conf 降到 0.15、IoU 设成 0.3 后两个漏检都回来了。从那以后我每次部署新场景都会先用 30 张困难样本快速过一遍检测结果看漏检和重复框的比例再决定要不要动这两个阈值而不是直接拿默认配置上线。希望这个习惯能帮到你。本文还有配套的精品资源点击获取
返回列表