这周刚把一个拖了两周的工地安全巡检模型迭代交付掉,就是标题里这个“工人个人防护装备佩戴检测与违规识别”项目。模型骨架用的是 YOLO11,但并不是原版直接拿来训练,而是把主干里的 C3k2 模块和最近很热的 MambaOut 思路做了融合,形成了一套专门为安全帽、反光背心、手套这类小目标装备定制的检测方案。如果你也在做类似的工业视觉落地项目,或者正打算用 YOLO11 做安全帽检测但被小目标、遮挡、夜间低照度这些场景折磨,这篇应该对你有用。
这个项目的核心目标只有一个:在施工现场的视频流里,实时识别出工人有没有戴安全帽、穿反光衣、戴手套,一旦违规就立即抓拍告警。听起来很常规,但真正做到“能稳定上线”没那么简单。我从数据标注、模型改造、训练调参到边缘部署踩了不少坑,下面把整个过程里的关键决策和实操细节一条条拆开讲。
1. 需求拆解:PPE检测到底在解决什么问题
1.1 工地安监的痛点和现状
很多工地实际上已经装了摄像头,但大部分还停留在“录下来、出事后翻监控”的层面。真正要做到主动预警,靠人盯屏幕根本不现实,一个监控室几十路画面根本看不过来。这时候就需要算法自动识别违规行为,在事故发生之前发出提醒。
个人防护装备(PPE,Personal Protective Equipment)检测就是其中最基础、也最刚需的一环。安全帽、反光背心、防护手套、防护面罩,这些东西佩戴与否直接关系到工人生命安全。但施工现场环境极其复杂,有强光、逆光、扬尘、雨天、夜间红外补光,还有工人走动、聚集、遮挡,这些都会让检测算法的性能断崖式下跌。
1.2 传统视觉方案为什么搞不定
在深度学习检测普及之前,很多团队尝试过传统图像处理手段,比如用颜色分割识别反光背心、用轮廓匹配检测安全帽。这类方案在固定机位、固定光照的实验室场景里表现尚可,一旦换到真实工地就不行了。安全帽有红黄蓝白各种颜色,反光背心有荧光黄和荧光橙,阳光一照颜色就偏了,阈值怎么调都压不住误报。
后来开始用通用目标检测模型,比如早期的 YOLOv3、Faster R-CNN。这类模型比传统方法强很多,但在小目标、密集遮挡场景下依然力不从心。安全帽在1080P画面里往往只有二三十个像素大小,普通检测头很难提取到有效的语义特征。这也是我们在选型时决定不上原版模型、要做结构改进的根本原因。
1.3 为什么选择“检测 + 业务规则”的路线
这里有一个方案分叉点:一种做法是直接训练“违规检测”模型,把“未戴安全帽的人”当做一个类别输出;另一种是先用模型检测出人和安全帽,再通过逻辑判断是否违规。我最终选了后者。
直接输出违规类别的问题在于:训练数据很难穷尽所有违规形态。帽子拿在手里算不算戴?帽子歪了算不算规范?反光背心敞开拉链算什么?这类边界情况如果交给模型自己学,很容易学到背景特征而不是语义特征。拆成“人 + 安全帽 + 反光衣”的独立检测,再用规则层去组合判断,逻辑清晰、可解释性强,也方便调整判定标准。比如某段时间安全帽查得严,只要把“帽子与头部的匹配阈值”调高一点就行,完全不需要重新训练模型。
2. 模型选型与结构改造:YOLO11-C3k2-MambaOut
2.1 为什么选 YOLO11 而不是 YOLOv5、YOLOv8
YOLO 系列发展到现在,YOLOv5 和 YOLOv8 依然有很多人在用,但我在对比之后还是选定了 YOLO11 作为底座。原因有三点。
第一,YOLO11 在 COCO 数据集上的精度和速度均衡性更好,尤其是小目标检测能力比前代有明显提升,这跟 PPE 检测的场景高度吻合。第二,YOLO11 的模型结构更加模块化,C3k2、C2PSA 这些模块可以灵活替换,适合做二次改造。第三,官方开源仓库对导出部署的支持很完善,训练完直接转 ONNX、TensorRT 都很顺畅,这对工业项目非常重要。
注意:这里说的能力提升不是玄学,而是结构演进的积累。YOLO11 在特征融合和检测头设计上做了不少微调,尤其是对低层语义信息的保留更充分,实测下来同分辨率下小目标召回率确实更高。
2.2 C3k2 模块到底改了什么
C3k2 是 YOLO11 的基础模块之一,设计上延续了 CSPNet 的思路。它把输入特征图沿着通道维度分成两个分支,一个分支做比较重的卷积变换,另一个分支保持原样,最后再把两条分支拼接起来。这样做的目的是让梯度在反向传播时有一条“高速旁路”,训练更稳定,同时控制了计算量。
关键改进在于,C3k2 里的 Bottleneck 采用了更精简的结构,把原来一些不必要的 1×1 卷积合并掉,在同等参数量的前提下提升了特征表达效率。这个设计对部署非常友好,因为工地现场的算力设备往往不强,参数量和 GFLOPs 需要精打细算。
在具体实现中,C3k2 通常在骨干网络的浅层和深层都要使用,浅层负责提取纹理、边缘等初级特征,深层负责聚合语义信息。对于安全帽这种既需要颜色纹理、又需要上下文语义来判断“是戴在头上还是拿在手里”的目标,这种多尺度特征组合能力就很重要了。
2.3 MambaOut 模块的融入思路
MambaOut 这个名字来自视觉架构领域最近对状态空间模型的一轮探索。它本身不是一个大模型,而是一种模块设计思路:通过多分支、多尺度的特征变换,让模型具备更强的长距离依赖建模能力。把它融合进 C3k2,实际上是希望在不显著增加推理延迟的前提下,提升模型对全局上下文的理解力。
我在改造时采用的方案是:在 C3k2 的 Bottleneck 分支末端插入一个轻量化的 MambaOut 块,这个块包含了一个多分支卷积结构和一个通道注意力门控,让特征图在经过局部卷积之后还能做一次全局信息交互。
用生活化的方式理解:普通卷积像是一个只看自己周围一个小区域的工人,MambaOut 则像是让工人在干活的同时能抬头看一眼整个工地,知道哪里有异常情况。融合之后,模型在判断“远处那个人是不是戴了安全帽”的时候,不再只依赖一小块模糊像素,而是能结合周围的人群分布、头部姿态等信息做出更稳定的判断。
2.4 参数量与推理速度的平衡
这里要提醒一句:结构改造不是越复杂越好。我最早试过把 MambaOut 块塞进每一个 C3k2 里,结果参数量暴涨,边缘设备上推理帧率直接掉了一半。后来又反复调,最终只在 P3、P4 两个尺度使用融合模块,既覆盖了小目标的特征增强需求,又控制了整体算力消耗。
以 YOLO11n 为基准做参考:原版大概 2.6M 左右参数量,改造之后涨到 3.4M,GFLOPs 从 6.5 涨到 8.2。在 Jetson Orin Nano 上 FP16 推理,单路 1080P 视频流能做到 30 FPS 左右,完全满足实时监控需求。如果算力更紧张的话,可以只保留 P3 层的融合,效果依然比原版好,速度几乎不掉。
3. 数据集构建与标注实操
3.1 数据来源与场景覆盖
PPE 检测模型的效果上限,很大程度由数据决定。公开的安全帽检测数据集虽然能用来做预训练,但真实工地场景千差万别,靠公开数据直接上线的结果就是泛化能力不足。我在这个项目里采用了“公开数据预训练 + 自采数据精调”的组合方案,实测效果比只用一个数据源要好得多。
自采数据方面,重点是覆盖不同时间段:白天的强光、傍晚的逆光、夜间的红外补光;不同天气:晴天、阴天、雨雾;不同镜头视角:高处俯视、平视、低机位仰视。尤其是俯视视角,这是工地监控最常见的角度,但很多公开数据集里几乎没有,这个缺口只能靠自采补。
另一个容易忽视的点是工人形态的多样性。安全帽不仅要采集“戴在头上”的样本,还要采集“拿在手里”“挂在腰间”“放在旁边”的负样本。因为违规判定逻辑里需要区分这些状态,如果模型没见过这些形态,推理时就会把拿了帽子的人误判成“已佩戴”。
3.2 标签体系设计:分而治之的组合逻辑
最终我采用的标签体系分为三类:
- person:人体目标,作为违规判定锚点。
- helmet:安全帽目标,只负责检测到帽子,不负责判断是否戴在头上。
- vest:反光背心目标,同样只负责检测。
判断是否违规的逻辑放在后处理层:如果检测到 person,但在对应头部区域没有检测到 helmet,则认为“未佩戴安全帽”。如果检测到 helmet,但和 person 框的 IoU 低于阈值(比如 0.3)或帽子中心点不在头部区域内,则认为是“未规范佩戴”。
这种拆分方式最大的好处是标签互斥性低、标注歧义小。如果直接标“helmet_on”和“helmet_off”,标注员在“帽子歪了算不算 on”这种问题上很容易产生分歧,数据噪声会直接传导给模型。拆成独立目标后,标注就变成很机械的判断:框出人头,框出帽子,是否匹配交给规则。
3.3 标注规范与质量校验
标注规范上,我定了几个强制要求。
- 安全帽的框要紧贴帽体外边缘,不能框到帽子下方的头发和脸。
- 反光背心的框应包含背心覆盖的躯干区域,但不能因为手臂摆动而扩大到整个身体。
- 当人处于严重遮挡状态(比如只有半边身体露出)时,只要可见区域大于 30%,依然标注,方便模型学习遮挡场景的鲁棒性。
- 完全看不清的小目标(比如 30 米外一团模糊的影子)不标,这类样本标进去只会变成噪声。
标注完成后还要做二次质量校验,我一般会抽检 20% 的标注框,计算标注框与模型初步预测框的 IoU 分布,如果发现某个标注员提交的框 IoU 明显低于平均水平,就退回重标。这一步看着繁琐,但能省掉后面大量调参时间。
3.4 数据增强策略
数据增强是提升泛化能力性价比最高的手段。除了常规的 HSV 扰动、随机翻转、缩放以外,我还专门针对工地场景做了三个增强策略。
- 模拟雨天:在训练样本上叠加半透明的随机雨线纹理,让模型不至于一遇到玻璃上的雨痕就失灵。
- 模拟夜间红外:把 RGB 图转成灰度后再叠加蓝色单通道伪彩,模仿红外摄像机画面。
- 遮挡增强:随机用黑色矩形块遮住人体或安全帽的部分区域,逼迫模型学会用残缺信息进行判断。
注意:Mosaic 增强在这个项目里需要谨慎使用。它把四张图拼接成一张,小目标会被进一步缩小,有时直接缩没了。我的做法是训练前 150 轮开启 Mosaic,最后 30 轮关闭,让模型在正常尺度上做精调,实测 mAP 能提升 1-2 个点。
4. 训练细节与调参记录
4.1 训练环境与超参数配置
训练环境用的是单张消费级显卡,显存 24GB 的配置。数据规模大概是 1.8 万张图像,其中自采数据 1.2 万张,公开数据筛选了 6000 张。具体超参数如下:
- 输入分辨率:训练 640,测试 1280。分辨率对 PPE 小目标检测影响极其显著,640 训练保证模型收敛稳定,1280 测试用于提升小目标召回。
- batch size:16。
- 优化器:SGD,momentum 0.937,weight decay 0.0005。
- 学习率:初始 0.01,采用 one-cycle 余弦退火策略。
- warmup:前 3 个 epoch 线性预热。
- epoch:300。
- EMA(指数滑动平均):开启,decay 设置为 0.9999。
- 损失函数:CIoU 用于定位,BCE 用于分类,DFL 用于分布预测。
为什么不用 AdamW?我试过,收敛确实快,但后期精度不如 SGD 微调来得干净,尤其在这种样本量不算很大的任务上,SGD 配合适当的 weight decay 更不容易过拟合。
4.2 训练策略与曲线观察
整个训练过程分三个阶段比较有效。
第一阶段用 COCO 预训练权重热启动,冻结骨干层,只训练检测头,学习率设为常规值的 1/10,跑 50 个 epoch。这一步是让检测头先适应 PPE 数据的分布,避免刚开始骨干就被破坏。
第二阶段解冻全部层,正常学习率训练 200 个 epoch。这个阶段重点观察两个指标:loss 是否持续下降、验证集 mAP 是否同步上升。
第三阶段是精调期,把输入分辨率从 640 提升到 1280,关闭 Mosaic,学习率降到原来的 1/10,训练 50 轮。这一步能让模型适应高分辨率输入的分布,有效提升小目标检测精度。
实际训练过程中最操心的不是 loss 不降,而是 loss 降了但 mAP 不动。遇到这种情况,我一般会先看学习率是否太高、分类分支是否比定位分支更难收敛。PPE 检测本质上是类别极少的目标检测任务(就 3 个类),分类压力不大,问题多半出在定位精度上,此时我会调高 box 损失的权重来平衡。
4.3 模型评估:指标怎么看
对于这个项目,单看 mAP@0.5 是不够的。我还会重点看小目标类别(面积小于 32×32 像素)的召回率,以及不同天气、时段切分出来的细粒度指标。整个验证集按来源分成三个子集:白天、夜间红外、遮挡密集,分别计算 mAP,很快就能定位模型的短板在哪个场景。
最终在验证集上的参考数据我记录一下:
- mAP@0.5:整体 96.8%
- mAP@0.5:0.95:整体 78.4%
- 24×24 像素以下小目标召回率:83.1%
- 白天子集 mAP@0.5:97.6%
- 夜间红外子集 mAP@0.5:88.2%
夜间红外子集掉分严重,这是所有视觉检测模型面对的共同难题,后面我会讲怎么针对性缓解。
4.4 消融实验的参考结果
为了确认改动不是心理作用,我做了三个对比:原版 YOLO11n、加 C3k2-MambaOut 但不改分辨率、最终版(改模块 + 1280 输入)。结果如下:
- 原版在验证集上的小目标召回率大概 79.6%,加了模块之后到 82.4%,再配合高分辨率精调,最终到 83.1%。
- 夜间子集提升更明显,加了 MambaOut 融合后 mAP@0.5 涨了 3.2 个点,说明全局上下文建模对低照度场景确实有帮助。
当然这组数据跟具体的数据分布强相关,不能代表所有场景,但至少说明这个改造方向没有白费。
5. 部署与业务集成
5.1 模型导出与加速
训练完成后我用 TensorRT 做了加速。导出流程是:PyTorch 模型转 ONNX,再转 TensorRT FP16 engine。这里有一个大的经验:ONNX 导出时一定要把 dynamic batch 关掉,固定 batch size 为 1,否则转 TensorRT 后推理时会出现莫名奇妙的延迟抖动。
模型推理前处理和后处理也同样重要。工地摄像头分辨率普遍是 200 万像素(1920×1080),但模型训练用的是 1280 分辨率,直接把整张图缩到 1280 会让小目标信息损失惨重。我的做法是先把原图基于长边等比缩放到 1280 后再做推理,如果画面中工人分布特别分散,还做了一次切图推理:把原图切成 4 个 960 的 patch 分别推理再合并结果。切图推理涨了点精度,但速度会降到 10 FPS 左右,只能在关键点位启用。
5.2 违规判定规则设计
模型输出的是 person、helmet、vest 三个类别的框和置信度。违规判定在后处理层实现,规则如下:
- 检测到 person 框后,计算其头部区域(框顶部 20% 区域)与所有 helmet 框的 IoU,如果最大值小于 0.3,则判定“未佩戴安全帽”。
- 同理,检测到 person 框后,计算其躯干区域(框中间 60% 区域)与所有 vest 框的 IoU,如果小于阈值,则判定“未穿着反光背心”。
- 如果 helmet 或 vest 的置信度低于判定阈值但高于 0.1,不立即告警,而是标记为“疑似违规”,等下一帧再确认。
连续确认是这个系统最重要的设计之一。单帧误报率哪怕只有 1%,在 30 FPS 的视频流里每秒也会产生接近 0.3 个误报,一天下来能刷几百条。只有连续 3 帧判定为同一人违规,才真正触发告警。这个简单逻辑能把有效告警准确率从不到 60% 提升到 95% 以上。
5.3 端到端告警链路
前后端联调环节,系统整体架构大概是:摄像头 RTSP 流 → 解码模块 → 模型推理 → 违规判定 → 抓图 + 叠加标记 → 推送到告警平台 → 管理员复核。
队长收到告警后可以在平台上查看抓拍图片和前后 5 秒的视频片段,确认后一键通知到对应班组长。这个闭环非常重要,因为算法不可能做到 100% 准确,必须有一个人工复核的中间环节,否则系统在工地上很难真正被信任。
部署硬件我最终选择了边缘计算盒子,原因很简单:工地网络环境不稳定,如果把几十路视频全部推回机房统一处理,一旦核心交换机故障,整个巡检系统就瘫痪了。边缘盒子部署在前端,断网也能本地运行、本地存储告警记录,网络恢复后再自动同步,这种健壮性是工业场景的基本要求。
6. 常见问题与避坑实录
6.1 漏检比误报更头疼
工地现场最怕的不是多报,而是漏报。一个人没戴安全帽从摄像头下面走过,如果算法没识别到,那系统就完全失去意义。我在调试初期遇到过不少漏检案例,尤其是 15 米外的小目标,模型经常视而不见。
排查思路是先从数据上看:这个场景在训练集里有没有类似的样本?如果没有,那就是覆盖不足,需要补采数据。如果有但模型没检出,那就是特征学习不充分,此时优先尝试提高输入分辨率,再考虑加大注意力模块。
实操经验:不要一上来就堆数据,先检查是不是推理分辨率设低了。很多漏检问题仅仅是因为推理时把 1080P 画面降到 640 分辨率,小目标直接被压缩成几个像素,神仙模型也救不回来。把推理分辨率提上去,漏检率通常立刻就能减半。
6.2 误报集中在哪些场景
误报率最高的场景往往是安全帽和脑袋颜色比较接近的画面。工地上有些工人戴黄色安全帽,远看和混凝土地面颜色相近,模型有时会把地面阴影误判成安全帽。另一个高发场景是汽车挡风玻璃上的人影反射,在夜间的工地门口尤其严重。
针对这类问题,我做了几个层面的处理。数据层面增加负样本,专门截取大量“看起来像安全帽但不是安全帽”的图片(例如墙上的圆形通风口、红色水桶、路障锥桶)参与训练。模型层面把置信度阈值从默认的 0.25 提高到 0.35,虽然会略微降低召回率,但能过滤掉大量低置信度误报。决策层面增加前面说的连续帧确认,这是最后一道保险。
6.3 小目标、遮挡、暗光的联合优化
这三个问题经常同时出现。比如夜间工地,工人穿着反光衣在远处走动,反光衣因为红外补光非常亮,而安全帽反而很暗,模型只检测到了 vest 却检测不到 helmet,于是系统误判“未戴安全帽”,实际上人家好好戴着。
解决这个问题,我采用了一个组合拳:把夜间样本单独拿出来做模型精调,训练时对暗光区域做随机遮照模拟;同时优化了检测头的注意力分配,让模型更关注头盔区域的高频纹理而不是整体的亮度;最后在判定规则上增加了头盔置信度的动态阈值——当整体画面亮度偏低时,自动降低 helmet 类别的置信度阈值。
组合之后,夜间场景的误报率下降了四成左右,但依然没法做到和白天一样的水平。这里我给同行的建议是:不要追求模型在所有光照条件下都完美,而是要在业务层建立容错机制,比如夜间安排定时巡逻抽查,和算法告警相互补充。
6.4 工程化上的其他心得
最后聊几个容易踩的工程坑。
第一,摄像头安装角度非常影响模型效果。最理想的是摄像头斜向下 30-45 度俯拍,既能看清头部区域,又能拍到身体。如果摄像头装太高,拍到的是头顶一片,反光背心的信息就完全丢失了。跟现场管理员沟通好机位,比调模型快得多。
第二,工地扬尘会把镜头弄脏,画面模糊会让整个系统的精度严重下降。工程交付时一定要包含定时清洗镜头的维护流程,并监听视频流的平均清晰度指标,一旦画面模糊超过阈值就自动告警。
第三,模型迭代和现场数据回流要闭环。系统上线后保持采集新数据的习惯,每周挑出所有的误报和漏报样本,补充进训练集做一轮增量训练。我见过太多项目交付即停止优化,时间一长现场场景一变,模型效果越来越差,最后被弃用。持续的小步迭代比一次性追求完美模型更靠谱。
这个项目从数据整理到最终上线,前前后后折腾了将近两个月。回头看,真正的难点其实不在模型结构本身,而在如何把 YOLO11-C3k2-MambaOut 这套东西和真实工地场景的复杂性匹配起来。每一轮修改,要么是在数据里找问题,要么是在规则里找问题,场景的确定性比模型炫技重要得多。如果你也在做类似的设备检测项目,建议先把现场跑透,再回来改模型。