
简介面向计算机专业毕业设计、课程设计与项目实战学习者的完整可运行资源包围绕Python农作物病虫害识别与分类任务提供模型训练、验证及推理所需全部代码。资源压缩包共96个文件以76个py源码文件为主涵盖CNN含CNLNet变体及EfficientNet、ResNet、Vision Transformer、Swin Transformer等多种视觉模型实现配套15个pyc编译模块、训练日志与说明文档整体约25.1MB。项目已调试可直接运行数据集与演示程序一并提供便于快速复现识别分类流程并开展实验对比。资源已吸引两千余人学习适合需要完整项目源码支撑毕业设计、课程作业或深度学习图像分类练习的读者使用。1. 基于python的农作物病虫害识别分类项目源码先搞清楚它到底帮你解决什么问题手机拍一张水稻叶片照片几秒后屏幕上跳出“稻瘟病置信度0.93”。这不是农业专家系统里的演示视频而是现在一个用Python写的图像分类工程能做到的基础效果。基于python的农作物病虫害识别分类项目源码核心就是拿卷积神经网络CNN对作物叶片图像做分类把“这是什么病”从肉眼经验变成可重复、可量化的判断。压缩包里通常包含三块东西模型源码、整理好的图像数据集、一份讲怎么跑起来的使用说明。很多人下载后急着训练结果卡在文件路径、依赖版本和数据划分上折腾两天连第一次epoch都没跑完。这个项目的真正难点不是“把模型跑起来”而是让模型在真实农田环境里可靠。田间照片的光照、泥土、拍摄角度都比公开数据集复杂得多识别系统必须能区分“病斑”和“虫咬”、“缺素”和“药害”。如果你是有Python基础的学生、做农业信息化的工程师或者想验证边缘设备推理方案的硬件玩家这个方向值得投入。它把图像分类、迁移学习、数据集工程三个常见需求串在了一个完整的项目里既能当毕业设计也能当企业原型的起点。2. 拿到压缩包先别急着训练看懂源码、数据与说明的分工2.1 解压后我一般先找这几个入口train.py、predict.py、requirements.txt一个规范的源码包目录往往会分成源码、数据、模型产物和文档四块。我先给一个最常见的布局不同项目名字可能不同但套路基本一致crop_pest_project/ ├── src/ │ ├── train.py # 训练脚本负责加载数据、训练模型、保存权重 │ ├── predict.py # 推理脚本读入单张图片并输出类别和置信度 │ ├── model.py # 模型定义常见做法是封装ResNet/MobileNet │ ├── data_utils.py # 数据加载、数据集划分、预处理函数 │ └── config.py # 超参数和路径配置集中修改的地方 ├── data/ │ ├── images/ # 按类别分目录存放的图片 │ └── labels.csv # 可选如果源码不按目录读取则用标签文件 ├── models/ │ └── best_model.pth # 训练产物通常不在下载包里需自己生成 ├── docs/ │ └── 使用说明.md └── requirements.txt # 用pip安装的依赖清单想快速判断这个项目能不能用不要先看readme先看三个文件train.py里数据是怎么读的、requirements.txt里有哪些依赖、config.py里默认的数据路径和类别数。这三个点能决定你按使用说明跑一次能不能成功。很多源码包里的路径写的是作者本机的绝对路径比如/home/user/data到你电脑上一跑就报文件不存在。这不是bug是路径没适配后面我会专门讲。如果压缩包里没有requirements.txt就去看使用说明里列出的依赖。常见组合有两种PyTorch系的torch/torchvision/numpy/opencv-python/scikit-learn/matplotlib或者TensorFlow系的tensorflow/keras。我偏好开头先确认框架再做环境安装避免硬编码的模型权重文件在两套框架之间换不过来。2.2 环境搭建用虚拟环境把依赖锁死避免“我机器上能跑”农业识别项目经常会在不同机器之间拷贝最怕某台机器已经装了老版本的numpy把新代码的API调用带崩。我拿到这类源码的第一件事永远是新建一个虚拟环境而不是直接往全局环境里装python -m venv venv source venv/bin/activate # Windows下用 venv\Scripts\activate pip install --upgrade pip pip install -r requirements.txtvenv会把Python解释器和依赖包都隔离在当前目录下版本冲突不会扩散到系统环境。如果项目代码是基于PyTorch的我会优先装CPU版还是GPU版开发阶段先装GPU版因为病虫害图像动辄上万张用CPU跑一个完整的epoch会让人失去耐心。但要注意torch和torchvision的版本需要配套更新如果先用pip装了最新版torchvision再装旧版torch很可能导入时报torchvision找不到匹配的算子。建议先看使用说明里写了哪类依赖组合比如它明确要求torchvision就用同一套索引安装。安装完后验证一下python -c import torch, torchvision; print(torch.__version__, torchvision.__version__)这一步能过滤掉一大半“明明装了却导入失败”的问题。另外注意requirements.txt里如果出现了opencv-contrib-python和opencv-python同时安装会导致cv2的接口混乱只保留其中一个即可。图像分类项目用opencv-python就够了除非源码里调用了sift之类的contrib函数。2.3 准备一份最简配置数据路径、类别数、输出目录大部分训练脚本都会引用一个配置文件。我习惯把路径、类别、学习率等集中在一个地方这样调参和换数据都很方便。常见的config.py长这样import os # 数据根目录按类别分目录的图片都放在这个文件夹下 DATA_ROOT data/images # 训练完成后保存权重文件的目录 SAVE_DIR models # 类别数量有几类病虫害就填几类 NUM_CLASSES 15 # 图像统一缩放尺寸迁移学习常用224x224 IMG_SIZE 224 # 训练超参数 BATCH_SIZE 32 EPOCHS 30 LEARNING_RATE 1e-3 WEIGHT_DECAY 5e-4 # 如果使用GPU设置设备没有GPU则回退到CPU DEVICE cuda if os.environ.get(USE_GPU, 1) 1 else cpu这段配置里最值得注意的是DATA_ROOT和NUM_CLASSES。很多源码包默认的类别数是固定写死在你下载的数据集上的如果你自己新增识别对象比如把“健康叶片”也放进训练集就必须同步修改NUM_CLASSES否则模型最后一层全连接输出维度对不上训练时直接报维度错误。IMG_SIZE也不是越大越好迁移学习用的预训练模型大多在224×224或256×256分辨率下表现稳定盲目改成512会把显存和训练时间拉上去但准确率收益很小。3. 整理数据集病虫害识别最花时间的一步也是模型上限的决定因素3.1 标签目录结构用ImageFolder直接读省掉手写标签图像分类项目里最省事的组织方式就是根目录下面按类别建子文件夹每一类图片直接放进去。PyTorch的torchvision.datasets.ImageFolder可以直接扫这种目录自动把文件夹名映射成数字标签。不用手写CSV也不用自己写解析函数这对农业场景的快速迭代特别友好。from torchvision import datasets, transforms # 先定义基础的预处理Resize和Normalize稍后会细说 data_transforms transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) # 假设数据目录结构为data/images/稻瘟病/xxx.jpg, data/images/健康/xxx.jpg dataset datasets.ImageFolder(rootdata/images, transformdata_transforms) print(dataset.classes) print(dataset.class_to_idx)ImageFolder会把data/images下的每一个子目录当作一个类别类别的排序依据是目录名的字母顺序。这里有一个隐蔽的坑如果你自己的标注目录是中文名比如“稻瘟病”、“玉米叶斑病”ImageFolder仍然能读但打印出来的class_to_idx顺序是按中文编码排列的训练脚本里如果硬编码了“0号类别是健康”很容易和实际顺序对不上。我一般会把class_to_idx输出保存下来推理阶段加载模型时按同一个映射做预测让训练和部署的类别编号保持一致。另外dataset.classes的类别顺序会在训练和推理两条链路里被反复使用。如果某天你删掉了一个类别的目录重新训练后类别顺序全变了之前保存的权重基本作废。所以数据目录一旦定下来不要轻易改动结构。3.2 数据集划分避免同一株叶片同时出现在训练集和验证集训练集、验证集、测试集怎么切是病虫害识别项目里决定“假准确率”的关键。常见做法是先把数据集按类别做分层划分保证每个类别在三份数据里的比例接近而不是把整个目录随机打散后切三段。import os import random import shutil from collections import defaultdict def split_dataset(source_root, train_ratio0.8, val_ratio0.1): 按类别分层划分保留10%作为测试集。 划分后会创建train/val/test三个新目录。 class_dict defaultdict(list) for class_name in os.listdir(source_root): class_dir os.path.join(source_root, class_name) if not os.path.isdir(class_dir): continue for img_name in os.listdir(class_dir): class_dict[class_name].append( os.path.join(class_dir, img_name) ) for class_name, img_list in class_dict.items(): random.shuffle(img_list) total len(img_list) train_end int(total * train_ratio) val_end int(total * (train_ratio val_ratio)) for split_name, split_list in [ (train, img_list[:train_end]), (val, img_list[train_end:val_end]), (test, img_list[val_end:]) ]: out_dir os.path.join(source_root, split_name, class_name) os.makedirs(out_dir, exist_okTrue) for img_path in split_list: shutil.copy2(img_path, out_dir)这段代码背后的逻辑是先按类名分组再把每一组的图片随机打乱按比例切成三段。这样做的好处是样本数量少的类别不会因为随机切分导致某些类别在验证集里没有数据。比如“稻曲病”只有200张如果你对全部图像做全局随机切分分到验证集的可能只有十几张甚至一张都没有。分层划分能保证每个类别在训练和验证里都保持大致相同的占比。另一个需要警惕的问题在代码里不直接体现同一株作物在不同角度拍下的多张照片可能分布在了训练集和验证集里。因为脚本只按“路径是否相同”去重并不会识别图像内容是否来自同一个样本。如果模型在训练集里见过某一个病斑的近距离特写又在验证集里看到同一病斑的远景图验证准确率会虚高。这类同源污染的解决办法是划分之前先按“拍摄时间地块”去重或者把来自同一目录连续编号的图片放进同一个分片里。项目里如果时间来不及至少要记住任何划分都不能保证绝对干净最后的测试集尽量用另一个来源的图片。3.3 预处理和数据增强病斑纹理比普通分类更怕过度增强图像分类的预处理一般分三步缩放到统一尺寸、转Tensor、做标准化。标准化用的均值和标准差来自ImageNet预训练模型的统计值迁移学习时沿用这套归一化参数能让预训练权重直接生效。病虫害识别里更值得关注的是数据增强。from torchvision import transforms train_transforms transforms.Compose([ transforms.RandomResizedCrop(224, scale(0.7, 1.0)), transforms.RandomHorizontalFlip(p0.5), transforms.RandomRotation(15), transforms.ColorJitter(brightness0.2, contrast0.2, saturation0.2), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) val_transforms transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ])注意验证集的增强只做缩放和中心裁剪不做随机翻转、旋转和颜色抖动因为验证集要尽量接近真实推理时的输入分布。如果验证集也做了RandomRotation同一张图每次验证的结果都不一样你就很难判断模型是变好了还是运气变好了。数据增强参数怎么调我付出血泪经验的结论是不要一味追求和通用分类比赛一样的增强强度。病斑纹理是识别的主要线索旋转15度以内可以模拟叶片姿态差异但如果把RandomResizedCrop的scale下限调成0.4模型很容易只看到叶片边缘的绿色区域病斑特征反而被裁掉了。ColorJitter的亮度对比度也不能太过田间光照虽然变化大但过度改变颜色会让模型把“黄化”和“正常老叶”搞混。常见的做法是先用轻度增强等看训练集损失已经很低而验证集损失偏高时再加一点旋转或裁剪来对抗过拟合。参数建议先按下面这个范围起步增强操作推荐范围使用注意RandomResizedCropscale(0.7, 1.0)低于0.5容易丢病斑RandomRotation10~20度旋转过大破坏叶脉走向ColorJitter亮度/对比度0.2左右过高容易混淆黄化症状RandomHorizontalFlip概率0.5叶形对称类病害可用4. 训练识别模型迁移学习、训练循环与参数选择4.1 模型选型ResNet、MobileNet还是从零搭一个CNN病虫害识别属于典型的细粒度图像分类类内差异大类间差异小。同样都是叶斑病有的病斑是圆形的有的是不规则形的不同病害之间的边界又很模糊。从零搭一个三层CNN很容易在训练集上过拟合因为它没有预训练知识只能靠少量农业图像硬学纹理特征。我一般不会这么做。更可靠的做法是直接加载在ImageNet上预训练过的分类模型把最后一层全连接换成本项目的类别数然后做迁移学习。常用选择是两个方向ResNet18/ResNet50偏重识别精度MobileNetV3偏重模型体积和推理速度。模型参数量级推理速度典型场景ResNet1811M级快服务器或PC端效果优先ResNet5025M级中等精度要求高且有GPUMobileNetV35M级快边缘设备和手机端EfficientNetB05M级快精度和速度相对均衡如果压缩包里的model.py已经写了某个模型我会先保留它的默认结构避免改了网络后加载不了预训练权重。只有在默认模型跑通后再替换成MobileNetV3验证边缘部署的可行性。import torch import torch.nn as nn from torchvision import models def create_model(num_classes, model_nameresnet18): if model_name resnet18: weights models.ResNet18_Weights.IMAGENET1K_V1 model models.resnet18(weightsweights) # 替换最后一层全连接为当前项目的类别数 in_features model.fc.in_features model.fc nn.Linear(in_features, num_classes) elif model_name mobilenet_v3: weights models.MobileNet_V3_Large_Weights.IMAGENET1K_V1 model models.mobilenet_v3_large(weightsweights) in_features model.classifier[-1].in_features model.classifier[-1] nn.Linear(in_features, num_classes) else: raise ValueError(fUnsupported model: {model_name}) return model核心逻辑是保留预训练模型从输入到倒数第二层学到的通用特征提取能力只替换最后的分类头。这样即使你的病虫害数据只有几千张模型也不会崩溃式过拟合。替换fc或classifier[-1]前必须先读出原来层的in_features否则写死的输入维度会和预训练权重对不上。4.2 训练脚本骨架从数据加载到模型保存有了模型接下来要把完整训练流程串起来。这个流程几乎在所有图像分类项目里通用我按照一个可复现的最小训练脚本来写import torch import torch.nn as nn from torch.utils.data import DataLoader from torchvision import datasets, transforms from model import create_model from config import DATA_ROOT, SAVE_DIR, NUM_CLASSES, BATCH_SIZE, EPOCHS, LEARNING_RATE, DEVICE def main(): # 1. 数据加载 train_transform transforms.Compose([ transforms.RandomResizedCrop(224), transforms.RandomHorizontalFlip(), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) train_ds datasets.ImageFolder(rootDATA_ROOT /train, transformtrain_transform) val_ds datasets.ImageFolder(rootDATA_ROOT /val, transformval_transform) train_loader DataLoader(train_ds, batch_sizeBATCH_SIZE, shuffleTrue, num_workers4) val_loader DataLoader(val_ds, batch_sizeBATCH_SIZE, shuffleFalse, num_workers4) # 2. 模型与损失函数 model create_model(NUM_CLASSES, model_nameresnet18).to(DEVICE) criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lrLEARNING_RATE) scheduler torch.optim.lr_scheduler.StepLR(optimizer, step_size10, gamma0.1) # 3. 训练循环 best_acc 0.0 for epoch in range(EPOCHS): model.train() running_loss 0.0 for images, labels in train_loader: images, labels images.to(DEVICE), labels.to(DEVICE) optimizer.zero_grad() outputs model(images) loss criterion(outputs, labels) loss.backward() optimizer.step() running_loss loss.item() * images.size(0) scheduler.step() epoch_loss running_loss / len(train_ds) # 4. 验证 val_acc evaluate(model, val_loader, DEVICE) print(fEpoch {epoch1}/{EPOCHS}, loss{epoch_loss:.4f}, val_acc{val_acc:.4f}) # 5. 保存验证集上最好的模型 if val_acc best_acc: best_acc val_acc torch.save(model.state_dict(), f{SAVE_DIR}/best_model.pth) def evaluate(model, loader, device): model.eval() correct, total 0, 0 with torch.no_grad(): for images, labels in loader: images, labels images.to(device), labels.to(device) outputs model(images) _, preds torch.max(outputs, dim1) correct (preds labels).sum().item() total labels.size(0) return correct / total if __name__ __main__: main()这段脚本里比较重要的是scheduler.step()的位置。我用的是StepLR每10个epoch把学习率乘0.1这种策略能在训练后期把损失压得更低。如果你发现验证集准确率在某个区间震荡先检查是不是学习率没有下降。torch.save(model.state_dict())只保存模型参数不保存类别映射。所以训练完成后我会把dataset.class_to_idx单独存成一份JSON否则预测脚本很可能把“稻瘟病”输出成“健康”。4.3 训练时看什么loss曲线、验证准确率和混淆矩阵很多初学者训练时只盯着终端打印的loss看到数字在降就安心了。但loss降不代表模型在病虫害识别里好用。类别不均衡时模型只要输出频率最高的那个类loss就能很低。所以我会同时关注三个指标训练loss它下降缓慢说明学习率过低或模型容量不够下降后又反弹说明过拟合已经开始。验证准确率简单直观但类别不均衡时会失真所以要配合混淆矩阵看。每一类的召回率比如“玉米大斑病”识别得再好如果“玉米小斑病”老是分错整体准确率再高也没用。验证时算混淆矩阵用scikit-learn一行能完成from sklearn.metrics import confusion_matrix, classification_report import numpy as np all_labels [] all_preds [] model.eval() with torch.no_grad(): for images, labels in val_loader: images images.to(DEVICE) outputs model(images) _, preds torch.max(outputs, dim1) all_labels.extend(labels.cpu().numpy()) all_preds.extend(preds.cpu().numpy()) print(classification_report(all_labels, all_preds, target_namesdataset.classes)) print(confusion_matrix(all_labels, all_preds))classification_report会输出每个类别的precision、recall、f1-score。病虫害识别里我优先看recall因为漏诊比误诊更危险一个健康叶片被判成病害最多是农户多打一次药一个正在扩散的病害被漏掉可能整片田都受影响。如果某个类别的recall明显低于其他类别就要去检查它的样本数量和图像多样性而不是急着调模型结构。5. 病虫害识别项目常见问题排查从读图失败到“假准确率”5.1 报错FileNotFoundError中文路径、相对路径和目录结构不一致现象照着使用说明运行训练脚本加载数据集时报FileNotFoundError: [Errno 2] No such file or directory但文件夹明明存在。原因最常见的是三处不一致。第一源码里的数据路径是作者机器上的绝对路径换到你电脑后没改config.py。第二Windows系统下路径分隔符是反斜杠部分脚本在拼接路径时用/写死了虽然Python通常能兼容但一旦代码里混用了os.path.join和字符串拼接就会拼出无效路径。第三中文目录名在部分Linux环境下乱码尤其是压缩包在Windows解压后传到Linux服务器内码转换导致目录名对不上。解决先别改代码直接让Python告诉你它真实读取的路径是什么。在运行前执行python -c import os; print(os.path.abspath(data/images/train))如果这个路径不对就回到config.py把DATA_ROOT改成绝对路径或基于当前文件位置的相对路径。更稳妥的做法是不要依赖命令行启动时的工作目录在config.py里用os.path.dirname(__file__)定位项目根目录。5.2 训练loss很快降到0.1验证准确率却只有60%现象训练到第5个epoch训练集loss已经降到0.2以下但验证准确率一直在60%徘徊甚至不再增长。原因这是过拟合的典型信号。模型把训练集里的背景、拍摄位置、光照等偶然特征记住了却没有学到真正的病斑纹理。病虫害数据集的样本数量通常不多如果从头训练一个深层网络这种过拟合几乎无解。解决先换成预训练模型并冻结除最后一层外的参数做一次“只训练分类头”的快速实验如果验证准确率有明显提升再解冻部分层微调。另外把验证集和训练集的增强策略再检查一遍验证集一定不能有RandomResizedCrop或RandomRotation。最后可以调大WEIGHT_DECAY到1e-3或者提前结束训练。5.3 CUDA out of memory不是batch调小就万事大吉现象程序跑了一个epoch后在第二个epoch突然报CUDA out of memory代码本身没有改过。原因显存溢出不只是batch_size的关系。图像分辨率、DataLoader的num_workers、模型大小都会影响显存占用。训练开始时不溢出后来溢出往往是因为验证或测试阶段把整批数据一次性加载了而验证集图片和训练集不是同一批某个batch里包含了更大尺寸的图片。解决先把batch_size减半同时在DataLoader里加上pin_memoryTrue。如果还溢检查是否在不该开梯度的阶段开了梯度验证时加with torch.no_grad()。另外transforms.Resize((224,224))会在预处理阶段把图片都统一尺寸如果报错发生在数据加载阶段优先看是不是某个损坏图片解码后尺寸反常。5.4 类别不均衡导致模型只会猜“健康”现象训练结束后整体准确率有90%但检查分类报告发现“健康”这一类recall是98%某几种病害的recall不到30%。原因田间收集的数据天然不均衡健康叶片数量可能占了一半以上而某些病害样本只有一两百张。交叉熵损失会尽可能拟合多数类少数类对loss的贡献被稀释。解决最简单的办法是把训练集中的少数类做过采样或者用WeightedRandomSampler让每个batch里每个类别出现概率更均衡。我一般先用类别权重的损失函数from torch.utils.data import WeightedRandomSampler labels train_ds.targets class_counts torch.bincount(torch.tensor(labels)) weights 1.0 / class_counts.float() sample_weights weights[labels] sampler WeightedRandomSampler(sample_weights, num_sampleslen(labels), replacementTrue) train_loader DataLoader(train_ds, batch_sizeBATCH_SIZE, samplersampler)WeightedRandomSampler会按照样本权重的比例抽batch少数类每个epoch被抽到的次数更多。代价是模型可能对少数类过拟合需要在验证集上密切观察这一类别的recall而不是整体准确率。另一种做法是直接换损失函数如FocalLoss让模型更关注难分类样本但实现稍复杂我建议先过采样。5.5 验证集泄露同源照片让模型分数虚高现象训练时验证准确率达到95%信心满满地部署到真实农田结果准确率掉到70%。原因很大概率是数据划分时同一个病害样本的多张连续拍摄照片被同时分进了训练集和验证集。模型见过某个病斑的“近距离版”验证集里出现它的“远距离版”模型等于直接背下了答案。这在公开数据集的规范划分下不太常见但自己整理田间数据时很容易发生。解决划分数据集之前按照图片文件名里的拍摄编号做分组同一个编号的照片必须划进同一个集合。如果文件名没有规律可以按拍摄时间给图片分组。判断是否泄露的简单方法是看验证集准确率是否高到异常比如比训练集准确率还高或者比实际场景表现高出一大截。这时不要相信准确率要把几个典型样本打印出来人工检查。6. 实战技巧把训练好的模型变成一个能落地的识别工具模型训练好只是第一步真正要拿去田间试用还需要解决“预测时该信它多少”的问题。病虫害识别里最危险的输出不是分类错误而是模型在遇到没见过的症状时仍然强行给出一个高置信度结果。我习惯在预测脚本里加一个置信度阈值低于阈值就输出“未知建议人工复核”。import torch from torchvision import transforms from PIL import Image def predict_image(image_path, model, class_names, devicecpu, threshold0.5): transform transforms.Compose([ transforms.Resize(256), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) ]) image Image.open(image_path).convert(RGB) image_tensor transform(image).unsqueeze(0).to(device) model.eval() with torch.no_grad(): outputs torch.softmax(model(image_tensor), dim1) confidence, pred_idx torch.max(outputs, dim1) confidence confidence.item() if confidence threshold: return class_names[pred_idx.item()], confidence else: return 未知病害, confidence这段代码看着简单但很重要的一点是class_names必须和训练时的class_to_idx完全一致。我每次训练完都会把类别索引存成JSON预测脚本从JSON读而不是靠手敲。阈值threshold建议先用0.5再根据实际误报情况调。如果模型频繁把健康叶片识别成病害就把阈值提高到0.7反过来如果真实病害经常被拒识就降到0.3。还有一个进阶技巧把模型保存成torchscript或ONNX格式推理时不再依赖原始Python模型定义。特别是拿到边缘设备上用的时候ONNX的跨框架兼容性和推理速度都更稳。导出ONNX一次就够python -c import torch; model create_model(...); model.load_state_dict(torch.load(models/best_model.pth)); model.eval(); dummy torch.randn(1,3,224,224); torch.onnx.export(model, dummy, model.onnx)导出后最好用onnxruntime验证一次输出一致别等部署到现场才发现算子不兼容。我个人的习惯是把所有类别打印出来提前拍几张“模型应该不认识”的图片测阈值确认低置信度样本会不会被拒识。这比单纯调高准确率更接近田间使用的真实场景。栽过跟头才知道识别模型真正值钱的不是准确率小数点后两位而是它在没见过的环境里敢不敢说“我不知道”。希望这篇笔记能把你在下载压缩包后可能踩的坑提前填上让这个python项目真正成为能跑进田里的工具而不是停留在训练日志里的数字游戏。希望帮到你。本文还有配套的精品资源点击获取