Introduction

(4) Classification - Binary

IT찬니 2020. 1. 6. 15:42

 

 

 

 

Classification

Regression과 마찬가지로 데이터 x를 넣었을 때, y가 출력으로 나오는 문제입니다.
다만 출력으로 나오게 되는 y가 Discrete한 space를 가지고 있다는게 차이점입니다.

개와 고양이의 분류, 점수에 따른 학점의 분류, 소비 패턴에 따른 성별예측과 같은 것이 Classification의 예 입니다.

 

Linear Regression의 Hypothesis를 사용한다면?

In [199]:
import numpy as np
import matplotlib.pyplot as plt

hour = np.arange(1, 11).astype(int)
hour = np.concatenate([hour, np.array([20])])
label = np.zeros(11).astype(int)
label[5:] = 1

plt.scatter(hour, label, c="b", alpha=0.5)
plt.scatter([5.5, 8.75], [0.5, 0.5], c="r")
plt.plot([0, 13.5], [0, 1.2], label="H1(x)")
plt.plot([0, 30], [0, 1.7], label="H2(x)")
plt.plot([5.5, 5.5], [-1, 0.5], "grey", alpha=0.5); plt.plot([8.75, 8.75], [-1, 0.5], "grey", alpha=0.5)
plt.quiver(6, 0.5, 2.5, 0, angles="xy", scale_units="xy", scale=1, width=0.005)

plt.xlim(0, 23); plt.ylim(-0.1, 1.1)
plt.yticks([0, 0.5, 1], ["Fail", "threshold", "Pass"])
plt.xlabel("Study hour")
plt.legend()
plt.show()
 
 

위 그래프는 학습 시간에 따른 시험의 Pass/Fail을 나타낸 것입니다.
파란색 점들은 데이터의 분포이고, 선은 모델이 학습하는 $H(x)$를 의미하며 그 값이 threshold 이상이어야 Pass로 예측합니다.

1~10시간까지의 데이터로 학습했을 때에 파란색 선이고 이후에 20시간 공부한 데이터를 추가했을 떄가 주황색 선입니다.

두 $H(x)$의 임계값 threshold의 지점이 바뀌는 것을 볼 수 있습니다.
이 말은 두 빨간점 사이의 구간 (약 6~9시간 공부한 구간) 은 파란색 선으로는 Pass로 잘 분류되겠지만, 주황색 선으로는 Fail로 분류된다는 것입니다.
즉, 학습한 데이터에 따라 $H(x)$가 변화하게 되어 True로 분류되어야 하는 샘플들이 False로 분류되거나 반대의 상황이 있을 수 있습니다.
또한, Classification의 Output은 Discrete한데 비해, Regression의 Output은 Continuous한 문제점도 발생할 것입니다.

따라서 우리가 Classification 문제를 해결하기 위해서는 Linear Regression이 아닌 새로운 Hypothesis가 필요합니다.

 

Logistic Hypothesis

이 문제를 해결하고자 했던 이전 시대의 연구자들은 기존의 Linear Regression의 회귀식에 어떠한 함수를 씌워서 그 문제를 해결하고자 했습니다.

$H_{linear}~(x) = Wx + b \\ H_{logistic}~(x) = G~(Wx + b)$

기존의 Linear Regression의 Hypothesis를 어떤 함수 G에 통과시킬 뿐 외관상으로 크게 달라지지 않습니다.
그러면 함수 G는 무엇이고 기존의 Hypothesis와는 무슨 차이가 있을까요?

Logistic Function (Sigmoid)
함수 G는 아래의 수식을 말합니다.
이것은 Logistic function 또는 Sigmoid($\sigma$) function 이라고 불리는 함수입니다.
$G(x) = \dfrac{1}{1 + e^{-x}}$

x가 0일 때 y축으로 0.5를 지나가고, 모든 실수에 대해서 0 ~ 1의 출력값을 가집니다.

Logistic Hypothesis
$H(X) = \dfrac{1}{1 + e^{-(WX + b)}}$

이를 Logistic Regression 이라고 합니다.
그러나 이 식의 결과는 0 ~ 1 사이의 실수, 즉 Continuous한 값이 출력됩니다.
이 때문에 Logistic Hypothesis만으로는 Classification이라고 할 수는 없습니다.

