首先,导入实验所需的库,定义一些宏参数,BATCH_SIZE表示每个batch加载多少个样本、EPOCHS表示总共训练批次。如果支持cuda就用gpu来run,不支持就用cpu来run。
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
BATCH_SIZE = 200
EPOCHS = 10
DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
Pytorch的torchvision的dataset里面有MNIST数据集,我们可以直接使用。 如果是第一次run需要下载data,如果已经下载过了就可以直接用了。
接着构造数据提供器,归一化数据,shuffle=True设置在每个epoch重新打乱数据,保证数据的随机性。
因为Pytorch已经实现了dataset,所以这里可以直接使用DataLoader来对数据进行读取。
处理好了训练集和测试集。
# 训练集
train_set = datasets.MNIST('data', train = True, download = True,
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1037,), (0.3081,))
]))
train_loader = torch.utils.data.DataLoader(train_set,
batch_size = BATCH_SIZE, shuffle = True)
# 测试集
test_set = datasets.MNIST('data', train = False,
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1037,), (0.3081,))
]))
test_loader = torch.utils.data.DataLoader(test_set,
batch_size = BATCH_SIZE, shuffle = True)
定义一个卷积神经网络,网络为1个卷积层接1个最大池化层,再接一个卷积层,然后紧接着两个全连接层,最后是输出层,最后输出10个维度,这10个维度我们作为0-9的标识来确定识别出的是那个数字。其中卷积层采用ReLU函数作为激活函数,输出层使用log_softmax函数.
# 定义模型
class MyConvNet(nn.Module):
def __init__(self):
super().__init__()
#1*1*28*28
self.conv1 = nn.Conv2d(1, 10, 5)
self.conv2 = nn.Conv2d(10, 20, 3)
self.fc1 = nn.Linear(20 * 10 * 10, 500)
self.fc2 = nn.Linear(500, 10)
def forward(self, x):
in_size = x.size(0)
out= self.conv1(x)
out = F.relu(out)
out = F.max_pool2d(out, 2, 2)
out = self.conv2(out)
out = F.relu(out)
out = out.view(in_size, -1)
out = self.fc1(out)
out = F.relu(out)
out = self.fc2(out)
out = F.log_softmax(out, dim = 1)
return out
初始化模型,优化器采用Adam。
# 定义模型
model = MyConvNet().to(DEVICE)
optimizer = optim.Adam(model.parameters())
定义训练函数,print进度和过程中的loss,print每一epoch的accuracy。
def train(model, device, train_loader, optimizer, epoch):
model.train()
train_loss = []
train_acc = 0
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
output = model(data)
loss = F.nll_loss(output, target)
loss.backward()
optimizer.step()
pred = output.max(1, keepdim = True)[1]
train_acc += pred.eq(target.view_as(pred)).sum().item()
if (batch_idx + 1) % 30 == 0:
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
train_loss.append(loss.data.item())
train_acc=train_acc/len(train_loader.dataset)
print('\nTrain Epoch: {}\tAccuracy:{:.4f}% '.format(epoch,100.*train_acc))
return train_loss,100.*train_acc
定义测试函数,print每一epoch的loss和accuracy。
def test(model, device, test_loader):
model.eval()
test_loss =0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
test_loss += F.nll_loss(output, target, reduction = 'sum')
pred = output.max(1, keepdim = True)[1]
correct += pred.eq(target.view_as(pred)).sum().item()
test_loss /= len(test_loader.dataset)
test_acc= correct / len(test_loader.dataset)
print("\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.4f}%) \n"
.format(test_loss, correct,
len(test_loader.dataset),100.* test_acc))
return test_loss.item(),100.*test_acc
预定义4个数组,分别存储训练集的loss和accuracy、测试集的loss和accuracy,然后开始训练和测试。
train_losses = []
train_acces = []
test_losses = []
test_acces = []
for epoch in range(1, EPOCHS + 1):
tr_loss,tr_acc=train(model, DEVICE, train_loader, optimizer, epoch)
te_loss,te_acc=test(model, DEVICE, test_loader)
for item in tr_loss:
train_losses.append(item)
train_acces.append(tr_acc)
test_losses.append(te_loss)
test_acces.append(te_acc)
图形化训练过程中和测试过程中的loss和accuracy。
def draw_plot(data,label,x,y):
plt.plot(data,label=label)
plt.xlabel(x, fontsize=14)
plt.ylabel(y, fontsize=14)
plt.legend()
draw_plot(train_losses,"train_loss","iteration","loss")
draw_plot(test_losses,"test_loss","iteration","loss")
draw_plot(train_acces,"train_accuracy","iteration","acc")
draw_plot(test_acces,"test_accuracy","iteration","acc")
卷积神经网络最后accuracy为98.94%