拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

YOLO安全帽手套检测数据集实战:格式转换与训练避坑指南

YOLO安全帽手套检测数据集实战:格式转换与训练避坑指南

简介:YOLO安全帽手套检测数据集面向目标检测算法学习者与工程落地人员,尤其适合需要训练自定义安全帽、手套检测模型的开发者。图片采集自真实工地场景,质量高且场景丰富,可用于安全巡检、智能监控、生产合规管理等方向。数据集采用LabelImg标注,标注框质量高,同时提供VOC、COCO、YOLO三种格式标签,分别存放在不同文件夹,可直接接入YOLO系列框架进行训练。整个压缩包约50.13MB,共2000个文件,其中包含1000个XML标注文件(VOC格式)、991个TXT标签文件(YOLO格式),并配有Python脚本用于训练集/验证集/测试集划分,YAML配置文件用于参数设定,还有HTML格式的图文训练教程。已有544人学习浏览,配套教程从环境搭建、数据集修改到训练启动均有细致说明,帮助新手绕过常见坑点,快速获得可用的检测模型。

1. YOLO安全帽手套检测数据集:从这三处开始检查

在工地的安全巡检项目里,安全帽和手套检测是最常见的落地场景,但把 YOLO 安全帽手套检测数据集真正用起来,第一步不是训练,而是检查三件事:标签文件夹里是否有和图片同名的文件,类别顺序是否和需求一致,VOC 的 xml、COCO 的 json、YOLO 的 txt 三种格式到底用哪一种。这套资料把这三件事都处理好了,1000 张真实场景图片不是合成图,对原型验证完全够用。

刚搭好 YOLO 环境、想拿干净数据把流程跑通的人,或者做安全帽检测项目、需要一套能直接训练的数据集的人,都比较适合。但直接开 train 会踩路径和类别顺序的坑,下面把每个环节拆开讲,脚本怎么用、参数怎么改、卡住看哪里,一步步来。

2. VOC、COCO、YOLO三种标签格式:结构差异与转换逻辑

资料包里三种标签是分开存放的,训练时不要混着用,也不建议把三种格式塞进同一个目录让 YOLO 自己猜。先搞清三种格式各自的结构,后面改脚本才不会翻车。

2.1 VOC的xml和COCO的json:两种主流目标检测标注结构

VOC 格式来自 PASCAL VOC 项目,每张图片对应一个 xml 文件。以安全帽为例,xml 里最核心的是 object 节点:

<annotation> <folder>safety_hat</folder> <filename>000001.jpg</filename> <size> <width>1920</width> <height>1080</height> <depth>3</depth> </size> <object> <name>safety_hat</name> <bndbox> <xmin>320</xmin> <ymin>180</ymin> <xmax>580</xmax> <ymax>330</ymax> </bndbox> </object> </annotation>

bndbox 里存的是像素坐标,左上角和右下角两个点。xml 的好处是每张图片独立,审核时打开单个文件就能看到标注内容,坏处是几百张图片要读几百个文件,批量处理时稍微慢一点。

COCO 格式整个数据集只有一个 json 文件,用 images、annotations、categories 三个数组组织数据。images 数组存每张图片的 id、宽高、文件名,categories 数组存类别列表,annotations 数组里的每个对象用 image_id 关联到具体图片,bbox 字段是 [x, y, w, h]。注意这里也是像素坐标,但表示的语义是左上角起点加宽和高,和 VOC 的 xmin、ymin、xmax、ymax 不一样。COCO 还有一个 segmentation 字段,检测任务里通常是空的多边形或直接省略,后来要做实例分割时才会用到。

2.2 YOLO的txt归一化坐标:class_id和坐标换算

YOLO 格式最简单,一个 txt 文件里每行一个目标,五个值:class_id、xc、yc、w、h,全部归一化到 0 到 1 之间。归一化是指除以图片的宽和高:

xc = (xmin + xmax) / 2 / width yc = (ymin + ymax) / 2 / height w = (xmax - xmin) / width h = (ymax - ymin) / height

