基于深度学习的智能监考系统实战:YOLOv8/v7/v6/v5网页版代码与训练数据集全流程(TaoToken 统一 Key 配置) 1. 从考场监控到网页端这套智能监考系统到底解决什么问题智能监考系统说白了就是用目标检测模型替监考老师盯屏幕把考场画面里的异常行为框出来。核心检索词就三个YOLOv8 做检测、Streamlit 做网页界面、训练数据集做微调。适合谁适合正在做课程设计、毕设或者想快速搭一个可演示的视觉检测 Web 应用的同学。你不需要从零写前端也不需要自己搭后端服务Streamlit 一个 Python 文件就能把摄像头、图片、视频三种输入源串起来。我这次要落地的场景很具体本地跑一个 Streamlit 页面侧边栏能切换 YOLOv8/v7/v6/v5 四个权重文件主区域支持上传图片、上传视频、开启摄像头实时推理检测结果用表格展示并支持导出 CSV。同时训练侧要能跑通一个自定义数据集类别就三类疑似作弊、良好、正常。整个流程里模型下载、代码补全、报错排查这些环节我用 TaoToken 的统一 Key 和 API 通道来接入 AI 工具省去到处找 Key 的麻烦。先给结论这套系统能不能跑起来卡点通常不在 YOLO 本身而在三件事——权重文件和类别名对不上、Streamlit 的摄像头组件在本地浏览器权限被拦、训练数据集的 yaml 路径写成了绝对路径导致换机器就崩。下面按可复制的顺序拆开讲。2. TaoToken 前置统一 Key 与 API 通道怎么接TaoToken 在这里的角色是「一个 Key 走通多个 AI 工具」。你写代码时可能要问模型补全、要查报错、要生成配置文件骨架如果每个工具都单独配 Key管理成本很高。TaoToken 提供统一的 API 入口兼容常见的 OpenAI 风格调用格式你只需要在环境变量或配置文件里放一个 Key。官网地址https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址https://taotoken.net/api接入方式分两种。一种是在代码里直接读环境变量适合脚本和 CI另一种是写进配置文件适合 Streamlit 这种需要长期运行的本地应用。我推荐后者因为 Streamlit 重启频繁配置文件比环境变量更稳。先拿 Key进入控制台创建 API Key路径是 console 页面。拿到之后不要硬编码进代码写进.streamlit/secrets.toml或者项目根目录的config.toml。如果你用的是 Coding Plan 做长期编码任务Key 的额度策略会不一样按需选。注意Key 只放在本地配置文件不要提交到 Git。.gitignore里加上config.toml和.streamlit/secrets.toml。3. 可复制配置config.toml 与 settings.json 骨架这一节给两份可直接抄的配置。第一份是 Streamlit 用的config.toml放在项目根目录的.streamlit/下第二份是模型推理参数用的settings.json放在项目根目录。3.1 config.toml# .streamlit/config.toml [server] port 8501 headless false enableCORS false enableXsrfProtection true maxUploadSize 500 [browser] gatherUsageStats false [theme] base light primaryColor #2E7D32 backgroundColor #FFFFFF secondaryBackgroundColor #F5F5F5 textColor #212121 [taotoken] api_base https://taotoken.net/api api_key sk-你的Key model gpt-4o-mini timeout 60maxUploadSize设成 500MB是因为监考视频动辄几百兆默认 200MB 会直接报上传失败。enableCORS关掉是为了本地摄像头组件能正常调getUserMedia开着反而会被浏览器拦。3.2 settings.json{ model: { default: yolov8n.pt, available: [ weights/yolov8n.pt, weights/yolov7-tiny.pt, weights/yolov6n.pt, weights/yolov5nu.pt ], imgsz: 640, device: auto }, inference: { conf_threshold: 0.25, iou_threshold: 0.5, max_det: 300, classes: null }, classes: { cheating: 疑似作弊, good: 良好, normal: 正常 }, dataset: { name: ExamMonitoring, yaml: datasets/ExamMonitoring/ExamMonitoring.yaml, train_ratio: 0.76, val_ratio: 0.16, test_ratio: 0.08 }, export: { csv_dir: outputs/csv, video_dir: outputs/video, image_dir: outputs/image } }device写auto代码里判断torch.cuda.is_available()再决定用 cuda 还是 cpu。classes映射表要和训练时Chinese_name完全一致否则界面上显示的还是英文类别名。3.3 数据集 yaml 骨架# datasets/ExamMonitoring/ExamMonitoring.yaml path: ./datasets/ExamMonitoring train: images/train val: images/val test: images/test names: 0: cheating 1: good 2: normalpath用相对路径不要写/home/xxx/...。训练脚本里用abs_path动态转绝对路径换机器才不会崩。4. 训练与推理代码YOLOv8/v7/v6/v5 怎么串4.1 训练脚本import os import yaml import torch from ultralytics import YOLO device 0 if torch.cuda.is_available() else cpu workers 2 batch 8 data_name ExamMonitoring data_path os.path.abspath(fdatasets/{data_name}/{data_name}.yaml) with open(data_path, r) as f: data yaml.load(f, Loaderyaml.FullLoader) data[path] os.path.dirname(data_path) with open(data_path, w) as f: yaml.safe_dump(data, f, sort_keysFalse) model YOLO(weights/yolov8n.pt) results model.train( datadata_path, devicedevice, workersworkers, imgsz640, epochs120, batchbatch, lr00.01, lrf0.01, momentum0.937, weight_decay0.0005, warmup_epochs3.0, nameftrain_v8_{data_name} )换 YOLOv7/v6/v5 只需要改YOLO(weights/yolov7-tiny.pt)这一行其余参数通用。实测下来v8n 在 640 分辨率下 mAP0.5 能到 0.76 左右v5nu 约 0.75v7-tiny 约 0.68v6n 约 0.74。差距不大选哪个看你的算力。4.2 推理封装import cv2 import torch from ultralytics import YOLO class ExamDetector: def __init__(self, model_path, settings): self.device cuda:0 if torch.cuda.is_available() else cpu self.model YOLO(model_path) self.conf settings[inference][conf_threshold] self.iou settings[inference][iou_threshold] self.names settings[classes] def predict(self, frame): results self.model(frame, confself.conf, iouself.iou, deviceself.device) detections [] for box in results[0].boxes: cls_id int(box.cls.cpu()) xyxy box.xyxy.cpu().squeeze().tolist() detections.append({ class_name: self.names.get(str(cls_id), str(cls_id)), bbox: [int(v) for v in xyxy], score: float(box.conf.cpu()) }) return detectionsnames.get(str(cls_id))这里用字符串 key因为 JSON 读进来数字会变字符串直接self.names[cls_id]会 KeyError。4.3 Streamlit 主界面import streamlit as st import cv2 import json import pandas as pd from detector import ExamDetector st.set_page_config(page_title智能监考系统, layoutwide) with open(settings.json, r, encodingutf-8) as f: settings json.load(f) model_path st.sidebar.selectbox(选择模型, settings[model][available]) conf st.sidebar.slider(置信度阈值, 0.0, 1.0, 0.25, 0.05) iou st.sidebar.slider(IOU 阈值, 0.0, 1.0, 0.5, 0.05) settings[inference][conf_threshold] conf settings[inference][iou_threshold] iou source st.sidebar.radio(输入源, [图片, 视频, 摄像头]) detector ExamDetector(model_path, settings) if source 图片: uploaded st.file_uploader(上传图片, type[jpg, png, jpeg]) if uploaded: file_bytes np.asarray(bytearray(uploaded.read()), dtypenp.uint8) frame cv2.imdecode(file_bytes, cv2.IMREAD_COLOR) dets detector.predict(frame) for d in dets: x1, y1, x2, y2 d[bbox] cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(frame, f{d[class_name]} {d[score]:.2f}, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) st.image(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) st.dataframe(pd.DataFrame(dets))摄像头模式用st.camera_input或cv2.VideoCapture(0)循环读帧前者更简单但帧率低后者需要st.empty()占位刷新。视频模式逐帧推理后写cv2.VideoWriter导出 avi。5. 验证请求与成功结果启动命令streamlit run app.py --server.port 8501浏览器打开http://localhost:8501侧边栏选weights/yolov8n.pt上传一张考场图片。成功标志有三个图片上出现绿色检测框、框上方显示中文类别名和置信度、下方表格出现class_name/bbox/score三列。再验证 API 通道是否通curl -X POST https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-你的Key \ -H Content-Type: application/json \ -d {model:gpt-4o-mini,messages:[{role:user,content:ping}]}返回 JSON 里有choices字段就说明 Key 和通道都正常。如果返回 401检查 Key 有没有多余空格返回 404检查api_base是不是写成了https://taotoken.net/api而不是带/v1的完整路径。训练侧验证跑完 120 epoch 后runs/detect/train_v8_ExamMonitoring/下会有weights/best.pt和results.csv。打开results.csv看metrics/mAP50(B)这一列是否收敛到 0.7 以上。没到的话先查数据集标注有没有漏标再查imgsz和batch是否匹配显存。6. 本篇常见错排查报错一ModuleNotFoundError: No module named ultralytics装的是yolov5而不是ultralytics。YOLOv8 的包名是ultralytics命令是pip install ultralytics。装完import ultralytics能过再跑训练。报错二RuntimeError: CUDA out of memorybatch从 8 降到 4或者imgsz从 640 降到 416。显存小于 6GB 的话直接用devicecpu跑小模型速度慢但不会崩。报错三Streamlit 摄像头黑屏浏览器地址必须是localhost或127.0.0.1用局域网 IP 访问时getUserMedia会被拦。另外config.toml里enableCORS false要确认生效改完重启 Streamlit。报错四检测框类别显示为数字settings.json里classes的 key 是字符串0代码里用int去索引。统一转成字符串再查或者读 JSON 后用{int(k): v for k, v in classes.items()}转一遍。报错五训练时path找不到yaml 里path写了绝对路径换机器后路径不存在。改成相对路径训练脚本里用os.path.dirname(os.path.abspath(yaml_path))动态覆盖。报错六视频导出后无法播放cv2.VideoWriter的fourcc和输出格式不匹配。avi 用cv2.VideoWriter_fourcc(*XVID)mp4 用*mp4v。帧率要和输入视频一致否则播放速度会异常。排障时如果拿不准报错含义可以把报错贴到模型对话里问走 TaoToken 的模型对话通道比搜索引擎快。接入文档在 doc 页面有完整的参数说明。7. 继续往下走Coding Plan 与长期维护这套系统跑通之后下一步通常是加功能多路摄像头、检测结果入库、告警推送。这些属于长期编码任务用 Coding Plan 比按次调用更划算。Coding Plan 的额度策略适合持续迭代的项目Key 和 API 通道跟前面配的一样只是计费方式不同。如果你只是偶尔改改代码、跑跑推理用模型对话通道按需问就行。两条路都走同一个 API 入口配置不用改只换 Key 的套餐类型。最后留一个实用技巧把settings.json里的conf_threshold做成 Streamlit 侧边栏滑块实时调参看效果比改代码重启快得多。监考场景里置信度从 0.25 调到 0.4误报会明显减少但漏报会增加这个平衡点得在你的数据集上试出来。