본문 바로가기

모두를 위한 딥런닝 by PyTorch

Lab-05 Logistic Regression

728x90

자! 어느덧 벌써 Part-1이 얼마 남지 않았습니다!!!

이번 시간에는 정말 정말 너무너무 너무 중요한!! 

 Logistic Classification이라고도 불리는

Logistic Regression에 대하여 정리해보도록 하겠습니다.

모모두 파이토치편에서는 로지스틱 회귀에 대한 개념적인 설명이 부족해서

시즌1과 위키독스를 참고해서 정리해보도록 하겠습니다!!

학습 목표

로지스틱 회귀(Logistic Regression)에 대해 알아본다.

.

핵심 키워드

로지스틱 회귀(Logistic Regression)

가설(Hypothesis)

손실 함수(Cost Function)

평가(Evaluation)


1. 이진 분류기(Binary Classification)

로지스틱 회귀는 다른 말로 이진 분류기라고 불립니다. 예를 들어, 어떤 메일이 들어왔을 때 해당 메일이 스팸인지 아닌지, 사진을 보고 해당 사진의 환자가 암에 걸렸는지 아닌지. 이런 둘 중에 하나를 선택하는 문제에 대하여 로지스틱 회귀를 사용합니다. 로지스틱 회귀는 매우 매우 잘 만들어진 알고리즘이기 때문에 실전에서도 바로 적용이 가능합니다.

자 그럼 우리가 그동안 열심히 공부한 Linear Regression이 있는데 왜 굳이 로지스틱 회귀를 사용하는걸까요?? 바로 하나의 직선으로만 분류가 안 되는 데이터가 실생활에서는 매우 많기 때문입니다. 그럼 본격적으로 로지스틱 회귀를 한번 뜯어보도록 하겠습니다.

 

2. 시그모이드 함수(Sigmoid function)

로지스틱 회귀를 이해하기 위해서는 가장 먼저 시그모이드 함수에 대해서 이해해야합니다. 우리는 선형 회귀를 배울 때 H(x) = W*X + b라고 가설을 세웠습니다. 하지만 이진 분류 문제에서 다음과 같은 가설은 문제에 봉착하게 됩니다. 이진 분류기는 0,1로 분류해야 하는데 선형 회귀의 가설의 경우 W, b의 값에 따라 1보다 큰 50, 100과 같은 값이 나올 수 있게 되는 겁니다. 그렇게 되면 이를 이진 분류하는데 어려움이 생기게 됩니다. 따라서 사람들은 모든 값을 0~1 사이의 값으로 표현할 수 있는 함수를 찾게 되는데 그것이 바로 시그모이드 함수(Sigmoid function)입니다.

 

위의 그래프와 같이 -∞로 갈수록 0에, ∞로 갈수록 1에 수렴하는 모양을 띠게 됩니다. 즉 출력값이 0.5 이상이면 1, 0.5 미만이면 0으로 이진 분류할 수 있게 되는 것이죠!

 

3. 비용 함수(Cost function)

하지만 이렇게 시그모이드 함수를 사용하게 되면 Loss function에서 문제가 생기게됩니다. 선형 회귀에서는 평균 제곱 오차를 사용하여 손실 함수를 구하면 매끈한 볼록한 모양의 그래프가 나왔습니다. 하지만 시그모이드 함수를 평균 제곱 오차 하여 손실 함수를 구하게 되면 아래와 같이 울퉁불퉁한 그래프가 그려지게 됩니다. 즉 x가 시작되는 위치에 따라 gradient=0이 되는 위치가 변하게 되는 것이죠. 

그래서 새롭게 고안된 손실함수가 바로 아래와 같습니다. 

다음과 같이 y=1 일때와 y=0일 때를 나누는 이유는 아래 그래프를 보면 설명하겠습니다.

주황색 : y=1   초록색 : y=0

cost function의 역할을 생각해보면 쉽게 이해할 수 있습니다. 비용 함수는 예측값이 실제값과 같으면 0, 다르면 다를수록 큰 값을 반환하여 오차를 알려주는 역할을 합니다. 즉, 주황색 그래프를 먼저 보게 되면 정답(y)=1일 때, 예측(H(x))=1이면 0을, 예측이 0에 가까울수록 더 큰 값을 반환하는 것을 볼 수 있습니다. 초록색 그래프는 반대로 생각하면 됩니다. 따라서 이와 같은 이유로 두 가지의 경우로 나누어 비용 함수를 계산해주는 것입니다. 이를 하나의 식으로 표현하면 다음과 같습니다.

4. 로지스틱회귀 실습

