用 YOLOv8n + 自研二分类模型做课堂行为识别:从 9000 张标注数据到 Flask 全栈落地

一个真实校园 AI 项目的完整复盘:数据怎么标、模型怎么选、指标怎么读、系统怎么部署。文末附开源仓库。

一、为什么要做这件事

课堂里的「趴桌、玩手机、站立、抬头」这几类行为,靠老师巡课几乎不可能实时掌握。一个 50 人的教室,一节课 45 分钟,人工观察的采样率极低,而且主观性强。

这个项目(EduBot)来自学校真实教室场景,目标很明确:

  1. 用教室监控数据,自建人员检测数据集 和行为分类数据集;
  2. 训练一个只认教室场景的人员检测模型,再配一套行为分类模型;
  3. 做成可落地的全栈系统(前端 + 后端 + 模型管理),而不是一个跑在 notebook 里的 demo。

最终跑通的方案是:YOLO 找人 + 自研分类模型判行为。下面把每一步的真实数据和踩过的坑摊开讲。

二、整体架构:为什么不是「一个 YOLO 干到底」

很多人第一反应是:直接把趴桌、玩手机做成 YOLO 的检测类别不就行了。

实际做下来,这条路在教室场景有几个硬伤:

  • 行为是「人身上的局部状态」,不是独立物体。同一个学生坐着和站着,检测框位置、尺度完全不同,标注一致性极差;
  • 细粒度行为差异太小。「互相耳语」和「正常交流」在低分辨率监控画面里几乎同形;
  • 类别不平衡严重。玩手机、趴桌是低频事件,直接当检测类会严重拉低整体 mAP。

所以架构拆成两级流水线:

复制代码
摄像头帧
   ↓
YOLOv8n 人员检测(只输出 person)
   ↓
按检测框裁剪单人图像
   ↓
5 个自研二分类模型并行推理
   ↓
行为标签 + 时间戳 → MySQL
   ↓
前端看板 / 统计报表 / LLM 教学辅助

检测负责「是谁、在哪」,分类负责「在干什么」,两级解耦之后,数据集可以分开构建,模型可以分开迭代,出问题也容易定位。

技术栈大致是:

层 选型
检测 ultralytics 8.3.x + YOLOv8n
分类 PyTorch 2.5.1 + torchvision 0.20.1,自研轻量网络
推理加速 opencv-python 4.11
后端 Flask 3.1 + SQLAlchemy 2.0 + PyMySQL + JWT + bcrypt
模型管理 FastAPI 风格独立服务 + langchain + openai SDK
数据库 MySQL
部署 本地服务器 + Nginx + 花生壳内网穿透 + pyinstaller 打包

三、数据工程:这个项目 70% 的时间花在这里

3.1 人员检测数据集

用 LabelImg(PyCharm 里跑),YOLO 格式,只标 person 一个类。不标行为类别,就是为了让标注规则足够简单,多人协作时一致性有保证。

3.2 行为分类数据集

写了一个自研标注工具:把检测框里的人员图像裁出来,人工按 5 类打标签 ------ 抬头看、站立、使用手机、头伏桌面、互相耳语。

两个数据集都按 3:1 划分训练集 / 验证集。

3.3 标注阶段的真实问题

  • 遮挡:后排学生被前排挡住,框裁出来只有半个身子;
  • 分辨率:远距离目标裁出来只有几十像素,人眼都难判断,模型更别想;
  • 标签边界模糊:「耳语」和「讨论」的界线,不同标注员理解不一致。

这三条直接决定了后面的模型上限 ------ 数据集的歧义,模型是学不掉的。

四、检测模型选型:8 个模型的真实对比

为了搞清楚「通用检测模型在教室场景到底能不能用」,先做了一轮密集行人检测对比实验:约 9000 张密集行人图像,3:1 划分,横向对比 Faster-RCNN 系列 4 个变体和 YOLO 系列 4 个版本。

Faster-RCNN 系列在验证集上的表现(节选):

模型 参数量 计算量 mAP mAP@50 FPS
fasterrcnn_mobilenet_v3_large_320_fpn 18.9M 0.9 GFLOPs 9.09 24.92 36
fasterrcnn_mobilenet_v3_large_fpn 18.9M 4.5 GFLOPs 22.33 45.93 38
fasterrcnn_resnet50_fpn 41.3M 133.9 GFLOPs 28.61 50.65 17
fasterrcnn_resnet50_fpn_v2 43.3M 280.4 GFLOPs 23.17 41.81 12

