Pytorch_P1 Pytorch实现mnist手写数字识别
目录
一、前言
二、前期准备
1、设置GPU
2、导入数据
3、数据可视化
三、创建CNN网络
1、实例化模型,并设置参数
2、训练函数
3、测试函数
4、正式训练
5、可视化
一、前言
- 🍨 本文为🔗365天深度学习训练营中的学习记录博客
- 🍖 原作者:K同学啊
二、前期准备
1、设置GPU
#构建和训练神经网络
import torch
#PyTorch的神经网络模块,提供构建网络所需的类和函数
import torch.nn as nn
import matplotlib.pyplot as plt
#用于处理图像数据集的库
import torchvision
import numpy as np
#提供激活函数的库
import torch.nn.functional as F
import warnings
函数原型:
torchvision.datasets.MNIST(root, train=True, transform=None, target_transform=None, download=False)
参数说明:
- root (string) :数据地址
- train (string) :
True
-训练集,False
-测试集 - download (bool,optional) : 如果为
True
,从互联网上下载数据集,并把数据集放在root目录下。 - transform (callable, optional ):这里的参数选择一个你想要的数据转化函数,直接完成数据转化
- target_transform (callable,optional) :接受目标并对其进行转换的函数/转换。
2、导入数据
train_data = torchvision.datasets.MNIST("data",
train=True,
transform = torchvision.transforms.ToTensor(),
download=True)
test_data = torchvision.datasets.MNIST("data",
train=False,
transform=torchvision.transforms.ToTensor(),
download=True)
batch_size = 32
处理导入的数据
#是一个 PyTorch 数据加载器(DataLoader),用于加载训练数据集。通常情况下,数据加载器会将数据集分成小批量(batches)进行处理
train_d = torch.utils.data.DataLoader(train_data,
batch_size = batch_size,
shuffle = True)
test_d = torch.utils.data.DataLoader(test_data,
batch_size = batch_size)
#iter(train_dl) 将数据加载器转换为一个迭代器(iterator),使得我们可以使用 Python 的 next() 函数来逐个访问数据加载器中的元素。
#next() 函数用于获取迭代器中的下一个元素。在这里,它被用来获取 train_dl 中的下一个批量数据。
#它将从 next() 函数返回的元素中提取出两个变量:imgs 和 labels
imgs, labels = next(iter(train_d))
"""imgs 变量将包含一个批量的图像数据,而 labels 变量将包含相应的标签数据。"""
3、数据可视化
#指定图片大小,图像大小为20宽、5高的绘图(单位为英寸inch)
plt.figure(figsize=(20, 5))
for i, imgs in enumerate(imgs[:20]):
#squeeze()函数的功能是从矩阵shape中,去掉维度为1的,实现维度缩减
nping = np.squeeze(imgs.numpy())
# 将整个figure分成2行10列,绘制第i+1个子图
plt.subplot(2, 10, i+1)
plt.imshow(nping ,cmap=plt.cm.binary)
#去掉坐标轴
plt.axis("off")
#plt.show()
执行结果如下:
三、创建CNN网络
# 设置图片的类别数,因为有十个数就有十个类别
num_classes = 10
class Model(nn.Module):
def __init__(self):
super().__init__()
#提取特征网络
# 第一层卷积,卷积核大小为3*3
self.conv1 = nn.Conv2d(1, 32, kernel_size=3)
# 设置池化层,池化核大小为2*2
self.pool1 = nn.MaxPool2d(2)
# 第二层卷积,卷积核大小为3*3
self.conv2 = nn.Conv2d(32, 64, kernel_size=3)
# 设置池化层,池化核大小为2*2
self.pool2 = nn.MaxPool2d(2)
#分类网络
#降维,从 1600 维降到 64 维
self.fc1 = nn.Linear(1600, 64)
#再降维
self.fc2 = nn.Linear(64, num_classes)
#前向传播
def forward(self, x):
#通过卷积层提取图像特征,然后通过激活函数增加非线性,最后通过池化层降低特征的空间维度
x = self.pool1(F.relu(self.conv1(x)))
x = self.pool2(F.relu(self.conv2(x)))
#其实就是把长和宽组成的二维数组拉直成一维的
x = torch.flatten(x, start_dim=1)
x = F.relu(self.fc1(x))
x = self.fc2(x)
return x
1、实例化模型,并设置参数
#实例化Model
model = Model()
#设置损失函数,损失函数为交叉熵损失函数
loss_fn = nn.CrossEntropyLoss()
#设置学习率
learn_rate = 1e-2
opt = torch.optim.SGD(model.parameters(), lr=learn_rate)
2、训练函数
# 训练循环
def train(dataloader, model, loss_fn, optimizer):
# 查看训练集的大小,一共60000张图片
size = len(dataloader.dataset)
# 批次数目,1875(60000/32)
num_batches = len(dataloader)
# 初始化训练损失和正确率
train_loss, train_acc = 0, 0
# 获取图片及其标签
for X, y in dataloader:
X, y = X, y
# 计算预测误差
# 设置网络输出
pred = model(X)
# 计算网络输出和真实值之间的差距,targets为真实值,计算二者差值即为损失
loss = loss_fn(pred, y)
# 反向传播
optimizer.zero_grad() # grad属性归零
loss.backward() # 反向传播
optimizer.step() # 每一步自动更新
# 记录acc与loss
#返回数组 pred 在第一个轴(即行)上最大值所在的索引。这通常用于多类分类问题中,其中 pred 是一个包含预测概率的二维数组,每行表示一个样本的预测概率分布。
#是将布尔数组的数据类型转换为浮点数类型,即将 True 转换为 1.0,将 False 转换为 0.0
#将求和结果转换为标量值
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
3、测试函数
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, target
# 计算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
4、正式训练
#设置训练批次
epochs = 5
#将每批训练的结果保存下来
train_loss = []
train_acc = []
test_loss = []
test_acc = []
for epoch in range(epochs):
model.train()
epoch_train_acc, epoch_train_loss = train(train_d, model, loss_fn, opt)
model.eval()
epoch_test_acc, epoch_test_loss = test(test_d, model, loss_fn)
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')
执行结果如下:
5、可视化
#忽略警告信息
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()
👏觉得文章对自己有用的宝子可以收藏文章并给小编点个赞!
👏想了解更多统计学、数据分析、数据开发、机器学习算法、深度学习等有关知识的宝子们,可以关注小编,希望以后我们一起成长!