Linear Regression에 이어서 두 번째로는 Logistic Regression을 해보려고 합니다. 원래는 여러 개의 x가 존재하는 Linear Regression도 해보려고 했으나, Logistic (Regression) Classification까지 한 이후에 여러 개의 x가 존재하는 Linear Regression과 Logistic (Regression) Classification을 동시에 하는게 더 좋을 거 같네요. 조금 응용해서 확장하는 수준이라서 큰 어려움은 없을 거 같아서 말이죠.


간단하게 Logistic Regression이 왜 나왔는지부터 시작하는게 좋을 듯 합니다. 예를 들어서 스팸 메일과 햄 메일(정상 메일)을 분류한다고 합시다. 스팸 메일일 경우에는 1, 햄 메일일 때는 0을 출력하게 머신 러닝을 구현하고 싶다고 하고, 이것을 Linear Regression을 통해서 해결해보려고 합시다. 일단 데이터가 다음과 같은 경우일 때를 고려해봅시다.


 메일 고유값

1 

3 

9 

4 

100 

스팸 여부 

0 

0

1 


이때의 Linear Regresssion을 구하면 다음과 같은 그래프가 나오게 됩니다. y = 0.5를 중심으로 이보다 크면 스팸이고 아래이면 햄이라고 간주됩니다.


이때 x = 4일 경우를 보면 Linear Regression으로 구한 그래프에서 스팸(1)이 아니라 햄(0)이라고 인식되게 점의 y좌표가 0.5보다 아래에 있습니다. 이러한 문제를 해결하기 위해서 이러한 Binary Classification에서는 Linear Regression보다는 훨씬 더 정확하게 나오는 Logistic Regression을 사용합니다.


Logistic Regression의 기본 모델은 다음과 같습니다. sigmoid 함수라고도 하죠.

이를 그래프로 그려보면 다음과 같습니다. (a = 1, b = 0)

그래프의 y절편은 0.5이며, y = 0과 y = 1을 점근선으로 가집니다. 이를 이용해서 머신러닝을 시켜보면 꽤 정확한 결과가 나온다고 합니다.


Linear Regression 때와 같이 이 함수도 최적화를 거쳐서 제대로된 함수로 만드는 과정이 필요합니다. 따라서 cost값을 계산을 해야합니다. 기존의 Linear Regression에서는 다음과 같은 cost 함수를 사용했었습니다. 

함수의 형태가 달라졌으니, 한 번 시험삼아 위의 값을 입력해 cost 함수의 그래프를 그려봅시다.

?! 그려보니 우리가 예상하던 U자 형태의 도형이 아닌 괴이한 형태의 도형이 나왔습니다. TensorFlow에서 사용하는 GradientDescentOptimizer, 일명 경사내려가기최적화기이라고 할 수 있는 이 알고리즘은 말 그대로 경사를 타고 내려가면서 최솟값을 찾는 방법이라고 합니다. 따라서 이 cost 함수를 그대로 적용해버리면 최적화된 함수가 나오지 않을 수도 있죠. 그래서 우리는 새로운 cost 함수를 정의해야 합니다.


먼저 우리는 학습할 데이터에서 한 데이터가 스팸(1)인 경우, 그 데이터를 함수에 넣었을 때 스팸이라고 나올 때는 cost를 가장 적게, 햄에 가깝게 나올 때에는 cost를 매우 많이 줘야합니다. 반대로 한 데이터가 햄(0)인 경우, 그 데이터를 함수에 넣었을 때 햄이라고 나올 때는 cost를 가장 적게 , 스팸에 가깝게 나올 때에는 cost를 매우 많이 줘야합니다. 이러한 특성을 생각하면 다음의 cost 함수를 생각해볼 수 있습니다.

이러한 cost 함수가 나올 수 있는 까닭은 log(x)는 점근선으로 x = 0을 가지기 때문에, 원래 데이터와 함수의 계산된 값이 정반대로 나올 수록 cost를 무지무지 많이 줄 수 있기 때문입니다. 이 함수를 정리하면 다음과 같은 수식을 얻을 수 있습니다.

한 번 어떻게 나오는 지 그래프를 그려봅시다.

오오, 생각했던 대로 그릇 모양이 나와서 GradientDescentOptimizer가 최적화된 함수를 잘 구할 수 있는 모양이 나왔네요! 이제 TensorFlow에서 Logistic (Regression) Classification을 해봅시다. 코드는 다음과 같습니다.

여기서 y 함수가 바로 sigmoid 함수를 나타낸 것인데, TensorFlow에 이미 자체적으로 내장되어 있는 tf.sigmoid 함수를 써도 됩니다.  


* 보통 Logistic Regression 하면 단순히 위에 설명한 함수를 그대로 넣어서 training을 하는데, 저 같은 경우는 위와 같이 돌리게 되면 log의 특성에 따라서 nan이 나오는 경우가 발생해서(...) tf.clip_by_value(num, min, max)를 통해 값을 잘라냈습니다. 잘라내지 않으면 정상적으로 training이 되지 않고요. (이 문제 땜에 은근 골치 아파서 + 귀차니즘 발생으로 2달간 글을 안 썻던 겁니다 읍읍)

import tensorflow as tf import matplotlib.pyplot as plt import numpy as np x_data = [1, 3, 9, 4, 100] y_data = [0, 0, 1, 1, 1] a = tf.Variable(tf.random_uniform([1], 1.0, 2.0)) b = tf.Variable(tf.random_uniform([1], 1.0, 2.0)) X = tf.placeholder(tf.float32) Y = tf.placeholder(tf.float32) y = tf.div(1., 1. + tf.exp(-a * X + b)) loss = -tf.reduce_mean(Y * tf.log(tf.clip_by_value(y, 1e-8, 1.)) + (1 - Y) * tf.log(tf.clip_by_value(1 - y, 1e-8, 1.))) optimizer = tf.train.GradientDescentOptimizer(0.5) train = optimizer.minimize(loss) init = tf.initialize_all_variables() sess = tf.Session() sess.run(init) for step in xrange(2500): sess.run(train, feed_dict={X: x_data, Y: y_data}) if step % 100 == 0: print step, sess.run(loss, feed_dict={X: x_data, Y: y_data}), sess.run(a), sess.run(b) # Show result t = np.arange(0., 101., 0.01) plt.grid(True) plt.xlim(0, 101) plt.ylim(-0.5, 1.5) plt.plot(t, sess.run(y, feed_dict={X: t}), "g") # Train datas plt.plot(x_data, y_data, "ro") # Learing result plt.plot(x_data, sess.run(y, feed_dict={X: x_data}), "go") plt.show()


위 예제를 돌려서 그래프를 그려보면 다음과 같이 이쁘게 잘 나옵니다.

빨간색 점: 데이터셋

초록색 그래프: 학습된 그래프

초록색 점: 데이터셋에서 x를 넣었을 때의 값

이게 바로 Logistic Regression이고, 여기서 Classification을 하시려면 단순히 0.5를 기점으로 1에 가까운 지, 0에 가까운 지 분류하시면 됩니다.


이렇게 간단하게 Logistic Regression을 다뤄봤습니다. 다음 시간에는 다 변수의 Linear Regression, Logistic Regression을 다뤄볼 생각입니다. 다 변수인 만큼 차원도 많아져서 변수 두 개까지만 간단히 다뤄서 3D 그래프 그려보는게 이해에도 좋고 편할 거 같네요. 




+ Recent posts

티스토리 툴바