
考场里那套自动监考的改造项目一开始最纠结的问题就是到底用什么技术路线。我也试过直接上动作识别模型想从视频流里端到端输出“作弊/正常”结果被数据量、标注成本和误报率反复教育。最后落地的方案非常务实核心就是YOLOv8、YOLOv7、YOLOv6、YOLOv5这一系列目标检测模型再叠加上目标跟踪和规则判断组合成一套完整的智能监考系统摄像头拉流、检测人和可疑物品、给每个考生分配稳定ID、根据位置关系和持续时间触发告警。它能解决的真正痛点是把监考老师从几十路实时视频里解放出来只在确有可疑时推送一条带截图的提示。这套思路对正在做边缘视觉识别、考场数字化、安防监控的开发者会很有参考价值下面我把选型理由、数据标注、训练调优、行为判断和部署排障全部摊开讲。1. 考场监控的痛点和系统设计思路1.1 人工监考为什么漏系统需要补什么人工监考最大的问题不是“看不看得见”而是“注意力能撑多久”。一个老师盯四五个考场监控屏前二十分钟还行四十分钟以后就开始疲劳靠回放录屏找证据又消耗大量人力。作弊动作本身往往是短促的掏手机、翻小抄、侧头看邻座可能只持续两三秒。人眼漏掉很容易机器却可以把每一帧都过一遍这是智能监考系统存在的根本理由。但这里有个常见的认知误区不要试图用一个大模型直接判断“是否作弊”。作弊是一个组合行为需要结合人、物体、位置、持续时间才能判断。单模型输出作弊概率结果是不可解释的——一旦误报管理员根本不知道它是根据什么判的。所以我把决策拆成两层底层用YOLO系列做目标检测输出人和物品的位置上层用规则引擎组合这些位置信息形成可靠的行为判断。这样既利用了检测模型的高精度又保留了逻辑的可控性。这套系统的目标并不是取代监考老师而是做一个“辅助注意力放大器”它能持续观测每一个考生记录下哪一帧出现了手机、哪段时间低头过长、哪两个座位长时间靠近再以告警片段的形式交给人工复核。这样监考老师只需要看结果不用全程盯着屏幕。1.2 把作弊行为拆成可检测的目标我把考场里需要关注的行为归成了五类每类都能映射到目标检测和空间关系上行为类型可观测特征判断依赖使用手机手机类目标出现在头手附近区域person、phone的框距离翻看书本/纸张桌面出现书本或纸张且头部低垂book、sheet、person的姿态交头接耳两个头部框距离过近且持续时间长person框、头部区域左右偷看头部朝向与屏幕/邻座夹角异常person框、关键点可选离开座位座位ROI内person框消失摄像头区域mask、tracking实际标注时不需要标“作弊”标签那既主观又容易漏。只标可见的物体类别再通过后置逻辑去映射行为这是整个系统做得稳的关键。因为模型只需要学习“画面上有没有手机、有没有纸片”这是相对明确的任务训练数据也好准备。1.3 整体流程与模块划分最后的架构不是单一模型而是这样一条链路摄像头视频流 - 抽帧 - YOLO目标检测 - 多目标跟踪获取稳定ID - 对每个目标计算位置关系与行为持续时间 - 规则引擎判断是否告警 - 推送含截图的提示给监考端。每个模块都可以独立替换检测模型可以在YOLOv5到YOLOv8之间换跟踪模块可以用ByteTrack也可以用DeepSORT规则引擎甚至可以直接用一个YAML配置文件编写。这种模块化设计是为了降低后续试错成本。实际开发中我先跑通了一条完整链路把检测精度和告警准确率调到可接受范围再考虑多路部署和性能优化。千万不要一上来就追求“全功能平台”那只会让调试变得特别痛苦。2. YOLOv5到YOLOv8选型对比与我的最终判断2.1 四个版本的核心变化YOLOv5、YOLOv6、YOLOv7、YOLOv8都不是同一个团队在同一时期推出的迭代版本它们更像是目标检测领域多个并行探索的产物。它们的核心差异主要体现在Backbone结构、检测头形式和训练策略上。YOLOv5是普及度最高的版本使用CSPDarknet作为骨干检测头是Anchor-Based方式特点是生态成熟、部署资料多训练配置也简单。YOLOv6针对工业部署做了大量优化提出了一套更简洁的骨架和Anchor-Free检测头训练速度比较快适合追求工程效率的场景。YOLOv7进一步引入重参数化模块和辅助训练头在相同算力下能取得更高精度但训练时显存占用会高一些。YOLOv8则是目前社区使用最广的版本骨干改为C2f结构检测头也是Anchor-Free同时集成了更完善的训练、导出和量化工具链在部署便利性上领先。单纯从精度排行榜看不同版本在不同数据集上互有胜负但工程选型不能只看榜单数字。我的判断依据是训练代码好不好改、导出ONNX/TensorRT是否顺手、社区踩坑资料多不多。从这几点看YOLOv5和YOLOv8都排在前面YOLOv6也是不错的选择YOLOv7则适合手里有较多训练资源、愿意进一步调参的团队。2.2 智能监考场景下的最终选择我在这个项目里最终选择了YOLOv8s作为主模型。原因有三个第一Anchor-Free检测头不需要预设锚框尺寸对手机、书本这类形状变化大的目标更友好第二训练与导出工具链完整从PyTorch权重到ONNX再到TensorRT引擎几乎是一条命令走完第三YOLOv8n/s版本体量小在教室这种密集场景下推理速度足够。不过我也要强调一点如果项目里已经有一套跑得挺顺的YOLOv5流程并且积累了标注数据那完全没必要强行切到YOLOv8。YOLOv5n在边缘设备上的推理延迟很低模型的部署资料也很多。我的建议是在满足实时性和精度的前提下优先选你团队最熟悉的版本。模型版本只是工具不是目标。2.3 算力估算与硬件配置教室场景一般是多路监控摄像头需要预先估算推理算力。我按这样一个公式做初步评估需要处理的路数 × 每路帧率 × 单帧推理耗时再留出20%-30%冗余。举个例子20路1080P摄像头每路只处理5FPS那系统整体需要100FPS的推理吞吐。如果用YOLOv8s在单张主流GPU上做TensorRT FP16推理单帧大概能跑到2-3毫秒理论上够用但实际还要考虑预处理、跟踪、后处理所以我把帧率降到3FPS就足够因为作弊动作通常持续数秒不需要高帧率。边缘端方案则建议使用Jetson系列或带NPU的盒子搭配YOLOv5n或YOLOv8n。摄像头侧统一降低输入分辨率到768×768或640×640不要直接处理原始1080P否则计算量会翻倍。3. 训练数据集制作标注什么、怎么标、如何避坑3.1 真实考场数据的采集方案数据质量决定模型上限。我刚开始贪图省事从网上找了一些相关公开数据但到了现场测试时发现效果很差因为摄像头视角、考场桌椅布局、光线都和训练数据对不上。所以项目启动后最优先的事情是去目标考场装几台临时摄像头采集真实画面。采集要覆盖几种典型角度教室正前方、教室后侧、侧面过道时间维度上要覆盖上午强光、下午侧光、阴天、拉窗帘后的昏暗情况。每路视频分辨率至少720P最好1080P采集。样本不要只拍“正在作弊”的画面也要拍大量正常考试画面这直接决定了模型误报率的起点。我的经验是正常帧和作弊帧比例接近3:1模型能学到“什么是干净背景”不容易把书挡住手就识别成异常。如果条件不允许退而求其次可以用模拟考场请同事或同学扮演考生每隔一段时间摆出看手机、翻纸条、侧头等动作。模拟数据的好处是作弊动作姿态丰富缺点是背景单一所以模拟数据和真实数据最好都用来训练。3.2 类别定义与标注规范我最终只定义了6个检测类别person、phone、book、sheet、electronic_device、chair。这里有几个容易被忽略的点不要标注“作弊”这个抽象类别。作弊是结果不是物体。标成person和phone模型学习的是稳定的视觉特征换成新场景还能用标成cheating模型只会记住训练集里那几个动作的背景。不要把书本和纸张合并成一个类。如果合并规则引擎无法区分“翻书”和“看一张小纸片”。虽然两者都是可疑行为但一旦出现一叠试卷放在桌上整张桌面都是sheet类误报率立刻飙升。我在第一次训练时就合并了结果正常考试时全场报警后来拆开才好。手机和电子设备分开。手机、手表、计算器都有屏幕但尺寸和形态差异大。合并后模型容易把小尺寸计算器识别成手机导致大量误报。如果电子设备样本不足宁可单独增加拍摄也不要合并。标注框要紧贴目标边缘不要为了省事把整个手部区域包进去。手常作为背景框大了模型学习到的是“手手机”不是“手机”会导致推理时握笔的手也被误检。3.3 数据增强、清洗与质检训练阶段会开启Mosaic、MixUp、HSV扰动、随机遮挡、翻转等增强。对考场场景我认为Mosaic有用但不要全程开启。在最后30个epoch建议关闭否则模型会忽略真实场景里的目标尺寸分布。数据清洗比增强更重要。我用脚本统计每个类别的目标数量后发现person的目标框数量可能是phone的50倍以上。这种严重不平衡如果不处理模型会把精力集中在“找得到人”上手机和纸张的recall会很低。处理办法并不是简单复制手机样本而是把手机出现时间段的相邻帧单独采样同时用更宽的裁剪窗口把手机周围的场景也保留下来。我还会手动抽查那些置信度低于0.3的检测结果如果同一张图被反复漏检就优先补标类似图像。质检环节我用LabelImg和X-AnyLabeling标注再让另一套同源模型对训练集做推理把预测结果和标注框不一致的图片拉出来人眼复核。这一步能发现大量标注边界错位和漏标情况。数据迭代做到位再去调模型比盲调超参数有效得多。4. 模型训练与推理优化实操4.1 训练超参与调优细节我的训练配置大致是这样的输入分辨率640×640batch size根据显存尽量给到16或32初始学习率0.01使用SGD优化器总epoch数120-150。前80个epoch开Mosaic和MixUp最后30个epoch关掉并做随机抖动帮助模型适应真实分布。类别不平衡需要专门处理。YOLOv8默认的分类损失权重可以对不同类别单独调整我把phone、sheet这两个小目标类别的权重提高到默认值的1.5-2倍。还有一个细节是学习率调度。不要用过早降低学习率的方案否则小目标类别还没收敛就被压住了。我用的策略是前30个epoch保持较高学习率让模型快速找到目标后90个epoch按余弦退火慢慢收敛。训练过程监控中除了看mAP我更关注每个类别单独的AP值。特别是phone的AP它直接决定了系统能不能发现最关键的作弊行为。如果phone的AP偏低就要回头看数据采样和增强策略而不是继续增加epoch。4.2 训练中出现的典型问题与处理我这次遇到的最大问题是手机漏检。教室后排座椅上手机只有20×40像素几乎看不清。后来加入两种处理一是把原图切分成更小的patch把后排目标放大后再训练一个专门模型二是在推理时对原图做一次“重点关注区域放大”也就是把座位区域按两倍尺寸裁剪后单独检测最后合并结果。这种方法会增加推理耗时但只对疑似低置信度区域启用所以整体开销可控。另一个问题是书本和手机的混淆。书页上的电子屏幕图案、反光封面经常被识别成手机。解决方法是增加“电子屏反光”在手机上呈现的样本同时把book类别的训练数据加入大量封面特写。我还刻意把纸张上的黑色印刷字体放大、改变倾斜角度让模型知道“平面图文”不等于手机屏幕。训练到后期模型在训练集上表现很好但测试集误检增多这是过拟合信号。我把Dropout打开、关掉部分增强中扰动幅度并且引入随机遮挡让模型不能只依赖背景纹理。考场这种静止背景很容易让模型学到“这张桌子存在手机”的捷径。4.3 导出与量化让模型跑得更快训练完成后我一般先导出ONNX再转成TensorRT或OpenVINO格式。对于GPU端TensorRT FP16是首选对于CPU或边缘NPUOpenVINO和INT8量化更现实。导出命令大致是yolo export modelruns/train/exp/weights/best.pt formatonnx dynamicFalse imgsz640 simplifyTrue然后使用trtexec转换trtexec --onnxyolov8s.onnx --saveEngineyolov8s_fp16.engine --fp16 --workspace2048如果目标设备是Intel CPU就转成OpenVINO格式yolo export modelbest.pt formatopenvino imgsz640量化后我需要特别注意精度回退。INT8量化最容易让手机这类小目标AP掉点。我的做法是拿一个包含1000张干净标注的验证集做精度对比如果phone的AP下降超过3个百分点就改用FP16或重新做带校准集的INT8量化。实际部署中TensorRT FP16比PyTorch推理快大约2-3倍对100FPS场景来说这个提升非常明显。5. 行为判断逻辑与告警策略模型之外的“监考脑”5.1 从检测框到可疑行为模型输出的只是一堆框系统要判断作弊必须把这些框转成空间关系。我写了一个轻量规则引擎输入是每一帧的目标框坐标和置信度输出是“持续可疑事件”。手机检测判断比较简单当phone目标的中心点落入某个person头部或手部附近区域且持续超过2秒就产生一条“疑似使用手机”事件。这里不要只看一瞬间的重叠摄像头视角会让人和手机的位置偶发重叠比如只是手机放在桌上刚好手部区域边框覆盖了它。所以必须加持续时间。翻看书本和纸张的判断我用的是person框和book/sheet框的关系。正常考试时试卷并不异常但如果sheet类目标长时间停留在桌面上方并且伴随person框的头部位置明显下移这类组合才触发告警。如果用关键点模型还可以计算头部俯仰角度超过某个阈值再报警但这不是必须的。5.2 多目标跟踪与轨迹缓存考场里有几十个考生如果不跟踪光靠单帧输出规则会产生大量抖动。我用ByteTrack给每个人分配稳定ID。它的好处是简单、不需要额外ReID特征适合人基本静止在座位上的场景。当人物短暂被前排遮挡时IOU匹配会暂时丢失但只要重新出现ID能恢复同一身份。每个跟踪ID后面保存一个滑动窗口缓存长度约100帧记录目标位置、置信度、周围物体类别和距离。规则引擎每处理一次新帧就更新这个缓存并在窗口内判断事件是否持续超过阈值。这个设计让逻辑实现变得很直观不是用“当前帧是否重合”来判断而是用“近N帧里重合了M帧”来判断抗抖动能力强很多。5.3 静默告警与防误报机制最开始部署时我的告警延迟设得很低几乎每发现一次手机框就立刻推送结果监考端被刷屏管理员直接关掉了系统。后来我加了三个缓冲机制事件确认期。检测到可疑行为后先进入“待确认”状态如果在连续2秒内稳定复现状态升级为“已确认”再推送如果中间消失超过0.5秒状态重置。这能过滤大量瞬时误检。单事件冷静期。同一个考生ID触发同一类告警后5分钟内不再重复推送只有新增其他类型行为或事件重新持续超过更长时间才再次告警。这样可以防止一条小人影浮动的误检反复轰炸。ROI区域过滤。在摄像头画面上划定每个座位的ROI同时屏蔽讲台、门口、窗户这些区域。比如监考老师从讲台边走过手机短暂入镜但ROI不在考生座位范围内就不会触发告警。这个功能看着简单实际是降低误报率最有效的手段之一。我用一个Python伪代码来表达核心逻辑def check_event(track, frame_id): phone_near track.has_overlap_with(phone, person_idtrack.id, dist_thresh0.15) if track.confirmed_phone_frames 12: # 连续2秒按6fps计算 if not track.cooldown_active(phone, 300): # 300帧冷却 trigger_alert(track.id, phone, frame_id) track.reset_phone_window()这里的阈值都要根据摄像头帧率和视角微调。我初期直接照搬默认值后来在真实考场里跑发现12帧阈值偏紧又调到了20帧误报降了一大半。6. 整体系统部署实录与常见故障排查6.1 系统各部分部署顺序与架构整个系统跑起来之后代码层面分成四个部分视频采集与拉流、检测推理、规则引擎、策略中心与前端告警。部署时不要一次性全上我建议的顺序是先跑通“单路视频流 检测 可视化画框”用一台笔记本摄像头做现场演示确认模型和规则逻辑能跑通。然后把规则引擎接进去加入持续时间、ROI、冷处理用离线录制好的视频段反复重放把告警准确率调到85%以上。最后才接入多路RTSP流增加队列和并发推理部署到服务器或边缘设备。管理端页面只需要展示告警列表和截图我的经验是告警截图一定要本地保存因为它是人工复核的第一证据。每次告警不仅要有时间戳还要把对应帧和之后3秒的视频片段留存下来否则后台管理员只能看到一行文字信任度会大打折扣。6.2 RTSP流接入与多路并发考场摄像头通常输出RTSP流。OpenCV的VideoCapture直接读RTSP在弱网环境非常容易卡死所以我给每路流独立建一个采集线程用先进先出队列缓存最新帧推理端从队列里取帧。队列长度限制在10帧左右满了就丢弃最旧帧保证推理永远拿到新鲜画面。import threading import queue stream_queue queue.Queue(maxsize10) def pull_stream(rtsp_url): cap cv2.VideoCapture(rtsp_url) while True: ret, frame cap.read() if not ret: cap.release() cap cv2.VideoCapture(rtsp_url) time.sleep(2) continue if not stream_queue.full(): stream_queue.put(frame) else: try: stream_queue.get_nowait() stream_queue.put(frame) except queue.Empty: pass如果RTSP断流我的处理方式是让采集线程自动重连并打印日志标记异常。不要在主线程里做重连逻辑否则会拖垮整个推理流程。多路并发推理时我按两路视频分配一个GPU推理上下文每路采用独立的推理线程但共享同一个TensorRT引擎实例。这样能明显降低显存占用。6.3 高频故障与排查记录我在实际运行中收集到下面这些高频问题整理成表症状常见原因解决方案推理延迟高GPU占用100%所有摄像头都跑原始1080P全帧率限制每路为3-5FPS分辨率降到640手机漏检严重后排目标太小、样本不足增加小目标patch训练启用ROI放大手机误检多书本反光、电子设备未分类单独增加book/sheet样本调整类别同一考生ID持续跳变检测置信度太低目标框闪烁提高检测阈值到0.45调整ByteTrack参数夜间噪点导致误检摄像头低照度噪声大增加图像预处理使用ISP降噪RTSP断流卡死网络抖动或摄像头重启独立线程自动重连超时释放另外还有一个经常被忽略的点摄像头的时间同步。多路视频流如果时间戳不同规则引擎里“同一事件跨镜头拼接”就会错乱。我在推流端统一用NTP时间校准并在告警记录里写入帧对应的绝对时间而不是只写“第几帧”。个人经验与扩展建议项目做下来我最大的体会是“模型只是系统的一半另一半是规则和工程细节”。在一个静止的考场里YOLOv8的检测精度再高如果没有持续时间和ROI过滤上线第一天就会因误报被管理员关停。我先花了大量时间在数据采集和规则阈值上模型本身反而改动不多。如果你也要做类似的智能监考或行为分析系统建议预留至少30%的时间做现场压力测试把告警截图和误报样本自动保存下来每隔几天让模型重新训练一版。这套数据闭环跑通之后系统才会越用越准而不是停留在实验室Demo阶段。