
又到一年毕业季很多同学选“基于深度学习的图像识别”作为题目下载开源代码却发现环境配不通、数据集不匹配、训练完没效果。本文整理一套基于YOLOv8 PyTorch的花卉图像识别实战方案从原理拆解到环境搭建再到完整代码跑通尽量让毕设新手少走弯路。文章会涉及 YOLOv8 的网络结构、PyTorch 环境配置、自定义数据集制作、模型训练、预测和导出以及常见报错排查。读完你不仅能完成一个花卉识别项目还能把同一套流程迁移到其他检测场景。1. YOLOv8 与花卉图像识别概述1.1 什么是 YOLOv8YOLO 全称是 You Only Look Once这是一种端到端的目标检测算法。它把目标检测当成回归问题直接在一张图上预测目标边界框和类别不需要像早期两阶段算法那样先产生候选区域再逐区域分类。YOLOv8 是 Ultralytics 公司在 2023 年初发布的 YOLO 系列新版本它既支持目标检测也支持实例分割、姿态估计和图像分类。对花卉识别来说我们既可以用它的目标检测能力定位画面里的每一朵花也可以用分类能力直接判断一张图片属于哪个花种。YOLOv8 相比旧版本的主要改进包括特性说明C2f 模块基于 C3 结构改进增强梯度流动特征提取效果更好Anchor-Free 检测头不需要预设锚框后处理更简单泛化能力更强多尺度训练默认支持尺度扰动小目标检测能力提升解耦检测头分类和回归分支分离收敛速度更快损失函数优化使用 BCE Loss 和 DFL Loss 的组合回归更稳定1.2 图像分类与目标检测的区别花卉识别有两种常见做法图像分类输入一张图输出一个标签比如“玫瑰”“向日葵”“郁金香”。它适合图片中只有一种主体花卉的场景。目标检测输入一张图输出多个边界框每个框带一个类别标签和置信度。它适合一张图里有多种花、或者花的位置不固定的场景。如果你的毕设要求是“识别图片中的花卉种类”分类模型就够了。但如果你需要统计花田里不同花的数量或者视频里实时检测花卉位置那就必须用检测模型。本文以目标检测为例因为 YOLOv8 的目标检测能力最成熟而且在毕设答辩时可以展示更多技术点。分类模式只需要改一行代码后面会提到。1.3 为什么选择 YOLOv8 做毕设第一YOLOv8 使用门槛低Ultralytics 官方封装了训练、验证、导出、预测的全套 API几十行代码就能完成整个流程。第二生态和资料丰富国内外社区讨论量大遇到问题很容易搜索到解决方案。第三推理速度快即使没有高端 GPU也可以用 CPU 跑推理满足展示需求。第四可改进空间大毕设如果要求有“创新点”可以在 YOLOv8 基础上替换主干网络、注意力机制或损失函数这些都是典型的论文改进方向。2. 环境准备与 PyTorch 安装2.1 软硬件环境说明YOLOv8 的底层框架是 PyTorch所以环境准备的核心是安装 PyTorch 和 Ultralytics 包。不同环境的安装命令差别很大下面的版本只是作者自用环境示例实际操作时以官方文档和你的本机显卡为准。项目推荐配置操作系统Windows 10/11 或 Ubuntu 20.04/22.04Python3.8 或 3.9 或 3.10PyTorch2.xCUDA11.8 或 12.1显卡NVIDIA 显卡显存建议 4GB 以上无显卡可用 CPU 训练速度较慢适合紧急上传代码演示2.2 安装显卡驱动与 CUDA如果电脑是 NVIDIA 显卡建议先确认驱动是较新版本。驱动装好后在命令行输入nvidia-smi如果能看到显卡型号和 CUDA 版本信息说明驱动正常。nvidia-smi输出的 CUDA 版本是驱动支持的最高版本不一定是 PyTorch 运行时用的 CUDA两者可以不一致。CUDA 工具包不一定要单独安装因为 PyTorch 自带了 CUDA 运行时。你只需要保证显卡驱动够新然后安装对应 CUDA 版本的 PyTorch 即可。2.3 创建 Python 虚拟环境强烈建议为项目创建独立虚拟环境防止和系统 Python 的其他包冲突。打开终端执行conda create -n yolo_flask python3.10 conda activate yolo_flask如果你不会用 conda也可以用 Python 自带的 venvpython -m venv yolo_env yolo_env\Scripts\activate # Windows source yolo_env/bin/activate # Linux/Mac2.4 安装 PyTorch安装 PyTorch 最靠谱的方式是去 PyTorch 官网根据操作系统和 CUDA 版本复制安装命令。CUDA 11.8 版本对应命令示例pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118这里提醒一点torchvision要和torch版本匹配否则后面数据预处理可能报错。建议一起安装不要分开装。安装完检查是否成功python -c import torch; print(torch.__version__); print(torch.cuda.is_available())如果输出True说明 GPU 可用输出False说明当前环境是 CPU 版本。如果 GPU 明明是 NVIDIA 卡却显示 False多半是 PyTorch 版本下载成了 CPU 版需要重装。2.5 安装 Ultralytics 和其他依赖pip install ultralytics pip install labelimgultralytics包会自动安装 YOLO 训练和推理依赖。labelimg是标注工具后面制作数据集时会用到。如果下载速度慢可以临时切换国内镜像源pip install ultralytics -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后验证yolo predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg这条命令会下载一个 YOLOv8n 预训练权重并测试一张图片输出检测结果后不报错说明整个基础环境已经通了。3. YOLOv8 核心原理拆解3.1 整体网络结构YOLOv8 网络可以分成三部分Backbone、Neck 和 Head。Backbone主干网络负责提取图像特征。YOLOv8 使用改进的 CSPDarknet 结构核心模块是 C2f。C2f 会把特征图按通道拆分一部分直接传递另一部分经过卷积和 Bottleneck 处理最后拼接起来。这样做的好处是梯度能更顺畅地回传深层网络也能训练得动同时保持较少的参数。Neck颈部负责融合不同尺度的特征。YOLOv8 使用 PAN-FPN 结构简单来说就是把高层语义信息和低层细节信息互相融合让检测头既能识别大目标也能识别小目标。Head检测头负责输出预测结果。YOLOv8 采用 Anchor-Free 方式不再需要预设一堆锚框而是让网络直接预测每个位置到目标的距离。检测头分成分类和回归两个分支分类分支预测类别概率回归分支预测边界框坐标。3.2 Anchor-Free 是什么意思传统 YOLO 版本是 Anchor-Based也就是提前定义一系列不同宽高比的锚框训练时让网络在这些锚框的基础上做微调。Anchor-Free 的思路是直接在特征图的每个位置预测目标中心点的偏移和宽高。这样减少了锚框设计和调参的工作量也让不同尺度的目标预测更加灵活。YOLOv8 在训练时还会使用 TaskAlignedAssigner 这种动态匹配策略为每个目标分配合适的正样本点进一步提高训练效率。3.3 损失函数YOLOv8 的损失函数主要包括三部分分类损失使用 BCEWithLogitsLoss判断每个预测框的类别是否正确。回归损失使用 CIoU Loss 或 DFL Loss衡量预测框和真实框的重合程度和位置偏差。DFL LossDistribution Focal Loss让边界框回归预测更接近真实分布提升定位精度。训练时命令行输出的各项指标含义指标含义box_loss边界框回归损失cls_loss分类损失dfl_loss分布聚焦损失Precision精确率预测为正例的样本中真正例占比Recall召回率真正例中被正确预测出来的占比mAP50IoU 阈值 0.5 时的平均精度mAP50-95不同 IoU 阈值下的平均精度更高更严格3.4 模型版本选择YOLOv8 提供 n、s、m、l、x 五种规格越往后参数越多、精度越高但速度更慢、显存需求更大。模型参数量适合场景YOLOv8n最小移动端、低算力环境、快速验证YOLOv8s较小毕设数据量少时首选YOLOv8m中等有 6G 以上显存可用YOLOv8l较大追求精度、显卡性能充足YOLOv8x最大高性能服务器较少用于毕设demo对花卉数据集建议先跑 YOLOv8s。数据扩增后如果精度不够再尝试 v8m。4. 数据集准备与标注4.1 数据来源花卉数据集有几种获取方式使用公开数据集比如 Oxford 102 Flowers、Flower Recognition 数据集。从 Kaggle 下载搜 “flower detection” 或 “flower classification”。自己拍摄适合做特定场景的花卉识别比如校园某区域的花。网络爬虫但需要注意版权和数据清洗成本。毕设场景下推荐公开数据集作为基础再补充少量自采数据这样既有权威性又能突出工作量。4.2 数据集目录结构YOLOv8 目标检测要求标注格式为 YOLO txt 格式每张图片对应一个同名 txt 文件每一行内容为类别序号 x_center y_center width height中心点坐标和宽高都是相对于图片宽高的归一化数值范围 0 到 1。推荐目录结构flower-dataset/ ├── images/ │ ├── train/ │ │ ├── 0001.jpg │ │ ├── 0002.jpg │ │ └── ... │ ├── val/ │ │ ├── 0101.jpg │ │ └── ... │ └── test/ │ ├── 0201.jpg │ └── ... ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── flower.yaml注意 images 和 labels 下子目录名必须一一对应否则训练时找不到标注文件。4.3 使用 LabelImg 标注图片如果使用自采数据需要用标注工具画框。LabelImg 安装命令已经在前面环境准备中提到。启动labelimg打开图片目录后按W键进入画框模式框住一朵花后输入类别名称比如rose。保存时格式选择 YOLOLabelImg 就会生成对应的 txt 文件。标注时要注意几个原则花朵太小、太模糊的图片建议删除。一株多花时尽量每一朵都单独画框。边界尽量贴合花瓣边缘不要留太多背景。遮挡严重的花可以跳过不标。4.4 编写数据配置文件在flower-dataset目录下创建flower.yaml内容如下# 文件路径flower-dataset/flower.yaml path: flower-dataset train: images/train val: images/val test: images/test nc: 5 names: [daisy, dandelion, rose, sunflower, tulip]这里nc是类别总数names是类别名称列表顺序必须和标注 txt 里的类别序号一致。如果你的数据集包含其他花种自行扩展即可。4.5 数据集拆分如果公开数据集本身没有划分训练集和验证集可以用脚本按比例拆分。下面是一个简单的 Python 脚本按 8:1:1 划分# 文件路径split_dataset.py import os import random import shutil image_dir flower-dataset/images_all label_dir flower-dataset/labels_all base_dir flower-dataset for sub in [images/train, images/val, images/test, labels/train, labels/val, labels/test]: os.makedirs(os.path.join(base_dir, sub), exist_okTrue) images [f for f in os.listdir(image_dir) if f.lower().endswith((.jpg, .jpeg, .png))] random.shuffle(images) train_num int(len(images) * 0.8) val_num int(len(images) * 0.1) for i, img in enumerate(images): name os.path.splitext(img)[0] suffix .jpg if os.path.exists(os.path.join(label_dir, name .txt)) else .txt label_file name .txt if i train_num: target_img images/train target_label labels/train elif i train_num val_num: target_img images/val target_label labels/val else: target_img images/test target_label labels/test shutil.copy(os.path.join(image_dir, img), os.path.join(base_dir, target_img, img)) if os.path.exists(os.path.join(label_dir, label_file)): shutil.copy(os.path.join(label_dir, label_file), os.path.join(base_dir, target_label, label_file))这个脚本会把图片和对应的标注文件同步移动到不同子目录。注意原目录中的无标注文件不会复制训练时能被忽略。5. 模型训练实战5.1 最小训练代码在项目根目录创建train.py# 文件路径train.py from ultralytics import YOLO if __name__ __main__: model YOLO(yolov8s.pt) # 加载预训练权重 results model.train( dataflower-dataset/flower.yaml, epochs50, imgsz640, batch8, device0, # 0 表示 GPUCPU 可改为 cpu workers2, pretrainedTrue, # 使用预训练权重做迁移学习 patience10, save_period10, )运行python train.py训练开始后控制台会打印每个 epoch 的损失值和指标。正常情况下loss 会逐渐下降mAP50 会逐渐上升。5.2 训练参数详解参数含义建议data数据集配置文件必填epochs训练轮数小数据集 50 轮起步imgsz输入图片尺寸目标小可以调到 832batch批次大小显存不够就调小device训练设备0 为 GPUcpu 为 CPUworkers数据加载进程数Windows 建议 0 或 2patience早停机制连续多少轮无提升就停止10 左右pretrained是否加载预训练权重毕设建议 Trueoptimizer优化器默认 auto 即可这里重点说下batch。显存不足时优先减小 batch也可以减小imgsz。如果显存只有 4GB训练 YOLOv8s 建议batch4、imgsz512。5.3 断点续训如果训练中途断了Ultralytics 会自动保存last.pt可以从断点继续训练# 文件路径resume_train.py from ultralytics import YOLO model YOLO(runs/detect/train/weights/last.pt) model.train(resumeTrue)resumeTrue会读取上次训练的全部参数配置继续后面的 epoch。5.4 训练结果与指标判断训练完成后在runs/detect/train/目录下可以看到weights/best.pt效果最好的模型权重weights/last.pt最后一个 epoch 的权重results.png损失曲线、精度曲线、召回率曲线confusion_matrix.png混淆矩阵val_batch0_pred.jpg测试集预测结果可视化判断训练是否正常优先看results.png中的曲线。如果损失下降后趋于平稳mAP 稳定在较高水平说明训练基本收敛。如果出现过拟合也就是训练损失降得很低、验证 mAP 反而下降需要增加数据增强、降低模型复杂度或增大验证集。5.5 数据增强与超参数调优YOLOv8 内置了很多数据增强策略如马赛克增强、随机仿射变换、HSV 颜色扰动等。小数据集训练时数据增强是提升精度的第一手段。你可以在训练参数里调整部分增强强度比如model.train( dataflower-dataset/flower.yaml, epochs100, imgsz640, batch8, hsv_h0.015, hsv_s0.7, hsv_v0.4, degrees10.0, translate0.1, scale0.5, flipud0.5, )不需要每个参数都调优先做随机旋转和水平翻转即可。对于花朵这种朝向不固定的目标degrees30甚至degrees45都可以试一下。6. 模型预测与推理6.1 单张图片预测训练完成后用下面的脚本对单张图片进行预测# 文件路径predict.py from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.predict( sourcetest_images/rose.jpg, conf0.3, # 置信度阈值低于该值的框会被过滤 saveTrue, # 保存检测后的图片 projectoutput, namepredict_demo, )预测结果保存在output/predict_demo/目录中。6.2 批量预测如果需要批量处理一个文件夹里的图片# 文件路径batch_predict.py from ultralytics import YOLO import os model YOLO(runs/detect/train/weights/best.pt) image_dir test_images output_dir output/batch_result results model.predict( sourceimage_dir, conf0.3, saveTrue, projectoutput_dir, ) for i, result in enumerate(results): names result.names if result.boxes is not None and len(result.boxes) 0: cls_ids result.boxes.cls.cpu().numpy().astype(int) confs result.boxes.conf.cpu().numpy() print(f图片 {i}:) for cls_id, conf in zip(cls_ids, confs): print(f 类别: {names[cls_id]}, 置信度: {conf:.4f})这里的result对象包含了检测框坐标、类别和置信度。如果你想在毕设系统里做后续业务逻辑比如统计数量、根据花种给出养护建议就可以从这些字段取值。6.3 摄像头实时检测如果你的毕设答辩需要现场演示实时检测可以用官方命令行yolo predict modelruns/detect/train/weights/best.pt source0 showTruesource0表示读取本机摄像头showTrue会弹出一个窗口实时显示检测框。笔记本自带摄像头一般都能直接用。6.4 导出 ONNX 或 TensorRT 格式如果需要部署到 Web 系统或边缘设备可以导出为 ONNXfrom ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) model.export(formatonnx, imgsz640)导出后会在同一目录下生成best.onnx文件。ONNX 格式可以转为 TensorRT、OpenVINO 等格式方便在不同平台部署。这里提醒一句导出 ONNX 可能导致精度轻微下降生产环境部署前务必在验证集上重新评估。7. 常见问题与排查思路毕设项目中大量时间都花在环境配置和报错处理上。下面列出高频问题。问题现象常见原因解决思路torch.cuda.is_available() 返回 False安装了 CPU 版 PyTorch重新安装对应 CUDA 版本的 PyTorch训练时报 CUDA out of memorybatch 太大或 imgsz 太大调小 batch或减低 imgsz或使用更小模型训练开始后一直停在 Downloading网络原因无法下载预训练权重手动下载 yolov8s.pt 放入当前目录训练找不到图片data yaml 中的路径不对检查 path 字段和 train/val 路径是否正确标注框全部错位归一化坐标写错或图片和 txt 不对应用 LabelImg 重新导出检查文件名一致性mAP 一直为 0标注文件类别序号和 yaml 不一致逐个检查 txt 内容和 names 顺序预测时一个目标都没检测出来conf 阈值过高调低 conf比如 0.1观察是否有框Windows 下 DataLoader worker 报错workers 设置过大设置 workers0训练损失下降但 mAP 不升数据标注质量差或正负样本不平衡检查标注框是否过小、过密清理无效标注换卡后训练结果不同不同硬件导致数值差异锁定版本和超参数论文中记录固化参数7.1 排查环境问题的标准流程如果你运行任何命令都报错按这个顺序排查确认虚拟环境是否激活。终端里输入python看输出路径是不是你的虚拟环境。确认当前目录是否正确。训练脚本和数据集目录要在同一个项目根目录下。确认 pip 包是否齐全。执行pip list | grep ultralytics如果没有就重装。确认 PyTorch 是 GPU 版还是 CPU 版。重新运行第 2.4 节的检查命令。查看完整报错不要只看第一行。Ultralytics 的报错信息一般很长重点看最后几行。7.2 一个容易踩的坑训练集和验证集图片重叠很多公开数据集本身有划分但部分爬虫数据集没有。如果你的训练集和验证集出现同一张图片最终 mAP 会偏高答辩时被问到数据划分就难看。解决办法比如用哈希去重脚本先去除重复图片再划分确保训练集、验证集、测试集三份数据互不重叠。# 文件路径remove_duplicates.py import hashlib import os def file_hash(filepath): h hashlib.md5() with open(filepath, rb) as f: for chunk in iter(lambda: f.read(4096), b): h.update(chunk) return h.hexdigest() root flower-dataset seen set() for split in [train, val]: folder os.path.join(root, images, split) for img in os.listdir(folder): path os.path.join(folder, img) h file_hash(path) if h in seen: print(重复图片, path) seen.add(h)建议在划分数据集的初期就做好这一步。8. 工程建议与毕设优化方向8.1 毕设系统代码结构很多同学交上去的代码是一片混乱的.py文件。推荐用下面的项目结构组织工程flower_project/ ├── dataset/ # 数据集 ├── weights/ # 预训练权重 ├── runs/ # 训练输出 ├── src/ │ ├── train.py # 训练脚本 │ ├── predict.py # 预测脚本 │ ├── utils/ │ │ ├── dataset_split.py │ │ ├── data_augment.py │ │ └── visualize.py ├── web/ │ ├── app.py # Flask 或 FastAPI 后端 │ ├── templates/ │ └── static/ └── requirements.txt这样的结构在答辩演示时有条理也方便后续扩展。8.2 数据集层面的提升方向花卉识别精度低最常见的原因不是模型不行而是数据太少。数据增强是成本最低的提升手段但也需要注意增强后的样本是否合理。比如花瓣纹理被过度变形反而会影响模型学习。另一个方向是做类别平衡。如果玫瑰样本有 1000 张而小雏菊只有 200 张模型会严重偏向样本多的类别。这时可以采用对样本少的类别做更多增强。复制样本少的图片并做轻微几何变换。在 loss 中增加类别权重。8.3 模型层面的改进方向如果你的毕设要求有“改进”和“创新”可以从以下几处入手注意力机制在 C2f 模块中加入 SE、CBAM、ECA 或 SimAM 模块增强模型对花朵特征的关注能力。主干网络替换将 YOLOv8 的 Backbone 换成 MobileNetV3、ShuffleNetV2 或 Swin Transformer 的变体。小目标检测改进增加一层 P2 检测头或在 Neck 中引入 BiFPN 结构提升对小花的检测能力。损失函数优化将 CIoU 换成 SIoU 或 Wise-IoU改善边界框回归精度。注意力蒸馏用大模型 YOLOv8x 蒸馏小模型 YOLOv8s兼顾精度和速度。这些改进方向都可以在论文中形成对比实验单独用表格列出 baseline 和改进后模型的 mAP、参数量、推理速度。8.4 部署层面的注意事项如果你的系统是一个 Web 应用比如用户上传花卉图片返回识别结果建议使用 FastAPI 或 Flask 封装模型推理接口。这里给出一个简单的 Flask 接口示例# 文件路径web/app.py from flask import Flask, request, jsonify from ultralytics import YOLO import tempfile import os app Flask(__name__) model YOLO(runs/detect/train/weights/best.pt) app.route(/predict, methods[POST]) def predict(): file request.files.get(image) if not file: return jsonify({error: no image}), 400 with tempfile.NamedTemporaryFile(suffix.jpg, deleteFalse) as tmp: file.save(tmp.name) result model.predict(tmp.name, conf0.3)[0] os.unlink(tmp.name) detections [] if result.boxes is not None: for box in result.boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) detections.append({ class: result.names[cls_id], confidence: round(conf, 4) }) return jsonify({detections: detections}) if __name__ __main__: app.run(host0.0.0.0, port5000)部署时要注意模型加载只需要一次不要在每次请求时反复加载权重否则服务响应会非常慢。另外务必做输入文件的类型校验和大小限制防止异常文件导致服务崩溃。8.5 关于模型精度的底线建议毕设答辩时老师往往不要求 mAP 多高更在意你是否理解了整个流程。所以只要 mAP50 在 0.8 左右mAP50-95 在 0.6 左右在花卉数据上已经是很好的结果没必要为了极致精度耗尽所有时间。把时间花在系统完整性和演示效果上性价比更高。9. 让项目迁移到其他场景这套流程不局限于花卉识别。换个数据集和配置文件就能做果树检测、交通标志识别、口罩佩戴检测、工业零件缺陷检测等任务。唯一需要修改的只是数据集目录和标注内容。flower.yaml中的nc和names。训练脚本中的data路径。比如你需要做“校园鸟类识别”只要准备相应的图像和标注把names改成鸟的类别其他代码完全不变。这也是为什么推荐毕设采用 YOLOv8 的原因扩展性很强后续如果改课题方向不用换技术框架。如果想从目标检测切到图像分类训练代码改一行from ultralytics import YOLO model YOLO(yolov8s-cls.pt) results model.train(dataflower_dataset, epochs50, imgsz224)Ultralytics 同时提供分类模型权重数据集目录结构不做标注也可以训练适合纯分类任务但不是本文重点。动手跑通整个流程才是关键。先准备数据再跑训练脚本把一次完整的训练流程记录成日志带着这个日志去迭代优化。比起反复看理论亲自动手遇到一次报错并解决收获更大。