YOLOv5头盔目标检测数据集实战:从格式校验到避坑指南

发布时间:2026/10/5 11:30:53
YOLOv5头盔目标检测数据集实战:从格式校验到避坑指南 简介面向YOLOv5目标检测任务的头盔识别数据集适合需要训练工地、骑行等场景安全帽佩戴检测模型的开发者与科研人员也适用于计算机视觉课程实验与算法验证。资源包共一百六十个文件包含八十张真实场景图片与八十个对应的XML标注文件每个XML文件对应一张图片并记录目标类别与边界框坐标信息可直接转换为YOLO训练所需的txt标签省去人工标注环节。压缩包整体仅2.86MB体积小巧便于快速下载与迭代测试。已有四百八十二人学习下载数据覆盖不同角度、光照和背景下的头盔实例图片与标注一一对应目录结构简明初学目标检测者也能轻松上手。利用该数据集可快速完成YOLOv5模型训练、验证与推理用于安全帽佩戴检测、施工区域人员安全监控等实际项目也可作为算法对比实验的基准数据。1. yolo5头盔目标检测的数据集先搞清楚能不能用再动手我最早是在一次工地安全巡检项目里正经用YOLOv5跑头盔检测那时候最耽误时间的不是调参而是找数据。网上很多头盔检测数据集下回来是VOC格式得自己写脚本转YOLOv5的归一化坐标转完发现类别id对不上再回头排查一晚上就没了。这份yolo5头盔目标检测的数据集zip是少见的、解压后图片和txt标注都按YOLO格式排好的资源省掉了最磨人的格式转换环节。对第一次碰YOLOv5的开发者来说它可以当基线数据跑通整个流程对已经在做安全帽佩戴检测的工程师来说它能直接用来验证模型结构和训练参数。先说结论这份数据集的底子是干净的直接能训但直接训练会踩掉几个典型坑——比如Mosaic增强把小目标搞丢、未戴帽类别样本偏少导致漏检。后面我按“认识结构→格式体检→划分→训练→避坑→验证落地”的顺序完整拆一遍。2. 认识数据集目录结构、标注格式与样本构成2.1 解压zip先看目录树别急着开训拿到zip第一件事是解压但解压完别急着扔进YOLOv5里跑训练。先打开目录树看一眼确认图片和标注是不是按train/val分好了。常见做法是这套结构helmet_dataset/ ├── images/ │ ├── train/ # 训练图片jpg │ └── val/ # 验证图片jpg ├── labels/ │ ├── train/ # 训练标注txt │ └── val/ └── README.txt # 部分打包版本会带说明这套结构跟我拿到的这份zip基本一致图片是jpg标注是与图片同名的txt。这里的判断标准很简单images/train/000001.jpg必须对应labels/train/000001.txt文件名完全一致只有扩展名不同。如果解压出来只有一个全量文件夹、没有train/val之分也不用慌第3章给的划分脚本可以直接用。但前提是先确认图片和标签的目录层级没有嵌套多一层比如有些打包会把所有图片平铺在一个文件夹里标签放在另一个平铺文件夹里——这种最好在划分之前先整理好不要指望后面脚本自动处理。2.2 一行标注拆开看类别id和归一化坐标打开任意一个txt一行通常长这样0 0.52 0.47 0.21 0.33 1 0.36 0.71 0.12 0.19每一行有5个数含义分别是类别id、目标中心点x、中心点y、目标宽、目标高。注意后四个坐标是归一化的也就是已经除以了图片本身的宽度和高度值域都在0到1之间。YOLOv5在训练时会将标签和resize后的图片做匹配所以读取txt时不需要再除以图片尺寸。关于类别idYOLO系列统一从0开始。这份头盔数据集最常见的类别配置是0head未戴安全帽的人头、1helmet戴了安全帽但也有相反配置就是0helmet、1head。拿到手先打开一个txt确认再写data.yaml里的names列表这两个地方不一致的话训练不会报错但指标计算和可视化标签会全反属于最隐蔽的一类错误。2.3 样本构成监控视角为主、近景为辅我翻了这份数据集里的图片大多数是工地出入口和作业区域的监控视角相机装在高处往下拍画面里人物偏小安全帽往往只有几十像素另外有一小部分是手持手机拍的近景安全帽占画面比例很大。这个构成特点直接影响后面几个选择一是训练尺寸要不要调大二是Mosaic增强要不要关三是未戴帽类别容易漏检。从标注质量上看这份数据集只有两个类别没有“人”“车辆”这类干扰项训练目标很纯粹。但有一个点需要注意监控视角图片分辨率普遍较高常见是1920x1080而YOLOv5训练默认会把图片缩放到640x640再喂给网络。缩放之后画面里远处未戴帽的人头可能只占十几个像素属于不折不扣的小目标。这批图的标注框整体贴得比较紧对mAP计算是个好消息但对训练策略是个挑战。提示在开始训练之前先正确定位这份数据集的适用场景——它适合做工地出入口的安全帽佩戴识别不适合做复杂工地全景图里的密集小目标检测。场景定位错了后面所有调参都容易白费。2.4 十行脚本抽查可视化标注有没有硬伤目录结构和txt格式都确认没问题之后我习惯随机抽10张图把标注框画出来看一眼。这一步成本很低但能发现靠读txt发现不了的问题比如标注框整体偏移、类别标反、框和物体明显不贴合。下面这段脚本把归一化坐标还原到图片像素坐标并画框import cv2, random, glob, os # 随机抽10张训练图做可视化检查 imgs sorted(glob.glob(helmet_dataset/images/train/*.jpg)) for img_path in random.sample(imgs, 10): label_path img_path.replace(images/train, labels/train) \ .replace(.jpg, .txt) img cv2.imread(img_path) h, w img.shape[:2] with open(label_path) as f: for line in f.readlines(): cls_id, cx, cy, bw, bh map(float, line.split()) # 归一化坐标转回像素坐标 x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) color (0, 0, 255) if cls_id 0 else (0, 255, 0) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) cv2.imwrite(fcheck_{os.path.basename(img_path)}, img)这段脚本不复杂核心就一步把归一化坐标乘以图片宽高。(cx - bw/2) * w算出框左上角的x坐标(cy - bh/2) * h算出左上角y坐标右下角同理。颜色上我让类别0显示红框、类别1显示绿框这样打眼一看就能确认两个类别是否都正常出现。如果某张图的框明显偏移或者框比目标大一圈说明这张图标注质量有问题值得在第5章的避坑清单里对着排查。抽查之后再做全量体检。3. 训练前的数据准备格式校验与train/val划分3.1 体检脚本缺图、空标、坏坐标一次查清不管多急着开训我都建议先跑一个不到30行的体检脚本。原因是YOLOv5的报错很多时候发生在训练运行半小时之后——某一张图读取失败、某个txt格式非法导致DataLoader直接崩掉、某个空标签让loss曲线出现诡异抖动。与其让训练跑到一半翻车不如先花两分钟把问题数清楚。下面的脚本遍历训练集逐个检查标签是否存在、是否为空、格式是否为5列浮点数、坐标是否在0到1范围内以及图片能否正常解码import os, cv2, glob img_dir helmet_dataset/images/train lab_dir helmet_dataset/labels/train imgs sorted(glob.glob(os.path.join(img_dir, *.jpg))) problems [] for img_path in imgs: lab_path os.path.join(lab_dir, os.path.basename(img_path).replace(.jpg, .txt)) # 1. 标签文件必须存在 if not os.path.exists(lab_path): problems.append(fmissing label: {lab_path}) continue # 2. 标签文件不能是0字节 with open(lab_path) as f: lines [ln.strip() for ln in f.readlines() if ln.strip()] if not lines: problems.append(fempty label: {lab_path}) continue # 3. 每行必须是: 类别id 4个归一化坐标 for ln in lines: parts ln.split() if len(parts) ! 5: problems.append(fbad format: {lab_path}: {ln}) break try: cls_id, cx, cy, bw, bh map(float, parts) if not (0 cx 1 and 0 cy 1 and bw 0 and bh 0): problems.append(fbad coord: {lab_path}: {ln}) except ValueError: problems.append(fnot float: {lab_path}: {ln}) # 4. 图片本身是否能被OpenCV解码 img cv2.imread(img_path) if img is None: problems.append(fbroken image: {img_path}) print(fchecked {len(imgs)} images, found {len(problems)} problems) for p in problems[:20]: print(p)脚本本身不接收参数改头部两个路径就行。四个检查项分别对应YOLOv5训练时最常翻车的点缺标签会让该图片参与训练时无法计算loss空标签会让该样本梯度为0间接拖慢收敛坐标值大于1说明标签是用像素坐标直接写的、没做归一化损坏图片会让数据加载线程卡住。输出只打了前20条问题多的话把print重定向到文件看全量。如果发现空标签的比例在10%以内我一般直接删对应图片速度快且不影响大局超过20%就要考虑换数据源了。这个阈值不是标准答案但可以帮你快速判断数据集的脏程度。3.2 训练/验证集划分8:2起步随机种子固定有些版本的zip下载下来没有分train/val只有一个全量文件夹这时候必须自己划分。另外还有一种常见情况数据集自带val目录但这个val和训练集来自同一批次图片分布太接近用它验证出来的指标会虚高。我习惯的做法是合并后重新划分固定随机种子保证别人复现你实验时不会因为划分差异导致指标对不上。import os, random, shutil src_img helmet_dataset/images/all src_lab helmet_dataset/labels/all train_ratio 0.8 imgs sorted(os.listdir(src_img)) random.seed(42) # 固定随机种子保证可复现 random.shuffle(imgs) train_imgs imgs[:int(len(imgs) * train_ratio)] val_imgs imgs[int(len(imgs) * train_ratio):] for split, split_imgs in [(train, train_imgs), (val, val_imgs)]: os.makedirs(fhelmet_dataset/images/{split}, exist_okTrue) os.makedirs(fhelmet_dataset/labels/{split}, exist_okTrue) for img_name in split_imgs: lab_name img_name.replace(.jpg, .txt) shutil.move(os.path.join(src_img, img_name), os.path.join(fhelmet_dataset/images/{split}, img_name)) shutil.move(os.path.join(src_lab, lab_name), os.path.join(fhelmet_dataset/labels/{split}, lab_name))划两个要点。第一shuffle之前必须先固定随机种子否则每次跑结果都不一样后面调参时根本分不清是数据划分差异还是超参改进带来的收益。第二移动图片的同时必须把同名txt一起移动这两个文件一旦分家训练时就会报找不到标签。验证集比例要看数据总量如果这个数据集的图片总量在几千张这个量级8:2是合理的如果总量不到一千张建议改9:1因为验证集太少时mAP曲线会剧烈抖动给你造成“模型时好时坏”的假象。划分完可以用两行命令核验数量echo train images: $(ls helmet_dataset/images/train | wc -l) echo val images: $(ls helmet_dataset/images/val | wc -l)这两条命令分别统计训练集和验证集的图片数量。正常来说val大约占总量20%如果明显偏少回头检查是不是移动脚本执行了一半就停了。3.3 划分前先统一后缀jpg和png混用怎么处理这个坑有点隐蔽。有的数据集打包时图片后缀不统一同一个文件夹里jpg和png混着放但标注txt全部按.jpg命名。比如一张图叫000088.png标签却是000088.txt用前面划分脚本的replace(.jpg, .txt)就匹配不上了。最省事的做法是统一后缀。实际项目中我一般不直接改扩展名因为png改jpg只是改了容器名编码没变OpenCV读起来没问题但部署到端侧推理框架时可能踩格式解析的坑。稳妥做法是用OpenCV转码import cv2, glob, os for png_path in glob.glob(helmet_dataset/images/all/*.png): img cv2.imread(png_path) jpg_path png_path.replace(.png, .jpg) cv2.imwrite(jpg_path, img) os.remove(png_path)这段脚本把所有png读进来再以jpg编码写回然后删掉原png。cv2.imwrite会按扩展名自动选择编码格式所以路径后缀写.jpg就行。执行完后重新跑一遍3.1的体检确认没有因为文件名替换产生新的缺失标签。3.4 按类别统计样本提前预判“未戴帽”漏检头盔检测场景里最难的是“未戴帽”这个类别因为多数工地图片是巡检视角绝大多数工人都规范戴了帽未戴帽样本天然少。训练前按类别统计一次样本量能提前知道后面要不要做重采样。统计命令很简单cat helmet_dataset/labels/train/*.txt | awk {print $1} | sort | uniq -c这条命令把训练集所有标签文件里的第一列类别id全部取出来sort之后用uniq -c计数。输出会类似812 0 2045 1看到这个结果就该意识到如果0是headhead类别只有helmet类别的一半那这个模型训练出来对未戴帽的recall大概率偏低后面第5章的类别重采样基本是必做的。如果两类数量悬殊到1:5以上先用第5.5节的方法处理再进训练流程。4. 训练头盔检测模型data.yaml、超参和第一次跑通的命令4.1 data.yaml路径写绝对names顺序别写反把数据集整理好之后第一步是写data.yaml。这是YOLOv5训练时的数据配置核心决定了模型去哪里读图、预测哪几个类别。针对这份头盔数据集配置长这样train: /home/user/helmet_dataset/images/train val: /home/user/helmet_dataset/images/val nc: 2 names: 0: head 1: helmettrain和val是训练集和验证集的图片路径nc是类别数这里是2names是类别名列表。有个细节值得多说一句train路径推荐写绝对路径。相对路径在本地跑没问题但一旦换机器、换工作目录或者放到服务器上用screen后台跑经常因为当前目录不同找不到图片报错信息还特别难排查我一般在拿到数据集的第一时间就把路径粘成绝对路径。names列表的顺序必须和txt标签里的类别id完全一致。这份数据集里id为0的对应head那names第一个必须是head不能先是helmet。顺序反了训练时不会报错但val指标、可视化标签全是反的。4.2 训练命令用s模型起步超参先按表来数据配置就绪后进入yolov5目录开始训练。针对这种几千张体量的头盔检测数据我给出的起步命令是cd yolov5 python train.py --data helmet.yaml --weights yolov5s.pt \ --img 640 --batch 16 --epochs 100 --device 0 \ --project runs/helmet --name baseline其中--weights yolov5s.pt指用s规模的预训练权重做微调。这个选择有明确理由头盔检测属于单类物体检测任务相对简单s模型的容量足够拟合这份数据集用l或者x模型跑在小数据上非常容易过拟合训练时间翻倍但mAP上限几乎不变。--img 640是YOLOv5默认输入尺寸如果你的数据集中监控视角的远距离人物较多可以改成960来保留小目标细节代价是显存占用明显上升。--batch 16按显卡显存调整显存6G左右降到84G显存降到4。--epochs设100轮比较稳跑完看曲线再决定要不要续训。各参数的选择逻辑可以这样记参数推荐值选择理由weightsyolov5s.pt模型容量与几千张数据集匹配不易过拟合img640 / 960小目标多时用960显存有限用640batch4 / 8 / 16显存6G用812G以上用16epochs100起步先跑到验证指标收敛不够再resumedevice0单卡训练没有GPU就写cpu训练过程会在runs/helmet/baseline/下生成weights/best.pt和weights/last.pt。前者是整个训练过程中验证集指标最好的权重后者是最后一个epoch的权重部署时只用best.pt这是YOLOv5最基础的习惯。多说一句如果你之后改用YOLOv8练头盔检测这份数据集的目录结构和标注格式可以原样复用只需要把训练入口换成v8的train脚本数据侧不需要动。4.3 训练日志与指标mAP0.5是主要参考训练开始后终端会周期性打印一行表格包含每类loss、precision、recall和mAP。第一次跑头盔检测不要被一堆指标绕晕聚焦两个东西训练loss是否持续下降以及mAP0.5最终能到多少。这个数据集上mAP0.5到0.85以上基本可以送到现场试跑mAP0.5:0.95能到0.6左右已经算正常水平不用强求因为0.5:0.95对框的精确贴合要求更高监控视角的小目标天然吃亏。如果loss曲线在20到30轮后基本平行、不再下降说明学习率已经衰减到位此时继续跑只是等mAP微调可以考虑提前结束不一定要跑满100轮。另外有个玄学但真实存在的情况多卡训练时batch翻倍初始学习率也要相应调大否则收敛速度明显变慢。单卡训练不用管这个只有--device 0,1这类多卡启动时才需要手动改--lr0。4.4 断点续训与显存不足两个必踩的启动问题第一次跑训练最容易撞上的是CUDA out of memory。很多情况下改参数重跑就行没必要重新跑100轮。处理方法有两档第一档是把batch降到8或4代价是训练变慢第二档是把--img从640降到480输入图变小显存占用大幅下降代价是模型对小目标更不敏感。如果训练已经跑到80轮崩了用resume续训不要从头再跑python train.py --data helmet.yaml \ --weights runs/helmet/baseline/weights/last.pt \ --resume --epochs 150这段命令从last.pt断点继续训练--epochs 150是最终总轮数而非新增轮数。YOLOv5的resume机制会读取上次训练的学习率调度状态直白说就是除了训练数据和权重优化器状态也续上了比重新训练省时间也是那段时间最常用的“后悔药”。5. 常见问题与避坑记录五个我踩过的坑5.1 类别id从1开始训练不报错但目标检测不出来现象训练过程一切正常loss正常下降验证集mAP也不算低但拿到现场测试时预测结果里只有安全帽的框人头一个都框不出来或者安全帽和人头两个类别互相串。原因YOLO的类别索引从0开始但不少人在自己标注数据或者整理数据集时习惯从1开始编号。如果标签文件里head写成1、helmet写成2而data.yaml里nc还是2模型就会把类别2当不存在预测时所有目标都被当成背景或者被挤到类别0。解决先统计标签文件里的实际类别id分布确认是不是从1开始cat helmet_dataset/labels/train/*.txt | awk {print $1} | sort | uniq -c如果输出是1和2而没有0说明id整体偏移了1位。用下面的脚本批量修正import glob shift -1 # 把1-0, 2-1 for lab_path in glob.glob(helmet_dataset/labels/train/*.txt): lines [] with open(lab_path) as f: for line in f: parts line.split() if parts: parts[0] str(int(parts[0]) shift) lines.append( .join(parts)) with open(lab_path, w) as f: f.write(\n.join(lines) \n)脚本逻辑是把每行第一个字段类别id整体减1。跑之前一定要先确认id分布如果原本就是0开头执行这个脚本反而会把标签全改成-1那问题更大。5.2 空标签文件loss曲线不下降mAP长期为0现象训练loss在前几个epoch有所下降后就不怎么动了mAP0.5在验证集上始终是0或者训练跑到中途DataLoader直接报错中断。原因数据集整理时漏掉了部分标注某些图片的txt文件是0字节。YOLOv5读取到空标签时该图片算作负样本参与训练如果这种图片占比偏高模型会倾向于把所有目标都预测成背景。解决用第3.1节的体检脚本把空标签图片全部找出来直接删除对应图片。删除比补标快得多——几百张图人工补标要半天删掉可能只是损失一点样本多样性。复盘这个坑时我最大的体会是训练之前先花两分钟跑一遍体检远比赛后对着loss曲线猜原因省时间。我当时是在训练到第30轮时发现问题退出来删图重跑等于浪费了40分钟GPU时间。5.3 图片和标签对不上训练指标虚高的教科书翻车现象训练集和验证集指标都很好mAP0.5过了0.9但把这个模型拿到新拍的工地照片上测试框的位置明显错乱有时把背景识别成安全帽。原因图片文件夹和标签文件夹来自不同的数据来源文件名前缀相同但实际内容错位。比如某张图内容是一个没戴帽的工人但对应的txt里写的却是一个戴帽工人头部的坐标模型训练时一直在学错误的对应关系。这种情况在合并多个来源的图片时特别容易发生尤其当两个来源都用了IMG_0001.jpg这类通用命名。解决写一个脚本核对图片和标签的一一对应关系同时检查标注框是否超出图片边界import cv2, glob, os for img_path in glob.glob(helmet_dataset/images/train/*.jpg): lab_path img_path.replace(images/train, labels/train) \ .replace(.jpg, .txt) if not os.path.exists(lab_path): print(missing:, lab_path) continue h, w cv2.imread(img_path).shape[:2] with open(lab_path) as f: for line in f: cls_id, cx, cy, bw, bh map(float, line.split()) if not (0 cx 1 and 0 cy 1 and 0 bw 1 and 0 bh 1): print(fcoord out of range: {lab_path}: {line})一旦出现大量越界坐标优先怀疑是标注工具导出的坐标基准不一致这通常意味着这批标签不可信需要换数据源而不是硬着头皮训练。5.4 Mosaic增强把远处人头搞没了小目标检测的必要取舍现象训练时mAP0.5轻松上0.9但把模型部署到工地现场测试时画面远处未戴帽的人几乎全漏只有走近镜头的人才能被检测出来。原因这个数据集里监控视角的人头属于小目标只有几十像素。YOLOv5在默认训练配置下开启了Mosaic增强训练时会把四张图随机拼成一张再缩放小目标在这个过程里被进一步压缩模型学到的小目标特征非常有限。解决训练时换成关闭Mosaic的配置文件python train.py --data helmet.yaml --weights yolov5s.pt \ --img 640 --batch 16 --epochs 100 \ --hyp hyp.scratch-low.yamlhyp.scratch-low.yaml里mosaic0.0同时把scale等增强强度也降了整体来说更适配小目标场景。如果你不想完全关闭Mosaic可以折中把输入尺寸从640提到960保留Mosaic但给小目标更多像素空间。实测下来在这个数据集上关闭Mosaic的收益比调高分辨率更直接代价是收敛速度稍慢。这个取舍没有标准答案只能基于你的实际部署场景试。5.5 未戴帽样本太少类别重采样补回来现象验证集整体mAP很高但单独看head类别的recall远低于helmet。在工地新图上没戴帽子的人被漏检的概率明显更大——对安全帽检测业务来说这是最致命的故障。原因数据集采集时以“检查大家是否戴帽”为目的所以绝大部分图片里人人都戴着安全帽未戴帽样本天然稀缺。模型在训练中见到的正负样本比例失衡自然倾向把目标预测成戴帽。解决做类别重采样把包含head类别的图片在每轮训练中多读几次。最简单的做法是在train.txt里把这类图片的路径重复写入import glob over_sampling 2 # 重复倍数从2倍开始试 imgs glob.glob(helmet_dataset/images/train/*.jpg) selected [] for img_path in imgs: lab_path img_path.replace(images/train, labels/train) \ .replace(.jpg, .txt) with open(lab_path) as f: cls_ids [ln.split()[0] for ln in f if ln.strip()] if 0 in cls_ids: # 0是head类别 selected.append(img_path) with open(train.txt, w) as f: for img_path in imgs: f.write(img_path \n) for img_path in selected: for _ in range(over_sampling - 1): f.write(img_path \n)然后训练时用--train-dir或直接把YOLOv5的数据加载指向这个train.txt。我一般从2倍开始试观察head类别recall的变化再微调。如果数据集本身不到一千张重采样容易造成过拟合这时优先换数据源而不是硬靠重采样撑。6. 验证与落地用mAP说话导出成可部署的模型6.1 用val.py出一份独立指标盯着未戴帽的recall训练结束后不要直接看训练日志里的mAP用独立的验证脚本再跑一遍。命令是python val.py --data helmet.yaml --weights runs/helmet/baseline/weights/best.pt \ --img 640 --conf-thres 0.25 --iou-thres 0.45这个命令会输出每个类别单独的precision、recall和mAP0.5。我每次先看head类别的recall如果低于0.8回到第5章的5.5做类别重采样然后重新训练如果head和helmet两个类别的recall都过了0.85才考虑导出部署。--conf-thres 0.25是置信度阈值这个值直接影响现场漏检率。头盔检测场景里漏检的代价远高于误检现场使用时可以把阈值降到0.15到0.2宁可多框几个错框不能漏掉没戴帽的人。6.2 导出ONNX做冒烟测试模型文件能不能被外部加载确定权重可用后把它导出成ONNX格式方便后续部署到服务端的onnxruntime或端侧推理框架python export.py --weights runs/helmet/baseline/weights/best.pt \ --include onnx --opset 12导出成功后会生成best.onnx。做一次冒烟测试验证用onnxruntime加载模型并对一张验证集图片做推理。这一步能提前暴露很多问题比如opset版本不兼容、动态输入尺寸不支持、模型里的某些算子在目标部署环境不认。如果计划部署到Jetson或ncnnopset选择12以下更安全新版框架对更高opset的支持不一定跟得上。导出之后把数据集的图片尺寸、类别顺序、置信度阈值这三个信息一起交给部署端。项目收尾时最怕的就是模型文件给了但对方不知道该用什么预处理、该用什么阈值。所以建议在部署包里带一个简短的README写清楚输入尺寸是640还是960、类别顺序是head在前还是helmet在前帮助后面对接的人少走弯路。从那以后我每次拿到头盔检测数据集都强制把第3章那三件事走一遍体检、配对、类别统计训练完再单独看一次head类别的recall。这套流程谈不上高深但它能拦住我重复踩同一批坑。希望帮到你。本文还有配套的精品资源点击获取