ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

YOLOv8实战:8979张图像嗜睡数据集训练与避坑指南

YOLOv8实战:8979张图像嗜睡数据集训练与避坑指南 简介适用于疲劳驾驶与分心行为检测的yolo算法嗜睡数据集包含8979张带标签图像覆盖头部下垂、唤醒、昏昏欲睡、分心、吸烟、打哈欠、电话等典型状态面向使用yolov5/v7/v8/v9/v10/yolo11等系列算法的开发者解决模型训练数据准备难题。压缩包共2000个文件主要为voc格式xml标签同时提供yolo格式txt标签两种格式分别存放并附带已划分好的数据集配置文件data.yaml可直接开展训练与验证测试。包体大小172.36MB目录结构清晰无需额外标注或划分操作。目前已有91人学习下载适合算法工程师、研究生及竞赛选手快速上手拿到即可用于疲劳检测相关项目显著缩短数据准备与处理周期。1. 嗜睡数据集上车实测8979张图到底能训练出什么模型做驾驶员监控系统DMS的人都会撞上同一个问题公开的疲劳检测数据集不是场景太单一就是标签类别含糊真正能拿来直接训 YOLO 的更少。这个名为“yolo算法-嗜睡数据集-8979张图像带标签”的压缩包我拿到后的第一反应是先把七个类别过了一遍——头部下垂、唤醒、昏昏欲睡、分心、吸烟、打哈欠、电话。这七个标签覆盖的不只是“闭眼”这一个动作而是把驾驶员行为分成了姿态类头部下垂、状态类昏昏欲睡、动作类打哈欠、吸烟、打电话和干扰类分心正好对应真实 DMS 产品要识别的几类高风险场景。8979 张图不算大但带完整标签、能直接转 YOLO 格式已经足够跑通一个可用的检测基线。适合谁用做车载视觉方案验证的工程师、需要快速拿数据集跑通训练流程的学生以及想评估“这套标注质量能不能支撑产品原型”的算法负责人。2. 拆开压缩包先看数据目录结构、标签格式与类别分布2.1 解压后别急着训练先确认目录结构和标注形式拿到 zip 后第一步不是解压就跑训练而是先把目录结构完整列出来。常见做法是先用tree或find看一眼确认图像和标签是放在同一级目录还是像典型 YOLO 数据集那样分成了images和labels两个兄弟目录。unzip yolo算法-嗜睡数据集-8979张图像带标签-头部下垂-唤醒-昏昏欲睡-分心-吸烟-打哈欠-电话.zip -d drowsy_dataset cd drowsy_dataset find . -maxdepth 2 -type d | sort这里-d指定解压目标目录避免把几百张图直接散落在当前文件夹里。find的-maxdepth 2只往下看两层目录够判断结构又不会刷出太多文件路径。我习惯在解压后顺手统计一下图片总数确认和标题标注的 8979 张对得上。find . -name *.jpg -o -name *.jpeg -o -name *.png | wc -l如果数量对不上先排查是不是解压中断或目录里混了非图像文件。这个数字是你后面判断数据集是否完整、训练集验证集划分是否合理的基准值得多花一分钟确认。2.2 YOLO 标签格式与类别 id 映射txt 文件里到底写了什么YOLO 格式的标签不是 XML 或 JSON而是每个图像对应一个同名的.txt文件每行代表一个目标框格式是class_id x_center y_center width height其中坐标是相对图像的归一化值。看一个实际标签文件能快速确认数据集的标注风格是否统一。cat labels/000001.txt # 预期输出示例每行一个目标 # 5 0.418750 0.421875 0.145833 0.187500 # 1 0.564583 0.531250 0.120833 0.145833第一列是类别 id后面四列是归一化框坐标。需要特别检查的是类别 id 与名称的对应关系——这个数据集有 7 个类别训练前必须写清楚 id 0 到 6 分别对应“头部下垂、唤醒、昏昏欲睡、分心、吸烟、打哈欠、电话”中的哪一个。如果你的类别顺序和数据集作者不一致训练出来的模型在部署时就是张冠李戴。2.3 用脚本统计类别分布看哪类样本少得可怜训练前统计每个类别的标注框数量比看图片数量更能暴露问题。有的类别可能有 3000 个框有的只有 200 个。类别不均衡在目标检测里是常态但如果某个类别样本过少后面训练时它的 mAP 大概率会拖后腿。import os from collections import Counter label_dir labels counter Counter() for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue with open(os.path.join(label_dir, fname), r) as f: for line in f: cls_id int(line.strip().split()[0]) counter[cls_id] 1 class_names [head_drop, awake, drowsy, distracted, smoking, yawning, phone] for i in range(7): print(fclass {i} ({class_names[i]}): {counter[i]} boxes)这段脚本遍历所有标签文件用Counter统计每个类别 id 出现的总次数。line.strip().split()[0]取出每行第一个字段类别 id并转成整数。运行结果如果发现“电话”只有一两百个框而“唤醒”有两千多个后面的训练策略就要针对这个分布做调整——比如对稀缺类别做过采样或者用数据增强扩大样本量。3. 用 YOLOv8 跑通嗜睡检测训练从目录整理到损失曲线判读3.1 整理数据集目录YOLO 训练前必须有 images 和 labels 平级目录YOLOv8 的detect任务对数据集目录约定很严格images 和 labels 必须在同一父目录下平级图像文件名和标签文件名必须完全一致后缀不同而且要按 train/val 划分好子目录。常见做法是手动按 9:1 比例划出验证集。mkdir -p dataset/images/train dataset/images/val mkdir -p dataset/labels/train dataset/labels/val # 按 9:1 划分先把所有文件打乱再分配 shuf -i 1-8979 -n 8080 | sort -n train_ids.txt for id in $(cat train_ids.txt); do mv images/${id}.jpg dataset/images/train/ mv labels/${id}.txt dataset/labels/train/ done mv images/*.jpg dataset/images/val/ 2/dev/null mv labels/*.txt dataset/labels/val/ 2/dev/null这里shuf -i 1-8979 -n 8080生成 8080 个不重复的随机序号作为训练集sort -n保证顺序不乱。注意这里假设图像文件名就是纯数字序号如果你的文件命名不规律建议改成用find拿到全部文件名再shuf打乱后按比例切分。划分完以后花一分钟数一下验证集图片数应该剩 899 张左右。3.2 写数据集 yaml七个类别的 id 和名称必须和标签文件对应YOLOv8 训练前需要一个.yaml文件描述数据集路径和类别列表。这个文件写错是最常见的低级错误——类别名称顺序必须和标签文件里的 id 一一对应不是按你“觉得合理”的顺序排。# drowsy.yaml path: ./dataset train: images/train val: images/val names: 0: head_drop 1: awake 2: drowsy 3: distracted 4: smoking 5: yawning 6: phonepath是相对于你执行训练命令的工作目录的路径。names的 key 必须是 0 到 6 的整数顺序不能乱。这里我把类别名按标题出现的顺序映射实际使用中如果你发现数据集作者提供过单独的classes.txt以那个文件里的顺序为准。3.3 训练命令与关键超参从 YOLOv8n 开始还是直接上 YOLOv8m8979 张图的数据量我用 YOLOv8n 起步比较稳妥。n 模型参数量小跑一轮验证速度很快能快速判断标签质量和数据划分有没有大问题。等确认 baseline 没问题再换 v8m 或者 v8l 榨精度。yolo detect train \ datadrowsy.yaml \ modelyolov8n.pt \ epochs50 \ imgsz640 \ batch16 \ workers4 \ project./runs \ namedrowsy_v8n \ patience10patience10表示验证集指标连续 10 个 epoch 不提升就早停能省时间imgsz640是 YOLOv8 默认的输入分辨率对车载摄像头拍摄的中近景人脸目标够用。如果你的图像本身分辨率很高但目标区域偏小可以试imgsz960但训练时间会增加约一倍。batch16在 12GB 显存的卡上跑 v8n 没问题如果你的卡只有 8GB降到 8 或者开ampTrue默认开启的混合精度。3.4 损失曲线和验证指标怎么看训练有没有翻车训练过程中要盯两个东西box_loss和clf_loss是否平滑下降以及val/box_loss有没有在某个 epoch 后掉头向上。val 损失持续上升而 train 损失还在降就是过拟合的典型信号。# 训练结束后查看验证集各类别指标 yolo val modelruns/drowsy_v8n/weights/best.pt datadrowsy.yaml注意看输出里每个类别的mAP50和mAP50-95。如果某个类别特别低比如“电话”的 mAP50 只有 0.2而其他类都在 0.8 以上这就是类别样本不足或者特征混淆导致的不是整体模型的问题。后续要针对这个类别单独处理而不是盲目加大训练轮数。4. 嗜睡数据集训练避坑指南5 个我踩过的坑4.1 标签错位类别 id 和名称对不上现象训练时 loss 正常下降但验证集的 PR 曲线里某些类别的 AP 是 0。原因数据集的classes.txt顺序和你在 yaml 里写的 names 顺序不一致。比如作者把“吸烟”放在 id0而你把“头部下垂”放在 id0模型学到的特征全部错位。解决训练前随机挑 3-5 张图手动用matplotlib把标注框画出来框旁边写上类别名称。这一步只需要五分钟但能避免整个训练白跑。不要完全信任压缩包里的任何说明文档以标签文件的实际内容为准。4.2 小目标漏检人脸区域太小导致 mAP 虚高现象整体 mAP50 有 0.85但实际跑视频检测时距离摄像头稍远的人脸完全检测不到。原因车载摄像头画面里人脸占比通常很小而 640x640 的输入分辨率会把小目标压缩到几十个像素。mAP 虚高是因为验证集里大部分目标本身比较大。解决训练时把imgsz提到 960同时开启 YOLOv8 的augment里对小目标友好的增强项。如果显存有限可以先训练一个 640 的模型再用 960 分辨率做微调modelbest.pt imgsz960。这类数据集里“头部下垂”和“昏昏欲睡”的标注框往往覆盖整个头肩区域目标大小波动很大这个坑几乎必踩。4.3 数据划分不当时序连续帧导致验证集“开卷考试”现象训练集 mAP 很高但验证集指标也不错部署到真实视频流里效果崩盘。原因这个数据集的图像可能是从视频里抽帧得到的相邻帧高度相似。如果划分 train/val 时直接按文件序号顺序切片同一段视频的帧会同时出现在训练集和验证集里验证指标虚高。解决划分前先看文件命名。如果文件是连续数字序号先用sort -R打乱再划分或者按间隔抽帧比如每隔 10 帧抽 1 帧进验证集。更稳妥的做法是直接按视频片段分组但压缩包里如果没有提供分组信息打乱划分是最现实的手段。4.4 打哈欠与说话特征混淆分类边界模糊导致误报现象模型把正常说话识别成打哈欠或者把揉眼睛识别成昏昏欲睡。原因打哈欠时嘴巴张大的程度和说话时嘴部张开很接近单帧图像里这两类目标的信息量不足以区分。这是数据本身的标注主观性带来的——不同标注人员对“打哈欠”和“张嘴说话”的判定标准不同。解决一种方法是训练时把这两类合并成“distracted”再训练牺牲细粒度换精度另一种是保持原类别但部署阶段对这两类的置信度阈值调高比如从 0.25 调到 0.45宁可漏检也不误报。真实 DMS 产品里误报比漏报更容易导致用户关掉系统这个取舍值得提前想清楚。4.5 模型直接不收敛标签文件里有空文件或异常框现象训练 loss 在第一个 epoch 就出现 NaN或者训练到一半突然崩掉。原因数据集里存在空标签文件0 字节或者异常标注——比如框的中心坐标超出 [0,1] 范围、框宽高为负数。解决训练前跑一遍数据清洗脚本。检查所有标签文件删除空文件过滤掉坐标小于 0 或大于 1 的行。空标签文件对应的图像可以直接从数据集里删掉或者移到单独目录避免 YOLOv8 在数据加载阶段报错。import os label_dir labels img_dir images removed 0 for fname in os.listdir(label_dir): path os.path.join(label_dir, fname) if os.path.getsize(path) 0: os.remove(path) img_path os.path.join(img_dir, fname.replace(.txt, .jpg)) if os.path.exists(img_path): os.remove(img_path) removed 1 continue valid_lines [] with open(path, r) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue c, x, y, w, h float(parts[0]), float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) if 0 x 1 and 0 y 1 and w 0 and h 0: valid_lines.append(line.strip()) with open(path, w) as f: f.write(\n.join(valid_lines)) print(fremoved {removed} empty label files)这个脚本先处理空文件再逐行过滤异常坐标。w 0 and h 0保证宽高为正。注意如果你的图像后缀不是.jpg需要改第三行的扩展名。跑完以后重新数一次标签数量确认清洗后数据量和清洗前差别在可接受范围内。5. 绕过类别不均衡数据增强、重采样和置信度阈值三板斧5.1 先调内置增强参数再考虑外部生成样本YOLOv8 的augment参数默认全开但默认值不一定适合这个数据集。我在训练时一般会把hsv_h和hsv_s调小一些因为车载摄像头的色彩偏移通常不大过度的色彩增强会让模型学到不真实的颜色分布。mosaic默认是 1.0也就是每张训练图都由 4 张图拼出来对小目标检测有明显帮助但如果你发现训练早期 loss 震荡剧烈可以降到 0.5 试一下。yolo detect train \ datadrowsy.yaml \ modelyolov8n.pt \ epochs80 \ imgsz640 \ batch16 \ mosaic0.7 \ hsv_h0.01 \ hsv_s0.3 \ hsv_v0.3 \ degrees10 \ translate0.1 \ fliplr0.5degrees10限制旋转角度在正负 10 度以内避免大幅旋转破坏头部姿态的真实性。translate0.1允许轻微平移模拟驾驶员头部在画面中移动的场景。fliplr0.5是水平翻转对对称类别人脸目标安全但注意它会翻转“分心”类目标的方向语义如果“分心”特指看向右侧后视镜水平翻转后会变成看左侧对训练造成误导。5.2 重采样给稀缺类别加权重比复制粘贴更有效如果类别分布严重不均衡最简单的办法是训练时修改 YOLOv8 损失函数里的cls权重对稀缺类别加强惩罚。但 YOLOv8 没有直接暴露 per-class 权重参数所以更实用的做法是训练前对稀缺类别的图像做重采样——把包含稀缺类别的图像复制一份放进训练集。# 找到包含类别 6phone的所有图像复制一份到训练集 grep -l ^6 dataset/labels/train/*.txt | while read f; do base$(basename $f .txt) cp dataset/images/train/${base}.jpg dataset/images/train/${base}_dup.jpg cp $f dataset/labels/train/${base}_dup.txt donegrep -l ^6 会列出所有以6开头的标签文件也就是包含“电话”类别目标的图像。复制时同时复制图像和标签文件名加_dup后缀避免覆盖原文件。注意复制后一个 epoch 里这些图像会被采样两次相当于过采样。复制你的数据集如果差距特别大复制两三份也会导致模型在稀缺类别上过拟合建议复制后观察验证集的该类 AP 变化涨了就是有效跌了说明已经过拟合。5.3 置信度阈值部署阶段控制误报的最后一道闸训练结束后部署时.pt权重可以设置检测阈值来调节误报与漏报的平衡。YOLOv8 预测时默认conf0.25对“昏昏欲睡”这种本身就是低强度状态的目标如果设太高会漏掉很多真实正样本。yolo predict modelruns/drowsy_v8n/weights/best.pt \ sourcetest_video.mp4 \ conf0.35 \ iou0.45 \ imgsz640conf0.35意味着低于 35% 置信度的框会被过滤。如果你在真实场景里发现误报太多比如把乘客的头部下垂识别成驾驶员昏昏欲睡先把conf调到 0.5 试效果如果漏检太多降到 0.2。iou0.45控制 NMS 的框合并阈值目标有遮挡时适当调低到 0.4 能减少重复框。6. 从实验到实车ONNX 导出和低成本上线方案模型训练完只是第一步真正要跑到车载设备上需要把 PyTorch 模型转换成推理框架能吃的格式。我用得最多的是先转 ONNX再视平台转换成 TensorRT 或 OpenVINO。yolo export modelruns/drowsy_v8n/weights/best.pt formatonnx imgsz640 opset12opset12是为了兼容性。导出后先用onnxruntime验证输出是否和 PyTorch 一致再决定要不要做量化。量化和部署前先单帧推理验证转换后没有精度损失。实测这个数据集的检测任务对边缘设备友好因为推理耗时主要取决于输入分辨率。v8n 模型在 640 分辨率下边缘设备的单帧推理时间通常可控制在 30ms 以内。如果帧率还不够优先降分辨率而不是换小模型因为人脸检测对分辨率敏感过度降低输入尺寸会导致小目标漏检。我的习惯是最后跑一段十分钟的真实视频流记录每帧的推理耗时和检测结果确认没有内存泄漏。边缘设备上常见的问题是连续推理几个小时后显存或内存持续上涨最终导致推流中断。这个坑不真正长时间跑很难暴露等部署上线再发现就麻烦了。如果你准备用这套数据训练出的模型做产品验证我的建议是先定好类别粒度——是保留七分类拿细粒度还是先做“唤醒状态 vs 非唤醒状态”的二分类保证精度。从实际落地来看后者在真实场景里更容易满足验收指标。希望这篇拆解能帮你把 8979 张图真正训练成能用的模型少走几步弯路。如果你也在这个数据集上踩过类似的坑欢迎带着具体现象再来讨论。希望帮到你。本文还有配套的精品资源点击获取
返回列表