본문 바로가기

Data Science/Machine Learning 구현

[ML] Tensorflow를 이용해 (Binary and Multi)Logistic Regression 구현하기

반응형

🔉해당 자료 내용은 순천향대학교 빅데이터공학과 김정현 교수님의 수업자료에 기반하였으며 수업자료의 저작권 문제로 인해 수업자료를 직접 이용하지 않고 수업자료의 내용을 참고하여 본인이 직접 작성하였으므로 저작권 문제가 발생하지 않음을 필히 알려드립니다. 

 

이번 포스팅에서는 저번 시간인 Tensorflow를 이용한 뉴럴네트워크 구현하기에서 배웠던 기본 문법과 구현 과정을 기반으로 회귀 모델이지만 분류 문제해결에 사용되는 Logistic Regression 모델을 구현해보려고 한다. Logistic Regression에서도 이진(Binary) 분류인지 다중(Multi)분류인지에 따라 사용하는 활성함수의 종류가 다르다. 이제 예시 데이터를 사용해서 각 모델을 텐서플로우를 이용해 구현해보자.

 

Logistic Regression은 분류를 위한 모델이다.

 

1. Logistic Regression 구현하기

2. Multi-class Logistic Regression 구현하기

1. Logistic Regression 구현하기

Logistic Regression은 Linear Regression(선형 회귀)에서 출발한 모델이지만 연속적인 숫자값을 예측하는 선형회귀와는 달리 범주형 변수를 예측한다는 점에서 차이점이 존재한다. input으로 들어오게 되는 데이터들에 Weight와 bias값을 곱하여 summation을 해주는 Activation function(활성함수)로 Sigmoid function을 사용한다. 

 

Sigmoid function은 0과 1사이의 값으로 반환해준다.

 

Sigmoid function의 가장 큰 특징이라고 한다면 반드시 결과값을 0과 1사이의 값으로 반환하게 된다는 점이다. 분류문제를 해결하기 위해서는 값이 무한히 커지거나 작아져서는 안 된다. 따라서 이러한 문제를 방지하기 위해 Sigmoid function을 발견하고 이를 적용하게 되었다.

 

이렇게 Sigmoid function으로 학습 데이터를 활용해 예측값을 1차적으로 도출했다. 하지만 머신러닝의 본질은 계속적인 학습이다. 지속적인 학습을 위해서는 자신의 예측값이 정답과 얼마나 오차가 있는지 자가 진단을 해야한다. 이것이 바로 Cost function을 활용해 Cost값을 최소화시켜주는 것을 의미한다. Logistic Regression의 Cost function은 Cross-entropy를 사용하며 Cross-entropy로 Cost값을 계산한 후 SGD(Stochastic Gradient Descent)방법, 즉, 경사하강법을 통해 Cost값을 점진적으로 최소화 시켜준다. 

 

https://towardsdatascience.com/where-did-the-binary-cross-entropy-loss-function-come-from-ac3de349a715

 

위 공식은 Cross-entropy 공식이다. 미지수에 대해 간단히 설명하자면 m은 데이터의 개수, y(i)는 i번째 데이터의 실제 y값, p(i)는 i번째 데이터의 예측된 y값을 의미한다. 

 

이론적인 설명은 이걸로 간단히 마치고 더 자세하게 Logistic Regression에 대해 알고 싶다면 여기를, Cross-entropy가 어떻게 계산되는지 알고 싶다면 여기를 참조하길 바란다.

 

이제 Logistic Regression의 기본 구조를 알았으니 텐서플로우를 이용해 코드로 구현해보자. 간단하게 임의로 데이터를 부여해서 실습을 해보자.

 

import tensorflow as tf
import warnings
warnings.filterwarnings(action='ignore')

x_data = [[1,2], [2,3], [3,1], [4,3], [5,3], [6,2]]
y_data = [[0],[0],[0],[1],[1],[1]]

X = tf.placeholder(tf.float32, shape=[None, 2])
Y = tf.placeholder(tf.float32, shape=[None, 1])
W = tf.Variable(tf.random_normal([2,1]), name='weight')
b = tf.Variable(tf.random_normal([1]), name='bias')

# sigmoid함수를 input summation 해주는 활성함수 적용
hypothesis = tf.sigmoid(tf.matmul(X, W) + b)

# cross entropy라는 Cost function정의
cost = -tf.reduce_mean(Y * tf.log(hypothesis) + (1 - Y) * tf.log(1- hypothesis))
# SGD 적용해서 minimize cost
train = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(cost)

# 0.5값 이상이면 True(1)로 예측되도록 함
# cast함수: float형으로 출력되는 hypothesis값이 0.5보다 크면 정수 1(True), 작으면 정수 0(False)으로 변환
predicted = tf.cast(hypothesis > 0.5, dtype=tf.float32)
# 예측값과 실제값 비교해서 Boolean으로 반환 후, 1(True)값들의 평균을 내어서 accuracy 출력
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicted, Y),
                                 dtype=tf.float32))

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 % 200 == 0:
            print(step, cost_val)
    
    # 위에서 역전파 학습으로 cost를 최소하하도록 학습한 후 마지막 업데이트 상태에서 forwarding한 후 예측된 확률값, 예측된 클래스값, 정확도 출력
    h, c, a = sess.run([hypothesis, predicted, accuracy],
                      feed_dict={X:x_data, Y:y_data})
    print("\nHypothesis:\n", h, "\nCorrect(Y):\n", c,"\nAccuracy:\n", a)

 