反过来从 YOLO 转到 VOC 或 COCO,就是乘回去再算出 xmin、xmax。这里最容易翻车的地方是 class_id。用 lableimg 标注时,xml 里保存的是类别名字符串,导出 YOLO 格式时按类别在配置文件里的顺序转成数字。如果你后边重新排了类别,txt 里的数字没跟着变,模型就会把安全帽识别成手套。资料包里这个顺序和 data.yaml 是配套的,自己加类别时一定要留意顺序。

2.3 三种格式互转时的几个检查点

第一,坐标必须分清像素还是归一化。很多转换脚本出错就是因为默认了输入格式:VOC 转 YOLO 要先读图片宽高再除,YOLO 转 VOC 要记得乘回去。第二,class_id 从 0 开始还是从 1 开始。YOLO 严格从 0 开始,COCO 的 category_id 习惯从 1 开始,转换时要做偏移。第三,注意同名的图片后缀,图片是 000001.jpg 还是 000001.png,label 文件按 stem 匹配,后缀不一致脚本会漏匹配。

三种格式的核心字段可以这样对应:

格式存储单位坐标表示类别表示框字段
VOC每张一个 xml像素 (xmin,ymin,xmax,ymax)字符串 namebndbox
COCO整个数据集一个 json像素 (x,y,w,h)数字 category_idbbox
YOLO每张一个 txt归一化 (xc,yc,w,h)数字 class_id每行第一列

为什么要三种格式都保留?如果你只在 Ultralytics YOLO 上训练,txt 就够了;想用 mmdetection 或 Detectron2 练,COCO json 更顺手;想做数据审核、画框看看有没有漏标,VOC 的 xml 可视化最直观。资料包把三种都给全,省去自己装的转换脚本,前提是你得知道自己当前在用的是哪一种。转换脚本遇到 xml 里带旋转角度的情况,直接算中心点会把旋转框转没了,这个坑我遇到过一次,当时安全帽数据集里歪着戴的帽子全被算成了大框,后来加了角度判断才修掉。

3. 三个划分脚本怎么选:从按比例划分到生成ImageSets文件

资料包里给了三个 Python 脚本,名字接近,容易搞混,先说清楚各自分工。

3.1 先看懂三个脚本的分工

第一个「训练集、验证集、测试集划分脚本(图片标签划分写入新文件夹).py」负责把图片和标签按比例分到三组,同时复制到新目录,适合 YOLOv5 之后按目录结构读数据的版本。第二个是它的简化版,只分成训练集和验证集,适合不想单留测试集的快速原型。第三个是 split_train_val 生成 ImageSets 下 txt 文件划分脚本,不做文件复制,而是在已有目录基础上生成 train.txt、val.txt、trainval.txt 这类清单文件,来自 darknet 时代的做法,配合老项目或者 mmdetection 的自定义数据加载时更常见。

如果你跑新版本 ultralytics,用前两个脚本按目录划分就够了。如果是从 GitHub 拉的老项目,第三个脚本的 txt 清单可能更合适。选脚本之前先确认自己训练的入口是「目录结构」还是「清单文件」,这个决定选错了,脚本跑了等于白跑。

3.2 实操:把1000张图片按8:1:1划分到train/val/test

第一个脚本的核心逻辑可以理解成下面这样:打乱图片列表,按下标切三段,图片和标签同步复制。

import random import shutil from pathlib import Path src_images = Path("images") src_labels = Path("labels") dst_root = Path("dataset") train_ratio, val_ratio, test_ratio = 0.8, 0.1, 0.1 all_images = list(src_images.glob("*.jpg")) + list(src_images.glob("*.png")) random.seed(2024) # 固定随机种子,保证每次划分结果一致 random.shuffle(all_images) n_train = int(len(all_images) * train_ratio) n_val = int(len(all_images) * val_ratio) for split_name, split_images in [ ("train", all_images[:n_train]), ("val", all_images[n_train:n_train + n_val]), ("test", all_images[n_train + n_val:]), ]: for img in split_images: label = src_labels / (img.stem + ".txt") dst_img_dir = dst_root / split_name / "images" dst_lab_dir = dst_root / split_name / "labels" # 图片和标签同步复制是关键,漏一个训练时会报 dataset not found shutil.copy(img, dst_img_dir / img.name) if label.exists(): shutil.copy(label, dst_lab_dir / label.name)

