
简介面向YOLOv8目标检测与图像分类任务的花卉数据集包含daisy、dandelion、roses、sunflowers、tulips五个常见类别覆盖不同角度、光照与背景下的花朵图像可直接用于训练花卉识别模型、评估分类算法也可作为高校计算机视觉课程的教学案例。压缩包共2000个文件其中1999张JPG图像构成主要样本集另附1个Python脚本便于做数据划分、格式检查或二次扩展整体大小约218.93MB目录结构简洁清晰可无缝接入YOLOv8训练流程省去大量数据准备时间。围绕花卉分类系统资源还从组织识别、科学研究、园艺农业应用、濒危物种保护和科普教育等方向展开使用者在利用图像完成训练、验证与推理的同时也能理解分类任务在植物学研究和产业实践中的实际价值。已有621人浏览学习该资源适合希望从数据到模型完整跑通流程的初学者同样适合用于算法对比、课程设计或后续数据增强研究的开发者。1. 花卉分类的瓶颈在数据一套 YOLOv8 五类数据集的定位花卉图像识别的公开实验很多真到落地时问题几乎都堆在数据集环节。ImageNet 风格的花卉数据集是单标签整图分类类别裁切范围、背景占比差异大直接转目标检测训练框的语义就乱了。这套 YOLOv8 格式的五类花卉数据集daisy、dandelion、roses、sunflowers、tulips把数据组织成了检测任务的标准形态图像与 txt 标签一一对应标签是 class_id 加归一化 bbox 坐标补一个 data.yaml 就能直接进入 ultralytics 训练流程。做毕业设计的人可以省掉标注和格式转换这两件最耗时的事做边缘端花卉识别的工程师可以拿它当基线数据先把检测头、增强策略和部署链路跑通再按业务场景扩数据。提醒一句解压后先确认完整样本量与类别分布再开始训练别被预览图带偏预期。2. 数据集目录结构与 YOLOv8 标签格式解析2.1 目录组织与 train/val 划分惯例YOLO 生态里数据集的标准组织方式是 images 与 labels 两个目录平级各自下面按 train、val 分子目录。这套五类花卉数据集的目录结构沿用了这个惯例解压后你会看到 images/train 下是 jpg 图像labels/train 下是逐图对应的 txt 标注val 目录同理。文件名主体一一对应、扩展名不同这是 ultralytics 数据加载器能够自动匹配的前提。flower_dataset/ ├── images/ │ ├── train/ │ │ ├── 2431737309_1468526f8b.jpg │ │ └── ... │ └── val/ ├── labels/ │ ├── train/ │ │ ├── 2431737309_1468526f8b.txt │ │ └── ... │ └── val/ └── data.yaml这套划分方式对检测任务来说是最省事的YOLO 的 dataloader 不做额外解析只要路径配置正确训练和验证阶段会自动读取对应目录下的 txt。如果原包没有提供 val 划分需要自己拆分时常见做法是 train:val8:2并用分层采样保证五个类别在两个集合里的比例接近原始分布。直接用 random.shuffle 切分的问题在于dandelion 这类小类别样本量少随机切分可能让验证集里某个类别只有个位数样本导致 mAP 指标方差很大一次实验的结果不可信。分层切分可以用 sklearn 的 train_test_split 实现按图片名对应的主标签传入 stratify 参数。from sklearn.model_selection import train_test_split from pathlib import Path img_files sorted(Path(images).glob(*.jpg)) def main_label(img_path): txt Path(labels) / (img_path.stem .txt) counts {} for line in txt.read_text().strip().splitlines(): cid int(line.split()[0]) counts[cid] counts.get(cid, 0) 1 return max(counts, keycounts.get) labels [main_label(p) for p in img_files] train_idx, val_idx train_test_split( range(len(img_files)), test_size0.2, stratifylabels, random_state42 )这段代码先统计每张图的主类别再按主类别做分层切分保证验证集里五类比例与全集一致。random_state 固定下来后续多次实验的划分可复现对比不同超参数时不会引入数据划分噪声。stratify 参数要求每个类别的样本数不小于 2否则会报错真遇到这种情况说明该类别数据量太少需要考虑先做数据扩充而不是强行划分。2.2 labels 里的五类标注规则每个 txt 文件的一行对应一个目标五个字段依次是 class_id、cx、cy、w、h全部为归一化数值。cx、cy 是 bbox 中心点相对图像宽高的比例取值在 0 到 1 之间w、h 是框的宽高相对图像宽高的比例同样在 0 到 1 之间。类别编号从 0 开始编号与类别名的对应关系如下表。class_id类别名典型视觉特征0daisy白色细长花瓣、黄色花心单头为主1dandelion黄色放射状花瓣花茎中空2roses多层螺旋花瓣红粉色调居多3sunflowers大型黄色花盘花径占比大4tulips杯状单层花瓣直立花茎这个编号顺序必须与 data.yaml 中 names 列表完全一致训练脚本不会自动纠正顺序写错一位整类全错。一个容易忽略的细节是roses 和 tulips 经常成簇出现一张图里可能有十几个框而 dandelion 通常单株出现标签文件行数差异大是正常现象不代表数据有问题。提示标签里允许同一张图存在多个类别但每行只能有一个类别 ID多类别混合图在自然拍摄的花卉场景里很常见标注时不要把一朵花拆成两个框。真正需要警惕的是框的边界归一化坐标允许 cx 或 cy 落在图像边缘但 w 和 h 不能为 0 或负数也不能超过 1。标注工具导出时偶尔会产生边角越界的框这类脏数据对 loss 的影响在训练初期不明显后期会持续拉低定位精度所以训练前做一轮体检是值得的。2.3 用脚本核对 bbox 坐标合法性拿到数据集先做一次全量体检比训练到一半再排查要划算得多。下面这个脚本遍历 labels 目录检查每个 txt 的行数、字段数和坐标范围。from pathlib import Path import cv2 label_root Path(labels/train) img_root Path(images/train) bad 0 for lp in sorted(label_root.glob(*.txt)): img_path img_root / (lp.stem .jpg) if not img_path.exists(): print(f[missing] {img_path}) bad 1 continue h, w cv2.imread(str(img_path)).shape[:2] for line in lp.read_text().strip().splitlines(): parts line.split() if len(parts) ! 5: print(f[field] {lp.name}: {line}) bad 1 continue cid, cx, cy, bw, bh map(float, parts) if not (0 cx 1 and 0 cy 1): print(f[center] {lp.name}: {line}) bad 1 if bw 0 or bh 0 or bw 1 or bh 1: print(f[size] {lp.name}: {line}) bad 1 print(ftotal issues: {bad})脚本对每个标签文件做三类检查图片缺失、字段数量不对、坐标越界。越界检查基于归一化约定cx、cy 必须落在 [0,1]w、h 必须在 (0,1]。如果原标注是从 COCO 或 VOC 格式转换来的转换时最容易犯的错误是把像素坐标直接除以图片短边而不是各自的长边导致宽高比失真这类问题能从这里查出一部分。检查通过后再进训练后续的 loss 波动才不会让人怀疑数据本身检查有报错也不要慌把异常文件单独移到一个 debug 目录不影响其余数据训练。3. 基于 ultralytics 训练五类花卉模型的配置与超参数3.1 data.yaml 的编写要点ultralytics 训练入口只认一个 yaml 文件把数据集路径、类别数、类别名写对就行。针对这套五类花卉数据集data.yaml 内容如下path: /home/user/flower_dataset train: images/train val: images/val nc: 5 names: 0: daisy 1: dandelion 2: roses 3: sunflowers 4: tulipspath 写绝对路径最省心train 和 val 相对 path 解析。常见的坑有三个一是 path 写在注释里被忽略训练时直接报 dataset not found二是 names 用 1 起始编号与标签文件里的 0 起始编号错位导致所有框的类别整体平移一位三是每类图片数量差距大时不加任何提示模型闷头训练最后小类别 mAP 近乎为 0。检查 yaml 最直接的方法是先用代码打印类别分布而不是直接开跑。from ultralytics.data import YOLODataset ds YOLODataset(flower.yaml) cnt {name: 0 for name in ds.names.values()} for lb in ds.labels: for c in lb[cls]: cnt[ds.names[int(c)]] 1 print(cnt)这段代码遍历训练集所有标签逐类累加目标数量。注意这里遍历的是 lb[cls] 的全部元素不是只取第一个密集标注的图可能同时包含多个类别只取第一个会把多类别图统计成单类别。输出结果用来判断是否需要做类别重加权或过采样这直接影响后续训练对稀有类别的关注程度。3.2 训练命令与关键超参数数据集检查通过后训练命令可以写得非常简洁yolo detect train \ modelyolov8n.pt \ dataflower.yaml \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ optimizerauto \ patience20几个参数单独说。modelyolov8n.pt 是预训练权重对五类花卉这种中等规模任务n 版本足够打出基线如果最终要部署到边缘设备n 也是性价比最高的选择。imgsz640 是训练与推理统一的分辨率花卉图像长宽比不一时ultralytics 会自动做 letterbox 填充不必手动预处理。batch16 在 8GB 显存的卡上比较稳妥显存不够就降到 8用 GTX 1660 Ti 这类 6GB 卡跑的话建议 batch8、关闭 mosaic 或者把 imgsz 降到 480否则容易 OOM。patience20 是早停窗口花卉分类任务通常在 60 到 80 轮收敛20 轮没有提升就停能省不少时间。参数默认值本数据集的建议设置理由imgsz640480~640花卉目标占比中等640 保留花瓣纹理小显存降 480batch168~16视显存而定小于 8 时 loss 波动明显lr00.010.005~0.01数据量小时 lr 过大容易震荡optimizerautoSGD 或 AdamWauto 会按模型自动选手动指定更好复现mosaic1.00.5~1.0密集花卉被裁剪后容易漏检小目标关于 lr0如果每类只有几百张图0.01 配余弦退火问题不大如果总量只有几十张建议降到 0.005并适当延长 warmup 轮数。训练完成后看 runs/detect/train 下的 results.csv比看终端输出更直观里面每一列对应一个指标可以直接用 pandas 读取绘图。3.3 类别不均衡与数据增强的取舍五类花卉天然存在不均衡roses 和 sunflowers 样本多dandelion 样本少。不处理这种不均衡模型会倾向于把不确定的框判给大类。常见处理方式有三种类别重加权、过采样小类、调整增强强度。ultralytics 可以用 class weights 参数传入每个类别的权重向量但需要手动算不如直接在数据层面处理来得直观。# augment 相关参数可以在训练命令中通过 augmentTrue 启用 hsv_h: 0.015 hsv_s: 0.5 hsv_v: 0.4 fliplr: 0.5 mosaic: 0.5 mixup: 0.1这些增强参数的作用对象是整张图。hsv 扰动模拟不同光照下的花色变化对花卉这种颜色敏感的类别很有效fliplr 水平翻转不改变花的语义可以放心开mosaic 和 mixup 对小样本类别有正则化作用但 mosaic 会把四张图拼在一起花卉边缘被切掉后原本就小的 dandelion 目标可能只剩半个所以建议从默认的 1.0 降到 0.5。跑一轮对比实验一组关闭 mosaic一组保持 0.5观察 val 集上 dandelion 类别的 mAP50 差异这个数字比整体 mAP 更能反映增强策略对弱类别的实际影响。mixup 对花卉这种细节纹理敏感的任务效果不稳定值不要超过 0.2否则模型会学到两张图叠在一起的混合特征。4. 训练过程评估与数据质量回溯4.1 从 loss 曲线读训练状态训练结束后runs/detect/train 目录下会有 results.csv 和一组自动生成的曲线图。对五类花卉这个任务重点关注三组曲线train/box_loss、train/cls_loss、val/box_loss 与 val/cls_loss。训练正常的信号是曲线同步下降并在后半程趋于平缓val 曲线没有明显回升说明没有过拟合。用下面这段代码直接读取 results.csv 画曲线比打开自动生成的图更灵活也能自定义保存分辨率import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/train/results.csv) df.columns [c.strip() for c in df.columns] fig, ax plt.subplots(1, 2, figsize(12, 4)) ax[0].plot(df[epoch], df[train/box_loss], labeltrain box) ax[0].plot(df[epoch], df[val/box_loss], labelval box) ax[1].plot(df[epoch], df[train/cls_loss], labeltrain cls) ax[1].plot(df[epoch], df[val/cls_loss], labelval cls) for a in ax: a.legend() a.set_xlabel(epoch) plt.tight_layout() plt.savefig(loss_curves.png, dpi150)常见但容易被误判的情况是train/cls_loss 一直下降val/cls_loss 在第 30 轮开始反弹而 box_loss 还在降。这通常说明分类分支过拟合bbox 回归还在正常进步。处理办法不是调低学习率而是增加数据增强强度或减少 epochs也可以先确认是不是类别不均衡把分类分支带偏了回看第 3.3 节的增强参数。loss 曲线整体偏高但趋势正常往往不是模型问题而是标签里 bbox 框得偏大或偏小检查标注就对了。4.2 混淆矩阵与 PR 曲线怎么读val 阶段生成的 confusion_matrix.png 是五类数据最值得看的图。行列都是五个类别加一个 background对角线越亮越好。对花卉分类最容易混淆的是 roses 和 tulips两者花型接近、颜色重叠混淆矩阵里这两个非对角线格子如果明显偏亮说明模型学到了颜色和形状的共用特征而没学到区分性细节比如 tulips 的杯状花冠和 roses 的螺旋花心。PR 曲线看的是每个类别在不同置信度阈值下的精确率与召回率权衡。dandelion 的曲线面积如果明显小于 roses大概率不是模型能力问题而是该类别的目标占比低、标注框偏小。此时优先检查标注框是否过紧很多标注工具的自动贴边功能会裁掉花瓣边缘导致模型学到的特征不完整。现象优先排查项对应处理roses/tulips 混淆严重标注框是否包含完整花冠重标或补充特写样本dandelion 召回率低小目标占比、mosaic 增强降低 mosaic提高 imgsz所有类别 mAP 都不高标签坐标是否正确回跑 2.3 节脚本val loss 曲线抖动batch 过小或 lr 过高减小 lr0增大 batch这张表是排查顺序的参考按数据、增强、超参的顺序走不要一上来就动网络结构。C2f 模块和 head 结构的改动留到基线稳定之后再做否则问题混在一起根本定位不到根因。4.3 数据质量回溯坏样本对指标的影响训练结果异常时先把预测结果可视化而不是盯着指标猜。用 ultralytics 的 predict 跑验证集保存置信度较低的预测结果直接看模型到底漏了什么。yolo detect predict \ modelruns/detect/train/weights/best.pt \ sourceflower_dataset/images/val \ conf0.3 \ save_txtFalse \ saveTrue保存下来的图片里没有框的花就是漏检样本。对五类花卉而言最常见的问题是背景复杂、花朵被叶片遮挡以及逆光条件下花瓣与背景对比度低。这类坏样本不需要马上删掉而是记录文件名检查对应标签是否存在标注遗漏。很多时候模型没学会某个特征不是网络能力不够而是标注里把遮挡的花漏标了模型把遮挡的花学成了负样本。这种数据一致性问题通过可视化能很快定位比反复调参有效得多。定位到具体坏样本后用 LabelImg 或 X-AnyLabeling 补上遗漏框重新训练一轮类别 mAP 的提升往往立竿见影。5. 模型导出与端侧部署ONNX 转换与 NMS 参数调优5.1 导出 ONNX 并固定输入尺寸训练完成后导出部署格式是常见环节。对边缘设备优先导出 ONNX再转成对应平台格式。导出的关键参数是 imgsz 必须与推理时的预处理一致yolo export modelbest.pt formatonnx imgsz640 opset12 simplifyTrueopset 版本别追新RK3588 这类平台的 NPU 工具链对 opset 的支持往往滞后12 到 14 是兼容性较好的区间。simplifyTrue 会去掉一些冗余算子但导出后务必用 onnxruntime 跑一遍推理确认输出形状和数值范围正常simplify 偶尔会误删有实际作用的节点。端侧部署时如果量化工具链支持先用 val 集的一个子集做校准数据这类数据分布与真实场景越接近INT8 量化后的精度损失越小。5.2 推理侧处理密集花卉的 NMS 参数花卉场景与通用目标检测有个显著差异roses 和 tulips 密集排列时默认 NMS 的 IoU 阈值 0.45 会把相邻花朵合并成一个框。部署时把 NMS IoU 阈值适当降低到 0.3 到 0.35能显著减少漏检。同时 score_threshold 设为 0.25 左右即可花卉分类的类间相似度高阈值太高会把低置信度的真目标全滤掉导致召回率骤降。这两个参数在端侧通常暴露为配置文件里的 nms_iou_thresh 和 conf_thresh优化顺序是先调 NMS 再调置信度因为 NMS 决定框的数量上限置信度只是从这些框中做二次筛选。用验证集上的 PR 曲线辅助选阈值PR 曲线拐点对应的置信度就是 conf_thresh 的合理初始值不需要反复试。最后再做一次端到端验证用一段包含多株花簇的实拍视频确认漏检率和误检率都达标整个链路才算真正跑通。本文还有配套的精品资源点击获取