In [150]:
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(-5, 5, 501)
y = 1 / (1 + np.exp(-x))

plt.title("Graph of Sigmoid")
plt.plot(x, y)
plt.plot([-5, 0], [0.5, 0.5], "black", linestyle="--", alpha=0.5); plt.plot([0, 0], [0, 0.5], "black", linestyle="--", alpha=0.5)
plt.xlim(-4.9, 4.9); plt.ylim(0, 1)
plt.yticks([0, 0.5, 1])
plt.show()
 
 

MSE Cost function을 그대로 사용할 수 있는가?

In [178]:
import numpy as np
import matplotlib.pyplot as plt

X = np.random.uniform(0, 1, 1000)
Y = np.random.uniform(0, 1, 1000)
W = np.arange(-500, 500)

def linear_hypothesis(w, X):
    return w*X

def logistic_hypothesis(w, X):
    return 1 / (1 + np.exp(-(w*X)))

def MSE(pred_Y, true_Y):
    return np.mean((pred_Y - true_Y)**2)

linear_losses = []
logistic_losses = []
for w in W:
    linear_loss, logistic_loss = MSE(linear_hypothesis(w, X), Y), MSE(logistic_hypothesis(w, X), Y)
    linear_losses.append(linear_loss)
    logistic_losses.append(logistic_loss)

plt.figure(figsize=(10, 5))

ax1 = plt.subplot(1, 2, 1)
ax1.plot(W, linear_losses)
ax1.grid()
ax1.set_title("MSELoss Graph of Linear Hypothesis")
ax1.set_xlabel("W")
ax1.set_ylabel("Loss")

ax2 = plt.subplot(1, 2, 2)
ax2.plot(W, logistic_losses)
ax2.grid()
ax2.set_title("MSELoss Graph of Logistic Hypothesis")
ax2.set_xlabel("W")
ax2.set_ylabel("Loss")

plt.show()
 
 

위의 그래프는 Linear와 Logistic의 두 Regression 함수를 사용했을 때의 손실함수의 그래프입니다.
Logistic Regression의 경우 Linear Regression과 같이 매끄러운 2차 함수의 모양이 아니라 특정 구간에서 급격하게 Loss가 떨어지는 모양을 갖습니다.
즉, 대부분의 구간에서는 거의 학습이 되지 않다가 최소값 근처 구간에서는 값을 너무 많이 업데이트해버리는 결과가 발생합니다.

따라서 Logistic Hypothesis에서는 MSE cost function은 사용하기 어렵다는 결론을 내릴 수 있습니다.

 

Cross Entropy

화학이나 물리에서는 Entropy라는 개념이 있습니다.
Entropy는 어떤 시스템의 불안정성을 나타내는 지표로 사용됩니다.

이와 유사하게 Cross Entropy는 실제 확률의 분포와 예측 확률의 분포, 두 확률분포의 다름 정도를 나타냅니다.
조금 더 쉽게 설명하자면 얼마나 예측을 못했는가 또는 예측 결과가 놀라운가를 나타냅니다.
다름의 정도이기 때문에 두 확률분포가 다르다면 Cross Entropy값이 커지고, 두 확률분포가 비슷하다면 작아질 것입니다.
즉, Cross Entropy는 예측을 잘 못할수록 커지는 값입니다. ($\doteqdot$ Loss)

 

아래는 Cross Entropy를 계산하는 수식입니다.
$P(x)$는 실제 확률을 말하고, $Q(x)$는 예측 확률을 말합니다.

$\begin{eqnarray} CE(P, Q) &=& - \sum \big ( P(x) \cdot \log \left( Q(x) \right) \big ) & \\ &=& \sum \big ( P(x) \cdot -\log \left( Q(x) \right) \big ) & ~~~~~~~~~~\text{수식을 조금 변형해서 log를 -log함수로 만들었습니다. } \end{eqnarray}$

-log함수는 x=0에서 무한대를 가지고, x=1에서 0 입니다.

In [193]:
import numpy as np
import matplotlib.pyplot as plt

x = np.linspace(0.000001, 1, 10001)
y = -np.log(x)

plt.title("Graph of -Log(x)")
plt.plot(x, y)
plt.xlim(-0.02, 1); plt.ylim(0, 12.5)
plt.show()
 
 

