ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于YOLOv11的鲜花识别检测系统实战:从数据集构建到模型调优

基于YOLOv11的鲜花识别检测系统实战:从数据集构建到模型调优 简介这份资源面向计算机视觉研究人员、软件工程师及园艺与植物研究从业者提供一套基于YOLOv11的106种鲜花识别检测系统完整方案帮助读者掌握从环境搭建、数据集准备到模型训练、导出与GUI落地的全流程技术细节。资源包共1个docx文档约40KB以图文文档形式系统梳理项目介绍、特点、参考资料、未来改进方向与注意事项并分步讲解环境准备、数据集配置、模型训练、ONNX导出、性能评估、可视化指标及Tkinter界面创建等模块目录结构清晰便于按章节检索学习。目前已有137人学习下载。读者可借此了解YOLOv11在鲜花识别场景中的配置方法、训练要点与评价指标并参考数据增强、超参数调优、多格式输入扩展等改进思路为植物分类研究与落地实践提供可复用的技术参考。1. 鲜花识别检测系统从一张花店货架图说起花店老板拍一张货架照片想自动数出玫瑰、百合、向日葵各有多少支这个需求听起来简单做起来却卡在三个地方花种细粒度差异小、遮挡严重、标注数据难找。基于 YOLOv11 的鲜花识别检测系统本质就是拿 Ultralytics 这套目标检测框架在自定义鲜花数据集上做迁移学习最终输出每朵花的类别和边界框。它适合两类人一类是想拿一个完整项目练手 YOLOv11 全流程的开发者另一类是真的要做花卉分拣、库存盘点、植物科普应用的工程团队。这篇文章不讲空泛概念直接按「数据怎么造 → 模型怎么训 → 参数怎么调 → 坑怎么避」的顺序把一套能跑通的鲜花检测方案拆开讲清楚。2. 鲜花数据集怎么造从采集到 YOLO 格式转换2.1 鲜花检测的数据从哪来鲜花识别和通用目标检测最大的区别在于公开数据集少且类别定义模糊。COCO 里没有「玫瑰」「百合」这种细粒度标签ImageNet 的花卉分类数据集只有图像级标签没有边界框。所以做鲜花检测数据基本得自己造。常见做法有三条路。第一条是实地采集去花市、花店、植物园拍用手机就行重点是覆盖不同光照、不同角度、不同遮挡程度。第二条是网络爬取按花种关键词搜图但要注意版权和标注成本。第三条是数据增强合成拿已有的花卉分类数据集用分割模型粗定位后再人工修正。我一般会建议先做 5 到 8 个常见花种每个类别至少 300 张有效图总图量控制在 2000 到 4000 张。类别太多、每类样本太少YOLOv11 的 head 很难学到细粒度特征。鲜花检测的难点不在「有没有花」而在「这朵是什么花」所以类别平衡比总量更重要。采集时有个血泪经验别只拍单朵特写。真实场景里花是成簇的一朵挨一朵遮挡率经常超过 40%。如果训练集全是干净单朵图模型一到货架场景就翻车。建议至少 30% 的图包含多朵花、部分遮挡、背景杂乱的情况。2.2 标注规范与 LabelImg 实操标注工具用 LabelImg 或 CVAT 都行核心是统一边界框规则。鲜花检测的标注有两个容易出问题的地方一是花蕊和花瓣的边界怎么定二是重叠花朵怎么标。我的做法是边界框紧贴可见花瓣的最外沿被遮挡的花如果可见面积小于 30%标为 difficult 或不标。重叠情况下每朵花独立标框允许框重叠。类别名用英文小写比如 rose、lily、sunflower、tulip、carnation、orchid避免中文路径问题。LabelImg 保存时选 YOLO 格式每张图对应一个同名 .txt 文件每行格式是class_id x_center y_center width height所有坐标都是归一化到 0 到 1 之间的浮点数。这里有个新手常踩的坑LabelImg 默认可能保存成 PascalVOC 的 XML需要在保存前切换格式或者后期用脚本转换。2.3 从 VOC 转 YOLO 格式的转换脚本如果你手头已经有 XML 格式的标注用下面这个脚本批量转换。注意类别映射表要和你后续 data.yaml 里的 names 顺序完全一致。import xml.etree.ElementTree as ET import os import glob # 类别映射必须与 data.yaml 的 names 顺序一致 CLASS_MAP { rose: 0, lily: 1, sunflower: 2, tulip: 3, carnation: 4, orchid: 5 } def convert_bbox(size, box): 将 VOC 的 xmin,ymin,xmax,ymax 转为 YOLO 的归一化中心点宽高 dw 1.0 / size[0] dh 1.0 / size[1] x (box[0] box[1]) / 2.0 y (box[2] box[3]) / 2.0 w box[1] - box[0] h box[3] - box[2] return x * dw, y * dh, w * dw, h * dh def convert_xml(xml_path, out_dir): tree ET.parse(xml_path) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text.strip().lower() if name not in CLASS_MAP: continue cls_id CLASS_MAP[name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) bb convert_bbox((w, h), (xmin, xmax, ymin, ymax)) lines.append(f{cls_id} { .join([f{v:.6f} for v in bb])}) if lines: base os.path.splitext(os.path.basename(xml_path))[0] with open(os.path.join(out_dir, base .txt), w) as f: f.write(\n.join(lines)) if __name__ __main__: xml_files glob.glob(./annotations/*.xml) os.makedirs(./labels, exist_okTrue) for xf in xml_files: convert_xml(xf, ./labels) print(f转换完成共处理 {len(xml_files)} 个文件)这段代码的逻辑很直接解析 XML提取尺寸和每个 object 的类别与坐标归一化后写入 txt。关键参数是 CLASS_MAP它决定了类别索引一旦和训练时的 data.yaml 不一致模型会把玫瑰认成百合而且 loss 曲线看起来还挺正常排查起来很费时间。另一个注意点是 convert_bbox 里的坐标顺序VOC 是 xmin,ymin,xmax,ymax传入时我写成 (xmin, xmax, ymin, ymax) 是为了配合函数内部的取值顺序改的时候要对应上。2.4 数据集划分与 data.yaml 配置转换完成后按 8:1:1 划分训练、验证、测试集。目录结构建议如下flower_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yamldata.yaml 内容path: ./flower_dataset train: images/train val: images/val test: images/test nc: 6 names: [rose, lily, sunflower, tulip, carnation, orchid]这里 nc 必须等于 names 长度names 顺序必须和转换脚本里的 CLASS_MAP 完全一致。我见过有人把 names 写成中文训练能跑但推理时显示乱码建议全程英文。3. YOLOv11 环境配置与训练参数怎么设3.1 Ultralytics 环境配置的极简路径YOLOv11 通过 Ultralytics 包调用环境配置比早期 Darknet 时代简单太多。推荐用 conda 建独立环境Python 版本 3.9 到 3.11 都行我一般用 3.10。conda create -n yolo11 python3.10 -y conda activate yolo11 pip install ultralytics如果你有 NVIDIA 显卡先确认 CUDA 可用python -c import torch; print(torch.cuda.is_available())输出 True 才说明 GPU 能调用。如果 False检查显卡驱动和 PyTorch 版本匹配。Ultralytics 会自动安装对应版本的 torch但有时会装成 CPU 版需要手动重装。验证安装yolo checks这个命令会输出环境摘要包括 Ultralytics 版本、Python 版本、torch 版本、CUDA 状态。如果 CUDA 显示不可用训练会退到 CPU速度慢几十倍鲜花数据集虽然不大但 CPU 训练也够你等一整天。3.2 用命令行跑通第一轮训练Ultralytics 支持命令行和 Python API 两种方式。先给一个最小可跑的命令yolo detect train \ modelyolo11n.pt \ data./flower_dataset/data.yaml \ epochs100 \ imgsz640 \ batch16 \ device0 \ projectflower_runs \ nameexp1逐项说明modelyolo11n.pt 用的是 YOLOv11 nano 预训练权重适合快速验证data 指向你的 data.yamlepochs100 对鲜花这种中等难度任务通常够用imgsz640 是标准输入尺寸batch16 在 8GB 显存上比较稳device0 指定第一块 GPUproject 和 name 决定输出目录。训练开始后终端会打印每个 epoch 的 box_loss、cls_loss、dfl_loss 和 mAP。重点看 mAP50 和 mAP50-95 是否在上升如果 20 个 epoch 后 mAP50 还低于 0.3大概率是数据或类别配置有问题。3.3 用 Python API 做更细粒度的控制命令行适合快速跑但要做学习率调度、冻结层、自定义回调还是 Python API 更灵活from ultralytics import YOLO # 加载预训练权重 model YOLO(yolo11n.pt) # 开始训练 results model.train( data./flower_dataset/data.yaml, epochs150, imgsz640, batch16, device0, workers4, optimizerAdamW, # 鲜花细粒度任务用 AdamW 比 SGD 收敛更稳 lr00.001, # 初始学习率 lrf0.01, # 最终学习率因子 momentum0.937, weight_decay0.0005, warmup_epochs3.0, # 预热轮数防止早期梯度爆炸 cos_lrTrue, # 余弦退火 close_mosaic10, # 最后 10 轮关闭 mosaic提升定位精度 patience30, # 30 轮无提升则早停 projectflower_runs, nameexp_adamw )关键参数解释optimizer 选 AdamW 是因为鲜花类别间差异小SGD 容易在早期震荡lr00.001 比默认的 0.01 更保守适合小数据集close_mosaic10 是个实用技巧mosaic 增强在训练后期会干扰边界框回归关掉后 mAP 通常能涨 1 到 2 个点patience30 防止过拟合。3.4 鲜花检测的小目标优化参数鲜花在货架图里往往只占几十个像素属于小目标检测范畴。YOLOv11 本身对小目标做了改进但还需要调几个参数参数默认值鲜花场景建议作用imgsz640960 或 1280提高输入分辨率小目标特征更清晰box7.59.0增大框回归 loss 权重cls0.50.8增大分类 loss 权重细粒度分类需要iou0.70.6NMS 阈值降低减少重叠花朵漏检max_det300500一束花可能上百朵提高最大检测数这些参数在 train 里直接传model.train( data./flower_dataset/data.yaml, imgsz960, box9.0, cls0.8, iou0.6, max_det500, epochs150, batch8, # imgsz 提高后 batch 要降否则显存爆 device0 )imgsz 从 640 提到 960显存占用大约增加 2.2 倍batch 要从 16 降到 8 甚至 4。如果显存不够可以用 imgsz960 配合 batch4 加梯度累积但 Ultralytics 不直接支持梯度累积参数需要自己写训练循环。4. 训练过程排查与推理部署4.1 训练曲线怎么看loss 不降的四种可能训练启动后第一件事是看 runs 目录下的 results.png。正常情况 box_loss、cls_loss、dfl_loss 都应该是下降趋势mAP50 上升。如果 loss 不降按以下顺序排查第一种学习率太大。现象是 loss 剧烈震荡甚至变成 nan。解决是把 lr0 降到 0.0005 或更低或者加长 warmup_epochs。第二种数据标注有问题。现象是 cls_loss 居高不下但 box_loss 正常。解决是抽查 labels 目录下的 txt看类别索引是否越界、坐标是否在 0 到 1 之间。我遇到过有人把像素坐标直接写进去模型完全学不动。第三种类别不平衡。现象是某些类别的 mAP 接近 0。解决是统计每个类别的实例数对少样本类别做过采样或加 copy-paste 增强。第四种预训练权重不匹配。现象是训练初期 loss 就很高。解决是确认 yolo11n.pt 下载完整文件大小约 5MB 左右损坏的权重会导致特征提取层失效。4.2 推理与结果保存训练完成后用 best.pt 做推理from ultralytics import YOLO model YOLO(flower_runs/exp_adamw/weights/best.pt) # 单张图推理并保存 results model.predict( source./test_images/flower_shelf.jpg, conf0.25, # 置信度阈值 iou0.6, # NMS 阈值 imgsz960, saveTrue, # 保存带框结果图 save_txtTrue, # 保存检测结果为 txt projectflower_infer, nameresult1 ) # 打印每朵花的类别和坐标 for r in results: for box in r.boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) xyxy box.xyxy[0].tolist() print(f类别: {model.names[cls_id]}, 置信度: {conf:.2f}, 坐标: {xyxy})saveTrue 会把画框后的图存到 project/name 目录save_txtTrue 会生成每张图对应的检测结果 txt格式和训练标签一致。conf0.25 是常用起点鲜花场景如果漏检多就降到 0.15误检多就提到 0.4。批量推理视频或整个目录results model.predict( source./test_images/, conf0.25, imgsz960, saveTrue, streamTrue # 流式处理适合大量图片省内存 )streamTrue 返回生成器不会一次性把所有结果加载到内存处理几千张图时很有用。4.3 模型导出与部署选型YOLOv11 支持导出 ONNX、TensorRT、OpenVINO 等格式。如果部署到 NVIDIA 边缘设备TensorRT 最快yolo export modelflower_runs/exp_adamw/weights/best.pt formatengine halfTrue device0halfTrue 启用 FP16 量化速度提升约 1.5 到 2 倍精度损失通常小于 1 个点。如果部署到 CPU 或 Intel 核显用 OpenVINOyolo export modelflower_runs/exp_adamw/weights/best.pt formatopenvino halfTrue导出后的模型可以用 OpenVINO Runtime 加载在 Intel CPU 上推理速度比原生 PyTorch 快 2 到 3 倍。选型建议服务器端有 GPU 用 TensorRT边缘设备看芯片Jetson 系用 TensorRTx86 工控机用 OpenVINO纯 CPU 小规模用 ONNX Runtime 就够。5. 鲜花检测避坑指南5 个真实翻车记录5.1 类别名顺序不一致导致「指鹿为马」现象训练 mAP 正常推理时玫瑰被标成百合但置信度很高。原因转换脚本里的 CLASS_MAP 和 data.yaml 的 names 顺序不同。比如脚本里 rose0、lily1yaml 里写成了 lily 在前。解决把两处的类别列表复制到同一个文件里维护或者写个校验脚本训练前自动比对。5.2 imgsz 提高后显存溢出现象把 imgsz 从 640 改成 960训练启动几秒后报 CUDA out of memory。原因输入分辨率提高特征图尺寸平方级增长显存占用大幅上升。解决batch 从 16 降到 4 或 2或者用 imgsz800 折中。如果还爆开 AMP 混合精度ampTrue能省约 30% 显存。5.3 验证集 mAP 高但实际场景漏检严重现象val mAP50 到 0.9但拿真实花店照片测试一半的花没框出来。原因训练集和验证集同分布都是干净单朵图模型没学过遮挡和密集场景。解决重新划分数据确保验证集包含至少 20% 的复杂场景图。或者用 test 集做最终评估test 集专门放难样本。5.4 训练到一半 loss 突然变 nan现象前 50 轮正常第 51 轮 loss 变成 nan之后所有输出都是 nan。原因学习率在后期仍然偏高某个 batch 的梯度爆炸。或者数据里有损坏图片解码出异常值。解决加梯度裁剪Ultralytics 里没有直接参数可以在 Python API 里设 lr0 更低、cos_lrTrue。同时用脚本检查所有图片是否能正常打开损坏的删掉。5.5 推理结果保存的 txt 坐标对不上原图现象save_txtTrue 生成的坐标画到原图上位置偏移。原因YOLO 保存的 txt 是归一化坐标且基于 letterbox 后的图像尺寸不是原图尺寸。如果原图不是 640x640 或 960x960直接乘原图宽高会偏。解决用 model.predict 返回的 boxes.xyxy 是原图坐标直接用它画框。如果要自己解析 txt先做 letterbox 逆变换或者统一把推理图 resize 到 imgsz 再保存。6. 把 mAP 再提 3 个点的进阶技巧训练跑通之后真正拉开差距的是细节。分享一个我反复验证有效的技巧分阶段解冻训练。YOLOv11 默认全程训练所有层但鲜花数据集小backbone 的通用特征其实不需要大改。我的做法是前 20 轮冻结 backbone只训 head让分类头先适配鲜花类别20 轮后解冻全部用更低的学习率微调。from ultralytics import YOLO model YOLO(yolo11n.pt) # 第一阶段冻结 backbone model.train( data./flower_dataset/data.yaml, epochs20, imgsz960, batch8, freeze10, # 冻结前 10 层 lr00.001, projectflower_runs, namestage1_freeze ) # 第二阶段解冻全量微调 model YOLO(flower_runs/stage1_freeze/weights/best.pt) model.train( data./flower_dataset/data.yaml, epochs100, imgsz960, batch8, lr00.0003, # 更低学习率 cos_lrTrue, close_mosaic10, projectflower_runs, namestage2_finetune )freeze10 表示冻结前 10 层YOLOv11n 的 backbone 大约就是前 10 层。第一阶段学习率可以稍高因为只训 head第二阶段用 0.0003 微调避免破坏已学到的特征。这个两阶段方案在我自己的鲜花数据集上比直接训 150 轮 mAP50-95 高了约 3 个点。另一个技巧是测试时增强TTA。推理时对同一张图做翻转、缩放合并检测结果results model.predict( source./test_images/, augmentTrue, # 开启 TTA conf0.25, iou0.6, imgsz960 )augmentTrue 会做多尺度翻转推理mAP 通常能涨 1 到 2 个点代价是推理时间增加约 3 倍。如果做离线批量检测这个开销值得如果是实时视频流就别开。最后说一个我自己的习惯每次改完参数先跑 10 个 epoch 看 loss 趋势别一上来就 150 轮。10 轮里 mAP50 能到 0.4 以上说明配置基本对如果 10 轮还在 0.1 徘徊赶紧停下来查数据和参数省下的时间够你多试三组配置。鲜花检测这个方向数据质量的决定性远大于模型结构把标注做干净、场景覆盖全比换更大的模型管用得多。希望帮到你。本文还有配套的精品资源点击获取
返回列表