这两年智能驾驶相关的视觉项目里基于YOLOv5的驾驶员状态与危险行为检测算是最常被问起的方向之一。我把这套方案从数据整理、模型训练到推理落地完整过了一遍过程中踩了不少坑也总结出一些规律性的东西。这篇就把关键环节的取舍逻辑和实操细节展开说说给正在做类似项目的同学一个可参考的路线。1. 项目需求拆解与技术选型1.1 检测对象与场景定义驾驶员状态检测系统要做的事本质上就是实时监控驾驶员的面部和手部行为判断当前是否处于疲劳、分心或危险驾驶状态。具体到检测目标通常包括闭眼疲劳指示、打哈欠疲劳指示、低头分心、玩手机分心、吸烟、喝水、双手脱离方向盘等行为。这些目标看起来简单但实际场景里难点不少。首先是车内光线环境复杂白天有侧窗阳光直射导致面部过曝夜晚只有仪表盘微光和路灯闪烁其次是驾驶员会佩戴眼镜、墨镜、口罩面部特征经常被遮挡再者是目标的尺度差异很大——人脸可能占据画面三分之一而手机可能只有几十个像素。这些因素都在逼迫检测模型既要看得准又要看得稳。从应用场景看这套系统主要面向两类需求一是商用车队的安全管理平台把疲劳和分心报警实时推送给监管端二是乘用车领域的驾驶员监控系统作为辅助驾驶功能的一部分在驾驶员注意力分散时给出提示。1.2 框架选型逻辑为什么是YOLOv5目标检测框架可选的范围其实很宽。两阶段检测器在精度上有优势但推理速度很难满足实时视频流的要求基于Transformer的检测模型精度不错可对部署环境要求偏高而YOLOv5恰好卡在一个非常舒服的位置上单阶段检测、推理速度快、精度能满足业务需求而且工程化生态极其成熟。选择YOLOv5s还是有更充分的考量的。项目中需要在车规级边缘设备或普通工控机上运行算力有限YOLOv5s模型体积约14MB单张640x640图像的推理时间在GPU上约3-5ms在CPU上也基本能做到实时如果换成YOLOv5m或YOLOv5l精度能提升两三个点但推理时间成倍增加在边缘设备上很难保证25FPS以上的帧率。还有一个很现实的理由是部署生态。YOLOv5的仓库结构清晰导出ONNX、TensorRT、OpenVINO等格式都支持配合NMS后处理的实现也比较成熟。项目推进过程中往往需要快速验证、快速迭代选一个团队上手快、文档全、社区活跃的框架能省去大量环境适配的时间。2. 数据准备决定模型效果的上限2.1 数据来源与采集策略很多人上来就急着调模型但实际效果的上限在数据阶段就已经定死了。我这次的数据主要由两个部分构成一部分是开源的驾驶行为数据集另一部分是自采数据。开源数据集能提供比较丰富的场景覆盖比如不同国家的驾驶员、不同光照条件、各种车内布局适合做模型预训练的底子。但只靠公开数据不够因为目标类别定义和标注风格跟我这边不完全一致尤其是吸烟、喝水这类动作公开数据里的样本数量往往偏少。所以自采数据是必须要做的。自采的方式不复杂用一台普通摄像头架在驾驶位侧前方模拟真实DMS摄像头的安装位置录制多名志愿者在模拟驾驶环境中的行为。采集时重点覆盖几个维度不同时间段的光照上午顺光、中午顶光、傍晚逆光、夜间弱光、不同人员特征是否戴眼镜、是否戴帽子、肤色差异、不同行为强度轻微闭眼与明显瞌睡、拿手机打电话与低头刷手机。采集的时候建议同时录制一段正常驾驶视频作为背景样本。背景样本非常重要模型容易把所有画面内容都当成待检测目标如果没有足够的什么都不该检出来的负样本推理阶段会出现大量误报。2.2 标注规范与类别体系标注规范直接决定了模型能学到什么。我这个项目把检测目标划分成六个类别类别名称定义标注框准则open_eye睁开眼睛面部可见时标注双眼区域closed_eye闭眼双眼闭合时标注眼部区域yawn打哈欠张嘴且嘴部区域明显张开phone使用手机手持手机且手机可见smoke吸烟烟或烟头在嘴部附近可见normal正常驾驶无上述行为时的标准面部状态这里有一个关键取舍为什么不直接用整张脸作为检测目标而是细分到眼睛和嘴部因为疲劳判断需要在眼皮闭合和嘴部张开的粒度上工作。如果只检测整张脸闭眼和睁眼无法区分后续状态判断逻辑就无从下手。同理打哈欠行为的核心特征是嘴部张开的形态把它作为独立目标检测比先检测人脸再做关键点分析要简单直接得多。标注时容易踩的坑主要是遮挡处理。驾驶员低头时脸部可能有一半被手或方向盘挡住拿手机时手部可能遮住嘴部。我的处理原则是目标的可辨识面积低于30%时不标高于30%但部分遮挡时正常标注并在备注里记录遮挡类型。这样模型既不会因为目标被大量遮挡而学出错误特征又能在部分遮挡时保持鲁棒性。2.3 数据增强与训练集划分数据增强策略上我采用了YOLOv5自带的Mosaic增强、随机仿射变换和HSV色域扰动。Mosaic增强把四张图随机拼接成一张训练图好处是变相扩大batch多样性让模型看到更多的小目标样本——这对检测远处的手机、烟头这类小物体尤其有帮助。随机仿射变换包含旋转、平移、缩放和错切能模拟驾驶员在不同坐姿、不同距离下的成像差异。HSV扰动则是把色调、饱和度、亮度随机拉伸增强模型对光线变化的适应力。这三个增强用下来闭眼和吸烟这两个小目标类别的mAP都能提升三到五个点。训练集划分上有个很多人忽略的细节必须先按人员分组再按组划分训练集和验证集而不是直接把所有图片随机打散。如果同一个人的大量画面同时出现在训练集和验证集里模型等于记住了这个人验证指标会虚高一到实际部署就现出原形。我这边按人员以7:2:1比例划分训练、验证和测试集确保验证集里出现的人完全没参与过训练。3. 模型训练全流程3.1 环境配置与超参数设定训练环境方面我用了PyTorch框架CUDA版本与显卡驱动匹配好后直接拉取官方YOLOv5仓库代码。这一版代码对新手友好尤其是训练和验证的命令行入口设计得很规范几乎不需要改代码就能跑通整个流程。关键的训练超参设置如下表参数名设定值选择理由模型大小yolov5s精度与推理速度的平衡点输入尺寸640 x 640标准分辨率小目标可辨识度与算力的折中训练轮数150 epochs充分收敛配合早停机制防止过拟合batch size16根据16GB显存设定显存不足时建议梯度累积初始学习率0.01YOLOv5默认值配合余弦退火策略动量0.937默认值训练过程稳定权重衰减0.0005默认值抑制过拟合batch size的选择要单独说一下。很多人盲目追求大batch但batch太大容易让训练曲线过早进入平台期模型泛化能力反而下降。16这个数值在显存允许的范围内足够稳定配合Mosaic增强等效batch相当于64张图的有效信息量训练收敛速度和最终精度都表现不错。如果显存只有8GB建议将batch降为8并启用梯度累积或者直接使用YOLOv5官方推荐的auto batch模式自动寻找最大可用的batch值。个人经验是不要为了把batch调大而大幅压缩输入尺寸640分辨率对眼部细节和小物体的检测影响很大。3.2 训练过程与监控要点训练过程中我最关注的指标是训练损失曲线和验证集mAP曲线而不是单看训练集损失。训练集损失持续下降但验证集mAP停滞甚至下滑说明模型已经开始过拟合如果训练和验证的损失同步下降说明模型还在有效学习。我在150轮中开启了早停机制patience设为30轮。也就是说如果连续30轮验证集mAP没有提升训练自动终止。这个策略在数据集规模不大时非常有效能避免无意义的算力浪费。实际训练中大约到110轮左右验证指标到达峰值早停机制也在这个区间生效。YOLOv5训练过程会自动保存每轮权重建议把best.pt和last.pt都留下来。best.pt用于最终评估和导出last.pt留着可以在后续增补数据时做热启动训练比从头训练省一半时间。训练时的数据加载线程数需要根据机器CPU核心数调整。我这边设为8磁盘读取速度足够训练吞吐接近满载。如果训练时GPU利用率一直上不去优先检查CPU数据加载是不是成了瓶颈。3.3 评估指标解读与阈值选取模型评估阶段YOLOv5默认输出mAP0.5和mAP0.5:0.95两组指标。mAP0.5是IoU阈值取0.5时的平均精度更贴近实际使用中对定位精度的容忍度mAP0.5:0.95则是从0.5到0.95每隔0.05取一组IoU阈值的平均结果更严格对框位置的精度要求更高。我这个项目最终目标是报警场景框的位置稍微偏一点其实不影响行为判断。所以调参时以mAP0.5为主要参考mAP0.5:0.95作为辅助参考。训练完成后六个类别的mAP0.5整体能到0.92左右其中open_eye和closed_eye最高yawn和phone中等smoke因为样本量最少指标也最低。推理阶段的置信度阈值和NMS阈值需要单独调。默认的conf_thres0.25在通用检测场景下没问题但驾驶员监控场景误报容忍度很低我把conf_thres提到了0.45NMS的IoU阈值设为0.5。提高置信度阈值会牺牲少量召回率但显著降低误报这个交换在报警系统中是值得的。如果实际部署中发现漏报偏高再逐步下调到0.35左右找一个平衡点。4. 推理与状态判断逻辑4.1 实时推理流程设计训练完成的模型要接入实际视频流才能产生业务价值。推理流程的基本链路是读取摄像头帧缩放至640x640送入模型推理输出检测框和类别在原始帧上叠加显示。这里有一个效率问题摄像头原始帧分辨率通常是1920x1080直接缩放成640x640后送入模型模型推理本身没问题但缩放过程会损失大量细节。我建议先用OpenCV做一次ROI裁剪把画面中驾驶员面部和手部活动区域裁剪出来再缩放至640x640。这样既保留更多有效信息又减少了背景区域对检测的干扰。实际部署时我采用了每隔一帧推理一次的策略。DMS画面中驾驶员的行为变化是渐进的闭眼、打哈欠这类动作持续几百毫秒甚至更久25FPS的推理频率已经足够。隔帧推理能把CPU占用降一半在较低算力的设备上也能稳定运行。4.2 状态判断与时序逻辑这里要强调一个容易被忽视的点目标检测模型输出的是单帧检测结果但状态必须是跨帧的时间序列结论。单帧检测出closed_eye可能只是眨眼连续几十帧都检测出closed_eye才是疲劳。单帧检测出phone可能只是拿起手机看时间持续几秒才属于分心驾驶。我这边设计了几个简单的状态判断规则行为类型判断逻辑报警条件疲劳检测到closed_eye连续超过2秒疲劳检测到yawn每分钟超过5次分心检测到phone持续超过3秒危险检测到smoke持续超过2秒每帧检测结果进入一个滑动窗口队列窗口长度按帧率换算成时间。比如25FPS下闭眼2秒意味着连续50帧出现closed_eye检测结果。这个设计能有效过滤掉眨眼、低头系安全带等瞬态误判。另外一个实用技巧是检测结果的置信度不只看单帧。如果一个目标的检测置信度忽高忽低说明模型不太确定这时可以结合前后几帧结果做一个简单的投票机制被多数帧确认的目标才进入状态统计能进一步压低误报率。4.3 报警策略与边缘部署报警逻辑的工程实现需要注意静默期设计。连续报警会让监控后台被无效消息淹没我这边实现了两级报警机制第一次触发危险行为后先发出提醒级消息如果在30秒内再次触发才升级为严重报警。这个设计在实际运营中非常有用大大降低了值守人员的疲劳感和无效处理的概率。部署层面我在测试中做了ONNX导出再转换成TensorRT引擎。TensorRT的FP16推理相比PyTorch原始推理帧率提升约两倍。如果用CPU部署可以尝试OpenVINO工具链在Intel平台上通常能获得不错的加速效果。对模型做轻量化时一定要重新验证精度。剪枝和量化都能带来速度收益但闭眼和吸烟这类小目标的精度损失最明显。我实验下来FP16精度几乎无损INT8会掉两个点左右但换来的是更大的速度提升适合对成本敏感的大规模车队部署场景。5. 常见问题与排查实录5.1 误检漏检的典型场景项目调试阶段遇到最多的问题是夜间和强光下的误检漏检。夜间光线弱闭眼特征不清晰模型经常漏掉closed_eye白天强光直射时脸部出现大面积过曝open_eye会被误判成closed_eye。排查后发现根本原因是训练数据里暗光和强光的分布太少。解决办法是针对性补采了夜间和逆光样本同时用自适应直方图均衡化对图像做预处理增强暗部细节后再送入模型。补采数据重新训练后夜间闭眼召回率提升了约一成。戴墨镜是另一个高频误判场景。墨镜遮挡了眼睛区域模型很容易把墨镜遮挡学成闭眼导致一路报警。这里我在状态判断逻辑里增加了一路OpenCV检测如果眼部区域存在大面积黑色矩形判定为戴墨镜跳过闭眼这一路的疲劳判断。虽然简单但非常奏效。5.2 性能瓶颈与加速手段如果部署发现帧率不够先从三个方向排查模型输入分辨率是否过高、NMS后处理是否用的CPU单线程、数据预处理是否拖慢整体链路。这三个因素通常能解释80%的性能问题。以我在一台低功耗工控机上的测试为例初始端到端推理约12FPS。我把输入分辨率从640降到544后升到16FPS但还是不够。进一步排查发现瓶颈在NMS是在CPU上跑的改成GPU NMS后帧率直接到了28FPS达到实时要求。如果还需要更高的性能最后的手段才是更换更轻量级的模型结构。但要注意模型结构变轻通常会让小目标的精度下降而驾驶员监控恰好对手机、烟这类小目标敏感。所以性能优化应该优先考虑工程侧手段模型侧改动放在最后。5.3 部署测试中的关键业务指标除了模型指标我建议项目上线前一定要定义清楚业务指标。模型mAP是技术层指标业务侧更应该关注的是危险行为检出率真实危险行为中有多少被成功触发报警和误报率单位小时内非危险行为触发报警的次数。我验收时给自己定的标准是疲劳和分心行为的检出率不低于90%误报率不超过每小时1次。这个标准在真机上跑了五轮模拟驾驶测试后才稳定达标。如果模型单帧指标很漂亮但业务指标不达标问题几乎一定出在状态判断逻辑上——阈值太高会漏报太低会误报需要根据实际路测数据反复调试。5.4 项目实操中的几条经验做完整个项目我总结几条对后来者最有用的经验第一数据准备阶段多花一倍时间训练和调试阶段就能省回三倍时间。尤其是背景负样本和困难样本直接影响系统落地后的误报率。把数据当成最重要的资产来管理每次训练用到的数据集版本都要留档记录方便回溯。第二单帧检测模型和业务状态判断逻辑要分开设计和测试。很多团队把精力全砸在模型上结果上线后报警逻辑一塌糊涂。我的做法是模型只负责输出事实——画面里有什么目标、位置在哪状态判断逻辑单独做单元测试用录制的视频片段模拟各种时序场景验证报警逻辑的可靠性。第三现场的软硬件环境远比训练环境复杂。摄像头安装角度差几度模型表现就会差很多。建议在项目早期就用目标安装角度的摄像头采集训练数据而不是先用理想位置的数据训练再后期适配现场安装角度。第四所有报警事件要留痕。不仅仅是为了事后追溯更重要的是积累真实场景的难例样本。我把每次触发报警的帧和前后各30帧的视频片段自动保存下来定期筛选后补充到训练集里模型的迭代效果非常明显。这个项目的技术路线已经比较成熟但远未到可以一把梭的程度。数据质量、工程细节和现场调优仍然主导着最终效果。如果后续要做更深入的方向可以考虑接红外摄像头解决夜间光线问题或者融合方向盘转角、车速等信号做多模态疲劳判断这会比单靠视觉检测更稳健。但不管怎么扩展扎实的数据基础和清晰的逻辑分层都是同一个起点。