ARTICLE DETAIL

资讯详情

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

yolov5座舱行为检测:从数据标注到边缘部署全流程

yolov5座舱行为检测:从数据标注到边缘部署全流程 简介这份资源面向计算机视觉与智能交通方向的开发者提供一套基于Yolov5的驾驶员行为检测完整工程可识别困倦、抽烟、喝水、打电话等危险驾驶状态适合课程设计、毕业项目或车载监控原型开发。压缩包共132个文件约88.34MB以59个Python源码与44个编译文件为主体配合18个YAML配置、预训练权重best.pt、人脸关键点数据文件及Dockerfile覆盖模型加载、数据配置与部署环节。目前已有1318人学习下载。资源内含Yolov5网络架构与检测头实现、数据集配置脚本、训练与推理代码以及基于面部特征与手部动作的行为判别逻辑读者可据此完成模型微调、实时视频流检测与告警功能扩展快速搭建可运行的驾驶员监测系统。1. 驾驶员困倦检测与危险驾驶行为识别yolov5 能一次搞定几件事高速上跑长途最怕的不是车多而是眼皮开始打架、手不自觉去摸烟、低头看手机那两秒。驾驶员困倦检测和危险驾驶检测这类需求落到工程上其实就是一个多类别目标检测问题把闭眼、打哈欠、抽烟、喝水、打电话这些动作从座舱画面里框出来。yolov5 之所以被大量拿来做这件事不是因为它有多新而是它训练快、部署链路成熟、小目标在 640 输入下还能接受配合树莓派或 RK3568 这类边缘板子也能跑出可用帧率。这篇笔记面向的是想自己训一版座舱行为检测模型、并且准备往嵌入式端落的工程师从数据集怎么标、yolov5 怎么改、参数怎么调一直讲到部署前必须避开的坑。如果你只是想知道 yolov5 网络结构图长什么样那网上图很多但要把困倦和抽烟喝水打电话同时检出来靠的是数据配比和类别定义不是换个 backbone 就能解决的事。2. 座舱行为检测的类别定义与数据准备别一上来就标 8 个类2.1 先想清楚要检哪些类再决定标多少很多人拿到 yolov5 就想把所有能想到的行为都塞进去闭眼、打哈欠、抽烟、喝水、打电话、低头、转头、手离方向盘。结果训出来每一类都半死不活。座舱场景里类别之间是互相抢特征的——抽烟和打电话都有手靠近脸的动作喝水和抽烟都有手到嘴边的轨迹闭眼和低头在低分辨率下几乎一样。我的做法是先分两级一级是安全强相关的闭眼、打哈欠、打电话、抽烟二级是辅助判断的喝水、低头。如果算力只够跑一个模型就先把一级做扎实二级用时序逻辑去补而不是硬塞进检测头。类别命名也要克制。常见做法是用英文短名比如closed_eye、yawn、phone、smoke、drink不要用driver_is_smoking这种长名标注工具和后续脚本处理起来都别扭。类别顺序一旦定下来整个项目里就不能再变因为 yolov5 的data.yaml里names的顺序直接对应标签文件里的 class id改一次就要重训。2.2 数据采集与标注的四个硬约束座舱数据和通用 COCO 完全不是一个分布。采集时要注意第一光照。白天逆光、隧道明暗交替、夜间红外补光这三种必须都有否则模型一出地库就翻车。第二角度。摄像头一般装在 A 柱或后视镜附近俯角大概 15 到 30 度采集时要固定这个视角不要一会儿正脸一会儿侧脸混着标。第三遮挡。方向盘会挡手口罩会挡嘴墨镜会挡眼这些样本要专门补不然模型学到的是「看到方向盘就认为没抽烟」。第四负样本。正常驾驶、双手扶方向盘、目视前方的样本要占相当比例否则模型会把「手在脸附近」一律判成打电话。标注用 labelImg 或 CVAT 都行输出 YOLO 格式的 txt每行class_id x_center y_center width height全部归一化到 0 到 1。这里有个血泪经验闭眼这种小目标框要贴着上下眼睑不要框整个头部否则模型学出来的是「检测头」而不是「检测闭眼」。2.3 目录结构与 data.yaml 的最小配置yolov5 对目录结构有约定按下面这样放最省事dataset/ images/ train/ val/ labels/ train/ val/对应的data.yaml# 座舱行为检测数据集配置 path: ./dataset # 数据集根目录 train: images/train # 训练集图片相对路径 val: images/val # 验证集图片相对路径 nc: 5 # 类别数必须和 names 长度一致 names: # 顺序即 class_id定下后不可改 0: closed_eye 1: yawn 2: phone 3: smoke 4: drink逻辑说明path是根train和val是相对path的路径yolov5 会自动把images替换成labels去找标签。参数上nc写错是最常见的报错来源多一个少一个都会在训练启动时直接抛维度不匹配。names用字典或列表都行但顺序必须和标注时的 class id 对齐。验证集建议占总量 15% 到 20%且要包含夜间和逆光样本否则mAP虚高部署就露馅。3. yolov5 训练自己的数据集从 clone 到第一次收敛3.1 环境与依赖别在版本上浪费时间yolov5 对 PyTorch 和 CUDA 版本比较敏感我一般用 Python 3.8 到 3.10PyTorch 1.12 以上CUDA 11.6 或 11.8。装依赖就两步# 拉取 yolov5 代码用官方仓库即可 git clone https://github.com/ultralytics/yolov5 cd yolov5 # 安装依赖requirements 里已锁定版本 pip install -r requirements.txt逻辑说明requirements.txt里已经写好了torch、torchvision、opencv-python等版本范围直接装比自己一个个 pip 稳。如果机器有 GPU装完用python -c import torch; print(torch.cuda.is_available())确认返回 True返回 False 就是 CUDA 和 torch 版本没对上先解决这个再往下走不然后面训练慢到怀疑人生。3.2 用预训练权重起步改两个关键参数座舱数据量通常不大几千到几万张从零训基本收敛不了。用官方预训练权重做迁移python train.py \ --weights yolov5s.pt \ # 预训练权重s 版本适合边缘部署 --data data.yaml \ # 上一步配好的数据集 --epochs 150 \ # 座舱数据一般 100-200 轮够 --batch-size 16 \ # 按显存调8G 显存用 16 --img 640 \ # 输入尺寸和部署端保持一致 --hyp data/hyps/hyp.scratch-low.yaml \ # 小数据集用 low 增强 --cache # 图片缓存到内存加速训练逻辑说明--weights决定起点yolov5s.pt在精度和速度之间平衡最好座舱这种类别少、目标大的场景够用。--img 640要和后面部署时的输入尺寸一致训练用 640 部署用 320精度会掉一截。--hyp选hyp.scratch-low.yaml是因为座舱数据量小默认增强太猛容易过拟合到增强后的分布。--cache在内存够的时候能明显提速内存不够会 OOM看情况加。3.3 训练过程看什么指标什么时候该停启动后重点盯三个输出box_loss、obj_loss、mAP0.5。box_loss和obj_loss应该在前 20 轮快速下降然后趋缓如果一直震荡不降多半是学习率太大或标签有问题。mAP0.5在座舱场景里闭眼和打电话能到 0.9 以上算正常抽烟和喝水因为动作相似0.7 到 0.8 就可用。早停用--patience 3030 轮没提升就停省时间。训练完权重在runs/train/exp/weights/下best.pt是验证集最好的last.pt是最后一轮。部署用best.pt但别迷信它有时候last.pt在夜间样本上反而更稳两个都测一下。3.4 验证与推理先看混淆矩阵再谈部署训练完先跑验证python val.py \ --weights runs/train/exp/weights/best.pt \ --data data.yaml \ --img 640 \ --conf-thres 0.25 \ # 置信度阈值座舱场景别设太高 --iou-thres 0.45 # NMS 的 IoU 阈值逻辑说明--conf-thres 0.25是座舱场景的常用起点因为闭眼这种目标模型给的分普遍不高设 0.5 会漏检。--iou-thres 0.45控制重叠框合并抽烟和打电话如果框重叠多可以适当调低到 0.4。跑完看runs/val/exp/confusion_matrix.png如果phone大量被误判成smoke说明这两类特征没分开要么补数据要么合并成一个「手持动作」类再靠时序区分。推理单张图python detect.py \ --weights runs/train/exp/weights/best.pt \ --source test.jpg \ --img 640 \ --conf-thres 0.25这一步主要是肉眼确认框的位置和类别对不对尤其是闭眼的框有没有框到眉毛上。4. 困倦与危险驾驶检测的避坑与排查翻车大多不在模型4.1 闭眼检不出来先查标注再查输入尺寸现象验证集mAP正常但实际视频里闭眼几乎不触发。原因通常是闭眼目标太小640 输入下眼睛区域只有十几个像素特征在 backbone 下采样后基本丢了。解决把输入提到 960 或 1280 重训一版或者单独裁一个眼部 ROI 做二级分类。另一个原因是标注时框了整个头模型学的是头部特征闭眼和睁眼区分度不够回去重标。4.2 抽烟和打电话互相误判是类别定义的问题现象模型把打电话判成抽烟或者反过来。原因这两类都有手靠近脸的动作单帧特征高度重叠。解决第一补数据时专门拍「手拿烟但没点」「手拿手机贴耳」的对比样本第二如果还是分不开就在后处理里加时序连续 5 帧以上同一位置才输出单帧抖动过滤掉第三实在不行合并成hand_to_face一类再用一个小的分类网络区分手里拿的是什么。4.3 训练 loss 不降八成是标签路径或类别数错了现象训练启动后box_loss一直在 1.0 以上不降。原因data.yaml里nc和实际类别数不一致或者labels目录下有空文件、有超出 0 到 1 范围的坐标。解决先跑一遍官方自带的检查脚本思路——遍历所有标签文件确认每行 5 个值、class_id 在[0, nc-1]、坐标在[0,1]。有空标签文件直接删掉yolov5 遇到空标签会当成背景少量没事大量就会带偏。4.4 树莓派上跑不动先量化再谈帧率现象PC 上 30 FPS树莓派 4B 上 2 FPS。原因yolov5s 在 ARM CPU 上没优化PyTorch 默认推理也没量化。解决导出 ONNX 再用 NCNN 或 ONNX Runtime 量化到 INT8树莓派 4B 上能到 8 到 12 FPS树莓派 5 上更好。RK3568 这类带 NPU 的板子用 RKNN 工具链转量化后能到 20 FPS 以上。注意量化时要用座舱数据做校准集别用 COCO 的图否则闭眼这种小目标量化后直接消失。4.5 夜间红外画面全黑模型输出乱框现象白天正常夜间红外下模型到处乱框。原因训练集里夜间样本太少模型没见过红外分布。解决采集时夜间样本至少占 20%标注时红外下的闭眼和抽烟要单独检查。如果已经训完不想重来可以在推理前加一个简单的亮度判断夜间走另一套阈值或者对红外图做直方图均衡再送进模型。5. 从 PC 到边缘端yolov5 量化与部署的进阶技巧5.1 导出 ONNX 并做动态量化部署前先把best.pt转成 ONNXimport torch from models.experimental import attempt_load # 加载训练好的权重 model attempt_load(runs/train/exp/weights/best.pt, map_locationcpu) model.eval() # 构造示例输入尺寸和部署一致 dummy torch.zeros(1, 3, 640, 640) # 导出 ONNXopset 11 兼容性最好 torch.onnx.export( model, dummy, yolov5s_cabin.onnx, opset_version11, input_names[images], output_names[output], dynamic_axes{images: {0: batch}} )逻辑说明opset_version11是 NCNN 和 RKNN 都支持的版本别用太新的。dynamic_axes把 batch 维设成动态方便后面按需改 batch。导出后用onnxsim简化一下去掉冗余节点推理能快一点。5.2 树莓派 5 上用 ONNX Runtime 跑最小闭环树莓派 5 的 CPU 比 4B 强不少直接上 ONNX Runtimeimport onnxruntime as ort import cv2 import numpy as np # 加载量化后的 ONNX 模型 session ort.InferenceSession(yolov5s_cabin_int8.onnx) # 读取一帧座舱画面 img cv2.imread(cabin.jpg) img cv2.resize(img, (640, 640)) img img[:, :, ::-1].transpose(2, 0, 1) # BGR 转 RGB 并调整维度 img np.expand_dims(img, 0).astype(np.float32) / 255.0 # 推理 outputs session.run(None, {images: img}) # outputs[0] 形状为 [1, 25200, 5nc]后处理按置信度过滤逻辑说明img[:, :, ::-1]是 BGR 转 RGByolov5 训练时用的是 RGB这一步漏了精度会掉。/ 255.0归一化也要和训练一致。outputs[0]里 25200 是三个尺度特征图展平后的框数后处理就是按conf过滤再 NMS这部分和 PC 上一样只是用 numpy 写别在树莓派上装 torch。5.3 RK3568 上用量化模型校准集要选对RK3568 走 RKNN 工具链流程是 ONNX 转 RKNN 再量化。关键在量化校准准备 200 到 500 张座舱图覆盖白天、夜间、逆光用这些图跑一遍生成量化参数。如果校准集里全是白天夜间闭眼量化后基本检不出来。量化完在板子上跑closed_eye这类小目标的conf会比 PC 上低 0.1 到 0.2所以部署时的conf-thres要相应下调比如 PC 用 0.25板子上用 0.15。5.4 一个容易被忽略的技巧把检测结果接时序状态机单帧检测永远会有抖动闭眼一帧不代表困倦抽烟一帧也不代表违规。我一般会在检测后面接一个简单的状态机维护一个长度为 30 帧的滑动窗口closed_eye出现超过 15 帧才触发困倦告警phone或smoke连续出现 10 帧才触发危险驾驶告警。这样误报能降一个数量级而且逻辑简单在树莓派上用 Python 的collections.deque就能实现不占什么算力。这套方案我从数据标注一路踩到 RK3568 量化最大的教训是模型精度不够八成是数据和类别定义的问题不是换个更大的模型就能救。先把闭眼和打电话这两类做稳再往上加抽烟喝水比一上来铺 8 个类靠谱得多。希望帮到你。本文还有配套的精品资源点击获取
返回列表