티스토리 뷰

이번 포스팅에서는 이항 분류(Binary Classification) 문제를 정의하고 있는 로지스틱 회귀에 대한 텐서플로우 구현에 대해서 이야기할 것이다.


구현하기전에 어떤 것을 다룰 것인지 간략하게 설명하자면..


여기서 다룰 트레이닝 데이터는 

학생이 n일동안 m시간 공부 했을 때  PASS 또는 FAIL에 대한 결과치에 해당하는 트레이닝 데이터 셋을 가지고 기계학습을 시킨 후 새로운 파라미터가 전달되었을 때 (일 수, 공부시간) 이 데이터에 대해서 PASS/FAIL을 결정하는 것을 지켜보겠다. 



여기서도 마찬가지로 오차 함수(Cost Function)가 최소화가 되도록 적절한 learning_rate의 파라미터를 지정하고 경사하강법 또는 최대경사법 최적화 알고리즘을 이용하여 기울기의 반대방향으로 조금씩 이동하여 최적해를 찾아내는 것이 목표가 되겠다.



물론, 로지스틱 회귀에 대해서는 기존의 선형 회귀의 H(w) = Wx + b 와 같은 식을 이용하게 되면 기울기가 사라져 국소 최적해(Local minimum)에 빠지게 되고 이를 보완하여 전체의 최적해(Global minimum)를 가지기 위해 이항 분류 문제에서의 오차 함수를 다르게 정의한다.


또한, 수치 데이터로 나타낸 가설을  0 또는 1의 데이터로 나타내기 위해 인코딩 하게 되는데 여기서 사용하는 

시그모이드 함수(Sigmoid Function) 의 매커니즘을 이용하여 구현하게 된다.



서두는 끝났다 이제 코드를 살펴보자!




위와 같이 설명했던 데로 트레이닝을 하기 위한 간단한 데이터 셋을 정의한다


1
2
3
4
5
6
import tensorflow as tf
 
# ex) x_data[1,5] = 1일동안 5시간 공부 한 것이라 예를 들면
x_data = [[1,2], [2,3], [3,1], [4,3], [5,3], [6,2]]
# Pass/Fail 를 나타내는 리스트
y_data = [[0],[0],[0],[1],[1],[1]]
cs




그리고 X와 Y의 변수를 feed_dict로 전달하기 위해 X는 두개의 파라미터(일 수, 공부시간) 을 전달하고 n개의 데이터를 받기 위해 shape를 [None, 2] 로 지정하고 Y의 출력 값은 1로

그리고 가중치와 바이어스 값은 난수 값을 생성한다.


1
2
3
4
5
6
7
= tf.placeholder(tf.float32, shape=[None, 2])
= tf.placeholder(tf.float32, shape=[None, 1])
 
# input = 2, output = 1 
= tf.Variable(tf.random_normal([2,1]), name='weight')
# output = 1
= tf.Variable(tf.random_normal([1]), name='bias')
cs



우리의 가설을 시그모이드 함수로 정의 한뒤 새롭게 정의된 오차 함수를 적용한다.
(새로운 오차함수를 정의하는 코드는 밑에 있음)


1
2
3
4
# sigmoid function 은 우리의 가설 H(X) = 1/(1+e^(-w.transpose * X))
# tf.div(1., tf.exp(tf.matmul(X, W) + b)) 와 같음
hypothesis = tf.sigmoid(tf.matmul(X, W) + b)
 
cs





여기서 오차함수는 0과 1 사이의 정보로 인코딩의 조건을 충족하기 위해 

- log(x)의 그래프와 -log(1-x)의 그래프를 활용하게 된다.


-log(x)의 그래프를 살펴보게 되면

y(실제 데이터)의 값이 1을 나타내고 우리의 가설 H(x)가 1로 예측하여 cost(1) 일 때 0으로 수렴하여 비용 함수가 최소 값에 가까워지도록 하고 H(x)가 0으로 예측하여 cost(0) 일 때 1로 수렴하여 비용 함수가 증가하고 오차가 커지게 오차 함수의 값을 조정한다.


H(x) = 1 -> cost(1) = 0

H(x) = 0 -> cost(0) = INFINITE



이와 반대로 실제 결과 데이터가 0(y=0)이라고 했을 때, -log(1-x)의 그래프를 가지게 되어 오차함수를 반대로 한다.



그래서 이와 같이 오차 함수가 이항 분류를 위해서 가지는 경우의 수 두가지에 해당하는 식을 표현 하자면,




아래와 같이 나타낼 수 있는데 오차 함수를 계산하는데 있어서 조건을 항상 계산하는 것은 문제가 있다. 

따라서 식을 변형하면, 다음과 같이 나타낼 수 있다.




이를 코드로 표현하자면, 이와 같이 오차함수를 정의할 수 있고 이에 따라 cost를 최소화 하도록 경사 하강법을 적용한다.

그리고 그렇게 시그모이드 함수를 통과 시킨 우리의 가설 즉, 예측 값을 0 또는 1로 캐스팅하고 실제 데이터(Y)와 일치하는지 정확도를 계산한다.


1
2
3
4
5
6
7
8
9
10
# 새롭게 정의된 오차함수
cost = -tf.reduce_mean(Y * tf.log(hypothesis) + (1 - Y) * (tf.log(1 - hypothesis)))
 
# 학습 그래프 최적화 알고리즘 경사하강법
train = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(cost)
 
# 예측값 H(X) > 0.5 is true, else false
predicted = tf.cast(hypothesis > 0.5, dtype=tf.float32)
# 0이나 1의 값을 트레이닝 횟수만큼 평균치 계산
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicted, Y), dtype=tf.float32))
cs



이에 따라, 그래프를 정의하고 세션을 통하여 트레이닝을 시킨다. 그리고 cost 값이 점점 최소화 되는지 관찰해본다.


1
2
3
4
5
6
7
8
9
10
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    
    for step in range(10001):
        cost_val,  _ = sess.run([cost, train], feed_dict={X:x_data, Y:y_data})
        
        if step % 1000 == 0:
            print(step, '\t', cost_val)
            
 
cs




실제로 트레이닝 1000회당 한번씩 로그를 출력해본 결과 cost값이 최소화 되고 있음을 알 수 있다.

0 	 3.13908
1000 	 0.353375
2000 	 0.301208
3000 	 0.263343
4000 	 0.23338
5000 	 0.209213
6000 	 0.189422
7000 	 0.17298
8000 	 0.159137
9000 	 0.147342
10000 	 0.137183



이를 통하여 우리의 로지스틱 회귀 모델이 위의 테스트 데이터를 잘 예측하는지 관찰해보면 될 것이다.






※ 본 포스팅은 최대한 정리하고자 노력하긴 했으나, 개인 공부 목적으로 남긴 글이며 본 사실과 다른 부분이 있다면 과감하게 지적 부탁드립니다. 홍콩과기대의 김성훈 교수님의 강의를 기반으로 만들어진 정리의 글임을 알립니다!


반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/05   »
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
글 보관함