ARTICLE DETAIL

资讯详情

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

基于YOLOv5的课堂行为检测:从数据标注到边缘部署实战

基于YOLOv5的课堂行为检测:从数据标注到边缘部署实战 简介YOLOv5教室行为检测系统代码包是一套面向智慧校园场景的轻量级实现针对教室人数统计、学生行为识别与教师授课行为检测提供基础代码框架适合具备PyTorch和YOLOv5基础、希望快速搭建检测原型的开发者。资源共5个文件压缩包仅12KB包含index.html可视化入口、app.js核心逻辑、TODO.md功能说明与开发计划以及.gitignore和.inscode工程配置整体结构精简便于阅读与二次开发。目前已有35人学习。尽管包体小巧但代码涵盖图像数据预处理、YOLOv5s模型推理、检测结果叠加展示等关键环节配合TODO.md中的模块说明可快速理解教室行为识别系统的实现思路为后续扩展人数统计、行为分类等功能提供了可复用脚手架。 去年有个做教育信息化的朋友找到我说客户想上一套课堂行为分析系统——摄像头对着教室自动统计哪些学生上课睡觉、玩手机、举手答题最好还能输出一节课的行为报表。拆开来看这件事的核心就是目标检测把学生的位置框出来再给每个框贴上对应行为类别的标签。我最后选了YOLOv5把数据采集、标注、训练、部署整条链路走了一遍。这篇文章就是这根链路里值得细说的部分适合正在做类似项目的朋友参考——不管你是做课程设计、毕业设计还是公司里的智慧教室项目核心流程都是同一套准备数据、训练模型、推理部署。而这中间最容易翻车的点往往不在模型本身。1. 先想清楚检测什么任务边界、行为类别与YOLOv5的取舍1.1 教室行为检测到底解决什么问题在动手写代码之前一定要先回答一个问题这个系统给谁用、用来做什么。我在这个项目里接触到的真实需求是教务老师想代替人工巡课通过监控视频快速掌握课堂情况。过去的做法是老师抽空去教室走一圈或者课后翻监控回放效率低且主观性强。目标检测方案能自动识别画面中的学生和动作状态输出结构化数据比如“第3排第2个学生在睡觉”“这节课共有8次举手”这些数据可以作为教学评估和课堂管理的参考依据。明确了业务目标后技术链条就清晰了摄像头采集教室画面目标检测模型识别每个人及其行为类别后续用跟踪逻辑对一段时间内的检测结果做平滑和统计最后输出报表或告警这条链路里目标检测是地基。地基本身的精度和速度决定了后面所有环节的上限。这也解释了为什么这个项目里模型选型这么重要。1.2 行为类别怎么定不是越多越好很多刚做这个项目的人一上来就列了十几个类别张嘴就是“交头接耳”“东张西望”“趴桌子翻白眼”……我劝你冷静。行为类别的定义直接决定标注成本和模型收敛难度。我第一版只定了6类类别含义实际标注难点sleep趴桌或低头闭眼容易被误判为低头书写phone使用手机手机是小目标远距离容易漏检raise_hand举手样本相对少且手势与伸懒腰相似write书写记录需要看到手部动作遮挡影响大read阅读材料与看手机在视觉特征上有重叠stand站立回答问题边界相对清晰好标好学为什么要控制在6类以内因为每增加一个类别不只增加标注工作量还会增加类别之间的混淆概率。比如说“交头接耳”这种类别本质上是两人的交互行为单帧图像根本判断不了你需要的是视频时序信息那就要接跟踪和序列模型项目复杂度立刻不一样。所以第一版就把这类需求挡在门外先保证能交付后续再迭代。1.3 为什么选YOLOv5生态成熟和可魔改度是决定性因素目标检测方案有很多YOLO系列、Faster R-CNN、SSD后来还有YOLOv8、YOLOv9。我最终选了YOLOv5不是因为它在学术榜单上多领先而是因为它对做项目的人最友好。首先是资料和生态。YOLOv5在GitHub上的讨论、博客教程、踩坑记录是最多的遇到环境问题基本都能搜到答案。其次是工程化的配套成熟导出ONNX、转TensorRT、在Jetson或带NPU的板卡上部署每一步都有现成方案这对要交付项目的场景非常重要。第三是代码结构清晰train.py、detect.py、export.py这些脚本职责单一二开起来非常顺手。如果你非要用YOLOv8或者更新的版本整个流程的逻辑完全一样只是命令和参数略有差异。但对一个从零开始的项目YOLOv5是时间成本最低的选择这一点在我做完整条链路后体会更深。2. 环境搭建显卡驱动、PyTorch版本和代码目录组织2.1 显卡驱动、CUDA、PyTorch三者怎么配合环境问题占了新手踩坑的一半以上。我先把三者关系讲透显卡驱动是操作系统和GPU之间的翻译层驱动装好了系统才能调用显卡计算CUDA是NVIDIA提供的一套通用并行计算接口深度学习框架通过它来操作GPU做张量运算PyTorch则是你在代码里直接调用的库它内部封装了对CUDA的调用。三者版本必须互相匹配否则就会出现“装好了代码但跑不起GPU”的情况。很多同学在虚拟机上、在教师机远程环境里跑来跑去环境变量混乱最后跑起来的是CPU版本训练速度直接差几十倍。我的建议是先确认基础环境用一行命令看显卡驱动nvidia-smi这个命令会显示驱动版本、GPU型号、显存占用和最高支持的CUDA版本。注意这里显示的CUDA版本是驱动支持的“上限”不代表你机器里装了对应版本的CUDA Toolkit。PyTorch安装时自带的CUDA runtime是够用的一般不需要单独装完整的CUDA Toolkit。我当时的搭配是Ubuntu 20.04、RTX 3060 12G、驱动530系列PyTorch 1.10.1 CUDA 11.3整个训练过程稳定。如果你拿到的是新卡建议直接上PyTorch 2.x配CUDA 11.8或12.1兼容性更好。显卡推荐PyTorch版本大致CUDA版本说明GTX 1660 / 20601.10~1.1311.3~11.7老驱动老版本兼容性好RTX 3060 / 30801.12~2.011.7~11.8主流搭配资料多RTX 40系列2.011.8 / 12.1新卡必须用新驱动2.2 从零搭好YOLOv5训练环境我习惯用conda建虚拟环境避免和系统Python打架conda create -n yolov5 python3.9 -y conda activate yolov5 pip install torch1.10.0 torchvision0.11.0 --extra-index-url https://download.pytorch.org/whl/cu113 git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt这里有几个细节要注意。第一PyTorch的安装不用清华源或阿里源直接用官方给出的extra-index-url更稳因为PyTorch的包组织和普通PyPI包不一样用国内镜像容易装出CPU版本或者装错平台包。第二YOLOv5仓库一直在更新不要直接拉main分支最新代码建议固定到一个release tag上比如v6.0或v7.0因为最新代码偶尔会改接口而网上教程大多基于某个稳定版本写的版本对不上容易踩无谓的坑。第三Windows下训练时把train.py里的workers参数设为0或者2否则数据加载很容易卡死这个坑几乎每个Windows用户都会遇到。装完依赖后先检查GPU是否对PyTorch可用import torch print(torch.__version__) print(torch.cuda.is_available())输出True说明环境基本没问题了。2.3 先用官方Demo跑通推理再开始训练环境装好后第一件事不是训练自己的数据而是用官方权重跑一次推理。这一步能过滤掉大部分环境问题。python detect.py --weights yolov5s.pt --source data/images/bus.jpg第一次运行会自动下载yolov5s.pt权重大约14MB国内网络可能稍慢。运行完成后结果图保存在runs/detect/exp目录下打开看看画框效果是否正常。这一步如果出了错绝大多数是三种情况一是torch.cuda.is_available()返回False说明PyTorch装成了CPU版或CUDA版本不匹配二是运行时报缺少某个库通常opencv-python没装全三是路径里有中文Windows用户特别常见标准做法是让项目路径全程英文。Demo跑通后才算是真正的“环境可用了”后面才有资格讨论训练。3. 数据集这一关数据来源、标注规范与小目标切图3.1 训练数据从哪来公开数据、半公开数据和自己采集做这个项目时数据准备大约占了整个项目60%的时间。很多人想找一个现成的课堂行为数据集直接开训我的建议是公开数据集可以作为前期验证但最终效果必须靠贴合自己场景的数据。公开数据集的优点是省时间缺点是场景单一。我见过的一些学术课堂数据集大多是在固定教室、固定角度拍摄的换一个教室光线一变化模型泛化能力立刻下降。还有一种思路是从COCO数据集里筛选person、cell phone、book等类别用来训练“有人”“有手机”“有书”这种粗粒度识别但COCO没有“睡觉”“举手”这类课堂特定行为所以只能作为辅助。更靠谱的做法是自己采集。让挂载的摄像头持续录制多个教室的授课视频覆盖不同时段上午、下午、拉窗帘的阴天、晚上的灯光环境抽帧成图片。采集时要注意两点一是不要只在同一个教室拍至少3个以上不同教室二是要把近景、中景、远景的学生都覆盖到否则模型对远处小目标完全无感。数据量方面我建议每个类别先用1000~3000个标注实例起步。注意这里说的是“实例”而不是“张数”一张图里可能同时有十几个标注框。总量控制在5000~20000张图片比较合理太少容易过拟合太多标注成本吃不消。3.2 标注工具与YOLOv5标签格式标注工具我用的是labelImg虽然界面朴素但胜在稳定、速度快、导出格式通用。它默认保存为Pascal VOC XML格式而YOLOv5训练需要的是txt格式所以标注之后要做一个格式转换。YOLOv5的标签格式是每行一个目标类别id cx cy w h其中cx、cy是目标中心点的坐标w、h是宽高四个值都归一化到0~1之间。转换代码核心逻辑如下import xml.etree.ElementTree as ET def convert_label(xml_path, out_path, classes): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in classes: continue cls_id classes.index(name) box obj.find(bndbox) xmin int(box.find(xmin).text) ymin int(box.find(ymin).text) xmax int(box.find(xmax).text) ymax int(box.find(ymax).text) cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) with open(out_path, w) as f: f.write(\n.join(lines))这里最容易出的错就是没有归一化或者把类别id和类别名搞混。标注前我强烈建议写一份标注规范目标被遮挡超过50%要不要标极小目标要不要标一张图里同一个对象出现两次怎么处理这些规则不提前定标到后面会越来越乱模型也会学到很多矛盾特征。3.3 教室场景必须做切图否则小目标直接丢失这个点在普通目标检测教程里很少被强调但对教室场景几乎起决定性作用。教室监控画面通常是1920×1080甚至更高分辨率学生坐在座位上有远有近远处的人可能只有20像素高手上的手机更是只有几个像素。YOLOv5默认把输入图像resize到640×640如果把整张高清图直接缩小远处的小目标直接就没细节了怎么训练都检测不到。解决办法是切图训练。把原图切成1280×1280或者960×960的块每个块之间留一些重叠区域避免目标正好被切碎。切图后再标注或者先标注后切图都行但要注意切图后要同步调整坐标并过滤掉边缘上目标不足一半的样本。这一步做完模型对远处小目标的检出率会明显提升。3.4 数据增强适量就行别迷信YOLOv5自带的增强很强Mosaic、MixUp、HSV抖动、随机翻转、随机透视默认配置在hyp.scratch-low.yaml里。对于教室场景我会把fliplr随机左右翻转的概率调到0.5以上因为教室里的学生左右对称性很强翻转不改变语义等于白送了一倍数据。但要记住数据增强是一把双刃剑。如果总数据量只有几百张增强强度拉满模型会把大量精力花在学习增强带来的噪声上反而学不好目标本身的特征。我的经验是先按默认增强训练一个版本看效果再根据过拟合程度适当调节。不要一上来就堆增强策略。4. 训练复盘超参数调整、loss曲线解读与常见翻车点4.1 数据配置与训练命令训练前先写一个数据配置文件YOLOv5要求yaml格式# data/classroom.yaml train: data/classroom/train/images val: data/classroom/val/images nc: 6 names: [sleep, phone, raise_hand, write, read, stand]然后启动训练python train.py --data data/classroom.yaml --weights yolov5s.pt --epochs 150 --batch-size 16 --img 640 --device 0参数选择上我建议按这个思路来weights必须用预训练权重从零训练在几百张数据上几乎没有收敛的可能。yolov5s.pt是速度和精度的平衡点显存只有4GB的话可以换yolov5n.pt追求精度可以上yolov5m.pt但要同时考虑显存和训练时间。batch-size以不爆显存为上限。12G显存跑yolov5s、img640batch-size设16没问题。如果出现CUDA out of memory直接减半。img训练图像尺寸。默认640如果做了切图训练可以保持640或提高到768。注意img越大训练时间和显存占用都涨得很快。epochs我先跑50轮看趋势确认loss在降、mAP在涨再跑满150~300轮。别一上来就跑300轮万一数据标签错了浪费一天时间。关于超参数文件hyp.scratch-low.yaml新手一般不用大改把lr参数当作最后手段。真正需要手动调的往往是数据本身的问题。4.2 训练日志里的各种指标到底怎么看训练过程中每轮结束会打印一行指标包括P精确率、R召回率、mAP50、mAP50-95还有三类loss值box loss、obj loss、cls loss。很多第一次训练的人只盯着mAP其实loss的变化能告诉你更多信息。box loss反映预测框和真实框的位置偏差obj loss反映目标置信度cls loss反映分类是否正确。如果某个loss训练到后面还在明显下跌说明还没收敛如果训练loss一直在降但验证集的mAP停滞甚至下降十有八九是过拟合了。训练结束后结果保存在runs/train/exp目录下其中results.png把loss曲线和指标曲线都画出来了一眼就能看出趋势。weights文件夹里有两个文件best.pt是验证集mAP最高的权重last.pt是最后一轮的权重。部署时优先用best.pt。训练集和验证集的划分也需要注意我习惯按图片所在的“视频片段”来划分而不是随机打散每一张图。因为同一段视频的相邻帧高度相似如果随机划分训练集和验证集里的画面几乎一样算出来的mAP虚高换个真实场景立刻现原形。这个细节直接影响你对自己模型水平的判断不要偷懒。4.3 训练完检测不到目标先查这几个地方我把做项目时常见的训练问题整理成一张表基本都是亲身踩过或者帮别人排查过的现象可能原因解决办法CUDA out of memorybatch-size或img过大减小batch-size或img尺寸loss一直不降标签类别和names顺序对不上打开一张标注图可视化确认类别id训练正常但detect没框标签坐标没归一化或txt格式错检查txt里的数值是否都在0~1之间验证集mAP高但实测差数据集随机划分导致数据泄漏按视频片段划分训练/验证集Windows下训练卡死workers进程阻塞设置workers0过拟合严重数据量太少或增强过强增加数据或降低增强强度手机目标完全漏检原图直接resize导致小目标丢失做切图训练或提高img分辨率这里重点提一下标签可视化。训练前把标注文件画回原图看一眼能发现绝大多数标注问题。YOLOv5仓库里有对应脚本可以参考画出来的图里框的位置和类别名都对再开始训练这是对自己显卡时间的尊重。5. 推理部署从视频检测到跟踪联动再到边缘设备迁移5.1 用detect.py跑通视频检测训练完成后用detect.py对测试视频做推理python detect.py --weights runs/train/exp/weights/best.pt --source test.mp4 --conf-thres 0.25 --iou-thres 0.45 --save-txtconf-thres这个参数值得多说一句。它代表置信度阈值默认0.25在普通检测场景下够用教室场景里因为行为类别之间有相似性模型输出的置信度普遍不会太高。如果发现很多目标没被框出来把conf-thres降到0.1再跑一遍看看模型到底检出了什么再决定用多少合理。如果框出来的结果里有大量误检就适当提高。这个参数的调优本质上是在精确率和召回率之间做取舍。5.2 从单帧检测到行为判断跟踪与滑动窗口跑通了单帧检测你很快会发现一个问题同一学生在连续帧里的行为标签会跳来跳去这一帧是“写”下一帧变成“读”再下一帧又变回“写”。这是因为单帧检测本身有波动而你真正想要的“这个学生上课睡了几分钟”是时序统计需要的是对检测结果做时间维度上的平滑。解决方案是接入跟踪算法给每个学生分配一个稳定的ID。我这边用的是ByteTrack它轻量、效果好而且和YOLOv5配合得很顺。拿到ID之后对每个ID的检测结果维持一个滑动窗口比如最近30帧统计每个类别的出现次数取占比最高的类别作为这段时间的行为结果。再进一步制定业务规则连续N帧判定为“sleep”才最终认为是睡觉偶尔低一次头不能算。这里的核心逻辑是目标检测负责“看”时序处理负责“信”。模型给出的是每帧的瞬时判断业务系统要的是一个稳定可靠的结论中间必须有一个消化过程。5.3 边缘部署的几条路线与后处理注意点项目要真正落地大概率不是在一台大GPU服务器上跑而是放到教室里的边缘设备上。主流路线有几种简单方案教室端用普通IPC摄像头RTSP流拉到一台带GPU的小主机上检测这是成本最低、最快能跑起来的方案。OpenCV读取视频流逐帧送入模型代码量不大。高性能方案NVIDIA Jetson平台Orin Nano这类上导出TensorRT engine推理速度可以做到实时以上生态也很成熟。导出命令很简单python export.py --weights best.pt --include engine --device 0低成本方案带NPU的ARM板子比如NXP i.MX 8M Plus、瑞芯微RK3588这类模型需要从PyTorch转ONNX再转对应NPU工具链的格式。这里最容易踩坑的是后处理NMS在很多NPU上不支持需要自己在CPU端实现算子裁剪也要逐层验证精度工作量不小。树莓派上部署也是类似的思路CPU推理yolov5s单帧耗时普遍超过1秒必须用ncnn或mnn这类推理框架做优化达不到实时是常态适合做定时抓拍分析而不是实时流。对于大多数课程设计或者Demo演示我建议先走“简单方案”把检测链路完整跑起来再根据需求聊优化。基础推理循环的框架大概是这样的import cv2 import torch model torch.hub.load(./yolov5, custom, pathbest.pt, sourcelocal) model.conf 0.25 model.iou 0.45 cap cv2.VideoCapture(test.mp4) while cap.isOpened(): ret, frame cap.read() if not ret: break results model(frame) rendered results.render()[0] cv2.imshow(classroom, rendered) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这个代码里torch.hub.load加载本地YOLOv5仓库和训练好的best.pt后面接上业务逻辑就能扩展成带统计功能的系统。实际上大部分部署项目都是在这个骨架上填充自己的东西。做完整条链路后我最大的体会是教室行为检测这个题目表面上是模型精度问题实际上更考验数据规范和业务理解。类别定义不清标注会越标越乱业务方如果期望系统回答“为什么交头接耳”而你只能输出“检测到长时间交谈”这个预期差必须在项目一开始就讲明白。如果你正准备做这个项目我的建议是先写死数据规范标几百张图快速跑一版模型验证流程再决定要不要扩数据、加类别。一上来就标两万张再训练大概率要返工。本文还有配套的精品资源点击获取
返回列表