简介YOLO格式的鲜花分类数据集覆盖康乃馨、玫瑰、向日葵、雏菊等14种常见花卉面向目标检测与图像分类的学习者适合用于模型快速验证、性能评估和小数据集分类训练。资源以JPG图像为主体共2000个文件、压缩包约844.66MB其中1994张图片按训练集和验证集分别存放并附带4个JSON标注文件、1个Markdown说明文档及1个gitattributes配置便于对照查看数据组织方式与标注细节。数据集采用train、val两层目录结构同一类别的图片集中在一个子文件夹中同时提供与标注ID对应的classname.txt类名文件可快速建立标签与类别映射降低上手门槛。目前已有387人学习下载适合刚接触YOLO系列模型、需要一份分类清晰的小型数据集做练习或算法验证的开发者。1. 为什么一张「yolo鲜花分类数据集」能卡住整个项目一周看到「yolo鲜花分类数据集」这个标题很多人的第一反应是去网上下载一个现成的花卉图片包扔给YOLO训练然后等着模型能数出画面里有几朵玫瑰。真这么做大概率翻车——公开的花卉数据集大多是分类任务格式一张图正中一朵大花直接喂给检测模型模型学到的其实是「画面中央带花瓣的风景」一到花店实拍、公园远景、花束拥挤的场景就全线崩坏。这背后的差距不在模型结构而在数据集的定义方式你需要的不是「能训练的数据」而是一套标注规范、目录结构、划分策略都贴合 YOLO 训练流程的样本集。本文面向想用检测模型做鲜花识别、又不满足于公开数据集效果的同学讲清楚这类数据集应该怎么造、怎么验、怎么把坑提前踩平。2. 公开花卉集为什么喂不饱 YOLO任务格式与数据难度的双重错位2.1 YOLO 吃的不是图片是归一化边界框YOLO 的 detect 任务训练样本是「图片 标签 txt」。每个 txt 文件里每一行代表一个目标包含类别编号和归一化后的中心坐标、宽高。这和分类数据集的「文件夹名即标签」完全是两套体系。如果你的需求是「一张图里有且只有一种花只要告诉我是什么花」那可以直接走 YOLO 的 cls 模式数据集按文件夹组织训练命令也简单。但只要你需要知道「画面里哪几朵是玫瑰、哪几朵是雏菊」就必须走 detect 模式为每一朵花画一个框。这个区别是标题歧义的根源。很多人搜「鲜花分类数据集」拿到的却是一堆图片集最后训练时才发现标签没法用。先想清楚自己的交付物是「类别」还是「框」——这一步想不清楚后面全部白做。2.2 公开花卉数据集的四个不合身公开的花卉图片集常见问题可以归成四类。第一标签粒度不统一。有的按品种分有的按颜色分有的把月季和玫瑰当成两个类而生物学上它们的关系非常复杂。YOLO 训练最怕类别定义漂移同一个物种今天叫 rose 明天叫 rosa 之类标注的人自己都会标乱。第二图片构图太「正」。公开集里大量是单花特写目标居中、占比大、背景干净。这种图训练出来的模型权重里「花」和「背景」的边界特别牢遇到真实场景里的遮挡、逆光、多目标重叠检测置信度直线下降。第三类别不平衡严重。好看的品种样本多冷门品种可能只有几十张训练时小类的梯度被大类的 loss 淹没最后 mAP 还行单独看某个冷门品种的召回率几乎为零。第四格式需要二次转换。就算你拿到的是 Pascal VOC 格式的标注也要把它转成 YOLO 的归一化 txt。转换本身不难难的是转换过程中常见的坐标越界、类别 ID 错位、图片和标签文件名对不上这些坑。2.3 鲜花检测比通用检测多出的三类坑鲜花不是「桌子」「椅子」那种结构固定的刚体。第一坑是类间相似度高菊科一堆花长得像同一个模子绣球和某些伞形科花卉在远处看几乎一样模型需要非常细的纹理特征才能区分。第二坑是类内差异大同一品种的绣球有蓝、粉、紫多个色系盛花期和凋谢期的形态也差很多。第三坑是尺度与遮挡花海远景里一朵花可能只有十几个像素而近景特写里一束花有二十几个互相重叠的框。这三类坑决定了鲜花数据集不能照搬通用目标检测的数据增强策略。比如随机裁剪就很容易把花冠裁掉一半模型学到的训练样本是一堆残花。后面的数据增强参数我会在训练前的小模型验证环节专门说明怎么调。3. 搭建一套 YOLO 可训练的鲜花分类数据集目录、标签与标注规范3.1 一图一标目录结构从哪开始我一般会在项目根目录下建一个干净的 data 目录把图像和标签分开管理然后按 train / val / test 划分。这里的关键不是目录名而是和 dataset.yaml 里的配置保持一致。mkdir -p flower_dataset/{images/{train,val,test},labels/{train,val,test}}注意 labels 目录下的子目录结构必须和 images 完全对应。YOLO 训练时会自动根据图片路径寻找对应的 txt 标签默认规则是把 images 替换为 labels、把图片后缀替换为 .txt。如果目录结构不一致训练时会疯狂报「label not found」的警告虽然训练不中断但你这批数据的有效标签数可能是 0。划分比例上我通常用 8:1:1 或者 7:2:1。样本总量少于 3000 张时建议 8:1:1因为验证集太薄的话指标波动会非常大你很难判断一次改动到底是变好还是变坏。3.2 标签 txt 与 dataset.yaml一个样本走完喂给 YOLO 的全链路假设你要做 5 种花玫瑰、向日葵、郁金香、雏菊、兰花。类别编号从 0 开始dataset.yaml 这样写path: ../flower_dataset train: images/train val: images/val test: images/test nc: 5 names: 0: rose 1: sunflower 2: tulip 3: daisy 4: orchidpath是数据集根目录train和val是相对于path的路径。nc是类别总数names里的顺序就是标签文件里类别编号的顺序。这里最大的坑是如果你在标注工具里设定的类别顺序和 names 不一致模型会把玫瑰学成向日葵而且你不会第一时间发现因为 loss 照样在下降。再看一张图的标签 txt。假设图片宽 1920、高 1080其中一朵玫瑰的框是左上角 (200, 300)、右下角 (600, 750)。归一化计算方式如下x_center (200 600) / 2 / 1920 # 0.2083 y_center (300 750) / 2 / 1080 # 0.4861 w (600 - 200) / 1920 # 0.2083 h (750 - 300) / 1080 # 0.4167对应的 txt 一行就是0 0.2083 0.4861 0.2083 0.41670是 rose 的类别编号后面依次是中心点 x、中心点 y、宽度、高度全部是 0 到 1 之间的浮点数。YOLO 官方实现里不允许 w 或 h 为 0也不允许中心点在图片外。这些数值如果出现越界训练时会被过滤掉代价是你可能某张图一个目标都没留下。我习惯在标注完成后用一小段脚本把所有标签扫描一遍而不是等到训练时让模型去「沉默地跳过」。这个脚本会在第四章给出。3.3 标注工具选型与花朵框的标注习惯单人小批量标注我推荐 labelImg轻量、装好就能用快捷键 W 画框、A 切上一张、D 切下一张。团队协作、需要多人同时标注时CVAT 是更合适的选择它在浏览器里跑可以分配任务、审核标注结果。如果你有 GPU 且想省时间x-anylabeling 这类带 SAM分割模型插件的工具可以先自动生成候选框人工微调效率提升明显。无论用哪个工具花朵框都有几个约定俗成的习惯。第一框只包住花冠主体尽量不包含花茎和叶子如果花是侧面的可以包含一点点花托但不要一路框到底把整根茎都圈进去。第二可见部分占整朵花的 50% 以上才标比如一把花束里被完全挡住的、只能看到一小片花瓣的不标。第三严重模糊的图不要删得太干净保留一部分作为困难样本但占比控制在总样本的 5% 以内否则会把模型训得疑神疑鬼。标注速度上单人一天大概能标 300 到 500 个框如果花束场景一图十几个目标速度会掉到 100 张以内。预算不够又赶时间的话可以先标 500 张训一版模型再用模型去预打标这个流程在第六章展开。4. 数据集清洗、分层划分与格式自检训练前必做的三件事4.1 第一轮清洗重复图、损坏图与模糊图批量排查很多人拿到一批图就直接开标标到一半发现有两百多张是同一场景换了个角度白白浪费人力。我一般先做三轮机械排查。先把完全重复的图去掉。计算文件的 MD5比对哈希值能干掉一模一样的副本。但手机连拍的多张照片往往只是相似、不是完全相同这时可以用感知哈希pHash把每张图缩到小尺寸、转灰度、算哈希汉明距离小于 5 的视为重复候选人工扫一眼确认。然后是损坏图。有的图后缀是 .jpg 但实际解码失败训练时读到一半会报错。用 OpenCV 批量读一遍读不出来的直接移入 discard 目录。最后是模糊图。这里给一个可跑的脚本思路用拉普拉斯方差给每张图打分分数越低越可能模糊。import cv2 from pathlib import Path def score_blur(img_path, threshold50): img cv2.imread(str(img_path), cv2.IMREAD_GRAYSCALE) if img is None: return None, False var cv2.Laplacian(img, cv2.CV_64F).var() return var, var threshold for p in Path(raw_images).rglob(*.jpg): var, is_blur score_blur(p) if is_blur: print(f{p}: {var:.1f})threshold不是固定值跟你的拍摄设备、压缩质量都有关系。我的习惯是先只打印不处理跑一遍看分数的分布再取分数最低的 5% 人工过一遍。不要脚本说模糊就删有些花天生纹理弱拉普拉斯分数就是低强行删掉会误伤正常样本。4.2 按类别与拍摄批次分层划分 train / val / test随机划分是最容易犯的错。假设你某一天在植物园拍了一整片郁金香同一个画面连续拍了 10 张随机划分时这 10 张可能 5 张进训练集、5 张进验证集。训练时模型相当于「见过」验证集的同一朵花的另一半角度验证指标会虚高到让你误以为模型已经很强。正确的做法是双层分层先按类别分层保证每个类别在三个集合里的比例和总体一致再按拍摄批次分组同一时间段、同一地点的照片只能整体进入其中一个集合。import random import shutil from pathlib import Path random.seed(42) def split_by_group(groups, train_ratio0.8, val_ratio0.1): groups list(groups) random.shuffle(groups) n_train int(len(groups) * train_ratio) n_val int(len(groups) * val_ratio) return { train: groups[:n_train], val: groups[n_train:n_train n_val], test: groups[n_train n_val:], } # 假设 groups 是 dict: {组名: [图片路径列表]} # 组名可以按日期地点拼接例如 20241001_植物园这里最关键的是随机种子固定方便复现。另一个容易被忽略的点是如果某个冷门类别只有 30 张按 8:1:1 划分后验证集只有 3 张指标波动会非常大。这种情况我一般把该类别的最小验证样本量卡到 10 张不足的话训练集和验证集适当交叉或干脆对这个类别不做 test 划分。4.3 标签合法性自检越界、缺文件与空标签标注完、划分完训练之前一定要跑一遍标签自检。常见问题包括标签文件里类别 ID 大于 nc-1、坐标出现负数或大于 1、w 或 h 为 0、图片存在但标签缺失、标签文件是空的。from pathlib import Path def check_dataset(label_root, num_classes5): problems [] for label_file in label_root.rglob(*.txt): lines label_file.read_text().strip().splitlines() if not lines: problems.append((str(label_file), 空标签)) continue for line in lines: parts line.strip().split() if len(parts) ! 5: problems.append((str(label_file), 字段数不为5)) continue cls int(parts[0]) x, y, w, h map(float, parts[1:]) if cls num_classes: problems.append((str(label_file), f类别ID越界: {cls})) if not (0 x 1 and 0 y 1 and 0 w 1 and 0 h 1): problems.append((str(label_file), f坐标非法: {line})) return problems for p, reason in check_dataset(Path(flower_dataset/labels), num_classes5): print(f{p}: {reason})num_classes必须和 dataset.yaml 里的nc一致。跑完自检后有问题的文件要么修要么移除不要带着问题进训练。YOLO 对非法标签的处理是「静默跳过」这意味着你可能训了 100 个 epoch 才发现某类图片实际上一张都没参与训练浪费一整个晚上的算力。4.4 先训一个最小的模型把数据集跑通数据集做完先不要上大模型。用最小的预训练权重比如 YOLOv8n先训 30 个 epoch目的不是出成绩而是验证「数据链路通不通」图片能不能读、标签能不能解析、loss 能不能正常下降。yolo detect train dataflower_dataset/dataset.yaml modelyolov8n.pt epochs30 imgsz640 batch16imgsz640是训练输入尺寸算力紧张时可以降到 512但对于花这种小目标多的场景降分辨率会丢掉细节不建议低于 512。batch16根据显存调整显存不够就降到 8。我看到很多新手用 3080 以上的卡也会把 batch 拉到 64然后训练时显存溢出、中断其实 batch 16 在这个阶段足够稳定地反映 loss 趋势。跑完后看两个东西。第一是 loss 曲线训练 loss 前 10 个 epoch 应该持续下降val loss 可能会震荡但整体趋势向下。如果训练 loss 从第一个 epoch 开始就横在 3 左右不动多半是标签和图片对不上或者 dataset.yaml 里路径写错。第二是可视化预测结果随便抽几张 val 图片看预测框如果框的位置明显偏离花的中心说明标签格式转换时坐标出了问题而不是模型训练不到位。这套最小模型跑通后再决定是直接调大模型训练还是先做预打标扩样本。大部分情况下你会发现样本量不够需要回到标注环节再补一批。5. 鲜花分类数据集训练避坑现象、原因与解决办法5.1 类别严重不平衡小类永远学不会现象训练结束后大类比如玫瑰的 mAP50 到了 0.9小类比如蒲公英只有 0.3推理时蒲公英几乎不输出框。原因样本量差距大模型在反向传播时大类贡献的 loss 占绝对主导小类的梯度被淹没。这不是学习率问题是数据分布问题。解决先尝试对小类做过采样也就是把蒲公英的样本复制几份进训练集。注意不要复制同一张图多次——模型会对这张图过拟合正确做法是复制后配上不同的数据增强。如果过采样后小类还是起不来给 loss 加类别权重具体做法是把每个类的样本数倒数归一化后传给训练脚本。最有效的做法还是回去补拍哪怕一个小类只补 100 张效果也比调参强。5.2 数据泄漏同一朵花出现在训练集和验证集现象验证集准确率很高但拿到真实场景一测就崩检测框乱飞置信度普遍低于 0.4。原因同一朵花的不同角度、不同光线下的照片被随机划分拆进了训练集和验证集。模型在训练时已经「背过」验证集里的目标验证指标失真。解决按拍摄批次分组划分同一时间、同一地点的一组照片只能整体进入 train / val / test 的一个集合。分组信息可以在采集时就写入文件名比如20241001_植物园_玫瑰_001.jpg这种格式此后做任何划分都基于这个前缀。我见过某开发者在这上面栽过跟头重划分后同一套模型真实场景的表现涨了十几个点。5.3 标注框把整株植物都框了进去现象训练 loss 正常下降但 val 的 PR 曲线异常有些类别的框明显偏大预测框往往比花大两三倍。原因标注员为了省事把花连同茎、叶、旁边的花苞一起框了。这样模型学到的正样本里包含大量绿色背景特征被稀释。解决回到标注规范框只包住花冠主体。这个问题的隐蔽性在于如果所有标注框都偏大模型也能收敛它学的是「一坨花叶」的整体模式等部署时遇到只有花没有叶的场景召回率骤降。我处理这种问题的方法是抽查每个类别的标注框可视化把框的尺寸分布拉出来看如果某一类框的宽高比集中在 2.0 以上说明大概率框进了茎叶。5.4 网络图片混入训练集loss 震荡不止现象训练 loss 曲线上下跳动滤波后也不平滑前 5 个 epoch 尤其明显且 val 指标一直上不去。原因从搜索引擎或公开数据集里抓的图带有水印、压缩噪声、拼接式长图甚至还有插画和真实照片混在一起。模型在这些人造特征上反复横跳学不到稳定的花的特征。解决严格限定训练集来源自己拍的优先确实需要外部图补充类别多样性至少过滤掉带水印的图并用 4.1 的模糊脚本筛掉低质量样本。水印很影响花朵的局部纹理模型很容易把「水印」当成「花瓣特征」的一部分推理时见到任何带纹理的区域都会误报高置信度。5.5 类别名称不统一标注错乱直到训练结束才发现现象训练跑完输出 confusion matrix 时发现「rose」和「月季」两个类互相误判率极高或者某个类别名称在标注工具里叫简称、在 dataset.yaml 里叫全称同一物种被拆成两个类。原因多人协作标注时没有统一的词汇表。一个人标「rose」另一个人标「rosa」模型被逼着把同一个物种学成两个类。解决动笔标注前先建一张类别定义表指定每个类别在数据集里的英文 ID 和中文备选名标注工具里只用 ID 或固定的英文名不允许标注员自由发挥。这张表还要包含「常见混淆项处理规则」比如「单瓣月季一律归入 rose即使它的商品名叫玫瑰」。类别定义是数据集的宪法改它的成本远高于重标几百张图。6. 让数据集越用越强预打标、主动补样与验收习惯6.1 用已有模型做预打标把标注成本压到最低整套数据做完且首版模型训好之后你会有大量未标注的新图片。常见做法是拿当前最好的权重去做批量推理把预测结果转成 YOLO 标签再让标注员只做「确认和微调」而不是从零画框。yolo detect predict modelruns/detect/train/weights/best.pt sourceunlabeled_images save_txtTrue conf0.3save_txtTrue会为每张图输出一个同名 txt 标签conf0.3控制置信度阈值。低于这个阈值的检测不会生成标签。注意这里有个权衡置信度阈值调得过低伪标签里全是噪声框人工复核反而更费劲调得过高漏检的目标需要标注员自己补充效率提升有限。我的习惯是先跑几个阈值比如 0.3 和 0.5对比伪标签的数量选一个人工修改量最小的组合。预打标能把单张标注时间从 30 秒压到 5 秒左右但它引入了「标注员默认模型是对的」的心理惯性所以漏检比误检更危险——模型没看到的目标标注员很容易跟着没看到。复核前要明确提醒格外注意没出框的区域。6.2 让模型告诉你该补哪些样本模型训练完后除了看指标拿它去跑一遍未标注的候选图片把「低置信度样本」和「误检样本」挑出来这些就是模型最困惑的数据。你给这些困难样本做标注并补充进训练集比随机补拍一批场景图的效果好得多。具体做法是对候选图片批量推理输出每张图最高置信度的类别和分数把所有最高置信度低于 0.5 的图片汇总成一份清单。有两种情况。一种是无检测框说明模型没认出来这些图往往是新场景或新角度。另一种是有框但置信度只有 0.2 到 0.4说明模型觉得「像花但不像任何一种已知花」这些图往往对应类间相似的品种。把这两类都补标进去训练迭代的效率立刻就能看出来。补数据的原则是一次补 200 到 500 张训一版看指标变化而不是攒了 2000 张才训一次。花的类别差异大可能补 200 张困难样本某个小类的召回率就从 0.5 跳到 0.8。6.3 每次训练完固定做一次可视化工序训练不是看 loss 降了就收工。我现在养成的习惯是每一版模型跑完必做三件事第一从验证集每个类别里随机抽 30 张图做推理可视化打印成网格图肉眼扫一遍检测框的位置和置信度这能揪出标签错乱这类指标看不出来的问题。第二看混淆矩阵尤其关注相似品种间的误判率——月季和玫瑰如果混淆率超过 5%回去查类别定义而不是调模型。第三用验证集扫描一遍置信度阈值画出 PR 曲线给业务方一个明确的阈值建议而不是让他们默认用 0.25。这三个习惯看着笨重但每一条都帮我省过重新标注的力气——尤其是可视化抽查它是最便宜的数据质量审计方式。如果你也在做类似方向建议每次都把固定随机种子、训练命令、最终可视化结果存档。等三个月后数据集扩到一万张这些记录就是你判断「这次改动到底有没有变好」的唯一依据。希望帮到你。本文还有配套的精品资源点击获取