怎么申请一个免费的网站,哪里有制作网站服务,php+mysql网站开发技术与典型案例导航【源代码】,网站建设一般用什么编程Pytorch从零开始实战——猴痘病识别
本系列来源于365天深度学习训练营
原作者K同学 文章目录 Pytorch从零开始实战——猴痘病识别环境准备数据集模型选择模型训练数据可视化其他模型图片预测 环境准备
本文基于Jupyter notebook#xff0c;使用Python3.8#xff0c;Pytor…Pytorch从零开始实战——猴痘病识别
本系列来源于365天深度学习训练营
原作者K同学 文章目录 Pytorch从零开始实战——猴痘病识别环境准备数据集模型选择模型训练数据可视化其他模型图片预测 环境准备
本文基于Jupyter notebook使用Python3.8Pytorch2.0.1cu118torchvision0.15.2需读者自行配置好环境且有一些深度学习理论基础。本次实验的目的是学习模型的保存和预测单张图片的结果。 第一步导入常用包。
import torch
import torch.nn as nn
import matplotlib.pyplot as plt
import torchvision
import torch.nn.functional as F
import torchvision.transforms as transforms
import random
import time
import numpy as np
import pandas as pd
import datetime
import gc
import pathlib
import os
import PIL
os.environ[KMP_DUPLICATE_LIB_OK]True # 用于避免jupyter环境突然关闭
torch.backends.cudnn.benchmarkTrue # 用于加速GPU运算的代码创建设备对象
device torch.device(cuda if torch.cuda.is_available() else cpu)
device设置随机数种子
torch.manual_seed(428)
torch.cuda.manual_seed(428)
torch.cuda.manual_seed_all(428)
random.seed(428)
np.random.seed(428)数据集
本次实验使用猴痘病图片数据集共2142张图片分别为有猴痘病的图片和没有猴痘病的图片 两种类别的图片分别存在两个文件夹中。
data_dir ./data/monkeydata
data_dir pathlib.Path(data_dir)data_paths list(data_dir.glob(*))
classNames [str(path).split(/)[2] for path in data_paths]
classNames # [Monkeypox, Others]对数据通过dataset读取并且将文件夹名设置为标签。
total_datadir ./data/monkeydata
train_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])
])
total_data torchvision.datasets.ImageFolder(total_datadir, transformtrain_transforms)
total_data我们可以查看所有标签
total_data.class_to_idx # {Monkeypox: 0, Others: 1}接下来划分数据集以8比2划分训练集和测试集
# 划分数据集
train_size int(0.8 * len(total_data))
test_size len(total_data) - train_size
train_ds, test_ds torch.utils.data.random_split(total_data, [train_size, test_size])
len(train_ds), len(test_ds)随机查看5张图片
def plotsample(data):fig, axs plt.subplots(1, 5, figsize(10, 10)) #建立子图for i in range(5):num random.randint(0, len(data) - 1) #首先选取随机数随机选取五次#抽取数据中对应的图像对象make_grid函数可将任意格式的图像的通道数升为3而不改变图像原始的数据#而展示图像用的imshow函数最常见的输入格式也是3通道npimg torchvision.utils.make_grid(data[num][0]).numpy()nplabel data[num][1] #提取标签 #将图像由(3, weight, height)转化为(weight, height, 3)并放入imshow函数中读取axs[i].imshow(np.transpose(npimg, (1, 2, 0))) axs[i].set_title(nplabel) #给每个子图加上标签axs[i].axis(off) #消除每个子图的坐标轴plotsample(train_ds)使用DataLoader划分批次和打乱数据集
batch_size 32
train_dl torch.utils.data.DataLoader(train_ds, batch_sizebatch_size, shuffleTrue)
test_dl torch.utils.data.DataLoader(test_ds, batch_sizebatch_size, shuffleTrue)
for X, y in test_dl:print(X.shape) # 32, 3, 224, 224print(y) # 1, 0, 1, 1, 1, 1, 0....break
print(len(train_dl.dataset) len(test_dl.dataset)) # 2142模型选择
本次实验第一次选择的是一个简单的卷积神经网络经过卷积卷积池化卷积卷积池化线性层并中间进行数据归一化处理。
class Model(nn.Module):def __init__(self):super().__init__()self.conv1 nn.Conv2d(3, 12, kernel_size5, stride1, padding0)self.bn1 nn.BatchNorm2d(12)self.conv2 nn.Conv2d(12, 12, kernel_size5, stride1, padding0)self.bn2 nn.BatchNorm2d(12)self.pool nn.MaxPool2d(2)self.conv3 nn.Conv2d(12, 24, kernel_size5, stride1, padding0)self.bn3 nn.BatchNorm2d(24)self.conv4 nn.Conv2d(24, 24, kernel_size5, stride1, padding0)self.bn4 nn.BatchNorm2d(24)self.fc1 nn.Linear(24 * 50 * 50, len(classNames))def forward(self, x):x F.relu(self.bn1(self.conv1(x)))x F.relu(self.bn2(self.conv2(x))) x self.pool(x)x F.relu(self.bn3(self.conv3(x))) x F.relu(self.bn4(self.conv4(x))) x self.pool(x) x x.view(-1, 24 * 50 * 50)x self.fc1(x)return x;使用summary查看模型
from torchsummary import summary
# 将模型转移到GPU中
model Model().to(device)
summary(model, input_size(3, 224, 224))模型训练
训练函数
def train(dataloader, model, loss_fn, opt):size len(dataloader.dataset)num_batches len(dataloader)train_acc, train_loss 0, 0for X, y in dataloader:X, y X.to(device), y.to(device)pred model(X)loss loss_fn(pred, y)opt.zero_grad()loss.backward()opt.step()train_acc (pred.argmax(1) y).type(torch.float).sum().item()train_loss loss.item()train_acc / sizetrain_loss / num_batchesreturn train_acc, train_loss测试函数
def test(dataloader, model, loss_fn):size len(dataloader.dataset)num_batches len(dataloader)test_acc, test_loss 0, 0with torch.no_grad():for X, y in dataloader:X, y X.to(device), y.to(device)pred model(X)loss loss_fn(pred, y)test_acc (pred.argmax(1) y).type(torch.float).sum().item()test_loss loss.item()test_acc / sizetest_loss / num_batchesreturn test_acc, test_loss定义一些超参数经实验将学习率设置为0.01效果最好。
loss_fn nn.CrossEntropyLoss()
learn_rate 0.01
opt torch.optim.SGD(model.parameters(), lrlearn_rate)开始训练epochs设置为20并且将训练集的最优结果保存。
import time
epochs 20
train_loss []
train_acc []
test_loss []
test_acc []T1 time.time()best_acc 0
PATH ./my_model.pthfor 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)if epoch_test_acc best_acc:best_acc epoch_test_acctorch.save(model.state_dict(), PATH)print(model save)train_acc.append(epoch_train_acc)train_loss.append(epoch_train_loss)test_acc.append(epoch_test_acc)test_loss.append(epoch_test_loss)print(epoch:%d, train_acc:%.1f%%, train_loss:%.3f, test_acc:%.1f%%, test_loss:%.3f% (epoch 1, epoch_train_acc * 100, epoch_train_loss, epoch_test_acc * 100, epoch_test_loss))
print(Done)
T2 time.time()
print(程序运行时间:%s毫秒 % ((T2 - T1)*1000))可以看到最好的时候测试集准确率达到百分之91.8
数据可视化
使用matplotlib进行数据可视化。
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, labelTraining Accuracy)
plt.plot(epochs_range, test_acc, labelTest Accuracy)
plt.legend(loclower right)
plt.title(Training and Validation Accuracy)plt.subplot(1, 2, 2)
plt.plot(epochs_range, train_loss, labelTraining Loss)
plt.plot(epochs_range, test_loss, labelTest Loss)
plt.legend(locupper right)
plt.title(Training and Validation Loss)
plt.show()其他模型
本次实验也使用了ResNet模型虽然参数量较大但训练效果较好 定义模型
class Model(nn.Module):def __init__(self):super().__init__()# 创建预训练的ResNet-18模型self.resnet torchvision.models.resnet18(pretrainedTrue)# 将ResNet的最后一层全连接层替换为适合二分类问题的新全连接层self.resnet.fc nn.Linear(self.resnet.fc.in_features, len(classes))def forward(self, x):return self.resnet(x)from torchsummary import summary
# 将模型转移到GPU中
model Model().to(device)经实验把学习率设置为0.001效果较好
import time
epochs 50
train_loss []
train_acc []
test_loss []
test_acc []loss_fn nn.CrossEntropyLoss()
learn_rate 0.001
opt torch.optim.SGD(model.parameters(), lrlearn_rate)T1 time.time()best_acc 0
PATH ./my_model.pthfor 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)if epoch_test_acc best_acc:best_acc epoch_test_acctorch.save(model.state_dict(), PATH)print(model save)train_acc.append(epoch_train_acc)train_loss.append(epoch_train_loss)test_acc.append(epoch_test_acc)test_loss.append(epoch_test_loss)print(epoch:%d, train_acc:%.1f%%, train_loss:%.3f, test_acc:%.1f%%, test_loss:%.3f% (epoch 1, epoch_train_acc * 100, epoch_train_loss, epoch_test_acc * 100, epoch_test_loss))
print(Done)
T2 time.time()
print(程序运行时间:%s毫秒 % ((T2 - T1)*1000))最终在测试集的准确率可达到97.2%。 可视化训练过程
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, labelTraining Accuracy)
plt.plot(epochs_range, test_acc, labelTest Accuracy)
plt.legend(loclower right)
plt.title(Training and Validation Accuracy)plt.subplot(1, 2, 2)
plt.plot(epochs_range, train_loss, labelTraining Loss)
plt.plot(epochs_range, test_loss, labelTest Loss)
plt.legend(locupper right)
plt.title(Training and Validation Loss)
plt.show()图片预测
img_path要进行预测的图像文件的路径。 model用于进行图像分类预测的深度学习模型。 transform用于对图像进行预处理的数据转换函数。 classes包含类别标签的列表用于将模型的输出索引映射回类别标签。 大致意思是图像与训练时的输入数据格式相匹配模型接受批量输入因此我们需要在维度上添加一个批次维度从而进行预测
classes list(total_data.class_to_idx)
def predict_img(img_path, model, transform, classes):test_img Image.open(img_path).convert(RGB)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_img(img_path./data/monkeydata/Monkeypox/M01_01_00.jpg, modelmodel, transformtrain_transforms, classesclasses)
# 预测结果是Monkeypox