이것저것 기록

[DL, PyTorch] 클래스로 소프트맥스회귀 구현하긔 - MNIST 데이터 본문

Data Science/ML & DL

[DL, PyTorch] 클래스로 소프트맥스회귀 구현하긔 - MNIST 데이터

anweh 2020. 10. 16. 17:20

다중클래스분류 (Multi-Class Classification)은 소프트맥스회귀를 통해 클래스를 분류한다. 다중클래스분류는 세 개 이상의 답 중 하나를 고르는 문제인데, 그 중 가장 유명하고 전형적인 다중클래스분류는 붓꽃 품종 구분이다. 

위 표는 꽃받침길이, 꽃받침넓이, 꽃잎길이, 꽃잎넓이 라는 4개의 특성(Feature)으로부터 setosa, versicolor, virginica라는 3개의 붓꽃 품종(Class) 중 어떤 품종인지 예측하는 문제에 쓰이는 데이터들이다. 


1. 소프트맥스회귀 분석을 한다는 것은

소프트맥스회귀는 선택지의 개수만큼의 차원을 가지는 벡터(붓꽃 문제는 3)를 만들고 해당 원소의 합이 1이되도록 원소들의 값을 변환시키는 것이다. 

x1, x2, x3, x4라는 4개의 Feature값이 입력값이 되고, 가중치(W)와 곱해지고 편향(B)가 더해진 후 ?라는 함수를 거쳐 3개의 원소를 가지는 벡터로 변환하는 과정이다. 

샘플데이터 벡터(4개의 Feature값)을 소프트맥스 함수의 입력 벡터로 차원을 축소하는 방법은 간단하다. 

소프트맥스 함수의 입력 벡터 z의 차원수만큼 결과값이 나오도록 가중치 곱을 진행하면 된다.

소프트맥스 함수의 입력 벡터 z의 차원은 3차원이며 (붓꽃의 종류가 세개이니까) 결과값이 3개가 나오도록 하는 가중치 곲은 4 x 3이다. 즉, 총 12개의 가중치를 통해 샘플데이터 벡터에서 입력 벡터 z를 만들 수 있는 것이다. 

입력을 특성(Feature)의 수만큼을 가진 입력 벡터 x라고 하고, 가중치 행렬을 W, 편향을 라고 했을 때 소프트맥스 회귀에서 예측값을 계산하는 과정을 시각화 하면 위의 사진과 같다. 

가중치 행렬의 크기는 (예측값의 차원 크기 x 입력 벡터의 길이)가 되고 편향 벡터의 길이는 예측값의 길이와 같다. 

 

 

2. 비용 함수 (Cost function)

 

 

3. 구현

import torch
import torchvision.datasets as dsets
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
import torch.nn as nn
import matplotlib.pyplot as plt
import random
import torch.nn.functional as F
import torch.optim as optim


USE_CUDA = torch.cuda.is_available() # GPU를 사용가능하면 True, 아니라면 False를 리턴
device = torch.device("cuda" if USE_CUDA else "cpu") # GPU 사용 가능하면 사용하고 아니면 CPU 사용
print("다음 기기로 학습합니다:", device)

# for reproducibility
random.seed(777)
torch.manual_seed(777)
if device == 'cuda':
    torch.cuda.manual_seed_all(777)

# hyperparameters and optimizer
batch_size = 100
lr = 0.1
epochs = 500


# 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)
# dataset loader
data_loader = DataLoader(dataset=mnist_train,
                                          batch_size=batch_size, # 배치 크기는 100
                                          shuffle=True,
                                          drop_last=True)


class SoftmaxClassifierModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.linear = nn.Linear(784, 10) # Output이 3!

    def forward(self, x):
        return self.linear(x)
model = SoftmaxClassifierModel()

optimizer = optim.SGD(model.parameters(), lr=lr)
for epoch in range(epochs):
    
    for x, y in data_loader:
        
        x = x.view(-1, 28 * 28).to(device)
        y = y.to(device)
        
        y_pred = model(x)
        loss = F.cross_entropy(y_pred, y)
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

    # 20번마다 로그 출력
    if epoch % 5 == 0:
        print('Epoch: {:4d}/{}   |   Loss: {:.6f}'.format(
            epoch, epochs, loss.item()
        ))

하.... 구현하다가 코드랑 포스팅 한번에 다 날라가서 다시 구현하고 다시 포스팅... 

자세히 포스팅 할 힘이 없다...ㅋ...ㅋ

 

 

 

 

 

Comments