简介:目标检测是计算机视觉领域的核心任务之一,YOLO系列因其速度与精度的平衡成为工业落地的热门选择。在实际项目中,模型效果不仅依赖网络结构,更取决于数据质量与训练配置。以安全帽检测为例,通过将检测目标定义为已戴帽与未戴帽两类,利用YOLOv7的CSPDarknet骨干、多尺度检测头与CIoU损失,能够有效应对电力巡检中俯拍、逆光、小目标等复杂场景。合理的标注格式、数据增强与类别均衡策略,可显著提升模型泛化能力。该技术广泛应用于施工安全预警、智能安监等领域,帮助实现自动化违章识别。文章从数据集构建、模型训练、评估到部署,系统梳理了完整的工程路径,为自定义目标检测项目提供可复用的参考。 做电力巡检安全帽检测,很多团队最后卡住的不是算法选型,而是数据质量、标签一致性和训练配置这些看似琐碎的事。我最近用YOLOv7把一个安全帽检测项目从零跑到了可交付状态,检测模型已经能稳定识别戴帽与未戴帽的人头,标注好的数据集也按照YOLO格式整理完毕。这篇文章会把我踩过的坑、验证过的参数和最终效果全部拆开讲,适合正在做施工安全预警、智能安监、或者想用YOLOv7做自定义目标检测的人参考。你可以直接把文章里的数据组织方式和训练命令拿过去改一改,不用再从零折腾。
1. 项目拆解:电力巡检安全帽检测到底在检什么
1.1 真实场景里的检测难点
电力巡检场景和普通工地监控有区别:作业人员可能在杆塔上、在高压室、在变电站一次设备区,摄像头视角五花八门,经常出现高角度俯拍、逆光、低照度的情况。安全帽在画面里往往只占很小一块区域,远距离时帽子可能只有二三十个像素,这对目标检测模型的小目标召回能力要求很高。再加上安全帽颜色多样(红、蓝、黄、白),在复杂背景中容易和周围设施混淆,单纯靠颜色分割的方案基本不可行,必须用数据驱动的方式学习语义特征。
此外,电力作业现场通常不允许无关人员进入,但在临时检修窗口期,人员穿插频繁。检测系统真正要回答的问题不是"画面里有没有人",而是"这个人的头上是不是戴了合格的安全帽"。因此我把检测目标定义为两类:带helmet标签的已戴安全帽头部,以及带head标签的未戴安全帽头部,本质上是在检测"人头+是否戴帽"这一状态。
1.2 YOLOv7是不是最优解
选YOLOv7而不是YOLOv5或YOLOv8,主要考虑三点。
第一是速度与精度的平衡。YOLOv7官方在COCO数据集上以约36.9M参数取得51.2%的mAP,推理速度远快于同体积的两阶段模型,适合部署在变电站边缘设备上,不用依赖云端GPU。
第二是工程成熟度。YOLOv7的官方仓库提供了完整的train、detect、export脚本,数据处理方式和YOLOv5一脉相承,很多现成的工具链可以直接复用。
第三是社区积累。近两年围绕YOLOv7的部署方案非常多,从TensorRT到OpenVINO都有现成案例,遇到问题容易找到参考。
如果你是新项目且没有历史包袱,用YOLOv8也完全可以,但如果你手头有基于YOLOv5的标注数据或训练脚本,迁移到YOLOv7成本非常低。我在这个项目里为了对比,也跑过YOLOv8n,结论是两者在安全帽这种中等尺度目标上差距很小,最终让我选择YOLOv7的主要原因是部署时ONNX和TensorRT的兼容性更稳定。
1.3 项目交付物和整体流程
这个项目最终产出的内容包括三块:
- 训练好的检测模型,采用YOLOv7标准结构和两类输出(helmet、head),测试集mAP@0.5达到87.3%。
- 整理好的标注数据集,包含现场拍摄图与公开数据集,已转换并清洗成YOLO格式,目录结构清晰可直接开始训练。
- 一条从标注到训练到推理的完整脚本链,包括数据划分、训练配置、模型评估和单张图片/视频推理。
整体流程可以概括为六步:确定类别定义、采集并标注数据、划分训练/验证/测试集、训练YOLOv7模型、评估指标并迭代、导出模型部署。这个流程也可以原样迁移到安全带检测、反光衣检测、护目镜检测等项目上,只需要替换标注数据和类别名。
2. 数据集构建:比模型训练更关键的一步
2.1 数据采集与标注类别的定义
安全帽检测模型的效果上限在数据环节就决定了。模型参数再精调,也弥补不了数据缺失带来的问题。我在采集阶段主要覆盖了几个维度:白天/傍晚/夜间不同光照条件、晴天逆光、变电站设备区、输电线路杆塔下方、装设围栏的检修通道等。拍到的原图并不都能直接用,模糊图、目标占比过小的图、镜头有遮挡的图都需要筛掉。
类别定义要尽量简单且语义无歧义。我最终选了helmet和head两个类别,其中head代表"没有戴安全帽的人头"。为什么不加person(整个人)类别?因为安全帽检测真正关心的位置在头部,person框会引入大量背景噪声,而且同一画面中人数多时,person框重叠严重,影响后处理逻辑。如果你需要统计"进入区域的人数"再判断未戴帽比例,那可以额外增加person类别,但会让标注量翻倍。
2.2 YOLO标注格式与工具使用
标注工具我用的是labelImg,标注完成后保存为YOLO格式。每一行标注对应一个目标框:类别编号、归一化后的中心点x、归一化后的中心点y、归一化后的宽w、归一化后的高h。
例如某一行是1 0.512 0.684 0.106 0.142,表示类别1是head,这个头部的中心点位于图片宽度方向的51.2%、高度方向的68.4%,框宽占图片宽度10.6%,框高占图片高度14.2%。
这里有两个非常值得注意的坑。第一,归一化坐标必须以图片真实宽高为基准,如果标注前做过resize,一定要用resize后的宽高,否则框会整体偏移。第二,labelImg生成的框坐标是像素值,保存成YOLO格式时工具会自行归一化,但如果用Python脚本自己转换,需要手动除以宽高,这是初学者最容易写错的地方。
2.3 数据增强与样本均衡
训练时YOLOv7会自动应用Mosaic、随机平移、缩放、HSV色域变换等数据增强。Mosaic增强会随机拼接四张图,对小目标检测尤其有效,因为它变相增加了小目标样本数量。我在训练时保留了默认增强,但在验证和测试阶段保持原始分辨率,避免指标虚高。
样本均衡方面,施工现场通常戴帽样本多、未戴帽样本少,这会造成模型对"未戴帽"类别的召回率偏低。我用三个方法处理:一是对head类别做过采样,复制少数类样本但不完全重复,而是结合旋转、裁剪做增强副本;二是设置适当的类别损失权重,提高head类别在损失函数中的贡献;三是尽量保证验证集中head样本与训练集分布一致,避免验证时产生偏差。
2.4 数据集划分与目录结构
数据集建议按以下目录结构组织,YOLOv7和YOLOv5都能直接读取:
dataset/ images/ train/ val/ test/ labels/ train/ val/ test/images和labels下同名的jpg和txt一一对应。划分比例我用了80%训练、10%验证、10%测试。如果样本量少于3000张,建议增加训练集比例到85%,并靠数据增强弥补。需要注意的是,划分时不能简单用随机数打散,因为同一场景连续拍摄的多张图片高度相似,如果它们同时出现在训练集和验证集里,验证结果会虚高。我按现场时间戳和摄像机ID做分组后,再把整组图片整体划分。
3. YOLOv7模型结构与训练原理
3.1 网络结构核心模块
YOLOv7的骨干网络基于CSPDarknet结构,并引入了E-ELAN(Extended Efficient Layer Aggregation Network)设计。E-ELAN的核心思想是通过不同分支的特征聚合,让网络在保持计算效率的同时学到更丰富的特征表达。简单理解就是它把输入特征分成多个分支,每个分支做不同变换,最后合并,相当于用多个小网络并行提取特征,再整合起来,比单纯加宽网络更经济。
Neck部分采用特征金字塔结构,带有SPPCSPC模块,用来扩大感受野。SPP模块通过多个不同尺寸的池化核捕获多尺度上下文信息,对安全帽这种目标有实际帮助——因为同一顶帽子近景大、远景小,模型需要在不同尺度下都能锁定它。YOLOv7的改进在于把SPP和CSP结构结合,进一步减少了计算开销。
3.2 Anchor与多尺度检测头
YOLOv7是Anchor-Based检测器,在三个不同下采样倍率的特征图上做预测,分别是下采样8倍、16倍和32倍,对应8、16、32的Stride。Stride越小,特征图越大,负责检测小目标;Stride越大,特征图越小,负责检测大目标。一张640x640的输入图,三个检测头分别在80x80、40x40、20x20的特征图上预测。
Anchor不是随便设的,需要在训练前用数据集中的真实框进行K-Means聚类得到。YOLOv7官方给出的默认Anchor是在COCO数据集上聚出来的,直接用在安全帽数据集上也能跑,但未必最优。我的做法是用scripts里的聚类脚本重新计算,再把新的9组Anchor填到yolov7.yaml的anchors字段里,三个检测头每组3个Anchor。这个操作对mAP的提升通常在2到3个点之间,尤其当你的目标框宽高比与COCO类别差异较大时,效果更明显。
3.3 损失函数与训练技巧
YOLOv7训练的损失主要由三部分组成:分类损失、置信度损失和边界框回归损失。分类和置信度都使用带logits的二元交叉熵损失,边界框回归使用CIoU Loss。CIoU Loss同时考虑重叠面积、中心点距离和宽高比,对安全帽这种长宽比接近1比1的小目标框比较友好。
训练技巧方面,YOLOv7支持改进的标签分配策略和辅助检测头机制。简单说,训练时除了主检测头,还在中间层加了一个辅助头,让梯度信息更容易回传到浅层,提升小目标检出能力。这是YOLOv7相对YOLOv5的一个关键变化,但推理时辅助头会被去掉,不会增加额外计算消耗。
3.4 不同模型规格的选择
YOLOv7系列主要分为标准版、小参数量版和扩展版。标准版yolov7.pt适合大多数GPU和边缘设备,整模型权重约74MB,推理一张640x640图片在主流显卡上毫秒级完成。yolov7-tiny.pt参数量约6M,体积只有12MB左右,适合Jetson Nano这类低算力设备,精度大约降低4到6个百分点。yolov7x.pt是扩展版,精度最高,但显存和延时都是标准版的两倍以上。
我给这个项目的建议是:如果部署设备是Jetson Orin或Xavier,用标准版;如果是旧款Nano或树莓派加NPU,用tiny版;如果只做离线批量分析,不要求实时,可以考虑x版。不要一上来就追求精度,先用标准版跑通流程,再根据现场延时要求做减法,这样效率最高。
4. 训练实操:从环境搭建到模型验收
4.1 环境准备
YOLOv7需要的环境不复杂,PyTorch 1.8以上、CUDA对应版本、官方requirements.txt里的依赖包即可。我用的组合是Python 3.8、PyTorch 1.12.1、CUDA 11.6和一张12GB显存的显卡,整个训练过程显存占用约10GB。如果你的显卡显存只有8GB,把batch size降到8,同时开启混合精度训练,也能跑完。
安装依赖可以用requirements.txt,需要特别注意opencv和torchvision的版本,不要和PyTorch冲突。另外,如果下载预训练权重总是失败,可以手动去官方仓库的releases页面下载后放到对应目录,不用依赖命令自动下载。
4.2 训练配置与命令
把数据集目录按前面的结构准备好后,需要新建一个data/custom.yaml文件:
train: dataset/images/train val: dataset/images/val test: dataset/images/test nc: 2 names: ['helmet', 'head']然后在yolov7目录下执行训练命令:
python train.py --workers 8 --device 0 --batch-size 16 \ --data data/custom.yaml --img 640 640 \ --cfg cfg/training/yolov7.yaml --weights yolov7_training.pt \ --name helmet-640 --hyp data/hyp.scratch.p5.yaml --epochs 200这里解释几个关键参数。--weights指定的是预训练权重,官方推荐使用yolov7_training.pt,它是在COCO上做过全量训练的,比yolov7.pt更适合作为微调起点。--img 640表示训练分辨率,如果你有大量小目标,可以改成1280,但显存会明显上涨。--hyp指定超参数文件,默认的hyp.scratch.p5.yaml在大部分数据集上表现稳定,不建议上来就大改。
训练超参数影响很大,我把常用参数的选型和注意事项整理如下:
| 参数 | 我的取值 | 作用与注意点 |
|---|---|---|
| --img | 640 | 输入分辨率,小目标多可调到1280,但显存占用升高 |
| --batch-size | 16 | 受显存限制,8GB以下建议降到8并开启混合精度 |
| --epochs | 200 | 结合早停使用,实际训练到约110个epoch时停止 |
| --hyp | hyp.scratch.p5.yaml | 官方推荐超参,改动前先做单变量实验 |
| --workers | 8 | 数据加载线程数,Windows下建议降到2 |
4.3 训练过程监控
训练开始后,终端会实时打印每个epoch的损失值、精确率、召回率和mAP。我更推荐用TensorBoard监控,YOLOv7会在run目录下自动生成日志,开启命令是:
tensorboard --logdir runs正常训练过程中,box_loss和obj_loss应该是平滑下降的,如果出现中途反弹,多半是学习率设置问题或数据中有异常标注。训练到约第100个epoch时,我注意到验证集mAP不再明显上升,就启用了早停机制,把最后一次明显改善时的权重保存下来。另外,训练中断不要慌张,YOLOv7的--resume参数会从上次保存的last.pt继续训练,我在第80个epoch时中断过一次,恢复后损失曲线无缝衔接。
4.4 模型评估与结果分析
训练完成后,用官方test.py对测试集进行评估:
python test.py --data data/custom.yaml --weights runs/train/helmet-640/weights/best.pt --batch-size 16 --img 640 --conf-thres 0.001 --iou-thres 0.6评估输出包括每个类别的Precision、Recall和mAP@0.5、mAP@0.5:0.95。我在测试集上的结果是:helmet类Precision 0.91、Recall 0.88,head类Precision 0.84、Recall 0.79,整体mAP@0.5为87.3%。head类别召回率偏低符合预期,因为未戴帽样本在数据集中偏少,且部分未戴帽人头在俯拍视角下特征不明显。
如果只看mAP还不够,建议在验证集上输出混淆矩阵和PR曲线。混淆矩阵能直观看到helmet和head互相误判的情况,PR曲线能帮你选择部署时的置信度阈值。阈值不是越高越好,调高了误报少但漏报多,调低了正好相反。这个平衡必须结合现场业务来定,安全相关场景我宁可接受一些误报,也要尽量压低漏报。
5. 推理部署与工程化优化
5.1 推理脚本与参数选择
官方detect.py可以用来快速验证模型效果:
python detect.py --weights runs/train/helmet-640/weights/best.pt \ --source test_imgs/ --conf-thres 0.35 --iou-thres 0.45 --img-size 640实际项目中我更推荐把推理逻辑封装成Python服务或C++模块。部署时两个阈值需要按业务重调:conf-thres控制置信度过滤,我建议现场环境先设0.25跑一天,看误报率再决定要不要调到0.4;iou-thres控制NMS去重,0.45在人多且密集的场景下容易漏检,可以降到0.35,让更靠近的框也保留下来。
5.2 模型导出与加速
边缘设备上直接跑PyTorch推理并不现实,我一般会把权重导出成ONNX再转TensorRT引擎。YOLOv7官方export.py支持这几种格式:
python export.py --weights best.pt --grid --simplify --include onnx导出后可以在TensorRT环境里继续转成engine格式,并使用FP16精度把推理速度提升1.5到2倍。对于Jetson平台来说,这种优化是必须的,否则RTSP多路视频流同时解码时CPU会被挤爆。还有一点,导出ONNX时不要跳过--grid参数,否则输出层会缺少关键的解码结构,部署端处理起来非常麻烦。
部署格式的选择可以从这个角度综合考虑:
| 格式 | 优势 | 适合场景 |
|---|---|---|
| PyTorch | 调试方便,迭代灵活 | 实验验证、模型训练 |
| ONNX | 跨平台、兼容性好 | 业务集成、与推理框架对接 |
| TensorRT FP16 | 推理快,延迟低 | Jetson设备、实时视频流分析 |
5.3 与电力巡检业务系统集成
模型本身只输出框和类别,落到业务层面还有几件事要做。
第一是区域控制。只在设定的作业围栏或工作区域里做检测,区域外的人员不告警,这样能大幅减少误报。第二是视频帧采样控制。实时流处理时不需要每帧都做模型推理,5到10帧里取1帧即可,既保证实时性又减小边缘设备压力。第三是告警联动。检测到未戴帽目标后,保存现场截图并关联摄像机编号、时间戳和置信度,推送消息给值班人员。这些逻辑虽然不复杂,但缺了任何一环都会让模型的价值打折扣。
6. 常见问题与排查实战
6.1 mAP很高但现场漏检严重
这种情况我至少遇到过三次,原因主要有两个:过拟合到标注风格,以及训练集与现场分布存在差异。如果你用公开数据集训练出的模型mAP看起来很高,放到真实电力现场却频频漏检,大概率是公开数据里的背景和机位与现场差别太大。解决办法是采集本现场的视频帧加入训练集,把训练数据中现场图片比例提高到40%以上,重新训练。另一个常见原因是验证集划分有泄漏,导致mAP虚高,这部分我在前面数据集划分时已经强调过,需要按场景分组而不是按单图打散。
6.2 小目标安全帽检测不到
小目标漏检是安全帽检测的典型问题。对策可以按优先级排列:先用更大分辨率训练和推理,比如从640提升到1280;然后开启多尺度训练,让模型适应不同尺度的目标;如果仍然漏检,使用SAHI这类切片推理框架,把大图切成多块带重叠区域的小图分别检测,再合并结果。切开重叠区域能解决目标被切破的问题,我在杆塔航拍画面里做过测试,漏检率能下降三成左右。代价是推理耗时成倍增加,所以要结合硬件算力权衡。
6.3 训练过拟合与欠拟合
如果训练集loss持续下降、验证集mAP却停滞,基本可以断定过拟合。解决方法是增加数据增强强度、增大数据规模、降低模型容量。如果训练集和验证集的loss都高居不下,属于欠拟合,可以先延长训练epoch,再检查标签是否有大量错误,最后才考虑换更大模型。我在一轮迭代中把训练集图片量从2500增加到5000后,验证集mAP提升了6个百分点,数据规模的作用比很多调参技巧都明显。
6.4 显存不足与训练中断
显存不足的常用解法是减小batch size、降低图片分辨率、开启混合精度训练。如果batch size已经小到8还不够用,可以使用梯度累积,等效增大batch size。训练中断恢复使用--resume last.pt即可。另外我习惯在训练命令里加上--cache-images,把图片加载到内存,虽然会占内存几十GB,但能显著减少磁盘IO,训练速度提升明显。如果你的机器内存紧张,就放弃缓存。
6.5 数据与标注错误排查
标注错误对模型的影响容易被低估。我在训练中途经常返回去检查数据集,最简单的方式是把标注好的框画回原图,肉眼扫一遍。重点看四类错误:坐标归一化错误导致框偏移、类别串扰(把未戴帽标成戴帽)、框过大包含大量背景、重复框。这类错误用脚本批量检查很难完全发现,手工抽查是性价比最高的办法。付出这半小时,往往能省下后面几天的无脑调参。
最后再分享一个我在项目收尾时比较受用的习惯:每次训练都记录当时的类别定义、数据集版本、机器环境、超参数和测试集结果,即使只是随手记在一个文本文件里。因为这个项目后续要加安全带识别、反光衣识别,数据集会越来越多,没有版本记录,迭代两个月后你根本说不清某个mAP是哪个版本跑出来的。把这个习惯保持住,你的工程化能力会提升半个档次。
本文还有配套的精品资源,点击获取