ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

YOLOv5花卉识别实战:从源码结构到YAML配置与训练调参

2026/10/4 3:22:09 拓冰建站 浏览量
YOLOv5花卉识别实战:从源码结构到YAML配置与训练调参 简介基于Python与Shell语言实现的YOLOv5花卉识别模型设计源码面向深度学习初学者、目标检测爱好者及需要快速落地花卉智能识别场景的开发者。资源聚焦YOLOv5在花卉图像上的训练与推理覆盖从数据准备、参数配置、模型训练到结果展示的完整流程。压缩包共102个文件包含40个YAML配置文件用于定义数据集路径、模型结构与训练超参数32个Python源文件承担数据加载、模型构建、训练验证和推理检测等核心任务11个YAML模板助力快速生成自定义配置5个Shell脚本可自动化批量处理、环境部署等重复操作。另附容器化部署配置、Jupyter教学笔记本及演示图片与文档方便搭建运行环境并理解技术细节。资源包整体仅1.19MB轻量完整已吸引371人学习浏览很适合希望通过真实代码学习YOLOv5改进与花卉识别应用的读者。1. 拿到花卉识别源码包别急着跑通就删很多人拿到一份 YOLOv5 源码包第一反应是跑一遍 demo、看到检测框就算“掌握了”然后整个目录躺在硬盘里吃灰。这份基于 Python 与 Shell 的花卉识别模型源码101 个文件真正的价值不在那 29 个 Python 文件里而是藏在 40 个 YAML 配置和 5 个 Shell 脚本中——它们把“训练参数、数据集声明、模型结构、启动流程”全拆成了可改的文本配置。它解决的不是“怎么装 YOLOv5”而是“拿到别人能跑的模型怎么改造成自己的花卉数据集还能稳定收敛”。适合刚准备把 YOLOv5 用到自定义识别场景的工程师也适合想搞懂配置参数含义、不想反复翻车的新手。2. 101 个文件拆解YAML 配置体系才是 YOLOv5 的骨架YOLOv5 和传统深度学习项目一个很明显的区别大量逻辑不是写在 Python 里而是写成 YAML 文本。模型结构、数据集路径、超参数、anchors 预设全部用键值对表达。这种设计的直接好处是——改结构不用动代码调参不用翻源码。对二次开发的人来说读懂了 YAML就等于读懂了这份源码的骨架。2.1 文件组成五个角色各管一段先把这 101 个文件按职责分成几类对照着看更容易理解谁在干什么文件类型数量典型职责YAML 配置文件40数据集声明、超参数、模型结构、anchors 预设Python 源文件29训练、验证、推理、数据集加载、工具函数YAML 模板文件11给用户复制修改的“母版”配置Shell 脚本5环境准备、数据划分、启动训练、清理缓存Markdown 文档4README、使用说明、训练教程JPG / TXT22测试图片、标签样例、日志输出Docker / Git 配置4构建镜像、版本控制规则那个tutorial.ipynb是 Jupyter 入门向导bus.jpg、zidane.jpg是官方库里沿用下来的验证图片用来快速看模型推理效果。setup.cfg是包配置声明项目元数据和打包规则本地运行一般不会直接动它。2.2 三种 YAML数据声明、超参数、模型结构40 个 YAML 配置文件看着多实际上只有三种角色。第一种是数据配置声明训练集、验证集的图片路径和类别数量。典型内容长这样train: ./datasets/flower/train/images val: ./datasets/flower/val/images nc: 5 names: [rose, sunflower, tulip, daisy, dandelion]nc是类别总数names是类别名称列表顺序必须和标注文件里的类别索引一一对应。这个文件是训练启动时最先被读取的路径只要错一级目录train.py立刻报错。第二种是超参数配置控制学习率、动量、数据增强强度等。YOLOv5 默认的hyp.scratch.yaml里几个关键字段lr0: 0.01 # 初始学习率 lrf: 0.2 # 最终学习率衰减系数 momentum: 0.937 # SGD 动量 weight_decay: 0.0005 warmup_epochs: 3.0 # 预热轮数 mosaic: 1.0 # mosaic 增强概率 hsv_h: 0.015 # HSV 色相增强范围lr0和lrf决定学习率从 0.01 一路衰减到 0.002训练后期步长变小收敛更稳。mosaic设为 1.0 表示每张图都参与四图拼接增强对小目标检测非常有用但如果数据集本身就是高清大图花卉可以降到 0.5 减少训练开销。第三种是模型结构配置例如yolov5s.yaml。它不写具体代码只描述网络每层怎么堆depth_multiple: 0.33 width_multiple: 0.50 anchors: - [10, 13, 16, 30, 33, 23] - [30, 61, 62, 45, 59, 119] - [116, 90, 156, 198, 373, 326] backbone: - [-1, 1, Focus, [64, 3]] - [-1, 1, Conv, [128, 3, 2]] head: - [-1, 1, Detect, [nc, anchors]]depth_multiple和width_multiple是缩放系数0.33 和 0.50 对应的是轻量版 s 模型。这两个值改成 0.67 和 0.75 就接近 m 模型但显存占用和训练时间会明显上升。anchors是预设锚框尺寸自定义数据集类别形状差异大时建议删掉让 YOLOv5 自动重算这个在第 4 章会展开讲。2.3 setup.cfg 与 Git 配置容易被忽略的工程化细节setup.cfg定义了项目打包和代码规范校验的规则属于 Python 工程的标准配置。.gitignore里会忽略runs/、*.pt、__pycache__/这些训练产物避免把动辄几百 MB 的权重文件提交进仓库。.gitattributes则用来自动化处理换行符和文件合并策略Windows 和 Linux 协作开发时能少很多莫名其妙的冲突。.dockerignore配合根目录的Dockerfile使用构建镜像时排除数据集和权重保持容器体积干净。这些文件不属于核心算法但对协作开发是刚需。拿到源码包后第一件事建议就是检查.gitignore是否把.pt权重和runs/输出目录排除掉否则训练一次就多出几个 G 的变动文件Git 仓库很快会膨胀到没法用。3. 数据集与标注格式先把 txt 标签和类别索引对上YOLOv5 的数据组织方式说简单也简单图片和标签放在两个平行的目录里同名文件一一对应。但就是这个“简单格式”坑了最多的人。3.1 数据布局images 和 labels 为什么必须同名单目录标准目录结构长这样datasets/flower/ ├── train/ │ ├── images/ │ │ ├── rose_001.jpg │ │ └── sunflower_002.jpg │ └── labels/ │ ├── rose_001.txt │ └── sunflower_002.txt └── val/ ├── images/ └── labels/train.py在加载数据时会遍历images目录下的每张图然后去对应的labels目录找同名.txt文件。如果标签文件不存在这张图会被当作背景样本跳过如果标签文件存在但图片缺失加载阶段直接报错。常见的翻车现场是label 文件后缀写成了.txt但实际是labelimg导出的 XML或者 labels 目录名多了一个空格YOLOv5 找不到对应用户文件时又不给明确提示只在日志里打印一行 “WARNING: ignoring corrupt image”。建议拿到数据集后先写一个校验脚本检查每张图是否都有对应的标签文件。import os from pathlib import Path img_dir Path(datasets/flower/train/images) label_dir Path(datasets/flower/train/labels) missing [] for img_path in img_dir.glob(*.jpg): label_path label_dir / (img_path.stem .txt) if not label_path.exists(): missing.append(img_path.name) print(f共检查 {len(list(img_dir.glob(*.jpg)))} 张图片缺失标签 {len(missing)} 个) if missing: for name in missing[:5]: print(name)这段代码的核心作用是把“训练到一半才报错”提前到“训练前报错”。img_path.stem拿到不带后缀的文件名再拼上.txt去 labels 目录探测存在性一目了然。3.2 YOLO 标注 txt五个数字的含义每个.txt标注文件里可能有多行每行代表一个目标格式是五个数字2 0.531250 0.468750 0.208333 0.240000 0 0.312500 0.364583 0.145833 0.320000 1 0.703125 0.489583 0.166667 0.260000依次含义是类别索引、归一化后的中心点 x、中心点 y、归一化后的宽 w、归一化后的高 h。注意两点第一坐标全部归一化到 01不是像素值第二w和h是相对整张图的宽高比例不是绝对尺寸。类别索引从 0 开始计数和.yaml里names列表的下标一一对应。比如上面第一行的2对应配置里names: [rose, sunflower, tulip, ...]的tulip。这里要特别提醒LabelImg 或 X-AnyLabeling 导出的 YOLO 格式坐标本身是归一化过的但不同标注工具的“类别起始值”不一定一致。有的工具界面显示类别序号从 1 开始保存时自动减 1有的工具直接按 0 存。换标注工具后一定要抽几张图人工核对这个坑几乎每个人都踩过。3.3 用 Shell 脚本切分数据for 循环加随机抽样项目里的 5 个 Shell 脚本最常用的就是数据集划分脚本。它遍历所有图片文件按比例随机抽出一部分作为验证集其余作为训练集并生成对应的目录和标签映射。#!/bin/bash # 数据集划分脚本按 8:2 比例切分训练集和验证集 src_dir./datasets/flower/all/images dst_train./datasets/flower/train dst_val./datasets/flower/val mkdir -p $dst_train/images $dst_train/labels mkdir -p $dst_val/images $dst_val/labels count0 for img in $src_dir/*.jpg; do name$(basename $img .jpg) count$((count 1)) if (( count % 5 0 )); then cp $img $dst_val/images/ cp ./datasets/flower/all/labels/$name.txt $dst_val/labels/ else cp $img $dst_train/images/ cp ./datasets/flower/all/labels/$name.txt $dst_train/labels/ fi done echo 划分完成共处理 $count 张图片逻辑很简单每 5 张取 1 张进验证集其余进训练集正好 8:2。basename $img .jpg去掉路径和后缀只留文件名再拼上.txt路径去复制标签文件。count % 5 0这个条件也可以改成按需比例比如十分之一就改成% 10 0。需要注意的是这里的抽样是顺序抽样不是随机抽样。如果原始图片本身就是按类别排列的验证集可能只包含某几类花训练集缺了另外几类。严谨的做法是用shuf先把文件列表打乱再遍历find $src_dir -name *.jpg | shuf /tmp/all_images.txt把随机种子交给shuf避免切分结果出现类别分布不均。真实项目里类别不平衡的问题往往就是从这种小细节开始的。4. 训练前后必踩的五个坑现象、原因、解法这一章是拿真金白银换来的经验。下面五条每一条都能让训练过程从“看起来很顺利”变成“损失爆炸或直接崩溃”。4.1 类别索引与 nc 不一致导致训练直接崩现象train.py启动后没跑几步就报错提示IndexError: index 5 is out of bounds for axis 0 with size 5或者损失值直接变成nan。原因标签文件里出现了大于等于nc的类别编号。比如 YAML 里声明了nc: 5但某个 TXT 标签里写了5超出有效范围04。常见场景是从别的项目直接复制了数据集原项目类别多复制过来只改了 YAML 忘了过滤标签。解决写一段清洗脚本遍历所有标签文件把超出范围的类别索引全部标记出来人工确认后要么删除该目标要么合并类别。import os from pathlib import Path label_dir Path(datasets/flower/train/labels) nc 5 # 与 YAML 中的 nc 保持一致 bad_files [] for label_path in label_dir.glob(*.txt): lines label_path.read_text().strip().splitlines() for line in lines: cls_id int(line.split()[0]) if cls_id nc: bad_files.append(label_path) break print(f发现 {len(bad_files)} 个标签文件存在越界类别索引)line.split()[0]取每行第一个字段转成int后跟nc比较。这类问题越早暴露成本越低等训练跑了两小时才发现损失不降回头看标签数据心态会崩。4.2 中文路径导致图像读取失败现象训练日志里频繁出现WARNING: skipping corrupt image被跳过的图片数量不少模型指标怎么调都上不去。原因YOLOv5 底层用 OpenCV 读图cv2.imread()对路径中的中文字符支持很差返回None后数据加载器只能把这张图当作损坏样本跳过。解决所有路径强制使用英文包括用户名目录、数据集目录、项目目录三层。如果数据集已经在中文路径下最简单的方式是整体复制到英文路径或者用软链接接入mkdir -p /opt/projects ln -s /home/用户/下载/花卉识别数据集 /opt/projects/flower软链接让原始目录不动训练代码访问的路径保持纯英文。这一条看起来基础但对国内开发者属于高频踩坑点。4.3 CUDA 显存不足与 batch-size 的博弈现象训练刚起步就报CUDA out of memory或者跑完前几个 epoch 后在评估阶段显存溢出。原因默认batch-size是按 16 或 32 设计的但显卡显存只有 8G 或 6G。花卉图片普遍分辨率偏高img 640输入加上多尺度训练显存压力比想象中大。解决先不急着换显卡按顺序调整三个参数python train.py --data flower.yaml --cfg yolov5s.yaml \ --batch-size 8 --img 640 --cache ram--batch-size 8直接减半显存占用基本跟着减半。--cache ram把图片缓存到内存而不是显存能明显降低显存峰值。如果还想压把--img 416输入尺寸降下来花卉这种大目标识别任务 416 分辨率通常够用。三个参数组合下来6G 显存也能跑得动 s 模型。4.4 AutoAnchor 计算耗时过长或锚框不收敛现象每次启动训练Analyzing anchors...阶段卡很长时间或者跑完报kmeans_iteration警告、锚框质量评分低。原因YOLOv5 默认用 COCO 数据集的锚框预设。自定义花卉数据集的检测目标形状分布和 COCO 差异较大比如向日葵是大而扁的圆盘玫瑰是紧凑的花苞锚框与目标形状不匹配会导致收敛慢、mAP 上不去。解决直接删掉 YAML 文件里的anchors字段注释掉让 YOLOv5 在训练前用 k-means 在自定义数据集上重新聚类。聚类过程需要几分钟到十几分钟属于正常耗时。如果希望跳过自动计算、直接用上一轮跑出来的最优锚框看训练日志里AutoAnchor: 3.11 anchors/target, 0.951 Best Possible Recall (BPR)这行BPR大于 0.9 就用它把输出的锚框值复制回 YAML 里固化下来以后每次训练就不重复计算了。4.5 训练到一半被打断重新跑还是用断点续训现象训练到第 40 个 epoch机器断电或显卡驱动崩了。重新运行同样的命令从头开始训练之前十几个小时的算力白费。原因train.py默认每次启动都是全新训练权重文件虽然存在runs/目录但不会自动接续。解决用--resume参数配合上次训练保存的权重文件python train.py --data flower.yaml --cfg yolov5s.yaml \ --resume runs/exp3/weights/last.ptlast.pt里除了模型权重还保存了 epoch、优化器状态、学习率调度器的当前值恢复后可以无缝接续。日常习惯是至少每 10 个 epoch 手动备份一次best.pt防止last.pt随训练进程崩溃而损坏。5. 从 Shell 脚本到训练命令完整跑一次训练与推理介绍完配置和坑这一章串联完整执行链路。项目里的 5 个 Shell 脚本常见的分工是环境检查、数据集准备、训练启动、结果打包、缓存清理。不同作者拆法略有差别但核心作用类似——把需要记住的一长串命令固化成可重复执行的脚本。5.1 五个 Shell 脚本各司其职典型的 Shell 脚本命名和逻辑如下# run_env_check.sh —— 检查 python、pip、显卡驱动是否就绪 #!/bin/bash python3 --version || echo Python3 not found nvidia-smi || echo CUDA not available pip show torch /dev/null 21 || pip install torch --index-url https://download.pytorch.org/whl/cu118||逻辑很有用前半段命令失败才执行后半段保证脚本可重复运行且失败时有明确提示。/dev/null 21把 torch 的检查输出先丢掉只在缺失时才走安装分支。# run_train.sh —— 封装训练命令固定参数避免每次手输出错 #!/bin/bash python train.py --data flower.yaml --cfg yolov5s.yaml \ --weights --batch-size 16 --epochs 100 --img 640 train.log 21注意--weights 的空字符串这个写法用于显式声明“从头训练”不加载预训练权重。 train.log 21把训练日志重定向到文件同时保留了终端输出的实时日志方便排查崩溃原因。5.2 train.py 参数逐项拆解核心训练命令参数拆开看python train.py \ --data flower.yaml \ # 数据集配置含 train/val 路径和类别名 --cfg yolov5s.yaml \ # 模型结构配置depth/width 缩放系数 --weights yolov5s.pt \ # 预训练权重用 COCO 训练好的做迁移学习 --batch-size 16 \ # 每次迭代喂给 GPU 的图片数 --epochs 100 \ # 完整遍历训练集 100 次 --img 640 \ # 输入图片分辨率训练时随机缩放 --cache ram \ # 图片缓存到内存减少磁盘 IO --device 0 \ # 指定 GPU 编号多卡用 0,1,2--weights yolov5s.pt和--weights 是完全不同的训练策略。加载 COCO 预训练权重做迁移学习收敛速度快很多尤其适合花卉这类目标特征和 COCO 中的植物有一定重叠的数据集。--cache ram对机械硬盘用户是刚需否则每次 epoch 都重新读一遍几百 G 的图片时间成本高到无法忍受。训练过程要盯三个指标box_loss、cls_loss、obj_loss是否整体下降mAP0.5是否在后期稳定上升。如果cls_loss持续下降但mAP0.5停滞通常是某个类别样本量太少模型把这一类的目标当背景忽略了。5.3 detect.py 推理与后处理边界训练完成后用最佳权重做推理python detect.py \ --weights runs/exp3/weights/best.pt \ --source ./test_images/ \ --conf-thres 0.25 \ --iou-thres 0.45 \ --img 640conf-thres是置信度阈值低于 0.25 的检测框被过滤iou-thres是 NMS 的 IoU 阈值重叠框保留得分高的那个。推理阶段 YOLOv5 的输出是一个三维张量形状类似[batch, anchor_num, 5 num_classes]detect.py内部先按conf-thres过滤低置信度框再做 NMS 去除重复框最后把归一化坐标换算回像素坐标画框。新手常在这里翻车把conf-thres调到 0.01 试图“看到更多检测框”结果一张图上几百个重叠框全是噪音。花卉识别这种大目标场景conf-thres保持 0.25 以上最高可以调到 0.4 都不会漏检。6. 让结果更好看超参数微调、AutoAnchor 与一组验证习惯模型跑通只是起点mAP 才是交付标准。超参数调整是最直接的手段但前提是知道每次改动的边界。lr0是最值得先调的参数。默认 0.01 对大多数数据集适用但如果训练日志里前 10 个 epoch 损失波动剧烈通常是把lr0降到 0.005反过来如果损失下降慢得肉眼可见可以提到 0.02 试试。mosaic对花卉这种大目标场景建议降一点花卉不像小目标密集场景需要拼接增强mosaic: 0.5能减少训练时间还保持精度。hsv_h、hsv_s这两个色彩增强参数对花卉很有用花朵颜色是天然的分类特征把色相增强范围从 0.015 提高到 0.02能让模型对光照、品种色差更鲁棒。AutoAnchor 利用 k-means 聚类重新生成锚框需要跑一次才会写入日志。复制最优锚框值回 YAML 后可以固定住减少后续每次训练的前置计算。从训练到交付我自己养成了一个固定习惯换任何新数据集第一轮先用 20 个 epoch 跑一个小实验不看 mAP只看results.png里的三行 loss 曲线——box_loss 是否稳定下行、cls_loss 有没有周期性回升、obj_loss 是否出现 nan。这三条线不干净后面调什么超参数都是白费。确认 loss 正常后再上全量 epochs 和完整超参做正式训练。这套流程跑过几十次之后几乎不会再遇到“损失爆炸”这种半夜惊醒的问题。希望这些经验帮你在花卉识别这个场景上少走几步弯路。本文还有配套的精品资源点击获取