ARTICLE DETAIL

资讯详情

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

安全帽检测实操:YOLO11训练从VOC/COCO/YOLO标签转换到三平台部署

安全帽检测实操:YOLO11训练从VOC/COCO/YOLO标签转换到三平台部署 简介面向目标检测初学者与工地安全帽检测项目开发者资源以PDF说明文档的形式完整介绍了一套1000张真实场景图片的安全帽检测数据集其中图片覆盖工地行人、高空作业、遮挡及严重遮挡等多种复杂情况均以labelimg标注划分为佩戴安全帽helmet与未佩戴安全帽head两类。文档详细说明了VOC(xml)、COCO(json)、YOLO(txt)三种格式标签的对应关系并附有标注截图与数据集缩略图方便读者快速评估数据质量。压缩包仅含1个PDF文件大小6.11MB内附数据集网盘获取方式目前已有886人学习下载。此外配套说明还介绍了作者提供的YOLO11一键训练脚本支持GPU、CPU及MacM芯片多平台运行并附训练结果日志便于对照复现对需要正规标注数据并快速跑通检测流程的开发者来说是一份实用的入门指引。1. 安全帽检测不是缺模型而是缺一份能直接开训的数据集目标检测落地到工地、电厂、化工厂时安全帽检测数据集是被问得最多的需求之一。1000张安全帽图片不算大但配合VOC、COCO、YOLO三种格式标签再加上一份能在GPU、CPU、Mac三平台直接跑YOLO11的一键训练脚本就能把「数据准备、格式转换、环境安装、训练调参」这些重复劳动一次带走。这个组合适合做安监算法验证、毕业设计、边缘盒子原型也适合第一次接触YOLO11训练的人。真正要解决的三个问题很简单标签格式怎么选、三平台环境怎么配、训练脚本里哪些参数不能乱动。2. 三种标签格式选型VOC、COCO、YOLO 的差异与转换逻辑拿到安全帽图片后的第一个决策不是选模型而是选标签格式。VOC、COCO、YOLO 三套格式都能描述「哪里有帽子、哪里是没戴帽子的头」但存储方式和坐标单位完全不同。习惯用 LabelImg 手工标注的人主格式适合选 VOC要接公开评测或做实例分割扩展COCO 更通用准备直接训练 YOLO11txt 格式最省事。数据集同时给三种格式不是要求你标三遍而是同一份标注导出成三种投影。2.1 VOC 与 COCO 的存储结构XML、JSON、TXT 的字段对应VOC 格式每张图对应一个 XML 文件文件名就是图片名所有目标框都挂在object节点下。安全帽检测里最简单的 VOC 标签长这样annotation filenameIMG_0001.jpg/filename size width1280/width height720/height /size object namehelmet/name bndbox xmin214/xmin ymin188/ymin xmax363/xmax ymax317/ymax /bndbox /object /annotationCOCO 格式则把所有图片和标注写进一个 JSON 文件框用bbox表示顺序是[x, y, w, h]。同一张图的 COCO 片段对应如下{ images: [{id: 1, file_name: IMG_0001.jpg, width: 1280, height: 720}], annotations: [{id: 1, image_id: 1, category_id: 1, bbox: [214, 188, 149, 129]}], categories: [{id: 1, name: helmet}, {id: 2, name: head}] }YOLO 标签最直接每张图对应一个 txt一行一个目标格式是class_id cx cy w h坐标全部归一化到 0~1。比如上面那个框在 YOLO 里写为0 0.2254 0.3507 0.1164 0.1792有一个起点坑会绊住很多人VOC 和 COCO 的类别编号从 1 开始YOLO 从 0 开始。COCO 里的category_id1对应 helmet转成 YOLO 时必须减 1 变成 0。如果漏掉这一步模型会把「戴帽子的头」和「没戴帽子的头」整个学反训练完 val 指标可能正常推理时却全出乱框。2.2 坐标转换逻辑xmin/ymin 如何变成 cx/cy/w/h无论从 VOC 还是 COCO 转 YOLO核心都是坐标单位换算。VOC 给的是xmin, ymin, xmax, ymaxYOLO 需要的是框中心点和宽高。转换公式不复杂cx (xmin xmax) / 2 / img_w cy (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h我一般会写一个几十行的 Python 脚本做这件事顺手把类别名映射也做掉import xml.etree.ElementTree as ET class_map {helmet: 0, head: 1} def voc2yolo(xml_path, img_w, img_h): root ET.parse(xml_path).getroot() lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_map: continue 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) cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{class_map[name]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) return \n.join(lines)这段代码里真正的注意点是class_map。如果标注人员把标签写成了hard_hat而不是helmet脚本里没有映射就会直接跳过这个目标一张图可能有几千个框被静默丢掉。建议转完之后按类别统计一次数量再抽查几张图把框画回去确认没有大面积漏标。COCO 转 YOLO 同理读取annotations里的bbox用x, y, w, h推cx x w/2cy y h/2再除以图像宽高。唯一多的一步是把category_id减 1。2.3 1000 张图的划分与三格式同步问题1000 张图建议按 8:2 拆成 train 和 val也就是 800 张训练、200 张验证。很多人会把验证集再从训练集里随机抽这个做法在安全帽场景里不太推荐。工地视频连续帧高度相似如果训练集和验证集来自同一段视频的相邻帧val 的 mAP 会虚高换一个工地马上掉点。我自己更倾向按拍摄场景或视频片段划分保证验证集是「没见过的机位和光照」。三种格式同步的关键是让 VOC 当主格式。LabelImg 标注产物就是 XML后续加标签、改错误框都只动 XML然后重新导出 COCO JSON 和 YOLO txt。不要手动去改 JSON 或 txt否则三份标注很容易不一致后期排查标签错位会非常消耗时间。提示COCO JSON 和 YOLO txt 都是导出产物。数据集的原始标签以 VOC XML 为准二次修改必须走标注工具再跑一次导出脚本。3. 动手配置 YOLO11 训练环境GPU、CPU、Mac 三平台怎么选YOLO11 依赖 PyTorch 和 ultralytics 库。所谓三平台支持本质上不是三套代码而是 PyTorch 在不同设备上选不同后端Linux/Windows 的 NVIDIA 显卡走 CUDAApple Silicon 走 MPS什么都没有就走 CPU。环境配置的差异也集中在这一个选择上。3.1 GPU/CPU 环境配置创建虚拟环境并安装 ultralyticsGPU 机器上最省事的做法是用 conda 建一个干净环境再装 ultralytics。装完先验证 PyTorch 能不能看到显卡conda create -n yolo11 python3.10 -y conda activate yolo11 pip install ultralytics python -c import torch; print(CUDA available:, torch.cuda.is_available())如果输出True说明 PyTorch 已经正确识别 GPU。如果输出False先执行nvidia-smi看驱动是否正常再看 PyTorch 版本和 CUDA 版本是否匹配。大多数情况下直接pip install ultralytics会带上对应平台的 PyTorch 预编译包不需要额外指定 CUDA 版本。只有当你本机驱动较老、或用的显卡太旧时才需要去 PyTorch 官网按 CUDA 版本重装。纯 CPU 环境的安装命令完全一样只是最后一步会输出False后面训练时把设备指定为cpu就行。3.2 Mac 用 MPS 训练安装命令与内存限制Mac 上的 MPS 是 PyTorch 对 Apple GPU 的支持方案不需要单独安装 CUDA。环境创建方式与 Linux 基本一致conda create -n yolo11 python3.10 -y conda activate yolo11 pip install ultralytics python -c import torch; print(MPS available:, torch.backends.mps.is_available())MPS available为True时训练时把device参数写成mps即可。要注意的是 MPS 会占用 Mac 的统一内存安全帽数据集虽然只有 1000 张但开启缓存和默认数据加载器后内存占用很容易超过 16GB。MPS 训练时建议把cacheFalse、workers0、batch减半这三项能显著减少内存压力。如果训练中遇到某个算子不支持可以设置环境变量PYTORCH_ENABLE_MPS_FALLBACK1让不支持的算子自动落到 CPU。这不是最优解但至少能保证训练不中断。3.3 设备自动选择一个函数解决三个平台写训练脚本时我会用一个pick_device函数把设备选择逻辑封装起来import torch def pick_device(): if torch.cuda.is_available(): return 0 if hasattr(torch.backends, mps) and torch.backends.mps.is_available(): return mps return cpu判断顺序是 CUDA 优先因为大多数训练场景还是 NVIDIA GPU其次查 MPS特别注意要先判断torch.backends里有没有mps属性否则在纯 CPU 机器上直接访问torch.backends.mps会报 AttributeError最后回落 CPU。这个函数放进训练脚本后同一份代码在 GPU、Mac、纯 CPU 三台机器上都能直接跑这就是标题里说的「三平台一键训练」的最小实现。4. 把 1000 张安全帽图跑进 YOLO11一键训练脚本与参数说明环境就绪后下一步是把数据集目录整理好再把训练脚本跑通。整个训练过程由 ultralytics 封装核心工作集中在 data.yaml、脚本参数和输出检查三件事上。4.1 准备数据集目录与 data.yaml路径和类别命名是头号变量对于 YOLO 格式目录结构建议这样组织datasets/safety_helmet/ ├── safety_helmet.yaml ├── images/ │ ├── train/ │ └── val/ └── labels/ ├── train/ └── val/data.yaml 是训练脚本的地图内容很直接path: ../datasets/safety_helmet train: images/train val: images/val nc: 2 names: 0: helmet 1: headpath是数据集根目录train和val是相对于根目录的子路径。我这里用../datasets/safety_helmet是因为训练脚本放在项目根目录下的tools/里如果你把 yaml 和数据集放在同一层path直接写.或绝对路径更保险。有一个常见的翻车点names的顺序必须跟 txt 标签里的class_id完全一致第 0 类写 helmet第 1 类写 head。如果数据里第 0 类其实是 head模型会把类别名学反loss 照样降验证集混淆矩阵会非常难看。4.2 train_yolo11.py 一键训练脚本先跑通再调参训练脚本的主体不需要很复杂核心是把设备选择、权重选择、超参数三件事固化下来import argparse from ultralytics import YOLO import torch def pick_device(): if torch.cuda.is_available(): return 0 if hasattr(torch.backends, mps) and torch.backends.mps.is_available(): return mps return cpu def main(): parser argparse.ArgumentParser() parser.add_argument(--data, defaultdatasets/safety_helmet/safety_helmet.yaml) parser.add_argument(--model, defaultyolo11n.pt) parser.add_argument(--epochs, typeint, default100) parser.add_argument(--batch, typeint, default16) parser.add_argument(--imgsz, typeint, default640) args parser.parse_args() device pick_device() print(fuse device: {device}) model YOLO(args.model) model.train( dataargs.data, epochsargs.epochs, batchargs.batch, imgszargs.imgsz, devicedevice, cacheTrue, plotsTrue, patience50, projectruns/detect, namehelmet_train, exist_okTrue, ) if __name__ __main__: main()运行方式也很简单python train_yolo11.py --data datasets/safety_helmet/safety_helmet.yaml --model yolo11n.pt --batch 8这段脚本里几个参数需要说明。model默认用yolo11n.pt这是 YOLO11 的 nano 版本权重首次运行会下载预训练模型到本地缓存再基于它微调。1000 张数据量不算多从预训练权重开始收敛速度会远好于随机初始化。cacheTrue会把图像缓存进内存加速训练如果数据量超过内存改成cacheram或关掉。plotsTrue会生成训练曲线、混淆矩阵和验证样例图跑完一轮就能可视化判断训练是否健康。exist_okTrue表示重复运行时不新建目录方便多次对比实验结果。4.3 必调参数batch、imgsz、epochs、patience 和增强开关下面是针对 1000 张安全帽图最常用的一组参数起点照着改即可参数作用建议值batch每次进 GPU 的图片数8 或 16显存小就减半imgsz训练输入分辨率640epochs完整训练轮数100~200patience验证指标连续多少轮不涨就早停50cache是否把图像缓存进内存Trueoptimizer优化器auto 或 SGDbatch是最先要考虑的参数。16 张 640x640 的图在 8GB 显存上经常放不下跑之前看显存占用显存不足就降到 8。imgsz对安全帽小目标影响很大帽子在画面里经常只占几十像素imgsz 太小容易漏检建议直接 640如果远距离样本多可试 960但 batch 要同步降低。epochs建议先跑 100观察results.png里的验证曲线是否还在上升再决定要不要追加。patience50意味着 50 轮验证指标没提升就自动停省时间也避免过拟合。5. 安全帽检测训练避坑指南五条实际踩坑记录与解决办法这个项目看起来步骤不多实际跑的时候有几个问题反复出现。下面按现象、原因、解决的思路写出来每一条都是我或身边同事真实遇到过的情况。5.1 训练损失下降但预测全空类别编号从 1 带进 YOLO现象训练时 loss 正常下降验证集 mAP 也显示有结果但拿一张图片去 predict输出完全没有框。原因转换脚本里没有处理类别起步编号。VOC 里helmet1、head2转 YOLO txt 时直接写了 1 和 2但 YOLO 要求类别从 0 开始0 和 1 才是合法编号。模型把背景当成了第 0 类真正要检测的目标变成了第 1、2 类推理时类别的置信度全乱。解决写一个检查脚本遍历所有 txt 标签统计每条记录的class_id范围是否在[0, nc-1]内。同时按类别输出目标数量例如 helmet 有 4000 个框head 有 5000 个框数量分布一目了然能快速发现类别映射是否颠倒。5.2 小目标安全帽漏检imgsz 太小和模型规模不够现象近处工人头顶的帽子能识别画面远处一个戴帽子的人走过完全漏掉把置信度降到 0.1 也检不出。原因安全帽在远距离画面里可能只有二三十像素YOLO11 的 nano 模型参数少对小目标的特征表达弱再加上训练分辨率只有 416输入放大后小目标特征进一步丢失。解决第一优先把imgsz提到 640 或 960远距离场景尤其明显。第二把yolo11n.pt换成yolo11s.pt模型变大后小目标召回率会好一些代价是训练时间更长。如果换了还是漏把远距离样本单独挑出来做一次简单复制粘贴增强让训练集里小尺寸目标数量增加。5.3 Mac 训练到一半报 MPS 相关错误现象M1/M2 芯片的 Mac 上训练前十几个 epoch 正常然后突然报NotImplementedError或out of memory进程直接退出。原因MPS 后端仍有少量算子没有实现某些网络层在特定输入尺寸下会触发兜底失败另一种情况是统一内存被训练缓存和数据加载占满Apple 的统一内存上限毕竟和独立显存不同。解决先设置PYTORCH_ENABLE_MPS_FALLBACK1让不支持的算子自动落到 CPU。再在训练参数里把cacheFalse、workers0、batch8降下来。如果仍然崩就把device改成cpu这样能跑通但速度会明显变慢。不要急着加数据并行MPS 的并行支持还没有 CUDA 成熟。5.4 验证 mAP 虚高但不能用划分和路径错位现象验证集的 mAP 到了 0.9自己拍一段视频测试同一个工人不同角度频繁漏检和 val 结果严重不符。原因验证集和训练集来自同一段视频的连续帧或者 data.yaml 里val路径写错验证时加载的又是训练集图片。两种情况下模型都见过验证图mAP 自然虚高。解决用脚本把 train 和 val 的图片路径取出来求交集交集为 0 是底线。更好的做法是按视频片段划分一段视频的前 200 帧进训练集后 50 帧进验证集这样验证集里的行人姿态、光照条件才是真正没见过的。5.5 帽子颜色和光照变化大数据增强与样本补充现象训练数据里大多是红色和黄色安全帽到了现场出现大量白色和蓝色安全帽模型开始漏检逆光时帽子反光边框紧贴帽檐的目标被误判为 head。原因1000 张图的多样性有限颜色和光照没覆盖到默认增强虽然开了但没有针对性强化色彩扰动。解决训练时开启并加大颜色增强比如hsv_h0.015、hsv_s0.7、hsv_v0.4让模型不过度依赖颜色。针对白帽蓝帽补 50~100 张带标签的样本比增加 200 张同色样本更能提升泛化。逆光场景可以在训练集里加入少量天黑前的帧或者把这类样本单独留到验证集里持续观察召回变化。6. 训练完成的验证与推理从 best.pt 到视频流上手训练结束后runs/detect/helmet_train/下会有best.pt和last.pt。后续所有推理都用best.pt它是验证集指标最好的权重。先跑单张图片再跑视频流最后检查混淆矩阵这条路最稳妥。6.1 用 best.pt 做图片和视频推理最简单的推理代码只有几行from ultralytics import YOLO model YOLO(runs/detect/helmet_train/weights/best.pt) results model.predict(demo.jpg, conf0.35, iou0.5, saveTrue)conf0.35是置信度阈值。安全帽检测场景里漏检的代价通常比误检大所以阈值不要设太高如果后续接的是抓拍报警0.35~0.45 比较合理。视频推理把demo.jpg换成demo.mp4即可也可以在参数里加vid_stride2每两帧取一帧本地视频和监控视频回放都能加速。想观察模型到底看的是帽子形状还是反光边缘可以借助特征热力图。用 ultralytics 推理时开启save_txtTrue保存坐标再配合 GradCAM 脚本在特定层上生成热力图。安全帽误检的头号来源是「白色反光区域被当成 head」热力图能直观看出模型的注意力是不是落在帽檐反光上。如果注意力过于分散优先检查训练集里有没有大量低质量反光样本。6.2 用混淆矩阵判断误检方向不要只看 mAP。训练过程中plotsTrue会自动生成confusion_matrix.png放在runs/detect/helmet_train/下。这个图比单个数字有用得多。model.val(datadatasets/safety_helmet/safety_helmet.yaml, splitval)跑完查看混淆矩阵里的 helmet 和 head 两列重点看两个数字背景被误判成 helmet 的比例以及 helmet 被误判成 head 的比例。帽子被框出来了但显示为 head说明两类样本的数量失衡head 类别过多导致模型偏向输出 head。背景误检多则需要提高conf阈值。混淆矩阵是最直接的调参依据只看 mAP 很容易漏掉这些细节。6.3 导出 ONNX 给边缘设备验证满意之后把权重导出成 ONNX 格式方便后续接边缘盒子的推理框架model.export(formatonnx, imgsz640)导出后会在权重目录生成同名.onnx文件。ONNX 不依赖 PyTorch 环境很多 GPU/CPU 盒子都能直接加载。我的习惯是先跑一遍 val 看混淆矩阵再用一段包含多人、逆光、不同帽色的视频做冒烟测试确认没有大面积漏检最后才导出 ONNX 做部署。这个顺序能帮你把问题留在训练阶段而不是部署之后到处救火。希望这些内容能帮你把安全帽检测从数据准备一路顺利带到实拍验证。本文还有配套的精品资源点击获取
返回列表