
简介这份资源面向计算机、人工智能、自动化等专业的在校学生与教师提供一套可直接运行的YOLOv8校园能耗智能检测项目适合作为毕业设计、课程设计或大作业的完整方案也便于初学者进阶学习。压缩包共8个文件包含3个Python脚本、3个模型权重文件与2个说明文本整体约15.91MB涵盖模型训练、可视化界面与视频检测等核心模块部署流程简单按说明操作即可跑通。项目已产出核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图便于答辩时直观展示实验效果。目前已有28人学习下载代码均经测试运行成功拿来即可使用也可在此基础上修改扩展实现其他功能是毕设与课设场景下省时省力的参考资源。1. 从一份校园能耗数据集说起YOLOv8 做能耗智能到底在做什么校园能耗智能这个词听起来像物联网平台的事但真正落到毕设或课程设计里绝大多数人卡在第一步数据从哪来、怎么让模型看见能耗异常。我拿到这个标题时第一反应不是去搭什么大平台而是先确认一件事——它用的是 YOLOv8说明核心是视觉检测不是时序预测。也就是说所谓能耗智能实际做的是从摄像头或巡检图像里识别出空调外机、照明灯具、电表箱、水管阀门这些设备的状态再据此判断哪些区域在非工作时段仍在耗电。这个定位很关键。如果你按传统能耗监测系统去做得接电表、传数据、搭后台一套下来没有两三个月根本跑不通。但基于 YOLOv8 的方案把问题转化成了目标检测数据集里标注好设备类别和开关状态训练一个模型推理时框出设备并给出状态标签前端可视化界面把结果叠加到画面上能耗异常就变成了该关没关的视觉告警。适合谁适合毕设周期只有八到十二周、手头没有真实电表数据、但能拍到校园设备照片的本科生和课程设计学生。源码、可视化界面、完整数据集、部署教程这四样东西凑齐意味着你不需要从零标注改改类别就能跑自己的场景。2. YOLOv8 校园能耗检测的选型逻辑与数据准备2.1 为什么是 YOLOv8 而不是分类网络或时序模型能耗异常检测有两条路一条是时序异常检测用 LSTM 或 Transformer 分析电表读数另一条是视觉检测用目标检测网络识别设备状态。前者精度高但依赖硬件采集后者精度稍逊但部署门槛极低。毕设场景下你没有真实的智能电表也没有历史用电曲线时序模型根本无从训练。而 YOLOv8 只需要你有一批标注好的设备图片就能训出一个可用的检测器。YOLOv8 相比 YOLOv5 的优势在于一是 anchor-free 解耦头小目标检测更稳校园场景里远处的空调外机、走廊尽头的灯管都属于小目标二是训练脚本更简洁ultralytics 库把数据加载、增强、学习率调度都封装好了你只需要准备 YAML 配置文件三是导出格式丰富onnx、tensorrt、openvino 都支持后面想部署到 RK3588 或边缘盒子也有路可走。GTX 1660 Ti 这种级别的显卡跑 YOLOv8n 或 YOLOv8sbatch size 设 8 到 16训练 100 轮大概两三个小时完全在毕设可接受范围内。2.2 校园能耗数据集的类别设计与标注规范数据集的质量直接决定模型能不能用。我见过太多人拿网上的通用数据集硬套结果模型连电表箱和配电柜都分不清。校园能耗场景的类别设计要围绕能耗相关设备 状态来定常见做法是分两大类设备类别和状态类别。设备类别包括空调外机、照明灯具、电表箱、水管阀门、插座排插状态类别包括开启、关闭、异常闪烁。但这样类别数会膨胀更实用的做法是把状态作为类别的一部分比如空调_开启空调_关闭灯具_开启灯具_关闭总共八到十二个类。标注用 Labelme 或 LabelImg 都行导出 YOLO 格式的 txt。每张图对应一个 txt每行格式是class_id x_center y_center width height坐标全部归一化到 0 到 1。这里有个血泪经验标注框不要贴边留出至少两个像素的余量否则 YOLOv8 在 mosaic 增强时会把框裁掉一半训练出来的模型对边缘目标特别不敏感。另外同一张图里如果设备密集标注顺序不影响训练但类别 ID 必须和 YAML 里的 names 列表严格对应错一个位模型就全乱。2.3 用 Python 脚本把 Labelme 标注转成 YOLOv8 可读格式Labelme 默认导出 JSON需要转成 YOLO 的 txt。下面这个脚本我用了很多次处理过几千张图稳定可用。import json import os import glob # 类别映射必须和 data.yaml 里的 names 顺序一致 class_mapping { air_conditioner_on: 0, air_conditioner_off: 1, light_on: 2, light_off: 3, meter_box: 4, water_valve: 5 } def labelme_to_yolo(json_path, output_dir): with open(json_path, r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] lines [] for shape in data[shapes]: label shape[label] if label not in class_mapping: continue # 跳过未定义类别避免训练时报错 points shape[points] x_coords [p[0] for p in points] y_coords [p[1] for p in points] # 计算归一化中心点和宽高 x_center (min(x_coords) max(x_coords)) / 2.0 / img_w y_center (min(y_coords) max(y_coords)) / 2.0 / img_h width (max(x_coords) - min(x_coords)) / img_w height (max(y_coords) - min(y_coords)) / img_h # 裁剪到 0-1 范围防止标注越界导致训练崩溃 x_center max(0, min(1, x_center)) y_center max(0, min(1, y_center)) width max(0, min(1, width)) height max(0, min(1, height)) lines.append(f{class_mapping[label]} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) base_name os.path.splitext(os.path.basename(json_path))[0] out_path os.path.join(output_dir, base_name .txt) with open(out_path, w) as f: f.write(\n.join(lines)) # 批量转换 json_files glob.glob(./labelme_jsons/*.json) os.makedirs(./labels, exist_okTrue) for jf in json_files: labelme_to_yolo(jf, ./labels) print(f转换完成共处理 {len(json_files)} 个文件)这段代码的逻辑很直白读 JSON、取多边形顶点、算外接矩形、归一化、写 txt。关键参数是class_mapping它决定了类别 ID 的分配必须和后续data.yaml里的names列表一一对应。另一个注意点是坐标裁剪Labelme 有时候会因为图片旋转或标注手抖导致坐标超出图像边界不裁剪的话 YOLOv8 在计算损失时会出 NaN。转换完成后建议随机抽十张图用cv2.rectangle画出来肉眼检查一遍确认框的位置和类别都对。2.4 data.yaml 的写法与数据集目录结构YOLOv8 靠一个 YAML 文件找到图片和标签。目录结构建议这样组织campus_energy/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamldata.yaml内容如下path: ./campus_energy train: images/train val: images/val test: images/test nc: 6 names: 0: air_conditioner_on 1: air_conditioner_off 2: light_on 3: light_off 4: meter_box 5: water_valvenc是类别数必须和 names 的长度一致。train、val、test 的路径是相对于path的。划分比例我一般按 7:2:1如果数据量少于 500 张就 8:1:1验证集太小会导致 mAP 波动大看不出真实效果。3. 训练 YOLOv8 校园能耗检测模型参数、命令与可视化3.1 环境配置与 ultralytics 安装的版本坑环境配置是第一个翻车点。网上教程有的让你装ultralytics有的让你克隆 YOLOv8 仓库两种方式都能跑但依赖冲突的概率不一样。我一般直接用 pip 装 ultralytics命令如下conda create -n yolov8_energy python3.9 -y conda activate yolov8_energy pip install ultralytics8.0.200 pip install torch1.13.1cu117 torchvision0.14.1cu117 --extra-index-url https://download.pytorch.org/whl/cu117这里锁版本是有原因的。ultralytics 8.0.200 之后的版本对data.yaml的路径解析做过调整如果你用相对路径新版可能找不到文件。torch 1.13.1 配 cu117 在 GTX 1660 Ti 上实测稳定再新的 torch 2.x 在部分老驱动上会报 CUDA 初始化失败。装完之后跑yolo checks确认环境输出里 CUDA 那一行显示可用就行。3.2 训练命令与关键参数怎么调训练命令本身很短yolo detect train \ data./campus_energy/data.yaml \ modelyolov8s.pt \ epochs150 \ imgsz640 \ batch12 \ lr00.01 \ patience30 \ device0 \ project./runs_energy \ nameexp1参数逐个说。modelyolov8s.pt是预训练权重校园能耗数据集通常不大用 s 版本比 n 版本精度高比 m 版本训练快。epochs150配合patience30意思是 30 轮验证集 mAP 不提升就早停避免过拟合。imgsz640是标准输入尺寸如果你的图片里设备特别小可以提到 1280但显存占用会翻四倍1660 Ti 的 6G 显存扛不住得降到 batch4。lr00.01是初始学习率YOLOv8 默认用 SGD 加余弦退火这个值对大多数场景都适用如果 loss 震荡厉害就降到 0.005。batch12是 6G 显存下的安全值再大就 OOM。训练过程中终端会实时打印每轮的 box_loss、cls_loss、dfl_loss 和 mAP50。box_loss 负责框的位置cls_loss 负责类别dfl_loss 是分布焦点损失三个都下降才说明模型在正常学习。如果 cls_loss 一直不降大概率是类别标注有问题回去检查 txt 里的 class_id 有没有越界。3.3 用训练日志画损失曲线和 mAP 曲线YOLOv8 训练完会在runs_energy/exp1/下生成results.csv里面记录了每轮的损失和指标。画曲线用 pandas 加 matplotlib 就行import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(./runs_energy/exp1/results.csv) df.columns df.columns.str.strip() # 列名可能有空格必须去掉 fig, axes plt.subplots(1, 2, figsize(14, 5)) # 损失曲线 axes[0].plot(df[epoch], df[train/box_loss], labelbox_loss) axes[0].plot(df[epoch], df[train/cls_loss], labelcls_loss) axes[0].plot(df[epoch], df[train/dfl_loss], labeldfl_loss) axes[0].set_xlabel(Epoch) axes[0].set_ylabel(Loss) axes[0].legend() axes[0].set_title(Training Loss) # mAP 曲线 axes[1].plot(df[epoch], df[metrics/mAP50(B)], labelmAP50) axes[1].plot(df[epoch], df[metrics/mAP50-95(B)], labelmAP50-95) axes[1].set_xlabel(Epoch) axes[1].set_ylabel(mAP) axes[1].legend() axes[1].set_title(Validation mAP) plt.tight_layout() plt.savefig(./training_curves.png, dpi150)这段代码的关键是df.columns.str.strip()YOLOv8 导出的 CSV 列名有时带前导空格不处理的话KeyError直接报错。画出来的图里正常收敛的曲线应该是 box_loss 快速下降后趋于平缓mAP50 在 50 轮左右达到 0.8 以上。如果 mAP50 卡在 0.3 不动先别怀疑模型去检查验证集的标注是不是和训练集用了不同的类别映射。3.4 推理验证与可视化界面怎么接训练完先用命令行推理几张图看看效果yolo detect predict \ model./runs_energy/exp1/weights/best.pt \ source./campus_energy/images/test \ conf0.4 \ saveTrueconf0.4是置信度阈值低于这个值的框不显示。校园能耗场景里我一般设 0.35 到 0.45太低会误检太高会漏检远处的设备。推理结果存在runs_energy/exp1/下打开图片看框的位置和标签对不对。可视化界面用 Gradio 或 Streamlit 都行Gradio 更简单十几行代码就能搭一个上传图片返回检测结果的页面import gradio as gr from ultralytics import YOLO model YOLO(./runs_energy/exp1/weights/best.pt) def detect(image): results model(image, conf0.4) return results[0].plot() # 返回画好框的 numpy 数组 demo gr.Interface( fndetect, inputsgr.Image(typenumpy), outputsgr.Image(typenumpy), title校园能耗设备检测 ) demo.launch(server_name0.0.0.0, server_port7860)results[0].plot()返回的是带框和标签的 BGR 图像数组Gradio 会自动转成 RGB 显示。server_name0.0.0.0让局域网内其他设备也能访问答辩时用手机拍一张教室照片上传界面直接出检测结果比放 PPT 有说服力。4. 部署与避坑从训练环境到边缘设备的常见问题4.1 模型导出 ONNX 与 RK3588 部署的注意点毕设如果要求部署通常指的是把 PyTorch 权重转成 ONNX 或 RKNN再放到边缘设备上跑。导出 ONNX 的命令yolo export model./runs_energy/exp1/weights/best.pt formatonnx opset12 simplifyTrueopset12是兼容性最好的版本simplifyTrue会调用 onnx-simplifier 去掉冗余节点。导出后得到一个.onnx文件用onnxruntime加载推理速度比 PyTorch 快百分之二三十。如果要部署到 RK3588还得用 RKNN-Toolkit2 把 ONNX 转成 RKNN这一步的坑在于量化。默认的 int8 量化需要提供校准数据集校准集里的图片要覆盖所有类别和光照条件否则量化后精度掉得厉害。我一般先用do_quantizationFalse导一版浮点 RKNN 验证精度确认无误再开量化。4.2 避坑校园能耗检测训练与部署的五个翻车现场现象一训练到一半 loss 变成 NaN。原因通常是标注文件里有坐标超出 0 到 1 范围或者某张图的 txt 是空的但图片还在。解决方法是写个脚本遍历所有 label 文件检查每行第一个数字是否在 0 到 nc-1 之间后四个数字是否在 0 到 1 之间发现异常直接删掉对应图片和标签。现象二mAP50 很高但实际推理全是误检。原因是验证集和训练集来自同一批图片的相邻帧数据泄漏了。解决方法是按拍摄时间段划分数据集比如上午拍的做训练下午拍的做验证确保同一场景不出现在两个集合里。现象三Gradio 界面在服务器上跑但外部访问不了。原因是防火墙没开端口或者server_name没设成0.0.0.0。解决方法是sudo ufw allow 7860然后确认启动日志里显示的是Running on local URL: http://0.0.0.0:7860。现象四RK3588 上推理速度只有 5 FPS。原因是模型没量化或者输入尺寸设成了 1280。解决方法是导出 RKNN 时开 int8 量化输入尺寸降到 640NPU 利用率能到 80% 以上帧率提到 25 FPS 左右。现象五换了新场景后模型完全失效。原因是训练集里的设备外观和部署场景差异太大比如训练用的是白色空调外机部署场景是灰色。解决方法是收集新场景的图片用yolo detect train的pretrained参数加载已有权重做微调学习率降到 0.001训 30 轮就能适应。4.3 用混淆矩阵和 PR 曲线判断模型短板训练完别只看 mAP混淆矩阵能告诉你模型到底把什么认成了什么。YOLOv8 在验证时会自动生成confusion_matrix.png和PR_curve.png在runs_energy/exp1/目录下。混淆矩阵的对角线越深越好如果air_conditioner_on和air_conditioner_off之间有明显交叉说明模型分不清开关状态这时候要么增加这两类的样本量要么在标注时把状态差异拍得更明显。PR 曲线看的是每个类别的查准率和查全率平衡点曲线下的面积就是 AP哪个类别的 AP 明显低就针对性地补那个类别的数据。5. 把检测结果变成能耗告警一个可复现的后处理技巧模型输出的是框和类别但毕设答辩时老师会问检测到灯开着然后呢你需要一个后处理逻辑把检测结果转成能耗告警。我的做法是定义一个非工作时段设备开启规则如果当前时间在 22:00 到次日 6:00 之间且检测到light_on或air_conditioner_on的框就判定为能耗异常在可视化界面上用红色边框标出并弹出提示。实现上在 Gradio 的detect函数里加时间判断from datetime import datetime def detect_with_alert(image): results model(image, conf0.4) boxes results[0].boxes alert False now datetime.now().hour if now 22 or now 6: for cls_id in boxes.cls: if int(cls_id) in [0, 2]: # 0 是空调开启2 是灯开启 alert True break annotated results[0].plot() if alert: # 在图像顶部叠加红色告警条 annotated[0:40, :, :] [0, 0, 255] return annotated这段代码的逻辑是先推理再取检测框的类别 ID如果当前是非工作时段且存在开启类设备就把图像顶部四十行像素涂红作为告警。boxes.cls返回的是张量用int()转成整数再比较。这个后处理虽然简单但把检测和能耗智能之间的逻辑补上了答辩时能讲清楚从视觉到业务的闭环。还有一个进阶技巧是统计画面中开启设备的数量如果超过阈值就触发二级告警。比如一间教室检测到三盏以上灯同时亮着且是深夜就判定为整间教室忘关灯比单设备告警更有实际意义。阈值怎么定我一般按场景面积来小教室设 2大教室设 4走廊设 3。这个数没有标准答案根据你数据集里的实际分布调就行。最后说个我自己的习惯每次训完模型不管 mAP 多高我都会拿手机去楼道里拍二十张新图跑一遍推理肉眼数误检和漏检。这个动作花不了十分钟但能暴露验证集上看不到的问题。毕设的模型不需要完美但得让老师觉得你真的在校园里跑过、看过、改过。希望帮到你。本文还有配套的精品资源点击获取