축구 경기를 Binary Classification의 관점에서 생각해보면 승과 패로 분류한다고 할 수 있습니다.
한국이 이겼다고 가정할 때, $P(x)$의 값은 1 입니다.

(1)
한국이 독일을 이길 예측 확률 $Q(x) = 0.01$
Cross Entropy = $1 \times -\log(0.01) = 6.907755278982137$

승과 패로 분류하는 Binary Classification 관점으로 생각하면 승으로 분류할 확률이 굉장히 적은 모델이었고,
실제로는 승으로 분류되어야 했으므로 Cross Entropy가 높게 계산됩니다.

(2)
한국이 중국을 이길 예측 확률 $Q(x) = 0.9$
Cross Entropy = $1 \times -\log(0.9) = 0.10536051565782628$

이번에는 승으로 분류할 확률이 굉장히 높은 모델이었고 실제로 승이었으니 올바르게 분류하는 모델이었습니다.
따라서, Cross Entropy는 이전에 비해 훨씬 적은 값으로 계산됩니다.

 

정리하면 $Q(x)$는 모델을 말하는 변수라고 할 수 있습니다.
또한, Cross Entropy가 낮으면 분류 성능이 우수한 모델이라고 할 수 있습니다.

 

Binary Classification Cost Function

이제 Cross Entropy를 사용해서 Binary Classification의 손실함수를 정의하겠습니다.

$Cost(W) = \dfrac{1}{m} \displaystyle \sum_{i=1}^{m} c \big( H \left( x^{(i)} \right), y^{(i)} \big)$

MSE를 사용하여 Linear Regression 하는 것과 유사하게 각 x에 대한 손실 값(c)의 평균을 손실함수로 정의했습니다.
여기서 손실 값을 계산하기 위한 함수를 MSE에서 Cross Entropy로 바꿔 사용하면 되겠네요.

 

그런데 Binary Classification에서 $P(x)$, 즉 y는 0 또는 1입니다.
위의 축구 예시를 다시 한번 생각해보면, 만약 한국이 졌을 경우에는 $Q(x)$의 값이 얼마이든간에 Cross Entropy는 0이 될 것입니다.
따라서 실제로는 Cross Entropy를 y가 0일때와 1일떄로 나누어 사용합니다.

$\begin{equation} c \big( H \left( x^{(i)} \right), y^{(i)} \big) = \begin{cases} -log(H(x)) & (y=1) \\ -log(1-(H(x)) & (y=0) \\ \end{cases} \end{equation}$

(아래 그래프를 참고해서 보면 이해가 더 쉽습니다.)

y=0일 때 모델의 예측이 0에 가까우면 Cross Entropy가 작아집니다.
반대로 y=1일 때 모델의 예측이 1에 가까우면 Cross Entropy가 작아집니다.

또한 위의 Case 식은 아래와 같이 한줄로 표현할 수 있습니다.
아래 식을 살펴보면 y=0일 때는 1번째 항이 소거되고, y=1일때는 2번째 항이 소거되는 것을 알 수 있습니다.

$c \big( H \left( x^{(i)} \right), y^{(i)} \big) = -y \cdot log(H(x)) - (1-y) \cdot log(1-(H(x))$

In [196]:
import numpy as np
import matplotlib.pyplot as plt

list_Hx = np.arange(0.0001, 1, 0.001).tolist() # prediction값은 0 ~ 1사이의 값

def cost_y1(Hx):
    return -np.log(Hx)

def cost_y0(Hx):
    return -np.log(1-Hx)

list_cost_y1 = []
list_cost_y0 = []
for Hx in list_Hx:
    list_cost_y1.append(cost_y1(Hx))
    list_cost_y0.append(cost_y0(Hx))

plt.figure(figsize=(10, 5))

ax1 = plt.subplot(1, 2, 1)
ax1.plot(list_Hx, list_cost_y1)
ax1.grid()
ax1.set_title("Loss function of y=1")
ax1.set_xlabel("Prediction (H(x))")
ax1.set_ylabel("Loss")

ax2 = plt.subplot(1, 2, 2)
ax2.plot(list_Hx, list_cost_y0)
ax2.grid()
ax2.set_title("Loss function of y=0")
ax2.set_xlabel("Prediction (H(x))")
ax2.set_ylabel("Loss")

plt.show()