简介:本资源为面向疲劳驾驶检测(DMS)场景的YOLO系列目标检测数据集,适用于yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等算法,可直接用于模型训练与验证测试。数据集共8511张图像并配有标签,覆盖未系安全带、唤醒、昏昏欲睡、系安全带、打电话、打哈欠等驾驶员状态类别,适合智能座舱安全监测方向的算法学习与项目实践。压缩包内共2000个文件,以xml标注文件为主,同时提供yolo格式txt与voc格式xml两套标签,分别存放于独立文件夹,并附带data.yaml配置文件,便于快速接入训练流程。目前已有393人学习下载。资源已完成训练集与验证集划分,标签坐标采用归一化格式,读者可直接复现检测流程、验证模型效果,并在此基础上开展类别扩展与调优实验。
1. 8511 张带标签的 DMS 疲劳驾驶数据集:从拿到压缩包到跑通第一轮训练
上周帮一个做车载 DMS 的团队看模型,他们卡在一个很实际的问题上:分类头能识别闭眼,但一遇到「手离开方向盘去拿手机」这种复合动作就崩。翻他们的训练集才发现,全是自己用手机拍的几百张摆拍图,类别只有睁眼闭眼两种。这类需求其实非常典型——疲劳驾驶检测从来不是单标签任务,打哈欠、打电话、没系安全带、昏昏欲睡、唤醒动作,这些状态在真实座舱里是并发出现的。这次拆的这个资源,就是一份 8511 张图像、带 YOLO 格式标签的 DMS 疲劳驾驶员数据集,覆盖没系安全带、唤醒、昏昏欲睡、安全带、电话、打哈欠这几类目标。它解决的不是「有没有数据集」的问题,而是「类别够不够贴近量产 DMS 场景」的问题。适合正在做 YOLOv8 目标识别、想快速验证座舱多状态检测方案的人,也适合拿它当标注格式和类别设计的参考样本。下面按我实际拆包的顺序讲,从目录结构一直讲到训练参数和踩坑。
2. 拆开压缩包先看什么:目录结构、标签格式与类别映射
拿到一个目标检测数据集,我第一件事不是急着写训练脚本,而是先把目录和标签翻一遍。这一步做扎实,后面能省掉大量「训练 loss 不降但不知道哪错了」的时间。这个包的结构是典型的 YOLO 检测数据集布局,图像和标签分离存放,标签是每张图一个 txt。
2.1 目录布局与文件命名规律
解压后大致是这样一个结构,不同人打包习惯略有差异,但核心就两块:images 和 labels。
dataset/ ├── images/ │ ├── train/ │ │ ├── 000001.jpg │ │ └── ... │ └── val/ │ └── ... ├── labels/ │ ├── train/ │ │ ├── 000001.txt │ │ └── ... │ └── val/ │ └── ... └── data.yaml先确认三件事:图像和标签是否同名(只差扩展名)、train/val 是否已经切好、有没有现成的 data.yaml。如果标签和图像不在对应目录,YOLOv8 会直接报「No labels found」,这是最常见的翻车点之一。命名上,图像是 jpg,标签是 txt,一一对应,这个规律必须严格保持,中间任何一张图缺标签,训练时都会被当成背景图处理,反而污染模型。
2.2 YOLO 标签格式逐字段拆解
YOLO 检测标签每行是一个目标,格式固定为五个字段:
class_id x_center y_center width height举个实际例子,一行标签长这样:
2 0.4531 0.6120 0.0875 0.1930含义是:类别索引 2,目标中心点横坐标占整图宽度的 45.31%,纵坐标占 61.20%,目标框宽占 8.75%,高占 19.30%。这里有个新手最容易搞错的点——后四个值全是归一化到 0~1 的相对值,不是像素。如果你拿标注工具导出的是像素坐标,直接喂进去,模型会学到一堆越界的框,训练 loss 会异常大甚至出 NaN。
| 字段 | 含义 | 取值范围 | 常见错误 |
|---|---|---|---|
| class_id | 类别索引,从 0 开始 | 0 ~ N-1 | 与 data.yaml 顺序不一致 |
| x_center | 框中心 x,归一化 | 0 ~ 1 | 误填像素值 |
| y_center | 框中心 y,归一化 | 0 ~ 1 | 误填像素值 |
| width | 框宽,归一化 | 0 ~ 1 | 用绝对宽除以了错误基准 |
| height | 框高,归一化 | 0 ~ 1 | 同上 |
2.3 类别映射与 data.yaml 的对应关系
这个数据集的核心价值在类别设计,它把 DMS 场景拆成了六类:没系安全带、唤醒、昏昏欲睡、安全带、电话、打哈欠。类别顺序必须和标签里的 class_id 严格对应,写错一位,模型就会把「打哈欠」学成「打电话」。data.yaml 一般长这样:
path: ./dataset train: images/train val: images/val names: 0: no_seatbelt 1: wake_up 2: drowsy 3: seatbelt 4: phone 5: yawn注意 names 的键必须从 0 连续编号,中间不能跳号。我见过有人把「安全带」和「没系安全带」顺序写反,结果模型在验证集上指标虚高,一上车全错。改完 yaml 后,建议先跑一遍标签可视化再训练,这一步后面会讲。
3. 用 YOLOv8 跑通训练:环境、配置与关键参数
数据集看明白了,接下来就是让它真正跑起来。这一章按「环境准备 → 配置 → 启动训练 → 看结果」的顺序走,每一步都给可抄的命令和参数解释。YOLOv8 是目前这类 DMS 检测任务里上手最快、生态最全的选择,Ultralytics 的接口把训练流程压得很短,但参数设不对照样白跑。
3.1 环境准备与依赖安装
先建一个干净的虚拟环境,避免和系统里的老版本 torch 打架。CUDA 版本要和显卡驱动匹配,这个不匹配是训练起不来的头号原因。
conda create -n dms_yolo python=3.10 -y conda activate dms_yolo # 安装 pytorch,按自己 CUDA 版本选,这里以 cu118 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 安装 ultralytics pip install ultralytics装完先验证 GPU 是否可用,这一步别省:
import torch print(torch.cuda.is_available()) # 期望 True print(torch.cuda.get_device_name(0)) # 打印显卡型号如果返回 False,先别怀疑代码,八成是 CUDA 版本和驱动对不上,或者装成了 CPU 版 torch。显存方面,8511 张图用 yolov8n 或 yolov8s 在 8G 显存上跑 batch=16 基本够用,想上 yolov8m 就得把 batch 降到 8 或开 AMP 混合精度。
3.2 训练脚本与参数逐项说明
Ultralytics 的训练入口非常简洁,但每个参数都影响结果。下面这份是我在这个数据集上常用的配置:
from ultralytics import YOLO # 加载预训练权重,从 COCO 迁移能明显加快收敛 model = YOLO("yolov8s.pt") results = model.train( data="dataset/data.yaml", # 指向你的 data.yaml epochs=100, # 轮数,小数据集 100 起步 imgsz=640, # 输入尺寸,DMS 场景 640 够用 batch=16, # 按显存调,爆显存就减半 device=0, # 用第 0 号 GPU workers=8, # 数据加载线程,Windows 下调小 patience=20, # 20 轮无提升就早停 lr0=0.01, # 初始学习率 lrf=0.01, # 最终学习率系数 augment=True, # 开启内置增强 cache=True, # 小数据集缓存到内存加速 project="runs/dms", # 结果保存目录 name="exp1" )逐项说下为什么这么设。imgsz=640 是 YOLOv8 的默认训练尺寸,DMS 图像里目标(手、手机、安全带)尺度中等,640 能兼顾速度和精度,盲目上 1280 只会拖慢训练。batch=16 是显存和梯度的折中,太小梯度噪声大,太大泛化差。patience=20 是后悔药,防止过拟合后还傻跑。cache=True 对 8511 张这种规模很友好,第一次读盘后常驻内存,后续 epoch 速度能快一截,但内存小于 16G 的机器慎开。
3.3 训练过程监控与结果解读
训练启动后,终端会实时打印每个 epoch 的 box_loss、cls_loss、mAP50 等指标。重点盯两个:cls_loss 是否稳定下降,mAP50 是否在涨。如果 cls_loss 震荡剧烈,多半是学习率偏大或标签有脏数据;如果 mAP50 早早卡住不动,先怀疑类别不平衡。
训练结束后,结果都在 runs/dms/exp1 下,几个关键文件:
| 文件/目录 | 内容 | 用途 |
|---|---|---|
| weights/best.pt | 验证集最优权重 | 部署和推理用这个 |
| weights/last.pt | 最后一轮权重 | 断点续训用 |
| results.csv | 每轮指标记录 | 画曲线分析 |
| confusion_matrix.png | 混淆矩阵 | 看类别间误判 |
| val_batch*.jpg | 验证集预测可视化 | 肉眼检查漏检误检 |
混淆矩阵特别值得看。DMS 数据集里「昏昏欲睡」和「打哈欠」容易混,「安全带」和「没系安全带」也容易互相误判,因为两者视觉特征高度相似,只差一条带子。如果这两对在矩阵里交叉严重,说明特征区分度不够,要么加数据,要么在类别定义上再细化。
3.4 推理验证:拿一张图看真实效果
训练完别只看指标,一定要拿真实图跑一遍推理,指标好看但实际漏检的情况太常见了。
from ultralytics import YOLO model = YOLO("runs/dms/exp1/weights/best.pt") results = model.predict( source="test_images/", # 可以是单图、目录或视频 conf=0.25, # 置信度阈值 iou=0.45, # NMS 的 IoU 阈值 save=True, # 保存带框结果 device=0 )conf=0.25 是默认值,DMS 场景如果漏检严重可以降到 0.15 试试,但会引入更多误检,需要权衡。iou=0.45 控制重叠框合并,同一目标被重复框出时调小这个值。推理结果图会存到 runs/detect/predict 下,逐张看,重点看小目标和遮挡目标——手部遮挡、夜间低照度是 DMS 的两大难点。
4. 避坑与排查:标签、显存、类别不平衡的五个真实翻车点
这一章是我和几个做 DMS 的同行踩过的坑汇总,每条都按「现象 → 原因 → 解决」写。数据集本身没问题,但用法不对,照样训不出能用的模型。
4.1 训练报 No labels found
现象:启动训练几秒后直接抛错,提示找不到标签文件。
原因:data.yaml 里的 train/val 路径写错,或者图像和标签没放在对应目录。YOLO 默认会在 images 同级找 labels,路径结构不对就找不到。
解决:确认 images/train 和 labels/train 是同级目录,且文件名一一对应。可以写个脚本快速核对:
import os img_dir = "dataset/images/train" lbl_dir = "dataset/labels/train" imgs = {os.path.splitext(f)[0] for f in os.listdir(img_dir)} lbls = {os.path.splitext(f)[0] for f in os.listdir(lbl_dir)} print("有图无标签:", imgs - lbls) print("有标签无图:", lbls - imgs)两边差集都为空才算干净。
4.2 训练中途 CUDA out of memory
现象:跑了几十个 epoch 突然爆显存,或者一开始就 OOM。
原因:batch 太大、imgsz 太高,或者 cache=True 把数据全塞进内存后显存被挤占。
解决:先把 batch 减半,再把 imgsz 从 640 降到 512 试。如果开了 cache,内存吃紧就关掉。另外 workers 设太大也会占资源,Windows 上建议设 0 或 2。
4.3 某几个类别 mAP 一直很低
现象:整体 mAP50 有 0.8,但「没系安全带」这类只有 0.4。
原因:类别样本数严重不平衡,或者该类目标太小、遮挡太多。DMS 里「没系安全带」往往只露出安全带一小段,特征弱。
解决:先统计各类别框数量,对少样本类做过采样或复制增强;也可以在训练时给类别加权,或者干脆把相似类合并再细分。统计脚本:
import os from collections import Counter lbl_dir = "dataset/labels/train" counter = Counter() for f in os.listdir(lbl_dir): with open(os.path.join(lbl_dir, f)) as fp: for line in fp: cls = int(line.split()[0]) counter[cls] += 1 print(sorted(counter.items()))4.4 验证集指标虚高,实车全错
现象:val mAP 很漂亮,但拿真实座舱视频一测,漏检误检一堆。
原因:训练集和验证集来自同一批拍摄条件,分布太像,模型没学到泛化特征。或者标签里有系统性错误,比如把「打电话」标成了「唤醒」。
解决:手动抽 50 张验证集图,用可视化脚本把框画出来肉眼过一遍。分布上尽量让 train/val 覆盖不同光照、不同驾驶员。标签错误只能靠人工复核,没有捷径。
4.5 标签坐标越界导致 loss 异常
现象:训练 loss 一开始就是几百甚至 NaN。
原因:标签里有像素坐标没归一化,或者归一化时除错了基准(比如用宽除了高)。
解决:写个校验脚本,检查每行后四个值是否都在 0~1:
import os lbl_dir = "dataset/labels/train" bad = [] for f in os.listdir(lbl_dir): with open(os.path.join(lbl_dir, f)) as fp: for i, line in enumerate(fp): parts = line.split() vals = [float(v) for v in parts[1:]] if any(v < 0 or v > 1 for v in vals): bad.append((f, i, line.strip())) print("越界标签数:", len(bad)) for b in bad[:10]: print(b)发现越界就回到标注工具重新导出,别想着在训练里硬扛。
5. 进阶技巧:标签可视化复核与迁移到自定义 DMS 场景
数据集跑通只是第一步,真正让它产生价值的是两件事:训练前把标签复核一遍,训练后把模型迁移到自己的场景。这一章讲我常用的两个具体技巧,都是能直接抄的。
5.1 训练前必做的标签可视化复核
我现在的习惯是,任何数据集进训练前,先随机抽 20 张把框画出来看。这一步能提前发现 80% 的标签问题。用 OpenCV 写个轻量脚本:
import cv2 import os import random img_dir = "dataset/images/train" lbl_dir = "dataset/labels/train" names = ["no_seatbelt", "wake_up", "drowsy", "seatbelt", "phone", "yawn"] colors = [(255,0,0),(0,255,0),(0,0,255),(255,255,0),(255,0,255),(0,255,255)] samples = random.sample(os.listdir(img_dir), 20) for f in samples: img = cv2.imread(os.path.join(img_dir, f)) h, w = img.shape[:2] lbl_path = os.path.join(lbl_dir, os.path.splitext(f)[0] + ".txt") if not os.path.exists(lbl_path): continue with open(lbl_path) as fp: for line in fp: c, x, y, bw, bh = line.split() c = int(c) x, y, bw, bh = float(x)*w, float(y)*h, float(bw)*w, float(bh)*h x1, y1 = int(x-bw/2), int(y-bh/2) x2, y2 = int(x+bw/2), int(y+bh/2) cv2.rectangle(img, (x1,y1), (x2,y2), colors[c], 2) cv2.putText(img, names[c], (x1, y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, colors[c], 1) cv2.imwrite(f"check_{f}", img)跑完打开 check_ 开头的图,重点看三样:框有没有偏、类别名对不对、有没有漏标的目标。漏标比错标更隐蔽,因为模型会把漏标目标当背景学,直接拉低召回。这个脚本我每次换数据集都跑,已经成了肌肉记忆。
5.2 迁移到自定义 DMS 场景的微调策略
如果你手上只有少量自己场景的图,别从零训,用这个数据集训出的权重做起点,冻结 backbone 先微调检测头:
from ultralytics import YOLO model = YOLO("runs/dms/exp1/weights/best.pt") model.train( data="my_dms/data.yaml", epochs=50, imgsz=640, batch=8, freeze=10, # 冻结前 10 层,只训检测头 lr0=0.001, # 微调学习率要小 project="runs/my_dms", name="finetune" )freeze=10 冻结主干浅层,保留通用特征,只让检测头适配新类别。lr0 调到 0.001 是因为预训练权重已经很好,大学习率会把学到的特征冲掉。等检测头稳定后,再解冻全部层做一轮小学习率全量微调,通常能再涨几个点。这套流程我在几个座舱项目里反复用,比直接从头训省一半以上数据。
5.3 一个容易忽略的验证习惯
最后说个习惯。每次训完,我都会把 best.pt 在一段真实视频上跑一遍,而不是只看验证集图片。视频能暴露时序上的抖动——比如同一帧里「安全带」和「没系安全带」来回跳,这种闪烁在静态图上根本看不出来。跑视频的命令很简单:
yolo predict model=runs/dms/exp1/weights/best.pt source=test_video.mp4 conf=0.3 save=True看完视频再决定要不要调 conf 或加时序后处理。从那以后我每次交付 DMS 模型前,都强制走一遍「标签可视化 + 视频推理」这两步,指标再好看也不跳过。希望帮到你。
本文还有配套的精品资源,点击获取