简介:面向计算机相关专业毕业生与实战学习者的Python人工智能毕业设计项目,基于深度学习实现农作物病虫害识别,覆盖图像分类、模型训练与Web端展示等环节。压缩包共281个文件、约522.67MB,其中py源码对应模型训练与推理脚本,vue/js构成前端界面,jpg/png为农作物病害图像数据集,pdf/docx提供论文及查重版资料,txt、md等包含环境配置与使用说明,另有参考论文与技术路线图文档辅助理解系统架构。该项目曾获导师指导并认可,评审分98分,适合作为毕业设计、课程设计或期末大作业的完整参考。借助源码、论文资料及使用教程,可快速复现实验流程,并迁移到类似识别任务中。已有186人学习下载,对准备从事算法应用或Web端开发的初学者也有不错的参考价值。
1. 农作物病虫害识别项目源码:从看叶子到跑通一个完整工程
Python人工智能基于深度学习的农作物病虫害识别项目,是一套把“图像分类”技术落地到农业场景的完整工程包:源码负责把叶片照片训练成能区分多种病虫害的模型,论文资料负责把方法、实验和结果整理成课设或毕设文档,使用教程负责让你从零环境跑到第一个准确率。它不是“打开即用”的小工具,而是一条需要按数据准备、环境搭建、模型训练、评估导出完整走一遍的深度学习入门路径。适合正在做课设或毕设、想快速上手真实人工智能场景的人。下面按我实际带项目的顺序,把源码结构、环境搭建、训练调参、避坑排查和最终验证串起来讲。照着走,能少熬几个通宵。
2. 先看原理和选型:为什么病虫害识别做成图像分类而不是检测
拿到的源码表面上是一个“识别”项目,其实绝大多数实现路径都落在图像分类这个框架里:输入一张叶片照片,输出一个病害类别标签。之所以少有人直接做目标检测,是因为分类任务的数据标注成本低、模型容易收敛、论文实验也更好写。理解这个前提,你才知道训练脚本里为什么到处是CrossEntropyLoss、fc层和top-1 accuracy。
2.1 分类任务的基本管线:一张病叶图如何变成一组类别概率
病虫害识别的本质,是让模型从像素里找到病害在叶片上留下的纹理、颜色和形状特征。代码实现上,整个过程分成三段:预处理把任意尺寸的图片缩放到统一大小并转成张量;骨干网络逐层提取特征,从边缘、纹理到病斑区域;最后的分类头把特征压缩成和类别数相同的得分向量,再接 softmax 变成概率分布。训练时取概率最大的类别作为预测结果,并用交叉熵损失衡量预测分布和真实标签的差距。
下面是一段最常见的核心模型定义,几乎所有源码里都能看到类似写法:
import torch.nn as nn import torchvision.models as models class CropPestModel(nn.Module): def __init__(self, num_classes=20, backbone='resnet50'): super().__init__() # 载入在 ImageNet 上预训练过的 ResNet50 self.backbone = getattr(models, backbone)(pretrained=True) # 把最后一层全连接换成自己的分类头 in_features = self.backbone.fc.in_features self.backbone.fc = nn.Linear(in_features, num_classes) def forward(self, x): return self.backbone(x)这里真正关键的动作有两个。pretrained=True会下载在 ImageNet 上训练好的权重,让模型一开始就具备识别通用纹理和形状的能力,不从这里开始的话,模型等于从随机参数起步,数据量少时几乎无法收敛。替换fc层是为了把输出维度从 ImageNet 的 1000 类变成你自己的num_classes,这个数字必须和数据集类别文件夹数量严格一致,否则训练时维度对不上会直接报错。
num_classes在源码里经常被写成 10、15、20 这种固定值,并不是所有项目都能直接帮你数好。换数据集时第一件事就是改这里,改完再同步检查类别映射列表的顺序,因为 PyTorch 的ImageFolder会自动按文件夹名排序生成标签,排错一个就全错位。
2.2 迁移学习和预训练权重:数据量越少越要“站在巨人的肩膀上”
病虫害公开数据集规模通常不大,常见课程设计场景下也就几千张图,自己拍照甚至只有几百张。在这种规模下从零训练一个深层卷积网络,几乎必然过拟合,验证集准确率上不去。所以这套源码的核心设计思路就是迁移学习:先让模型在 ImageNet 上学会各种通用图像特征,再拿到病虫害数据上微调。
微调策略一般分两步走。第一步冻结骨干网络所有参数,只训练新替换的分类头,用 1e-3 左右的学习率跑十几轮,让分类头先学会在通用特征上区分具体病害。第二步解冻部分高层卷积层,用更小的学习率整网微调。到底解冻多少层,是源码里最值得调的参数,常见做法是只解冻最后一个残差块,函数写出来长这样:
def freeze_backbone(model, freeze_until='layer3'): for name, param in model.named_parameters(): if name.startswith('backbone.'): # 从 'backbone.layer3.0.conv1.weight' 里提取层编号 layer_name = name.split('.')[1] # 例如 'layer3' layer_num = int(layer_name.replace('layer', '')) if layer_num <= int(freeze_until.replace('layer', '')): param.requires_grad = False这段代码遍历所有参数,把 layer3 之前的卷积层全部设为不可训练,只让 layer4 和分类头参与更新。需要特别注意的坑是:这个函数必须在创建 optimizer 之前执行。PyTorch 的优化器在初始化时只收集requires_grad=True的参数,如果你先建了优化器再冻结,那些参数依然会被更新,很多人复现时梯度爆炸就是栽在这里。
预训练权重会不会让模型直接记住 ImageNet 里的类别?不会,因为预训练的最后一层已经被替换掉了,骨干网络只提供通用的特征提取能力,病害特征是在微调阶段重新学出来的。只要确保加载权重前fc层已经换成了你自己的分类头,就不会有维度冲突的问题。
2.3 源码目录与核心模块:train.py、utils.py、config.py 各管什么
拿到源码先别急着运行,花十分钟读一遍目录比什么都值钱。一个规范的病虫害识别项目,文件组织大致是这个样子:
crop_pest_project/ ├── data/ │ ├── train/ │ │ ├── apple_black_rot/ │ │ ├── apple_healthy/ │ │ └── ... │ ├── val/ │ └── test/ ├── src/ │ ├── train.py # 训练入口,负责数据加载、训练循环和保存权重 │ ├── predict.py # 单图推理脚本 │ ├── config.py # 集中管理路径、超参数和类别映射 │ └── utils.py # 数据增强、评估指标、日志记录 ├── weights/ # 训练好的模型权重 ├── requirements.txt └── README.mdtrain.py 是整个项目的核心,通常先解析命令行参数,再从 config.py 读默认配置,接着创建 DataLoader、模型、优化器和学习率调度器。config.py 是改参数的第一站,数据路径、图片尺寸、batch size、学习率、训练轮数基本都集中在这里,而不是散落在 train.py 的各个角落。
utils.py 里藏着最容易被忽略但影响最大的部分:transform 定义、早停逻辑、模型保存与加载、混淆矩阵统计。我见过不止一个项目,训练脚本看起来写得很完整,但 utils.py 里的类别顺序和 train.py 里不一致,导致训练时标签对不上,loss 一直高位横盘。所以换数据集时,一定要把 utils.py 里的类别列表和文件夹顺序整体对齐一遍。
提示:拿到项目的第一个动作是读 README,第二个动作是看 requirements.txt,然后再碰 train.py。绝大多数复现问题不是代码写错,而是环境或数据目录没有按 README 的预期摆放。
骨干网络的选择也在这个阶段定下来。ResNet50、EfficientNet、MobileNet 是源码里最常见的三个候选,差异可以用一张表概括:
| 骨干网络 | 参数量 | 收敛稳定性 | 典型用途 |
|---|---|---|---|
| ResNet50 | 中等 | 稳定,参考资料最多 | 课设/毕设默认选择 |
| EfficientNet-B0 | 偏小 | 数据量小时容易欠拟合 | 小数据集、追求均衡 |
| MobileNetV3 | 小 | 快但精度略低 | 后续要部署到嵌入式设备 |
我一般默认先跑 ResNet50,不是为了性能,而是因为它的训练曲线平稳、报错信息容易搜、论文里找对比实验也方便。等你把项目整体流程跑通,再换其他骨干网络才不慌。
3. 从零跑通源码:环境搭建、依赖安装与第一条训练命令
环境问题占掉了初学者一半以上的报错时间,而且报错信息五花八门:缺库、版本冲突、CUDA 不可用、torch 和 torchvision 版本不匹配。这一章按我日常带项目的方式,把环境搭建的关键步骤拆开讲,照着做可以少走很多弯路。
3.1 先建虚拟环境:Python 安装与 conda 指令
很多新手直接在系统 Python 里用 pip 装包,装完这个项目后,另一个项目的依赖就冲突了,最后只能重装系统。正确姿势是给这个项目单独建一个虚拟环境,我习惯用 Anaconda:
conda create -n pest python=3.8 conda activate pest python --version第一行pest是环境名,随意取;python=3.8指定解释器版本。3.8 对大多数病虫害识别源码兼容性最好,如果你的源码明确要求 3.9 或 3.10,按它的要求来就行,不要贪新用 3.12。执行完conda activate pest之后,所有 pip 包都会装进这个隔离环境,后面出了乱子,直接conda remove -n pest --all重来,这是整个项目最好的后悔药。
在 Windows 上安装 Anaconda 后,建议从开始菜单里打开 “Anaconda Prompt”,不要直接在 CMD 里敲命令,因为 conda 可能不在 PATH 里。激活成功后,命令行前面会出现(pest)前缀,这表示你已经进入虚拟环境。如果没出现,说明激活失败,需要先执行conda init再重新打开终端。
3.2 requirements 与 CUDA 版本:先装对 PyTorch 再装其他
requirements.txt里列的多半是 torch、torchvision、numpy、pillow、scikit-learn、matplotlib、tqdm 这几类。最容易出问题的不是 numpy 或 pillow,而是 torch 和 torchvision 的版本匹配,以及它们和本机显卡驱动支持的 CUDA 版本是否对得上。如果直接pip install -r requirements.txt,pip 默认拉的是 PyTorch 官方最新的版本,大概率和你本机的 CUDA 环境不配套,训练时彻底用不上 GPU。
常见做法是分成两步。先看nvidia-smi确认显卡驱动支持的最高 CUDA 版本,再装对应版本的 PyTorch,最后才装其他依赖:
# 查看显卡驱动支持的 CUDA 版本 nvidia-smi # 以 CUDA 11.8 为例,安装对应版本的 torch pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 再安装项目剩余依赖 pip install -r requirements.txtnvidia-smi里显示的 CUDA Version 是驱动支持的最高版本,你装的 PyTorch CUDA 版本只要不高于它就能正常运行,并不需要额外安装完整的 CUDA 工具包。如果你的机器没有 NVIDIA 显卡,就直接装 CPU 版:
pip install torch torchvision代码完全不用改,只是训练速度慢几倍,课设规模的数据集也能等得起。装完后可以先跑一行python -c "import torch; print(torch.cuda.is_available())",输出 True 说明 GPU 可用,输出 False 也先别慌,看看是不是装到了 CPU 版。
3.3 第一条训练命令:先做冒烟测试再正式开跑
环境就绪后,不要一上来就完整训练。我习惯先跑一次极小规模的“冒烟测试”,只跑两三个 epoch,确认数据加载、前向传播、反向传播、日志打印全都通顺,再中断掉重新正式训练。
python src/train.py \ --model resnet50 \ --pretrained \ --data ./data \ --epochs 3 \ --batch-size 8 \ --lr 0.001--pretrained表示加载预训练权重,没有它模型从随机参数开始训练,需要几十倍数据量才能收敛,冒烟测试的意义在于验证链路而不是关注精度,所以一定带上。--epochs 3只跑三轮,正常情况下两三轮就能看到 loss 明显下降。--batch-size 8是照顾小显存显卡,正式训练时根据显存大小调到 16 或 32;如果显存足够也不用一上来就拉满,batch size 翻倍会显著改变收敛速度,最好先用默认值跑通。
如果输出里每个 epoch 结束后 loss 都在下降,哪怕从 1.8 降到 1.5,也说明整套链路通畅。这时中断训练,把--epochs改成 50 到 100,--batch-size调大,正式开跑。
注意:训练日志里如果出现 loss 一直停在 2.3 或 3.0 这种水平,准确率也不动,问题大概率不在环境,而在标签或数据,后文第五章会专门讲这个。
4. 换成自己的病虫害数据集:文件夹结构、数据增强与调参
源码自带的示例数据往往只是验证流程用的,真正做课设或参与比赛时,你几乎一定要换成自己的图片。这一步涉及数据组织、划分、增强和超参数调整,是整个项目里最花时间的部分,也是最容易出隐性错误的地方。
4.1 文件夹结构即标签:丢进 ImageFolder 前的准备工作
PyTorch 的torchvision.datasets.ImageFolder是最省事的数据加载方式,它不需要你写 csv 或 json 标注文件,直接把文件夹名字当作类别标签。前提是目录必须按规范摆放:
./data/train/apple_black_rot/001.jpg ./data/train/apple_healthy/001.jpg ./data/val/apple_black_rot/001.jpg ./data/val/apple_healthy/001.jpg核心原则是训练集和验证集完全分开,验证集里绝对不能出现训练集用过的同一张照片。如果图省事把所有图片放在一个大文件夹里让源码自己划分,至少要用下面的方式做分层抽样,保证每个类在验证集里都有一定比例:
from sklearn.model_selection import train_test_split import glob images = glob.glob('./data/all/*/*.jpg') labels = [img.split('/')[-2] for img in images] train_files, val_files = train_test_split( images, test_size=0.2, stratify=labels, random_state=42 )stratify=labels的意思是按类别比例抽样,防止某些罕见病类别在验证集里只剩一两张,那样验证准确率会抖动成心电图。random_state=42固定随机种子,保证每次划分结果一致,这样后来改代码、换参数时,还能和之前的实验结果公平对比。
图片格式方面,jpg、png 都行,但要注意有些源码会预先要求图片全部转成 RGB 三通道。如果数据集里混入灰度图或带透明通道的 png,加载时可能报通道数不匹配,最常见的处理方式是在读取时统一转成 RGB。
4.2 数据增强与切分:训练集、验证集、测试集设计
病虫害图片的实际拍摄场景往往光线不均、背景杂乱、叶片角度多变,模型如果只在干净背景上训练,实际应用时很容易翻车。数据增强是缓解这个问题最直接的手段,源码的 utils.py 里通常会定义好一套 transform:
from torchvision import transforms train_transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.RandomHorizontalFlip(), transforms.RandomAffine(degrees=10, translate=(0.05, 0.05)), transforms.ColorJitter(brightness=0.2, contrast=0.2), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ]) val_transform = transforms.Compose([ transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ])几个参数值得解释清楚。Resize((224, 224))是绝大多数预训练模型的默认输入尺寸,改了之后要连模型一起改,否则预训练权重用不上。RandomAffine(degrees=10, translate=(0.05, 0.05))做小角度旋转和轻微平移,模拟拍摄时角度的自然偏差;ColorJitter调整亮度和对比度,对应不同光照条件。归一化的四个数分别是 ImageNet 数据集的均值和标准差,这是预训练模型的标准配方,不要随便改。
关键区别在验证集:只能做 resize 和归一化,绝不能加随机翻转或色彩变化,否则验证分数会虚高,因为你等于把验证集也“增强”出了变体,模型对同一张图的多个版本做预测,结果自然偏乐观。测试集同理,保持和验证集一样的 transform。
4.3 超参数怎么调:batch size、学习率、权重衰减
在数据组织好之后,影响训练结果最大的三个超参数分别是 batch size、学习率和权重衰减。batch size 主要受显存限制,太小梯度噪声大,loss 波动明显,收敛不稳定;太大容易显存溢出,也可能让模型收敛到尖锐极小值,泛化能力下降。常见做法是从 32 开始试,溢出就减半,减到 16 或 8,直到能稳定跑完一个 epoch 为止。如果机器显存够,也只是在这个区间里微调,不要追求过大的 batch。
学习率是微调阶段最重要的参数。预训练模型对学习率非常敏感,分类头新换的层可以给稍大的学习率,骨干网络里解冻的层必须用小学习率,否则预训练特征会被破坏。源码如果不支持分层设置,可以手动构造两组参数传给优化器:
optimizer = torch.optim.AdamW([ {'params': model.backbone.parameters(), 'lr': 1e-5}, {'params': model.backbone.fc.parameters(), 'lr': 1e-4}, ], weight_decay=1e-4)weight_decay是权重衰减,相当于 L2 正则,能有效抑制过拟合,AdamW 默认 1e-4 到 5e-5 是常见区间。如果训练后期 loss 在最优解附近来回震荡不收敛,可以配合学习率调度器每 10 个 epoch 把学习率乘 0.1,让训练过程稳定下来。很多人忽略的一点是:学习率不是越大训练越快,预训练模型里它只决定你有多克制地更新特征,学会用小学习率,远比学会调大学习率重要。
4.4 评估与保存:准确率之外还要看混淆矩阵
训练结束后,只盯着最后的准确率是远远不够的。病虫害数据通常类别不均衡,健康叶片和常见病的样本数量远多于罕见病,模型只要把所有样本都预测成多数类,准确率也能达到百分之七八十。这种情况下你必须看每个类别自己的 precision、recall 和 F1,源码里一般会集成 sklearn 的工具函数:
from sklearn.metrics import classification_report print(classification_report(y_true, y_pred, target_names=class_names))classification_report会逐类打印精确率和召回率,哪个病完全没学会一目了然。如果发现某个类的 recall 是 0,典型就是类别不平衡问题,第五章会讲对应的解决办法。
模型保存也值得注意,不要只存裸的 state dict。部署阶段你需要类别映射、输入尺寸、transform 配置,否则权重拿出去根本不知道该怎么用。建议保存成一个字典:
torch.save({ 'state_dict': model.state_dict(), 'class_names': class_names, 'input_size': 224, }, './weights/best_model.pth')这种保存方式的另一个好处是,换了机器或换了项目,只要加载时把class_names拿出来和你当前数据集的类别顺序比对一下,就能立刻发现标签错位问题。
5. 避坑:病虫害识别项目最常见的 5 个翻车现场与排查方法
这一章专门说踩坑记录。每一条都是实际训练中反复出现过的,按“现象、原因、解决”的顺序写,你可以直接对照自己的情况排查。
5.1 loss 卡在高位不动,准确率像抛硬币
现象:训练多个 epoch,loss 一直停在 2.3 或 3.0 这种接近随机猜测的水平,准确率始终在 10% 到 30% 徘徊。
原因:最常见的是标签和输入没有对齐。torchvision.datasets.ImageFolder会按文件夹字典序生成标签索引,如果你的类别名字带大小写差异或前缀数字,排序结果会和你的预期不同。另一种常见原因是num_classes与实际类别数不一致,模型输出的概率分布长度错了,loss 再怎么优化也找不到正确方向。还有一种隐蔽情况:数据增强里对图像做了错误的归一化,像素值范围被压缩到接近零,网络提取不到有效特征。
解决:先打印一个 batch 的labels.unique(),确认类别数等于num_classes;再画一张增强后的图像看看,确认它没有变成全黑或全灰。这两步能排除掉八成以上的“loss 不动”问题。
5.2 显存溢出:CUDA out of memory
现象:训练刚开始就报RuntimeError: CUDA out of memory,或者跑了一两个 epoch 才突然爆掉。
原因:batch size 设置过大、输入图片分辨率过高、DataLoader 的num_workers开太多,或者同一张显卡上同时跑着其他进程。很多源码默认把输入尺寸设成 256 或 512,显存占用比 224 高出一倍不止。
解决:优先把 batch size 减半,直到能跑为止;把Resize从 256 改回 224;num_workers设成 2 或 4 就够了,不要盲目拉高。运行nvidia-smi查看显存占用,确认没有其他训练任务占着显存。如果 batch size 已经小到 8 还是溢出,检查图片是否意外包含了非常大的长宽比,考虑换成 MobileNet 这种轻量骨干。
5.3 小数据集严重过拟合:训练集升到 98%,验证集只有 70%
现象:训练集准确率稳步爬升到接近满分,验证集却卡在 70% 上下浮动,或者验证曲线像锯齿一样剧烈抖动。
原因:数据量太少,模型把训练集的背景、叶片角度、光照等无关特征一起记了下来。很多学生自己拍照,每个类只有三五十张图,网络参数量远大于样本量,过拟合几乎是必然的。
解决:加大数据增强强度,把RandomRotation的角度适当调大,或者引入 Mixup、CutMix 这类数据混合增强;把训练轮数降低一半,配合早停,在验证集不再提升时及时中断。另一个关键改进是切分时做分层抽样,保证每个类别在验证集里有足够样本,否则验证集曲线必然抖成心电图。
5.4 类别不平衡:少数类预测全为 0
现象:classification_report 里健康叶和常见病的 F1 值很高,某个罕见病的 precision 和 recall 全是 0,准确率看着还行,但那个病等于完全没学会。
原因:病虫害数据集天然不平衡,罕见病样本量只有常见病的十分之一甚至更少。网络为了最小化整体 loss,倾向于把所有样本都判成多数类,少数类被完全忽略。
解决:给损失函数加类别权重,权重按1 / 每类样本数归一化:
num_samples_per_class = [300, 120, 40, 10] total = sum(num_samples_per_class) class_weights = torch.tensor( [total / (len(num_samples_per_class) * n) for n in num_samples_per_class] ) criterion = nn.CrossEntropyLoss(weight=class_weights.to(device))或者在 DataLoader 里使用WeightedRandomSampler,让每个 epoch 中少数类的采样次数提高。两种方法可以同时用,但先加 loss 权重即可,因为改动最小,不会影响数据加载逻辑。
5.5 论文资料和源码版本对不上:实验结果无法复现
现象:论文资料里写准确率 92%,你按源码跑出来只有 85%,反复调参也追不上,答辩时可能被质疑数据造假。
原因:作者写论文时用的数据划分、随机种子、训练轮数和源码默认值可能不一样,这才是“对不上”的真相。源码经过多次迭代后,README 里的描述往往滞后于实际代码,特别是训练轮数和数据划分方式,这两个参数对最终准确率影响巨大。
解决:训练前把所有关键配置记录下来:数据文件数、train/val 划分比例、随机种子、初始学习率、epoch 数,全部写进一个训练日志文件。先把项目自带样例数据跑通,确认和你拿到的示例结果一致,再换自己的数据。论文里如果出现训练曲线,和你跑出来的曲线形状对比一下,而不是只看最终数字。实在对不齐,就以自己实际跑出来的结果写论文,这个结果经得起复现,比硬凑论文数字安全得多。
6. 让模型真正能用:单图预测、PR 曲线与论文实验表
训练完成并不等于项目交付。我自己验收模型时,从来不对着训练日志鼓掌,而是找一个没参与训练的真实场景图片去测。这里分享一个我自己常用的单图推理脚本,以及把实验结果写进论文的补充思路。
6.1 自己写一个 predict 脚本:把模型从“能跑”变成“能用”
源码里的 predict.py 有时只是简单地打印类别名,远远不够用。建议自己写一段推理逻辑,同时输出前两个候选概率:
from PIL import Image import torch def predict_one(model, img_path, class_names, transform, device): img = Image.open(img_path).convert('RGB') tensor = transform(img).unsqueeze(0).to(device) model.eval() with torch.no_grad(): prob = torch.softmax(model(tensor), dim=1)[0] top2 = prob.topk(2) for idx, score in zip(top2.indices.tolist(), top2.values.tolist()): print(f"候选 {class_names[idx]}: {score:.4f}")这段脚本里“top-2”不是敷衍,因为很多病虫害的早期症状在视觉上非常相似,比如番茄早疫病和晚疫病,农技人员肉眼判断也容易犹豫。如果模型给出的第一候选和第二候选概率接近,说明它捕捉到了真实特征;如果第一候选自信爆棚但实际是错的,那模型可能是在偷懒,学到了背景特征。
6.2 用 PR 曲线和混淆矩阵撑起论文实验表
论文实验部分只写一个“准确率 92%”是不够的,答辩时一句“你的模型是不是只对训练集有效”就能问住你。建议在实验表里补两张图:每类别的混淆矩阵和 PR 曲线。混淆矩阵能直观展示哪两个病容易被互相混淆,PR 曲线则能说明模型在不同置信度阈值下的表现。用 sklearn 就能生成,不需要额外依赖。
做这两个图时注意:要在测试集上生成,而不是验证集,并且测试集从训练开始就不要碰,等所有调参结束后再测一次。如果论文要求提供源码和数据说明,把数据划分时的随机种子、增强参数、backbone 和训练轮数写清楚,让读者能按同样的条件复现。
这是我自己带项目养成的习惯:每次训练前先把测试集放一边,测试集只出一次结果,写进论文,之后无论怎么调参都不再碰它。这样做出来的实验数据,比反复调整得到的“最好看数字”可信得多。希望帮到你。
本文还有配套的精品资源,点击获取