• pytorch-实现猴痘识别


    我的环境

    🍺要求:

    1. 训练过程中保存效果最好的模型参数。(✔)
    2. 加载最佳模型参数识别本地的一张图片。(✔)
    3. 调整网络结构使测试集accuracy到达88%(重点)。(✔)

    🍻拔高(可选):

    1. 调整模型参数并观察测试集的准确率变化。(✔)
    2. 尝试设置动态学习率。(×)
    3. 测试集accuracy到达90%。(✔)

    目录

    一 前期工作

    二 数据预处理

    数据格式设置

    数据集划分

    设置dataset

    检查数据格式 

     三 搭建网络

    四 训练模型

    1.设置学习率

    2.模型训练

    五 模型评估

    1.Loss和Accuracy图

    2.对结果进行预测

    3.总结


    一 前期工作

    环境:python3.6,1080ti,pytorch1.10(实验室服务器的环境😂😂)

    1. import torch
    2. import torch.nn as nn
    3. import matplotlib.pyplot as plt
    4. import torchvision
    5. device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
    6. device

     2.导入数据

    1. import os,PIL,random,pathlib
    2. data_dir = '4-data/'
    3. data_dir = pathlib.Path(data_dir)
    4. print(data_dir)
    5. data_paths = list(data_dir.glob('*'))
    6. print(data_paths)
    7. classeNames = [str(path).split("/")[1] for path in data_paths]
    8. classeNames

    数据预处理

    数据格式设置

    1. total_datadir = './4-data/'
    2. # 关于transforms.Compose的更多介绍可以参考:https://blog.csdn.net/qq_38251616/article/details/124878863
    3. train_transforms = transforms.Compose([
    4. transforms.Resize([224, 224]), # 将输入图片resize成统一尺寸
    5. transforms.ToTensor(), # 将PIL Image或numpy.ndarray转换为tensor,并归一化到[0,1]之间
    6. transforms.Normalize( # 标准化处理-->转换为标准正太分布(高斯分布),使模型更容易收敛
    7. mean=[0.485, 0.456, 0.406],
    8. std=[0.229, 0.224, 0.225]) # 其中 mean=[0.485,0.456,0.406]与std=[0.229,0.224,0.225] 从数据集中随机抽样计算得到的。
    9. ])
    10. total_data = datasets.ImageFolder(total_datadir,transform=train_transforms)
    11. total_data

    数据集划分

    1. train_size = int(0.8 * len(total_data))
    2. test_size = len(total_data) - train_size
    3. train_dataset, test_dataset = torch.utils.data.random_split(total_data, [train_size, test_size])
    4. train_dataset, test_dataset

    设置dataset

    1. batch_size = 32
    2. train_dl = torch.utils.data.DataLoader(train_dataset,
    3. batch_size=batch_size,
    4. shuffle=True,
    5. num_workers=1)
    6. test_dl = torch.utils.data.DataLoader(test_dataset,
    7. batch_size=batch_size,
    8. shuffle=True,
    9. num_workers=1)

    检查数据格式 

    1. for X, y in test_dl:
    2. print("Shape of X [N, C, H, W]: ", X.shape)
    3. print("Shape of y: ", y.shape, y.dtype)
    4. break

     三 搭建网络

    1. import torch.nn.functional as F
    2. import torch
    3. from torch import nn
    4. from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential,ReLU
    5. # """
    6. # nn.Conv2d()函数:
    7. # 第一个参数(in_channels)是输入的channel数量
    8. # 第二个参数(out_channels)是输出的channel数量
    9. # 第三个参数(kernel_size)是卷积核大小
    10. # 第四个参数(stride)是步长,默认为1
    11. # 第五个参数(padding)是填充大小,默认为0
    12. # """
    13. class Network_bn(nn.Module):
    14. def __init__(self):
    15. super(Network_bn,self).__init__()
    16. # 卷积层
    17. self.layers = Sequential(
    18. # 第一层
    19. nn.Conv2d(3, 24, kernel_size=5),
    20. nn.BatchNorm2d(24),
    21. nn.ReLU(),
    22. # 第二层
    23. nn.Conv2d(24,64 , kernel_size=5),
    24. nn.BatchNorm2d(64),
    25. nn.ReLU(),
    26. nn.MaxPool2d(2,2),
    27. nn.Conv2d(64, 128, kernel_size=5),
    28. nn.BatchNorm2d(128),
    29. nn.ReLU(),
    30. nn.Conv2d(128, 24, kernel_size=5),
    31. nn.BatchNorm2d(24),
    32. nn.ReLU(),
    33. nn.MaxPool2d(2,2),
    34. nn.Flatten(),
    35. nn.Linear(24*50*50, 516,bias=True),
    36. nn.ReLU(),
    37. nn.Dropout(0.5),
    38. nn.Linear(516, 215,bias=True),
    39. nn.ReLU(),
    40. nn.Dropout(0.5),
    41. nn.Linear(215, len(classeNames),bias=True),
    42. )
    43. def forward(self, x):
    44. x = self.layers(x)
    45. return x
    46. device = "cuda" if torch.cuda.is_available() else "cpu"
    47. print("Using {} device".format(device))
    48. model = Network_bn().to(device)
    49. model

    打印网络结构

    四 训练模型

    1.设置学习率

    1. loss_fn = nn.CrossEntropyLoss() # 创建损失函数
    2. learn_rate = 1e-2 # 学习率
    3. opt = torch.optim.SGD(model.parameters(),lr=learn_rate)

    2.模型训练

    训练函数

    1. # 训练循环
    2. def train(dataloader, model, loss_fn, optimizer):
    3. size = len(dataloader.dataset) # 训练集的大小,一共60000张图片
    4. num_batches = len(dataloader) # 批次数目,1875(60000/32)
    5. train_loss, train_acc = 0, 0 # 初始化训练损失和正确率
    6. for X, y in dataloader: # 获取图片及其标签
    7. X, y = X.to(device), y.to(device)
    8. # 计算预测误差
    9. pred = model(X) # 网络输出
    10. loss = loss_fn(pred, y) # 计算网络输出和真实值之间的差距,targets为真实值,计算二者差值即为损失
    11. # 反向传播
    12. optimizer.zero_grad() # grad属性归零
    13. loss.backward() # 反向传播
    14. optimizer.step() # 每一步自动更新
    15. # 记录acc与loss
    16. train_acc += (pred.argmax(1) == y).type(torch.float).sum().item()
    17. train_loss += loss.item()
    18. train_acc /= size
    19. train_loss /= num_batches
    20. return train_acc, train_loss

    测试函数 

    1. def test (dataloader, model, loss_fn):
    2. size = len(dataloader.dataset) # 测试集的大小,一共10000张图片
    3. num_batches = len(dataloader) # 批次数目,313(10000/32=312.5,向上取整)
    4. test_loss, test_acc = 0, 0
    5. # 当不进行训练时,停止梯度更新,节省计算内存消耗
    6. with torch.no_grad():
    7. for imgs, target in dataloader:
    8. imgs, target = imgs.to(device), target.to(device)
    9. # 计算loss
    10. target_pred = model(imgs)
    11. loss = loss_fn(target_pred, target)
    12. test_loss += loss.item()
    13. test_acc += (target_pred.argmax(1) == target).type(torch.float).sum().item()
    14. test_acc /= size
    15. test_loss /= num_batches
    16. return test_acc, test_loss

    具体训练代码 

    1. epochs = 20
    2. min_loss = 100
    3. train_loss = []
    4. train_acc = []
    5. test_loss = []
    6. test_acc = []
    7. for epoch in range(epochs):
    8. model.train()
    9. epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, opt)
    10. model.eval()
    11. epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)
    12. print('tr loss',epoch_train_loss)
    13. print('te loss',epoch_test_loss)
    14. if min_loss > epoch_test_loss :
    15. min_loss = epoch_test_loss
    16. print("save model")
    17. # 保存模型语句
    18. PATH = './bestmodel'+'%d'%epoch+'.pth' # 保存的参数文件名
    19. torch.save(model.state_dict(), PATH )
    20. else :
    21. print("不能保存")
    22. train_acc.append(epoch_train_acc)
    23. train_loss.append(epoch_train_loss)
    24. test_acc.append(epoch_test_acc)
    25. test_loss.append(epoch_test_loss)
    26. template = ('Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%,Test_loss:{:.3f}')
    27. print(template.format(epoch+1, epoch_train_acc*100, epoch_train_loss, epoch_test_acc*100, epoch_test_loss))
    28. print('Done')

    五 模型评估

    1.Loss和Accuracy图

    1. import matplotlib.pyplot as plt
    2. #隐藏警告
    3. import warnings
    4. warnings.filterwarnings("ignore") #忽略警告信息
    5. plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
    6. plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
    7. plt.rcParams['figure.dpi'] = 100 #分辨率
    8. epochs_range = range(epochs)
    9. plt.figure(figsize=(12, 3))
    10. plt.subplot(1, 2, 1)
    11. plt.plot(epochs_range, train_acc, label='Training Accuracy')
    12. plt.plot(epochs_range, test_acc, label='Test Accuracy')
    13. plt.legend(loc='lower right')
    14. plt.title('Training and Validation Accuracy')
    15. plt.subplot(1, 2, 2)
    16. plt.plot(epochs_range, train_loss, label='Training Loss')
    17. plt.plot(epochs_range, test_loss, label='Test Loss')
    18. plt.legend(loc='upper right')
    19. plt.title('Training and Validation Loss')
    20. plt.show()

    2.对结果进行预测

    1. from PIL import Image
    2. classes = list(total_data.class_to_idx)
    3. def predict_one_image(image_path, model, transform, classes):
    4. test_img = Image.open(image_path).convert('RGB')
    5. # plt.imshow(test_img) # 展示预测的图片
    6. test_img = transform(test_img)
    7. img = test_img.to(device).unsqueeze(0)
    8. model.eval()
    9. output = model(img)
    10. _,pred = torch.max(output,1)
    11. pred_class = classes[pred]
    12. print(f'预测结果是:{pred_class}')
    1. # 预测训练集中的某张照片
    2. predict_one_image(image_path='./4-data/Monkeypox/M01_01_00.jpg',
    3. model=model,
    4. transform=train_transforms,
    5. classes=classes)

    预测结果如下:

    3.总结

    1.本次引入了根据准确率保存最佳模型的部分,其实就是判断每次测试集的准确率来看是否要保存。

    2.本次调整了网络模型,参考上篇天气识别。

    3.本次调整了预测的代码,之前我的太复杂了,这次参考k导的简化了很多

    4.没有完成动态学习率设置,主要本周有点忙,害。。。

  • 相关阅读:
    python到底是强类型语言还是弱类型语言
    机器学习——异常检测
    11.27学术报告听讲笔记
    Python语法--列表(类似数组)
    C语言08、数据在内存中的存储、大小端存储模式
    如何写出优美的代码
    2021CCPC 哈尔滨(B D E I J)
    【Pytorch Lighting】第 10 章:扩展和管理培训
    Redis入门完整教程:Java客户端Jedis
    交互与前端9 Tabulator+Flask开发日志006
  • 原文地址:https://blog.csdn.net/m0_60524373/article/details/127513524