
简介面向农业病害识别与图像分类实践该数据集包含大白菜叶片背蛾、潜叶虫、霉菌三类病害图像已标注并整理为训练集与测试集适合初学者练习CNN分类流程也可作为YOLOv5等深度学习项目的直接数据源。压缩包为7z格式内含2000个文件以1998张jpg叶片图像为主体另配1个Python可视化脚本和1个json标注说明文件整体约350.83MB。json文件用于查看类别划分与具体标签三个类别分别对应不同病害表型便于训练时对照分析show脚本可快速预览样本分布帮助读者在训练前完成数据检查与目录确认。目前已有154人学习/浏览对于需要构建植物病害识别模型、开展分类网络实验或制作数据集的读者这份已标注数据集能省去大量采集与整理时间直接进入模型训练与效果验证阶段。1. 大白菜叶片病害图像识别数据集2800张已标注图像能撑起什么场景如果你正在做植物病害方向的图像识别最难的不是搭模型而是找一份能直接用的数据集。公开的PlantDoc、PlantVillage虽然经典但病害种类偏番茄、马铃薯大白菜的霜霉病、软腐病、黑斑病样本要么稀少要么标注框画得粗糙。大白菜叶片病害图像识别数据集已标注约2800张数据解决的就是这个缺口——它是围绕大白菜叶片病害整理的图像识别数据集包含约2800张已标注图像覆盖常见叶部病害类别与健康叶片样本适合用来训练目标检测、图像分类或病害分割模型。这个规模放在深度学习里不算大但对农业场景的单作物病害识别已经够用配上合适的数据增强和预训练权重足够撑起一个可落地的病害检测demo或田间巡检原型。适合谁做植保AI、农业视觉检测、算法验证或者想拿一份干净数据练手YOLOv8训练流程的开发者。2. 先搞清楚数据集的真实面貌目录结构、标注格式与质量核查拿到这份已标注数据集的第一件事不是急着开训练而是把它当黑匣子拆开看一遍。约2800张图像说多不多说少不少但如果标注格式、类别分布、图像分辨率没摸清后面训练全是翻车现场。我一般会花一两个小时做一次完整的数据体检这一步能省下后面排错的半天时间。2.1 常见目录组织方式与标注格式识别这类农业视觉数据集常见的目录组织方式有两种一种是按类别分文件夹存放每类一个目录标注文件跟随图像另一种是采用标准检测数据集结构images和labels分家训练、验证子集也提前分好。标题里说已标注但没说具体格式所以拿到的可能是以下几种主流形式标注格式文件形态适用场景YOLO txt每张图对应一个同名txt每行class x_center y_center width height目标检测可直接喂给YOLO系VOC XML每张图对应一个XML记录对象框与类别名检测/分割需转换给YOLOCOCO json所有标注汇总在一个json含categories/annotations检测/分割mmdetection等CSV/Excel表格记录文件名与类别标签图像分类常见做法是先看根目录有没有classes.txt或data.yaml有的话直接打开看类别名没有的话随机挑几张图看标注文件内容几秒就能判断格式。具体到这份大白菜数据集如果是检测用途大概率是YOLO txt或VOC XML如果做了整图分类标注那就是按类别归档的文件夹结构。拿到手先跑一条命令把目录树拉出来find . -type f | head -50 find . -type d | sort先看顶层结构再深入别一上来就统计全量文件。头50个文件足够判断组织方式目录列表能看出是否已划分train/val。遇到过不少数据集文件名乱跳、子文件夹嵌套好几层的情况先摸清结构再写处理脚本才不会漏文件。2.2 用Python核查类别分布与标注质量数据体检的核心三件事类别是否均衡、标注框是否有错位或越界、图像和标注文件是否一一对应。约2800张图像如果分布均匀每类可能有三四百张如果存在严重长尾训练时就需要针对性处理。下面这个脚本专门做标注质量核查兼容YOLO txt格式import os from collections import Counter import cv2 label_dir labels image_dir images # 读取类别名YOLO格式通常有classes.txt with open(classes.txt, r, encodingutf-8) as f: class_names [line.strip() for line in f.readlines()] # 统计每个类别的实例数 class_counter Counter() error_log [] for label_file in os.listdir(label_dir): if not label_file.endswith(.txt): continue img_file os.path.join(image_dir, label_file.replace(.txt, .jpg)) if not os.path.exists(img_file): error_log.append(fmissing image: {label_file}) continue h, w cv2.imread(img_file).shape[:2] with open(os.path.join(label_dir, label_file), r, encodingutf-8) as f: for line in f.readlines(): parts line.strip().split() cls int(parts[0]) x_c, y_c, bw, bh map(float, parts[1:]) class_counter[class_names[cls]] 1 # 检查标注框是否越界 if not (0 x_c 1 and 0 y_c 1 and 0 bw 1 and 0 bh 1): error_log.append(finvalid bbox in {label_file}: {line.strip()}) print(类别实例统计, dict(class_counter)) print(异常条数, len(error_log)) for e in error_log[:10]: print(e)脚本逻辑说明遍历所有标签文件对每个标签检查对应图像是否存在同时读取图像真实宽高用于校验归一化坐标是否在合法范围内。0 x_c 1这类条件看起来简单但实际数据集里常见标注软件导出时会生成x_c0或bw1.0001这类边缘值YOLO训练时虽然不报错但会拉低边界框回归精度。异常条数如果超过几十条就需要写脚本统一修正而不是直接开训。2.3 训练/验证划分随机种子与类别分层很多已标注数据集会直接附带一个划分好的train/val列表但有的只给全量图像划分得自己做。约2800张图的规模下常见做法是9:1或8:2划分验证集至少保留200张以上否则评估曲线波动太大。划分时一定要做分层抽样保证每个类别在验证集中都有代表避免某个稀有病害只出现在训练集里验证集指标虚高。import random from collections import defaultdict import shutil random.seed(42) # 固定随机种子保证可复现 train_ratio 0.85 # 按类别对样本分层 class_to_files defaultdict(list) for label_file in os.listdir(label_dir): cls int(open(os.path.join(label_dir, label_file)).readline().split()[0]) class_to_files[cls].append(label_file.replace(.txt, .jpg)) train_files, val_files [], [] for cls, files in class_to_files.items(): random.shuffle(files) split_idx int(len(files) * train_ratio) train_files.extend(files[:split_idx]) val_files.extend(files[split_idx:]) print(ftrain: {len(train_files)}, val: {len(val_files)})代码说明random.seed(42)锁死随机序列同一份数据每次划分结果一致方便复现别人的训练结果。按类别分层是预防长尾问题的关键——如果某个病害只有80张图随机划分可能让验证集只分到5张指标波动极大。80/20比例适合训练快速迭代如果追求更稳的评估可以改成85/15。3. 图像预处理与数据增强让2800张图发挥出上万张的效果图像识别任务的现实是模型参数量越大越需要数据喂。2800张直接训练一个YOLOv8m过拟合几乎是必然的。这个规模的数据集真正决定上限的是预处理和数据增强策略。病害识别场景里增强不只是为了凑数量更是模拟田间拍摄的复杂光照、露水反光、叶片叠加等真实干扰。3.1 统一尺寸与归一化等比例缩放比直接拉伸更安全大白菜叶片图像来源可能很杂手机拍的、田间监控的、实验室扫描的尺寸从几百像素到几千像素都有。训练前统一尺寸是必须的但直接resize成正方形会破坏叶片形态导致病斑比例失真。更安全的做法是等比例缩放后pad到目标尺寸或者让YOLO自动处理。YOLOv8的imgsz参数其实已经内置了letterbox处理但如果你自己写预处理管线要注意下面这个区别import cv2 import numpy as np def letterbox(img, target_size640): h, w img.shape[:2] scale min(target_size / w, target_size / h) new_w, new_h int(w * scale), int(h * scale) resized cv2.resize(img, (new_w, new_h), interpolationcv2.INTER_LINEAR) canvas np.full((target_size, target_size, 3), 114, dtypenp.uint8) canvas[(target_size - new_h) // 2:(target_size - new_h) // 2 new_h, (target_size - new_w) // 2:(target_size - new_w) // 2 new_w] resized return canvas参数说明scale取宽高缩放比的小值保证图像完整落入画布不裁剪填充值114是YOLO训练时常用的中性灰度不会引入额外噪声。INTER_LINEAR适合缩小图像如果是从小图放大到大分辨率建议换INTER_CUBIC减少锯齿。这个函数的作用是让所有输入尺寸统一同时不因裁剪丢失叶片边缘的早期病害斑点——很多人直接cv2.resize(img, (640, 640))把叶片拉变形病斑形状特征被扭曲模型学到的就是错误的几何信息。3.2 病害场景的增强组合策略别把病斑增强没了数据增强对病害识别的核心矛盾在于既要增加多样性又不能把病斑本身的纹理特征破坏掉。病斑识别依赖的是颜色褪绿、褐变、霉层和纹理斑点的边缘形态所以增强策略要避开破坏色彩的极端操作。我常用的一套组合from ultralytics import YOLO # YOLOv8内置增强参数在yaml中配置 model YOLO(yolov8n.pt) model.train( datacabbage_disease.yaml, epochs100, imgsz640, hsv_h0.015, # 色调扰动幅度调小避免颜色失真 hsv_s0.5, # 饱和度扰动模拟不同光照强度 hsv_v0.4, # 亮度扰动模拟阴天/强光 flipud0.1, # 上下翻转大白菜叶片朝向不影响病害判断 fliplr0.5, # 左右翻转常见的有效增强 mosaic1.0, # 拼接增强 mixup0.1, # 混类增强比例要调低 )参数说明hsv_h0.015小幅度色相扰动因为病斑的黄化或褐变是重要判据色相抖动太大模型就分不清霜霉病的黄斑和正常叶片的边缘黄化hsv_s0.5和hsv_v0.4模拟的是田间不同光照适度加强泛化mosaic1.0开启拼接增强让模型在小目标检测上更鲁棒但拼接时会生成不自然的图像边界如果病害斑点很小可能被拼接缝切掉实测中发现大白菜黑斑病的早期小斑点直径只有10像素出头容易被mosaic干扰建议调到0.8上下mixup0.1混类增强会让两张不同病害的叶片叠加这个对病害识别来说双刃剑比例超过0.3模型就容易混淆两种形态相近的病害。3.3 增强的边界陷阱什么情况下增强反而有害数据增强不是越多越好这个在病害识别里尤其明显。第一条边界是类别平衡问题如果某些病害原始样本只有80张增强可以把它凑到300张的效果但如果原本某两类样本就长得相似比如霜霉病初期和黄萎病初期都是叶片局部褪绿再叠加颜色扰动和混类增强模型会彻底分不清这两个类。遇到这种情况优先解决的是类间特征而不是盲目加增强。第二条边界是背景干扰大白菜叶片数据集的背景可能包含土壤、杂草、水滴反射mosaic和mixup会把这些背景混合模型反而学到了土壤块病害的错误关联。我一般会先用原始数据训一个baseline记录各类别的precision和recall再开启增强训练一轮对比每类的mAP变化——增强让某类掉点了说明这个增强对该病害不友好单独关掉比全局调参更有效。提示图像识别任务里增强参数的最终验证靠的是模型在独立验证集上的表现不是增强后图像看起来自然。4. 用YOLOv8训一个病害检测基线最小可行流程数据集体检完、增强策略定好接下来就是把模型跑起来。YOLOv8是目前训练自定义检测数据集最高效的框架之一一套配置跑通整个流程。这个环节的目标不是追求最高精度而是先拿到一个可评估、可迭代的基线结果。4.1 环境配置与data.yaml训练的第一步是把数据集的路径和类别信息写进data.yaml。YOLOv8的配置文件格式统一路径用相对路径或绝对路径都可以但注意类别顺序必须与标注文件里的class id严格一致# cabbage_disease.yaml path: /path/to/cabbage_dataset train: images/train val: images/val nc: 4 names: 0: healthy 1: downy_mildew 2: soft_rot 3: black_spot配置说明path是数据集根目录train和val是相对path的路径。nc必须等于names列表长度否则训练会报错。names与标注文件的类别索引是硬绑定关系——如果数据集原本的类别顺序是downy_mildew:0, healthy:1而你这里写成了healthy:0那训练时模型理解全乱套。拿到数据集后一定先开一份原始类别清单核对别想当然按字母序排列。4.2 训练启动与关键超参训练命令用ultralytics的CLI或Python接口都行命令行方式更适合快速复现。一套适合2800张数据集的初始参数如下yolo train \ modelyolov8n.pt \ datacabbage_disease.yaml \ epochs150 \ imgsz640 \ batch16 \ lr00.005 \ patience20 \ device0参数说明yolov8n.pt是nano版本权重2800张规模用s/m以上模型容易过拟合先从nano起步建立baseline是稳妥路线epochs150给足收敛空间batch16取决于显存12GB显存跑640分辨率nano模型这个值没问题显存小就降到8或4lr00.005是初始学习率比默认的0.01稍低因为数据集规模小学习率过大前期震荡明显patience20表示20个epoch验证集指标没提升就早停约2800张图用这个值能省不少时间。这里的关键是把model设为预训练权重yolov8n.pt而不是空模型ImageNet预训练权重迁移到农业病害图像上收敛速度快得多。4.3 训练日志解读与迭代决策训练过程会打印每轮的loss和mAP很多人只看最终结果忽视中间过程。看训练日志先抓三个信号box_loss是否持续下降且验证集和训练集差距不大cls_loss是否快速收敛到低位mAP50-95曲线是否平滑上升。如果训练集loss降但验证集mAP不升说明过拟合下一轮减少epoch数或增强正则如果前20个epoch mAP还在低位抖动大概率是学习率设置问题或数据标签有问题。跑完一轮后调出来的results.csv是分析依据cat runs/detect/train/results.csv | awk -F, NR1 {print $1, $10} | tail -20这行命令提取每个epoch的验证集mAP50-95列快速看趋势。如果最后几个epoch的mAP还在明显上升说明训练没收敛完加大epochs再跑如果已经走平甚至下降就按当前权重做推理测试。4.4 推理验证跑通整个落地闭环训练结束后用最佳权重对验证集做一次推理输出可视化结果确认模型学到的内容和病害特征匹配yolo predict \ modelruns/detect/train/weights/best.pt \ source/path/to/cabbage_dataset/images/val \ conf0.25 \ saveTrue推理参数说明conf0.25是置信度阈值低于这个值的预测框会被过滤。田间场景如果追求召回率不漏检阈值往下降到0.15如果追求精确率减少误报往上调到0.4。保存的可视化图像里重点看三件事病斑定位是否准确覆盖实际病变区域、健康叶片是否被误报为病害、小病斑目标是否被漏检。这一步跑完基线模型闭环完成。提示验证集推理结果里如果发现大量误报先别调模型参数回去检查标签和图像是否错位——这类问题八成出在数据本身不是模型能力。5. 避坑大白菜叶片病害数据集的五个高频踩坑记录这类中等规模的农业数据集隐蔽坑比想象中多。基于做过的类似植物病害数据集项目把最容易翻车的几条整理出来按现象→原因→解决的排查思路记录省得你重新趟一遍。5.1 类别索引错位导致训练指标虚高现象训练时loss降得飞快mAP曲线漂亮但推理时预测的类别和实际病害对不上比如把黑斑病预测成软腐病。原因标注文件的class id与data.yaml的names顺序不一致。常见于数据集的原始类别顺序是[soft_rot, black_spot, healthy, downy_mildew]但写yaml时按字母序排了整个错位。更隐蔽的是如果某个类别在原始数据里没有样本错位甚至看不出异常。解决训练前跑一遍第2.2节的统计脚本把class_counter打印结果和data.yaml逐行对齐核对。用脚本自动检查不靠肉眼——我曾在数据集里遇到class 2实际上是downy_mildew但配置文件写的是black_spot一直训到第七轮才发现mAP异常白白浪费两小时。5.2 验证集污染训练集现象训练loss和验证loss都极低但换一批新的田间图像测试时mAP暴跌。原因数据集划分时直接用了全量shuffle没有按图像来源或拍摄批次做分组。同一株植物、同一拍摄时段的图像被分到训练集和验证集模型实际上记住了拍摄背景而不是病害特征。解决划分前检查文件名是否带采集批次标识。大白菜叶片的常见命名格式是field1_20240601_001.jpg这种带拍摄时间和地块编号的名字按前缀分组后再划分。如果没有批次标识按目录结构分——不同子目录大概率对应不同采集批次。5.3 标注框过拟合叶片边缘而非病灶现象训练时mAP不错但可视化推理发现预测框总是偏向叶片边缘而不是病害中心。原因标注人员画框时习惯把整个病斑连同边缘健康组织一起框进去尤其霜霉病的黄化区域边界模糊框画大了圈进大量健康组织。模型学到的是黄绿色渐变区域而非病斑实体。解决用可视化工具抽20%样本人工检查框位置。如果发现系统性偏移需要重新标注或写脚本按病斑mask收缩边界框。这个坑不太好自动排查检测结果里的偏差必须靠人眼确认。如果数据集本身没有提供分割mask只能接受现有标注并尝试在损失函数上做调整比如降低IoU阈值的影响——但这影响有限根治要靠更精细的标注。5.4 图像尺寸不一致导致小目标病斑被忽略现象黑斑病这类小型圆形病斑的recall明显低于霜霉病大片黄斑。原因数据集中图像分辨率跨度大有的2666×2000大图有的640×480小图。统一resize到640后大图里直径20像素的病斑缩成5像素小目标的语义信息几乎丢失模型学不到小病斑特征。解决分分辨率统计病斑尺寸分布。如果确实存在大量小目标把imgsz从640提到960显存允许的话或者在大图上做切片推理slide inference。这类问题在田间采集的大白菜图像中很典型别指望完全靠模型解决数据侧先尽量保留分辨率。5.5 病斑颜色在增强后被抹平现象开启较强增强后训练loss稳定下降但验证集上霜霉病和软腐病的混淆度反而上升。原因hsv_h色调扰动过大。霜霉病初期是黄绿色斑块软腐病初期是水渍状暗绿色斑两者本来色差就小色调抖动把这一点差异直接消除了。解决把hsv_h降到0.01以下同时用第3.3节的逐类对比方法分别记录两个类在增强前后的precision变化。这个坑的判断标准很简单如果某个类的识别效果在增强后变差优先怀疑颜色类增强参数不是模型结构问题。6. 进阶用类别权重与混淆矩阵把mAP再提一档基线跑通后真正的收益来自对数据分布特点的针对性调优。约2800张已标注的大白菜叶片病害数据集最值钱的优化点集中在类别不平衡和误判模式分析上。先说你一定会遇到的问题长尾分布。假设霜霉病有800张软腐病只有250张即使增强模型对软腐病的特征学习也不充分。YOLOv8支持对类别设置loss权重方法是修改data.yaml的weight字段。实际操作中我通常把稀有类别的权重设到1.5到2.0之间同时避免超过2.5——权重太大会让模型对稀有类产生过度敏感正常叶片反而被打上病害标签。这个参数配合早停机制是在不重写训练逻辑的情况下最直接的平衡手段。第二个实用技巧是从混淆矩阵找突破口。训练结束后看confusion_matrix.png如果霜霉病和软腐病互相误判严重说明这两种病害的初始特征褪绿、褐变存在交叉。我常用的做法是对易混淆类别做针对性图像分析裁剪两类病害的典型样本对比颜色直方图和纹理特征有时会发现数据集本身存在着色偏差——比如霜霉病图像偏暗环境采集软腐病偏亮环境模型学的其实是亮度差异而不是病害特征。这种情况下我会做一个简单的亮度归一化预处理效果往往比调模型结构更明显。我的个人习惯是在每个训练轮次结束后保留best.pt和last.pt一份同时把训练用的全套增强参数和数据集划分脚本放进同一个目录归档保证三个月后还能原样复现当时的实验结果。这个习惯在换机器、换环境时帮我省过很多次重新调参的麻烦。这套方法论可以原样套用到其他作物病害数据集上——先体检、再划分、后增强、跑基线、查混淆、调权重六步走完2800张的数据就能发挥出接近上万张的效果。希望帮到你祝你训练顺利。本文还有配套的精品资源点击获取