ARTICLE DETAIL

资讯详情

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

安全帽检测实战:基于YOLO11n的训练、避坑与部署指南

安全帽检测实战:基于YOLO11n的训练、避坑与部署指南 简介安全帽检测模型yolo11n主要用于实时识别图片或视频中人员是否佩戴安全帽其训练基于YOLOv11检测架构兼顾速度与精度主要面向智能安防开发者与现场安全监管人员适合高风险环境下的视频监控集成。资源为zip压缩包共9个文件大小49.47MB包含onnx、pt、rknn、tar、bin、xml、yaml等格式其中onnx便于跨框架部署pt为PyTorch权重rknn针对Rockchip NPU优化tar为模型归档包bin/xml提供权重与网络定义yaml为模型配置。这些格式可按目标硬件选择对应版本便于在不同推理环境快速移植。目前已有364人学习下载适合用于目标检测入门实践、模型部署流程演练或安全帽功能二次开发也可基于现有权重进一步微调训练适配更多场景。最终拿到完整模型文件与多格式转换版本可减少环境适配工作量快速搭建原型系统体验从权重到中间格式的完整转换与部署链路。1. 安全帽检测模型 yolo11n 训练的模型一个能直接上工地的目标检测方案工地安全帽检测大概是目标检测里最典型的“小目标、高遮挡、强背景干扰”场景——人站在塔吊下、戴帽子的和没戴帽子的人挤在一起、逆光拍摄时帽沿几乎和背景融为一体。用 yolo11n 训练出来的安全帽检测模型就是把 Ultralytics 的 YOLO11 里参数最小的 nano 版本拿来做这个任务训练完成后得到一个十几 MB 左右的 .pt 权重文件能跑在普通 IPC 的 NVIDIA 显卡上也能压缩后放到边缘盒子和树莓派 5 上做实时视频流推理。这篇按我自己从数据准备一直走到训练、错误分析、导出的完整流程来写新手可以直接把数据集换成自己的现场图片熟手可以重点看第五节里的 BN 崩溃处理和小目标漏检调参。2. 为什么用 yolo11n 而不是 yolo11s/yolo11m安全帽场景的模型选型拆解2.1 安全帽检测的难点决定了模型选型方向安全帽检测和其他常规物体检测有个明显的差异目标不大但数量多、分布密、互相遮挡严重。一条工地视频流里远处一整排工人走过去每个人的安全帽在 640 分辨率下可能只有二三十个像素宽近处的人虽然帽子大但经常被脚手架钢管、反光背心、安全绳挡住一半。这种场景下模型既要抓得住小目标又不能在遮挡时把半个帽檐当成安全帽。这类任务最怕的往往不是模型不够强而是模型太大导致现场跑不动。视频流接入的是工地的 NVR 或者边缘盒子算力被压缩得很厉害推理帧率要保持在 15 到 25 FPS 以上才有实用价值。所以选型第一原则不是“哪个模型精度最高”而是“哪个模型在目标硬件上跑得动的前提下精度够用”。yolo11n 就是干这个用的。2.2 yolo11n 的内部结构C3k2、C2PSA 与解耦检测头YOLO11 是 YOLOv8 的后继版本nano 后缀表示网络宽度和深度都缩到最小的一套配置。yolo11n 的骨干网络沿用了 CSP 风格但把 v8 里的 C2f 模块换成了 C3k2简单理解就是卷积核大小可以在 3×3 和更小的尺度之间选择骨干提取特征时计算量降下来了。骨干后面还有一个 C2PSA 模块带空间注意力机制相当于在特征提取时加了“重点看哪里”的选择能力——这对安全帽这种背景杂乱的目标很有帮助。检测头用的是 Anchor-Free 的解耦结构分类和回归走两条独立分支每个格子直接预测目标中心点落在哪不需要像 YOLOv5 那样预设一堆锚框。损失函数上分类用 BCE Loss回归用 CIoU 加 DFL。这里不需要背公式只需要记住一件事回归分支的 DFL 会把边框预测拆成多个小值的加权组合对小目标的边缘回归比直接回归一个宽高数值更稳。安全帽这种小目标占比很高的场景选 Anchor-Free 加 DFL 的模型是有实际收益的。2.3 与 yolo11s/yolo11m 以及 yolo8n 的选型数据对比几个候选型号放在一起看参数和推理量大概在下面这个量级不需要记死重要的是找规律。模型参数规模量级推理量适合的场景yolo11n最小约两兆级低视频流、边缘盒子、树莓派、需要跑的快的场景yolo11s中等约九兆级比 nano 高约一倍本地 GPU 推理、对精度有更高要求的离线检测yolo11m较大约二十兆级高服务器端、大图离线分析、追求极限精度yolov8n比 yolo11n 略大略高于 yolo11n老项目迁移新项目直接用 yolo11 更划算同样跑到 300 个 epochnano 和 s 的 mAP 差距通常在两三个点以内但推理延迟能差出一倍甚至更多。安全帽检测要的是“在工地上跑得动”不是“在服务器上刷榜单”所以 yolo11n 是最稳的起点。如果后面发现小目标漏检严重再考虑升到 yolo11s 也不迟数据、标注、训练流程完全通用。2.4 部署端与训练端的算力预估yolo11n 训练阶段的显存开销不大。用 640 输入尺寸、batch size 32一张 8GB 显存的卡就能跑得很舒服12GB 显存可以把 batch 拉到 64 或者把 imgsz 提到 800。推理阶段更宽松CPU 上跑一张图大约几百毫秒GPU 上轻松过百帧。不过我要提醒一下训练和部署是两套环境训练可以用大卡部署要考虑的则是“目标硬件能不能跑起来、功耗多少”。我一般会先确认最终跑在什么设备上再决定要不要在训练时就加上小目标增强和更高的输入分辨率。3. 准备安全帽数据集公开 SHWD 与自采的标注转换全流程3.1 先判断数据来源公开集适合起步现场数据决定上限安全帽检测有一个常用的公开数据集叫 SHWD里面标注了两类目标戴安全帽和没戴安全帽的人头。公开集的优点是干净、类别划分明确、训练起来很快能跑出一个基线模型缺点是场景相对单一和你实际工地的光照、摄像头角度、安全帽颜色不一定匹配。我的做法是先用公开集跑通全流程拿到一个能用的基线模型然后去现场拍一段监控视频抽帧补充训练。补充的目的不是凑数量而是补“现场特有”的样本——比如傍晚逆光、雨天帽檐有水光、戴头巾再扣安全帽的人、安全帽系带没扣但是帽子戴在头上的人。对于安全帽检测来说二十张现场图片对精度的提升可能比两百张网上随便找的图片还大。3.2 类别定义安全帽检测不是“帽子检测”很多初次接触这个任务的人会把类别定义成“安全帽”和“人”两类这是一个容易埋坑的做法。因为“人”这个类别的边界太模糊半身、全身、远距离的人怎么框都不统一。正确做法是参考 SHWD 标注规范只标注人头区域用两个类别区分“戴了安全帽的人头”和“没戴安全帽的人头”类别 0helmet戴安全帽的头画框时把整个帽子加脸框进去类别 1head没戴安全帽的头画框时只框脸。有人会问为什么不直接标注“头部”一个类然后靠帽子在头部框里的面积占比来判断理论上可以但实际推理时要额外写逻辑而且面积占比阈值很难定——戴帽子和不戴帽子的头部面积可能完全一样。直接分成两类让模型自己学是最省事的方案判定逻辑也简单模型输出 head 就说明没戴帽子。3.3 从 XML 转成 YOLO txt一个完整可跑的转换脚本SHWD 原始标注是 VOC 格式也就是每张图片对应一个 XML 文件里面用bndbox记录目标的 xmin、ymin、xmax、ymax。YOLO 训练需要的是 txt 格式每行一个目标格式是class x_center y_center width height坐标都是归一化到 0~1 的浮点数。这个转换逻辑是固定的我每次做新数据集都会先跑一遍这个脚本import os import random from xml.etree import ElementTree as ET # 类别名到 id 的映射顺序不能乱和最终 yaml 里的 names 要一致 CLASS_MAP {helmet: 0, head: 1} def convert_xml_to_yolo(xml_path, output_dir): tree ET.parse(xml_path) root tree.getroot() img_width int(root.find(size/width).text) img_height int(root.find(size/height).text) lines [] for obj in root.iter(object): class_name obj.find(name).text if class_name not in CLASS_MAP: continue class_id CLASS_MAP[class_name] 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 / img_width y_center (ymin ymax) / 2.0 / img_height box_width (xmax - xmin) / img_width box_height (ymax - ymin) / img_height lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {box_width:.6f} {box_height:.6f}) image_name os.path.splitext(os.path.basename(xml_path))[0] txt_path os.path.join(output_dir, image_name .txt) with open(txt_path, w) as f: f.write(\n.join(lines))这段脚本的核心逻辑就是从 XML 里读坐标、换算成归一化中心点坐标、按类别映射表写入 txt。两个参数要特别注意一是CLASS_MAP里类别名的顺序训练配置 yaml 里的 names 列表必须和这个映射一一对应否则模型学到的类别名是错位的二是归一化用的是图片的原始宽高不是标注框所在区域的宽高这个写反会在训练日志里看到 loss 一直降不下去。3.4 划分 train/val 与检查错标的三个必做动作转换完标注之后要把图片和 txt 一起按约 8:2 比例随机划分成 train 和 val。划分时建议按“图片所在文件夹”来切不要按单张图片随机切因为同一段监控视频抽出来的帧高度相似训练集和验证集如果混了同场景的帧验证集分数会虚高。我每次训练前会强制自己做三个检查动作打开十张标注后的图片用image cv2.rectangle()画框检查看框是否明显偏移目标中心。打印每个类别的目标数量算一下 helmet:head 的比例如果超过 10:1后面要考虑类别不平衡问题。确认训练集和验证集图片没有重名文件——这个坑我踩过复制数据集时把同一批图片放了两个目录验证集和训练集重叠了百分之三十训练时 loss 曲线很好看一上现场就露馅。4. 训练 yolo11n 安全帽模型命令、日志与关键参数4.1 环境准备与安装训练环境这块不需要折腾太多。Ultralytics 的 pip 包把模型定义、训练循环、数据增强全部封装好了装好依赖就能开始pip install ultralytics pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121第一条装 ultralytics 主包第二条根据你的显卡驱动选 CUDA 版本。装完之后在 Python 里执行import torch; print(torch.cuda.is_available())如果输出 True 说明 GPU 可用。千万别在这一步跳过去我就见过有人在 CPU 环境下闷头训了两百个 epoch一个 epoch 要跑二十分钟最后才想起来看显卡。4.2 编写 helmet.yaml 数据配置YOLO 训练不需要写 Python 代码一个 yaml 文件把数据路径和类别定义清楚就行# helmet.yaml path: /home/user/datasets/safety_helmet train: images/train val: images/val nc: 2 names: 0: helmet 1: headpath是数据集根目录的绝对路径train和val是相对于根目录的图片文件夹路径。这里有个细节训练时只认图片文件同名的 txt 标注文件会被自动匹配但要保证images/train和labels/train两个目录在同一个数据根目录下目录名不能自己乱改。4.3 启动训练命令行、日志与关键参数环境就绪、数据就绪下面就是核心的训练命令行yolo detect train \ datahelmet.yaml \ modelyolo11n.pt \ epochs300 \ imgsz640 \ batch32 \ lr00.01 \ patience50 \ projectruns/detect \ namehelmet_nano_v1modelyolo11n.pt会先下载官方预训练权重再从预训练权重继续训练这叫迁移学习比从零训练收敛快得多安全帽这类目标也已经在 COCO 的基础特征上覆盖了一部分。epochs300是总轮数imgsz640是输入分辨率batch32是每轮批大小patience50表示验证集指标连续 50 个 epoch 不提升就提前停止。训练过程中终端会不断输出每个 epoch 的 loss 值和验证指标我一般只看四个数box_loss、cls_loss、dfl_loss 和 mAP50。前三个稳步下降是正常的mAP50 在训练初期会在 0.4 到 0.8 之间剧烈抖动不用慌这是正常的波动但如果训练到一半 mAP50 突然掉到 0.1那就是出问题了后面一节专门讲。4.4 训练中的参数怎么调epochs、batch、imgsz、优化器与学习率新手最容易把 yolov8 训练参数含义搞混这里把安全帽场景最常用的几个参数集中列一下参数默认值安全帽场景建议说明epochs100300安全帽数据集一般不大300 轮加早停比较稳妥imgsz640640~800远距离小目标多就开 800但显存和推理延迟都会涨batch1616~64显存不够优先降 batch不要动 imgszlr00.010.005~0.01数据集小或目标小时lr0 调低一点更稳optimizerautoauto自动选择优化器手动设 AdamW 也很稳patience10050数据量小的时候提前停止要更激进一点mosaic1.01.0马赛克增强对小目标有效但最后 10 个 epoch 建议关掉有一个经验供参考安全帽数据集如果只有几千张图epochs 设 200 到 300 之间就够了再多就有过拟合风险。imgsz 从 640 提到 800小目标的 mAP 能涨两三个点但模型推理时间可能从 8ms 涨到 15ms现场能不能接受要提前确认。4.5 断点续训与参数修正训练中途断电或崩掉是很常见的事情。yolo11n 训练过程中每 10 个 epoch 会存一个last.pt中断后直接续训yolo detect train datahelmet.yaml modelruns/detect/helmet_nano_v1/weights/last.pt resumeTrueresumeTrue会自动读取之前的训练状态包括 epoch 数、学习率、优化器状态不会从头开始。这个功能就是后悔药训练发现学习率有问题或者想加大 imgsz改动参数后直接续训就行不用推翻重来。5. 安全帽训练避坑从 BN 崩溃到小目标漏检的五个常见问题5.1 BN 崩溃梯度变 NaN 的全模型翻车现象训练跑到二三十个 epoch日志里 loss 突然变成nan或者 GPU 显存报错然后每个 epoch 的 mAP 都归零。原因BN 层批归一化层在训练过程中对 batch 的统计量计算不稳定通常因为 batch size 太小、学习率太大、或者数据里出现全黑或全白的异常图片。解决把 batch 提到 32 以上lr0 降到 0.005同时检查数据集里有没有损坏的或纯色的图片。这条我印象很深刻第一次自己调数据集的时候就因为 batch 只有 8 又开了高分辨率BN 训练震荡直接把整个模型的权重毁掉了只能从预训练权重重新开始。5.2 远距离安全帽小目标漏检现象训练时验证集 mAP 有 0.85但把摄像头架到塔吊下俯拍时远处七八米以外的工人完全检测不到。原因远距离时安全帽在画面里只有十个像素左右而模型的默认下采样倍数是 32 倍640 分辨率下最小的特征图是 20×20 格点一个 10 像素的目标在这个尺度上几乎被抹掉了。解决把imgsz提高到 800 或 960配合mosaic增强让模型看到更多不同尺度的小目标如果还不行就要考虑用 SAHI 之类的切片推理把大图切成小块分别检测再合并结果。这里提一个教训不要为了提升近处目标的框精度而把 imgsz 调小小目标安全帽是主要漏检来源。5.3 类别不平衡head 类远少于 helmet 类现象训练结束后模型的 helmet 类 mAP 很高但 head 类 mAP 很低大量不戴帽子的人头被检测成 helmet。原因现场大多数工人都戴帽子数据集中 helmet:head 的比例常年是 8:1 甚至 10:1模型为了降低 loss 会把所有情况都偏向 helmet。解决一是采集数据时刻意补充 head 类样本二是用cls_loss给 head 类加更高的损失权重三是用复制粘贴增强——把 head 类的目标贴到没有帽子的背景区域里。我在第三个方案上试过几次效果是最明显的。5.4 过拟合验证集分数高现场却漏检翻车重灾区现象val 集 mAP 0.92拿去跑一段新的现场视频误报漏报一堆。原因图片量不足或者 train 和 val 划分太随便搞成同场次模型学的是场景特征而不是安全帽特征。解决划分数据集时确保 train 和 val 来自不同时间段、不同机位训练时把patience设低一点最后对比 best.pt 和 last.pt 在真实帧上的表现如果一个在真实场景里表现很差说明 best.pt 在验证集上的优势只是运气。5.5 视觉混淆安全帽与背景物体互相干扰现象把空调外机、红色水桶、安全帽颜色的钢梁识别成安全帽或者反光衣上的黄色图案盖住了帽檐导致漏检。原因深度学习模型会从颜色和纹理上取捷径训练数据里正样本的安全帽颜色单一模型学到的其实不是“帽子形状”而是“黄色半圆”。解决把训练数据里的安全帽颜色做 HSV 增强让黄色、白色、蓝色安全帽都出现然后刻意加上一些带有“像安全帽颜色和形状的背景物体”的负样本。这类问题不在训练日志里表现只能通过在真实视频里跑出误报图、再人工收集反馈解决。6. 验证你的安全帽检测模型从 val 指标到 ONNX 导出6.1 val 指标读法训练完第一步不是急着部署而是用验证集跑一遍正式验证yolo detect val datahelmet.yaml modelruns/detect/helmet_nano_v1/weights/best.pt这里主要看 mAP50 和 mAP50-95。mAP50 表示 IoU 阈值 0.5 时的平均精度安全帽检测这个任务只要位置大致对就行所以 mAP50 的参考价值最高mAP50-95 是更严格的连续阈值平均可以用来横向对比模型好坏。一个能用的安全帽模型mAP50 一般要过 0.85。6.2 混淆矩阵与坏事例Ultralytics 训练完会在 results 目录生成confusion_matrix.png这张图值得花三分钟看仔细。重点关注两件事一是对角线上的数值是否够大特别是 head 类——如果 head 类别被大比例分到 helmet说明漏检率偏高二是背景行有没有非零值那代表误报来源。另外我会用yolo detect predict把几十张验证集图片跑一遍逐张看漏检情况这一步比任何指标都直接。6.3 导出 ONNX 与边缘部署验证满意之后就可以导出本地推理格式了yolo export modelruns/detect/helmet_nano_v1/weights/best.pt formatonnx opset12 imgsz640导出后得到一个 onnx 文件大小通常比原始 pt 还要小可以接入 OpenCV DNN、ONNX Runtime 或者 TensorRT。如果部署目标是树莓派 5推荐直接用 ONNX Runtime 跑 CPU 推理输入尺寸固定 640前处理记得做 letterbox 填充输出层做一次置信度筛选和 NMS完整跑一遍推理在树莓派上大概几十毫秒做 15 FPS 的实时检测够用。至于再往下的 TensorRT 加速建议等模型精度稳定了再做因为每次改输入尺寸都要重新导出和校准属于部署末期的事。我自己的习惯是训练阶段全程关注 val 指标和坏事例到了导出阶段才一次性把分辨率定死避免反复折腾。安全帽检测这个方向不算新但踩过的坑基本都是数据层面的——模型本身 yolo11n 足够可靠真正决定现场效果的是你喂给它的数据和调参时的耐心。希望帮到你。本文还有配套的精品资源点击获取
返回列表