YOLOv5茶叶枯萎病检测:从环境搭建到模型部署实战
简介一份基于Python与Shell的茶叶枯萎病检测系统设计源码面向茶叶种植者、农业科研人员及AI开发者用于替代传统人工目测识别实现茶叶病害的自动化巡检与快速预警。项目包含51个文件压缩包约745KB核心为23个Python源码文件覆盖数据加载、模型训练、检测推理等流程16个YAML文件用于配置数据集路径与训练超参数另有3个Shell脚本简化权重下载和自动化操作配合Dockerfile可快速部署Jupyter Notebook则便于复现实验过程。资源内含YOLO系列模型配置、YOLO-TLB权重下载脚本、基于VisDrone、COCO等数据集的训练/测试入口以及Hubconf等扩展接口整体结构清晰适合作为目标检测项目二次开发或农业AI入门参考。目前已有272人学习浏览代码量适中、依赖明确能帮助读者快速搭建一套可运行的茶叶病害识别流程。1. 茶叶枯萎病检测一套能直接跑起来的 YOLO 工具链茶叶枯萎病这东西真到茶园里看绝大多数农户还是靠老师傅肉眼认叶子一人一天撑死看几百株等肉眼能看出来的程度损失往往已经扩散了。这套基于 Python 和 Shell 开发的茶叶枯萎病检测系统源码本质是把 YOLOv5 的检测能力搬到茶树叶片的图像识别上用一组训练好的 YOLO-TLB 权重配合 Shell 脚本做自动化下载与部署让一张叶片图片进去几秒就能给出枯萎区域的位置和置信度。对茶叶种植者、农业科研人员和做图像识别的开发者来说它解决的是「拿现成代码改成自己数据集就能用」的问题不用从零搭网络也不用手工配一堆依赖值得动手复现一遍。2. 源码拆解YOLO-TLB 与 Python 调用链2.1 先看仓库里到底有什么拿到压缩包解压之后第一件事别急着跑先花十分钟把目录结构捋一遍。这份源码包含 50 个文件20 个 Python 源文件、16 个 YAML 配置、5 个 Markdown 文档、3 个 Shell 脚本、2 个 TXT、1 个 LICENSE、1 个 Dockerfile 和 1 个 Jupyter Notebook。核心结构如下├── YOLO-TLB # 茶叶枯萎病检测权重/模型标识 ├── download_weights.sh # Shell 脚本自动拉取预训练权重 ├── data/ │ ├── coco128.yaml # 微型数据集配置用于验证 pipeline │ ├── coco.yaml # COCO 全量数据集配置 │ ├── voc.yaml # VOC 数据集配置 │ ├── VisDrone.yaml # 无人机视角数据集配置 │ ├── SKU-110K.yaml # 密集商品检测数据集配置 │ └── hyp.finetune.yaml # 微调阶段超参数配置 ├── hyp.scratch.yaml # 从零训练超参数配置 ├── models/ │ ├── yolov5s.yaml # 轻量模型结构定义 │ ├── yolov5m.yaml # 中等模型结构定义 │ ├── yolov5l.yaml │ ├── yolov5x.yaml │ ├── common.py # 基础模块C3、SPP、Focus 等 │ └── yolo.py # 检测头与前向逻辑 ├── utils/ │ ├── datasets.py # 数据加载与增强 │ ├── loss.py # 损失函数实现 │ ├── metrics.py # mAP、PR 曲线指标 │ ├── autoanchor.py # 自适应 anchor 计算 │ └── torch_utils.py # 训练工具与设备管理 ├── detect.py # 推理入口 ├── train.py # 训练入口 ├── test.py # 验证/测试入口 ├── requirements.txt # Python 依赖清单 ├── Dockerfile # 容器化部署配置 ├── flask_rest_api/ # 基于 Flask 的接口封装 └── tutorial.ipynb # 入门演示 Notebook这里每一类文件都有明确分工Python 文件负责数据加载、损失计算、模型前向和训练循环YAML 文件管的是三类配置——数据集路径、模型结构、训练超参数Shell 脚本解决的是权重文件自动下载这类重复性操作Dockerfile 则是给后续部署留的接口。对于想改造成自己数据集的人来说重点关注 data 目录下的 YAML 和 models 目录里的结构文件改这两个地方就能换检测目标。2.2 YOLO-TLB 是什么detect.py 怎么找到它YOLO-TLB 这个文件乍看有点突兀拆开理解就很直白TLB 是 Tea Leaf Blight茶叶枯萎病的缩写这份文件就是针对茶叶枯萎病训练好的权重。它的作用不是代码而是模型参数本身detect.py 执行时的--weights参数直接指向它。# 最常见的调用方式直接指到权重的相对路径 python detect.py --weights YOLO-TLB --source data/images/tea_leaf.jpgdetect.py 里读取--weights参数后会根据后缀判断是.pt还是.onnx然后加载对应模型结构。常见做法是把权重文件放在 weights 目录下统一管理而这份源码把 download_weights.sh 放在根目录方便一上来就把权重拉下来。YOLO 这类单阶段检测网络的核心思路是「一次前向同时输出目标框坐标、类别概率和置信度」相比两阶段的 Faster R-CNN速度优势明显在农业场景的实拍图上跑起来单张图片在 GPU 上通常几十毫秒出结果。这份源码里的 models/yolo.py 就是检测头的实现它把特征图上的每个网格点映射成预测框配合自适应的 anchor 尺寸由 utils/autoanchor.py 计算才能在小叶片、密集叶片这类场景下不丢目标。2.3 三种 YAML 的分工别搞混数据配置 YAMLcoco128.yaml、voc.yaml、超参数 YAMLhyp.scratch.yaml、hyp.finetune.yaml、模型结构 YAMLyolov5s.yaml是三种完全不同的东西刚上手的人最容易在这上面翻车。# 以 coco128.yaml 为例数据配置长这样 train: ../datasets/coco128/images/train2017 val: ../datasets/coco128/images/train2017 nc: 80 names: [person, bicycle, car, ...]nc是类别数names是类别名列表训练时--data参数指向这个文件。如果你要检测茶叶枯萎病就要新建一个tea.yaml把nc改成 1names改成[wilt]路径指向你自己的图片目录。超参数 YAML 则是 lr、momentum、weight_decay 这些训练策略参数和数据集无关换数据集可以不换超参数。模型结构 YAML 定义的是网络多深多宽yolov5s 最轻量yolov5x 最重但精度相对更高茶叶叶片这类不算特别难的目标s 或 m 级别就够用。3. 环境搭建与 Shell 权重下载三行命令让检测器开机即用3.1 Python 环境与依赖安装这份源码基于 Python 和 Shell环境配置绕不开 Python 依赖。用虚拟环境是避免依赖冲突最有效的做法见过太多人图省事直接往系统 Python 里装结果把环境搞坏后面跑什么都报错。我一般会按下面这套流程走# 创建 Python 3.8 的虚拟环境yolov5 对 3.83.10 兼容最好 python3 -m venv yolotlb_env source yolotlb_env/bin/activate # 先升级 pip避免装依赖时版本解析出问题 pip install --upgrade pip # 安装核心依赖 pip install -r requirements.txtrequirements.txt 里通常包含 torch、torchvision、opencv-python、numpy、matplotlib、PyYAML、scipy 这些。torch 和 torchvision 的版本要匹配不然 CUDA 环境下会报 operator 不存在之类的错误。CPU 机器也能跑推理只是速度会慢不少训练的话强烈建议用带 CUDA 的显卡nvidia-smi先看一眼驱动版本再决定装哪个版本的 PyTorch。Linux 上如果装的是 Ubuntu/Debian 系开头加sudo是常事Windows 上没有source这个命令虚拟环境激活要换成yolotlb_env\Scripts\activate。这段路径差异看起来小其实是新人最容易卡住的地方。3.2 download_weights.sh 脚本逐行解读download_weights.sh 是这份源码里 Shell 自动化能力的集中体现。它的作用是自动下载所需的预训练权重避免手动去网页上找下载链接。脚本核心逻辑一般是这样#!/bin/bash # 定义权重文件的下载基础路径和列表 BASE_URLhttps://github.com/ultralytics/yolov5/releases/download/v1.0 FILES(yolov5s.pt yolov5m.pt yolov5l.pt) # 遍历下载列表-c 支持断点续传 for f in ${FILES[]}; do echo Downloading $f ... wget -c $BASE_URL/$f -O weights/$f done这段脚本的关键点有两个wget -c里的-c参数表示断点续传网络不稳定时下载到一半断了重跑脚本会从断点继续不用从头再来-O指定下载后保存的路径统一放到 weights 目录下后面训练或推理时引用路径就清清楚楚。用 for 循环遍历文件列表是 Shell 脚本里最常见的批量处理模式以后要加新的权重文件只要往 FILES 数组里追加一个名字就行。执行时先给脚本加执行权限再运行chmod x download_weights.sh ./download_weights.shWindows 环境没有 wget 的话可以用 Git Bash 或者 WSL 来执行这个脚本。如果你的网络环境访问外网较慢可以把 BASE_URL 换成国内镜像地址这个操作不影响脚本逻辑。3.3 验证环境用自带的 tutorial.ipynb 跑通全流程环境装完别急着训练自己的数据先用仓库自带的 tutorial.ipynb 验证一遍流程是否通畅。这个 Notebook 里一般包含数据加载、模型初始化、单张图片推理几个环节跑通了说明你的环境没问题后面再折腾自己的数据才有意义。常见做法是在 Jupyter 里逐格执行# 启动 Jupyter浏览器打开对应地址 jupyter notebook如果 Notebook 里某一步报No module named torch说明前面 pip install 那步失败了回去看 pip 的报错信息通常是网络问题导致某个包没下全。验证通过之后环境才算真正立住了。4. 训练与推理参数把模型从 COCO 迁移到茶叶叶片4.1 准备自己的茶叶枯萎病数据集训练 YOLO 模型数据集格式是关键。YOLOv5 使用的是标准的目标检测标注格式每张图片对应一个同名.txt文件放在 labels 目录下每行内容为class x_center y_center width height坐标全部归一化到 01 之间。比如一张叶片图片里有一个枯萎区域标注文件里就是0 0.52 0.48 0.21 0.17这样一行。# 常见的目录结构组织方式 datasets/ ├── tea/ │ ├── images/ │ │ ├── train/ # 训练图片 │ │ │ └── leaf_001.jpg │ │ └── val/ # 验证图片 │ │ └── leaf_100.jpg │ └── labels/ │ ├── train/ # 标注文件与图片一一对应 │ │ └── leaf_001.txt │ └── val/ │ └── leaf_100.txt自己采集图片时手机拍的叶片照片就能用但要注意角度统一、光线均匀枯萎区域尽量拍清楚。标注工具常见做法是 labelImg 或 labelme画框时宁可框大一点也别把枯萎边缘截掉因为 YOLO 的 anchor 匹配机制对边界框的微小误差并不敏感但框太小会漏掉特征。标注完检查一遍类别 ID 一定要从 0 开始连续编号这个坑后面会详细说。4.2 train.py 训练命令与关键参数训练是整套流程里最重的一环。常见做法是用 COCO 预训练权重做迁移学习而不是从随机初始化开始训这样可以大幅缩短收敛时间小数据量下精度也明显更高。train.py 的运行方式如下python train.py \ --data data/tea.yaml \ --weights YOLO-TLB \ --cfg models/yolov5s.yaml \ --epochs 200 \ --batch-size 16 \ --img-size 640 \ --device 0 \ --name tea_wilt这里逐个参数说明参数作用建议--data数据集配置文件路径指向自定义的 tea.yaml--weights初始权重优先用 YOLO-TLB 或 coco 预训练权重--cfg模型结构配置数据量小用 yolov5s精度优先用 yolov5m/l--epochs训练轮数小型数据集 200 轮起步看 loss 收敛情况--batch-size批大小由显存决定OOM 时往小调--img-size输入图片尺寸640 是精度和速度的平衡点--device计算设备0 表示第一块 GPUCPU 训练写cpu--name实验名称每次实验换名字方便对比结果训练过程要重点关注两个东西loss曲线和验证集mAP。loss 下降得越平滑越好如果 loss 震荡很大通常是学习率设置有问题去hyp.finetune.yaml里把lr0从默认值调小一个数量级试试。mAP 在 50 轮之后还上不去优先怀疑数据标注有错误而不是模型结构问题。4.3 detect.py 推理与超参数调优训练完的模型用来做实际检测用 detect.py。推理时的参数选择和训练时不一样更关注置信度阈值和 NMS 阈值这两个python detect.py \ --weights runs/train/tea_wilt/weights/best.pt \ --source data/images/ \ --img 640 \ --conf-thres 0.25 \ --iou-thres 0.45 \ --save-txt--conf-thres是置信度阈值低于这个值的检测结果会被过滤掉。茶叶枯萎病场景里宁可多框出几个疑似区域让农户去看也别漏检所以 0.25 比默认的 0.25 更低一点的 0.20.25 更实用。--iou-thres是 NMS 的 IoU 阈值控制重叠框的合并力度叶片密集时适当调高到 0.5避免相邻枯萎区域被合并成一个框。超参数调整有一个基本顺序先看置信度阈值再看 NMS 阈值最后才动模型结构。上来就换大模型往往只是把问题从漏检变成误检整体收益不大。在茶叶叶片这种背景相对干净的场景yolov5s 0.25/0.45 的组合在很多情况下已经够用。超参数这里没有绝对最优hyp.finetune.yaml里的box、cls、obj三项损失权重也是同理。box控制框回归的惩罚力度cls控制分类错误obj控制目标置信度。枯萎区域如果偏小可以稍微加大box权重到 0.06 左右让模型更关注框的精确位置。每改一个参数就跑一组实验用 test.py 输出的 mAP 做对比别凭感觉下结论。5. 避坑与排查训练不掉点、推理不出框的五个真实记录5.1 训练 loss 不下降卡在初始值附近现象train.py 跑起来前几十轮 loss 几乎不动偶尔还往上跳。原因最常碰到的情况是--weights没有指定预训练权重模型从随机初始化开始训收敛极慢。其次是学习率设置太高Adam 优化器下lr00.01对迁移学习来说偏激进。解决先确认加载的是 YOLO-TLB 或 COCO 预训练权重而不是空权重再把hyp.finetune.yaml里的lr0从 0.01 调到 0.001momentum保持 0.937weight_decay保持 0.0005。改完重新跑一般 20 轮内 loss 就会有明显下降。5.2 推理一张图结果框一个都没有现象detect.py 跑通了图片也正常输出但检测结果全空。原因置信度阈值设得过高是最常见的原因。茶叶枯萎区域的表观特征有时并不明显模型给的置信度普遍偏低--conf-thres 0.5会把所有结果都过滤掉。还有可能是类别 ID 对不上训练时nc1但推理时类别索引写错了。解决先把--conf-thres降到 0.1 跑一次看看有没有框出来。如果有再逐步往上调到合理的 0.25如果没有去检查 tea.yaml 里的nc和names是否和训练时一致。强制建议每次推理都先看一眼输出图片上画出来的框再做批量处理。5.3 训练时显存爆掉报 CUDA out of memory现象train.py 跑了几步就中断报CUDA out of memory。原因batch-size 和 img-size 两者叠加导致显存超了。很多人上来就--batch-size 32 --img-size 6408GB 显存的卡根本扛不住。解决先看显存大小nvidia-smi确认可用显存。8GB 的卡跑 yolov5sbatch-size 16 img-size 640 是一个稳妥的组合还爆就把 batch-size 降到 8 或 4。别只降 batch-size 不降 img-size输入尺寸对显存的影响是平方级的640→512能省接近 40% 显存。如果数据量少还可以开梯度累积把 batch-size 调小但保持等效批次大小不变。5.4 Shell 脚本在 Windows 上报错bad interpreter现象download_weights.sh 在 Windows 上用 Git Bash 执行报bad interpreter或\r 一类的错。原因Windows 下编辑保存的脚本默认是 CRLF 换行Linux 系的 Shell 解释器只认 LF回车符被当成了脚本内容的一部分。解决用下面的命令把换行转回来转换完再执行就正常sed -i s/\r$// download_weights.sh这个教训同样适用于所有从 Windows 传到 Linux 的脚本文件。从那以后我每次在 Windows 上改完 Shell 脚本都要先跑一遍这个 sed 转换才继续已经形成条件反射了。5.5 换了数据集之后检测效果反而更差现象在 COCO 上预训练的模型换到自己几百张茶叶图片上微调之后mAP 反而比直接用原模型推理还低。原因这是典型的过拟合问题。数据集只有几百张微调轮数又跑了 200 轮以上模型把训练集的特征背下来了但对新图片完全不泛化。另一个原因是类别差异太大——茶叶枯萎病和 COCO 里的 person、car 这类目标的特征完全不同微调时基础特征也需要大量重学。解决控制微调轮数150 轮以内重点看验证集 mAP一旦验证集 loss 开始回升而训练集还在降立即停止。数据增强是关键datasets.py 里的 mosaic 增强默认开着就别关再叠加随机旋转、亮度扰动、缩放剪切相当于把几百张图扩成几千张。如果数据实在太少先冻结骨干网络只训练检测头等验证集 mAP 有起色了再解冻全模型联合微调。6. 从命令行到服务化用 Docker 与 Flask 把模型封装成检测接口命令行工具能自己用但要给茶园现场的人用还是得封装成一个 HTTP 接口。仓库里自带的 flask_rest_api 目录和 Dockerfile 就是干这个的。6.1 Docker 构建环境一致性一步到位FROM python:3.8-slim WORKDIR /app COPY requirements.txt . RUN pip install -r requirements.txt COPY . . CMD [python, app.py]构建和启动都简单docker build -t yolo-tlb-api . docker run -p 5000:5000 yolo-tlb-api用容器部署的价值在于训练机器上能跑的代码换一台机器同样能跑不会出现「本地好好的服务器上一堆报错」的尴尬。6.2 Flask 封装把 detect.py 变成 POST 接口from flask import Flask, request, jsonify import base64 import cv2 import numpy as np from models.experimental import attempt_load from utils.general import non_max_suppression app Flask(__name__) # 加载模型只做一次 model attempt_load(YOLO-TLB, map_locationcpu) app.route(/detect, methods[POST]) def detect(): data request.json[image_base64] img base64.b64decode(data.split(,)[1]) img cv2.imdecode(np.frombuffer(img, np.uint8), cv2.IMREAD_COLOR) results model(img, size640) det non_max_suppression(results[0], conf_thres0.25, iou_thres0.45) return jsonify({boxes: det[0].tolist()}) if __name__ __main__: app.run(host0.0.0.0, port5000)调用方只需要把图片转成 base64 字符串 POST 过来接口返回检测框坐标和置信度。这样前端无论做 Web 页面还是小程序都能直接对接。从那以后每次做检测类项目我都会先把模型的推理封装成这样一个接口再考虑页面上怎么展示等到真正联调的时候省掉了大量来回传图的麻烦。希望这份源码的拆解思路能帮你在茶叶病害检测或类似的目标检测项目上少走几步弯路。本文还有配套的精品资源点击获取