资讯动态

安全帽检测实战:6000张真实场景数据集与YOLO训练避坑指南

发布时间:2026/10/18 11:53:52 来源:尧图企业网站定制
简介面向目标检测与计算机视觉开发者的YOLO安全帽识别数据集覆盖室内、室外、人群中等多种真实场景包含6000余张戴安全帽与未戴安全帽图像可用于工地安全监管、安防巡检等场景也适合作为目标检测入门与实战训练素材。资源按YOLOv5与YOLOv8格式完成标注images目录存放图像labels目录存放labelImg手动标注的txt文件另附1个yaml配置文件共2000个文件压缩包约900MB。作者在YOLOv5和YOLOv8上实测mAP0.5达0.9以上正负样本均衡类别标注清晰懂行的可直接下载使用无需额外整理格式。已有367人浏览学习。1. 为什么安全帽检测项目都卡在数据集上6000张图的真实分量做安全帽检测的人多半是带着 YOLO 跑通过公开样例可一到自家工地数据就翻车——误检一堆、小目标漏检、阴天夜晚全瞎。根本原因往往不在网络结构而在数据集质量。这套安全帽数据集包含 6000 张真实场景图片覆盖戴帽、未戴、反戴、手持、背影等常见形态标注为 YOLO 与 Pascal VOC 双格式训练集、验证集、测试集已按比例划分好。如果你正在找能直接丢进 YOLOv5 / YOLOv8 训练的目标检测数据集或者想少踩几轮标注和数据清洗的坑这套资源值得花时间完整看一遍。下面我从标注细节、目录结构、训练配置到常见翻车点逐一拆开讲。2. 数据集解剖标注格式、类别分布与文件结构怎么对齐 YOLO 训练拿到一份目标检测数据集别急着开练先花 20 分钟把它的目录结构、标注格式和类别分布摸清楚。这三样东西决定你要不要改配置、改脚本也决定训练出来的模型是不是在“有效学习”。2.1 目录结构train/valid/test 的划分逻辑这套数据集的顶层目录是我见过比较规整的做法解压之后大概是这样的helmet_dataset/ ├── images/ │ ├── train/ # 约 4800 张 │ ├── valid/ # 约 800 张 │ └── test/ # 约 400 张 ├── labels/ │ ├── train/ │ ├── valid/ │ └── test/ └── annotations/ ├── train/ # Pascal VOC 格式 XML ├── valid/ └── test/我不建议你直接把图片和标签混着放训练时 YOLO 会通过代码去索引路径图、标分离反而是最稳妥的。如果你手里是别的数据集建议先用脚本统一成这种风格再开训练。还有一点值得注意这里的 test 目录是真正留出来的而不是从 val 里随手切一部分。很多开源数据集为了省事把测试集和验证集混在一起导致模型的 mAP 虚高。规范的 test 划分意味着你可以拿它做一次“不带感情的最终评估”。2.2 标注格式txt 与 XML 的关联关系YOLO 训练用的是 labels 下的 txt 文件每张图片对应一个同名 txt文件里每一行代表一个目标框格式是class_id x_center y_center width height其中 x_center、y_center、width、height 都是相对于图片宽高的归一化值。比如一张 1920×1080 的图框左上角在 (480, 270)、宽 240、高 270那记录就写作0 0.3125 0.375 0.125 0.25因为 480/19200.25270/10800.25这里我只是举个例子。实际训练时 YOLO 会自动解析这些值不需要你自己写。而 annotations 下的 XML 是 Pascal VOC 的 bndbox 绝对像素坐标给那些想用 MMDetection、或者自己做数据增强和可视化的人用。两套标注内容一致只是坐标系表达不同。我的建议是用 YOLO 训练就用 txt做可视化检查或者迁移到别的框架再用 XML两边都留着的意义就在这里。2.3 类别设计两类还是三类别踩设计的坑这套数据集标注了两个类别类别 ID类别名含义0helmet佩戴安全帽的人头/头部区域1head未佩戴安全帽的人头/头部区域只标“头部区域”而非“全身”是有意为之的。工地场景下人员互相遮挡严重全身框往往包含别人的安全帽导致模型学到错误特征。只框头部把注意力集中在“头上有没有帽子”这件事上模型学起来更纯粹误检也更少。有一个容易被忽略的细节很多团队会设计三个类别——helmet、head、person想的是“先检测人再看是否戴帽”。但实际训练时会发现 person 类往往占据大量标注且与 helmet 的框高度重叠导致模型在 person 和 helmet 之间犹豫。这套只有两类的设计省掉了这一层纠缠推理阶段你拿到 helmet 与 head 两个框直接在业务逻辑里判断是否报警即可。2.4 用脚本清洗一遍数据再开跑无论数据集的来源有多“干净”我的习惯是先跑一版数据体检脚本。这个脚本是拿来就能用的检查三件事txt 与图片是否一一对应、标注类 ID 是否在合法范围内、框坐标是否越界或退化成线。import os from pathlib import Path def check_dataset(img_dir: str, label_dir: str, num_classes: int 2): img_files {p.stem for p in Path(img_dir).glob(*.jpg)} label_files {p.stem for p in Path(label_dir).glob(*.txt)} orphan_labels label_files - img_files orphan_imgs img_files - label_files print(f无标签的图片: {len(orphan_imgs)}无图片的标签: {len(orphan_labels)}) for label_file in Path(label_dir).glob(*.txt): with open(label_file, r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: print(f异常行: {label_file} - {line.strip()}) continue cls_id int(parts[0]) w, h float(parts[3]), float(parts[4]) if cls_id num_classes: print(f非法类别ID: {label_file} - {cls_id}) if w 0 or h 0 or w 1 or h 1: print(f框尺寸异常: {label_file}) if __name__ __main__: check_dataset(helmet_dataset/images/train, helmet_dataset/labels/train)逻辑是先用 stem 取文件名主干做集合对比把“有图无标”和“有标无图”的文件挑出来然后逐行解析 txt检查五元组合法性。这里 num_classes 默认 2如果你在别的数据集上扩展了类别记得改。常见输出有两类一是图片里确实存在没标注的目标二是早期标注工具导出时落下了空标签文件。前者你要么补标要么把这个图从训练集移除后者直接把空 txt 删掉即可。做完体检再开训练比训练完发现 loss 不收敛再回头查数据要省事得多。3. 训练流程落地从 YAML 配置到 mAP 评估的完整步骤数据准备就绪下一步就是把数据集接进 YOLO 训练流程。这里不追求复杂的调参炫技给你一套稳健的基准配置和跑通路径。3.1 自定义数据集 YAML路径坑与参数说明YOLO 训练前需要一个描述数据集的 YAML 文件放在数据集根目录下即可# helmet.yaml path: /data/helmet_dataset # 数据集根目录绝对路径 train: images/train val: images/valid test: images/test # 类别定义 nc: 2 names: 0: helmet 1: head我遇到最常见的坑是相对路径。如果你用相对路径YOLO 默认相对于当前工作目录解析一旦你在别的目录启动了训练脚本训练开始报 FileNotFoundError。所以我一般建议写绝对路径或者用一个环境变量动态拼接。这里的 nc 是 number of classes必须等于 2names 字典的 ID 顺序必须和标注 txt 里的数字对应一旦顺序写错模型训练出来会把 helmet 和 head 的语义完全互换推理时看着 loss 挺低实际全是错位识别。3.2 训练命令与核心参数batch/epoch/image size 的选择逻辑基准训练用 YOLOv8s 起步命令如下yolo train \ modelyolov8s.pt \ datahelmet.yaml \ epochs100 \ batch16 \ imgsz640 \ workers8 \ device0 \ patience15几个参数我拆开讲一下我为什么这么选batch16 是在单张主流显卡显存范围12GB 左右内比较稳妥的数值。如果你显存更大可以提到 32训练速度大约快一截mAP 通常不会有明显波动。epochs100 对 4800 张图的安全帽任务足够模型收敛如果你发现 60 轮左右验证集 mAP 已经到平台期early stopping 会通过 patience15 自动打断不需要难看地干等。imgsz640 是精度与速度的平衡点项目里如果后续要上边缘设备推荐用 640 训练、416 推理而不是直接用 416 训练后者在远距离小目标上会明显吃亏。训练过程中建议盯三个东西train/box_loss 是否平滑下降、val/box_loss 是否同步下降、val/cls_loss 是否在几十轮后仍有跳动。如果 val loss 在 20 轮后持续上升而 train loss 下降说明模型过拟合应加大数据增强或缩减 epochs。3.3 验证与导出跑测试集、生成指标、转成部署格式训练完成后先跑验证集再跑留出的测试集顺序不能反。验证集的作用是选模型测试集的作用是算“真实水平”用验证集选完模型再拿测试集评估这样的 mAP 才可信。yolo val \ modelruns/detect/train/weights/best.pt \ datahelmet.yaml \ imgsz640 \ splittestsplittest 会加载 data.yaml 里的 test 字段输出测试集 mAP50、mAP50-95 以及每个类别的精确率与召回率。对于安全帽检测项目我建议重点关注 recall——漏检一个未戴帽子的工人比误检一个戴了帽子的工人后果严重得多。如果 recall 偏低后面第 5 章会把这类问题单拎出来处理。部署环节这两条命令覆盖常见路径yolo export modelruns/detect/train/weights/best.pt formatonnx opset12 yolo export modelruns/detect/train/weights/best.pt formatengine device0第一条导出 ONNX给后面接 TensorRT 或 OpenVINO 做跨平台推理用第二条直接在显卡上构建 TensorRT engine适合上线 N 卡服务。导出后建议用 onnxruntime 或 TensorRT 对同一张测试图各跑一次对比推理结果坐标是否与 PyTorch 版本一致相差超过几个像素就要检查预处理缩放逻辑。4. 翻车避坑标注错误、类别不平衡、误检漏检的五个典型问题这部分内容算是我在安全帽这个任务上反复踩过、也帮别人排过的一线坑。每条按“现象 → 原因 → 解决”展开不少问题是数据标注层面而非模型层面排查时注意别在错误的方向上浪费时间。4.1 验证集精度奇高现场完全不行训练集和验证集泄露同帧连续图现象训练日志里 mAP50 到 0.97模型却把现场一些未戴帽人员漏成筛子。原因很多安全帽数据是从监控视频按帧截图的如果划分数据集时是“随机切分”而不是“按视频片段切分”同一段视频的连续帧会同时出现在训练集和验证集。验证集里尽是训练集里见过的画面指标自然好看但模型没有学到不同机位、不同站姿下的泛化特征。解决拿到这类数据先按视频源分组再以组为单位切分 train/valid/test。另外注意检查有没有重复图片——哪怕转了码、改了尺寸感知哈希对比也能揪出来。4.2 护栏边站几个人模型只报后面不报前面小目标与遮挡叠加现象远距离、低像素的行人头部模型倾向于漏检多个人站在一起时前面的挡住了后面的人头也容易丢框。原因一个是头部目标像素占比太小YOLO 在 640 分辨率下对这类目标的特征表达偏弱另一个是遮挡导致标注框大面积重叠训练时 NMS 把相邻的候选框压制掉了。解决这里我一般做两步。第一步是把训练尺寸从 640 提到 960头部在输入图上占的像素直接翻倍mAP50 通常有 24 个点的提升代价是推理速度降三成左右。第二步是用高分辨率大图切成滑动窗口训练比如把 1920×1080 分成四块 960×540相当于变相增加小目标样本比单纯硬调 NMS 阈值更治本。4.3 戴帽人员手持安全帽被识别成两个 head语义混淆现象现场某人安全帽提在手上模型在手上的帽子和脑袋上各出一个框而且两个框类别都判成 helmet。原因标注阶段正样本里“人手拿帽”的场景太少模型没有见过“帽子不在头顶”的形态却学过了“帽子是圆形彩色物体”这个表象于是它在手部的圆形区域上也“猜”出一顶帽子。解决数据层面把这套数据集里所有手持、拎着、夹着的安全帽图片拉出来确认标注是否正确正确标注应该只有一个 head 框如果实在缺这类场景就多找相关素材补一批。算法层面可以给推理结果做一个后处理规则如果两个检测框中心距离很近、且一个 helmet 一个 head、两者重合度很低优先保留 head 框。这个规则在工地上验证下来误伤率很低。4.4 类别不平衡head 样本太少模型“懒得”报未戴帽现象训练集的 helmet 框有 18000 多个head 框只有 4000 多个训练出来的模型对 head 的召回明显偏低。原因YOLO 默认按类别独立计算损失但样本量差距过大时模型会把有限的学习容量倾斜到样本多的类别上head 类别的优化力度不足。解决优先想到的不是修改损失函数而是先把 head 样本做好增强——对未戴帽的图片做翻转、旋转、亮度抖动、随机裁剪把有效样本量提上去。如果增强后 head 框数量仍明显偏低再考虑在损失函数里按类别频率增大 head 类别的 loss 权重。很多文档直接推荐改数据增强或损失权重但我的经验是先看绝对样本量够不够不够就补数据靠调权只能解决表面问题。4.5 加载预训练权重时报错或者训练出来类别全乱模型结构与数据 yaml 不匹配现象用 yolov5n.pt 或某个自定义训练的 pt 文件启动训练报错提示 shape mismatch或者训练过程正常但推理时类别 ID 与预期完全错位。原因预训练权重的输出层类别数是 80COCO而自定义数据集是 2 类模型最后一层卷积核数不匹配加载时自然会报错。类别错位的情况则是因为用了别人的权重而那个权重的 names 顺序和你的不同模型输出通道对应的含义根本不是你的类别定义。解决正确做法是加载预训练权重时让框架自动跳过输出层训练脚本里加 exclude 参数或者干脆从 yolov8s.pt 官方预训练开始训练官方权重输出的 80 类固定框架会自动替换成 nc2 的输出层不需要手动干预。如果是从别人那里拿的 pt 继续训练务必先跑一段推理确认类别顺序一致再决定要不要沿用。5. 进阶校准与部署技巧把阈值、难例、增强用在刀刃上模型训练到 mAP 看着不错离真正上线还差一个“校准”环节。这里分享三个我反复用的小技巧。第一步是置信度阈值校准。安全帽检测的默认置信度阈值是 0.25但这个值对不同的工地场景并不通用。做法是拿一段真实的现场视频至少 30 分钟包含不同光线、远近场景跑一遍推理统计误检和漏检在置信度区间上的分布。比如你发现漏检集中在 0.10.3 区间误检集中在 0.30.6 区间那阈值就可以往 0.45 附近抬反之如果漏检压力大就降到 0.15 左右。这个校准过程至少要做两轮第二次在接近真实工况的时间段再验证一次。第二步是难例挖掘。训练完之后用模型去跑验证集筛出那些预测错误或低置信度的图片单独放在一个 hard_examples 目录里。每周挑一部分人工复核如果这张图确实标注错了修正标注如果是真难例比如背影、逆光、戴兜帽判断是否需要补充训练数据。这一步看起来像纯人工活但它是提升工地场景鲁棒性最有效的一招很多公开模型就是靠这种迭代把现场精度磨上去的。第三步是数据增强的补抽。YOLO 默认开启了马赛克增强对目标检测普遍有效但安全帽这类小目标场景马赛克增强把目标缩得极小反而增加漏检风险。我一般会关掉后半程的 mosaic或者把 mosaic 概率调低到 0.3同时把随机旋转、缩放、亮度的幅度加大一点让小目标样本的形态更丰富。最后谈一个经验习惯每次换数据集或调参后我会固定用同一段包含清晨、正午、黄昏三个时段的视频做回归测试把 mAP 指标和这段视频的“人在框内”准确率一起记录。这样做的好处是能直观看到调参对真实场景的影响而不是只看抽象指标。这个习惯救过我很多次后来每次接手新的安全帽项目都会强制走一遍这个流程。希望上面这些拆解能帮你在训练安全帽检测模型时少走几轮弯路把时间花在真正影响落地效果的事情上。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