简介基于YOLOv8的社区高空抛物监测系统提供了一套可直接运行的完整工程面向计算机视觉、人工智能等相关专业的毕业设计或课程设计场景覆盖目标检测模型训练、预测视频检测及可视化页面交互等功能。包内共有8个文件包括3个Python脚本训练、检测与可视化界面、3个模型权重文件含预训练与最佳权重和2个文本说明文档压缩包总大小约15.91MB结构精简便于快速部署。目前已有30人学习代码均通过运行测试后上传。项目中可生成核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图便于在毕业答辩中展示模型效果附带详细说明文档即使是入门水平也能按步骤完成环境搭建与推理演示适合作为项目初期立项或课程设计的基础版本。1. 社区高空抛物监测为什么绕不开 YOLOv8一个毕设题目背后的真实工作量把「基于 YOLOv8 的社区高空抛物监测系统」这行字抛给刚接触目标检测的人第一反应往往是训练一个模型检测从楼上掉下来的物体然后告警。听起来不复杂但实际上手会发现高空抛物检测和常规的车辆、行人检测完全是两回事——目标极小、运动极快、背景是整栋楼的外立面光照和天气随时在变。YOLOv8 能成为这个题目的主流选择不是因为它的 mAP 数字最好看而是因为它是少数同时满足「检测速度够快、小目标能力能调、部署链路短、社区资料多」的模型。就算是用 CPU 机器跑YOLOv8n 的权重也只有 6MB 上下单帧推理在笔记本上能压到几百毫秒放在毕设和课程设计这个场景里成本和效果刚好平衡。这篇文章要讲的不是又一篇 YOLOv8 的原理复述而是把「训练自己的数据集 → 搭可视化界面 → 部署到实际环境」这条完整链路拆开每个环节怎么做、参数怎么定、卡在哪、怎么绕。适合两类人一是拿这个题目做毕业设计或课程设计、需要完整跑通并答辩的学生二是物业或工程侧想验证「一套基于摄像头的抛物监测到底能不能落地」的技术人员。下面所有内容都按可复现的标准来写。2. 选型与数据集为什么公共数据集用不了以及怎么在三天内自建一套能用的高空抛物数据集2.1 方案选型对比YOLOv8s/n 与 Faster R-CNN、SSD 的取舍高空抛物监测的第一关不是模型训练是「检测什么」。稍作调研就会发现网上公开的高空抛物数据集几乎没有能直接用的要么是仿真渲染图要么是无人机视角要么是俯拍和真实小区监控的仰拍视角差别太大迁移学习的效果会很差。常见做法是自己采集和标注这也是这个题目里工作量最大的部分之一。在模型选型上常见对比对象有三个Faster R-CNN、SSD、YOLOv8。Faster R-CNN 在两阶段检测器里精度确实有优势但推理速度慢实时视频流根本扛不住而且小目标检测需要单独调 RPN 的锚框参数对新手不友好。SSD 速度快但特征金字塔设计较老在极小目标上的表现普遍弱于 YOLOv8 的 C2f 结构加多尺度检测头。YOLOv8 的 n/s/m 三个尺寸覆盖了从 CPU 到 GPU 的使用场景加上 Ultralytics 的 API 封装得很好训练、验证、导出 ONNX 都一条命令能完成这是它成为毕设首选的根本原因。模型推理速度单帧 640x640小目标能力部署难度社区资料Faster R-CNN慢不适合实时中需调 RPN高一般SSD快弱中一般YOLOv8n/s快较强低丰富中文资料多落到实际选择如果是毕设且有 GPU哪怕是 GTX 1660 Ti 这种入门卡用 YOLOv8s 起步如果只能在 Ubuntu 20.04 的 CPU 机器上跑用 YOLOv8n。不要一上来就选 m 或 l训练时间和显存占用对新手是灾难。2.2 自建数据集的采集与标注用手机也能做出像样的训练集数据采集的核心思路是「模拟监控视角」。不需要真的去小区楼顶架摄像头操作方式是带着手机到普通居民楼下从低处往高处拍模拟监控摄像头的仰拍角度。选择 6 到 18 层之间的楼体避免强光时段分别在清晨、正午、黄昏、阴天各拍一段视频。抛掷物品种类覆盖最常见的矿泉水瓶、易拉罐、纸团、塑料袋、烟头、手机壳、儿童玩具。为了模拟真实抛物轨迹建议让助手在楼上往下扔楼下拍摄每个物体至少抛 10 次以上。用手机视频抽帧是效率最高的方式。用 OpenCV 从视频里抽帧每 5 到 10 帧取一帧避免连续帧过于相似导致数据冗余。抽帧脚本用下面这个import cv2 import os video_path raw_data/parabola_01.mp4 output_dir frames/parabola_01 os.makedirs(output_dir, exist_okTrue) cap cv2.VideoCapture(video_path) frame_id 0 saved_id 0 while True: ret, frame cap.read() if not ret: break # 每隔 6 帧保存一次避免相邻帧重复 if frame_id % 6 0: # 统一缩放到 1280x720减轻后续标注和训练的负担 resized cv2.resize(frame, (1280, 720)) cv2.imwrite(f{output_dir}/frame_{saved_id:04d}.jpg, resized) saved_id 1 frame_id 1 cap.release() print(f抽取完成共保存 {saved_id} 帧)这个脚本的逻辑是逐帧读取视频取余数为 0 的帧保存并统一缩放到 1280x720。缩放这一步很关键监控画面原始分辨率通常在 2K 以上直接拿原图训练会显著拖慢训练速度而标注框的绝对像素值变化不大720p 足够。抽帧间隔 6 帧是经验值既保证轨迹连续性又避免相邻帧几乎一模一样导致训练集过拟合到重复样本上。标注工具用 labelme这是做毕设最稳妥的选择。安装和启动pip install labelme labelme打开 labelme 后用矩形框Create Polygons 模式下选 Rectangle框住抛物物体。需要注意标注的类别名必须统一比如全部叫parabola_object不要一会儿叫bottle一会儿叫trash。类别一多每个类别的样本量都会被稀释而高空抛物本身类别边界模糊统一成一类反而能让模型更专注地学「运动中的小物体」这个共性。框的时候紧贴物体边缘不要把背景包进去背景占比太大会让模型学到错误特征。标完的 labelme 格式是 JSON内部记录的是多边形的点坐标。YOLOv8 训练需要的是 txt 格式的归一化坐标格式为class_id x_center y_center width height。转换脚本在下一节给出。2.3 数据集划分与格式转换一套不会出错的脚本标注完成后把 JSON 转成 YOLO 格式同时将数据集按 8:1:1 划分训练集、验证集、测试集。这一步用下面的脚本import json import os import random from pathlib import Path # 遍历 labelme 输出的 JSON 文件转换为 YOLO txt def convert_labelme_to_yolo(json_path, output_dir, class_nameparabola_object): with open(json_path, r, encodingutf-8) as f: data json.load(f) img_w data[imageWidth] img_h data[imageHeight] txt_name Path(json_path).stem .txt txt_path os.path.join(output_dir, txt_name) with open(txt_path, w) as out: for shape in data[shapes]: if shape[label] ! class_name: continue points shape[points] # 矩形框的两个对角点 x1, y1 points[0] x2, y2 points[1] # 归一化到 0~1 之间的 YOLO 格式 x_center (x1 x2) / 2 / img_w y_center (y1 y2) / 2 / img_h w abs(x2 - x1) / img_w h abs(y2 - y1) / img_h out.write(f0 {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n) # 划分训练/验证/测试集 frames_dir frames all_images list(Path(frames_dir).glob(*.jpg)) random.seed(42) random.shuffle(all_images) total len(all_images) train_split int(total * 0.8) val_split int(total * 0.9) # 剩下的 10% 做测试 splits { train: all_images[:train_split], val: all_images[train_split:val_split], test: all_images[val_split:] } for split_name, images in splits.items(): img_out_dir fdataset/{split_name}/images label_out_dir fdataset/{split_name}/labels os.makedirs(img_out_dir, exist_okTrue) os.makedirs(label_out_dir, exist_okTrue) for img_path in images: # 复制图片 os.rename(img_path, os.path.join(img_out_dir, img_path.name)) # 转换并移动对应的 label json_path img_path.with_suffix(.json) if json_path.exists(): convert_labelme_to_yolo(str(json_path), label_out_dir)这个脚本做了两件事先根据 JSON 里的 imageWidth 和 imageHeight 做归一化再把图片按 8:1:1 随机划分到三个目录。random.seed(42) 保证每次运行划分结果一致方便复现。如果后续训练效果不理想需要增补数据重跑这个脚本前记得保留原始 JSON不要把标注结果覆盖掉。这里又一个容易踩坑的点labelme 标注的 JSON 文件名和图片名必须保持一致否则转换时找不到对应文件。建议在标注前就把图片统一重命名为img_0001.jpg这类格式。数据集规模方面400 到 600 张标注图片是毕设的最低门槛。少于 400 张YOLOv8 的泛化能力很难保证验证集上的 mAP50 会经常性地在 0.3 到 0.6 之间波动答辩时经不起问。如果前期采集不够不要硬凑优先补不同光线条件的数据。2.4 数据增强别过度依赖 YOLOv8 的默认增强YOLOv8 自带 mosaic、翻转、色域变换等增强策略这是它的优势。但对于高空抛物这个场景默认增强有个问题——mosaic 拼接会把多个不同楼层的图像拼成一张物体间的尺度对比关系变得混乱模型在训练初期很容易发散。实践中建议把 mosaic 从默认的 1.0 降到 0.5让模型在前半程用正常图片稳定学习后半程再启用 mosaic 提升泛化。在数据集配置文件里体现为# dataset.yaml path: ./dataset train: train/images val: val/images test: test/images nc: 1 names: [parabola_object] # 训练时用命令行参数覆盖增强配置 # --mosaic 0.5nc 是类别数这里只有 1 类。如果你的项目里额外加了「人」这个类别nc 改成 2names 里顺序也要对应否则类别 id 错位会导致训练完全失败。3. 训练 YOLOv8 模型从环境搭建到损失曲线解读的完整路径3.1 在 Ubuntu 20.04 上搭建环境CPU 版本也能跑但要有预期管理很多同学一听到深度学习就默认需要 GPU实际上 YOLOv8 的 CPU 训练是可行的只是时间成本高。在 Ubuntu 20.04 上搭建 CPU 环境先确认 Python 版本在 3.8 到 3.10 之间Ultralytics 对 3.11 以上的支持有过兼容问题然后执行sudo apt update sudo apt install python3-pip python3-dev -y pip install ultralytics pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu第二行安装 CPU 版的 PyTorch千万不要直接pip install torch否则默认装的是 CUDA 版在无 GPU 机器上会报错或运行时找不到 CUDA 设备。装完后验证一下 torch 是否能正确调用 CPUpython -c import torch; print(torch.__version__)如果输出版本号且没有 CUDA 报错环境就基本可用。紧接着跑一次官方预训练模型做冒烟测试确认整条链路没问题yolo predict modelyolov8n.pt sourcetest.jpg这一步的意义是排除「环境问题」和「代码问题」的干扰避免后续训练失败时在环境上反复浪费时间。有 GPU 的机器则直接装对应 CUDA 版 torch方法网上很成熟不再展开。3.2 训练参数学习率、batch、epoch 怎么搭配训练命令本身很简洁但对毕设场景来说参数比命令重要yolo train \ datadataset.yaml \ modelyolov8s.pt \ epochs100 \ batch8 \ imgsz640 \ lr00.01 \ mosaic0.5 \ patience15 \ projectruns/detect \ nameparabola_yolov8s参数说明如下epochs100不多不少。高空抛物数据集小50 epoch 往往欠拟合150 epoch 以上损失曲线已经平坦还会增加过拟合风险。batch86GB 显存GTX 1660 Ti能跑的上限。如果显存不足降到 4显存够大且是 YOLOv8n可以提到 16。imgsz640YOLOv8 的默认推理尺寸。不要调到 1280虽然对小目标检测有提升但训练时间会翻好几倍显存占用也暴涨毕设场景不划算。lr00.01Ultralytics 的默认值对 s 尺寸稳定。如果训练两三个 epoch 后 loss 就变成 nan把 lr0 调到 0.001。patience15早停参数连续 15 个 epoch 验证集没有提升就停止用来防止无效训练浪费时间。训练开始后几秒钟内会在终端输出每个 epoch 的 mAP50、mAP50-95、box_loss、cls_loss 等指标。不要看到 mAP 是 0 就慌前 10 个 epoch 模型还在收敛阶段指标低是正常的。3.3 损失函数曲线训练结束后第一件要做的事训练结束后runs/detect/parabola_yolov8s/ 目录下会生成 results.png这张图是一次训练是否正常的核心判据。常见做法是用脚本把损失曲线单独拿出来看import pandas as pd import matplotlib.pyplot as plt # Ultralytics 会保存每个 epoch 的指标到 results.csv df pd.read_csv(runs/detect/parabola_yolov8s/results.csv) plt.figure(figsize(10, 6)) plt.plot(df[epoch], df[train/box_loss], labeltrain box loss, colorblue) plt.plot(df[epoch], df[val/box_loss], labelval box loss, colorred) plt.xlabel(epoch) plt.ylabel(loss) plt.title(Box Loss Curve - YOLOv8s) plt.legend() plt.grid(True) plt.savefig(loss_curve.png)正常曲线应该满足box_loss 在前 20 个 epoch 快速下降之后缓慢收敛val 曲线和 train 曲线之间的距离不大。如果 val 曲线在训练中后期开始反弹上升train 继续下降这是过拟合的信号应对方式是减少 epoch、调大 mosaic 概率增强数据多样性或增加 dropout。如果 val 曲线全程在 0.2 以上几乎不动说明特征没学到优先检查数据集标注是否准确、类别是否统一。3.4 评估一张图还是评估一段视频别被 mAP 骗了训练完成后跑一次验证集评估yolo val modelruns/detect/parabola_yolov8s/weights/best.pt datadataset.yaml输出里的 mAP50 如果能到 0.7 以上这个模型在毕设层面就是合格的。但更真实的检验方式是拿一段训练集里没有的视频做实测脚本很简单yolo predict modelruns/detect/parabola_yolov8s/weights/best.pt sourcetest_video.mp4 saveTrue把保存的预测视频逐帧看一遍重点关注两个指标有没有漏检该检测到的物体没框出来、有没有误检把飞鸟、落叶、晾晒衣物当成了抛物。漏检远比误检严重因为高空抛物监测的价值在于「不漏报」误检可以通过后续的轨迹判断逻辑过滤漏检则意味着整个系统失去意义。如果漏检多优先从数据层面补样本而不是调阈值。4. 可视化界面用 PyQt5 把算法包装成一套能演示的监测系统4.1 界面架构摄像头画面、检测结果、告警记录三块布局一个能拿去答辩或在物业值班室展示的可视化界面至少要包含三个区域实时视频显示区、检测信息面板当前帧检测到的物体类别、置信度、坐标、告警日志列表。用 PyQt5 实现是 Python 生态里最顺手的方案它和 OpenCV、YOLOv8 的 Python API 天然兼容。架构上采用单线程加 QTimer 定时刷新而不是单独开线程做视频读取这样对新手来说更简单也不容易出现界面卡死。每 30ms 从视频流取一帧送入模型推理在界面上绘制检测框并更新日志。30ms 对应大约 33fps 的刷新率人眼看起来流畅CPU 机器也能扛住。4.2 核心代码检测线程加界面更新界面主体代码用下面的结构import sys import cv2 import torch from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QVBoxLayout, QWidget, QTextEdit from PyQt5.QtCore import QTimer from ultralytics import YOLO class ParabolaDetectorWindow(QMainWindow): def __init__(self, model_path, video_source0): super().__init__() self.setWindowTitle(社区高空抛物监测系统 - YOLOv8) self.setGeometry(100, 100, 1280, 720) # 模型加载优先用 GPU没有就 CPU self.device cuda if torch.cuda.is_available() else cpu self.model YOLO(model_path).to(self.device) # 视频来源0 表示摄像头也可以传视频文件路径 self.cap cv2.VideoCapture(video_source) self.video_label QLabel(self) self.log_text QTextEdit(self) self.log_text.setReadOnly(True) layout QVBoxLayout() layout.addWidget(self.video_label) layout.addWidget(self.log_text) container QWidget() container.setLayout(layout) self.setCentralWidget(container) # 30ms 刷新一次 self.timer QTimer() self.timer.timeout.connect(self.update_frame) self.timer.start(30) self.frame_count 0 def update_frame(self): ret, frame self.cap.read() if not ret: return # 推理时把 OpenCV BGR 转成 RGB 再送模型 rgb_frame cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results self.model(rgb_frame, verboseFalse) for result in results: boxes result.boxes for box in boxes: conf float(box.conf[0]) if conf 0.35: continue # 置信度阈值过滤降低误检 x1, y1, x2, y2 map(int, box.xyxy[0]) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(frame, fparabola {conf:.2f}, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) self.log_text.append( f[告警] 帧 {self.frame_count} - 检测到抛物物体 f置信度 {conf:.2f}位置 ({x1},{y1}) - ({x2},{y2})) # 绘制完的帧转回 QPixmap 显示 rgb_display cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch rgb_display.shape bytes_per_line ch * w from PyQt5.QtGui import QImage, QPixmap image QImage(rgb_display.data, w, h, bytes_per_line, QImage.Format_RGB888) self.video_label.setPixmap(QPixmap.fromImage(image).scaled(960, 540)) self.frame_count 1 if __name__ __main__: app QApplication(sys.argv) window ParabolaDetectorWindow( model_pathruns/detect/parabola_yolov8s/weights/best.pt, video_sourcetest_video.mp4 ) window.show() sys.exit(app.exec_())代码逻辑不复杂QTimer 每 30ms 触发一次 update_frame从 OpenCV 的 VideoCapture 取一帧送入 YOLO 模型推理置信度大于 0.35 的预测框画在画面上并写入日志。置信度阈值 0.35 是经验值比 YOLOv8 默认的 0.25 高一点点能过滤一部分因为光影、模糊产生的低置信度误检又不会漏掉太多真实目标。两条重要细节模型加载用.to(self.device)否则在有 GPU 的机器上模型跑在 GPU 但 OpenCV 读帧在 CPU反而会因为数据拷贝浪费时间。verboseFalse必须加否则每次推理都会在终端刷一大堆耗时和类别信息界面会卡顿。4.3 参数调整置信度阈值与告警逻辑的联动界面的置信度阈值不是一个孤立的数字它和告警逻辑是联动的。如果只追求低漏检阈值下调到 0.2告警数量大幅上升如果追求低误报阈值上调到 0.5漏检风险随之增加。毕设答辩时被问到「阈值怎么选的」可以从这个矛盾切入去讲你的调参过程比单纯说「我设了 0.35」更有说服力。更进一步可以把阈值设计成界面上的一个可拖动的滑条实时调整而不用重启程序。这样既能展示对参数的理解也能让评测老师亲手操作体验感会好很多。告警日志的内容也要注意时间戳记录格式方便后续统计告警频率这在论文的过程分析章节里很好用。5. 部署与常见问题排查从训练机器到实际运行的避坑记录5.1 部署链路从 GPU 训练机导出 ONNX再考虑边缘设备训练阶段的模型是 PyTorch 的 .pt 格式不能直接放到普通服务器或边缘设备上跑。实际部署时第一步是把 best.pt 导出成 ONNXyolo export modelruns/detect/parabola_yolov8s/weights/best.pt formatonnx imgsz640导出的 ONNX 文件有两个用处一是可以在 CPU 上用 ONNX Runtime 推理比纯 PyTorch CPU 推理快 30% 到 50%二是可以进一步转换成 OpenVINOIntel CPU 平台或 RKNN瑞芯微平台比如 RK3588满足嵌入式部署需求。毕设和课程设计做到 ONNX 导出这一步就已经达标了项目文档里写明「可迁移至边缘设备」即可不一定要真的在开发板上跑通。5.2 常见问题排查五个高频坑的记录问题 1训练时 loss 变成 nan现象训练第二个 epoch 开始终端输出的 box_loss 变成 nan后面全部 nan。原因最常见的是学习率过高导致梯度爆炸。YOLOv8 默认 lr00.01 对 s 以上尺寸没问题但如果换了更大的模型或者 batch 太小0.01 就会偏大。解决把 lr0 降到 0.001 重新训练保险起见可以把 weight_decay 同步降到 0.0001。如果降完还是 nan检查数据集里有没有空的 txt 文件一个没有标注的图片会导致 loss 计算异常。问题 2CPU 训练慢到让人怀疑人生现象500 张图YOLOv8sCPU 训练一个 epoch 要 20 分钟以上。原因CPU 训练本身慢加上 imgsz 和 batch 设置不合理时间被进一步放大。解决换 YOLOv8n把 imgsz 降到 480batch 保持 4epoch 从 100 降到 60。YOLOv8n 在 CPU 上训练时间大概是 s 的三分之一精度损失在小数据集上并不明显。这是「能跑」和「跑得动」之间的平衡。问题 3推理时检测框位置偏移现象训练时 mAP 正常但实际检测时框的位置总是偏向物体下方或者上方。原因数据集标注时框得不够紧或者某些图片的标注框包含了过多背景。高空抛物场景里物体在下落过程中会运动模糊标注者容易把模糊的拖影一起框进去导致模型学到的框中心偏移。解决重新检查标注对模糊帧做删除或重标。如果重标成本高一个缓解办法是训练时把 imgsz 提高到 640 以上让模型看到更多框内细节但这只是缓兵之计根治还得靠标注质量。问题 4可视化界面卡死或黑屏现象PyQt5 界面运行几秒后无响应画面停在第一帧。原因QTimer 的 timeout 回调里做了推理而 CPU 推理耗时超过 30ms 时界面事件循环被阻塞。更隐蔽的是如果视频源是网络流cap.read() 本身就会阻塞几百毫秒。解决把推理放到 QThread 里界面线程只负责显示。简单方案是使用 Python 的 threading 模块推理完一帧后通过信号机制通知主线程刷新界面。如果不想引入线程复杂性至少把 timer 间隔从 30ms 改到 100ms降低单位时间工作量。问题 5视频文件跑得动接摄像头就掉帧现象测试视频推理 30fps 没问题换成 USB 或 RTSP 摄像头后帧率暴跌。原因VideoCapture 读取摄像头时如果摄像头输出分辨率过高比如 1080p 甚至 4K读帧和缩放本身就成了瓶颈。解决在打开摄像头后立即设置分辨率cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) cap.set(cv2.CAP_PROP_FPS, 15)把 1080p 降到 720p 后帧率通常能恢复到可接受水平。如果还是不行检查摄像头是不是需要特定的驱动或解码方式换一个官方 SDK 兼容性更好的摄像头往往比调代码更管用。6. 进阶做法从「能跑」到「跑得稳」的两个关键手段模型训练完、界面能跑通这个项目在毕设层面已经完整。但如果答辩老师问「你的系统能不能实际部署」或者你想把它真正放到社区环境里验证有两个进阶方向很值得做。第一个是轨迹连续性判断。单帧检测只能给出「此刻画面里有一个像抛物物体的东西」但会把飞鸟、飘落的树叶、突然进入画面的晾晒衣物都算进来。实际部署时正确的做法是记录同一物体在连续多帧中的位置变化判断它是否持续下落且加速——高空抛物在垂直方向上的位移曲线符合自由落体特征而飞鸟和树叶的轨迹要么有水平偏移要么速度不稳定。实现上不需要复杂算法维护一个简单的按位置关联的小目标列表每个目标记录最近 20 帧的 y 坐标变化只有当 y 方向位移持续增加且加速度大于某个阈值时才触发告警。这个逻辑单独写成一小节是最容易在项目文档里出彩的亮点。第二个是模型的持续优化。部署一段时间后会积累大量误检和漏检样本把这些坏案例定期挑出来加入训练集重新训练。常见做法是每周人工过一遍告警截图把明显是误检的帧归为负样本加入一个background类别重新训练。很多成熟方案里模型越用越准的原因不是初始算法好而是持续的数据回流在起作用。最后说一下我的个人习惯所有训练命令和参数配置都写在一个 requirements.txt 或 shell 脚本里不要指望几个月后还记得当时是怎么调的。整个项目跑通之后用自己的模型完整的跑一遍 demo 视频从头到尾做一次记录包括环境安装时间、训练耗时、最终 mAP 指标。这段记录在写课程设计报告或毕业论文时能省下大量时间也是真正「做完」一个项目的证据。希望这些步骤和踩坑记录能帮你把这个题目做透。如果你的机器配置一般就老实从 YOLOv8n 开始把时间花在数据集和界面上这两个部分占最终分数的比重往往比模型本身更大。本文还有配套的精品资源点击获取