几个很直观的结论:

  1. 精度和速度是硬 trade-off。ResNet50 backbone 的 mAP 明显更高,但 12-17 FPS 在实时监控场景基本不可用;
  2. 轻量 backbone 掉点严重。MobileNetV3-320 版本跑到 36 FPS,但 mAP 只有 9.09 ------ 「能跑」不等于「能用」;
  3. 过拟合非常明显。同一批模型在训练集上的 mAP 能到 39.52% ~ 85.71%,验证集只有 9.09% ~ 28.61%。这么大的 gap 说明训练集和验证集分布差异大,或者数据量根本不够;
  4. 小目标检测是短板。所有模型的 mAP_large 都远高于 mAP_small,教室后排的小目标就是最难的部分。

最终选了 YOLOv8n:在 4060 上训练和推理都能接受,精度损失在可容忍范围内,模型体积小、部署成本低,还有一个很实际的理由 ------ 后面要迁到没有独显的笔记本上跑 CPU 推理。

五、行为分类:5 个小模型,比 1 个大模型更好用

5.1 真实指标

5 个行为各训练了一个轻量二分类模型,验证集结果如下:

行为模型 体积 参数量 FPS 验证集 Acc 验证集 Precision 验证集 Recall
Look_up(抬头) 3.30 MB 843,362 349 98.70% 96.93% 98.72%
Stand(站立) 0.25 MB 53,858 633 99.31% 98.52% 90.50%
Use_phone(玩手机) 0.87 MB 212,578 477 94.82% 73.68% 60.58%
Head_on_desk(趴桌) 0.87 MB 212,578 453 94.70% 44.86% 44.86%
Whispering(耳语) 0.87 MB 212,578 457 94.57% 50.00% 27.78%

5.2 怎么读这张表

Acc 好看不代表可用。趴桌的验证集 Acc 有 94.70%,但 Precision 和 Recall 都是 44.86% ------ 这意味着模型「大部分时候说没有」,也能拿到 94.7% 的准确率。这类指标在类别不平衡任务里极具欺骗性。

任务难度差异是数量级的:

  • 抬头、站立这种姿态差异明显的行为,小模型就能做到 98%+,而且模型只有 0.25 MB,FPS 600+;
  • 玩手机属于中等难度,验证集 Recall 60.58%,实际使用需要配合时间窗口过滤;
  • 趴桌、耳语属于细粒度 + 严重不平衡,Recall 只有 44.86% 和 27.78%,直接拿来做「判定」会误伤大量学生。

5.3 产品层面的处置

对低召回行为,系统里做了降级处理:不作为「异常判定」,只作为「趋势提示」,并且要求连续多帧命中才计入统计。这是工程上比调模型更划算的做法 ------ 与其硬把 Recall 从 27% 拉到 60%,不如先让系统不误报。

六、工程化:让系统真的能跑起来

模型只是系统的一部分,剩下的工作量同样不小。

6.1 多线程依赖安装脚本

原来是静态的 setup() + install_requires,问题很明显:无法根据设备选择 CUDA 或 CPU 源,安装慢、易断。

改成了交互式安装脚本,核心逻辑:

python 复制代码
import threading, subprocess

device = input("推理设备 (cpu / cuda): ").strip()
torch_index = (
    "https://download.pytorch.org/whl/cu124"
    if device == "cuda"
    else "https://mirrors.aliyun.com/pypi/simple/"
)

def install(pkgs, index):
    subprocess.run(["pip", "install", *pkgs, "-i", index])

threads = [threading.Thread(target=install, args=(["torch==2.5.1", "torchvision==0.20.1"], torch_index))]
for dep in ["opencv-python==4.11.0.86", "ultralytics==8.3.99", "flask==3.1.0"]:
    threads.append(threading.Thread(target=install, args=([dep], "https://mirrors.aliyun.com/pypi/simple/")))

for t in threads:
    t.start()
while any(t.is_alive() for t in threads):
    done = sum(1 for t in threads if not t.is_alive())
    print(f"\r进度 {done / len(threads):.2%}", end="")

上面是核心逻辑示意,不是完整源码。

效果:PyTorch 单独线程走官方源,其余依赖并行走阿里云镜像,同时输出进度百分比。相比单线程串行安装,等待时间明显缩短。

