基于YOLOv12的课堂学生行为识别检测系统设计与实现
前阵子帮某高校的实验室做课堂督导辅助系统被问得最多的就是怎么把学生的课堂行为识别做成一个真正能用的项目而不只是跑通一个模型。正好手头这套基于YOLOv12的学生课堂行为识别检测系统刚整理完包含完整的Python源码、训练好的模型权重、可选的数据集还配了带登录注册的UI界面索性把整个实现过程和一些踩坑经验梳理成文给准备做类似项目的读者一个能直接上手的参考。这套系统解决的问题很具体课堂场景下需要自动识别学生是否在看书、写字、举手、睡觉、玩手机、交头接耳等典型行为并把检测结果实时展示在界面上。相比传统的人工巡视或随机抽查这类系统最大的价值是能把课堂行为数据变成可量化的统计给教学改进提供依据。适用的对象也比较广从计算机视觉方向的学生做课题设计到教育信息化公司的产品原型再到学校实验室的课堂分析研究都能用得上。1. 项目整体设计与方案选型1.1 从YOLOv8走到YOLOv12为什么是这一版做课堂行为识别模型选型是个绕不开的决策点。早期版本的YOLOv5和YOLOv8在工业界已经很成熟也稳定跑了很多项目但这次我选择直接用YOLOv12核心原因是它在检测架构上有一个关键变化引入了区域注意力机制和可学习的注意力模块替换掉了之前版本大量依赖的卷积C3/C2f结构在同等参数量的情况下对遮挡目标和小目标的特征提取能力明显更强。课堂场景恰恰是这两种目标的密集区。学生前后排互相遮挡很常见后排学生的人脸和手部区域在画面占比很小玩手机、睡觉这类行为如果特征不明显传统卷积很容易漏检。YOLOv12在训练时会对注意力区域做更精细的特征交互实际跑下来后排小目标的召回率比之前用过的YOLOv8模型高了几个点。另外YOLOv12的推理速度和模型体积也有优势。它把部分传统卷积替换成了轻量化的注意力计算在相同精度目标下模型参数量更小对部署机器的要求也更友好。教室监控场景一般就是普通工作站或者边缘设备不是所有学校都有高性能GPU这一点很现实。1.2 项目技术栈和运行环境规划整个系统的技术栈并不复杂但每个环节都要能落地。模型部分基于Ultralytics框架训练和导出推理用ONNX Runtime部署界面用PySide6做桌面应用数据存SQLite登录状态用会话管理控制。编程语言Python 3.10深度学习框架PyTorch 2.x目标检测模型YOLOv12n / YOLOv12s根据机器性能选ONNX Runtimeonnxruntime-gpu 或 onnxruntimeUI框架PySide6Qt for Python数据库SQLite内置免安装适合单机系统辅助库OpenCV、Pillow、NumPy、matplotlib硬件方面训练阶段建议至少一张12GB显存的显卡不然batch size拉不上去训练会很慢。推理阶段的要求低很多普通四核CPU加8GB内存就能跑实时检测如果想跑高清视频流又不掉帧建议上一张GTX 1660级别以上的显卡。2. 课堂行为数据集的制作与标注细节2.1 课堂场景下行为类别怎么定很多初学者拿到项目第一件事就想着堆类别这其实是个典型误区。课堂行为识别不是类别越多越好类别定义得不清晰模型训练出来边界全是模糊的精度很难看。我在这套系统里默认定义了六类核心行为看书、写字、举手、睡觉、玩手机、交头接耳。这六类是经过实际调研的基本覆盖了课堂督导最关心的行为维度。设计的时候有一个原则就是行为之间必须有清晰的视觉差异。比如看书和写字虽然都和桌面相关但看书时头低着、眼睛朝向书本写字时手部有持续动作这两类通过目标框的位置和特征差异是可以区分的。睡觉和低头看书容易混淆所以我在标注规范里特别强调头部完全贴在桌面上或者闭眼趴着才标睡觉头部抬起但低着看书算看书。玩手机和交头接耳也容易出歧义。我的处理方式是手机出现在手里或者桌面上且视线朝向屏幕的标玩手机两名及以上学生有明显头部靠近、嘴部张合交流的标交头接耳。如果学生只是在发呆或者东张西望不参与分类这样减少负样本的干扰。2.2 图片采集与标注工具实战数据集的质量决定了模型的天花板这句话在课堂行为识别里体现得尤其明显。我用的数据集由两部分组成一部分是公开的学生课堂行为数据集这部分数据场景比较干净可以作为预训练基础另一部分是自己在教室环境中拍摄并标注的补充数据这部分的场景光照、摄像头角度更贴近实际部署。数据采集有几个实操心得教室的摄像头通常挂在黑板正上方或教室后方墙角视角差异很大训练数据里如果只有单一视角换一个教室部署效果会明显下降。建议至少采集三个不同教室、两个不同角度的数据每个角度拍3到5段不同时间段的视频再从视频里抽帧。光线也要有区分上午的自然光、下午的侧光、晚自习的灯光都要覆盖。标注工具我用的是X-AnyLabeling因为可以直接加载YOLO格式的预训练模型做自动预标注人工只需要修正边界框和漏检目标能省下大概一半的时间。如果你更习惯传统工具LabelImg或者CVAT也可以。标注格式是YOLO的txt格式类别id加归一化中心坐标和宽高这个格式Ultralytics框架直接读。2.3 标注质量对模型上限的影响标注这项工作看似机械实际上是对模型精度影响最大的环节。我踩过一个很实在的坑前面几千张图片因为标注得比较随意睡觉和低头的边界框画得不严训练出来的模型在课堂场景下误报率很高经常把正常的低头看书识别成睡觉。后来我重新制定标注规范所有边界框必须紧贴目标物体轮廓不能多留背景同时让两个标注人员独立标同一批图片逐张核对差异模型精度才有了质的提升。遮挡目标的标注重点是如果后排学生被前排学生挡住了超过一半的身体仍然要标出可见部分不要因为遮挡就跳过。你训练的模型最终要面对的就是这种密集遮挡场景如果训练时全部跳过推理时也就学不会识别遮挡目标。只保留头部或者上半身的信息模型反而能学到部分特征。3. 模型训练与优化从预训练权重到可用模型3.1 YOLOv12训练配置与超参数选择数据准备好之后训练前要理清楚YOLOv12和之前版本在代码适配上的差异。Ultralytics官方在较新的版本里已经支持YOLOv12网络结构只需要把yaml配置文件里的scale参数调整为对应的模型尺寸然后用标准的训练命令即可。yolo detect train dataclassroom.yaml modelyolov12n.pt epochs150 imgsz640 batch16 device0这个命令里有几个参数需要根据你的机器调整。batch大小很关键以16G显存为例模型用n版本时batch16比较稳妥显存不够就降到8甚至4不要强行拉高导致OOM。imgsz我建议选择640课堂行为属于中等尺寸目标640的输入在精度和速度之间是比较平衡的。如果部署环境性能较差可以用480但小目标的识别会略降。classroom.yaml的数据集配置文件是最容易写错的地方我贴一个标准格式path: datasets/classroom train: images/train val: images/val names: 0: reading 1: writing 2: raising_hand 3: sleeping 4: playing_phone 5: talking有个细节必须注意path字段指向的路径最好用绝对路径。之前用过相对路径换了一台机器训练就报错找不到图片排查了半天最后发现是路径解析的问题。Ultralytics的默认逻辑会把path拼上train里的相对路径如果你用相对路径建议确认好当前工作目录。3.2 训练过程观察指标训练不是跑完就算了要会看曲线。重点关注三个指标train/loss、metrics/precision、metrics/recall。loss曲线如果在训练后期还持续波动不下降说明学习率没配好或者标注噪声太大要回查数据。precision和recall是矛盾指标课堂行为检测场景我更看重recall也就是宁可漏报也不要误报因为误报会直接引发课堂管理纠纷漏报还可以通过调低置信度阈值来弥补。训练轮数我建议至少150轮不要看到90轮精度不错就提前停止课堂数据集的难点在遮挡目标上更多轮数有助于让模型稳定收敛到更好的局部最优解。如果150轮后loss还在明显下降就加轮次到200。YOLOv12的注意力模块训练比传统卷积要慢一些收敛周期也会相应拉长这是正常现象。另一个容易忽略的参数是mosaic数据增强。在Ultralytics的新版本里mosaic默认在前10轮关闭之后开启这是为了稳定训练。如果你的数据集本身数量不多低于3000张建议把mosaic的强度调低或者关闭因为mosaic会产生大量拼接后的虚假目标数据量少的时候模型容易被带偏。3.3 模型压缩与ONNX导出训练完的PyTorch模型权重文件很大而且推理速度在CPU上并不理想部署到UI系统前必须导出成ONNX格式。这个环节用Ultralytics封装好的命令就行yolo export modelruns/detect/train/weights/best.pt formatonnx opset12 simplifyTrue导出后建议用ONNX Runtime的Python接口做一个快速验证确保推理结果和PyTorch一致。不要直接丢到UI程序里先在测试图片上对比两者的检测框和置信度。我遇到过导出后类别顺序错乱的问题一般原因是ONNX的输入输出张量形状顺序和模型元信息不匹配用onnxruntime的session拿到输出后再手动对齐类别名即可。如果推理环境性能偏弱可以用半精度FP16导出速度提升明显但要注意有些旧显卡不支持FP16算子运行时会报错。折中方案是保留FP32的onnx文件在代码层对输入图像做缩放预处理减少计算量。4. 系统界面与业务功能实现4.1 登录注册模块的设计整个UI项目在动手写代码之前我建议先规划好页面结构和交互流程。这套系统虽然是单机桌面应用但登录注册模块不能随便做个文本框就交差。它要承担两个职责一是限制系统使用权限防止学生成绩和行为数据被随意查看二是记录操作日志谁在什么时间登录过系统、进行过哪些检测操作后台都要有迹可循。登录注册的技术实现比较简单密码用hashlib加盐存储不存明文登录成功后用一个全局session变量保存当前用户名主界面从session里读取身份信息展示在状态栏。权限上分了admin和teacher两级admin可以管理用户、查看所有历史记录teacher只能进行检测和查看自己的统计结果。这个权限模型虽然简单但贴合实际使用场景。数据库表结构我建了三张users表存用户名、密码哈希、角色、创建时间detect_records表存检测时间、行为类别、置信度、截图路径login_logs表存登录记录。SQLite对于这种单机应用足够不需要上MySQL减少部署依赖。4.2 检测主界面的功能拆解主界面的核心是一个多标签页的检测面板我把它分成了四个区域视频检测区、图片检测区、统计报表区、系统设置区。视频检测区放了视频流显示控件、开始/停止按钮、摄像头源选择下拉框和行为类别筛选勾选框。图片检测区支持单张图片拖拽导入检测结果直接在原图上画框显示。统计报表区用表格展示每次检测的结果并可以用matplotlib绘制柱状图方便看课堂行为分布。一个比较实用的细节是置信度阈值滑条。不同教室的光线和摄像头清晰度差异会导致同一模型的表现波动如果用户觉得误检太多可以直接拖动滑条把阈值调高不用改代码重启。系统设置区可以配置检测间隔帧数比如每10帧检测一次而不是每帧都检测这样能大幅降低CPU占用同时行为变化本身是慢变量不会漏掉关键事件。检测主线程和UI线程一定要分离。直接用PySide6的定时器去跑模型推理界面很容易卡死特别是视频码率较高的时候。我采用的是QThread加队列的模式视频采集线程不断读帧放入队列检测线程从队列取帧推理推理结果通过信号发送给UI线程刷新画面。队列长度控制在10帧以内超出就丢弃旧帧保证检测的实时性。4.3 系统与模型推理的集成方案模型推理这部分我建议优先使用ONNX Runtime而不是直接调PyTorch。原因有两个一是onnxruntime在CPU上的推理速度明显更快特别是在不启用GPU的情况下差距能到2倍以上二是部署时不需要带整个PyTorch环境打包体积能小一半。核心推理代码大概是这样import onnxruntime as ort import numpy as np import cv2 session ort.InferenceSession(best.onnx, providers[CUDAExecutionProvider, CPUExecutionProvider]) def predict_frame(frame, conf_thres0.35): img cv2.resize(frame, (640, 640)) img img[:, :, ::-1].transpose(2, 0, 1) # BGR-RGB, HWC-CHW img np.ascontiguousarray(img, dtypenp.float32) img / 255.0 img np.expand_dims(img, axis0) outputs session.run(None, {session.get_inputs()[0].name: img}) # 解析outputs中的检测框、类别和置信度 # 这部分根据模型导出的输出格式做解析 boxes, scores, class_ids post_process(outputs, conf_thres) return boxes, scores, class_ids代码里的预处理细节要注意OpenCV读出来的是BGR格式YOLO模型训练时用的是RGB做推理前一定要转换不然颜色通道反了检测精度会严重下降。另外输入图像要归一化到0到1的浮点数这一步很多人容易漏。5. 常见问题排查与工程落地经验5.1 训练不收敛或精度差的坑训练完发现mAP一直上不去第一反应应该是查标注而不是调参。我见过不少同学训练了好几天最后发现数据集的标注框有大量错位和漏标模型学到的特征本身就是乱的。建议训练前先可视化一批标注数据把标注框画在图片上检查一遍确认框的位置和类别对得上再开始训练。第二类高发问题是类别不均衡。在课堂场景里看书和写字是高频行为举手的次数很少玩手机更是少数。如果直接拿原始数据集训练模型会对高频类别严重过拟合因为学不到低频类别的特征。处理方法有两个一是对低频类别的图片做过采样复制二是用Ultralytics自带的class weights功能给低频类别加大loss权重。两个方法可以同时用亲测有效。还有一个坑是anchor尺寸的问题。YOLOv12虽然大幅改进了架构但数据集中的小目标框如果分布和默认anchor差距过大精度还是会受影响。如果发现小目标漏检可以在训练前用数据集聚类重新计算anchor尺寸或者通过调整anchor的宽高比来覆盖更多细长型的框比如学生手部和手机区域。5.2 推理慢、显存不足的处理推理慢的瓶颈绝大多数不在模型本身而在图像预处理和帧处理策略。OpenCV的resize默认插值算法是双线性如果你把一个大分辨率画面每次resize到640x640处理耗时会很高。建议直接从视频流里按region of interest裁剪出教室区域再做resize既能降低计算量还能排除掉黑板区域等无效信息的干扰。显存不足的问题在训练阶段最常出现。除了降低batch外还有一个好用的技巧是设置cacheTrue参数让Ultralytics在训练前把增强后的图像缓存到内存中减少每次迭代时从磁盘读图和随机增强的开销训练速度能显著提升。推理阶段的显存问题主要是多路视频并行引起的。如果你要同时处理多路摄像头建议创建多个ONNX Runtime的session每个session绑定一个摄像头线程但如果显存不够可以全部走CPU推理控制帧率在10到15帧UI上照常显示不卡顿。5.3 打包和部署实战用PyInstaller打包PySide6加ONNX Runtime项目是教程里写起来容易、实操起来坑最多的一步。核心经验是一定要用--onedir模式而不是--onefile。onefile启动时会先解压到临时目录加载大模型和onnx运行时速度很慢而且杀毒软件经常误报。onedir模式虽然输出是一个文件夹但启动速度和稳定性都好很多代码的依赖路径确认更方便。打包前要把模型文件和UI需要的资源文件放到独立目录在代码里用os.path.dirname(__file__)拼接绝对路径不要用相对路径。这算是最常见的部署报错点了界面能打开、模型加载不到大概率就是路径没有按打包后的目录结构重新定位。另一个高频问题是onnxruntime的GPU版本打包后运行报DLL缺失。最优解是放弃打包直接在目标机器上装Python环境或者用docker把环境整个封装。桌面应用如果非要打包建议在目标机器上装Visual C Redistributable并在打包命令里加上--collect-all onnxruntime把相关动态库完整收集进包里。6. 这套系统的后续扩展口径目前这套系统默认支持图片、视频文件和本地摄像头的实时检测整个框架的耦合度设计得比较低如果你想扩展功能改动成本不大。比如接入RTSP网络摄像头只需要新增一个视频流读取类把OpenCV的VideoCapture参数从本地文件路径改成rtsp://地址即可后面的推理和UI逻辑完全不用动。行为统计报表的分析维度也可以再深入。当前柱状图只是统计各类行为的占比如果下一步想做课堂专注度分析可以结合检测结果的时间序列计算每个学生在单位时间内的专注行为时长占比输出成课堂专注度热力图。这类分析已经接近教育知识图谱的范畴也算是这个项目比较有延展空间的后续方向。从我这个项目的实际效果来看YOLOv12这套架构在课堂行为识别上的提升是实打实的特别是对后排小目标和遮挡目标的召回率改进比较明显。不过要强调一点YOLOv12对数据集质量的要求也比前代更高注意力机制的收益建立在标注足够精细的基础上。如果你准备做类似项目建议把至少一半的时间预算放在数据采集和标注上模型训练反而是整个流程里最不容易出问题的一环。最后的一个小建议训练之前先把类别名、路径配置和标注可视化这三个地方各检查一遍能帮你省掉后面大量排错的时间。