- 🍨 本文为🔗365天深度学习训练营中的学习记录博客
- 🍖 原作者:K同学啊
-
1. 前期准备
-
1.1 设置GPU
import torch import torch.nn as nn import matplotlib.pyplot as plt import torchvision # 设置硬件设备,如果有GPU则使用,没有则使用cpu device = torch.device("cuda" if torch.cuda.is_available() else "cpu") device
运行结果:
device(type='cuda')
-
1.2 导入数据
-
train_ds = torchvision.datasets.MNIST('P1_mnist手写数字识别/data/', train=True, transform=torchvision.transforms.ToTensor(), # 将数据类型转化为Tensor download=True) test_ds = torchvision.datasets.MNIST('P1_mnist手写数字识别/data/', train=False, transform=torchvision.transforms.ToTensor(), # 将数据类型转化为Tensor download=True)
-
1.3 数据可视化
-
import numpy as np # 指定图片大小,图像大小为20宽、5高的绘图(单位为英寸inch) plt.figure(figsize=(20, 5)) # 遍历前20张图像,i是索引,imgs是图像数据 for i, imgs in enumerate(imgs[:20]): # 维度缩减:原始图像数据可能包含冗余的维度。例如,一张灰度图像可能被表示为 (1, 28, 28) 的形状,其中第一个维度是冗余的。squeeze() 函数可以去除这些大小为1的冗余维度,将其转换为 (28, 28) 的形状。 # np.squeeze()从数组的形状中删除所有大小为1的维度(单维度) npimg = np.squeeze(imgs.numpy()) # 将整个figure分成2行10列,绘制第i+1个子图 plt.subplot(2, 10, i+1) # 显示图像,使用二进制颜色映射 # imshow期望接收一个2D数组来显示图像。如果输入的是3D或更高维度的数组,可能会导致显示错误或不符合预期。 plt.imshow(npimg, cmap=plt.cm.binary) # 关闭坐标轴显示 plt.axis('off') #plt.show() 如果你使用的是Pycharm编译器,请加上这行代码
-
2. 构建简单的CNN网络
-
import torch.nn.functional as F num_classes = 10 # 图片的类别数 class Model(nn.Module): def __init__(self): super().__init__() # 特征提取网络 self.conv1 = nn.Conv2d(1, 32, kernel_size=3) # 第一层卷积,卷积核大小为3*3 self.pool1 = nn.MaxPool2d(2) # 设置池化层,池化核大小为2*2 self.conv2 = nn.Conv2d(32, 64, kernel_size=3) # 第二层卷积,卷积核大小为3*3 self.pool2 = nn.MaxPool2d(2) # 分类网络 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
-
注意:在下一步之前用cmd安装pip install torchinfo,这一步的作用是导入导入torchinfo包。
-
from torchinfo import summary # 将模型转移到GPU中(我们模型运行均在GPU中进行) model = Model().to(device) summary(model)
-
代码的输出:
-
================================================================= Layer (type:depth-idx) Param # ================================================================= Model -- ├─Conv2d: 1-1 320 ├─MaxPool2d: 1-2 -- ├─Conv2d: 1-3 18,496 ├─MaxPool2d: 1-4 -- ├─Linear: 1-5 102,464 ├─Linear: 1-6 650 ================================================================= Total params: 121,930 Trainable params: 121,930 Non-trainable params: 0 =================================================================
-
3. 训练模型
-
3.1 设置超参数
loss_fn = nn.CrossEntropyLoss() # 创建损失函数 learn_rate = 1e-2 # 学习率 opt = torch.optim.SGD(model.parameters(),lr=learn_rate)
3.2 编写训练函数# 训练循环 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 # argmax(1)返回每一行中最大值的索引,pred.argmax(1) == y返回一个布尔值,计算正确率 # 计算正确率,将布尔值转换为浮点数,再求和,再除以图片数目 # .item()将张量转换为python数字 train_acc += (pred.argmax(1) == y).type(torch.float).sum().item() train_loss += loss.item() # 例如,张量[1, 0, 1, 0, 1]转换为[1, 0, 1, 0, 1],再求和,再除以5,得到正确率0.6 train_acc /= size train_loss /= num_batches return train_acc, train_loss
3.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: # 遍历每个批次的图像和标签,并将它们移到指定设备(CPU或GPU) 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
3.4 正式训练 -
epochs = 5 # 初始化四个空列表用于存储每轮的训练和测试结果 train_loss = [] train_acc = [] test_loss = [] test_acc = [] for epoch in range(epochs): # 将模型设置为训练模式,然后调用train函数进行一轮训练,返回训练准确率和损失 model.train() epoch_train_acc, epoch_train_loss = train(train_dl, model, loss_fn, opt) # 将模型设置为评估模式,然后调用test函数进行一轮测试,返回测试准确率和损失 model.eval() epoch_test_acc, epoch_test_loss = test(test_dl, 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')
-
代码输出
Epoch: 1, Train_acc:76.1%, Train_loss:0.780, Test_acc:90.8%,Test_loss:0.282 Epoch: 2, Train_acc:94.0%, Train_loss:0.196, Test_acc:96.0%,Test_loss:0.126 Epoch: 3, Train_acc:96.3%, Train_loss:0.122, Test_acc:96.6%,Test_loss:0.104 Epoch: 4, Train_acc:97.1%, Train_loss:0.093, Test_acc:97.5%,Test_loss:0.072 Epoch: 5, Train_acc:97.5%, Train_loss:0.079, Test_acc:97.8%,Test_loss:0.066 Done
-
4. 结果可视化
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()
-
5. 个人总结
在这个项目中,我学习并实践了基于卷积神经网络(CNN)进行手写数字识别的完整流程。整个流程可以分为几个主要的阶段,包括数据准备、模型构建、训练和评估,最后是结果的可视化。
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.youkuaiyun.com/xushuaixin/article/details/143180959
# 当不进行训练时,停止梯度更新,节省计算内存消耗
365天深度学习训练营-第P1周:mnist手写数字识别
最新推荐文章于 2024-11-19 13:37:43 发布