ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

番茄叶片病害目标检测实战:基于YOLO与PyTorch的深度学习方案

番茄叶片病害目标检测实战:基于YOLO与PyTorch的深度学习方案 简介面向Python深度学习初学者的番茄叶片病害目标检测完整项目基于YOLO与PyTorch实现涵盖数据集制作、模型训练与PyQt可视化识别全流程。压缩包共1470个文件、约40.55MB包含730张jpg叶片图像、363个txt标签、358个xml标注文件、3个YOLO配置文件、3个Python脚本及3个已训练模型pt权重其中数据划分脚本可自动将原始标注转为YOLO格式并生成训练/验证集训练脚本输出results.csv、验证集预测图与TensorBoard事件文件便于直观评估模型效果。已有110人学习下载适合需要快速搭建植株病害识别实验、熟悉YOLO训练流程或开展毕业设计/课程项目的读者。通过运行代码既能了解数据标注格式转换与训练参数调优方法也能直接使用PyQt界面加载图片完成病害类别检测是一份从理论到部署的综合性参考样例。1. 番茄叶片病害目标检测别急着解压跑模型先搞清楚这个方案在解决什么拿到“基于python深度学习对番茄叶片病害目标检测-含数据集和代码.zip”这个压缩包我劝你别急着解压敲训练命令。农业视觉项目里决定模型能不能用的往往不是深度学习算法本身而是数据集里那些框得歪歪扭扭的标注。这个方案本身很直白输入番茄叶片照片用 python 做目标检测框出早疫病、晚疫病、细菌性斑点等病害的位置和类别输出带预测框和置信度的结果图。它对应的是农业巡检里的真实痛点人工逐叶翻看效率低病害特征又非常相似肉眼很容易把早疫病和晚疫病看混。适合谁的场景本科或研究生阶段做农业AI课题的学生想给温室或大棚配一个低成本病害筛查工具的工程师以及刚接触深度学习、恰好拿到一份带数据集和代码的初学者。在动手训练之前先想清楚模型选型、数据格式、训练参数、问题排错、结果验证这五步后面才能少走弯路。2. 选型决定省力程度目标检测模型、框架与标注工具怎么配很多人拿到包含数据集和代码的项目包第一反应是“用什么模型更牛”。真实经验恰恰相反选型阶段省下来的力气最后都会在数据清洗阶段加倍还回来。番茄叶片病害检测有两个明显特征一是目标在整张图里占比小叶片边缘还有卷曲、阴影和露水反光二是病害类别之间的视觉差异极小早疫病和晚疫病都呈现为叶片上的同心环纹连人都容易看错。这种场景下模型选型要优先考虑标注成本低、迭代速度快、单卡能训练而不是单纯追求 mAP 刷高多少。2.1 YOLO 为什么是番茄叶片的默认答案和 Faster R-CNN、SSD 放在一起看先给结论这类项目我一般会把 YOLO 系列作为默认选项只有特殊需求才回头用两阶段检测器。原因是病害检测对“框得准”的要求远低于“找得到、分得对”而 YOLO 把定位和分类放进同一个网络里一次推理完成训练只需要一份标注框不用为候选区域生成额外写采样逻辑。Faster R-CNN 在极端小目标上有理论精度优势但训练时要跑 RPN显存占用和单 epoch 耗时明显更高SSD 处于两者之间工程生态这些年几乎不再更新遇到问题连可抄的教程都少。算法定位与分类方式单卡可训性工程生态适合场景Faster R-CNN两阶段先提候选框再分类一般显存和耗时高成熟但配置繁琐对精度极致敏感、机器资源充足SSD单阶段多尺度预测较好更新停滞已有旧代码要维护YOLO 系列单阶段anchor-free 演进好显存可控活跃教程和预训练权重最全病害检测这类快速迭代项目选 YOLO 而不是更花哨的模型还有个务实原因预训练权重。COCO 上训出来的 YOLO 权重对叶片纹理、茎秆背景已经有不错的底层特征提取能力迁移到番茄病害上只需微调高层几百张图也能训出能看的初版。相比之下从零训练一个商业级模型同样数据量往往连收敛方向都找不到。这项“借用预训练权重”的能力也是标题里“深度学习”三个字价值最大的地方。不过这里有个边界要认清如果你最终要做的不只是框出病害还要统计病斑面积占比那就得换成 YOLO-seg 这类实例分割模型检测框给不了像素级面积。2.2 框架、标注工具、硬件搭配给纯小白的选型清单框架上我默认 PyTorch。不否认 TensorFlow 在工业部署里也有一席之地但 YOLO 系工程几乎全部以 PyTorch 实现网上能被搜到的“超详细配置教程”大多也是这条路线。PyTorch 的调试手感也更适合入门print 一个张量的 shape 立刻就知道数据流到哪一步出了错断点打在 loss.backward() 前后能直接看到梯度是否消失这份直觉对第一次做目标检测的人非常重要。标注工具方面常见做法是先用 LabelImg 这类轻量工具把最初的 200 张图标完再换 X-AnyLabeling 这类带自动辅助标注的工具做增量扩充。工具选型不用纠结能导出 YOLO 格式 txt 就行。关键在导出后必须看一遍标注文件类别 ID 有没有和类别名错位、框的坐标是不是负数、叶片重叠区域有没有漏标。如果数据集是多批次采集的还要注意批次间的光照和色温差异最好在训练前做一次全局的亮度归一化否则模型会把“偏暗环境”当成一个隐性类别。硬件上一张 6GB 显存的显卡就够完成训练没有 GPU 就用 CPU 先把流程跑通只是速度会慢几十倍。真到调参阶段再租卡也不迟。配置环境时如果遇到 Windows 报缺 msvcp140.dll别急着重装系统装一下 VC 运行库就能解决具体在 4.1 小节细说。2.3 拿到的压缩包先别训解压自检三步第一步看目录结构。常见做法是数据集解压后出现两个顶层目录images 放图片labels 放同名 txt 标签各自里面再分 train 和 val。如果压缩包里的图片按病害类别分文件夹说明它还是分类数据集格式得先转成检测格式第三章会给转换脚本。第二步看标签文件的数值。YOLO 格式的每一行是“类别ID 中心点x 中心点y 框宽 框高”坐标全部归一化到 0~1。用文本编辑器随便开一个 txt如果看到 x_center 大于 1.5、宽度是 0、或者行里的数字超过 6 列这份数据基本不能直接进训练。第三步检查标签和图片是否能对上。统计每个类别有多少目标顺便看图片尺寸是否统一。快速命令# 统计训练集图片数量 find dataset/images/train -name *.jpg | wc -l # 抽查前 20 个标签文件里各有多少个标注框 for f in dataset/labels/train/*.txt; do echo $(basename $f): $(wc -l $f); done | head -20 # 按标签文件的第一列聚类统计每个类别目标总数 cat dataset/labels/train/*.txt | awk {print $1} | sort | uniq -c第一行命令看图片总量第二行抽查标签框数量第三行直接用 awk 按第一列聚类得到每个病害类别在训练集里的目标总数。如果某个类别只有个位数目标要尽早决定是扩充数据还是调 loss 权重等到训练结束才发现类别不平衡前面几十个 epoch 等于白跑。另外建议用 file 命令抽查几张图片的实际格式防止扩展名是 jpg 内容却是 png 的混入情况这类文件在统一缩放的训练流程里会造成偶发的解码报错。3. 把数据集喂给训练脚本目录重组、格式转换与可视化自查数据准备这个环节最花时间也最容易被跳过。我见过太多人拿到数据集后直接开训第一次跑通后才发现标注框画错了方位回头改数据等于把整个训练流程重做一遍。与其赌运气不如先花半小时做三件事把目录按 YOLO 规范重组、把非 YOLO 格式的标注转成统一 txt、把标注可视化逐张看一遍。这三步做完模型训练才算有了一个可信的输入。3.1 目录重组与 train/val 划分一个能直接跑的 Python 脚本如果压缩包里的图片和标注文件在同一目录、共用同一文件名前缀还要按 8:2 划分训练集和验证集。下面这份脚本可以直接放到数据集根目录运行它会把图片和标签同步复制到 YOLO 要求的布局里。# split_dataset.py import os import shutil import random random.seed(42) # 固定随机种子保证多次运行划分一致 src_images raw_data/images # 原始图片目录 src_labels raw_data/labels # 原始标签目录 out_images dataset/images # 输出图片目录 out_labels dataset/labels # 输出标签目录 for sub in [train, val]: os.makedirs(f{out_images}/{sub}, exist_okTrue) os.makedirs(f{out_labels}/{sub}, exist_okTrue) imgs [f for f in os.listdir(src_images) if f.endswith((.jpg, .jpeg, .png))] imgs.sort() random.shuffle(imgs) val_count max(1, int(len(imgs) * 0.2)) val_imgs set(imgs[:val_count]) for img in imgs: sub val if img in val_imgs else train stem os.path.splitext(img)[0] src_txt os.path.join(src_labels, stem .txt) if not os.path.exists(src_txt): continue # 图片没有对应标签时跳过避免把脏数据带进训练 shutil.copy(os.path.join(src_images, img), os.path.join(out_images, sub, img)) shutil.copy(src_txt, os.path.join(out_labels, sub, stem .txt))逻辑说明脚本先按扩展名筛出图片通过 sort 和 random.seed 保证划分可复现再按 20% 比例取前 n 张作验证集最后把图片和同名 txt 一起复制过去。这里最重要的一点是“同步”图片和标签文件共用文件名前缀只要不同步训练时会报“找不到标签”或者把两张图的标签错配到一张图上。参数说明src_labels 没有对应 txt 时直接跳过避免把未标注图片带进训练想改成 9:1把 0.2 改成 0.1 即可shutil.copy 是复制而不是移动原目录文件还在跑错了可以删掉 dataset 重来这算一个低成本后悔药。3.2 把 VOC/COCO 标注转成 YOLO 格式转换脚本与四个边界坑很多公开数据集给的是 VOC 的 xml 或 COCO 的 json 标注YOLO 训练读不了这两种格式必须先转换。VOC 格式里每个目标对应一个 bndbox 节点里面是 xmin、ymin、xmax、ymax 四个像素坐标YOLO 要的是相对图片宽高的中心点和宽高比例。核心换算只有几行但真正的坑全在换算之外。# voc2yolo.py import os import xml.etree.ElementTree as ET class_map {healthy: 0, early_blight: 1, late_blight: 2, bacterial_spot: 3} def convert_one(xml_path, img_w, img_h, out_txt): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_map: continue # 类别名不在映射表里直接跳过 box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) # 越界裁剪坐标小于 0 按 0大于宽高按宽高 x1 max(0, x1); y1 max(0, y1) x2 min(img_w, x2); y2 min(img_h, y2) if x2 x1 or y2 y1: continue # 裁剪后框为空说明原始标注有问题 x_center (x1 x2) / 2 / img_w y_center (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h lines.append(f{class_map[name]} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_txt, w, encodingutf-8) as f: f.write(\n.join(lines)) # 使用时传入图片实际宽高不要用 xml 里的假设值 convert_one(annotations/tomato_001.xml, 1280, 960, labels/tomato_001.txt)逻辑说明代码遍历每个 object 节点从 bndbox 拿四角像素坐标裁剪到图片边界内再归一化。裁剪很重要人工标注经常把框画出图片边缘不裁会让后续数据增强在越界坐标上产生空 box。类别 ID 由 class_map 映射不在表里的名称直接跳过便于反向排查数据里有没有未知病害类别。参数说明输出精度保留 6 位小数够 YOLO 使用如果手里是 COCO 的 json 格式需要换 pycocotools 读取换算公式一样。四个边界坑提前说清楚一是 xml 里的图片尺寸可能是 0 或错误值转换前先查实际尺寸二是坐标越界要裁剪而不是直接丢弃丢弃会丢目标三是不同数据集里 bndbox 字段名可能写错写成 xmin、ymax 之外的名字会直接 KeyError四是一张图可能包含多个同名 object代码里的 for 循环天然支持多目标别只取第一个。3.3 标注可视化自查把 txt 画到图上60 秒内发现问题格式正确不等于标注正确。最有效的自查方法就是把标签框画回原图逐张翻看。下面这段代码读一张图和同名 txt用 OpenCV 画出目标框和类别 ID输出到检查目录跑一遍就能看出坐标是否错位、框是否框住了整片叶、类别是否标错。# check_annotations.py import os import cv2 img_dir dataset/images/train label_dir dataset/labels/train out_dir check_output os.makedirs(out_dir, exist_okTrue) for img_name in os.listdir(img_dir): stem os.path.splitext(img_name)[0] label_path os.path.join(label_dir, stem .txt) if not os.path.exists(label_path): continue img cv2.imread(os.path.join(img_dir, img_name)) img_h, img_w img.shape[:2] with open(label_path, r, encodingutf-8) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue # 行格式不对直接跳过 cls_id, xc, yc, w, h parts cls_id int(cls_id); xc float(xc); yc float(yc) w float(w); h float(h) x1 int((xc - w / 2) * img_w) y1 int((yc - h / 2) * img_h) x2 int((xc w / 2) * img_w) y2 int((yc h / 2) * img_h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(img, str(cls_id), (x1, max(0, y1 - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imwrite(os.path.join(out_dir, img_name), img)逻辑说明脚本按文件名前缀找对应标签把归一化坐标还原成像素坐标后用 cv2.rectangle 画框cv2.putText 在框上方写类别 ID处理完保存到 check_output。如果发现大量框偏到叶片外侧通常是标签归一化公式错了如果框位置基本正确但类别 ID 对不上病害说明 class_map 映射写歪了。参数说明建议把检查图片放到统一目录里用看图工具快速翻页。一次性检查几百张图时可以把图片先缩到 640 宽度再保存减少翻页体量。这一步不产生任何模型收益但能省掉后面无数次调试时瞎猜的时间是整条流程里性价比最高的一步。4. 训练落地用 PyTorch 把训练跑顺记住这组参数数据准备好了接下来是把训练脚本跑起来。这里最大的风险不是模型不懂番茄叶片而是环境装不好、参数设置不合理、训练中断后不知道怎么续上。建议严格按“环境 → 配置 → 监控”三步走每一步只做最小必要的事不要一上来就去调花里胡哨的训练技巧。4.1 环境准备conda 虚拟环境与依赖安装为了不让系统里已有的 Python 包污染项目我一般先建独立的 conda 环境。下面这段命令在终端里按顺序执行。conda create -n tomato python3.10 -y conda activate tomato pip install torch torchvision pip install ultralytics逻辑说明第一行创建名为 tomato 的 Python 3.10 虚拟环境第二行激活第三行安装 PyTorch 和配套 torchvision第四行安装 ultralytics——这个库封装了 YOLO 系列的训练、验证、导出接口。torch 和 torchvision 需要配套版本直接 pip 安装通常会自动匹配但要确认 torch 能用 GPU方法是在 Python 里执行 import torch; print(torch.cuda.is_available())输出 True 才说明 CUDA 可用。参数说明Python 3.10 是这几年 PyTorch 兼容性最稳的版本之一纯小白照抄即可如果机器是纯 CPU不装 CUDA 版 torch 也能跑只是慢很多。Windows 上最容易翻车的点有两个一个是缺 VC 运行库报错文字里出现 msvcp140.dll装一下运行库就好另一个是显卡驱动太旧torch 报“CUDA driver version is insufficient”去显卡厂商官网更新驱动即可不用自己乱改 torch 版本。装完后建议跑一下 yolo --version 确认命令行可用很多环境问题在这一步就能暴露。4.2 数据集配置与训练命令参数表里哪些是安全区哪些是玄学ultralytics 的训练接口要求先用一个 yaml 文件描述数据路径和类别信息。文件名随意结构固定。假设只做四类健康叶片、早疫病、晚疫病、细菌性斑点内容如下。# tomato.yaml path: dataset train: images/train val: images/val nc: 4 names: 0: healthy 1: early_blight 2: late_blight 3: bacterial_spot逻辑说明path 是数据集根目录train 和 val 是相对路径nc 是类别总数names 给每个类别 ID 一个名字。训练脚本读这个文件就知道去哪里找图片、验证集用哪份数据、输出多少个类别。最容易翻车的配置是 path 写成绝对路径换机器后路径失效相对路径则要求执行训练命令时的工作目录在数据集上层我会在命令前用 cd 进入项目根目录来规避。训练命令如下cd tomato_project yolo detect train modelyolov8n.pt datatomato.yaml \ epochs80 imgsz640 batch8 device0 workers4 \ lr00.01 patience15逻辑说明modelyolov8n.pt 表示加载官方预训练权重做迁移学习n 是 nano 版本显存占用小、适合入门datatomato.yaml 指向刚才的配置epochs80 是完整遍历训练集 80 次imgsz640 让图片缩放成 640x640 再进网络batch8 是每次送入 GPU 的图片数量patience15 表示验证指标连续 15 个 epoch 不提升就提前停止防过拟合还能省时间。参数我的默认值影响说明modelyolov8n.pt模型容量与速度显存小用 n数据多再换 s 或 mepochs80训练轮数几百张图时 80 够用imgsz640输入分辨率分辨率越高越吃显存小目标多再调 960batch8单轮显存占用6GB 显存安全区是 8溢出就减半lr00.01初始学习率迁移学习时 0.01 是保守安全值patience15早停耐心值验证指标不升就停防无效等待参数说明imgsz 和 batch 的乘积直接决定显存占用6GB 显存跑 6408 是比较稳的搭配如果数据里叶片只占很小一块可以试 imgsz960但 batch 要降一半。lr0 是最容易踩的玄学参数调大了 loss 早期爆炸调小了 40 轮还在原地晃迁移学习场景下 0.01 基本不会出错。显存溢出时优先把 batch 减半而不是换更小的模型因为 batch 减半不影响模型表达能力只是梯度估计噪声变大。4.3 训练过程怎么监控从 loss 数值到 best.pt 的完整闭环训练开始后终端会打印每个 epoch 的进度条和一堆指标要有取舍地看。第一优先看 box_loss 和 cls_loss前者是定位损失后者是分类损失两者都应随 epoch 数增加而下降下降速度变缓是正常现象。第二看 val 行的 mAP50这是最能说明模型真实水平的数字不要只看最终值要关注它在训练中期的爬升趋势。训练结束时runs/detect/train 目录下会出现两个权重文件best.pt 是验证指标最好的权重last.pt 是最后一轮权重。默认用 best.pt不要只拿 last.pt 做推理因为训练后期可能出现轻微过拟合best.pt 才是泛化能力最强的快照。中断恢复也有后悔药训练中途崩了在命令最后加 resumeTrue脚本会从 last.pt 断点继续不用从头再来。如果 mAP50 到某个 epoch 后突然掉一截别急着加正则化先回第三章把可视化自查再做一遍看是不是训练集里混进了贴错标签的图。数据层面干净了指标才会恢复正常。另外值得记的一个经验是batch 小的时候 loss 曲线更抖这是正常的不用过度紧张真正要警惕的是 loss 徘徊在高位完全不降那种情况多半是标签坐标越界回 3.2 小节的转换脚本检查边界裁剪逻辑。5. 番茄叶片病害检测的典型翻车现场排查与避坑训练和推理跑通之后真正的疑难杂症才开始浮出来。下面五条是从实际项目里反复遇到、且在新手身上出现频率最高的问题按现象、原因、解决的顺序写每一条都尽量给一个能直接抄的判断路径方便你在训练失败时按图索骥。5.1 显存溢出不只是换显卡就能解决现象训练跑到十几个 epoch 后进程突然报 CUDA error: out of memory前面十几个 epoch 的进度全部作废。原因最典型根源是 batch 和 imgsz 的乘积超过显存上限尤其是带数据增强的 YOLO 训练显存峰值往往出现在增强后的大图堆叠阶段而不是推理阶段。有时候 6GB 显存跑 batch8 能启动、却在某 epoch 中途溢出是因为增强操作随机生成了比平时更大的输入图瞬时峰值比平均值高出一截。解决先把 batch 减半到 4同时把 imgsz 降到 512大多数 6GB 卡能稳定跑完如果还溢出再看 workers 是否太大workers4 会让数据加载线程同时准备多批数据显存和内存都被推高。改完参数重新训练因为 best.pt 还没生成没有断点可以利用。这条经验的关键是显存溢出不是换显卡的信号先把参数调回安全区再说。5.2 标注框口径不统一模型学的到底是叶片还是病斑现象训练完的模型在真实照片上表现尚可但预测框总是只框住病斑区域而不是整片叶或者反过来该框病斑却框了整片叶子。原因这是标注阶段埋下的锅。同一批数据里一部分人标整片叶另一部分人只标病斑模型在矛盾中学会了“最小化损失”的折中方案输出框忽大忽小。整片叶占图面积大、病斑占图面积小两者混合会让置信度分布非常奇怪。解决没有捷径只能回标注环节统一口径。建议定成“目标是叶片类别是病害”如果真正关心病斑面积占比就定成“目标是病斑类别是病害类型”。定好之后把不符合的标注批量改成统一规则再跑一次 3.3 小节的可视化自查确认每个框都符合新口径再重新训练。这个问题越早发现代价越小训练完才发现等于前几十个 epoch 全部作废。5.3 类别严重不平衡整体指标还行细看某个类别几乎不检现象训练完看验证结果mAP50 有 0.7但按类别拆开统计晚疫病这一类精确率和召回率双双接近 0模型把所有相似目标都判成了早疫病。原因数据集中晚疫病样本只有早疫病的十分之一。目标检测的损失函数在加权求和时样本多的类别贡献的梯度更大模型很容易倾向把所有相似纹理都判成大类。病害之间的视觉相似性会放大这个问题早疫病和晚疫病的同心环差几层纹理细节样本不足时模型根本学不到区分特征。解决优先做数据扩充找更多晚疫病照片或做旋转、亮度、雨露等增广把数量拉到一个相对均衡的水平确实找不到素材再调整损失权重比如给 cls loss 按类别占比反比加权或者换 focal loss 让模型更关注难分的少数类。我的经验是调 loss 权重只能把指标从几乎为零拉回“勉强能用”真正有效的还是数据量本身。5.4 loss 不降先查标签再调学习率现象训练到第 30 轮box_loss 和 cls_loss 都停在一个较高水平不再下降验证集 mAP50 也在低位震荡调 epochs 也没用。原因排在前列的三类原因分别是标签坐标越界或归一化错误、学习率过高导致 loss 反复震荡、模型容量不足。最常见的是第一种因为转换脚本如果没做边界裁剪x_center 和 w 会偶尔出现大于 1 或小于 0 的数值模型看到的标签和实际目标框对不上自然学不下去。解决不要先动模型先执行第三章的可视化自查脚本逐张看标注框是否贴合叶片。框全部正常再检查 lr0把 0.01 降到 0.002 重跑数据量大且模型是 yolov8n可以换 yolov8s 提高容量。这三步按顺序排查能覆盖九成“loss 不降”的现场。很多人一上来就换高级损失函数或加注意力模块但在这类项目里数据问题占比远高于模型能力问题先把数据钉死再谈模型。5.5 推理阶段误检满天飞把 conf 阈值调高只是治标现象模型在训练集上的指标很好看但把训练时没见过的真实照片喂进去预测结果里到处是框连土壤、茎秆甚至背景纹理都被标注成病害。原因训练正样本里几乎全是“叶片居中、背景干净”的照片模型没见过不带叶子的负样本于是在推理阶段对一切有纹理的区域都打了高分。这是数据分布和真实场景不匹配造成的问题不是单纯过拟合。解决治本的手段是往训练集里加入背景图片作为负样本再配合 mosaic 和 mixup 增强让模型学会忽略无关区域。治标的手段是把推理时的 conf 参数调高例如从默认的 0.25 提到 0.5误检数量会明显下降但会牺牲一部分真目标召回。建议一起做先用 conf0.5 把眼前误检压下去同时补一批带背景的负样本重新训练双管齐下才算真正解决。提示这五条经验的共同点是现象在训练或推理中暴露根源却都在数据或参数上。遇到问题按“数据 → 参数 → 模型”的顺序排查不要一上来就换网络结构。6. 把模型从“能跑”变成“能用”验证指标与落地前的最后一步训练完成不代表项目结束模型要在没见过的真实照片上证明自己。验证阶段最有参考价值的数字是 mAP50 和混淆矩阵比单独看训练 loss 诚实得多。yolo detect val modelruns/detect/train/best.pt datatomato.yaml这条命令会在验证集上跑一遍最优权重打印 box_loss、mAP50、mAP50-95 等指标同时生成混淆矩阵图。混淆矩阵的阅读方法是看对角线对角线数值越高说明每个类别分得越清楚如果早疫病和晚疫病之间出现大片非对角区域说明这两个类别在特征空间里确实太接近优先回 5.3 小节补数据。推理阶段的验证要换一批照片最好用手机在真实温室拍几张分别覆盖单叶片、多叶片、背景杂乱、光线不均四种情况。下面这段代码可以快速做批量预测并保存结果。from ultralytics import YOLO model YOLO(runs/detect/train/best.pt) results model.predict( sourcereal_photos/, conf0.45, saveTrue, imgsz640, projectpredict_output )逻辑说明model 加载训练好的 best.ptsource 指向真实照片目录conf0.45 比默认值略高以过滤误检saveTrue 保存画好框的结果图project 指定输出目录。参数说明如果真实场景里叶片占整图比例很小imgsz 可调到 960 再试一次代价是推理变慢但小目标检出率通常会提高。这里有一个我从第一次做叶片检测就记住的习惯永远同时保存两份验证输出一份按默认参数一份按高 conf对比着看模型的边界在哪里。如果两份输出差异极大说明模型对置信度非常敏感部署时要仔细标定阈值。这套流程走完这个基于 python 深度学习的番茄叶片病害检测项目才真正从“代码能跑”变成了“检测能信”。我早年第一次做完类似项目时花在换模型上的时间远超花在查数据上的时间结果每个模型的指标都类似地差。后来养成先做数据自查、再看混淆矩阵、最后用真实照片兜底的顺序返工次数骤降。希望这个顺序也能帮你在番茄叶片病害检测上少走几步弯路。本文还有配套的精品资源点击获取
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表