Watching the lecture Working in code lab result
1 2 0
2 3 0
3 1 0
4 3 1
5 3 1
6 2 1

다음과 같은 데이터가 있을 때 로지스틱 회귀를 이용하여 합격하였는지, 불합격하였는지 판단하는 모델을 만들어보도록 하겠습니다.

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
# data
x_data = [[1, 2], [2, 3], [3, 1], [4, 3], [5, 3], [6, 2]]
y_data = [[0], [0], [0], [1], [1], [1]]

이전과 같이 다음과 같이 데이터를 준비해줍니다.

W = torch.zero((2,1), requires_grad=True)
b = torch.zero(1, requires_grad=True)
# hypothesis by math
hypothesis = 1/(1+torch.exp(-(x_train.matual(W)+b))) # Sigmoid function

위에서 설명한 것과 같이 시그모이드 함수로 가설을 설정합니다. 하지만 Sigmoid 함수 역시 아래와 같이 이미 모듈에서 제공해줍니다.

# hypothesis by module
hypothesis = torch.sigmoid(x_train.matual(W) + b)

다음은 cost function입니다. cost function 역시 cross_entropy 함수를 제공해주고 있습니다.

# cost function by math
losses = -(y_train * torch.log(hypothesis) + (1 - y-train) * (torch.log(1 - hypothesis))
cost = losses.mean()

# cost function by module
F.binary_cross_entropy(hypothesis, y_train)

지금까지 내용을 총 정리하면 다음과 같습니다.

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

# data
W = torch.zeros((8, 1), requires_grad=True)
b = torch.zeros(1, requires_grad=True)

# optimizer 설정
optimizer = optim.SGD([W, b], lr=1)

# learning
nb_epochs = 100
for epoch in range(nb_epochs + 1):

    # Cost 계산
    hypothesis = torch.sigmoid(x_train.matmul(W) + b) # or .mm or @
    cost = F.binary_cross_entropy(hypothesis, y_train)

    # cost로 H(x) 개선
    optimizer.zero_grad()
    cost.backward()
    optimizer.step()

    # 10번마다 로그 출력
    if epoch % 10 == 0:
        print('Epoch {:4d}/{} Cost: {:.6f}'.format(
            epoch, nb_epochs, cost.item()
        ))

같은 실습을 nn.Module을 활용해서 실습을 진행해보겠습니다.

class BinaryClassifier(nn.Module):
	def __init__(self):
    	super().__init__()
        self.linear = nn.Linear(6,1)
        self.sigmoid = nn.Sigmoid()
        
	def forward(self, x):
    	return self.sigmoid(self.linear(x))

model = BinaryClassifier()

x_data = [[1, 2], [2, 3], [3, 1], [4, 3], [5, 3], [6, 2]]
y_data = [[0], [0], [0], [1], [1], [1]]
x_train = torch.FloatTensor(x_data)
y_train = torch.FloatTensor(y_data)

# optimizer 설정
optimizer = optim.SGD(model.parameters(), lr=1)

nb_epochs = 100
for epoch in range(nb_epochs + 1):

    # H(x) 계산
    hypothesis = model(x_train)

    # cost 계산
    cost = F.binary_cross_entropy(hypothesis, y_train)

    # cost로 H(x) 개선
    optimizer.zero_grad()
    cost.backward()
    optimizer.step()
    
    # 20번마다 로그 출력
    if epoch % 10 == 0:
        prediction = hypothesis >= torch.FloatTensor([0.5])
        correct_prediction = prediction.float() == y_train
        accuracy = correct_prediction.sum().item() / len(correct_prediction)
        print('Epoch {:4d}/{} Cost: {:.6f} Accuracy {:2.2f}%'.format(
            epoch, nb_epochs, cost.item(), accuracy * 100,
        ))

train data가 적어서 그런지 매우 높은 정확도를 보이고 있습니다. 이렇게 로지스틱 회귀는 매우 간단한 알고리즘이지만 높은 정확도를 보입니다. 이상으로 로지스틱 회귀에 대한 정리를 마무리하도록 하겠습니다.


 이제 어느덧 Softmax에 대한 내용만 정리하면

Part1에 대한 내용이 끝나게 됩니다.

후딱 part1을 끝내보도록 하겠습니다!!!

 

반응형

'모두를 위한 딥런닝 by PyTorch' 카테고리의 다른 글

Lab-07-1 DNN  (0) 2021.08.24
Lab-06 Softmax Classification  (0) 2021.08.14
Lab-04-2 Minibatch Gradient Descent  (0) 2021.08.09
Lab-04-1 Multivariable Linear regression  (0) 2021.08.08
Lab-02,03 Linear Regression  (0) 2021.08.07