본문 바로가기
AI

ML06-2-logistic-regression : multiple-classification(softmax-classifier)

by 월곡동로봇팔 2019. 10. 23.

이번 게시물은 logistic_regression에서도 여러 value로 분류하는 Multiple Classification 이다.

import tensorflow as tf
import numpy as np
tf.set_random_seed(777)  # for reproducibility

# Predicting animal type based on various features
xy = np.loadtxt('./data-04-zoo.csv', delimiter=',', dtype=np.float32)
x_data = xy[:, 0:-1]
y_data = xy[:, [-1]]

print(x_data.shape, y_data.shape)
print(x_data)
'''
(101, 16) (101, 1)
'''

# y_data들의 종류들의 갯수
nb_classes = 7  # 0 ~ 6

X = tf.placeholder(tf.float32, [None, 16])
Y = tf.placeholder(tf.int32, [None, 1])  # 0 ~ 6 까지 담아내는 그릇

 

numpy를 이용하여 loadtxt 파일을 이용하여 csv파일을 불러올 때, delimiter를 ','으로 나눠서 가져온다.

그 다음 x_data, y_data로 나누고 shape을 꼭 살펴봐야지 나중에 X, Y placeholder의 shape도 정할 수 있다.

xy 불러온 data의 형태는 다음과 같다.

 

"""
xy data:

1,0,0,1,0,0,1,1,1,1,0,0,4,0,0,1,0
1,0,0,1,0,0,0,1,1,1,0,0,4,1,0,1,0
0,0,1,0,0,1,1,1,1,0,0,1,0,1,0,0,3
1,0,0,1,0,0,1,1,1,1,0,0,4,0,0,1,0
1,0,0,1,0,0,1,1,1,1,0,0,4,1,0,1,0
1,0,0,1,0,0,0,1,1,1,0,0,4,1,0,1,0
1,0,0,1,0,0,0,1,1,1,0,0,4,1,1,1,0
0,0,1,0,0,1,0,1,1,0,0,1,0,1,1,0,3
0,0,1,0,0,1,1,1,1,0,0,1,0,1,0,0,3
1,0,0,1,0,0,0,1,1,1,0,0,4,0,1,0,0
1,0,0,1,0,0,1,1,1,1,0,0,4,1,0,1,0
0,1,1,0,1,0,0,0,1,1,0,0,2,1,1,0,1
0,0,1,0,0,1,1,1,1,0,0,1,0,1,0,0,3

"""

 

 

# One_hot function
Y_one_hot = tf.one_hot(Y, nb_classes)  # one hot rank 가 n이면 rank n+1로 리턴
print("one_hot:", Y_one_hot)

# reshape([-1, nb_classes]) 여기서 -1은 모든 숫자를 가져온다는 의미
Y_one_hot = tf.reshape(Y_one_hot, [-1, nb_classes])
print("reshape one_hot:", Y_one_hot)

 

tf.one_hot 메소드는 Y가 [[0],[0],[3],[0],[0],-----] 이런형식이라면,

이를 [ [[1,0,0,0,0,0,0]], [[1,0,0,0,0,0,0]], [[0,0,0,1,0,0,0]] -----]      이런형식으로 바꿔준다.

따라서 y값이 나타내고 있는 부분을 한 array의 index로 생각한다. 이 때 차원이 하나 늘어나기 떄문에!!!!!

항상 reshape를 꼭 해줘야한다.

 

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

# tf.nn.softmax_cross_entropy_with_logits_v2 쓸 때!!
logits = tf.matmul(X, W) + b
hypothesis = tf.nn.softmax(logits)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=logits,
									labels=tf.stop_gradient([Y_one_hot])))
                                                                 
# 안 쓸때는!!
hypothesis = tf.nn.softmax(tf.matmul(X, W) + b)
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(hypothesis), axis=1))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)

 

 

여기서 우리는 최적화함수를 sigmoid 가 아닌 softmax를 쓴다

softmax란!!

 

 

softmax function

 

softmax는 y값들을 exponential의 제곱수에 y를 대입하여 모두 합친 값 중에 개별y값이 가지는 값을 나눠준 것으로 이들의 합은 모두 1로 수렴한다. 이는 각각 y들이 모델에 영향을 끼치는 정도를 말한 것이며, 이는 각각이 모델에 끼치는 확률을 말해준다. 

 