6.2 Nginx 子路径反向代理

前后端和模型管理要共用一个入口,于是用 Nginx 监听 9004,按路径分发:

nginx 复制代码
server {
    listen 9004;
    server_name 10.5.8.248;

    location / {
        proxy_pass http://127.0.0.1:8080;
    }

    location /zheng_en_ci/ {
        proxy_pass http://127.0.0.1:8192/;
    }
}

关键点:proxy_pass 末尾的 / 会自动剥掉 /zheng_en_ci 前缀,后端服务不需要感知子路径 ------ 否则所有路由都要改一遍。

6.3 公网访问与打包

  • 公网访问:本地服务器 + 花生壳内网穿透,满足演示和试用;
  • 打包 :pyinstaller==6.14.2 把后端和模型管理分别编译成 exe,交给非技术用户也能一键启动;
  • 环境迁移:从带 4060 的机箱迁到 ThinkPad E15 Gen4 之后,模型管理模块全部改成 CPU 推理,重新验证了加载和推理链路。

七、LLM 教学辅助:让系统不只是「监控」

单做行为识别,价值天花板很低。所以接入了通义千问和中科院紫东太初,做了几个教学侧功能:

  • PPTX → 思维导图:解析课件结构,生成知识脉络;
  • 教案 / 题目生成:基于 PPTX + 提示词生成教案和带答案的题目,支持保存;
  • 英文翻译与解析:面向双语教学场景。

实现上用 langchain + openai SDK 的兼容层,模型管理服务独立打包,切换模型只改配置。

八、踩坑复盘

  1. 数据集决定上限。标注歧义、遮挡、小目标,这三条在训练前就锁死了模型能达到的高度;
  2. 训练集指标没有参考价值。所有模型训练集 mAP 都远高于验证集,只看 train loss 会严重误判;
  3. Acc 在类别不平衡时是陷阱。趴桌 94.7% 的 Acc 对应 44.86% 的 Recall;
  4. 多模型串行推理会拖垮实时性。5 个分类模型必须并行,否则单帧耗时直接翻倍;
  5. 打包成 exe 后路径全变。所有资源路径必须改成相对路径或运行时解析;
  6. 内网穿透只适合演示。真要做产品,得正经部署到有公网 IP 的服务器上。

九、开源与后续

项目前端部分已在 Gitee 开源:

arduino 复制代码
https://gitee.com/zheng-enci050704/AiKeTangJiaoXuePingCeXiTong_QianDuan

后续计划:

  • 补充低召回行为的高质量标注数据,优先解决耳语和趴桌;
  • 检测侧尝试 YOLOv8s / 更新版本,并导出 ONNX 做推理加速;
  • 视频流改成 WebSocket 推流,降低轮询开销;
  • 行为统计接入时序模型,从「单帧判断」升级为「行为片段识别」。

这个项目最大的收获不是某个模型涨了几个点,而是搞明白了一件事:AI 项目真正的难点,永远在数据、指标解读和工程落地这三件事上,模型结构反而是最简单的那一环。

如果这篇文章对你有帮助,欢迎在评论区交流教室场景下的检测和分类方案。

相关推荐
成为深度学习高手1 小时前
xLSTM-Mixer:用标量记忆同时混合时间与变量,把循环网络带回多元时序预测
人工智能·python·深度学习·数据挖掘·transformer
骑士雄师1 小时前
多轮对话流程梳理详细版本
python
进击的明明15 小时前
当AI开始“边想边干”:深入聊聊ReAct,以及如何用Python手搓一个简单Agent
python·面试·agent
全栈弄潮儿15 小时前
Python实战第8期:函数
后端·python·编程语言
卷无止境17 小时前
暗流与破局:AI时代的代码安全审查工具全景指南
后端·python
卷无止境20 小时前
一人公司的全栈选型指南:让 AI Agent 写得快,也让生意跑得稳
后端·python
滴啦嘟啦哒21 小时前
【具身笔记】【π0.5 微调与仿真】五、在MuJoCo中实现可视化仿真
笔记·python·vla·具身
全栈练习生1 天前
AI安全与红队测试
python·ai
费曼学习法1 天前
把「发送成功」当「送达」?我排查 IM 长消息被静默吞掉的完整过程
python·ai编程·自动化运维