본문 바로가기
딥러닝 with Python

[딥러닝 with 파이썬] 분류(Classification) / MNIST 데이터 사용

by CodeCrafter 2023. 9. 29.
반응형

[본 포스팅은 "Must Have 텐초의 파이토치 딥러닝 특강"의 내용을 참조하여 작성하였습니다]

 

이번에는 파이토치를 활용해서 분류기(Classifier)를 만들어 보겠습니다. 

 

 분류(Classification)는 실수 또는 정수 등 수치로 정의된 것이 아닌,  [강아지, 고양이, 호랑이, .......] 등 Class로 정의된 종속변수를 특성(Features)들의 연산을 통해 분류해내는 것을 말합니다.

 

 분류에 사용할 데이터는 MNIST라는 데이터이며, 이번에는 분류라는 목적 자체에만 초점을 맞춰 간단한 딥러닝 분류기를 만들것이기에 CNN(Convolutional Neural Network / 합성곱 신경망)을 사용하지는 않겠습니다.

 ( CNN은 이후 포스팅부터 많이 다룰 것이니 이번에는 분류의 개념에 대해서만 알아보겠습니다 :) )

 

1. MNIST 데이터란?

- MNISTS 데이터는 손으로 쓴 숫자 이미지로 구성된 데이터를 세트를 말합니다.

- 0에서 9까지의 숫자로 이루어져 있으며, 각 숫자 이미지는 28x28 픽셀 크기의 이미지로 표현됩니다.

 

더 자세한 세부적인 정보는 아래 내용을 참고 해보시면 되겠습니다.

[딥러닝 with 파이썬] GAN (Generative Adversarial Networks) / 생성적 적대 신경망 / MNIST 데이터로 구현

 

[딥러닝 with 파이썬] GAN (Generative Adversarial Networks) / 생성적 적대 신경망 / MNIST 데이터로 구현

이번에는 GAN, 생성적 적대 신경망에 대해서 알아보겠습니다. 1. GAN이란? - GAN은 Generative Adversarial Network의 약자로, 생성적 적대 신경망으로 불립니다. - 이는 딥러닝을 기반으로 한 모델로서, 이름

jaylala.tistory.com

 

- 이번에는 파이토치를 활용해 해당 데이터를 손쉽게 다운받고 샘플 이미지를 출력해보겠습니다.

 

 

* 아래 코드는 파이토치의 torchvision 중 dataset로 MNIST 데이터를 불러오고, ToTensor로 해당 데이터를 텐서(Tensor)의 형태로 만들기 위한 라이브러리를 불러오는 것으로 시작합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import matplotlib.pyplot as plt
 
from torchvision.datasets.mnist import MNIST
from torchvision.transforms import ToTensor
 
# ❶ 학습용 데이터와 평가용 데이터 분리
training_data = MNIST(root="./", train=True, download=True, transform=ToTensor())
test_data = MNIST(root="./", train=False, download=True, transform=ToTensor())
 
 
print(len(training_data)) # 학습에 사용할 데이터 개수
print(len(test_data))     # 평가에 사용할 데이터 개수
 
for i in range(9): # 샘플 이미지를 9개 출력
   plt.subplot(33, i+1)
   plt.imshow(training_data.data[i])
plt.show()
cs

* 추후 분류기를 만들어 학습하고 평가하기 위해 train 데이터와 test 데이터를 나누어야 합니다. 이때, MNIST 데이터 셋은 train용 60,000개와 test용 10,000개로 분류가 되어있는 데이터 셋이기에 별도의 작업은 필요가 없습니다.

* 즉, train 과 test 용 데이터의 개수가 몇개인지 len함수를 통해 확인하고

* 이후 train데이터 중 총 9개의 샘플 이미지를 한번에 출력해보겠습니다. 이를 위해 subplot 기능을 사용하고, 출력을 위해 imshow 기능을 활용했습니다.  출력 결과는 아래와 같습니다.

 

(train 데이터가 60,000개, test 데이터가 10,000개)

 

 

