拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Django+深度学习课堂行为识别系统:从环境搭建到推理部署全流程

简介这是一套面向高校计算机相关专业毕业设计场景的完整项目资料围绕“上课学生行为识别”展开采用Python语言与Django框架搭建后台管理系统结合YOLOv5与OpenCV实现课堂行为检测数据库使用MySQL适合作为深度学习与Web开发结合的毕设选题参考。系统区分管理员与学生两类权限管理员负责学生注册审核、课程信息维护、行为检测记录查询与通知发布学生端可修改个人信息、查看通知并通过摄像头选择当前课堂课程实时识别玩手机、睡觉、举手等课堂行为。压缩包共705个文件约299.74MB包含224个png、207个jpg、96个gif等图像素材44个py源码、50个js脚本、13个html页面及21个css样式文件另有sql建库脚本与db数据文件覆盖前端界面、后端逻辑与模型资源。资源还附带论文、开题报告与PPT已有110人学习便于读者快速理解系统架构、复现检测流程并整理毕设文档。1. 从一张教室监控截图说起这套 Django 深度学习行为识别系统到底能跑出什么去年帮一个做教务的朋友看他们学校的课堂录像四十分钟一节课人工回看统计学生抬头率、趴桌率、玩手机次数一个老师一天最多处理两个班眼睛都看花了。当时我就在想这种重复劳动完全可以用视觉模型顶上去。后来拿到这套「上课学生行为识别系统」它的定位很明确用 Python 深度学习做课堂场景下的学生行为分类再用 Django 把推理结果、统计报表、课程管理串成一个能登录、能上传、能看图的 Web 系统。技术栈是 Django PyTorch/OpenCV 这一套配套还带了论文、开题报告和答辩 PPT属于典型的毕业设计完整交付物。适合谁一是正在做计算机视觉方向毕设、需要一套能跑通闭环的同学二是想拿一个真实场景练手 Django 工程化部署的开发者。它解决的不是「识别精度刷到 SOTA」的问题而是「从数据集标注、模型训练、推理服务到 Web 展示」这条链路怎么打通。下面我按自己拆包复现的顺序把能抄的步骤和踩过的坑都摊开讲。2. 环境与依赖把 Django 和深度学习框架装到同一台机器上2.1 为什么这套系统对 Python 版本和 CUDA 特别敏感这套项目本质上是两个技术栈的缝合Django 负责 Web 层PyTorch或 TensorFlow看具体实现负责推理层。缝合点在于 Django 的视图函数里要 import torch 并加载模型权重。问题就出在这里——Django 4.x 要求 Python 3.8 以上而很多深度学习轮子对 Python 小版本又很挑。我见过最常见的翻车是系统里装了 Python 3.12pip 装 torch 时找不到对应版本的 whl于是 pip 自动去编译源码编译到一半报错退出。所以第一步不是急着 pip install而是先把版本对齐。我一般会这样确认环境# 查看当前 Python 版本建议 3.8 ~ 3.10 python --version # 查看 pip 对应的 Python pip --version # 如果有 NVIDIA 显卡确认驱动和 CUDA 版本 nvidia-sminvidia-smi右上角显示的 CUDA Version 是驱动支持的最高版本不是你必须装的版本。比如显示 12.1你装 cu118 的 torch 也完全没问题向下兼容。没有独显就用 CPU 版 torch训练会慢但推理一张图几百毫秒也能接受毕设演示够用。2.2 依赖安装的推荐顺序与 requirements 处理拿到源码包后先别急着pip install -r requirements.txt。很多毕设项目的 requirements 是作者本机pip freeze出来的里面混了一堆无关包甚至锁死了平台相关的版本。我的做法是先看文件内容把核心依赖挑出来单独装。# 建议先建虚拟环境避免污染全局 python -m venv venv # Windows 激活 venv\Scripts\activate # Linux / macOS 激活 source venv/bin/activate # 先装深度学习框架CPU 版示例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu # 再装 Web 与图像处理相关 pip install django opencv-python pillow numpy这里有个参数值得说--index-url指向 PyTorch 官方轮子源比默认源快很多也能避免装到同名但不对的包。装完 torch 后进 Python 敲import torch; print(torch.__version__)确认能正常导入再继续装 Django。顺序反了的话Django 装完发现 torch 导入失败你还得回头排查浪费时间。2.3 数据库迁移与静态文件Django 首次启动必做Django 项目跑起来之前数据库表结构得先建好。这套系统一般用 SQLite开箱即用不用额外装 MySQL。# 生成迁移文件如果作者没提供 python manage.py makemigrations # 执行迁移建表 python manage.py migrate # 创建后台管理员账号 python manage.py createsuperuser # 启动开发服务器 python manage.py runservermigrate这一步如果报错八成是 models.py 里定义的字段和已有迁移文件对不上或者作者把 db.sqlite3 一起打包了但表结构是旧的。遇到这种情况把 db.sqlite3 删掉重新 migrate 通常能解决但要注意会丢失已有数据。createsuperuser创建的账号用来登录 Django admin 后台方便你直接看数据库里的识别记录。启动后浏览器访问 127.0.0.1:8000能看到登录页或首页说明 Web 层通了。这时候还没到模型推理别急着传图。3. 模型推理链路从上传一张课堂图到返回行为标签3.1 数据预处理为什么训练时的归一化参数必须和推理一致深度学习模型对输入尺寸和数值范围极其敏感。训练时如果用的是 224x224 输入、ImageNet 均值方差归一化推理时也必须一模一样。我见过有人推理时直接cv2.imread读原图塞进模型结果输出全是乱码标签——因为尺寸和归一化都对不上。这套系统里通常会在推理脚本或 Django 视图里封装一个预处理函数你要确认它和训练脚本用的是同一套参数。import cv2 import numpy as np import torch def preprocess(image_path, input_size224): # 读取图片注意 OpenCV 默认 BGR img cv2.imread(image_path) # 转 RGB因为训练时多半用的是 RGB img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 缩放到模型输入尺寸 img cv2.resize(img, (input_size, input_size)) # 转 float 并归一化到 [0,1] img img.astype(np.float32) / 255.0 # 标准化均值方差要和训练一致 mean np.array([0.485, 0.456, 0.406]) std np.array([0.229, 0.224, 0.225]) img (img - mean) / std # HWC - CHW再加 batch 维度 img img.transpose(2, 0, 1) img np.expand_dims(img, axis0) return torch.from_numpy(img).float()逻辑说明cvtColor转 RGB 是因为 OpenCV 读进来是 BGR而 PyTorch 预训练模型基本都按 RGB 训练。resize到 224 是 ResNet、MobileNet 这类骨干网的标准输入。归一化的 mean/std 是 ImageNet 统计值如果你训练时用的是自己算的均值方差这里必须换成你自己的。最后transpose把通道维换到前面expand_dims加 batch 维因为模型 forward 期望的是 NCHW 四维张量。参数input_size要和你训练时的配置对齐改错一个数字精度就掉一大截。3.2 加载权重与推理state_dict 不匹配怎么办模型结构定义在某个 model.py 里权重要么是 .pth 要么是 .pt。加载时最常见的报错是Missing key(s) in state_dict或Unexpected key(s)。前者说明模型定义少了层后者说明多了层。还有一种情况是作者用torch.save(model)保存了整个模型对象而不是state_dict这种加载方式对目录结构有依赖换台机器就可能失败。import torch from model import BehaviorNet # 假设模型定义在这个模块 # 实例化模型结构 model BehaviorNet(num_classes5) # 加载权重map_location 保证 CPU 也能加载 GPU 训练的权重 state_dict torch.load(weights/best.pth, map_locationcpu) # 如果保存的是整个模型而非 state_dict需要判断 if isinstance(state_dict, dict) and state_dict in state_dict: state_dict state_dict[state_dict] model.load_state_dict(state_dict) model.eval() # 切换到推理模式关闭 dropout 和 batchnorm 更新map_locationcpu是个后悔药级别的参数没有它GPU 上训练的权重在纯 CPU 机器上加载会直接报错。model.eval()必须调用否则 dropout 层会随机丢弃神经元每次推理结果都不一样你会以为是模型玄学其实是模式没切对。如果load_state_dict报 key 不匹配先用print(model.state_dict().keys())和print(state_dict.keys())对比看差在哪一层再决定是改模型定义还是改权重加载逻辑。3.3 把推理接进 Django 视图一次请求的完整生命周期Web 层和模型层的交汇点在 views.py。用户上传图片视图接收文件调用预处理和推理把结果写进数据库再渲染到模板。这里要注意的是模型加载不能放在每次请求里否则每传一张图就重新加载一遍权重慢到无法忍受。正确做法是在模块级别或 AppConfig.ready() 里加载一次全局复用。from django.shortcuts import render from django.core.files.storage import FileSystemStorage from .models import RecognitionRecord from .inference import predict # 封装好的推理函数 def upload_and_predict(request): if request.method POST and request.FILES.get(image): image request.FILES[image] # 保存上传文件 fs FileSystemStorage() filename fs.save(image.name, image) file_path fs.path(filename) # 调用推理返回标签和置信度 label, confidence predict(file_path) # 写入数据库 RecognitionRecord.objects.create( imagefilename, labellabel, confidenceconfidence ) return render(request, result.html, { label: label, confidence: round(confidence, 4), image_url: fs.url(filename) }) return render(request, upload.html)逻辑说明request.FILES拿到上传的文件对象FileSystemStorage负责落盘并返回可访问路径。predict函数内部做了预处理、模型 forward、softmax 取最大概率。RecognitionRecord.objects.create是 Django ORM 的写入操作一行搞定建表插入。confidence用 round 保留四位小数避免模板里显示一长串浮点数。这里有个隐藏坑如果predict里加载模型用了全局变量而 Django 开发服务器默认是多线程的第一次请求时模型还没加载完第二个请求进来可能拿到空模型。稳妥做法是在apps.py的ready()里预热加载。4. 避坑与排查复现这套系统时最容易翻车的五个地方4.1 上传图片后页面报 500日志显示 CUDA out of memory现象本地用 CPU 跑得好好的换到有显卡的机器或者服务器上传几张图之后突然 500。原因模型默认加载到了 GPU但显存被其他进程占着或者 batch 维度没控制好一次塞了太多图。解决在加载权重时显式指定map_locationcpu或者推理前torch.cuda.empty_cache()。如果确实要用 GPU把 batch_size 设为 1课堂场景单张推理足够。另外检查是不是在视图里循环调用了模型加载导致显存里堆了一堆重复模型。4.2 识别结果永远是同一个标签现象不管传什么图输出都是「抬头」或都是「趴桌」。原因最常见的是预处理归一化参数和训练不一致模型收到的输入分布完全变了相当于在噪声上推理。其次是model.eval()没调用dropout 随机性导致输出不稳定但偏向某一类。解决先确认训练脚本里的 mean/std 和 resize 尺寸逐项对齐再确认 eval 模式最后用训练集里的一张图做推理如果训练图都识别错那就是权重加载有问题检查 state_dict 的 key 是否完全匹配。4.3 Django 静态文件 404CSS 和 JS 加载不出来现象页面能打开但样式全乱控制台一堆 404。原因Django 开发模式下静态文件需要配置STATIC_URL和STATICFILES_DIRS生产模式下还需要collectstatic。很多毕设项目只在自己机器上跑过settings.py 里的路径是绝对路径换台机器就找不到。解决检查 settings.py 里STATIC_URL /static/和STATICFILES_DIRS [os.path.join(BASE_DIR, static)]确保 static 目录真实存在。如果用了DEBUG False还要配STATIC_ROOT并执行python manage.py collectstatic。4.4 数据库迁移报 no such table现象migrate显示成功但一访问页面就报no such table: app_xxx。原因Django 的 app 没有注册到INSTALLED_APPS里迁移时跳过了这个 app 的模型。或者作者提供的 db.sqlite3 是旧版本表结构对不上。解决打开 settings.py确认你的 app 名字在INSTALLED_APPS列表里。如果是旧数据库删掉 db.sqlite3重新makemigrationsmigrate。注意makemigrations要指定 app 名比如python manage.py makemigrations yourapp否则可能漏掉。4.5 上传大图导致请求超时或内存溢出现象手机拍的课堂照片三四千像素宽上传后服务器卡死或报 MemoryError。原因原图直接读进内存做 resize一张 4000x3000 的图占几十 MB并发几个请求就爆了。解决在预处理前先做一次降采样用cv2.resize把长边限制到 800 以内再走后续流程。或者在 Django 层面限制上传文件大小settings.py 里设置DATA_UPLOAD_MAX_MEMORY_SIZE和FILE_UPLOAD_MAX_MEMORY_SIZE。课堂场景不需要原图精度压缩后再推理对结果几乎没影响。5. 进阶技巧用 Django ORM 做行为统计与模型置信度过滤5.1 按课程和时间段聚合识别记录系统跑起来之后真正有价值的是统计数据而不是单张图的标签。Django ORM 的聚合查询能直接出报表不用手写 SQL。比如统计某门课下每种行为出现的次数from django.db.models import Count from .models import RecognitionRecord # 按标签分组计数过滤置信度低于 0.6 的记录 stats (RecognitionRecord.objects .filter(course_id1, confidence__gte0.6) .values(label) .annotate(totalCount(id)) .order_by(-total)) for item in stats: print(item[label], item[total])filter里的confidence__gte0.6是置信度阈值低于这个值的记录不参与统计避免模型瞎猜的标签污染报表。values(label)指定分组字段annotate做计数order_by(-total)按次数降序。这套查询在 Django 里是惰性的只有遍历 stats 时才真正打数据库所以可以放心在视图里用。如果你要按时间段统计把filter里的条件换成create_time__range(start, end)即可。5.2 置信度阈值怎么定别拍脑袋看分布置信度阈值不是拍脑袋定的 0.5 或 0.6。我的习惯是先把一批测试图的置信度打印出来看分布。如果模型对某类行为普遍给出 0.9 以上那阈值可以设 0.7如果普遍在 0.5 到 0.7 之间晃说明模型本身没学好这时候调阈值只是自欺欺人得回去看训练。可以用下面这段代码快速看分布import numpy as np from .inference import predict confidences [] for path in test_image_paths: _, conf predict(path) confidences.append(conf) # 打印分位数了解整体置信水平 print(25%:, np.percentile(confidences, 25)) print(50%:, np.percentile(confidences, 50)) print(75%:, np.percentile(confidences, 75))如果中位数在 0.8 以上说明模型对大部分样本有把握阈值设 0.6 到 0.7 比较稳。如果中位数只有 0.5 出头那说明模型在瞎猜这时候该做的是检查训练数据标注质量、类别是否均衡、学习率是否合理而不是在推理端调参。我一般会把阈值设成中位数减 0.1这样能过滤掉明显不可信的记录又不至于把大部分结果都扔掉。5.3 一个我踩过的坑模型文件路径写死导致部署失败最后说个血泪经验。很多毕设项目里加载权重的路径是写死的绝对路径比如torch.load(D:/project/weights/best.pth)。你自己机器上跑没问题一换机器或者部署到服务器就报 FileNotFoundError。正确做法是用os.path.join(BASE_DIR, weights, best.pth)BASE_DIR 在 Django settings 里已经定义好了。从那以后我每次拿到新项目第一件事就是全局搜torch.load和open(看有没有硬编码路径。这个习惯帮我省了至少三次通宵排查。希望这套拆解能帮到你少走点我走过的弯路。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门