几个参数要注意:random.seed(2024) 固定随机种子,别人跑同一个脚本能得到同样结果,复现实验时不会因为划分不同导致指标差一截。train_ratio、val_ratio、test_ratio 加起来要等于 1,否则后边切片的边界对不上。如果只要训练集和验证集,把 test_ratio 改成 0、val_ratio 改成 0.2 就行,对应资料包里第二个脚本的写法。

还有个容易被忽略的地方:glob(".jpg") 和 glob(".png") 分开匹配,数据里有大小写混用的 .JPG 就会漏掉。我一般会在脚本里加一行,统一把后缀转成小写再匹配。复制用 shutil.copy,源目录没被改动,可以反复换比例重新划分。

注意:划分前先确认磁盘空间够不够,图片加标签复制过去约占多少,用 df -h 看一眼再跑,避免复制到一半磁盘写满。

3.3 train_list.txt和trainval_list.txt的格式与作用

资料包里有两个 txt 文件:train_list.txt 和 trainval_list.txt。它们对应的是传统划分方式:train_list 里放所有训练图片的路径,trainval_list 是训练加验证的总和。trainval 的作用是,当你希望用更多数据做最终轮训练时,直接引用这个清单,不用再合并两个文件夹。

这些 txt 的行格式一般是每行一张图片的路径,可以是绝对路径也可以是相对于数据集根的相对路径。建议用相对路径,因为项目换到别的机器上时,绝对路径会失效一大半。老版 darknet 训练时还需要一个独立的 obj.names 文件列出类别名,顺序要和 txt 里的 class_id 一致,这又回到了第 2 章说的类别顺序问题。

自己写生成脚本时注意两点:一是路径分隔符,Windows 是反斜杠,Linux 是斜杠,建议统一转成斜杠;二是 txt 里的图片顺序和训练顺序有相关性,如果原始文件按拍摄时间排,划分时要先打乱,否则模型会学到时间相关性。

划分完我习惯先验证一下:train、val、test 三个目录里图片数和 txt 数要一致。不一致通常是某个图片没有标签文件,这种图片放进训练集会让 YOLO 报错或产生空标签。最简单的方式是用 Python 统计两边的文件后缀数量差,数量对不上就回源目录排查。另外测试集单独留出来这一点,资料包做得比较规范——很多人只用 train 和 val,最后拿 val 当测试集,mAP 会虚高一截,部署时才发现精度对不上。

4. YOLO环境搭建与训练:GPU驱动到第一个模型跑通

资料包里附带了两份 YOLO 环境教程,一份是 GPU 显卡驱动版,一份是 Ubuntu 安装教程。环境搭建的坑不在操作步骤,而在版本匹配。

4.1 GPU驱动、CUDA、PyTorch的版本匹配关系

先明确三个层次:显卡驱动是系统级的,CUDA 是运行库,PyTorch 里编译的 CUDA 版本要和前两层兼容。nvidia-smi 能看到的是驱动支持的 CUDA 最高版本,nvcc -V 显示的是 CUDA Toolkit 版本。很多人在 conda 里装了 cudatoolkit,nvcc 显示的版本和 PyTorch 实际用的不一定同一个,这一点最容易把人绕晕。

一套比较常见的搭配:

显卡驱动版本CUDAPyTorch
RTX 30系列470+11.7/11.8cu117/cu118
V100/A100525+12.1/12.2cu121/cu122
RTX 40系列545+12.4+cu124

