본문 바로가기

[Classification] CNN으로 MNIST data 분류하기

Derrick 발행일 : 2022-06-05
728x90
반응형

 

# 딥러닝 학습 단계 (code 기준)
 1) 라이브러리 불러오기 (torch, torchvision, matplotlib 등등)
 2) GPU 사용 설정하고 randon value를 위한 seed 설정
 3) 학습에 사용되는 hyper-parameter 설정 (learning rate, training epochs, batch size 등)
 4) Dataset download & 학습에 사용되기 편하게 DataLoader 생성
 5) 학습 모델 만들기 (CNN, DNN 등)
 6) Loss function(=Criterion) 정의하고 Optimizer 선언
 7) 모델 학습 및 Loss check (=Criterion의 output)
 8) 학습된 모델의 성능 Test

 


 

MNIST 데이터를 CNN을 적용하여 분류해보는 실습을 해보자.

 

[ CNN architecture for MNIST dataset ]

 

1. Package Load 및 초기 설정

# 초기 라이브러리 불러오기
import torch
import torchvision.datasets as dsets
import torchvision.transforms as transforms
import torch.nn.init
import torch.nn as nn

# GPU 설정
device = 'cuda' if torch.cuda.is_available() else 'cpu'
'''cuda가 사용가능하면 GPU 사용, 그렇지 않으면 CPU 사용'''

torch.manual_seed(123)                  # random value를 고정해주는 역할
if device == 'cuda':
  torch.cuda.manual_seed_all(123)

print(device)                             # GPU or CPU 사용여부 check
torch.cuda.is_available()                 # True : GPU 사용 가능

 

>>
cuda
True

 

2. 하이퍼파라미터 설정

# parameter 설정
learning_rate = 0.001
training_epoch = 15
batch_size = 100

 

3. MNIST dataset 및 DataLoader

# MNIST dataset 불러오기

mnist_train = dsets.MNIST(root='MNIST_data/',
                          train=True,
                          transform=transforms.ToTensor(),
                          download=True)
mnist_test = dsets.MNIST(root='MNIST_data/',
                         train=False,
                         transform=transforms.ToTensor(),
                         download=True)

# dataloader 생성
data_loader = torch.utils.data.DataLoader(dataset=mnist_train,
                                          batch_size = batch_size,
                                          shuffle=True,
                                          drop_last=True)

 

- transform을 통해 불러온 input 데이터를 어떻게 변환할 것인지 결정한다.
 → ToTensor() : 데이터를 Tensor로 전환
- 다운로드 완료한 data로 DataLoader 생성

 

4. CNN 모델 설계 ***

# CNN 모델 생성 (layer1 - layer2 - view - FC layer)
class CNN(nn.Module):

  def __init__(self):
    super(CNN, self).__init__()

    # Layer 1
    self.layer1 = nn.Sequential(
        nn.Conv2d(1,32,kernel_size=3, stride=1, padding=1),
        nn.ReLU(),
        nn.MaxPool2d(2)
    )

    # Layer 2
    self.layer2 = nn.Sequential(
        nn.Conv2d(32,64,kernel_size=3, stride=1, padding=1),
        nn.ReLU(),
        nn.MaxPool2d(2)
    )

    # Layer 3
    self.layer3 = nn.Sequential(
        nn.Conv2d(64,128, kernel_size=3, stride=1, padding=1),
        nn.ReLU(),
        nn.MaxPool2d(2)
    )

    # Fully Connected Layer
    self.fc1 = nn.Linear(3*3*128, 625)
    self.relu = nn.ReLU()
    self.fc2 = nn.Linear(625, 10, bias=True)
    torch.nn.init.xavier_uniform_(self.fc1.weight)      # weight 초기화
    torch.nn.init.xavier_uniform_(self.fc2.weight)      # weight 초기화

  def forward(self, x):
    out = self.layer1(x)      # forward에 input으로 받은 x가 layer1를 통과하고 out으로 출력
    out = self.layer2(out) 
    out = self.layer3(out)
    out = out.view(out.size(0), -1)     # batch_size만큼 펼치고, 나머지는 한 줄로 펼침
    out = self.fc1(out)
    out = self.relu(out)
    out = self.fc2(out)       # 마지막으로 통과할 Fully Connected layer 통과
    return out

 

