资讯动态

VGG-16复现马铃薯病害识别

发布时间:2026/9/4 13:22:19 来源:尧图企业网站定制
我的环境语言环境Python 3.12.7编译器jupyter notebook深度学习环境TensorFlow 2.18.0PyTorch version: 2.5.1cu118Torchvision version: 0.20.1cu118一、前期准备import torch import torch.nn as nn import torchvision.transforms as transforms import torchvision from torchvision import transforms, datasets import os,PIL,pathlib,warnings warnings.filterwarnings(ignore) #忽略警告信息 device torch.device(cuda if torch.cuda.is_available() else cpu) deviceimport os,PIL,random,pathlib data_dir ./PotatoPlants/ data_dir pathlib.Path(data_dir) data_paths list(data_dir.glob(*)) classeNames [str(path).split(\\)[1] for path in data_paths] classeNames二、使用步骤1.处理图片transforms.Resize([224, 224])将输入图像调整到224x224像素的大小。这通常是为了适配预训练模型的输入尺寸。transforms.ToTensor()将PIL图像或NumPy数组转换为PyTorch张量Tensor并且自动将像素值从[0, 255]缩放到[0, 1]。transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225])对图像进行标准化处理使其符合标准正态分布。这里的均值mean和标准差std是根据ImageNet数据集计算得出的通常用于预训练模型。# 关于transforms.Compose的更多介绍可以参考https://blog.csdn.net/qq_38251616/article/details/124878863 train_transforms transforms.Compose([ transforms.Resize([224, 224]), # 将输入图片resize成统一尺寸 # transforms.RandomHorizontalFlip(), # 随机水平翻转 transforms.ToTensor(), # 将PIL Image或numpy.ndarray转换为tensor并归一化到[0,1]之间 transforms.Normalize( # 标准化处理--转换为标准正太分布高斯分布使模型更容易收敛 mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) # 其中 mean[0.485,0.456,0.406]与std[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。 ]) test_transform transforms.Compose([ transforms.Resize([224, 224]), # 将输入图片resize成统一尺寸 transforms.ToTensor(), # 将PIL Image或numpy.ndarray转换为tensor并归一化到[0,1]之间 transforms.Normalize( # 标准化处理--转换为标准正太分布高斯分布使模型更容易收敛 mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225]) # 其中 mean[0.485,0.456,0.406]与std[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。 ]) total_data datasets.ImageFolder(E:/Jupyter/MR_K/7/PotatoPlants,transformtrain_transforms) total_data2.划分数据集train_size int(0.8 * len(total_data)) test_size len(total_data) - train_size train_dataset, test_dataset torch.utils.data.random_split(total_data, [train_size, test_size]) train_dataset, test_dataset3.处理数据集train_dataset和test_dataset这些是包含训练和测试数据的数据集对象。你需要确保这些变量已经被正确定义并包含了相应的数据。batch_size32指定每个批次中包含的样本数量。在这个例子中每个批次包含32个样本。shuffleTrue在每个epoch开始时是否对数据进行随机打乱。这有助于模型训练的泛化能力。num_workers1指定加载数据时使用的子进程数量。这里设置为1意味着数据加载将在主进程中进行。增加num_workers可以提高数据加载的效率特别是在处理大型数据集时。batch_size 32 train_dl torch.utils.data.DataLoader(train_dataset, batch_sizebatch_size, shuffleTrue, num_workers1) test_dl torch.utils.data.DataLoader(test_dataset, batch_sizebatch_size, shuffleTrue, num_workers1) for X, y in test_dl: print(Shape of X [N, C, H, W]: , X.shape) print(Shape of y: , y.shape, y.dtype) break4.配置模型卷积块定义每个卷积块由若干个卷积层、ReLU激活函数和最大池化层组成。这些层的配置如下卷积层(nn.Conv2d)用于提取图像特征。每个卷积层的参数包括输入通道数、输出通道数、卷积核大小、步长和填充。ReLU激活函数(nn.ReLU)用于引入非线性帮助模型学习更复杂的特征。最大池化层(nn.MaxPool2d)用于降低特征图的空间维度减少参数数量和计算量。全连接层分类器在卷积块之后你使用了一个全连接层分类器它由三个全连接层组成第一个全连接层(nn.Linear)将特征图展平后映射到4096维。第二个全连接层将4096维映射到4096维。第三个全连接层将4096维映射到输出类别数这里假设为3。前向传播在forward方法中你定义了数据通过网络的流程输入数据x依次通过五个卷积块。然后通过torch.flatten将多维的特征图展平成一维。最后展平后的数据通过全连接层分类器。设备选择你检查了是否有可用的CUDA设备GPU如果有则使用GPU进行计算否则使用CPU。这是为了加速训练和推理过程。模型实例化和设备分配最后你实例化了vgg16模型并且将其移动到了选择的设备GPU或CPU上。import torch.nn.functional as F class vgg16(nn.Module): def __init__(self): super(vgg16, self).__init__() # 卷积块1 self.block1 nn.Sequential( nn.Conv2d(3, 64, kernel_size(3, 3), stride(1, 1), padding(1, 1)), nn.ReLU(), nn.Conv2d(64, 64, kernel_size(3, 3), stride(1, 1), padding(1, 1)), nn.ReLU(), nn.MaxPool2d(kernel_size(2, 2), stride(2, 2)) ) # 卷积块2 self.block2 nn.Sequential( nn.Conv2d(64, 128, kernel_size(3, 3), stride(1, 1), padding(1, 1)), nn.ReLU(), nn.Conv2d(128, 128, kernel_size(3, 3), stride(1, 1), padding(1, 1)), nn.ReLU(), nn.MaxPool2d(kernel_size(2, 2), stride(2, 2)) ) # 卷积块3 self.block3 nn.Sequential( nn.Conv2d(128, 256, kernel_size(3, 3), stride(1, 1), padding(1, 1)), nn.ReLU(), nn.Conv2d(256, 256, kernel_size(3, 3), stride(1, 1), padding(1, 1)), nn.ReLU(), nn.Conv2d(256, 256, kernel_size(3, 3), stride(1, 1), padding(1, 1)), nn.ReLU(), nn.MaxPool2d(kernel_size(2, 2), stride(2, 2)) ) # 卷积块4 self.block4 nn.Sequential( nn.Conv2d(256, 512, kernel_size(3, 3), stride(1, 1), padding(1, 1)), nn.ReLU(), nn.Conv2d(512, 512, kernel_size(3, 3), stride(1, 1), padding(1, 1)), nn.ReLU(), nn.Conv2d(512, 512, kernel_size(3, 3), stride(1, 1), padding(1, 1)), nn.ReLU(), nn.MaxPool2d(kernel_size(2, 2), stride(2, 2)) ) # 卷积块5 self.block5 nn.Sequential( nn.Conv2d(512, 512, kernel_size(3, 3), stride(1, 1), padding(1, 1)), nn.ReLU(), nn.Conv2d(512, 512, kernel_size(3, 3), stride(1, 1), padding(1, 1)), nn.ReLU(), nn.Conv2d(512, 512, kernel_size(3, 3), stride(1, 1), padding(1, 1)), nn.ReLU(), nn.MaxPool2d(kernel_size(2, 2), stride(2, 2)) ) # 全连接网络层用于分类 self.classifier nn.Sequential( nn.Linear(in_features512*7*7, out_features4096), nn.ReLU(), nn.Linear(in_features4096, out_features4096), nn.ReLU(), nn.Linear(in_features4096, out_features3) ) def forward(self, x): x self.block1(x) x self.block2(x) x self.block3(x) x self.block4(x) x self.block5(x) x torch.flatten(x, start_dim1) x self.classifier(x) return x device cuda if torch.cuda.is_available() else cpu print(Using {} device.format(device)) model vgg16().to(device) model# 统计模型参数量以及其他指标 import torchsummary as summary summary.summary(model, (3, 224, 224))5.循环训练# 训练循环 def train(dataloader, model, loss_fn, optimizer): size len(dataloader.dataset) # 训练集的大小 num_batches len(dataloader) # 批次数目, (size/batch_size向上取整) train_loss, train_acc 0, 0 # 初始化训练损失和正确率 for X, y in dataloader: # 获取图片及其标签 X, y X.to(device), y.to(device) # 计算预测误差 pred model(X) # 网络输出 loss loss_fn(pred, y) # 计算网络输出和真实值之间的差距targets为真实值计算二者差值即为损失 # 反向传播 optimizer.zero_grad() # grad属性归零 loss.backward() # 反向传播 optimizer.step() # 每一步自动更新 # 记录acc与loss train_acc (pred.argmax(1) y).type(torch.float).sum().item() train_loss loss.item() train_acc / size train_loss / num_batches return train_acc, train_lossdef test (dataloader, model, loss_fn): size len(dataloader.dataset) # 测试集的大小 num_batches len(dataloader) # 批次数目, (size/batch_size向上取整) test_loss, test_acc 0, 0 # 当不进行训练时停止梯度更新节省计算内存消耗 with torch.no_grad(): for imgs, target in dataloader: imgs, target imgs.to(device), target.to(device) # 计算loss target_pred model(imgs) loss loss_fn(target_pred, target) test_loss loss.item() test_acc (target_pred.argmax(1) target).type(torch.float).sum().item() test_acc / size test_loss / num_batches return test_acc, test_loss6.训练和测试循环初始化优化器和损失函数使用 Adam 优化器学习率设置为1e-4。使用交叉熵损失函数nn.CrossEntropyLoss。设置训练周期epochs设置为 40即模型将训练 40 个周期。初始化记录列表train_loss、train_acc、test_loss、test_acc用于记录每个周期的训练损失、训练准确率、测试损失和测试准确率。最佳准确率初始化best_acc初始化为 0用于记录测试准确率最高的模型。训练和测试周期对于每个周期执行以下步骤将模型设置为训练模式model.train()。调用train函数进行训练并记录训练准确率和损失。将模型设置为评估模式model.eval()。调用test函数进行测试并记录测试准确率和损失。如果当前周期的测试准确率超过best_acc则更新best_acc并深拷贝当前模型到best_model。记录和打印信息将每个周期的准确率和损失添加到相应的列表中。打印当前周期的信息包括周期编号、训练准确率、训练损失、测试准确率、测试损失和当前学习率。保存最佳模型训练结束后将最佳模型的参数保存到文件best_model.pth中。注意事项和建议确保train_dl和test_dl已经正确初始化并且包含正确的数据。确保device变量已经定义并且模型和数据已经移动到正确的设备上。在保存模型时你保存的是model的状态字典而不是整个模型对象。这是推荐的做法因为它只保存模型参数不包含模型架构。在打印信息时你使用了格式化字符串来清晰地展示每个周期的结果。你可以考虑添加一个学习率调度器例如torch.optim.lr_scheduler.StepLR以在训练过程中调整学习率。import copy optimizer torch.optim.Adam(model.parameters(), lr 1e-4) loss_fn nn.CrossEntropyLoss() # 创建损失函数 epochs 40 train_loss [] train_acc [] test_loss [] test_acc [] best_acc 0 # 设置一个最佳准确率作为最佳模型的判别指标 for epoch in range(epochs): model.train() epoch_train_acc, epoch_train_loss train(train_dl, model, loss_fn, optimizer) model.eval() epoch_test_acc, epoch_test_loss test(test_dl, model, loss_fn) # 保存最佳模型到 best_model if epoch_test_acc best_acc: best_acc epoch_test_acc best_model copy.deepcopy(model) train_acc.append(epoch_train_acc) train_loss.append(epoch_train_loss) test_acc.append(epoch_test_acc) test_loss.append(epoch_test_loss) # 获取当前的学习率 lr optimizer.state_dict()[param_groups][0][lr] template (Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%, Test_loss:{:.3f}, Lr:{:.2E}) print(template.format(epoch1, epoch_train_acc*100, epoch_train_loss, epoch_test_acc*100, epoch_test_loss, lr)) # 保存最佳模型到文件中 PATH ./best_model.pth # 保存的参数文件名 torch.save(model.state_dict(), PATH) print(Done)7.检测图像函数参数image_path要预测的图片的文件路径。model已经训练好的 PyTorch 模型。transform用于将图片转换为模型输入格式的转换序列。classes类别名称列表通常从数据集的class_to_idx属性中获取。预测过程加载图片使用PIL.Image.open加载图片并将其转换为 RGB 格式。展示图片使用matplotlib.pyplot.imshow展示图片。注意这里需要导入matplotlib库。应用转换使用transform将图片转换为模型可以接受的格式。数据移动到设备将转换后的图片移动到指定的设备GPU或CPU。模型评估模式将模型设置为评估模式model.eval()以关闭 dropout 和 batch normalization 等仅在训练时使用的层。模型预测使用模型对图片进行预测得到输出output。获取预测结果使用torch.max获取预测结果中概率最高的类别索引。根据索引从classes列表中获取对应的类别名称。打印预测结果打印预测的类别名称。from PIL import Image classes list(total_data.class_to_idx) def predict_one_image(image_path, model, transform, classes): test_img Image.open(image_path).convert(RGB) plt.imshow(test_img) # 展示预测的图片 test_img transform(test_img) img test_img.to(device).unsqueeze(0) model.eval() output model(img) _,pred torch.max(output,1) pred_class classes[pred] print(f预测结果是{pred_class})总结提示这里对文章进行总结例如以上就是今天要讲的内容本文仅仅简单介绍了pandas的使用而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价