装 PyTorch 用官方 cu121 索引,比 conda 默认源稳得多。装完验证方式是小段代码跑通:import torch 后 torch.cuda.is_available() 返回 True,再打印 torch.cuda.get_device_name(0) 确认识别到的显卡型号无误。这一步过了再往下走,不过就回头查驱动。

4.2 修改data.yaml和模型配置:类别数改错会直接崩

资料包里是两类目标:安全帽和手套。data.yaml 按自己的目录改成这样:

path: /home/workspace/safety_hat_dataset train: images/train val: images/val nc: 2 names: ['safety_hat', 'glove']

path 是数据集根目录,train 和 val 是相对这个根的路径,nc 必须是 2,names 的顺序要和 labels 里 txt 的 class_id 严格一致。模型配置文件也要同步改:如果用 yolov8s,模型 yaml 里有 nc 字段,改成 2。改漏一个就会报类别数不匹配,或者训练时直接崩。

资料包里的训练教程 html 写了怎么根据案例修改自己的数据集,核心就是换路径、换 names、换 nc。教程里的路径是作者的,全部替换成自己的路径,全局搜索作者写的目录名一次性替换,不要只改 data.yaml。其他参数像 batch 和 epochs 第一次先保持默认,能跑通比什么都重要。

4.3 训练启动命令与输出日志

数据和环境都验证通过后,启动训练:

# 用官方预训练权重做迁移学习,收敛更快 yolo train model=yolov8s.pt data=safety_hat.yaml epochs=200 batch=16 imgsz=640 device=0

epochs 先给 200,batch 按显存调整,imgsz=640 是速度和精度的平衡点。1000 张图对 YOLOv8s 来说 200 轮足够看到明显收敛。日志里主要看三个 loss:box_loss、cls_loss、dfl_loss,这三个对应 YOLO 的损失函数。前 30 轮 loss 下降快是正常的,后面变慢也是正常的,如果 loss 突然上涨或变成 nan,基本可以断定是学习率问题或数据里混进了脏标签。

训练结束后生成 runs/detect/train 目录,里面有 weights/best.pt 和 last.pt,还有混淆矩阵和 PR 曲线图。best.pt 是 val mAP 最高的权重,部署时用这个,last.pt 一般只用来续训。

5. 训练排查与避坑:图片路径、显存和标签错位的常见问题

训练 YOLO 时最容易翻车的点不在模型,而在数据准备和环境细节。下面几条是第一次跑数据集的人最常遇到的,按「现象 → 原因 → 解决」写。

5.1 Dataset not found:路径拼接与孤立文件

训练时报「Dataset not found」或「found no images in val」。原因基本都是 data.yaml 的 path 写了相对路径,启动命令的工作目录不在数据集根目录下。YOLO 解析时会把 path 和 train、val 拼接,拼接结果不存在就直接报错。很多时候不是图片真没了,是拼接后路径不对。

解决:把 data.yaml 里的 path 改成绝对路径。训练前手动跑一段 Python,确认 images 和 labels 两个目录都存在,并且两边没有多余的孤立文件。还有一个容易忽略的点——文件夹里混进隐藏文件(比如 Mac 的 .DS_Store),打开目录时不会报错,但会让 glob 统计数量不准。

5.2 CUDA out of memory:batch、imgsz和cache

训练没跑几步就报 CUDA out of memory。原因通常是 batch 和 imgsz 开太大。V100 32G 听起来很大,imgsz=1280 加 batch=32 照样 OOM。

解决:先按 batch=8、imgsz=640 跑通,再逐步加 batch,加到显存占用接近 90% 为止,用 nvidia-smi -l 1 实时监视。还有一个技巧:如果开了 cache=True,图片会缓存进显存,这时候 OOM 不一定是 batch 的锅,先把 cache 关掉试。

5.3 loss变成nan或BN崩溃:学习率与class_id越界

