ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

YOLO全系实战:2000张课堂行为检测数据集训练与避坑指南

YOLO全系实战:2000张课堂行为检测数据集训练与避坑指南 简介这份资源面向计算机视觉方向的学生、教师与算法工程师提供一套可直接用于YOLO系列目标检测训练的学生课堂行为数据集解决课堂场景下行为识别数据采集与标注成本高的问题。压缩包共约2000个文件以1999个txt标注文件和1个yaml配置文件为主txt对应每张图像的边界框标注yaml用于定义数据集路径与类别信息整体约502.99MB已按训练集、验证集、测试集划分完毕开箱即用。数据集涵盖举手、阅读、书写、使用手机、低头、趴在桌子上共6个类别覆盖课堂中常见的学习与分心行为适合yolov5、yolov8、yolo11等模型直接加载训练与效果验证。目前已有347人学习下载读者可据此快速搭建课堂行为检测基线省去数据清洗与格式转换环节将精力集中在模型调优与场景落地上。1. 学生课堂行为检测数据集从 2000 张标注图到 YOLO 全系跑通带过几个课堂行为识别的项目后我发现真正卡住进度的往往不是模型结构而是数据。你拿到一份 2000 多张、6 类别、已经划分好训练集/验证集/测试集、还附带 data.yaml 的 YOLO 格式数据集理论上开箱即用但实际跑起来总有人翻车路径对不上、类别名和索引错位、验证集 mAP 死活上不去。这篇就把 yolov5、yolov8、yolo11 三个版本在这份课堂行为数据集上的落地路径讲清楚——数据怎么验、环境怎么配、训练参数怎么设、坑在哪。适合手里已经有这份数据集、想快速跑出第一版基线的人也适合想搞清楚 YOLO 数据集目录规范到底长什么样的新手。2. 先验数据再谈训练2000 张 6 类别数据集的目录结构与校验2.1 YOLO 数据集的标准目录长什么样一份「划分好的训练集、验证集和测试集」的 YOLO 数据集常见目录结构是这样的dataset/ ├── data.yaml ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/注意 images 和 labels 是平行目录不是嵌套。很多人第一次拿到数据集会把 labels 塞进 images 里面训练时 Ultralytics 找不到标签文件直接报No labels found。另一种常见布局是 train/val/test 各自带 images 和 labels 子目录两种都能用关键是 data.yaml 里的路径要对应上。data.yaml 是整份数据集的入口典型内容path: ./dataset train: images/train val: images/val test: images/test nc: 6 names: 0: hand_raise 1: reading 2: writing 3: standing 4: discussing 5: sleepingpath是数据集根目录train/val/test是相对 path 的路径。nc是类别数names是索引到类别名的映射。这里最容易出问题的是 names 的顺序——如果标注时用的是 0举手、1阅读但 yaml 里写反了模型照样能训练loss 照样下降但推理出来的类别全是错的。这种错误不会报异常属于典型的玄学问题只能靠可视化抽查发现。2.2 用脚本做一次完整的数据体检在开训之前我一般会跑一段校验脚本把图片和标签的配对情况、标注框合法性、类别分布一次性查清楚import os import yaml from pathlib import Path from collections import Counter def check_dataset(root): root Path(root) with open(root / data.yaml, r, encodingutf-8) as f: cfg yaml.safe_load(f) nc cfg[nc] names cfg[names] print(f类别数: {nc}, 类别名: {names}) for split in [train, val, test]: img_dir root / cfg[split] # labels 目录与 images 平行替换路径中的 images 为 labels lbl_dir Path(str(img_dir).replace(images, labels)) imgs {p.stem for p in img_dir.glob(*.*) if p.suffix.lower() in (.jpg, .png, .jpeg)} lbls {p.stem for p in lbl_dir.glob(*.txt)} missing_lbl imgs - lbls missing_img lbls - imgs print(f[{split}] 图片 {len(imgs)} 张, 标签 {len(lbls)} 个, f缺标签 {len(missing_lbl)}, 缺图片 {len(missing_img)}) cls_counter Counter() bad_lines 0 for lbl in lbl_dir.glob(*.txt): for line in lbl.read_text().strip().splitlines(): parts line.split() if len(parts) ! 5: bad_lines 1 continue cid int(parts[0]) cls_counter[cid] 1 # YOLO 格式坐标必须是 0~1 的归一化值 coords [float(x) for x in parts[1:]] if any(c 0 or c 1 for c in coords): bad_lines 1 print(f 类别分布: {dict(sorted(cls_counter.items()))}) print(f 异常标注行: {bad_lines}) check_dataset(./dataset)这段脚本做四件事读 data.yaml 确认类别配置检查每个 split 下图片和标签是否一一对应统计每个类别的标注框数量校验标注行格式是否为 5 列且坐标在 0~1 之间。跑完如果发现某个类别样本极少比如 sleeping 只有几十个框训练时就要考虑类别不平衡的问题后面训练参数里再处理。提示如果 labels 目录名不是和 images 平行而是嵌在 images 里面上面 replace 的逻辑要相应调整。先确认目录结构再跑脚本。2.3 可视化抽查别跳过这一步脚本只能查格式查不出标注框画得对不对。我习惯随机抽 9 张图把框画出来看一眼import cv2 import random from pathlib import Path def visualize(root, splittrain, n9): root Path(root) img_dir root / images / split lbl_dir root / labels / split imgs random.sample(list(img_dir.glob(*.jpg)), n) for img_path in imgs: img cv2.imread(str(img_path)) h, w img.shape[:2] lbl_path lbl_dir / (img_path.stem .txt) if not lbl_path.exists(): continue for line in lbl_path.read_text().strip().splitlines(): cid, cx, cy, bw, bh line.split() cx, cy, bw, bh map(float, (cx, cy, bw, bh)) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, cid, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imwrite(fvis_{img_path.name}, img) visualize(./dataset)YOLO 的标注格式是class_id cx cy bw bh全部归一化到 0~1。画框时先乘回像素坐标再画。如果看到框整体偏移、框大小明显不对大概率是标注工具导出时坐标系搞混了比如用了左上角宽高而不是中心点宽高。这一步花五分钟能省掉后面几小时的无效训练。3. 三个版本的环境配置与最小训练命令3.1 环境选择conda 隔离是底线yolov5、yolov8、yolo11 对 PyTorch 版本要求不同混装必翻车。我一般用 conda 建独立环境conda create -n yolo_train python3.10 -y conda activate yolo_train # 有 NVIDIA 显卡按 CUDA 版本装 torch pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 # 纯 CPU 环境比如 ubuntu20.04 无显卡的机器 # pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu pip install ultralyticsultralytics 这个包同时覆盖 yolov8 和 yolo11yolov5 虽然也能通过它调用但 yolov5 官方仓库的独立版本对超参数控制更细。如果只是跑基线统一用 ultralytics 最省事。注意Windows 上装 ultralytics 时如果报Microsoft Visual C 14.0 required装一下 VS Build Tools 即可。这个报错和数据集无关但很多人第一次配环境会卡在这里。3.2 yolov8 训练最省心的一条路yolov8 的 API 设计最简洁适合快速出基线from ultralytics import YOLO model YOLO(yolov8n.pt) # n/s/m/l/x 五档n 最小最快 results model.train( data./dataset/data.yaml, epochs100, imgsz640, batch16, device0, # 0 表示第一块 GPUCPU 填 cpu workers4, projectruns/classroom, nameyolov8n_baseline, patience20, # 20 轮无提升就早停 lr00.01, # 初始学习率 cos_lrTrue, # 余弦退火 close_mosaic10, # 最后 10 轮关闭 mosaic 增强 )参数说明imgsz640是输入分辨率课堂场景如果后排学生很小可以提到 960 或 1280但显存占用会翻倍。batch16在 8G 显存上跑 yolov8n 基本安全跑 yolov8m 要降到 8。patience20是早停防止过拟合。close_mosaic10是 YOLO 系列的经典技巧——最后几轮关掉 mosaic 数据增强让模型在真实分布上收敛mAP 通常能涨 1~2 个点。训练完在runs/classroom/yolov8n_baseline/weights/下会得到best.pt和last.pt。验证yolo val modelruns/classroom/yolov8n_baseline/weights/best.pt \ data./dataset/data.yaml splittest imgsz6403.3 yolo11 训练换模型名就行但注意结构差异yolo11 在 ultralytics 里的调用方式和 yolov8 几乎一致from ultralytics import YOLO model YOLO(yolo11n.pt) model.train( data./dataset/data.yaml, epochs100, imgsz640, batch16, device0, projectruns/classroom, nameyolo11n_baseline, patience20, lr00.01, cos_lrTrue, close_mosaic10, )yolo11 相比 yolov8 在网络结构上做了调整C3k2 模块替换了部分 C2f检测头也换了深度可分离卷积的设计。对使用者来说最直接的差异是同规模下 yolo11n 比 yolov8n 略快、精度略高但显存占用可能稍大。如果显存吃紧把 batch 降一档。3.4 yolov5 训练独立仓库的写法yolov5 如果走官方仓库训练命令是git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt python train.py \ --data ./dataset/data.yaml \ --weights yolov5n.pt \ --epochs 100 \ --img 640 \ --batch 16 \ --device 0 \ --project runs/classroom \ --name yolov5n_baseline \ --patience 20yolov5 的超参数集中在data/hyps/hyp.scratch-low.yaml里想调数据增强强度、学习率策略改这个文件比命令行传参更系统。yolov5 的 mosaic 增强默认开启同样建议在最后 10 轮通过--close-mosaic 10关掉。三个版本在这份 2000 张 6 类别数据集上的基线表现我实测下来的大致排序是yolo11n ≈ yolov8n yolov5n差距在 1~3 个 mAP 点以内。数据集规模不大模型容量不是瓶颈数据质量才是。4. 训练参数怎么调课堂行为检测的针对性设置4.1 类别不平衡与样本量少的处理2000 多张图分 6 类平均每类 300 多个框但实际分布往往不均——举手、阅读这类高频行为可能上千框睡觉、讨论可能只有一两百框。这种不平衡会让模型偏向多数类。处理方式有几个层次。最轻的是在 data.yaml 里给类别加权但 YOLO 原生不支持 class weights需要改 loss 计算。更实际的做法是数据层面对少数类做过采样或者用 mosaic、copy-paste 增强人为增加少数类样本的出现频率。ultralytics 的 mosaic 增强本身就会混合 4 张图对少数类有一定补偿作用。如果某个类别实在少得可怜低于 100 框建议先合并类别或者补充标注硬训效果不会好。4.2 输入分辨率与小目标课堂场景的难点在于后排学生目标小。640 分辨率下一个后排学生可能只有 20×40 像素特征提取很容易丢。两个方向一是提高 imgsz 到 960 或 1280二是用带 P2 检测层的模型配置yolov8 有yolov8n-p2.yaml这类配置增加一个更高分辨率的检测头。提高分辨率的代价是显存和速度。960 相比 640显存占用大约翻倍推理速度降一半左右。如果部署端是边缘设备比如 RK3588、树莓派640 是更务实的选择小目标问题靠数据增强和 P2 层来补。4.3 数据增强参数的取舍ultralytics 默认的增强参数对课堂场景基本适用但有几个值得调参数默认值课堂场景建议原因mosaic1.01.0保持对少数类有补偿mixup0.00.1~0.2轻微开启提升泛化degrees0.05.0~10.0课堂摄像头有轻微角度translate0.10.1保持scale0.50.3~0.5保持模拟远近变化fliplr0.50.5保持左右翻转合理flipud0.00.0课堂场景不会上下颠倒flipud 千万别开。课堂监控画面不会上下翻转开了反而引入噪声。degrees 也别开太大超过 15 度会让标注框和实际语义脱节。4.4 学习率与优化器YOLO 系列默认用 SGDlr00.01配合余弦退火。这份数据集规模不大100 轮足够收敛。如果发现 loss 震荡厉害把 lr0 降到 0.005 试试。如果收敛太慢可以换 AdamWmodel.train( data./dataset/data.yaml, optimizerAdamW, lr00.001, # AdamW 的学习率要比 SGD 低一个量级 epochs100, ... )AdamW 在小数据集上通常收敛更快但最终精度不一定比调好的 SGD 高。我一般先用默认 SGD 跑一版基线效果不理想再换 AdamW 对比。5. 避坑与排查课堂行为数据集训练中最容易翻车的 5 个点5.1 训练 loss 正常下降但 mAP 极低现象训练日志里 box_loss、cls_loss 都在降但验证集 mAP 一直在 0.1 以下。原因最常见的是 data.yaml 里 names 的顺序和标注时的类别索引不一致。模型学到的映射和真实语义错位loss 能降是因为它在拟合错误的标签但验证时按正确类别算 mAP 就崩了。解决用 2.3 节的可视化脚本抽查确认画出来的框类别 ID 和实际行为对得上。对不上就改 data.yaml 的 names 顺序或者批量改标签文件里的类别 ID。5.2 报错 No labels found in cache现象训练启动时报No labels found或者WARNING: Cache file not found。原因images 和 labels 目录不平行或者 data.yaml 里的路径写错了。ultralytics 会按images替换成labels去找标签如果实际目录结构不是这个约定就找不到。解决确认目录结构必要时在 data.yaml 里显式写 labels 路径。或者把数据集整理成标准结构。5.3 显存溢出 CUDA out of memory现象训练几轮后报 OOM。原因batch 太大、imgsz 太高或者 workers 太多导致内存泄漏。解决先降 batch再降 imgsz。workers 在 Windows 上设 0 或 2Linux 上设 4~8。如果还不行用ampFalse关掉混合精度会慢但省显存。5.4 验证集 mAP 波动大现象相邻两轮的 mAP 差距超过 5 个点。原因验证集太小或者 batch 太小导致 BN 统计不稳定。解决这份数据集如果验证集只有一两百张mAP 波动是正常的。可以增大验证集比例或者看多轮的平均值而不是单轮峰值。另外把 batch 提到 16 以上BN 层会更稳定。5.5 推理时类别名显示为数字现象推理结果画出来的框上标的是 0、1、2 而不是 hand_raise、reading。原因推理时没有加载 data.yaml模型不知道类别名。解决推理时显式传 data 参数或者从训练时的best.pt里读 namesultralytics 训练时会保存from ultralytics import YOLO model YOLO(runs/classroom/yolov8n_baseline/weights/best.pt) results model.predict(test.jpg, imgsz640, conf0.25) # names 已经存在 model.names 里 print(model.names)6. 从基线到可用提升课堂行为检测精度的几个实操技巧跑通基线只是第一步。这份 2000 张的数据集yolov8n 大概能到 0.75~0.85 的 mAP0.5但要真正用在课堂场景还有几个提升点。第一个是难例挖掘。训练完一版后用best.pt在验证集上推理把置信度低或者预测错的样本挑出来人工检查是标注问题还是模型能力问题。如果是标注漏标、错标修一批标签再训效果立竿见影。我一般会迭代两到三轮每轮修 50~100 张难例。第二个是测试时增强TTA。推理时对同一张图做多尺度、翻转等变换综合多个结果results model.predict(test.jpg, augmentTrue, imgsz640)augmentTrue会开启 TTAmAP 通常能涨 1~2 个点但推理速度慢 3 倍左右。如果部署端算力够值得开。第三个是模型集成。把 yolov8n 和 yolo11n 的预测结果做 NMS 融合或者用 WBF加权框融合。两个模型结构不同错误模式有差异融合后 mAP 能再涨 1~3 个点。代价是推理要跑两个模型。第四个是导出部署格式。如果最终要上边缘设备训练完用model.export(formatonnx)导出 ONNX再用对应工具链转成 RKNN、TensorRT 等格式。导出时注意 opset 版本和动态轴设置不同部署框架要求不一样。最后说个血泪经验别在数据集没验干净之前就开始调模型。我见过太多人花一周调参、换模型、改结构最后发现是验证集里有几十张标签错位的图。先把 2.2 和 2.3 的校验跑完再开训能省掉大量无效折腾。希望帮到你。本文还有配套的精品资源点击获取
返回列表