# 모델 적용 및 출력
model = CNN().to(device)

model

 

>>
CNN(
  (layer1): Sequential(
    (0): Conv2d(1, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU()
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (layer2): Sequential(
    (0): Conv2d(32, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU()
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (layer3): Sequential(
    (0): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
    (1): ReLU()
    (2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
  )
  (fc1): Linear(in_features=1152, out_features=625, bias=True)
  (relu): ReLU()
  (fc2): Linear(in_features=625, out_features=10, bias=True)
)

 

- CNN 모델이 잘 설계되었는지 확인하는 작업!
 → layer1, 2, 3 그리고 FC layer를 가지는 CNN 모델을 확인할 수 있다.
# 테스트하기
input = torch.Tensor(1,1,28,28).to(device)
print((model(input)).shape)

 

>>  torch.Size([1, 10])

 

5. Loss function & Optimizer 정의

# loss function & Optimizer 선언
criterion = nn.CrossEntropyLoss().to(device)
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

 

6. Training (학습)

# Training code
total_batch = len(data_loader)
print('Learning Started.')

for epoch in range(training_epoch):
  avg_cost = 0        # avg_cost에 loss를 하나씩 추가하기 위함

  for X, Y in data_loader:    # X : Image, Y : Label
    X = X.to(device)
    Y = Y.to(device)

    optimizer.zero_grad()
    hypothesis = model(X)      # model의 input값을 넣어서 출력값이 가설(hypothesis)

    cost = criterion(hypothesis, Y)

    # cost값은 위에 선언한 CrossEntropy로 계산 - 가설과 실제 Label 사이의 loss 계산
    cost.backward()
    optimizer.step()

    # cost값은 total_batch로 나누어서 누적 연산
    avg_cost += cost / total_batch

  # 1 epoch이 끝날때마다 cost값 출력
  print('[Epoch:{:2d}] Cost = {}'.format(epoch+1, avg_cost))

print('Learning Finished!')

 

>>
Learning Started.
[Epoch: 1] Cost = 0.023552587255835533
[Epoch: 2] Cost = 0.019308632239699364
[Epoch: 3] Cost = 0.015114493668079376
[Epoch: 4] Cost = 0.013405434787273407
[Epoch: 5] Cost = 0.010400256142020226
[Epoch: 6] Cost = 0.010682093910872936
[Epoch: 7] Cost = 0.008156407624483109
[Epoch: 8] Cost = 0.00843567494302988
[Epoch: 9] Cost = 0.006146769970655441
[Epoch:10] Cost = 0.005543440580368042
[Epoch:11] Cost = 0.006324873771518469
[Epoch:12] Cost = 0.005305475555360317
[Epoch:13] Cost = 0.005281165707856417
[Epoch:14] Cost = 0.004536697641015053
[Epoch:15] Cost = 0.005650686100125313
Learning Finished!

 

Epoch이 돌수록 cost(=loss)값이 현저히 감소하는 것을 확인할 수 있다. 학습 잘 됨!

 

7. Test (테스트)

# 학습 결과값에 대한 Test
with torch.no_grad():     # 학습할 필요가 없으므로 no_grad()
  X_test = mnist_test.test_data.view(len(mnist_test),1,28,28).float().to(device)
  Y_test = mnist_test.test_labels.to(device)

  prediction = model(X_test)
  correct_prediction = torch.argmax(prediction, 1) == Y_test
  accuracy = correct_prediction.float().mean()
  print('Accuracy:', accuracy.item())

 

>>  Accuracy: 0.9878000020980835

 

- X_test : 위에 선언한 mnist_test값을 불러와서 한번에 넣기 위해 view() 함수 이용
 → model에 X_test값을 통째로 입력한다.
- torch.argmax : 얻어진 예측값이 실제 Label인 Y_test값과 같은지 체크
- accuracy : correct_prediction의 평균으로 출력된다.
 → 위에서 확인할 수 있듯이 학습한 모델의 정확도가 98.78% 를 가진다.



References :

 

 

댓글