训练中 loss 变成 nan,或者 BN 层崩溃,输出全部归零。最常见原因是学习率过高,尤其是用预训练权重迁移时,全部层用同一个高学习率,BN 层的均值和方差会被搞崩。另一个原因是标签里 class_id 越界——txt 第一列的值大于等于 nc,模型算损失时索引越界,产生 nan。

解决:学习率从默认的 0.01 降到 0.001,还在 nan 就把 batch 调小。数据侧写一个校验脚本,遍历 labels 目录下所有 txt,检查第一列最大值是否小于 nc、每行是不是 5 个数值。损坏的数据文件直接删掉或重新标注,不要带脏标签硬训。我从那以后每次换数据集都强制先跑一遍标签校验脚本,这个习惯帮我避开了很多半夜 debug。

5.4 混淆矩阵行和列不等于100%:这是正常的

训练完看混淆矩阵,有人会逐行算百分比,发现行和列加起来不是 100%,怀疑代码有 bug。实际上混淆矩阵每一行代表一个真实类别,行内各列是该类被预测成各类的比例,所以行可以加到 100。但列的分母是预测为该类的总数量,和行的样本数不一致,列加起来不等于 100 是正常的。

这个现象在资料包训练教程生成的 runs 里也很常见,不用处理。真正要看的是对角线数值,对角线越亮说明分类越准。如果 mAP50 很高但 mAP50-95 偏低,说明框的定位不错但和标注框的重合度差一点,可以加大训练轮数,或者把 imgsz 提到 1280 再试。以上几类问题第一次跑数据集时出现频率最高,排查时按数据路径、标签内容、显存设置、输出指标这个顺序来,能省不少时间。

6. 进阶:预训练权重、数据增强与mAP验证的实战技巧

最后讲三个训练前就要做的选择。

用预训练权重而不是从零训练。yolo 预训练模型下载最方便的方式就是 YOLO 命令行本身,第一次指定 model=yolov8s.pt 时它会自动下载。迁移学习意味着把 COCO 上学到的通用特征搬过来,安全帽和手套这种小目标检测,用 yolov8s.pt 改 nc=2 继续训练,比随机权重初始化少跑上百轮,最终 mAP 也更高。资料包的 1000 张图定向微调完全够用,没必要从零开始。

数据增强参数在 ultralytics 里集中在 hyp 配置中。默认的 mosaic=True 对 1000 张小数据集特别重要,它把四张图拼成一张,等于变相扩充了样本量。hsv_h、hsv_s、hsv_v 控制颜色扰动,工地这种光照变化大的场景,可以把饱和度扰动从默认 0.7 加到 0.9,但对比度扰动别调太高,会让暗部的小目标彻底看不见。fliplr 水平翻转对安全帽这种左右对称的目标可以开,但如果目标上有文字标识或方向性特征要慎用。

训练结束后的验证不是看一眼 mAP 就完事。用 best.pt 跑一次 val:

yolo val model=runs/detect/train/weights/best.pt data=safety_hat.yaml

重点看 mAP50 和 mAP50-95 两个指标。前者反映粗召回,后者对框位置要求苛刻。安全帽在远距离下属于小目标,mAP50-95 比 mAP50 低 10 到 15 个点是正常的,用 imgsz=1280 重新 val 一次差距会缩小。再多一步,把 val 的批量预测图翻一遍,重点看漏检和重复框。

如果模型要放到板子或服务器上做推理部署,最后一步是导出 ONNX:

yolo export model=runs/detect/train/weights/best.pt format=onnx imgsz=640

导出后可以用 onnxruntime 验证输入输出维度,输入 1x3x640x640,输出三个检测头的张量。默认导出的 onnx 带动态 shape,部署引擎只接受静态 shape 时,加 dynamic=False 参数重新导出。

这套资源的脚本和教程都是现成的,按上面的顺序走完就能跑出自己的权重。我的习惯是先校验标签,再 train,再 val,三步走完才敢把模型交给别人用。希望帮到你。

本文还有配套的精品资源,点击获取

返回列表