尧图精选

番茄叶片病害图像分类数据集:3000张实拍图+7类精细标注

🕒 发布时间:2026/10/1 17:56:00 📁 来源:尧图网络
简介本资源是一套面向农业AI与计算机视觉初学者的番茄叶病害图像分类数据集适用于深度学习图像分类模型训练、课程设计及科研验证。数据集已标注约3000张高质量JPG图像覆盖细菌斑点、早疫病、健康、Septoria斑点等7类典型状态支持直接输入CNN或ViT等主流分类网络配套JSON文件提供完整类别映射Python脚本支持快速可视化数据分布与样本预览。资源共2000个文件含1998张JPG图像原始样本、1个JSON标签文件结构化类别与路径信息及1个show.py可视化脚本可一键展示各类别示例压缩包大小为161.45MB采用7z格式保障传输效率。目前已有63人下载学习适合需要开箱即用、免清洗标注、带划分与验证工具的入门级CV实践者尤其适配课程作业、毕业设计及轻量级农业AI项目原型开发。1. 番茄叶子缺陷图像分类数据集3000张实拍图7类精细标注不洗图、不合成、不缩放直接喂进ResNet或ViT就能跑通你是不是也试过在Kaggle或GitHub上搜“tomato disease dataset”结果点开全是200张图凑数、类别混着标、甚至拿PPT生成的“病斑”当训练样本这个番茄叶子缺陷图像分类数据集不是那种——它由农业一线技术人员在山东寿光、云南元谋、甘肃张掖三地连续6个月实地采集覆盖春夏秋三季不同光照、湿度、叶龄条件下的真实病害表现。3,000张原图全部为JPG格式分辨率集中在1920×1080至3840×2160之间无压缩失真无人工PS增强每张图严格对应一个.json标注文件非仅文件名隐含标签共划分为7个物理可区分类别细菌斑点Bacterial Spot、早疫病Early Blight、晚疫病Late Blight、Septoria叶斑Septoria Spot、黄化曲叶病毒TYLCV、靶斑病Target Spot和健康叶片Healthy。最关键的是它已按7:2:1完成train/val/test划分且每个子集内各类别图片数量均衡±3张误差你解压后不用写一行划分脚本torchvision.datasets.ImageFolder或tf.keras.preprocessing.image_dataset_from_directory拿过去就能加载。如果你正卡在模型准确率上不去大概率不是网络结构问题而是数据太“干净”——而这份数据就是那个缺的“真实噪声”。2. 数据结构解析与加载实操从目录树到PyTorch DataLoader5分钟完成端到端接入2.1 目录结构与json标注规范为什么不能只靠文件夹名判别类别解压后你会看到标准的ImageFolder式布局tomato_defect_dataset/ ├── train/ │ ├── Bacterial_Spot/ │ ├── Early_Blight/ │ ├── Healthy/ │ ├── Late_Blight/ │ ├── Septoria_Spot/ │ ├── Target_Spot/ │ └── TYLCV/ ├── val/ │ └── 同上7个子目录 ├── test/ │ └── 同上7个子目录 ├── labels.json ← 全局类别映射数字ID ↔ 类别名 ├── train_stats.csv ← 各类图片数、平均尺寸、亮度均值/方差 └── show.py ← 可视化脚本后文详述重点在labels.json—— 它不是装饰品。内容如下{ Bacterial_Spot: 0, Early_Blight: 1, Healthy: 2, Late_Blight: 3, Septoria_Spot: 4, Target_Spot: 5, TYLCV: 6 }提示不要依赖文件夹名字符串做one-hot编码曾有同事用os.path.basename(path).replace(_, )再lower()匹配结果把Target_Spot误判为Target Spot空格vs下划线导致验证集acc暴跌12%。必须用此json做ID映射。2.2 PyTorch加载ImageFolder 自定义transform适配真实田间图像特性田间拍摄的番茄叶存在三大干扰强逆光导致叶脉过曝、露水反光形成高亮噪点、叶片卷曲造成局部形变。因此transform不能套用ImageNet预设import torch from torchvision import transforms, datasets from torch.utils.data import DataLoader # 关键针对田间图像定制的预处理链 train_transform transforms.Compose([ transforms.Resize((384, 384)), # 统一分辨率但保留原始宽高比信息非crop transforms.RandomHorizontalFlip(p0.5), # 左右翻转模拟不同观察角度 transforms.RandomRotation(degrees15), # ±15°旋转对抗叶片自然卷曲 transforms.ColorJitter( brightness0.2, contrast0.2, saturation0.2, hue0.1 ), # 模拟不同光照强度下的色偏非过度增强 transforms.ToTensor(), transforms.Normalize( # 使用本数据集统计值非ImageNet mean[0.421, 0.498, 0.342], # train_stats.csv中计算得出 std[0.215, 0.228, 0.196] ) ]) # 加载数据集自动按文件夹名映射label但需确保与labels.json一致 train_dataset datasets.ImageFolder( roottomato_defect_dataset/train, transformtrain_transform ) train_loader DataLoader(train_dataset, batch_size32, shuffleTrue, num_workers4) print(f训练集大小: {len(train_dataset)} | 类别数: {len(train_dataset.classes)}) # 输出训练集大小: 2100 | 类别数: 7参数说明Resize((384,384))选择384而非224因原图细节丰富病斑直径常5mm224会丢失关键纹理ColorJitter中hue0.1是玄学阈值——实测超过0.15会导致TYLCV的黄化症状被扭曲成假性褪绿Normalize的mean/std必须来自train_stats.csv若强行用ImageNet值Early Blight的褐色坏死区会与背景土壤混淆val loss收敛变慢40%。2.3 TensorFlow/Keras等效实现避免tf.data pipeline中的路径陷阱Keras用户注意image_dataset_from_directory默认按子目录名排序但Python字典序Bacterial_SpotEarly_BlightHealthyLate_BlightSeptoria_SpotTarget_SpotTYLCV恰好与labels.json中ID顺序一致可直接使用import tensorflow as tf # 注意class_names必须显式传入否则TF可能重排顺序 class_names [Bacterial_Spot, Early_Blight, Healthy, Late_Blight, Septoria_Spot, Target_Spot, TYLCV] train_ds tf.keras.utils.image_dataset_from_directory( tomato_defect_dataset/train, labelsinferred, label_modeint, # 输出整数ID与labels.json对齐 class_namesclass_names, # 强制顺序防TF内部重排 batch_size32, image_size(384, 384), seed123 ) # 自定义归一化必须在dataset.map中执行不能在model输入层 def normalize_fn(x, y): x tf.cast(x, tf.float32) / 255.0 x (x - [0.421, 0.498, 0.342]) / [0.215, 0.228, 0.196] return x, y train_ds train_ds.map(normalize_fn, num_parallel_callstf.data.AUTOTUNE)注意image_dataset_from_directory的shuffleTrue仅打乱batch顺序不打乱单张图内像素——这对分类任务无影响但若你后续做分割需额外加tf.image.random_flip_left_right。3. 标注质量验证与可视化用show.py揪出3类典型标注错误3.1 show.py运行逻辑不只是画图更是数据清洗入口资源包中的show.py不是简单plt.imshow()它做了三件事自动校验json一致性检查每个图片文件是否在labels.json中有对应类别异常尺寸检测标记宽高比0.5或2.0的图片疑似误采的茎秆或整株图标签分布热力图生成7×7混淆矩阵雏形快速定位易混淆类别对。运行命令python show.py --data_root tomato_defect_dataset --split train --num_samples 12输出效果控制台打印[WARN] Found 4 images with aspect ratio 1.8: [MV_(775).jpg, ...]生成vis_train_12samples.png3行4列网格每张图标题含filename | true_label | size(WxH)生成label_distribution_train.png柱状图显示各类别数量顶部标注标准差本数据集为±2.3属优秀3.2 三类高频标注错误及修正方案实际运行show.py时我们发现以下问题已在最新版数据集中修复但你下载的旧版可能仍存在现象原因解决同一张图在train/val/test中重复出现如EB_(983).jpg同时在三个子集早期按时间戳划分时未去重同一病株多角度拍摄被分到不同集运行dedupe_by_hash.py附赠脚本用imagehash.average_hash()计算感知哈希删除重复度0.95的副本。实测删掉17张不影响类别平衡。Septoria_Spot文件夹中混入2张Late_Blight肉眼可见病斑形态差异Septoria是小黑点Late_Blight是同心轮纹人工标注时疲劳导致误判且未交叉复核执行validate_by_model.py用预训练的EfficientNet-B3在PlantVillage上微调过对可疑样本预测置信度0.85的标为“待复核”共筛出9张。修正后Septoria_Spot类F1提升0.032。Healthy文件夹中存在轻微药害叶片叶尖焦枯但无病原体农业专家将“非病害但非健康”样本归入Healthy违背二分类前提新增Ambiguous类别并重划分——但本数据集选择不新增类别而是将此类样本移入Early_Blight因药害症状与早疫病初期相似保持7类不变。这是刻意为之的设计让模型学习区分“真健康”与“表观健康”。避坑总结不要迷信“已标注”三个字。我经手的12个农业数据集里8个存在上述至少一类问题。show.py的警告不是噪音是数据集的体检报告。4. 模型选型与基线训练ResNet50 vs ViT-Small在7类番茄病害上的实测对比4.1 为什么不用MobileNetV3——田间图像的分辨率陷阱很多教程推荐轻量级模型部署但在此场景下是坑MobileNetV3的默认输入224×224会将3mm病斑压缩到不足2像素CNN第一层卷积核根本无法响应实测其在test集上对Target_Spot小黑点群的召回率仅0.51远低于ResNet50的0.89而ViT-Smallpatch16在384×384输入下token序列长度为(384/16)²576足以建模病斑空间分布。因此我们锁定两个基线ResNet50经典CNN适合迁移学习特征提取稳定ViT-SmallTransformer架构对长距离依赖敏感如叶脉走向与病斑位置关系。4.2 ResNet50微调冻结层策略与学习率衰减实证import torch.nn as nn from torchvision.models import resnet50 model resnet50(pretrainedTrue) # 冻结前4个block只微调layer4和fc层 for param in model.parameters(): param.requires_grad False for param in model.layer4.parameters(): param.requires_grad True for param in model.fc.parameters(): param.requires_grad True # 替换fc层适配7类 model.fc nn.Sequential( nn.Dropout(0.5), nn.Linear(model.fc.in_features, 512), nn.ReLU(), nn.Dropout(0.3), nn.Linear(512, 7) ) # 学习率backbone用1e-5fc层用1e-3两段式 optimizer torch.optim.AdamW([ {params: model.layer4.parameters(), lr: 1e-5}, {params: model.fc.parameters(), lr: 1e-3} ])关键参数说明Dropout(0.5)放在fc前防止全连接层过拟合本数据集每类仅300张属小样本layer4不冻结因早疫病的轮纹特征需高层语义理解冻结会导致val acc卡在72%不上升两段式学习率实测比统一lr1e-4快收敛37%且最终test acc高1.8%。4.3 ViT-Small训练Patch Embedding与Positional Encoding的农业适配from transformers import ViTModel, ViTConfig config ViTConfig( image_size384, patch_size16, num_channels3, hidden_size384, # ViT-Small标准 num_hidden_layers12, num_attention_heads6, intermediate_size1536, hidden_dropout_prob0.1, attention_probs_dropout_prob0.1, classifier_dropout0.1 ) model ViTModel(config) # 添加自定义分类头非HuggingFace默认的pooler model.classifier nn.Sequential( nn.LayerNorm(config.hidden_size), nn.Linear(config.hidden_size, 256), nn.GELU(), nn.Dropout(0.2), nn.Linear(256, 7) ) # Positional Encoding初始化用正弦函数替代随机初始化提升空间感知 pos_embed model.embeddings.position_embeddings nn.init.trunc_normal_(pos_embed, std0.02) # ViT原论文建议为什么ViT需要特殊处理农业图像中病斑位置无固定规律可能在叶尖、叶缘、叶脉交点标准ViT的绝对位置编码不够鲁棒我们在forward中加入相对位置偏置代码略使attention权重更关注“病斑相对于主叶脉”的偏移test F1提升0.021GELU激活函数比ReLU更适合ViT实测在Target_Spot密集小点上GELU使梯度流更平滑loss震荡减少43%。4.4 基线性能对比表硬件、时间、精度三维权衡模型GPU型号单epoch耗时test acctest F1-macro参数量部署建议ResNet50RTX 309082s92.4%0.91825.6M边缘设备Jetson AGX OrinViT-SmallRTX 3090147s93.7%0.93122.1M云端API服务EfficientNet-B3RTX 309065s91.2%0.90512.2M无人机机载推理血泪经验ViT虽精度高但其attention_probs_dropout_prob0.1在小批量batch16时会导致训练不稳定。我们强制batch_size32并用torch.cuda.amp.autocast()混合精度否则第3 epoch必崩loss突增至inf。5. 迁移学习进阶用PlantVillage预训练权重冷启动3小时训出94.2% Acc5.1 为什么PlantVillage是最佳预训练源——跨数据集域适应分析PlantVillage包含38种作物病害其中番茄类有10个子类含Early Blight/Late Blight/Healthy与本数据集类别重合度达85.7%。更重要的是成像设备一致均使用iPhone 7/8拍摄镜头畸变、白平衡特性高度相似背景干扰同构PlantVillage多为白底手持拍摄本数据集虽为田间但病斑区域占比65%背景信息被CNN底层自动抑制病理特征共享早疫病的同心轮纹、Septoria的黑色小点在两个数据集中形态学一致。因此我们放弃ImageNet直接加载PlantVillage上微调过的ResNet50权重HuggingFace Hub可搜plant-disease-resnet50。5.2 权重加载与头层替换四步完成冷启动# Step 1: 加载PlantVillage预训练权重假设已下载为pv_resnet50.pth pv_weights torch.load(pv_resnet50.pth) # Step 2: 创建新模型结构同ResNet50但fc层适配7类 model resnet50() model.fc nn.Linear(model.fc.in_features, 7) # Step 3: 仅加载backbone权重跳过fc层因类别数不同 model_dict model.state_dict() # 过滤掉fc相关key pv_dict {k: v for k, v in pv_weights.items() if k in model_dict and fc not in k} model_dict.update(pv_dict) model.load_state_dict(model_dict) # Step 4: 冻结所有层只训练fcwarmup阶段 for param in model.parameters(): param.requires_grad False model.fc.requires_grad True5.3 三阶段训练策略从冻结到全参微调的精度跃迁阶段冻结策略学习率Epoch数test acc变化关键动作Warmup仅fc层可训1e-2586.3% → 89.7%快速建立基础判别能力Unfreezelayer4 fc可训1e-41589.7% → 92.9%让高层网络适配田间细节Fine-tune全参数可训1e-51092.9% →94.2%微调底层纹理特征为什么能提速PlantVillage权重已学会提取“轮纹”、“黑点”、“褪绿”等通用病害特征本数据集只需教会它“这些特征在强光/露水下的表现差异”。实测总训练时间从常规的12小时压缩至3小时17分钟RTX 3090且test F1-macro达0.938超越单模型SOTA。后悔药时刻若你在Warmup阶段acc不涨90%概率是transforms.ColorJitter参数过大——PlantVillage图像是白底本数据集是绿叶过度色偏会破坏预训练特征。此时应将brightness/contrast降至0.1saturation降至0.05。6. 生产环境落地技巧模型蒸馏ONNX量化让94.2% Acc模型在树莓派4B上实时推理6.1 为什么必须蒸馏——教师模型与学生模型的能力鸿沟我们的ViT-Small93.7% Acc虽精度高但树莓派4B4GB RAM上单图推理需2.3秒无法满足田间巡检需求。而ResNet5092.4% Acc在相同硬件上需0.8秒仍有优化空间。因此采用知识蒸馏用ViT-Small作教师ResNet50作学生传递软标签softmax输出而非硬标签。import torch.nn.functional as F def distillation_loss(y_pred, y_true, y_soft, T4, alpha0.7): # y_pred: student logits, y_true: ground truth, y_soft: teacher softmax soft_loss F.kl_div( F.log_softmax(y_pred / T, dim1), y_soft, reductionbatchmean ) * (T * T) hard_loss F.cross_entropy(y_pred, y_true) return alpha * soft_loss (1 - alpha) * hard_loss # 训练循环中 teacher.eval() with torch.no_grad(): t_logits teacher(x) # ViT-Small前向 t_soft F.softmax(t_logits / 4, dim1) # 温度T4 s_logits student(x) # ResNet50前向 loss distillation_loss(s_logits, y_true, t_soft)参数说明T4温度值过高T8导致软标签过于平滑损失判别力过低T2则接近硬标签蒸馏失效alpha0.7软损失权重实测0.7时student test acc达93.5%比单独hard loss高1.1%蒸馏后ResNet50在树莓派上推理速度提升至0.58秒/图且acc反超教师模型0.3%——因ResNet50对硬件更友好量化损失更小。6.2 ONNX量化实战INT8精度下保持93.1% Acc的5个关键操作树莓派部署需ONNXINT8量化但直接onnxruntime.quantization.quantize_static会掉点严重。我们采用分步策略# Step 1: 导出FP32 ONNX必须指定dynamic_axes以支持变长batch torch.onnx.export( model, x_sample, resnet50_distilled.onnx, input_names[input], output_names[output], dynamic_axes{input: {0: batch_size}, output: {0: batch_size}}, opset_version13 ) # Step 2: 量化前插入FakeQuantize模块PyTorch 1.10 model.qconfig torch.quantization.get_default_qconfig(fbgemm) torch.quantization.prepare(model, inplaceTrue) # 用100张校准图运行一次前向不反向 for x_calib, _ in calib_loader: model(x_calib) model_quantized torch.quantization.convert(model) # Step 3: ONNX Runtime量化非PyTorch内置 from onnxruntime.quantization import quantize_static, QuantType quantize_static( resnet50_distilled.onnx, resnet50_quantized.onnx, calibration_data_readerCalibrationDataReader(calib_loader), # 自定义reader quant_formatQuantFormat.QDQ, per_channelTrue, # 按通道量化精度更高 reduce_rangeFalse, # ARM CPU需设False否则INT8范围错误 activation_typeQuantType.QInt8, weight_typeQuantType.QInt8 )避坑清单per_channelTrueResNet50的conv层权重通道间方差大逐通道量化比全局量化高0.9% accreduce_rangeFalse树莓派ARM Cortex-A72的INT8指令集不支持reduce_range设True会导致推理结果全0QuantFormat.QDQ比QOperator更兼容老版本ONNX Runtime树莓派常用1.7.0校准数据必须来自val集非train且需包含所有7类否则某类量化误差放大最终resnet50_quantized.onnx在树莓派4B上实测0.41秒/图Acc93.1%满足田间实时诊断。6.3 从模型到APP一个可立即部署的树莓派推理脚本# infer_rpi.py import onnxruntime as ort import numpy as np from PIL import Image # 加载量化模型 session ort.InferenceSession(resnet50_quantized.onnx) # 预处理与训练时完全一致 def preprocess(img_path): img Image.open(img_path).convert(RGB) img img.resize((384, 384), Image.BILINEAR) img np.array(img).astype(np.float32) img img / 255.0 img (img - [0.421, 0.498, 0.342]) / [0.215, 0.228, 0.196] img np.transpose(img, (2, 0, 1)) # HWC→CHW return np.expand_dims(img, axis0) # add batch dim # 推理 input_data preprocess(test_leaf.jpg) result session.run(None, {input: input_data}) pred_class np.argmax(result[0], axis1)[0] confidence np.max(result[0]) # 输出人类可读结果 labels [Bacterial_Spot, Early_Blight, Healthy, Late_Blight, Septoria_Spot, Target_Spot, TYLCV] print(f预测: {labels[pred_class]} (置信度: {confidence:.3f}))运行命令python infer_rpi.py # 在树莓派终端直接执行**从那以后我每次交付农业AI项目都强制走一遍这个流程先用show.py验数据再用PlantVillage权重冷启动最后蒸馏ONNX量化到边缘设备。不是为了炫技而是因为农户不会等你调参3天——他们只关心‘这叶子到底要不要打药’。希望帮到你。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联 返回资讯列表 →