Mnist作业
1 设计思路
首先,我们要明确我们的任务是什么。任务是对mnist手写数据集进行分类,那么我们用pytorch来做的话,它是内置了Fashion-Mnist和Mnist数据集,我们只要从框架里面下载即可。然后我们创建dataloader,设置batch_size,设置交叉熵损失函数因为这是一个多分类问题。注意一般二分类不用这个损失函数,一般用BCELoss损失函数。然后设置优化器为SGD或者Adam,设置学习率、权重衰减、动量值。设置训练函数,进行训练,将正确率和loss显示在终端上,最后可视化每一个epoch的准确率和损失。
2 实现过程
2.1 导入相关包
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from torch.utils import *
import torchvision
2.2 处理数据集
transfroma = transforms.Compose(
[
transforms.ToTensor(),
]
)
# 内置mnist
train_ds=torchvision.datasets.MNIST(
root='MNIST', # 根路径
train=True, # 是否为训练集
transform=transfroma, # 图像预处理 转为tensor 或者裁剪 归一化
download=True # 是否下载
)
test_ds=torchvision.datasets.MNIST(
root='MNIST',
train=False,
transform=transfroma,
download=True
)
2.3 创建dataloader
BATCH_SIZE = 64 # 一次送入多少数据
# 创建dataloader
train_dl = data.DataLoader(
train_ds,
batch_size = BATCH_SIZE,
shuffle = True #乱序
)
test_dl = data.DataLoader(
test_ds,
batch_size = 64
)
2.3 画图查看数据集 在pytorch里面图片的表示形式:[batch, channel, hight, width]
plt.figure(figsize=(12,5))
for i,img in enumerate(imgs[:12]):
plt.subplot(3,4,i+1)
img = np.array(imgs[i].squeeze())
plt.title("TrueNumber:{}".format(labels[i]))
plt.axis('off') # 去掉坐标轴
plt.imshow(img)
2.4 创建AlexNet分类模型
class AlexNet(nn.Module):
def __init__(self):
super(AlexNet,self).__init__()
# 28 * 28 * 1 #----> 卷积核 11*11*96 (n-f)/s+1--> 5 * 5 * 96
self.conv1 = nn.Sequential(
nn.Conv2d(in_channels=1,out_channels=96,kernel_size=11,stride=4,padding=0),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3,stride=2),
nn.Conv2d(in_channels=96,out_channels=256,kernel_size=4,padding=2,stride=1),
nn.ReLU(),
nn.MaxPool2d(kernel_size=3,stride=2),
)
self.linear = nn.Sequential(
nn.Linear(256,4096),
nn.ReLU(),
nn.Linear(4096,10)
)
def forward(self, input):
input = self.conv1(input)
#print(input.size())
input = self.linear(input.view(input.shape[0], -1))
return input
model = AlexNet()
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device) # 把模型放入GPU
2.5 定义训练函数
def fit(epoch, model, trainloader, testloader):
correct = 0
total = 0
running_loss = 0
for x, y in trainloader:
x, y = x.to(device), y.to(device)
y_pred = model(x)
loss = loss_fn(y_pred, y)
optim.zero_grad()
loss.backward()
optim.step()
with torch.no_grad():
y_pred = torch.argmax(y_pred, dim=1)
correct += (y_pred == y).sum().item()
total += y.size(0)
running_loss += loss.item()
epoch_loss = running_loss / len(trainloader.dataset)
epoch_acc = correct / total
test_correct = 0
test_total = 0
test_running_loss = 0
with torch.no_grad():
for x, y in testloader:
x, y = x.to(device), y.to(device)
y_pred = model(x)
loss = loss_fn(y_pred, y)
y_pred = torch.argmax(y_pred, dim=1)
test_correct += (y_pred == y).sum().item()
test_total += y.size(0)
test_running_loss += loss.item()
epoch_test_loss = test_running_loss / len(testloader.dataset)
epoch_test_acc = test_correct / test_total
print('epoch: ', epoch,
'loss: ', round(epoch_loss, 3),
'accuracy:', round(epoch_acc, 3),
'test_loss: ', round(epoch_test_loss, 3),
'test_accuracy:', round(epoch_test_acc, 3)
)
return epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc
2.6 定义损失函数、优化器
optim = torch.optim.Adam(model.parameters(), lr=0.001)
loss_fn = torch.nn.CrossEntropyLoss() # 损失函数
2.7 开始训练
epochs = 10
train_loss = []
train_acc = []
test_loss = []
test_acc = []
for epoch in range(epochs):
epoch_loss, epoch_acc, epoch_test_loss, epoch_test_acc = fit(epoch,
model,
train_dl,
test_dl)
train_loss.append(epoch_loss)
train_acc.append(epoch_acc)
test_loss.append(epoch_test_loss)
test_acc.append(epoch_test_acc)
2.8 Result
2.9 可视化
plt.plot(range(1, epochs+1), train_loss, label='train_loss')
plt.plot(range(1, epochs+1), test_loss, label='test_loss')
plt.legend()
plt.plot(range(1, epochs+1), train_acc, label='train_acc')
plt.plot(range(1, epochs+1), test_acc, label='test_acc')
plt.legend()
3 调参过程 展现最优结果
由于使用的网络结构比较好,对于这种小的数据集一下就收敛了,所以准确率达到了99%。
lr = 0.001 weight decay=0.0001 momentum = 0.9 opt = SGD、Adam