2. 분류기를 만들고 학습 및 평가하기

- 이번에는 pytorch를 활용해 딥러닝 이미지 분류기를 만들고 학습 시킨 후, 학습 모델의 성능을 평가해보겠습니다.

 

* 먼저, 학습할 데이터(train data)와 평가용 데이터(test data) DataLoader를 통해 미니 배치(mini-batch)로 분할합니다.

1
2
3
4
5
6
from torch.utils.data.dataloader import DataLoader
 
train_loader = DataLoader(training_data, batch_size=32, shuffle=True)
 
# ❶평가용은 데이터를 섞을 필요가 없음
test_loader = DataLoader(test_data, batch_size=32, shuffle=False)
cs

* 이때, 미니 배치(mini-batch)란 전체 데이터를 특정 크기의 배치(batch / 전체 학습 데이터를 나눈 작은 그룹)로 나뉘어진 것을 의미합니다. 즉, 학습과 평가를 할때 각 용도의 전체 데이터를 한번에 불러들이는 것이 아닌, 그룹으로 나누어 순서대로 불러오는 것을 의미합니다.

 이와 같이 미니 배치를 사용하는 이유는 메모리 관리(크기가 큰 이미지 데이터가 한번에 들어오면 메모리 부족현상이 발생할 수 있음)를 위함입니다.

* 또한, 미니 배치를 사용하는 다른 이뉴는 데이터의 전처리(Data preporcessing)을 손쉽게 하기 위함입니다. 

* 위 코드에서는 전체 데이터를 32개의 미니 배치로 나누어 담은 것을 의미합니다. 이때 학습용 데이터는 순서에 의해 학습 결과가 달라지는 것을 방지하기 위해 순서를 섞어서 담고, 평가용 데이터는 순서를 섞을 필요가 없으니 그대로 담습니다.

 

 

 

* 이제 pytorch를 활용해 신경망(nn / Neural Network)를 만들고 학습 시켜보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import torch
import torch.nn as nn
 
from torch.optim.adam import Adam
 
device = "cuda" if torch.cuda.is_available() else "cpu" # ❶ 학습에 사용할 프로세서를 지정
 
model = nn.Sequential(
   nn.Linear(78464),
   nn.ReLU(),
   nn.Linear(6464),
   nn.ReLU(),
   nn.Linear(6410)
)
model.to(device) # 모델의 파라미터를 GPU로 보냄
 
lr = 1e-3
optim = Adam(model.parameters(), lr=lr)
 
for epoch in range(20):
   for data, label in train_loader:
       optim.zero_grad()
       # ❷ 입력 데이터를 모델의 입력에 맞게 모양을 변환
       data = torch.reshape(data, (-1784)).to(device)
       preds = model(data)
 
       loss = nn.CrossEntropyLoss()(preds, label.to(device)) # ❸ 손실 계산
       loss.backward()
       optim.step()
 
   print(f"epoch{epoch+1} loss:{loss.item()}")
 
