제로부터 시작하는 코딩 생활

[모각코] MNIST 분류 모델 리뷰 본문

제 1회 모각코

[모각코] MNIST 분류 모델 리뷰

VacTEn 2022. 10. 14. 18:43

저번 시간엔 DNN에 대해 배워보았다. 이번시간엔 MNIST 데이터셋을 분석 하는 인공지능 모델을 리뷰해보는 시간을 가져보자.

이렇게 총 4개의 파일로 이루어져있다. 먼저 models.py 부터 살펴보자.

Data_loader.py

from torchvision import datasets, transforms
from torch.utils.data import DataLoader

def load_data_loader(config):
    transform=transforms.Compose([
        transforms.ToTensor(),
        transforms.Normalize((0.1307,), (0.3081,))
    ])

    train_dataset = datasets.MNIST(config.data_dir, train=True, download=True, transform=transform)
    valid_dataset = datasets.MNIST(config.data_dir, train=False, download=True, transform=transform)

    train_loader = DataLoader(dataset=train_dataset,batch_size=config.batch_size, shuffle=True)
    valid_loader = DataLoader(dataset=valid_dataset,batch_size=config.batch_size,shuffle=False)

    return train_loader, valid_loader

MNIST 데이터셋을 불러오는 파일이다

 

Models.py

import torch.nn as nn
import torch.nn.functional as F

class DNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(784, 512)
        self.fc2 = nn.Linear(512, 256)
        self.fc3 = nn.Linear(256, 128)
        self.fc4 = nn.Linear(128, 64)
        self.fc5 = nn.Linear(64, 32)
        self.fc6 = nn.Linear(32, 10)

    def forward(self, x):
        x = x.float()
        h1 = F.relu(self.fc1(x.view(-1, 784)))
        h2 = F.relu(self.fc2(h1))
        h3 = F.relu(self.fc3(h2))
        h4 = F.relu(self.fc4(h3))
        h5 = F.relu(self.fc5(h4))
        h6 = self.fc6(h5)
        return F.log_softmax(h6, dim=1)

28*28 픽셀사이즈의 손글씨데이터를 1*784 사이즈로 변환시켜 fc1을통해 사이즈 512로 변환한뒤 활성화함수를 거친다. 이과정을 반복하여 사이즈를 10까지 변환시켜준다. 이 사이즈 10짜리의 데이터는 softmax 함수를 통해 각각 0부터 9까지의 확률을 나타내게된다.

 

Train.py

import argparse 
import torch 
import torch.nn as nn
import torch.optim as optim
from models import DNN
from data_loader import load_data_loader
from trainer import MnistTrainer

def define_argparser():
    p = argparse.ArgumentParser() 
    p.add_argument('--data_dir', type=str,default='./Mnist')    
    p.add_argument('--batch_size',type=int,default=512)
    p.add_argument('--n_epochs',type=int,default=10)
    p.add_argument('--lr',type=float,default=0.01)
    p.add_argument('--seed',type=int,default=42)
    
    config = p.parse_args()

    return config

def seed_everything(seed: int):
    import random, os
    import numpy as np
    import torch
    
    random.seed(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.benchmark = True

def main(config):
    seed_everything(config.seed)
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    train_loader, valid_loader = load_data_loader(config)

    print("Train:", len(train_loader.dataset))
    print("Valid:", len(valid_loader.dataset))

    model = DNN().to(device)
    optimizer = optim.Adam(model.parameters(), lr=config.lr)
    crit = nn.CrossEntropyLoss()

    trainer = MnistTrainer(config, model, crit, optimizer, train_loader, valid_loader, device)
    trainer.train()

if __name__ == '__main__':
    config = define_argparser()
    main(config)

본격적으로 학습하기에 앞서 설정들을 하는 단계 seed는 랜덤한 값들을 고정시켜주는 작업이다. 벤치마킹을 제대로 하려면 같은 어느 환경에서든 같은 값들을 사용해야 하기 때문이라고 한다. main 에선 데이터셋을 불러오고 model, optimizer, loss_fn 등을 정해준뒤 trainer를 돌린다.

Trainer.py

import torch
import torch.nn.functional as F

class MnistTrainer():
    def __init__(self, config, model, crit, optimizer, train_loader, valid_loader, device):
        self.config = config
        self.model = model
        self.crit = crit
        self.optimizer = optimizer
        self.train_loader = train_loader
        self.valid_loader = valid_loader
        self.device = device
    
    def run_train(self, epoch):
        self.model.train()
        for batch_idx, (data, target) in enumerate(self.train_loader):
            data, target = data.to(self.device), target.to(self.device)
            self.optimizer.zero_grad()
            output = self.model(data)
            loss = F.nll_loss(output, target)
            loss.backward()
            self.optimizer.step()

            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(self.train_loader.dataset),
                100. * batch_idx / len(self.train_loader), loss.item()))

    def run_valid(self):
        self.model.eval()
        test_loss = 0
        correct = 0
        with torch.no_grad():
            for data, target in self.valid_loader:
                data, target = data.to(self.device), target.to(self.device)
                output = self.model(data)
                test_loss += F.nll_loss(output, target, reduction='sum').item()  # sum up batch loss
                pred = output.argmax(dim=1, keepdim=True)  # get the index of the max log-probability
                correct += pred.eq(target.view_as(pred)).sum().item()

        test_loss /= len(self.valid_loader.dataset)

        print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
            test_loss, correct, len(self.valid_loader.dataset),
            100. * correct / len(self.valid_loader.dataset)))
                
    def train(self):
        for epoch in range(1, self.config.n_epochs+1):
            self.run_train(epoch)
            self.run_valid()

run_train을 통해 학습을 한뒤, 완료 후 run_valid를 통해 전체 손실정도와 정확성을 계산하여 출력해준다..

'제 1회 모각코' 카테고리의 다른 글

[모각코] RNN 순환신경망  (0) 2022.11.30
[모각코] CNN  (0) 2022.11.04
[모각코] DNN & Mnist  (0) 2022.10.08
[모각코] (Pytorch) Tensor 생성 과 연산  (2) 2022.09.30