我的环境
- 语言环境:Python3.6
- 编译器:jupyter lab
- 深度学习环境:pytorch1.10
- 参考文章:本人博客(60条消息) 机器学习之——tensorflow+pytorch_重邮研究森的博客-CSDN博客
🍺要求:
🍻拔高(可选):
目录
环境:python3.6,1080ti,pytorch1.10(实验室服务器的环境😂😂)
- import torch
- import torch.nn as nn
- import matplotlib.pyplot as plt
- import torchvision
-
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
-
- device
2.导入数据
- import os,PIL,random,pathlib
-
- data_dir = '4-data/'
- data_dir = pathlib.Path(data_dir)
- print(data_dir)
-
- data_paths = list(data_dir.glob('*'))
- print(data_paths)
- classeNames = [str(path).split("/")[1] for path in data_paths]
- classeNames
- total_datadir = './4-data/'
-
- # 关于transforms.Compose的更多介绍可以参考:https://blog.csdn.net/qq_38251616/article/details/124878863
- train_transforms = 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(total_datadir,transform=train_transforms)
- total_data
- 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_dataset
- batch_size = 32
-
- train_dl = torch.utils.data.DataLoader(train_dataset,
- batch_size=batch_size,
- shuffle=True,
- num_workers=1)
- test_dl = torch.utils.data.DataLoader(test_dataset,
- batch_size=batch_size,
- shuffle=True,
- num_workers=1)
- for X, y in test_dl:
- print("Shape of X [N, C, H, W]: ", X.shape)
- print("Shape of y: ", y.shape, y.dtype)
- break

- import torch.nn.functional as F
- import torch
- from torch import nn
- from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential,ReLU
- # """
- # nn.Conv2d()函数:
- # 第一个参数(in_channels)是输入的channel数量
- # 第二个参数(out_channels)是输出的channel数量
- # 第三个参数(kernel_size)是卷积核大小
- # 第四个参数(stride)是步长,默认为1
- # 第五个参数(padding)是填充大小,默认为0
- # """
- class Network_bn(nn.Module):
- def __init__(self):
- super(Network_bn,self).__init__()
- # 卷积层
- self.layers = Sequential(
- # 第一层
- nn.Conv2d(3, 24, kernel_size=5),
- nn.BatchNorm2d(24),
- nn.ReLU(),
- # 第二层
- nn.Conv2d(24,64 , kernel_size=5),
- nn.BatchNorm2d(64),
- nn.ReLU(),
- nn.MaxPool2d(2,2),
- nn.Conv2d(64, 128, kernel_size=5),
- nn.BatchNorm2d(128),
- nn.ReLU(),
- nn.Conv2d(128, 24, kernel_size=5),
- nn.BatchNorm2d(24),
- nn.ReLU(),
- nn.MaxPool2d(2,2),
- nn.Flatten(),
- nn.Linear(24*50*50, 516,bias=True),
- nn.ReLU(),
- nn.Dropout(0.5),
- nn.Linear(516, 215,bias=True),
- nn.ReLU(),
- nn.Dropout(0.5),
- nn.Linear(215, len(classeNames),bias=True),
- )
-
- def forward(self, x):
-
- x = self.layers(x)
- return x
-
- device = "cuda" if torch.cuda.is_available() else "cpu"
- print("Using {} device".format(device))
-
- model = Network_bn().to(device)
- model
打印网络结构

- loss_fn = nn.CrossEntropyLoss() # 创建损失函数
- learn_rate = 1e-2 # 学习率
- opt = torch.optim.SGD(model.parameters(),lr=learn_rate)
训练函数
- # 训练循环
- def train(dataloader, model, loss_fn, optimizer):
- size = len(dataloader.dataset) # 训练集的大小,一共60000张图片
- num_batches = len(dataloader) # 批次数目,1875(60000/32)
-
- 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_loss
测试函数
- def test (dataloader, model, loss_fn):
- size = len(dataloader.dataset) # 测试集的大小,一共10000张图片
- num_batches = len(dataloader) # 批次数目,313(10000/32=312.5,向上取整)
- 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_loss
具体训练代码
- epochs = 20
- min_loss = 100
- train_loss = []
- train_acc = []
- test_loss = []
- test_acc = []
-
- for epoch in range(epochs):
- model.train()
- epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, opt)
-
- model.eval()
- epoch_test_acc, epoch_test_loss = test(test_dl, model, loss_fn)
- print('tr loss',epoch_train_loss)
- print('te loss',epoch_test_loss)
-
- if min_loss > epoch_test_loss :
- min_loss = epoch_test_loss
- print("save model")
- # 保存模型语句
- PATH = './bestmodel'+'%d'%epoch+'.pth' # 保存的参数文件名
- torch.save(model.state_dict(), PATH )
- else :
- print("不能保存")
-
-
- train_acc.append(epoch_train_acc)
- train_loss.append(epoch_train_loss)
- test_acc.append(epoch_test_acc)
- test_loss.append(epoch_test_loss)
-
- template = ('Epoch:{:2d}, Train_acc:{:.1f}%, Train_loss:{:.3f}, Test_acc:{:.1f}%,Test_loss:{:.3f}')
- print(template.format(epoch+1, epoch_train_acc*100, epoch_train_loss, epoch_test_acc*100, epoch_test_loss))
- print('Done')

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

- 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}')
- # 预测训练集中的某张照片
- predict_one_image(image_path='./4-data/Monkeypox/M01_01_00.jpg',
- model=model,
- transform=train_transforms,
- classes=classes)
预测结果如下:
![]()
1.本次引入了根据准确率保存最佳模型的部分,其实就是判断每次测试集的准确率来看是否要保存。
2.本次调整了网络模型,参考上篇天气识别。
3.本次调整了预测的代码,之前我的太复杂了,这次参考k导的简化了很多
4.没有完成动态学习率设置,主要本周有点忙,害。。。