torch.save(model.state_dict(), "MNIST.pth"# ➍ 모델을 MNIST.pth라는 이름으로 저장
cs

* 위에서 nn은 신경망(neural network)를 만들때 사용되는 라이브러리입니다.

 

* torch.optim은 역전파(Back propagation)간 경사하강법에 사용될 알고리즘, 즉 옵티마이저를 어떤 종류를 사용할 것인가를 정하는 것이고, 가장 성능이 좋은 옵티마이저 중 하나인 adam을 사용합니다.

 

* device = ......      코드는 학습에 사용할 프로세서를 설정하는 것이고, cpu 또는 gpu를 선택하면 되겠습니다. 데이터가 클 경우에는 gpu를 활용해 학습을 하면 더 빠르게 결과가 나올 수 있습니다. 위 코드는 기본적으로 gpu를 사용하겠다는 것을 의미하며, gpu가 사용이 제한된다면 cpu로 사용한다는 것을 의미합니다.

 

* model 구성은 nn.Sequential() 함수를 통해 진행하며, 이는 순차적으로 딥러닝의 층(Layer)을 쌓아가는 것을 의미합니다.

 첫번째 층은, 입력값의 크기가 784(=28*28 / MNIST데이터의 픽셀 개수)이며 다음 전파되는 층의 크기를 64로 정의하는 고 이때 입력 데이터에 가중치를 곱하고 편향을 더하는 선형 변환을 통해 입력 데이터를 처리하는 nn.LInear 함수를 사용했습니다. 즉,  nn.Linear(784,64)는  nn(신경망) 중 Linear(선형 변환하는 함수)를 사용하는데 해당 층에 들어오는 입력 데이터의 크기가 784개이고 선형변환을 통해 출력되는 데이터가 64개로 만든다는 뜻입니다.

 

* 이렇게 nn.Sequential 함수를 통해 정의된 신경망은

 1) 첫번째 층 (입력층) 노드개수 : 784 

 2) 두번째 층 노드 개수 : 64

 3) 세번째 층 노드 개수 : 64

 4) 네번째 층(출력층) 노드 개수 : 10 

 의 모습을 나타내게 되겠습니다. 

 

*lr 은 Learning Rate 즉 학습률을 말하고, 0.001로 정의했습니다.

 

* optim은 Adam으로 하는데, 위에서 정의한 model의 parameter, 즉 가중치와 편향을 업데이트 할때 사용하며, lr은 위에서 정의한 lr, 즉 0.001을 말합니다.

 

이후 아래 정의된 함수는

 

입력 데이터를 모델의 입력에 맞게 변환하고, model에 입력값으로 넣은 뒤 손실을 계산한 뒤 손실에 경사하강법을 적용해 역전파 (오차역전파) 를 구현하는 것을 말합니다.

 

(사실 위와 같이 반복하는 것은 for 함수를 통해 과정을 보여주기위해 임의로 만든 것이지, 이후에 다룰 딥러닝 모델에서는 순전파 함수와 역전파 함수를 정의해서 구현하는 것이니 참고용으로 보시면 되겠습니다)

 

그리고 각 시행(epoch)마다 오차(loss)를 출력하는 코드를 만들어서 돌려보면 아래와 같은 결과가 나옵니다.

 

 

*이후 모델을 MNIST.pth 라는 이름으로 저장해봅니다.

 

 

 

*이후 모델의 성능평가는 분류 정확도로 평가해보겠습니다.  정확도에 대한 개념에 대해서는 아래 포스팅을 통해서 알아보면 좋습니다.

[머신러닝 with Python] 정확도(Accuracy)란? / 유방암(Breast Cancer) 데이터 사용

 

[머신러닝 with Python] 정확도(Accuracy)란? / 유방암(Breast Cancer) 데이터 사용

이번에 알아볼 것은 머신러닝의 분류(Classification) 문제 중 정확도(Accuracy)에 관한 것입니다. 1. 정확도(Accuracy)란? 정확도(Accuracy)란, 분류 모델의 성능을 평가하는 지표 중 하나로, 전체 예측 중 올

jaylala.tistory.com

 

 

*이후 모델의 가중치를 불러와서 해당 가중치를 가진 모델을 통해 test 데이터를 평가해보겠습니다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# ❶ 모델 가중치 불러오기
model.load_state_dict(torch.load("MNIST.pth", map_location=device))
 
num_corr = 0 # 분류에 성공한 전체 개수
 
with torch.no_grad(): # ❷ 기울기를 계산하지 않음
   for data, label in test_loader:
       data = torch.reshape(data, (-1784)).to(device)
 
       output = model(data.to(device))
       preds = output.data.max(1)[1# ❸ 모델의 예측값 계산
       # ❹ 올바르게 분류한 개수
       corr = preds.eq(label.to(device).data).sum().item()
       num_corr += corr
 
   print(f"Accuracy:{num_corr/len(test_data)}"# 분류 정확도를 출력합니다.
cs

결과는 97.34%의 정확도가 도출되었음을 확인할 수 있습니다.

반응형

댓글