ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

农作物病虫害识别源码包全解析:数据加载、模型训练与避坑指南

农作物病虫害识别源码包全解析:数据加载、模型训练与避坑指南 简介面向计算机专业毕业生及项目实战学习者的Python农作物病虫害识别分类项目资源包含完整项目源码、配套数据集与使用说明可直接支撑毕业设计、课程设计或期末大作业。项目经过严格调试下载即可运行适合初次接触深度学习图像分类的学生快速搭建完整流程。资源包共96个文件其中76个Python脚本构成主体涵盖模型训练、网络结构定义、数据加载及工具函数等模块另含15个pyc编译文件、数据集压缩包、训练日志及说明文档整体大小25.1MB。压缩包内目录按主程序、模型库、配置层、工具层分层组织便于阅读和二次开发。目前已有2166人学习下载。通过完整代码可直接复现农作物病虫害识别流程理解从数据处理到模型训练验证的工程实现细节也可在此框架上替换数据与网络结构进行拓展实验。1. 从模型库到训推脚本这份农作物病虫害识别源码包里装了什么做农作物病虫害识别很多同学的思路是下载一个训练好的权重文件跑一下 predict 就完事。但真正能当毕设交的 python 农作物病虫害识别项目不是单个权重文件而是一整套能训练、能验证、能换模型的源码。这份资源的主目录里同时躺着 dataloader、train_val.py、config 和几十个 backbone 模型定义说明它是一个可以直接复现训练的识别分类框架。它适合两类人一类是计算机相关专业做毕设、课设、期末大作业的学生需要一份能讲清楚训练流程的完整源码另一类是想做迁移学习实战、手头有作物叶片图片但缺一套标准训练管线的人。接下来按「先跑通数据、再选模型、再谈避坑」的顺序拆。2. 先把数据管好dataloader 与 config 的落地配置2.1 dataloader.pyc 是黑匣子但加载逻辑可以推打开压缩包第一眼大多数人会被两件事吓到一是 .pyc 文件非常多二是 models 目录下模型定义占了半壁江山。先说 dataloader.pyc。它被编译成了字节码意味着你拿不到原始 python 源码能看到的只有加载接口。对这类资源我一般不会去反编译而是先假设它遵循最主流的约定数据集根目录下放 train.txt 和 val.txt每行是「图片路径 空格 类别索引」dataloader 按行读取后交给 Dataset 封装。这个约定在农业病害数据集里非常通用PlantVillage 一类的公开数据导成清单文件时几乎都是这个格式。如果你后续要换自己的数据不需要动 pyc直接把清单文件按同样格式生成即可。下面是一个常见的替代实现当你怀疑原 dataloader 不对劲、想绕开黑匣子时可以直接用# 简易 dataloader按 train.txt/val.txt 读取图像与标签 import os from PIL import Image from torch.utils.data import Dataset, DataLoader from torchvision import transforms class CropDiseaseDataset(Dataset): def __init__(self, list_path, root_dir, transformNone): self.samples [] with open(list_path, r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue # 兼容空格或逗号分隔先按空格切再按逗号切 parts line.replace(,, ).split() img_rel, label parts[0], int(parts[1]) self.samples.append((os.path.join(root_dir, img_rel), label)) self.transform transform def __len__(self): return len(self.samples) def __getitem__(self, idx): img_path, label self.samples[idx] img Image.open(img_path).convert(RGB) if self.transform: img self.transform(img) return img, label train_transform transforms.Compose([ transforms.Resize((224, 224)), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ])这段代码的逻辑说明先读清单文件区分空格和逗号两种分隔方式这是很多网上数据集翻车的重灾区——train.txt 里用的是逗号代码里却按空格 split结果标签全串位。Resize 到 224 是因为绝大多数分类 backbone 的默认输入就是 224Normalize 用的是 ImageNet 统计值如果后面加载的是 ImageNet 预训练权重就必须用它否则模型权重与输入分布对不上收敛会很慢。一个常见的误用是训练和验证用同一套增强验证集也加随机翻转导致验证指标虚高后面单张推理时又对不上。参数说明list_path 传 train.txt 或 val.txtroot_dir 是图像实际存放的根目录transform 决定训练和验证用不同增强策略。训练集建议加 RandomHorizontalFlip 和 RandomResizedCrop验证集只做 Resize 和 CenterCrop这是识图分类的标配操作。如果机器的 CPU 核数够DataLoader 里设 num_workers4 能明显加快数据吞吐但 Windows 下 workers 开多了偶尔会卡死在数据读取遇到就先降回 0别纠结性能。2.2 config 参数先改 num_classes再动 lr资源里有 config 目录里面是 constants.pyc 和 config.pyc。编译过的 config 同样没法直接看但分类项目的配置项基本是固定的那几样数据路径、类别数、输入尺寸、batch、学习率、epoch、weight decay、是否用预训练。我建议的做法是不动 pyc在 train_val.py 外层创建一个覆盖配置的字典。训练脚本常见做法是支持命令行参数优先于默认配置如果你的版本不支持就在入口处强制覆盖。# 覆盖配置不改 config.pyc CFG { data_dir: ./dataset, # 数据集根目录 train_list: ./dataset/train.txt, val_list: ./dataset/val.txt, input_size: 224, # 可切到 256/299视显存而定 num_classes: 38, # 一定要改成你自己的类别数 batch_size: 16, # 显存不够就 8 梯度累积 lr: 1e-3, # 微调用 3e-4 更稳 epochs: 60, weight_decay: 5e-4, device: cuda, } # 如果训练脚本支持命令行传参直接 # python train_val.py --num_classes 38 --batch_size 16 --lr 1e-3参数说明里最容易踩的是 num_classes。很多下载资源自带的数据集类别数与你要做的场景不一致比如包内样例数据是 10 类某种作物病害而你要识别 38 类这个数字不改训练时最后的全连接层维度对不上轻则报错重则训练结束后新类别根本不在输出里。batch_size 和 input_size 是显存的两个调节阀二者是乘积关系总显存不变时减任何一个都能换回训练稳定性。lr 是迁移学习的关键从头训练用 1e-3 起步加载预训练权重微调时我一般降到 3e-4 左右避免破坏已经学好的底层特征。weight_decay 保持 5e-4 是 ResNet 系列的常见默认值换 Swin Transformer 这类结构时可以适当下调到 1e-4。第一次跑我强烈建议只改 num_classes、batch_size、lr 三样其他全部保持默认等通路跑通了再逐个动否则两个参数同时调出了问题你根本不知道是谁引起的。提示config 编译成 pyc 不代表配置不能再改优先看 train_val.py 是否支持命令行覆盖不要用记事本直接改 pyc 文件那样会直接损坏字节码连程序都启动不了。2.3 验证集与类别均衡先数数再训练很多人在数据上栽跟头不是代码问题而是根本不知道自己的数据长什么样。启动训练前我习惯先跑一个类别分布统计确认每类样本量、确认 train.txt 和 val.txt 的标签范围一致。这个动作只要 30 秒能避免后面所有「为什么这个类 acc 是 0」的排查。# 统计 train.txt 里的类别分布 from collections import Counter with open(train.txt, r, encodingutf-8) as f: labels [int(line.replace(,, ).split()[1]) for line in f if line.strip()] print(Counter(labels)) # 检查验证集标签是否超出训练集范围 with open(val.txt, r, encodingutf-8) as f: val_labels [int(line.replace(,, ).split()[1]) for line in f if line.strip()] print(val 最大标签:, max(val_labels), train 类别数:, len(Counter(labels)))逻辑说明Counter 输出能看到每个类别的样本数。如果少数类只有几十张多数类几千张训练时总体 loss 会被多数类主导少数类几乎学不到特征f1.txt 里那几个类别分数会惨不忍睹。val 标签范围检查是防止切分时把类别索引写乱这个问题在手工整理数据集时特别常见。解决思路有两个方向一是给少数类多采集样本二是给 loss 加类别权重让少数类样本的梯度贡献放大。如果你用的是 torch 的 CrossEntropyLoss直接把权重向量传到 weight 参数里即可如果原训练脚本没暴露这个参数就用 2.1 节的办法自己写一个 loss 封装替换进去。记住一个原则数据集质量决定精度上限模型只是尽可能接近这个上限。3. 识别分类的核心CNLNet 与几十个 backbone 怎么选3.1 模型库模式一个 factory 管住所有网络models 目录里那一长串文件不是凑数的它是一套完整的模型动物园resnet、densenet、resnest、sknet、efficientnet、regnet、xception 这类 CNN到 vit、swin_transformer、visformer、xcit、levit、pit、tnt 这类 Transformer 或混合结构基本覆盖了近年主流分类网络。这种组织方式在 timm 里非常常见所有模型注册进一个 registry通过 model_name 字符串创建实例。好处是换模型只改一个名字不用动训练逻辑。# models/factory.py 风格的模型创建方式 import torch from models import factory # 按名字创建num_classes 与 pretrained 是必调参数 model factory.create_model(resnet50, num_classes38, pretrainedTrue) model factory.create_model(efficientnet_b0, num_classes38, pretrainedTrue) model factory.create_model(swin_transformer_tiny, num_classes38, pretrainedFalse)逻辑说明factory.create_model 内部会根据名字去 registry 查构造函数然后按参数实例化。pretrainedTrue 会加载 ImageNet 预训练权重这意味着你的机器最好能访问外网否则会卡在权重下载环节离线环境下需要提前把权重文件放到 checkpoint 目录再把 pretrained 参数指到本地路径。num_classes 决定最后一层输出维度训练脚本通常会在这里做分类头替换所以你传错类别数时训练不会立刻报错而是把错误维度带进 loss 计算里等推理阶段才暴露。参数说明三个示例分别对应「入门验证型」「性价比型」「高精度型」三类选择。第一个跑通的永远是 resnet50因为它的收敛行为最可预测调参资料最多确认管线没问题后再上 efficientnet_b0 这类性价比高的模型刷指标Swin Transformer 留给数据量大、要写进论文对比实验的场景。如果你只是想交一份能运行的毕设resnet50 微调已经足够不必追求最复杂的结构。3.2 cupy_layers 与 cnlnet_5CNLCUDA 相关的自定义算子cupy_layers 目录里是 aggregation_zeropad、aggregation_zeropad_dilate、aggregation_zeropad_mix 等一堆 pyc这是用 CuPy 手写的 CUDA 算子核心是做带零填充的膨胀聚合dilated aggregation。cnlnet_5CNL.pyc 从命名看是堆叠了 5 个 CNL 模块的自定义网络CNL 可以理解为把局部卷积响应和全局上下文做交叉聚合。这类算子的共同点是依赖 GPU、依赖特定版本的 CUDA 和 CuPyCPU 机器上直接 import 就会崩。它对小目标病斑和叶片边缘的上下文建模确实有帮助但代价是环境非常挑剔。# 检查 CuPy 与 CUDA 是否匹配 python -c import cupy; print(cupy.__version__) python -c import cupy; cupy.show_config() # 确认 PyTorch 的 CUDA 版本 python -c import torch; print(torch.version.cuda) # 查看安装的是哪个 cupy 包cupy-cuda11x 还是 cupy-cuda12x pip list | grep cupy逻辑说明CuPy 的包名和 CUDA 版本是绑定的cupy-cuda11x 对应 CUDA 11.xcupy-cuda12x 对应 CUDA 12.x。装错版本的表现是 import 阶段报 libcudart 找不到或者 kernel 编译失败而不是训练中途才出错所以环境检查要在跑 train_val.py 之前做。失败时看报错的位置很关键如果报在 import cupy_layers说明是算子编译环境问题如果报在模型 forward 阶段说明算子编译成功了但输入维度不匹配后者通常是你改 input_size 导致的。如果你的显卡不支持原项目编译时的 CUDA 版本常见做法是把算子整体替换成 PyTorch 原生实现或者干脆放弃 cnlnet_5CNL改用纯 PyTorch 的 backbone 走通流程。先把毕设跑起来比纠结自定义算子重要得多这是我从翻车经验里总结出来的不要在一个跑不起来的模型上耗掉整个周末。3.3 选型建议先复现再比较模型输入尺寸显存/耗时精度适合场景resnet50224低/快中第一次复现、验证数据集可用性efficientnet_b0224低/快中高样本量 1w 以下时性价比最高swin_transformer_tiny224中/慢高样本充足、GPU 较好时冲精度cnlnet_5CNL224/299高/慢视环境环境匹配时作为自定义网络亮点选型逻辑很简单先小后大先快后准。第一步用 resnet50 跑通全流程确认数据、训练、验证闭环没问题第二步换 efficientnet_b0 这类性价比模型刷基线第三步才是 Swin Transformer 或 cnlnet_5CNL。cnlnet_5CNL 是这份资源的差异点也是毕设答辩时可以讲「自定义网络改进」的素材来源但前提是先把 CuPy 环境搞定否则它只是一个跑不起来的名字。如果你只想要一个稳定复现的结果efficientnet_b0 微调通常是最省心的选择它兼顾了训练速度和迁移效果能在小数据集上拿到比 resnet50 更好的 F1。3.4 往模型库里加自己的网络注册制怎么玩理解了 factory 的注册机制你就可以把自定义网络塞进这套训练框架这是让项目变成「你自己的项目」的关键一步。cnlnet_5CNL 能被 train_val.py 调用大概率就是因为它在 models 目录里完成了注册你照抄这个模式加新模型就行。# 在 models/my_model.py 里定义网络后注册到 registry from models.registry import register_model import torch.nn as nn register_model def my_net(num_classes38, pretrainedFalse, **kwargs): 自定义分类网络签名必须与 factory 调用方式一致 model nn.Sequential( nn.Conv2d(3, 32, kernel_size3, stride2), nn.ReLU(inplaceTrue), nn.AdaptiveAvgPool2d(1), nn.Flatten(), nn.Linear(32, num_classes) ) return model逻辑说明register_model 装饰器会把函数名注册成模型名之后 factory.create_model(my_net, num_classes38) 就能创建实例。关键的约束是函数签名必须兼容 num_classes、pretrained、**kwargs 这三个参数因为训练脚本创建模型时统一传这几项pretrained 在你自己的网络里可以暂时忽略返回 model 即可。参数说明加一个新模型文件后记得在 models/init.py 里 import 一下否则注册不生效这个细节容易漏注册了半天 factory 还是找不到名字。从那以后我每加一个模型都会先跑一句 factory.create_model 验证注册成功再进训练流程。4. 跑通 train_val.py训练、日志与单张推理4.1 训练启动从零训练与迁移学习的两种姿势train_val.py 是整份源码的主入口从名字看同时承担训练和验证。启动方式基本是命令行参数控制常见做法是用 argparse 接收 model、batch_size、lr、epochs、num_classes 等参数。第一次跑我的建议是直接用小模型、小 epoch 验证全流程能通而不是上来就堆大模型。压缩包里的 README.md 和自带使用说明一般会写清支持的参数名启动前先花两分钟扫一遍能省掉后面很多参数名对不上的麻烦。# 第一步复现通路用 resnet50 20 epoch 验证 python train_val.py --model resnet50 --num_classes 38 \ --batch_size 16 --lr 1e-3 --epochs 20 # 第二步加载预训练微调冲精度 python train_val.py --model efficientnet_b0 --pretrained \ --batch_size 16 --lr 3e-4 --epochs 60参数说明--pretrained 加不加直接决定训练时间和最终精度。农业病害数据集通常只有几千到几万张从头训练 ResNet 系列想收敛到 90% 以上很吃力用 ImageNet 预训练权重做微调通常几十个 epoch 就能到可用水平。--epochs 第一次设 20 就够目的是确认 loss 在下降、验证集 acc 在上升确认无误后再拉长。如果你的版本把配置写死在 config.pyc 里命令行和覆盖配置二选一即可不要两套同时改否则排查问题时你不知道生效的是哪一份。启动失败时看什么先看 traceback 最后 10 行。AttributeError 说明参数名不对去 README 里查真实名字FileNotFoundError 说明路径或清单文件不对回 2.1 节检查CUDA error 则按第 5 章的环境坑处理。不要一上来就怀疑模型代码训练脚本的报错 80% 出在数据路径和参数名上这是血泪经验。4.2 日志会说话CNLtrainlog.txt 和 f1.txt 怎么读包里自带了 CNLtrainlog.txt 和 f1.txt这是前人跑完留下的真实训练痕迹别当成垃圾文件删掉。CNLtrainlog.txt 一般记录每个 epoch 的 train loss、val loss、top1 accf1.txt 通常是按类别统计的 F1 明细。读懂它们你就能判断自己的训练是否健康。下面是个通用的解析脚本正则要跟着日志实际格式调整import re # 解析训练日志提炼每个 epoch 的关键指标 with open(CNLtrainlog.txt, r, encodingutf-8) as f: lines f.readlines() for line in lines: # 按你的日志实际格式调整正则 m re.search(repoch (\d).*?loss ([\d.]).*?acc ([\d.])%, line) if m: print(fepoch {m.group(1)} loss{m.group(2)} acc{m.group(3)}%)逻辑说明判断训练是否健康的核心是两个信号。一是 train loss 是否稳步下降如果有震荡不降先怀疑 lr 太大降到原来的 1/10 再试二是 val acc 与 train acc 的差距差距大于 10 个点基本就是过拟合优先加数据增强、降 lr、加 weight_decay。f1.txt 的价值在类别不均衡比如水稻稻瘟病样本多、白叶枯病样本少总体 acc 可能还行但少数类 F1 很低这时候要查是不是类别权重没设置。注意日志文件的编码有些是用 gbk 存的用 utf-8 打开会直接乱码解析失败打开看到乱码先换 encoding 参数。另外注意日志里有没有保存 best_model.pth 的逻辑。常见做法是每个 epoch 根据 val acc 更新最优权重训练结束后根目录会有一个 best_model.pth 或类似命名的文件那个才是推理时要用的不是最后一个 epoch 的模型。如果训练脚本没做这个逻辑你自己在循环里加一个 val acc 对比保存这是后悔药没有它你训完会无从下手。4.3 单张推理aidemo.zip 与 ipdemo.zip 的角色资源里还有 aidemo.zip 和 ipdemo.zip我一般理解 aidemo 是可直接运行的脚本演示ipdemo 是 Jupyter Notebook 形式的交互演示。二者都是「读权重 预处理 前向推理 输出类别」的流程只是载体不同。如果你想快速验证模型效果用演示脚本比重新写推理代码更省事如果演示脚本报依赖缺失照下面的标准推理流程走一遍也不难。# 标准单张推理流程 import torch import torchvision.transforms as T from PIL import Image from models import factory model factory.create_model(efficientnet_b0, num_classes38, pretrainedFalse) model.load_state_dict(torch.load(best_model.pth, map_locationcuda)) model.eval() transform T.Compose([ T.Resize((224, 224)), T.ToTensor(), T.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]), ]) img transform(Image.open(test_leaf.jpg).convert(RGB)).unsqueeze(0) with torch.no_grad(): logits model(img) pred logits.argmax(dim1).item() print(预测类别索引:, pred)逻辑说明load_state_dict 之前必须保证 model 的 num_classes 和权重文件一致这是我遇到最多的推理报错——权重是 38 类模型建成了 10 类直接 size mismatch 崩掉。预处理 pipeline 必须和训练时完全一致差一个 Normalize 的均值特征分布就偏了典型表现是「训练 acc 95%单张推理偶尔错」。如果你加载 pyc 版模型权重时结构对不上常见做法是通过 factory 逐个对齐模型名再 load不要尝试修改 pyc 文件本身。如果要批量验证整个文件夹的图片把上述代码包一层循环收集每张图的预测索引和 softmax 分数。Softmax 分数低比如低于 0.5的样本大概率是类别外图片或者预处理不对这类样本单独挑出来看比只看 acc 更能暴露问题。5. 避坑指南五个最容易翻车的现场5.1 环境坑CuPy 与 CUDA 版本错位导致 import 崩溃现象首次运行 import cupy_layers 或创建 cnlnet_5CNL 模型时报错错误信息指向 cupy 的 CUDA 依赖找不到或者提示 kernel 编译失败连训练都没开始就退出。原因cupy_layers 里的 aggregation_zeropad 是 CuPy 写的自定义 CUDA 算子pypi 上 cupy 的安装包和 CUDA 版本绑定。cupy-cuda11x 与 cupy-cuda12x 装混了或者 PyTorch 自带的 CUDA runtime 与系统中 nvcc 版本不一致都会在 import 阶段崩。这也是「下载即用」最容易翻车的地方因为对方的环境和你不可能完全一样python 环境和依赖安装是两回事。解决先 nvidia-smi 查驱动支持的 CUDA 版本再 python -c import torch; print(torch.version.cuda) 看 PyTorch 的 CUDA 版本最后安装对应版本的 cupy 包。装完用 cupy.show_config() 确认 device 可用。如果反复配不好止损方案是放弃 cnlnet_5CNL改用 resnet50 走通全流程别在这上面耗两天。5.2 运行坑.pyc 黑匣子让人改不动加载逻辑现象想改 dataloader 的缓存策略、想改类别映射发现目录里只有 dataloader.pyc 和一堆 config.pyc没有对应的 .py 文件找不到源码可改。原因资源发布方只提供编译后的字节码目的是保护核心实现但副作用是使用者失去修改入口。很多人死磕这一关花大量时间去反编译收益几乎为零。解决不要尝试反编译或直接改 pyc那是浪费时间的玄学操作。正解是在 train_val.py 外层做封装自己写一个 Dataset 子类在入口处覆盖数据加载函数把原 dataloader 的结果替换成你自己的实现。pyc 黑匣子对复现来说是坏事但也逼着你把数据处理握在自己手里后续换数据集反而更顺手。我见过太多同学在 pyc 上浪费一下午最后真正能解决问题的还是这个封装思路。5.3 数据坑路径分隔符、中文目录与清单格式现象训练启动后报 FileNotFoundError或者 dataloader 读到空列表训练循环根本没有数据有时 Windows 下能跑Linux 下报路径不存在反之亦然。原因train.txt 里的路径写死成 Linux 风格斜杠在 Windows 上被当成非法路径数据集放在带中文的目录下编码处理不当直接解析失败还有清单文件里是逗号分隔代码按空格切label 全部串位。这类问题不看数据文件本身完全猜不出来。解决统一用英文纯路径根目录不要带空格和中文打开清单文件前先 head 几行确认分隔符是空格还是逗号代码里用 os.path.join 而不是手拼字符串。我现在的习惯是跑训练之前先写个 10 行的脚本打印前 5 条样本和标签眼见为实确认通过再开训练。这一个动作能拦下 30% 的启动报错。5.4 显存坑batch 过大直接 OOM 死机现象train_val.py 一启动就报 CUDA out of memory严重的时候整个显卡驱动崩溃屏幕黑一下训练进程直接没了。原因默认配置往往按大显存卡设置224 输入加 resnet50batch 开 32 或 644G 以下的小卡根本扛不住。很多同学不舍得动默认参数认为改 batch 会影响精度结果在大 batch 上反复死机白白浪费时间。解决先降到 batch_size8把 input_size 保持 224还不够就降 batch 到 4 并开梯度累积累积步数 4 等价于 batch 16 的梯度统计精度损失很小。显存不足时优先减 batch不要先减输入尺寸因为很多模型在非训练尺寸下表现会掉点。如果你用的是 cnlnet_5CNL它的自定义算子比普通卷积更吃显存就更要保守直接按 batch 4 起步试。5.5 效果坑自建数据集和包内指标对不上现象用包内数据集跑出来 acc 挺高换成自己拍的田间叶片图片F1 掉到 80% 甚至更低于是怀疑源码有 bug。原因包内数据集类别少、背景干净你的现场图片有光照变化、复杂背景、多病斑共存分布差异大加上自建数据常常类别不均衡少数类的样本只有几十张总体 acc 掩盖了少数类崩盘的事实。这不是源码问题是数据分布问题。解决先做类别均衡统计每类样本数差太多就做增强复制统一采集环境尽量和训练数据的光照、角度一致在 config 里给少数类加权 loss。识别分类项目 90% 的翻车都发生在「数据分布不齐」这一步源码本身反而是最可控的部分。遇到指标对不上先回去数数据不要急着怪模型。提示以上五条按出现顺序排错最省时间环境 → 数据 → 显存 → 精度。每修完一条跑一个 5 epoch 的小训练验证再往下走别攒着一起爆发。6. 进阶把识别模型套到自己的作物数据上6.1 组织自己的数据集清单文件是最便宜的迁移路径把新数据组织成 train.txt / val.txt 的格式是这套资源最省事的复用方式。目录建议 dataset/ 下按类别建子目录比如 dataset/rice_blast/、dataset/rice_bacterial_blight/然后写脚本扫描生成清单每类按比例独立切分训练集和验证集避免某类全部进了验证集这种极端情况。# 按比例切分 train/val 清单 import os import random root my_crops train_lines, val_lines [], [] for label, cls_name in enumerate(sorted(os.listdir(root))): imgs [f for f in os.listdir(os.path.join(root, cls_name)) if f.lower().endswith((.jpg, .jpeg, .png))] random.shuffle(imgs) n_val int(len(imgs) * 0.2) for i, name in enumerate(imgs): line f{cls_name}/{name} {label}\n (val_lines if i n_val else train_lines).append(line) with open(train.txt, w) as f: f.writelines(train_lines) with open(val.txt, w) as f: f.writelines(val_lines) print(ftrain{len(train_lines)}, val{len(val_lines)})这段逻辑说明类别名排序决定 label 索引训练和推理必须用同一套排序每类独立按 20% 切验证比全局随机更稳。做完这步把 config 的 num_classes 改成你的类别数训练管线就能直接复用。注意切出来的 val.txt 里每个类别都要有样本如果某类一共只有 3 张图切完验证集可能只剩 2 张训练图这种类别要么补数据要么合并到相近类。6.2 用 F1 和混淆矩阵收口验证训完以后不要只看 acc 就收工。写一个验证脚本统计每类 F1 和混淆矩阵找出互相混的类别——水稻稻瘟病和胡麻斑病在叶片上本来就长得像这类混淆是模型的合理错误也是答辩时能讲清楚的故事。迭代顺序固定为加数据 → 调增强 → 调 lr → 换更大模型。从那以后我每次拿到新数据集都会强制走一遍「生成清单 → 跑 20 epoch 验证通路 → 看 F1 明细 → 再调参」这个循环不再凭感觉直接把大模型怼上去。这份基于 python 的农作物病虫害识别分类源码包真正值钱的不是某个权重文件而是这套能反复换数据、换模型的训练框架下载下来按上面的顺序复现一遍比收藏一百个教程都有用。希望帮到你。本文还有配套的精品资源点击获取
返回列表