Pytorch实现MNIST手写数字识别
- 🍨 本文为🔗365天深度学习训练营 中的学习记录博客
- 🍦 参考文章:365天深度学习训练营-第P1周:实现mnist手写数字识别
- 🍖 原作者:K同学啊|接辅导、项目定制
📌第P1周:实现mnist手写数字识别📌
难度:小白入门⭐
语言:Python3、Pytorch
🍺 要求:
了解Pytorch,并使用Pytorch构建一个深度学习程序
了解什么是深度学习
🍻拔高(可选)
学习文中提到的函数方法
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
# device(type='cpu')
train_ds = torchvision.datasets.MNIST('data',
train=True,
transform=torchvision.transforms.ToTensor(), # Change the data type to tensor
download=True)
test_ds = torchvision.datasets.MNIST('data',
train=False,
transform=torchvision.transforms.ToTensor(), # Change the data type to tensor
download=True)
batch_size = 32
train_dl = torch.utils.data.DataLoader(train_ds,
batch_size=batch_size,
shuffle=True)
test_dl = torch.utils.data.DataLoader(test_ds,
batch_size=batch_size)
imgs, labels = next(iter(train_dl))
imgs.shape
# [batch_size, channel, height, weight]
import numpy as np
plt.figure(figsize=(20, 5))
for i, imgs in enumerate(imgs[:20]):
# squeeze the dimention
npimg = np.squeeze(imgs.numpy())
# plot the images
plt.subplot(2, 10, i+1)
plt.imshow(npimg, cmap=plt.cm.binary)
plt.axis("off")
构建网络
import torch.nn.functional as F
num_classes = 10
class Model(nn.Module):
def __init__(self):
super().__init__()
# Feature Extraction Network
self.conv1 = nn.Conv2d(1, 32, kernel_size=3) # (input_channel, output_channel, kernel_size)
self.pool1 = nn.MaxPool2d(2) # Max Pooling Layer
self.conv2 = nn.Conv2d(32, 64, kernel_size=3)
self.pool2 = nn.MaxPool2d(2)
# Classification Network
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
from torchinfo import summary
model = Model().to(device)
summary(model)
# Loss function
loss_fn = nn.CrossEntropyLoss()
learn_rate = 1e-2
# optimizer
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) # 60000 / 32 = 1875
train_loss, train_acc = 0, 0
for X, y in dataloader:
X, y = X.to(device), y.to(device)
# calculate the prediction error
pred = model(X) # output of the Network
loss = loss_fn(pred, y) # calculate the Loss based on the loss function
# Backword
optimizer.zero_grad()
loss.backward()
optimizer.step()
# Record the acc and 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) # 10000 / 32 = 313
test_loss, test_acc = 0, 0
# Stop the gradient calculation
with torch.no_grad():
for imgs, target in dataloader:
imgs, target = imgs.to(device), target.to(device)
# Loss
pred = model(imgs)
loss = loss_fn(pred, target)
test_loss += loss.item()
test_acc += (pred.argmax(1) == target).type(torch.float).sum().item()
test_acc /= size
test_loss /= num_batches
return test_acc, test_loss
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_dl, model, loss_fn, opt)
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')
这里发现第一轮测试集精度高于训练集精度:
训练集的准确率是每个batch之后产生的,而验证集的准确率一般是一个epoch后产生的,验证时的模型是训练一个个batch之后的,有一个滞后性,可以说就是用训练得差不多的模型用来验证,所以准确率要高一点。
- model.train()
model.train()
is used to startBatch Normalization
andDropout
If there is aBN
layer orDropout
layer in the model, we need to set model to train() mode.
It ensure that BN layer can use the mean and variance of data from each batch. - model.eval()
When model is at this mode,BN
layer is set to use the mean and variance from all data of the training set
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()