
简介YOLOv5反光衣与安全帽检测资源为经导师指导的高分毕业设计评审98分面向计算机、电子、数学等专业的毕设学生及需要项目实战的开发者可用于课程设计、期末大作业或实际工程场景。资源共1131个文件压缩包约48.12MB涵盖Python源码、训练好的pth权重、数据集样本、YOLOv5配置文件、标注信息、辅助脚本、说明文档、演示notebook及展示视频等既可直接运行也能作为二次开发基础。从文件构成看py/pyc源码负责检测流程与模型逻辑yaml/yml配置模型结构与训练参数txt/csv存放标签或数据清单png/jpg/gif/mp4等提供可视化验证素材整体目录清晰完整。目前已有154人浏览学习。使用者可快速掌握反光衣识别与安全帽佩戴检测的训练推理流程利用自带权重免去重复训练成本再按业务数据微调模型适合作为毕设或实战项目的参考起点。1. 反光衣安全帽检测YOLOv5 把毕业设计从 PPT 变成现场可跑的东西施工工地进出场审核、远程视频巡检、安全监督台账都要回答同一个问题画面里的人到底有没有穿反光衣、戴安全帽。反光衣和安全帽检测不是学术上新奇的任务它是典型好落地、也最容易被评审老师追问“你解决了什么问题”的毕业设计方向。YOLOv5 是这里成本最低的一条路权重公开、社区资料全、一张 1080P 图在普通显卡上跑到几十毫秒配合一份带标注的数据集就能走通从训练到验证的完整闭环。这篇笔记写给准备拿这类题目做毕业设计或课程项目的同学也写给想把 PPE 检测快速接入监控系统的工程师——从数据整理、模型选型到训练参数和踩坑点一条线讲完。2. 反光衣安全帽检测为什么选 YOLOv5结构、权重与选型取舍做反光衣安全帽检测可选的目标检测方案很多Faster R-CNN 精度稳但速度慢SSD 轻但小目标效果一般YOLOv8 新颖但生态相对薄一点。我一般还是优先推荐 YOLOv5原因很实际它的网络结构图在网上随便一搜就有大量解读遇到报错能查到对应解法权重文件从 s 到 x 各档齐全拿来即用而且从数据准备、训练到部署的链路最短适合一个周期只有几个月的毕业设计。2.1 从 CSPDarknet 到检测头安全帽这种小目标的特征是怎么保住的YOLOv5 的主干是 CSPDarknet中间通过 PANet 做特征融合最后在三个不同尺度的特征图上做预测。对着网络结构图数一下 stride可以得到下采样 8 倍、16 倍、32 倍的三张特征图。安全帽在监控画面里通常只有二三十个像素宽属于典型小目标所以下采样 8 倍的那层高分辨率特征图尤其关键它保留了更多位置细节。这也是为什么 YOLOv5 默认输入是 640你强行把输入压到 320 会明显丢小目标。拿到一份别人训练好的权重第一件事不是直接跑 detect而是把权重文件拆开看看里面装了什么import torch ckpt torch.load(yolov5s.pt, map_locationcpu) print(权重文件顶层键, list(ckpt.keys())) model ckpt[model].float() print(模型配置, model.yaml) print(state_dict 里参数张量数量, len(model.state_dict()))这段代码能确认三件事文件里包含的不只是网络参数还有训练时的 epoch、optimizer 状态和类别数配置model.yaml 记录了这个权重对应的网络结构state_dict 的数量决定你后面改结构时哪些层能对上。很多人迁移权重时报 KeyError就是没做这一步检查。2.2 预训练权重的三种用法直接推理、迁移学习、从头训练拿到权重后先分成三种用法第一种是直接推理把现成的 .pt 文件丢给 detect.py对图片或视频流做检测。这种方式适合中期答辩演示自己还没训练时先跑通全流程。第二种是迁移学习用 COCO 或别人在安全帽数据集上训练过的权重作为初始值在自己的数据集上继续训练。这是毕业设计最常用的做法数据量小也能收敛。第三种是完全从头训练命令行里传--weights 或直接不写 weights 参数。这个只在你有上万张图、类别分布又很偏的时候才考虑样本少的话训练会极其痛苦。实操里还有一口小坑.pt文件可能来自不同来源有的保存的是完整模型有的只保存 state_dict加载方式不一样。收到陌生权重时先用上面的 torch.load 看一下顶层键有model字段就是完整模型只有weight之类的裸参数就得分外小心。2.3 根据显卡和精度选档位s/m/l/x 怎么挑YOLOv5 官方有 s、m、l、x 四档权重参数量和推理耗时逐级上升档位参数量级适用场景YOLOv5s约 7M单卡入门CPU 勉强能跑适合演示YOLOv5m约 21M精度性价比最好的一档YOLOv5l约 46M对漏检要求严格、有独立显卡YOLOv5x约 86M追求极致 mAP离线批量处理反光衣安全帽检测在大多数工地监控场景下物体不算极小背景也不算极端复杂我用得最多的是 s 和 m 两档。s 在 GTX 1660 上跑到 640 输入基本能保证实时m 会慢一半但精度能上去一截。不要上来就选 x训练时间和显存都会让你后悔。选好档位后权重路径、模型 yaml 的 depth_multiple、width_multiple 这三处要配套混用很容易训练时报尺寸不匹配。3. 构建反光衣安全帽数据集采集策略、标注操作与格式转换模型选得再好数据不行一切白搭。这一步不仅是训练的前置工作更是毕业设计里评审老师最容易追问细节的地方。数据怎么来的、标注规不规范、类别粒度为什么这么定都要能用一两句话说清楚。3.1 数据来源与数量自己拍、借公开集、二次标注反光衣安全帽数据集的来源大体三条路自己去工地或工厂门口拍、从网上搜开放图片、复用公开的 yolov5 安全帽数据集再筛一遍。自己拍的优势是场景真实但角度单一、数量有限公开数据集能补足多样性但标签风格和你的类别定义未必一致。我的习惯是先确定目标场景。如果是工地出入口监控重点收正面和侧面的全身画面如果是塔吊或高处巡检重点收俯视角度的画面。每种场景准备 500 到 1000 张有效图类别覆盖不平衡就用更多样本去补。网上搜图时注意筛选许可尽量用注明可自由使用的图源别在论文里留下版权隐患。3.2 类别怎么定helmet、head、person 与 vest 的粒度问题反光衣安全帽检测最常见的类别设计有两种。一种是只标helmet和vest背景里出现的人不标任何东西这样最简单但训练时模型会把“没穿反光衣的人”当成背景误检率更高。另一种是我推荐的设helmet、head、person、vest四个类head表示没戴安全帽的人头person表示未穿反光衣的人体轮廓vest表示反光衣目标。这样设计的好处是给模型提供了明显的负样本它不仅要学会识别反光衣和安全帽长什么样还要学会“有人但没穿”这个状态。安全帽与头的关系天然是包含关系标注时如果同时标了head和helmet两者框几乎重叠这没问题检测器会通过类别置信度区分。标注工具我一般用 LabelImg安装和启动很简单pip install labelImg labelImg打开 LabelImg 后先把输出格式切到 YOLO这样它直接生成 txt 文件而不是 XML。操作顺序是Open Dir 选图片目录Change Save Dir 选标签输出目录按 W 开始画框画完选对应类别。画框时有个细节安全帽框要稍微贴合帽子边缘不要包进太多额头反光衣框也不要覆盖整条腿反光衣通常只覆盖躯干部分框大了会把腰腹区域的颜色也带进来。3.3 把 VOC 转成 YOLO 格式转换脚本与四个边界坑如果你用的是 LabelImg 的 PascalVOC 模式或者从别处下载的数据集是 XML 标注就需要转成 YOLO 的 txt 格式。YOLO 格式每行是类别id cx cy w h其中 cx、cy、w、h 都是相对图片宽度和高度的归一化小数。下面这个脚本处理 xmlimport os import xml.etree.ElementTree as ET classes [helmet, head, person, vest] def convert_xml_to_yolo(xml_path, out_dir): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in classes: continue cls_id classes.index(cls_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) w (xmax - xmin) / img_w h (ymax - ymin) / img_h cx (xmin xmax) / 2 / img_w cy (ymin ymax) / 2 / img_h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) out_name os.path.splitext(os.path.basename(xml_path))[0] .txt with open(os.path.join(out_dir, out_name), w) as f: f.write(\n.join(lines)) if __name__ __main__: xml_dir Annotations out_dir labels os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if xml_file.endswith(.xml): convert_xml_to_yolo(os.path.join(xml_dir, xml_file), out_dir)脚本逻辑不复杂但有四个边界坑常让人翻车。一是图片尺寸读的是 size 节点如果 XML 里没有 size 或宽高为 0所有坐标归一化都会出错。二是 xmin、xmax 有些标注工具给的是整数有些给的是浮点统一转 float 后没问题但别用 int 强转。三是类别名大小写要严格匹配Helmet和helmet是不同的。四是如果一张图里某个目标没有标注但另一张有txt 文件允许为空空 txt 训练时会自动跳过。转换完标签之后做一次数据集划分。把图片和对应 txt 一起按比例分到 train 和 val 两个目录不要只分图片文件import os import shutil import random random.seed(42) img_dir images label_dir labels train_dir data/train val_dir data/val for d in [train_dir, val_dir]: os.makedirs(f{d}/images, exist_okTrue) os.makedirs(f{d}/labels, exist_okTrue) ids [os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.endswith(.jpg)] random.shuffle(ids) val_n int(len(ids) * 0.2) for i, img_id in enumerate(ids): src_img os.path.join(img_dir, img_id .jpg) src_lbl os.path.join(label_dir, img_id .txt) dst train_dir if i len(ids) - val_n else val_dir shutil.copy(src_img, f{dst}/images/{img_id}.jpg) shutil.copy(src_lbl, f{dst}/labels/{img_id}.txt) print(ftrain: {len(ids) - val_n}, val: {val_n})先用 random.seed(42) 固定随机种子保证每次运行划分结果一致训练结果可复现。划分比例 8:2 对常规规模的数据集够用如果图片超过五千张可以适当提高验证集比例但别低于 10%。划分完检查一下 train/val 两个目录里图片和 txt 数量是否一一对应数量不一致十有八九是某些图片没有标注文件后续训练会直接报找不到标签的错。4. 用训练好的权重和数据集跑通训练配置文件、命令与参数数据准备好了环境干净了下一步就是把训练跑起来。很多同学习惯直接复制网上的训练命令执行然后在报错里挣扎半天。这里我先说一个原则用 yolov5 训练自己的数据集要改的无非三个文件——数据配置、模型配置、超参数配置命令本身反而最简单。4.1 环境配置conda 建环境与依赖安装环境配置是拦路虎第一名多数报错都出在 torch 和 CUDA 版本不匹配上。我一般用 conda 建独立环境避免把系统 Python 搞乱conda create -n yolov5 python3.8 -y conda activate yolov5 cd yolov5 pip install -r requirements.txt把代码仓库 clone 下来后先按 requirements.txt 装依赖。这里有个经验直接用 pip 默认源装 torch 可能会装成 CPU 版本训练慢到怀疑人生。建议先单独安装匹配自己显卡的 PyTorch再装其他依赖。安装完成后用一小段代码验证 GPU 是否可用import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0))输出True和你的显卡型号才算环境就绪。如果cuda.is_available()是 False多半是 torch 版本和驱动不匹配可别直接卸载重装先nvidia-smi看驱动支持的 CUDA 版本再装对应版本的 torch。4.2 改数据配置和模型配置data.yaml 与 nc 的一致性训练前先建一个 data.yaml告诉 YOLOv5 数据在哪、有几类、类别名是什么。我习惯放在数据集根目录下# data.yaml train: data/train/images val: data/val/images nc: 4 names: [helmet, head, person, vest]train 和 val 指向的是图片目录YOLOv5 会自动在同级 labels 目录里找同名 txt。nc 必须和 names 列表长度一致且和标注 txt 里的类别 id 一一对应。这里最容易出问题你从网上下载的安全帽数据集类别顺序可能是[person, helmet]直接替换 names 会导致模型训练时把 head 当成 person。模型配置在models/yolov5s.yaml打开后主要改 ncnc: 4 depth_multiple: 0.33 width_multiple: 0.50depth_multiple 和 width_multiple 决定网络缩放比例s 档就是这两个系数乘出来的。你不需要手动深究每个数字但要记住用了 yolov5s.pt 的权重就必须配合yolov5s.yaml使用权重和模型文件的缩放系数不一致训练一开始就会报尺寸不匹配。4.3 训练命令与关键参数超参数怎么调配置就绪后训练命令是标准写法python train.py \ --data data.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 100 \ --hyp hyp.scratch-low.yaml \ --cache每个参数的取舍要讲清楚--weights yolov5s.pt是迁移学习的起点。如果你拿到了别人在反光衣安全帽数据集上训练好的权重这里就填那个权重路径比如runs/train/exp3/weights/best.pt训练会在此基础上继续微调收敛速度明显更快。--img 640是训练分辨率通常和推理时一致。如果你数据集中安全帽目标特别小可以试试 768 甚至 960代价是显存占用和训练时间增加。批量大小--batch受显存限制一般 8 或 16显存不够就把--cache去掉别硬扛。--hyp hyp.scratch-low.yaml指定超参数文件里面有 lr0、momentum、weight_decay、anchor 的损失权重等。刚上手时不要动里面的值用官方默认先跑。如果想提升我会优先只改两个lr0从 0.01 调低到 0.005让迁移学习更稳cls从默认值调高一点因为反光衣和安全帽的类别数量可能不平衡。训练到一半想暂停观察时可以直接 CtrlC。YOLOv5 每个 epoch 都会保存last.pt和best.pt下次用--weights runs/train/exp/weights/last.pt --resume就能续训不用从头再来。这个后悔药在长训练里特别有用。4.4 训练日志怎么看看懂 loss 和 mAP 的变化训练时终端会打印每个 epoch 的指标长这样Epoch gpu_mem box obj cls labels img_size 1/100 3.2G 0.09 0.04 0.012 30 640box loss 表示预测框与真实框的位置误差obj loss 是目标置信度误差cls loss 是分类误差。正常情况下三者随 epoch 缓慢下降到后期趋于平缓。如果 box loss 在前几个 epoch 就降到很低而 obj 一直高怀疑正负样本不平衡如果三个 loss 都在降但 mAP 不涨很可能是类别定义有问题或者标注噪声大。每轮结束还会输出验证集的 mAP。这里记住一个判断标准mAP0.5 到 80% 以上算合格90% 以上说明数据集比较简单或者模型已经学好。毕业设计答辩时老师大概率会在意 mAP0.5:0.95 这个更严格的值能到 60% 以上就不错。训练结束后模型在runs/train/exp/weights/best.pt这是按验证集 mAP 挑出来最好的权重后续所有演示和部署都用它。5. 反光衣安全帽训练常见避坑现象、原因与解决办法训练一个检测模型的过程里不可能不遇到异常。下面五个问题是我在反光衣安全帽项目里见过最多、也最典型的按“现象、原因、解决”的路径写清楚遇到时直接对照处理。5.1 现象一loss 下降几轮后突然变 NaN 或剧烈震荡现象训练到第 5 到 20 轮loss 从正常值直接跳到 nan或者在小数点后两位之间来回抖验证集的 mAP 纹丝不动。原因最常见的是学习率太大导致梯度更新步子过大跨过了最优区域其次是标签中存在类别 id 超出 nc 范围或坐标值超出 [0,1] 的脏数据模型无法计算有效梯度还有就是训练数据太少模型已经过拟合到开始“记住”噪声。解决先查标签文件写个小脚本检查 txt 里有没有大于 1 的坐标或者超过 nc 的类别值。标签没问题就把 hyp 文件里的 lr0 调低到 0.001动量保持 0.937 不变重跑。如果还崩用--weights 从头训一次排除迁移权重的问题。按这个顺序排查能覆盖九成情况。5.2 现象二预测框整体偏移类别对但位置偏现象检测结果里安全帽框贴着头顶上方一大截或者反光衣框只框住一半身体但分类准确。原因基本可以确定是数据预处理阶段坐标出了问题。最常见的是 XML 转换脚本里除以了错误尺寸比如原图是 1920x1080但脚本用了缩略图的宽高去归一化另一种情况是训练和推理时输入尺寸不一致比如训练用 640 推理用 320模型预测的框按比例缩放后自然对不上。解决先随机抽 10 张训练图把标注框画出来看一眼import cv2 import numpy as np img cv2.imread(data/train/images/001.jpg) h, w img.shape[:2] with open(data/train/labels/001.txt) as f: for line in f: cls_id, cx, cy, bw, bh map(float, line.split()) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(check.jpg, img)框的位置画出来对不对一目了然。如果训练图里画着没问题那就是推理时尺寸不一致保证--img参数训练推理一致就行。5.3 现象三加载权重报错KeyError 或不匹配现象运行 train.py 或 detect.py 时终端报类似KeyError: model.0.conv.weight或者size mismatch for model.0.conv.weight。原因权重文件和当前模型配置不匹配。你拿的是 YOLOv5s 的权重但当前 modles/yolov5m.yaml 是 m 配置或者权重是用旧版本训练保存的网络层的命名规则在新版本里变了。解决把--weights对应的 yaml 和 models 目录里的结构对上。动手前先用第 2 章的 torch.load 检查权重的 state_dict 层名再对比当前模型 yaml 的层结构。我在实际项目里见过最隐蔽的情况是接收了同学发来的最佳权重对方用 s 结构训练自己却用 m 结构加载报错看不出是版本问题最后是把 state_dict 打印出来逐层对比才找到原因。最稳妥的办法是权重文件放好之后在模型 yaml 所在目录一起打包不要只传 .pt。5.4 现象四安全帽和反光衣互相误检、类别混淆严重现象训练完跑验证集安全帽经常被识别成反光衣反光衣被识别成普通工作服混淆矩阵里非对角线元素占比高。原因两类物体的外观在特定角度下确实像比如黄色反光衣和黄色安全帽在大太阳底下颜色相近但更常见的原因是标注不一致——同一个人戴黄安全帽穿黄反光衣前 100 张图安全帽框和反光衣框分得很清楚后面 100 张图新手标得随意框大了互相包含训练时模型学到的是混乱的边界。解决重新检查标注质量类别定义写在标注规范文档里让参与标注的每个人遵守同一条规则安全帽框贴近帽沿反光衣框从肩部到衣服下摆。如果人工核对成本太高训练后用混淆矩阵反查把误检严重的图片挑出来重新标注修正。这类问题靠调超参数救不回来数据质量是唯一解。5.5 现象五显存不足batch 只能设 2 还爆显存现象执行训练命令后报CUDA out of memory把 batch 降到 2 依然报错。原因一般是输入分辨率设置太高或者开启了--cache把数据一次性载入显存缓存。另一个隐蔽原因是开了一堆其他程序占用显存比如浏览器视频播放。解决训练前用nvidia-smi清点显卡占用把无关进程关掉。训练时先确认分辨率--img 640是常规选择别为了“看得更清楚”一下子提到 1280显存占用是平方级增长的。batch 可以调低但 batch 太低会导致 BN 层统计量不稳定。我的底线是 batch 不小于 4低于 4 就用梯度累积YOLOv5 的--batch 8配合--nbs 64nbs 是名义批量大小实际一次只算 8但梯度累积到 64 张图再更新一次效果接近大 batch 训练。6. 最后一步落地验证用 mAP 说话用阈值调出可用的检测结果模型训练完别急着打包毕业设计文档先用验证集做一次正经体检。运行验证命令python val.py \ --data data.yaml \ --weights runs/train/exp/weights/best.pt \ --img 640 \ --conf-thres 0.25 \ --iou-thres 0.45输出的 mAP0.5 和 mAP0.5:0.95 是给答辩老师看的硬指标。前者是标准 IOU 0.5 下的平均精度后者是 0.5 到 0.95 每隔 0.05 取一次的平均要求更严格。反光衣安全帽检测是安全性相关任务我通常把 mAP0.5 目标定在 85% 以上优先保漏检率而不是误检率。体检合格后真正部署到摄像头或视频流时置信度阈值直接影响可用性。检测命令里的--conf-thres默认是 0.25这个值在实际工地监控里偏宽松容易把树影、栏杆误报成人。但调太高又会漏掉角度刁钻的安全帽。我的习惯是先跑一遍当天录制的几十张现场画面统计误报和漏报比例阈值先设 0.35如果误报还多就往上加到 0.45如果漏检明显就降到 0.3。每次改动后重新跑一轮历史视频确认两类错误在你场景里的平衡点。另一个实战技巧是固定随机种子。训练前在命令行加--seed 42否则每次训练的初始权重和数据增强顺序不同结果会有轻微波动写进论文里的指标就没法复现。我用这个参数训练了两个版本发现同数据集同参数下 mAP 浮动在 1% 以内但论文里能给出稳定可复现的数字评审印象会好很多。这套从数据整理到验证调优的流程我做过不止一次反光衣安全帽项目每次都把数据检查放最前面权重和模型的配套关系核对清楚再谈训练参数。磨刀不误砍柴工别一上来就拿命令猛跑。希望这篇笔记能帮你把这几个关键环节少走点弯路。本文还有配套的精品资源点击获取