Pytorch基于卷积神经网络手写数字识别

1.实验环境

  • Pytorch 1.4.0
  • conda 4.7.12
  • Jupyter Notebook 6.0.1
  • Python 3.7
  • 数据集:MNIST

2 训练过程

数据准备

首先,导入实验所需的库,定义一些宏参数,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%

你可能感兴趣的:(深度学习,深度学习,pytorch,神经网络)