위 코드에서 텐서플로우의 문법 중 cast함수, equal함수의 반환 값이 어떻게 되는지 궁금하다면 여기를 참고하자.

2. Multi-class Logistic Regression

Softmax Regression이라고도 부르며 예측하려는 범주형 변수의 level이 3개 이상일 때 사용한다. 방금까지 살펴보았던 Binary Logistic Regression과는 달리 활성함수를 Sigmoid function이 아닌 Softmax function을 사용한다. 하지만 이름만 다를 뿐 Sigmoid function에서 클래스 개수를 3개 이상으로 일반화 시키면 Softmax function이 유도된다.

 

반면에 Multi-class Logistic Regression도 Cost function은 Cross-entropy를 사용한다. Multi-class Logistic Regression에 대해서 자세히 알고 싶다면 여기를 참고하자.

 

이제 Softmax Regression을 동물 예시 데이터를 활용해 텐서플로우로 구현해보자.

 

import numpy as np

xy = np.loadtxt('data-04-zoo.csv', delimiter=',',
               dtype=np.float32)
x_data = xy[:, 0:-1]
y_data = xy[:, [-1]]

# 클래스 개수 할당
nb_classes = 7
# 16개의 Feature
X = tf.placeholder(tf.float32, shape=[None, 16])
Y = tf.placeholder(tf.int32, shape=[None, 1])
# ?는 몇개의 데이터 개수가 들어올지 모르니 유동적인 값을 의미
# target을 원 핫 인코딩 시켜주기, one_hot은 그런데 3차원 shape(?, 1, 7)로 반환함.. 
Y_one_hot = tf.one_hot(Y, nb_classes)
# 그래서 2차원 shape으로 만들어주어야 함. (?, 7)로!
Y_one_hot = tf.reshape(Y_one_hot, [-1, nb_classes])

W = tf.Variable(tf.random_normal([16, nb_classes]), name='weight')
b = tf.Variable(tf.random_normal([nb_classes]), name='bias')

logits = tf.matmul(X, W) + b
# 활성함수를 Softmax function을 사용
hypothesis = tf.nn.softmax(logits)

# 텐서플로우는 Softmax 활성함수와 cross-entropy Cost function을 한 번에 정의 가능. 대신 logits인자에 활성함수 적용 '전'을 넣어야 함!
cost_i = tf.nn.softmax_cross_entropy_with_logits(logits=logits,
                                                labels=Y_one_hot)

cost = tf.reduce_mean(cost_i)
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)

# argmax 인자의 1은 max를 찾을 방향을 찾는것: 0=행, 1=열
# tf.argmax : hypothesis 배열 중 열(1)기준으로 가장 큰 값을 갖는 index를 반환시킴
prediction = tf.argmax(hypothesis, 1)
# 예측값과 실제값을 비교해 Boolean값 맞췄으면 True(1), 틀렸으면 False(0)으로 반환
correct_prediction = tf.equal(prediction, tf.argmax(Y_one_hot, 1))
# 예측값과 실제값이 일치하는 True값들의 평균 계산하여 accuracy 계산
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    # 2000번 학습을 통해서 SGD수행
    for step in range(2000):
        sess.run(optimizer, feed_dict={X:x_data, Y:y_data})
        if step % 100 == 0:
            loss, acc = sess.run([cost, accuracy],
                                feed_dict={X:x_data, Y:y_data})
            print(f"Step:{step}\nLoss:{loss:.4f}\nAcc:{acc:.2f}")
            
    # 2000번의 학습 종료 후 마지막에 업데이트된 파라미터값으로 예측값 출력
    pred = sess.run(prediction, feed_dict={X:x_data})
    # 실제값의 차원을 예측값과 일치시켜준 후 예측값과 실제값 각각 출력
    for p, y in zip(pred, y_data.flatten()):
        print(f"[{p==int(y)}] Prediction:{p}, True_Y:{int(y)}")

 

# Reference

towardsdatascience.com/where-did-the-binary-cross-entropy-loss-function-come-from-ac3de349a715
 

Where did the Binary Cross-Entropy Loss Function come from?

Binary Classification presents a unique problem where: each example(x, y) belongs to one of two complementary classes, each example…

towardsdatascience.com

hero4earth.com/blog/learning/2018/01/15/tensor_flow_basics/
 

사회 혁신을 위한 데이터 중심의 서비스 기획자

더 나은 세상을 위한 데이터 중심의 서비스 기획가를 꿈꿉니다. 데이터 분석, 그로스해킹, 머신러닝, UX, 디자인씽킹, 애자일, 스타트업, 비즈니스, IT기술에 관심이 많습니다.

hero4earth.com

반응형