sigmoid와 헷갈리는데, sigmoid는 그저 우리가 큰 data를 다루다보면 숫자가 크기 때문에,

이를 방지하기위해 Hypothesis 의 범위를 줄인 것이다. 이는 binary classificatino 할 때 주로 쓴다. 흔히 이를 Activation Function이라고 부른다.

softmax는 각 y값들이 모델에 어느정도로 영향을 끼치는지 확률로써 알기위해 쓰는 함수이며, 장점은 출력확률범위이다.

이는 multi classification 할 때 쓴다.

 

 

# tf.nn.softmax_cross_entropy_with_logits_v2 쓸 때!!
logits = tf.matmul(X, W) + b
hypothesis = tf.nn.softmax(logits)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=logits,
									labels=tf.stop_gradient([Y_one_hot])))
                                                                 
# 안 쓸때는!!
hypothesis = tf.nn.softmax(tf.matmul(X, W) + b)
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(hypothesis), axis=1))

 

여기서 두 개의 차이점이 존재한다. 

tf.nn.softmax_cross_entropy_with_logits_v2(logits=logits, labels=tf.stop_gradient([Y_one_hot])) 는 cost함수를 구현하는 것을 logits 부분에 Hypothesis 전 X와 weight, bias 를 연산한 값만 넣어주고, label에는 tf.stop_gradient([Y_one_hot])을 넣어준다.

 

tf.stop_gradient(label)은 label이 포함되어있는 값들을 변하지 않고 유지시키는 것을 의미한다.

 

사실 나는 밑에 부분을 더 선호한다. 위에가 더 짧게 구현할 수는 있지만, 밑에 코드가 더 세분화해서 구현하기 때문에 나중에 내가 코드를 확인할 때 더 세분화해서 확인할 수 있다.

 

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

# prediction은 hypothesis에서 axis = 1일때 가장 큰 값을 return한다.
prediction = tf.argmax(hypothesis, 1)

# correct_prediction 은 prediction과 동일한지 비교.
correct_prediction = tf.equal(prediction, tf.argmax(Y_one_hot, 1))

# accuracy 은 tf.cast는 correct_prediction이 True이면 1, False이면 0, 정확도높을수록 1근사.
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

 

prediction은 예측값으로 hypothesis중에서 axis = 1인 구간에서 제일 큰 값의 index를 return하면서 예측값으로 정한다.

correct_prediction은 prediction과 tf.argmax(Y_one_hot, 1)과 같으면 1을 retunn한다. tf.equal(A,B)가 A, B가 서로 일치하면True, 아니면 False를 return한다.

accuracy은 tf.cast(A)는 A가 True이면 1, A가 False이면 0을 return 한다. 결론은 prediction이 실제 Y_one_hot과 같으면 correct_prediction이 1로 되고 tf.cast가 True이기 때문에 1을 많이 return을 하기 때문에 accuracy는 100을 향해 갈 것이다.

 

# Launch graph
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    for step in range(2001):
        _, cost_val, acc_val = sess.run([optimizer, cost, accuracy], feed_dict={X: x_data, Y: y_data})
                                        
        if step % 100 == 0:
            print("Step: {:5}\tCost: {:.3f}\tAcc: {:.2%}".format(step, cost_val, acc_val))

    # Let's see if we can predict
    pred = sess.run(prediction, feed_dict={X: x_data})
    # y_data: (N,1) = flatten => (N, ) matches pred.shape
    """
        flatten : [[1],[0]] - > [1, 0]
        zip : 하나의 list로 묶음.
    """
    for p, y in zip(pred, y_data.flatten()):
        print("[{}] Prediction: {} True Y: {}".format(p == int(y), p, int(y)))

※ 중간에 format 함수에 {:.2%} 는 원래 숫자를 2를 곱해서 %치로 나타내준다.

※ flatten은 reshape과 같은 맥락으로 dimension을 서로 합쳐준다.

'AI' 카테고리의 다른 글

ML07-4-MNIST-data (실제 data 분석)  (0) 2019.10.24
ML07-4-MNIST-data  (0) 2019.10.24
ML05-1-logistic_regression : Binary Classification  (0) 2019.10.23
ML04-1-linear-regression(Tensorflow basic)  (0) 2019.10.23
Tensorflow : background  (6) 2019.10.23

댓글