ARTICLE DETAIL

资讯详情

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

YOLOv7打电话检测实战:数据集、权重与训练代码全解析

YOLOv7打电话检测实战:数据集、权重与训练代码全解析 简介一套面向目标检测实操的YOLOv7打电话行为检测资源包内含训练好的识别权重与配套数据集适合需要快速部署手机打电话检测能力的开发者或目标检测初学者。数据标签同时提供txt和xml两种格式分别存放于独立文件夹便于接入YOLO系列训练流程或转换成其他标注体系核心代码基于PyTorch框架包含Python训练/推理脚本及模型配置文件覆盖从数据准备到模型评估的基本链路。整个压缩包共2000个文件以jpg图像、txt/xml标注、py脚本、pt权重、yaml配置等类型为主压缩后约703.16MB其中大量jpg与txt/xml对应同一批标注数据py与yaml用于模型训练与推理pt为可直接加载的权重文件。目前已有725人学习下载对想复现打电话检测实验、理解YOLOv7训练流程或获取现成数据集的用户来说是一套完整的落地参考资料。1. YOLOv7打电话检测权重、数据集和训练代码一次拿全YOLOv7打电话检测这个资源包我拆下来第一感觉是“居然不用从零标数据”。它同时给了训练好的权重、打电话数据集和PyTorch训练代码数据标签还同时给txt和xml两套分别存在两个文件夹里想直接训还是转给别的模型用都留了余地。对刚接触目标检测的人按文档把数据集路径一换就能把训练跑起来对已经在用YOLO的熟手重点可以放在它怎么处理“手机握在手里”这个小目标场景上。这个项目真正面对的问题是监控画面里判断有没有人正在打电话。打电话行为的特点是目标小、手部姿态变化大、手机可能被遮挡单靠纯框“手机”很容易误检成玩手机或者拿东西。所以它的数据集标注得更像“手机手部”的组合区域也就是一个完整的打电话行为框而不是单独框手机。这个标注思路决定了后面模型能学到什么。我拆这套资源时最关心的是三个问题数据标签到底怎么组织、模型代码能不能直接跑、微调训练时有哪些容易翻车的地方。下面就从数据集开始一层层把这块代码包拆开看。2. 打电话数据集的标签格式txt和xml双套随包先做一次格式体检2.1 两套标签的差别带归一化的txt和带绝对坐标的xml打电话检测数据集里每个标注目标基本都是同一个类别常见命名是phone_call或calling大家拿到手后要看清楚classes顺序因为txt格式第一列的类别索引是靠排序固定的。如果训练时类的名字和txt里的索引对不上模型会把所有框都学错这种情况我见过不止一次。txt标签是YOLO标准格式每行五个数class_id x_center y_center width height其中坐标全部做了归一化除过图片宽高所以取值在0到1之间。看一眼大概是这样0 0.512383 0.487305 0.183350 0.248473xml标签是Pascal VOC格式里面是一段树状结构每张图一个xml文件文件里会写清楚图片的宽高然后用绝对像素坐标给出bndboxannotation size width1920/width height1080/height /size object namephone_call/name bndbox xmin683/xmin ymin421/ymin xmax1035/xmax ymax689/ymax /bndbox /object /annotation同一张图片既生成txt又生成xml说明作者是想兼容两套训练工具链。实际用的时候大部分人只会用到其中一套YOLOv7直接吃txt你不需要去动xml。但如果后续想转成COCO、Pascal VOC或者用LabelImg重新检查xml就有用了。2.2 写一个转换脚本把xml转成txt顺便检查标签异常我在拿到这类数据集时不会直接开训。我会先跑一个格式体检脚本把xml转txt再统计所有txt有没有越界目标。这么做是因为很多公开数据集的标签是从别的地方转过来的经常出现坐标越界、类名不一致、图片尺寸写错的问题。下面这个脚本是我常用的xml转yolo脚本可以直接存成xml2yolo.pyimport xml.etree.ElementTree as ET import os def xml_to_yolo(xml_path, out_dir, classes): tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text.strip() if name not in classes: continue cls_id classes.index(name) bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # 转归一化坐标中心点除以图片宽高 cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 越界保护避免写出负数或大于1的数值 cx max(0, min(1, cx)) cy max(0, min(1, cy)) w max(0, min(1, w)) h max(0, min(1, h)) lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) base os.path.splitext(os.path.basename(xml_path))[0] out_path os.path.join(out_dir, base .txt) with open(out_path, w, encodingutf-8) as f: f.write(\n.join(lines)) # 用法示例把xml目录下的所有标注转到yolo_dir if __name__ __main__: classes [phone_call] # 顺序必须固定 xml_dir labels_xml/train yolo_dir labels_txt/train os.makedirs(yolo_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if xml_file.endswith(.xml): xml_to_yolo(os.path.join(xml_dir, xml_file), yolo_dir, classes)这段脚本里我特意做了个坐标截断操作把归一化后的值强制限制在0到1之间。可能有人说“越界框应该报错而不是截断”但在标注不干净的数据集里越界往往是标注边界时手抖多出1个像素截断后对训练影响很小直接抛错会中断整批转换。如果你的数据集里越界特别多就需要回到原图确认是不是标注质量问题了。2.3 目录结构怎么摆datasets.py才会认YOLOv7的datasets.py默认是根据图片路径推导标签路径的规则是把路径里的/images/换成/labels/后缀改成.txt。所以我一般会把目录整理成下面这种结构dataset/ images/ train/ 0001.jpg 0002.jpg val/ 0001.jpg labels/ train/ 0001.txt 0002.txt val/ 0001.txt如果你手里的资源是txt文件夹、xml文件夹平铺的而没有images和labels这套结构需要手动分一下。典型做法是写一个整理脚本按train/val的划分文件把图片和txt对拷到上述结构中。划分文件可以是train.txt或train.py里读的路径列表YOLOv7训练时--data参数指向的yaml文件里会写train和val的图片路径所以目录结构必须和yaml对齐。还有一个小坑datasets.py里img2label_paths函数是用os.sep拼接的Windows下反斜杠和Linux下斜杠不一致。如果你在自己电脑上训练数据集路径最好用绝对路径或统一用相对路径避免路径替换失败导致所有标签都读不到。我拆这个包时第一件事就是打印一个标签路径确认它存在。3. 模型代码调用链common.py、loss.py、yolo.py各管哪一段3.1 common.py是零件库yolo.py是组装车间打开资源包会看到common.py、loss.py、yolo.py、datasets.py、train.py、train_aux.py还有一份yolov7.pdf。这套文件结构与官方YOLOv7源码基本一致common.py里放的是基础模块比如卷积、CSP、SPPCSPC、RepConv这些。你不需要记住每个类但要知道它是被yolo.py调用的零件。yolo.py是模型定义的核心入口。它会读取模型的yaml配置通过parse_model函数把common.py里的模块按配置组装起来最后生成一个Model对象。这个Model对象在训练和推理时都要用到。yolo.py里还定义了Detect层这是个关键类训练阶段它输出三个尺度的预测特征图推理阶段它会做解码把网络输出转成xyxy坐标和置信度。loss.py则对应损失函数。YOLOv7的损失分三类box损失、objectness损失、class损失。打电话检测只有单一类别通常cls_loss权重不大重点在box_loss和obj_loss上。如果训练时发现mAP迟迟上不去先想想是不是obj_loss没有收敛。3.2 loss.py和train_aux.py辅助头到底要不要开资源包里的train_aux.py是YOLOv7的aux head训练入口。官方YOLOv7和YOLOv7-E6E这类模型在训练时除了主检测头还会叠加一个辅助检测头辅助头只参与训练、不参与推理。这个机制对提升小目标召回率有帮助但代价是显存占用更高、训练时间更长。如果你的机子只有一张消费级显卡我更建议先用train.py它训练的是无aux head的标准YOLOv7显存占用小收敛也快。等你把数据集和训练流程跑通了再去试train_aux.py。很多新手一上来就选aux结果batch size只能设4loss波动大反而不如标准版稳定。判断权重要不要用train_aux.py可以打印权重里有没有aux相关参数名有就用aux入口没有老老实实用train.py。3.3 用训练好的权重做一次推理有了训练好的模型最快的验证方式是直接加载权重跑一张测试图。我用YOLOv7时最通用的一段推理代码是这样的import torch import cv2 # 本地加载YOLOv7权重path换成你的权重路径 model torch.hub.load(., custom, pathbest.pt, sourcelocal) model.eval() device cuda:0 if torch.cuda.is_available() else cpu model.to(device) img cv2.imread(test.jpg) img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 推理size是输入尺寸conf_thres控制置信度iou_thres控制NMS results model(img, size640, conf_thres0.25, iou_thres0.45) # 转成DataFrame方便筛选 det results.pandas().xyxy[0] print(det[det[name] phone_call])这段代码里有两个点要说明。第一sourcelocal表示加载当前目录的YOLOv7实现不会走联网下载前提是你的目录里已经有hubconf.py或完整工程结构。第二size参数很关键打电话区域通常小在显存充足时把size调到960或1280比单纯调低conf_thres有效得多。conf_thres和iou_thres分别是置信度阈值和NMS阈值监控场景我一般把conf设到0.3以上宁漏检不要误检。如果不想依赖torch.hub也可以直接实例化yolo.py里的Model类再手动load权重。但那种方式要求你把cfg yaml文件也补齐而这份资源包没有单独列出cfg目录所以我个人更推荐先走hub流程省事。4. 用自带权重微调把打电话模型训成你的专属版本4.1 先整理数据yaml确认类别和路径训练前要写一个数据集yaml文件YOLOv7靠它读数据路径和类别名。假设你按2.3节整理好了目录可以写成这样# phone_call.yaml train: dataset/images/train val: dataset/images/val nc: 1 names: [phone_call]这段配置里train和val分别指向图片目录nc是类别数names是类别名称列表。需要特别强调的是names的顺序必须和txt标签里的class_id一致否则整个训练都是错的。如果资源里类别名不叫phone_call你可以换成对应的名字但转换脚本里的classes列表也要同步改。启动训练前我还会做一个标签统计确认每张图的目标数量和目标尺寸分布。打电话这类行为容易出现大量小框如果小框比例太高训练时会拉低整体精度这时可以在训练参数里调高img_size或者后续部署时使用多尺度推理。4.2 启动训练train.py参数怎么给先看一份我实际用过的训练命令python train.py \ --data dataset/phone_call.yaml \ --weights weights/best.pt \ --batch-size 16 \ --img-size 640 \ --epochs 50 \ --workers 4 \ --device 0 \ --project runs/train_phone参数含义拆开看--weights指向自带的训练好权重它会作为预训练模型让模型不用从零开始--batch-size根据显存调整一般8G显存建议16以下--img-size是训练输入尺寸显存够就设640以上--workers是数据加载进程数Windows下建议设2或4设太高有时会卡在DataLoader--project是输出目录。微调打电话模型时epochs不需要太多50轮基本够。因为自带权重已经见过打电话数据继续训练是在“复习”不是“学新语言”。如果本地数据很少比如只有几千张建议把--epochs降到30同时把--cache-images打开把所有图片缓存进内存加快读取。但要注意cache-images在内存小的机器上会导致内存溢出我一般只在服务器上开。4.3 训练日志怎么看什么时候该停训练过程中主要盯tensorboard里三个指标box_loss、obj_loss和mAP0.5。正常情况是前10轮loss快速下降后面进入缓慢振荡。如果看到box_loss降得很好但obj_loss一直在高位徘徊大概率是训练图里包含大量无目标的背景区域可以适当提高置信度损失权重或在数据增强里增加裁剪缩放。另一个常见现象是mAP值在某一轮突然升高之后又回落。这不是模型坏了而是数据增强随机性造成的波动尤其是用了mosaic增强后每轮看到的样本组合差异很大。不要急着保存中间权重等训练结束后看best.pt和last.ptYOLOv7会自动保存这两份其中best.pt是按mAP挑出来的最优模型。我只取best.pt拿来部署。这类“看到某个epoch很好就以为崩了”的情况属于被训练曲线带偏的典型不用慌。如果你发现训练过程始终不收敛先回头查标签。我拆这个项目时一开始loss下降慢检查后发现txt标签文件名和图片名对不上比如图片是img_001.jpg标签却是IMG_001.txt。Linux区分大小写这个问题在Windows上倒是会被忽略但到服务器上就立刻暴露。5. 避坑打电话检测训练与部署中的五个常见问题5.1 CUDA内存不足不是只减batch就能解决现象训练或推理时抛RuntimeError: CUDA out of memory即使把batch size减到2还是报错。原因打电话检测常用大输入尺寸比如--img-size 960显存消耗随输入分辨率平方级增长。有时候不是batch的问题而是模型权重、输入图和梯度同时占据显存减batch反而没触到根因。解决先做减法再找替代。把--img-size降到640确认能跑通后再调大如果必须用大图打开梯度累积YOLOv7的训练不支持直接梯度累积参数可以用多个小batch手动循环。部署推理时更简单加上torch.no_grad()并调用model.eval()显存占用能降不少。5.2 中文路径导致图片加载失败现象代码不报错但所有图片的检测结果都是空的或训练时样本数一直为0。原因Windows下如果图片路径带中文OpenCV的cv2.imread()会返回空对象PyTorch的DataLoader也会因文件打不开而静默跳过。这个在监控视频截帧场景特别常见文件名经常叫夜间三楼_0001.jpg。解决把所有图片、标签和项目路径都改成英文路径包含中间文件夹名。这是我调试YOLO系列的默认动作路径里不要出现中文、空格和括号。类似的xml文件里的路径字段如果写了旧路径也要同步改否则转标签时读不到图片尺寸。5.3 txt和xml坐标互相转错现象用转换脚本生成的txt训练模型输出框的位置永远偏移有时框的中心点在目标外面。原因xml转txt时width和height用错字段或者在绝对值转归一化坐标时忘了先除图片尺寸。另一个常见坑是xml的xmax和ymax被当作宽高而不是右下角坐标直接减xmin就出错。解决写转换脚本后先挑三张图可视化验证。最简单的方式是把生成的txt坐标还原成矩形画到原图上肉眼确认和xml里的框一致。没有这个步骤后面训练多久都是错的。我在2.2节的脚本里已经做了中心点转换如果你从txt转xml记住乘法换除法不要用反。5.4 远距离小目标漏检现象近距离的打电话框很准一到监控画面的远端要么检测不到要么置信度只有0.1。原因打电话行为依赖手机和手的细节远距离时目标只有几十个像素默认640输入会把小目标压缩得没影了模型学不到足够特征。解决第一优先提推理分辨率部署时把size设成1280或更高第二是训练时也用高分辨率和数据增强里的大尺度随机缩放配合第三是单独筛一批远端样本加入训练集而不是靠调阈值硬扛。纯调conf_thres其实是把漏检变成了误检不是一个好办法。5.5 单帧误检成灾行为检测要过时序现象在视频帧上跑总有几帧把“抬手扶额头”识别成打电话单张图看起来确实像。原因打电话是一个持续行为正常人手机会在脸侧保持一段时间而抬手等动作是瞬时的单帧检测丢失了时间维度的信息。解决部署时不要直接输出单帧结果用一个帧间投票窗口比如连续10帧有6帧判断为打电话才输出一次报警。这样能把很多瞬时误检压掉而且代价小。具体做法在下一章我会给出一个可以直接用的投票逻辑。6. 进阶连续帧投票和mAP验证让打电话检测真正可用6.1 用验证集算一次mAP别只靠肉眼我看很多新手训练完只看检测图觉得“看着挺准”就上线了。但在打电话检测这种误检成本高的场景我更建议先算mAP。YOLOv7的val.py能直接输出mAP0.5和mAP0.5:0.95但这份资源包没列val.py所以你可以把验证集图片丢给推理脚本自己统计结果。最省力的做法是先用torch.hub跑完验证集再把预测结果和txt标签比对计算IoU。如果你只要一个快速指标可以统计“置信度大于0.5且类别正确”的框数占总标注框数的比例这个值就是召回率。打电话检测里mAP0.5大于0.85就算很好0.8左右也能用关键是部署时把conf阈值调到0.4以上别让低置信度框直接触发报警。6.2 连续帧投票一段能落到代码里的部署技巧最后给你一段我常用的视频帧投票逻辑很简单但能解决打电话检测里至少一半的误报from collections import deque window deque(maxlen10) ALARM_THRESH 6 # 10帧里至少6帧检出才报警 for frame in video_frames: det run_inference(frame) # 你的模型推理函数 detected len(det[det[name] phone_call]) 0 window.append(detected) if sum(window) ALARM_THRESH: trigger_alarm(frame) # 输出报警或截图这段代码核心是deque(maxlen10)它天然保留最近10帧的检测结果每帧只追加一个布尔值。sum(window)统计这10帧里有多少帧检测到打电话。当连续多帧出现打电话行为时才报警单帧抖动就不会触发误报。实际部署时ALARM_THRESH需要根据你的场景调如果画面里人走动频繁我会改成连续5帧命中因为误报代价不大如果是银行柜台、考场这类高风险场景我会提高到7帧并额外要求目标框移动幅度小于某个值避免路人握着手机路过也被报警。在这类行为检测项目里我交过不少学费。以前做单帧检测把“摸耳朵”报了无数次警后来用了这个时序投票误报率至少降了一半。从那以后我每次做视频行为检测都强制把单帧结果过一遍滑动窗口再谈下一步报警策略。这套资源的价值就在于此模型给你打底时序技巧给你落地希望帮到你。本文还有配套的精品资源点击获取
返回列表