rueki

7. Pytorch를 이용한 MNIST CNN 구현 본문

pytorch

7. Pytorch를 이용한 MNIST CNN 구현

륵기 2020. 3. 24. 20:37
728x90
반응형

이번에는 Convolution Neural Network를 이용해서 MNIST Classification을 진행해보자.

 

1. 라이브러리 호출

import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
from torchvision.utils import make_grid

import numpy as np
import pandas as pd
from sklearn.metrics import confusion_matrix
import warnings
import matplotlib.pyplot as plt
%matplotlib inline

2. 데이터 불러오기 및 transform 선언

transform = transforms.ToTensor()
train_data = datasets.MNIST(root = '../data',train= True, transform= transform)
test_data = datasets.MNIST(root = '../data',train= False, transform= transform)

train data : 60000개

test data : 10000개

 

 

3. 미니 배치 적용

train_loader = DataLoader(train_data, batch_szie=10, shuffle=True)
test_loader = DataLoader(test_data, batch_size = 10, shuffle = True)

여기까지 라이브러리 선언 및 데이터 불러오기, 배치 적용까지 알아보았다. 

이제 모델을 만들기에 앞서, CNN이 어떻게 작용하는지 하나씩 거쳐가보는 과정을 보자.

여기서는 2개의 convolution layer를 사용할 것이다.

 

- convolution layer 만들기

conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size3, stride=1)
conv2 = nn.Conv2d(6,16,3,1)

convolution layer는 이미지의 특징 추줄을 해주는 것으로, 레이어 파라메터로 이전에 봤던 ANN에서와 마찬가지로

입력 값, 출력 값이 존재해야한다. 여기서는 채널에 중점을 둔다.

MNIST 이미지는 흑백이미지 이므로, 채널 1개를 가진다. 컬러 이미지는 R,G,B 3채널을 가지게 된다.

 

그리고 이를 일반 신경망에 넣기위해서는 벡터 형태를 가져야하므로, view를 통해 벡터의 형태로 바꾸어준다.

for i,(X_train, y_train) in enumerate(train_data):
    break
    
x = X_train.view(1,1,28,28)
x = F.relu(conv1(x))
x = F.max_pool2d(x, 2,2) # kernel_size, stride
x = F.relu(conv2(x))
x = F.max_pool2d(x,2,2)
x.view(-1,16*5*5).shape

하나의 이미지에만 테스트로 적용하는 것이므로 for문에서 제일 앞의 이미지, 레이블 값만 불러왔다.

그리고 train data에서 배치를 적용했기에, X_train을 (1,1,28,28)로 적용해보았다. 이는 이미지 개수, 채널, 이미지 height, width 순이다.

 

그리고 CNN모델은 Conv -> pooling -> Conv -> pooling 을 거치도록 했으며, 활성화 함수로는 Relu를 사용했다.

마지막으로는 앞서 벡터형태를 언급했던 내용과 같이 (-1, 16*5*5) 로 바꿔주는데,

위와 같은 형태의 숫자를 갖는 이유는 아래 설명하도록 하겠다.

(1, 1, 28, 28) -> Conv -> (1, ,6, 26, 26) -> pooling -> (1, 6, 13, 13) -> Conv -> (1, 6, 11, 11) -> pooling ->(1, 16, 5, 5)


4. 모델 생성

 

class ConvolutionalNetwork(nn.module):
	def __init__(self):
    	super().__init__()
        self.conv1 = nn.Conv2d(1,6,3,1)
        self.conv2 = nn.Conv2d(6,16,3,1)
        self.fc1 = nn.Linear(5*5*16,120)
        self.fc2 = nn.Linear(120,84)
        self.fc3 = nn.Linear(84,10)
        
    def forward(self, X):
    	X = F.relu(self.conv1(X))
        X = F.max_pool2d(X,2,2)
        X = F.relu(self.conv2(X))
        X = X.view(-1,16*5*5)
        X = F.relu(self.fc1(X))
        X = F.relu(self.fc2(X))
        X = self.fc3(X)
        
        return F.log_softmax(X, dim=1)
        
  torch.manual_seed(42)
  model = ConvolutionalNetwork()
  model
  '''
  
ConvolutionalNetwork(
  (conv1): Conv2d(1, 6, kernel_size=(3, 3), stride=(1, 1))
  (conv2): Conv2d(6, 16, kernel_size=(3, 3), stride=(1, 1))
  (fc1): Linear(in_features=400, out_features=120, bias=True)
  (fc2): Linear(in_features=120, out_features=84, bias=True)
  (fc3): Linear(in_features=84, out_features=10, bias=True)
)
  '''

 

5. 손실함수, 최적화 함수, train, evaluate

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(),lr=0.001)
import time
start_time = time.time()

epochs = 5
trian_losses = []
test_losses =[]
train_correct =[]
test_correct = []

for i in range(epochs):
	trn_corr = 0
    tst_corr = 0
    
    for b, (X_train, y_trian) in enumerate(train_loader):
    	b+=1
        y_pred = model(X_train)
        loss = criterion(y_pred, y_train)
        
        predicted = torch.max(y_pred.data,1)[1]
        batch_corr = (predicted==y_train).sum()
        trn_corr += batch_corr
        
        optimizer.zero_grad()
        loss.backward()
        optimizer.step
        
        if b % 600 == 0:
        	print(f'epochs : {i} batch {b} loss {loss.item()}')
            
    train_losses.append(loss)
    train_correct.append(trn_corr)
        
    with torch.no_grad():
    	for b, (X_test, y_test) in enumerate(test_loader):
        	y_val = model(X_test)
            predicted = torch.max(y_val.data, 1)[1]
            tst_corr += (predicted == y_test).sum()
            
    loss = criterion(y_val, y_test)
    test_losses.append(loss)
    test_correct.append(tst_corr)
    
current_time = time.time()
total = current_time - start_time
print(f'Training took {total/60} minutes')

 

6. Loss 시각화

plt.plot(train_losses, label='train loss')
plt.plot(test_losses, label='validation loss')
plt.title('Loss At Epoch')
plt.legend()

plt.plot([t/600 for t in train_correct], label='training acc')
plt.plot([t/100 for t in test_correct],label='validation acc')
plt.legend();

# 배치에서의 accuracy 시각화 한 것

 

7. 테스트 확인

test_load_all = DataLoader(test_data, batch_size=10000, shuffle=False)

with torch.no_grad():
	correct = 0
    for X_test, y_test in test_load_all:
    	y_val = model(X_test)
        predicted = torch.max(y_val.data, 1)[1
        correct += (predicted == y_test).sum()

- 맞은 개수 비율 확인하기

correct.item()/len(test_data)
# 0.986
model.eval()
with torch.no_grad():
    new_pred = model(test_data[2019][0].view(1,1,28,28))
    
new_pred.argmax() # 9
test_data[2019][1] # 9

이로서 데이터 불러오기, 모델 생성, 훈련 및 검증, 테스트 셋에 대한 예측 진행 및 평가까지 해보았다.

다음 시간에는 Fashion Mnist 데이터를 가지고 CNN 공부를 더 해보도록 하겠다.

728x90
반응형
Comments