1. 程式人生 > >深度學習之PyTorch —— CNN實現MNIST手寫數字分類

深度學習之PyTorch —— CNN實現MNIST手寫數字分類

​# 運用CNN分析MNIST手寫數字分類

import torch 
import numpy as np
from torch.utils.data import DataLoader
from torchvision.datasets import mnist
from torch import  nn
from torch.autograd import Variable
from torch import  optim
from torchvision import transforms

# 定義CNN
class CNN(nn.Module):
    def __init__(self):
        super(CNN,self).__init__()
        
        self.layer1 = nn.Sequential(
                nn.Conv2d(1,16,kernel_size=3), # 16, 26 ,26
                nn.BatchNorm2d(16),
                nn.ReLU(inplace=True))
        
        self.layer2 = nn.Sequential(
                nn.Conv2d(16,32,kernel_size=3),# 32, 24, 24
                nn.BatchNorm2d(32),
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=2,stride=2)) # 32, 12,12     (24-2) /2 +1
        
        self.layer3 = nn.Sequential(
                nn.Conv2d(32,64,kernel_size=3), # 64,10,10
                nn.BatchNorm2d(64),
                nn.ReLU(inplace=True))
        
        self.layer4 = nn.Sequential(
                nn.Conv2d(64,128,kernel_size=3),  # 128,8,8
                nn.BatchNorm2d(128),
                nn.ReLU(inplace=True),
                nn.MaxPool2d(kernel_size=2,stride=2))  # 128, 4,4
        
        self.fc = nn.Sequential(
                nn.Linear(128 * 4 * 4,1024),
                nn.ReLU(inplace=True),
                nn.Linear(1024,128),
                nn.ReLU(inplace=True),
                nn.Linear(128,10))
        
    def forward(self,x):
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        x = self.layer4(x)
        x = x.view(x.size(0),-1)
        x = self.fc(x)
        
        return x


# 使用內建函式下載mnist資料集
train_set = mnist.MNIST('./data',train=True)
test_set = mnist.MNIST('./data',train=False)

# 預處理=>將各種預處理組合在一起
data_tf = transforms.Compose(
                [transforms.ToTensor(),
                 transforms.Normalize([0.5],[0.5])])

train_set = mnist.MNIST('./data',train=True,transform=data_tf,download=True)
test_set = mnist.MNIST('./data',train=False,transform=data_tf,download=True)

train_data = DataLoader(train_set,batch_size=64,shuffle=True)
test_data = DataLoader(test_set,batch_size=128,shuffle=False)

net = CNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(),1e-1)

nums_epoch = 20

# 開始訓練
losses =[]
acces = []
eval_losses = []
eval_acces = []

for epoch in range(nums_epoch):
    train_loss = 0
    train_acc = 0
    net = net.train()
    for img , label in train_data:
        #img = img.reshape(img.size(0),-1) 
        img = Variable(img)
        label = Variable(label)
        
        # 前向傳播
        out = net(img)
        loss = criterion(out,label)
        # 反向傳播
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        # 記錄誤差
        train_loss += loss.item()
        # 計算分類的準確率
        _,pred = out.max(1)
        num_correct = (pred == label).sum().item()
        acc = num_correct / img.shape[0]
       
        train_acc += acc
        
    losses.append(train_loss / len(train_data))
    acces.append(train_acc / len(train_data))
    
    eval_loss = 0
    eval_acc = 0
    # 測試集不訓練
    for img , label in test_data:
        #img = img.reshape(img.size(0),-1)
        img = Variable(img)
        label = Variable(label)
        
        out = net(img)
        
        loss = criterion(out,label)
        
        # 記錄誤差
        eval_loss += loss.item()
        
        _ , pred = out.max(1)
        num_correct = (pred==label).sum().item()
        acc = num_correct / img.shape[0]
        
        eval_acc += acc
    eval_losses.append(eval_loss / len(test_data))
    eval_acces.append(eval_acc / len(test_data))
    
    print('Epoch {} Train Loss {} Train  Accuracy {} Teat Loss {} Test Accuracy {}'.format(
        epoch+1, train_loss / len(train_data),train_acc / len(train_data), eval_loss / len(test_data), eval_acc / len(test_data)))


輸出: 

Epoch 1 Train Loss 0.14103838276348388 Train  Accuracy 0.9574893390191898 Teat Loss 0.03636252877738657 Test Accuracy 0.9888251582278481
Epoch 2 Train Loss 0.03642434606165774 Train  Accuracy 0.9888059701492538 Teat Loss 0.0744408220288497 Test Accuracy 0.9761669303797469
Epoch 3 Train Loss 0.025223525594483053 Train  Accuracy 0.9920542377398721 Teat Loss 0.02412710657131068 Test Accuracy 0.9920886075949367
Epoch 4 Train Loss 0.020014993536637535 Train  Accuracy 0.9937533315565032 Teat Loss 0.022930343906524816 Test Accuracy 0.9923852848101266
Epoch 5 Train Loss 0.015570432650668027 Train  Accuracy 0.9948694029850746 Teat Loss 0.019973596770174896 Test Accuracy 0.992879746835443
Epoch 6 Train Loss 0.011754893727584688 Train  Accuracy 0.99605210554371 Teat Loss 0.01934802131373671 Test Accuracy 0.9936708860759493

因個人用CPU運算速度問題,這次僅訓練六次。相比上篇部落格,比只簡單用全連線神經網路準確率要高,達到99%。

有什麼問題歡迎評論。