恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
YOLO训练番茄叶病害7类数据集:从数据检查到调参避坑全指引
首页
资讯中心
/
YOLO训练番茄叶病害7类数据集:从数据检查到调参避坑全指引
YOLO训练番茄叶病害7类数据集:从数据检查到调参避坑全指引
发布时间:2026/9/28 17:12:50
简介面向番茄叶部病害的智能识别与目标检测场景该YOLO数据集收录约700张实拍叶片图像覆盖细菌性斑点、黑点、早期枯萎病等7个常见类别图像兼顾不同光照、角度与生长期能够为农业视觉模型提供较丰富的训练样本。其中每张jpg图片均配套txt格式的YOLO标注文件类别信息记录于classes.txt中可直接用于YOLOv5、YOLOv8等主流模型训练与验证。整个资源共1477个文件包含737张jpg原图、738个txt标签文件另附1个Python可视化脚本和1个类别展示png压缩包仅22.18MB轻量便于下载与分发。可视化脚本无需任何修改即可运行随机读取一张图像即可绘制真实边界框并保存到当前目录方便快速检查标注质量。数据目录按用途划分清晰训练集与验证集划分已初步完成省去自行整理数据的繁琐步骤。目前已有266人学习使用适合正在开展番茄病害检测、需要现成YOLO数据集快速入手的开发者或研究人员。1. 番茄叶病害 7 类 YOLO 数据集为什么拿到手先别训练目标检测跑番茄叶病害很多人把精力放在换模型上实际翻车点全在数据集。标题里的“YOLO 数据集番茄叶病害识别检测7类”看起来是给你一堆图片和标签但真正决定训练能否一次跑通的是三样东西划分好的训练/验证目录、类别 class 文件、数据可视化脚本。前两样保证 YOLO 能读进去第三样保证你能看出标签对不对、样本平不平衡。这篇笔记就按“检查数据 → 跑最小训练 → 调参数 → 避坑”的顺序讲清楚一套可复现的落地路径。适合第一次用 YOLO 做农业检测的新手也适合被乱标签折腾过的熟手。2. 划分好的 YOLO 数据集长什么样目录结构、class 文件与最小训练命令2.1 目录结构images 与 labels 必须一一对应train/val 各自成对我拿到一份划分好的番茄叶病害数据集第一步不是看图片而是看目录。YOLO 系列v5/v8 以及 Ultralytics 现在的训练入口都遵守同一套约定图片放在 images 下标签放在 labels 下标签文件是 .txt文件名和图片一致train/val 子目录两边都要有。一个标准结构是这样tomato_yolo/ ├── images/ │ ├── train/ │ │ ├── 001_leaf.jpg │ │ ├── 002_leaf.jpg │ │ └── ... │ └── val/ │ ├── 301_leaf.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── 001_leaf.txt │ │ ├── 002_leaf.txt │ │ └── ... │ └── val/ │ ├── 301_leaf.txt │ └── ... └── data.yaml注意 labels/train 目录下必须有和 images/train 同名的 txt一个都不能少。我见过有人从网盘解压后只上传了 images 的 train/val漏掉 labels 里的 val训练时 loss 照常下降最后在验证集上全部为 0因为验证时没有任何 ground truth 可对比。每张图对应的 txt 内容是这个格式0 0.512 0.465 0.231 0.187 2 0.700 0.350 0.150 0.200五个数字依次是class id、归一化中心点 x、归一化中心点 y、归一化宽、归一化高。全部都是 0~1 之间的小数不是像素坐标。这个格式决定后面可视化脚本怎么换算。如果你是从 LabelImg 或 Roboflow 导出的数据可能还会看到没有归一化的版本那就要在预处理阶段统一转成这个格式。如果拿到手的数据不是这个结构常见做法是自己写个脚本整理。你只需要保证一个原则图片能找到同名 txttxt 里 class id 是整数、坐标是归一化小数。整理完用可视化脚本抽查一遍比什么检查都靠谱——这一章的第三节我给了脚本。2.2 class 文件不是摆设data.yaml 里的 names 顺序决定标签 id“class 文件”在不同工具里叫法不一样。LabelImg 导出的是 classes.txtDarknet 用的是 obj.namesYOLOv5/v8 训练时用的是 data.yaml。标题里说的 class 文件落到 YOLOv8 训练里就是 data.yaml它把图片路径和 7 个类别名称绑在一起。path: /home/user/tomato_yolo # 数据集根目录绝对路径最稳 train: images/train # 相对 path 的训练图片目录 val: images/val # 相对 path 的验证图片目录 nc: 7 # 类别数量必须和 names 长度一致 names: 0: bacterial_spot # 细菌性斑点病 1: early_blight # 早疫病 2: late_blight # 晚疫病 3: leaf_mold # 叶霉病 4: septoria_leaf_spot # 斑枯病 5: target_spot # 靶斑病 6: yellow_leaf_curl # 黄化曲叶病毒这里的顺序不能乱。txt 标签里的 0 永远对应 names 里的第 0 项1 对应第 1 项。很多数据集作者习惯按自己的排列顺序导出 class 文件而你训练时用了另一个顺序结果就是模型收敛了但 mAP 始终是零。我第一次做 7 类番茄叶病害时就在这上面白跑了一天。如果你拿到的是 classes.txt 而不是 data.yaml说明作者用的是 LabelImg 或 Roboflow 导出的旧格式。你要做的不是硬套而是读一遍 classes.txt 里的顺序原样写进 data.yaml 的 names。这个动作叫“对 class id”比改标签快得多。7 类的具体命名以你拿到的 class 文件为准上面这段只是按农业检测里比较常见的组合写的示例。另外注意 path 字段。我一般写绝对路径因为相对路径在不同机器上跑容易失效。如果只在当前目录操作也可以省略 path直接写 train: images/train。团队协作时更常见的做法是各写各的 pathdata.yaml 只作为模板提交到仓库避免把本机路径带去别人机器上。2.3 用最小命令跑通第一次训练不调参先验证加载链路环境准备好之后第一次训练我不会调任何参数只求把数据链路跑通。用 Ultralytics YOLOv8 的命令行就是这么一条pip install ultralytics opencv-python matplotlib yolo detect train datatomato_yolo/data.yaml modelyolov8n.pt epochs50 imgsz640 batch16 device0如果本机有 NVIDIA GPUdevice0 用显卡没有就把 device0 改成 devicecpu。第一次跑的时候yolov8n.pt 这个预训练权重会自动下载网络慢的话会卡在下载那一步。常见做法是先手动把权重文件下载到当前项目目录再重新跑同样的命令这样 Ultralytics 会在本地找到yolov8n.pt不再走网络下载。这条命令就是“yolov8 训练自己的数据集”的标准入口。别急着改 mosaic、hsv 这些增强参数先把结果跑出来。看到终端出现类似Task: detect, Mode: train和每 10 个 epoch 一次的训练指标表说明数据被正确读进去了。跑完后验证一下yolo detect predict modelruns/detect/train/weights/best.pt sourcetomato_yolo/images/val yolo detect val modelruns/detect/train/weights/best.pt datatomato_yolo/data.yaml这里predict是看一眼预测框是否基本贴住病斑val会输出 mAP50、mAP50-95用来判断数据集划分和标签质量。如果 mAP50 能从 0.5 左右往上走再进入参数调优如果一直是 0多半是前面说的标签 id 或路径问题不是模型问题。3. 数据可视化脚本把标签画回原图、统计类别分布、一键体检3.1 用 OpenCV 把 YOLO 标签画回原图坐标换算是关键没有可视化脚本你根本不知道手里数据是好是坏。我拿到数据集后的第一个动作是随机抽 train 里 20 张图把标签画上去。脚本不复杂但坐标换算必须做对。import cv2 def draw_yolo_labels(image_path, label_path, class_names): img cv2.imread(image_path) if img is None: print(图片读取失败:, image_path) return None h, w img.shape[:2] with open(label_path, encodingutf-8) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue cid int(parts[0]) cx, cy, bw, bh map(float, parts[1:5]) # YOLO 存的是归一化中心坐标要换算回像素坐标 x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) color (0, 0, 255) # BGR 红色 cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) label class_names[cid] if cid len(class_names) else str(cid) cv2.putText(img, label, (x1, max(0, y1 - 8)), cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2) return img if __name__ __main__: names [bacterial_spot, early_blight, late_blight, leaf_mold, septoria_leaf_spot, target_spot, yellow_leaf_curl] result draw_yolo_labels(tomato_yolo/images/train/001_leaf.jpg, tomato_yolo/labels/train/001_leaf.txt, names) cv2.imwrite(check_001.jpg, result)脚本逻辑没什么玄学就是拿归一化坐标乘回宽高。cx - bw/2是框左上角的 xcy - bh/2是左上角的 y。画框用cv2.rectangle框上方用cv2.putText写类别名。跑完之后重点看三类问题一是框是不是比真实病斑大一圈或小一圈那是标注或解析问题二是整张图内容旋转了 90 度那是 EXIF 旋转问题三是多个框重叠在同一个位置那可能是重复标注。这三类问题在训练阶段都会让模型学到错误特征越早发现越省事。如果你想批量画出 20 张图在脚本外套一层glob.glob循环就行。3.2 用直方图看 7 类样本分布不平衡会让 mAP 虚高或虚低标签画回原图只能看单张质量样本量分布要看统计数据。番茄叶病害数据集最常见的问题是某一类病叶特别多另一类只有几百个框。直接用 Python 数一下每个类有多少个框import glob from collections import Counter def count_boxes(label_dir, num_classes7): counts Counter() total_boxes 0 for txt_path in glob.glob(f{label_dir}/*.txt): with open(txt_path, encodingutf-8) as f: for line in f: parts line.strip().split() if len(parts) 5: cid int(parts[0]) if 0 cid num_classes: counts[cid] 1 total_boxes 1 return counts, total_boxes counts, total count_boxes(tomato_yolo/labels/train) for cid in range(7): ratio counts[cid] / total if total else 0 print(fclass {cid}: {counts[cid]} 框, 占比 {ratio:.1%})输出类似class 0 有 1240 框class 6 只有 86 框。这就是不平衡信号。YOLO 默认的损失函数对多数类更友好少数类会被压住。我不建议一上来就改损失函数先从数据层面解决比如把少数类用水平翻转做离线增强或者去补充收集。数据可视化脚本在这一步的价值就是让你把“看似平衡”的错觉打掉。如果还想看得更直观用 matplotlib 画个柱状图import matplotlib.pyplot as plt labels [fclass{i} for i in range(7)] plt.bar(labels, [counts[i] for i in range(7)], colorskyblue) plt.title(Tomato leaf disease box distribution) plt.ylabel(box count) plt.tight_layout() plt.savefig(class_distribution.png, dpi150)这个图存下来后面调增强参数、改数据划分时都用得到。训练完对比混淆矩阵和这个分布图你就能解释为什么某一类病害总是识别不好——大概率是它本身样本就少而不是模型不行。3.3 一键体检同名文件、空标签和坐标越界一起查除了画框和统计分布可视化脚本还有一个隐藏功能体检。训练数据里最容易藏雷的三种情况是图片缺同名标签、标签是空文件、坐标越界。写成一个小脚本一次查完import os def inspect_dataset(image_dir, label_dir): img_names {f.rsplit(., 1)[0] for f in os.listdir(image_dir) if f.endswith((.jpg, .jpeg, .png))} lbl_names {f.rsplit(., 1)[0] for f in os.listdir(label_dir) if f.endswith(.txt)} print(缺标签的图片数:, len(img_names - lbl_names)) print(缺图片的标签数:, len(lbl_names - img_names)) bad [] for f in os.listdir(label_dir): path os.path.join(label_dir, f) with open(path, encodingutf-8) as fh: for line in fh: parts line.strip().split() if len(parts) ! 5: bad.append((f, 列数不对, line)) continue cid int(parts[0]) vals list(map(float, parts[1:])) if not 0 cid 7: bad.append((f, class id 越界, line)) if any(v 0 or v 1 for v in vals): bad.append((f, 坐标越界, line)) print(异常标签行数:, len(bad)) for item in bad[:10]: print(item) inspect_dataset(tomato_yolo/images/train, tomato_yolo/labels/train)这里的逻辑很直白先用集合差算出缺同名文件的数量再逐行检查 txt 的列数、class id 和坐标范围。这个 7 是类别数如果你手里的 class 文件不是 7 类记得改成实际的 nc。跑完看到“异常标签行数: 0”再开始训练能省掉很多无意义的排错时间。4. 训练参数怎么设imgsz、batch、增强与预训练权重的取舍4.1 imgsz 和 batch先定分辨率再量显存番茄叶病害检测里病斑往往很小早疫病的病斑可能只占整张图的 1%。这种场景下 imgsz640 是性价比选择但不是精度选择。想要把小黑点、黄化初期的细微纹理抓住常见做法是把 imgsz 提到 1280。imgsz 每翻一倍单张图的像素数翻四倍显存占用和控制差不多是平方关系。yolo detect train imgsz1280 batch8跑不动就降到 imgsz640 batch16。一个简单的经验是先跑 imgsz640 batch8如果能跑完一个 epoch再把 batch 翻倍试显存不够时优先降 batch别一开始就降 imgsz因为分辨率对病斑检测的影响比 batch 更直接。batch 参数还影响 BNBatch Normalization统计。batch 太小时比如 batch2 或 4BN 的均值和方差抖动很大训练不稳定。如果只有小显存卡要么选更小的 yolov8n要么开cacheTrue减少显存与硬盘之间的等待要么用devicecpu老老实实跑小模型。不要指望提高 batch 能解决一切它只决定梯度估计的噪声水平对数据质量问题是无效的。4.2 数据增强参数植物叶片场景要动四个地方Ultralytics YOLO 默认的增强参数适合自然图像但番茄叶病害有自己的脾气。默认mosaic1.0会把四张图拼在一起训练这对小目标是双刃剑一方面增加上下文多样性另一方面病斑在拼接边界处容易被切碎、缩小模型学到的是“半截斑”。我一般把 mosaic 调到 0.5 以下并在最后 10 个 epoch 让它自动关闭。具体修改方式可以建一个 hyp 配置也可以直接在命令行传yolo detect train datatomato_yolo/data.yaml modelyolov8n.pt \ epochs80 imgsz640 batch16 \ mosaic0.5 hsv_h0.015 hsv_s0.7 hsv_v0.4 fliplr0.5 flipud0.0这几个参数的含义hsv_h/hsv_s/hsv_v控制色调、饱和度、亮度的随机扰动。番茄叶在不同光照下颜色差异很大给一点 HSV 扰动能让模型不依赖“叶子必须很绿”这个特征。但 hsv_h 别给太大0.015 就好太大会把病斑的黄色、褐色也给改了模型反而学不到真实病色。fliplr0.5是左右翻转叶片左右对称安全。flipud0.0是上下翻转我建议关闭因为番茄叶片有向光性病斑分布和叶脉方向有关上下翻转会制造出自然界不存在的样本。再加上scale0.4适当缩放和translate0.1小范围平移增强集就不会太畸变。这几个参数在精度上差别不一定大但能少一个干扰就少一个。4.3 预训练权重从 n 开始小事下载失败用本地文件兜底训练入口里的modelyolov8n.pt是 nano 版权重参数最小、跑得最快适合先验证数据集。等第一次训练结束确认 mAP 能用再换yolov8s.pt或yolov8m.pt跑一版。不要一上来就用 x 版一旦数据有问题x 版跑一天给你一个垃圾结果排查成本极高。“yolo 预训练模型下载”是很多人卡住的步骤。Ultralytics 默认从 GitHub 下载网络不稳时下载失败训练命令会一直停在 Downloading 阶段。解决办法是先用浏览器手动下载 yolov8n.pt放到运行命令的当前目录再执行训练。只要当前目录有这个文件Ultralytics 就不会重复下载会直接加载本地权重。训练时还有个参数值得打开cacheTrue。它会提前把整份数据集读进内存省掉每个 epoch 从磁盘读图的 IO 等待。如果你的机器内存足够大16G 以上这个参数能把训练时间缩短近一半。内存不足时系统会频繁换页反而更慢酌情使用。训练结束后runs/detect/train/里会自动生成 confusion_matrix.png、results.png、val_batch*.jpg 这些验证文件这就是后面排查的基础。4.4 训练日志读法P、R、mAP50 和 mAP50-95 分别看什么很多新手盯着 loss 曲线以为 loss 降了就行其实检测任务要看验证集指标。训练结束时 Ultralytics 会打印一个按类别统计的表大概长这样Class Images Instances Box(P R mAP50 mAP50-95) all 50 392 0.72 0.68 0.71 0.45 bacterial_spot 50 130 0.91 0.75 0.87 0.56 early_blight 50 88 0.66 0.59 0.62 0.38P 是精确率框到真正病斑的比例R 是召回率真实病斑被框出来的比例。mAP50 是 IoU 阈值 0.5 下的平均精度mAP50-95 是 0.5 到 0.95 多个阈值下的平均后者更严格。看类别行能直接定位问题类别P 高 R 低说明这类病斑大量漏检可能和样本少或病斑太小有关P 低 R 高说明误报多模型把健康组织也框了。每轮看这个表比看 loss 曲线有用得多。5. 避坑指南番茄叶病害数据集最容易翻车的 5 个问题5.1 标签 id 和 class 文件不一致训练正常但 mAP 一直为 0现象loss 在降训练日志也很正常但 val 的 mAP 从头到尾都是 0。画验证集图片时发现框完全不对。原因labels txt 里的 class id 顺序和 data.yaml 的 names 顺序对不上。比如作者用 LabelImg 时类别顺序是 early_blight 在第 0 位你换成的 data.yaml 把 bacterial_spot 放到了第 0 位模型始终在用第 0 类的名字学习第 2 类的图像。解决不要改标签文件先打开作者提供的 class 文件看第一行是什么。把 data.yaml 的 names 改成一模一样的顺序。改完后重新跑一次yolo detect valmAP 立刻恢复正常。以后每次拿到新数据集先做这个核对成本两分钟。5.2 图片 EXIF 旋转可视化脚本画完框全偏了现象标签画回原图框的位置比病斑偏出去很远或者整张图内容转了 90 度。原因手机或数码相机拍的 JPG 会记录 EXIF 方向信息很多图像库默认不处理这个字段导致图像实际像素是旋转过的而标签坐标是按原始方向标注的。解决训练前做一次批量修正用 PIL 的ImageOps.exif_transpose()处理后另存为 JPG同时重新生成对应标签。脚本大概长这样from PIL import Image, ImageOps import glob for path in glob.glob(tomato_yolo/images/train/*.jpg): img Image.open(path) img ImageOps.exif_transpose(img) # 按 EXIF 信息旋转回正 if img.getexif(): img.save(path, quality95, exifb) # 旋转后清除 EXIF避免二次旋转注意如果图片确实被转正了原标签里的坐标可能不再准确保险做法是旋转后重新用标注工具检查。我一般只对来源是手机照片的数据执行这个操作从网上下载的公开数据集基本不需要。5.3 标签坐标不在 0~1 范围训练时不报错但损失曲线特别高现象loss 在 2.0 以上降不下去损失曲线抖动剧烈可视化画框位置全在画布外。原因标注工具导出的坐标有的是像素坐标有的是归一化坐标。有人直接把 512、346 这种像素值当归一化坐标写进 txt模型读到 x 大于 1 后先报 warning然后异常预测。解决统计一下所有 txt 里的坐标是否落在 0~1 区间awk {for(i2;i5;i) if($i0||$i1) print FILENAME, $0} tomato_yolo/labels/train/*.txt | head如果发现大量超界坐标说明数据的坐标格式不一致。常见做法是写一个校正脚本检查异常行数量确认全部异常后按原图宽高做除法把像素坐标批量转成归一化坐标。千万不要手工改几百个文件。5.4 验证集划分不按样本来源mAP 虚高换手机拍摄就崩现象训练集 mAP50 达到 0.85但换一批新拍的番茄叶照片检测效果很差。原因划分 train/val 时用的是纯随机文件划分同一株番茄、同一个视频连续帧的图片同时出现在训练集和验证集。模型记住的是背景、光照、叶位纹理不是真正的病害特征。解决按样本来源分组划分。比如同一个植株编号或同一天拍摄的图片只能进训练集或验证集不能两边都进。常见做法是给图片名里的植株编号加一列元数据用 sklearn 的GroupShuffleSplit按组划分。如果没有编号就用采集时间戳分组。这一步对农业数据集尤其重要因为同一块地里叶片背景非常相似。5.5 中文路径和特殊字符cv2.imread 返回 None训练直接中断现象可视化脚本读图老是不成功返回 None训练时提示找不到图片文件。检查路径文件夹名是“番茄病害数据集7类”。原因OpenCV 的 imread 在 Windows 和部分 Linux 环境下不支持中文路径和全角括号返回空指针。解决把数据集根目录改成纯英文路径例如从C:\Users\张三\番茄病害数据集\001.jpg改成D:\tomato_yolo\images\train\001.jpg。代码内部也不要拼中文路径。如果你因为项目要求必须保留中文名可以改用 PIL 读图再转成 OpenCV 的 BGR 格式但训练阶段 YOLO 在加载图片时仍可能出问题根治办法还是统一英文路径。这个坑看起来小但一旦数据集里混了一部分中文路径训练会在中途莫名中断日志还不容易定位。6. 用混淆矩阵和热力图验收 7 类模型三个低成本检查法6.1 混淆矩阵7 类里哪两类最容易混训练完成后runs/detect/train/confusion_matrix.png是最值得放大的图。番茄叶病害里早疫病和晚疫病、斑枯病和靶斑病的外观极其接近混淆矩阵里这两组大概率有交叉。看到交叉不用慌先确认是不是样本量不平衡导致回到第 3 节的分布图对比。如果某类样本少且混淆严重加样本比换模型更有效。6.2 热力图确认模型看的是病斑而不是叶柄用 Grad-CAM 或类似类激活图检查模型关注区域时注意YOLO 这类检测头并不像分类网络那样天然就有一个全局可解释层直接把 Grad-CAM 套在 backbone 输出的特征图上能看到大致的关注区域。关注区域应该落在叶面病斑附近而不是叶柄、土壤背景或图片角落。我一般抽 10 张 val 图分别看原图、预测图、热力图只要有一两张明显关注错区域就值得重新检查标签有没有标到背景上。6.3 一个收尾习惯我自己的固定流程是训练结束后先跑yolo detect val记下 mAP50 和 mAP50-95再打开 confusion_matrix.png 看类别交叉最后用可视化脚本随机抽 20 张 val 图对比标签框和预测结果。三步都做完模型才算过了我的验收线。如果时间允许再把 best.pt 导出成 ONNX提前暴露算子兼容问题。这套流程不挑数据集换到其他作物病害或者工业质检同样适用。希望这份番茄叶病害 7 类数据集的使用经验能帮你少熬几个夜。本文还有配套的精品资源点击获取