본문 바로가기
Dev/딥러닝

06-2. Tensorflow 에서 One hot 인코딩을 이용한 classification

by bsion 2018. 8. 22.
06-2. Fancy Softmax Classification

출처 : 모두를위한 머신러닝 (http://hunkim.github.io/ml/)


One hot incoding 이란

One hot 인코딩은 특정 상수값으로 표현된 Y 를 Matrix 형태로 바꿔주는 방법이다.

위의 데이터를 보면 원본 파일에서는 각 직업에 따라 1~5 사이의 값으로 그 직업을 대표했다면, one hot encoding 을 거치고 난 후엔 1x5 행렬에서 한 값만 1이고 나머지는 0을 갖는 행렬로 표시된다.

아래 예제에서 Tensorflow 에서 어떻게 구동되는지 살펴본다.

예제: 동물의 종 파악하는 알고리즘

파일 위치: https://raw.githubusercontent.com/hunkim/DeepLearningZeroToAll/master/data-04-zoo.csv

데이터파일의 각 column 이 나타내는 의미:

  1. animal name: (deleted),,,,,,,,,,,,,,,,
  2. hair Boolean",,,,,,,,,,,,,,,,
  3. feathers Boolean",,,,,,,,,,,,,,,,
  4. eggs Boolean",,,,,,,,,,,,,,,,
  5. milk Boolean",,,,,,,,,,,,,,,,
  6. airborne Boolean",,,,,,,,,,,,,,,,
  7. aquatic Boolean",,,,,,,,,,,,,,,,
  8. predator Boolean",,,,,,,,,,,,,,,,
  9. toothed Boolean",,,,,,,,,,,,,,,,
  10. backbone Boolean",,,,,,,,,,,,,,,,
  11. breathes Boolean",,,,,,,,,,,,,,,,
  12. venomous Boolean",,,,,,,,,,,,,,,,
  13. fins Boolean",,,,,,,,,,,,,,,,
  14. legs Numeric (set of values: {0",2,4,5,6,8}),,,,,,,,,,,
  15. tail Boolean",,,,,,,,,,,,,,,,
  16. domestic Boolean",,,,,,,,,,,,,,,,
  17. catsize Boolean",,,,,,,,,,,,,,,,
  18. type Numeric (integer values in range [0",6]),,,,,,,,,,,,,,,

데이터 로드

  • 데이터를 읽어들이고 가장 마지막 column 을 y 로 설정한다.
  • 동물의 종의 종류가 7개 (0~6)
  • X 의 placeholder 의 shape 은 16개의 column 이 존재하고, row 의 갯수는 알수없으므로 [None, 16] 으로 한다.
  • Y 의 placeholder 는 0~6 사이의 값을 하나 갖기 때문에 [None, 1] 로 한다.
In [1]:
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('./static/data-04-zoo.csv', delimiter=',', dtype=np.float32)
x_data = xy[:, 0:-1]
y_data = xy[:, [-1]]

print(x_data.shape, y_data.shape)

nb_classes = 7  # 0 ~ 6

X = tf.placeholder(tf.float32, [None, 16])
Y = tf.placeholder(tf.int32, [None, 1])  # 0 ~ 6
(101, 16) (101, 1)

One hot 방법

  • 이 예제에서는 0~6으로 표현된 종의 종류를 Matrix 형태로 바꿔주는 방법이다.
    0 : [0, 0, 0, 0, 0, 0, 0]
    1 : [0, 0, 0, 0, 0, 0, 1]
    2 : [0, 0, 0, 0, 0, 1, 0]
    3 : [0, 0, 0, 0, 1, 0, 0]
    ... 생략

  • 그런데 tensorflow 에 내장되어있는 one_hot 을 사용할 경우 dimension 이 증가한다.

  • 이 증가한 dimension 은 reshape 모듈을 이용하여 원래의 dimension 으로 바꿔준다.
In [2]:
Y_one_hot = tf.one_hot(Y, nb_classes)  # one hot
print("one_hot", Y_one_hot)            # one_hot은 N 차원을 받으면 N+1 차원을 return 함
Y_one_hot = tf.reshape(Y_one_hot, [-1, nb_classes])
print("reshape", Y_one_hot)
one_hot Tensor("one_hot:0", shape=(?, 1, 7), dtype=float32)
reshape Tensor("Reshape:0", shape=(?, 7), dtype=float32)

W, b 의 shape 결정

  • X W = Y 가 되야 하므로 (None x 16) * (16 x 7) = (None x 7)
In [3]:
W = tf.Variable(tf.random_normal([16, nb_classes]), name='weight')
b = tf.Variable(tf.random_normal([nb_classes]), name='bias')

with_logits 을 이용한 cost 계산

In [4]:
# tf.nn.softmax computes softmax activations
# softmax = exp(logits) / reduce_sum(exp(logits), dim)
logits = tf.matmul(X, W) + b
hypothesis = tf.nn.softmax(logits)

# Cross entropy cost/loss
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)
WARNING:tensorflow:From <ipython-input-4-81897dd691b1>:8: softmax_cross_entropy_with_logits (from tensorflow.python.ops.nn_ops) is deprecated and will be removed in a future version.
Instructions for updating:

Future major versions of TensorFlow will allow gradients to flow
into the labels input on backprop by default.

See @{tf.nn.softmax_cross_entropy_with_logits_v2}.

Session 돌리기

In [5]:
prediction = tf.argmax(hypothesis, 1)
correct_prediction = tf.equal(prediction, tf.argmax(Y_one_hot, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
# Launch graph
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    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("Step: {:5}\tLoss: {:.3f}\tAcc: {:.2%}".format(
                step, loss, acc))

    # 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
    for p, y in zip(pred, y_data.flatten()):
        print("[{}] Prediction: {} True Y: {}".format(p == int(y), p, int(y)))
Step:     0	Loss: 5.106	Acc: 37.62%
Step:   100	Loss: 0.800	Acc: 79.21%
Step:   200	Loss: 0.486	Acc: 88.12%
Step:   300	Loss: 0.349	Acc: 90.10%
Step:   400	Loss: 0.272	Acc: 94.06%
Step:   500	Loss: 0.222	Acc: 95.05%
Step:   600	Loss: 0.187	Acc: 97.03%
Step:   700	Loss: 0.161	Acc: 97.03%
Step:   800	Loss: 0.140	Acc: 97.03%
Step:   900	Loss: 0.124	Acc: 97.03%
Step:  1000	Loss: 0.111	Acc: 97.03%
Step:  1100	Loss: 0.101	Acc: 99.01%
Step:  1200	Loss: 0.092	Acc: 100.00%
Step:  1300	Loss: 0.084	Acc: 100.00%
Step:  1400	Loss: 0.078	Acc: 100.00%
Step:  1500	Loss: 0.072	Acc: 100.00%
Step:  1600	Loss: 0.068	Acc: 100.00%
Step:  1700	Loss: 0.064	Acc: 100.00%
Step:  1800	Loss: 0.060	Acc: 100.00%
Step:  1900	Loss: 0.057	Acc: 100.00%
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 3 True Y: 3
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 3 True Y: 3
[True] Prediction: 3 True Y: 3
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 1 True Y: 1
[True] Prediction: 3 True Y: 3
[True] Prediction: 6 True Y: 6
[True] Prediction: 6 True Y: 6
[True] Prediction: 6 True Y: 6
[True] Prediction: 1 True Y: 1
[True] Prediction: 0 True Y: 0
[True] Prediction: 3 True Y: 3
[True] Prediction: 0 True Y: 0
[True] Prediction: 1 True Y: 1
[True] Prediction: 1 True Y: 1
[True] Prediction: 0 True Y: 0
[True] Prediction: 1 True Y: 1
[True] Prediction: 5 True Y: 5
[True] Prediction: 4 True Y: 4
[True] Prediction: 4 True Y: 4
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 5 True Y: 5
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 1 True Y: 1
[True] Prediction: 3 True Y: 3
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 1 True Y: 1
[True] Prediction: 3 True Y: 3
[True] Prediction: 5 True Y: 5
[True] Prediction: 5 True Y: 5
[True] Prediction: 1 True Y: 1
[True] Prediction: 5 True Y: 5
[True] Prediction: 1 True Y: 1
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 6 True Y: 6
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 5 True Y: 5
[True] Prediction: 4 True Y: 4
[True] Prediction: 6 True Y: 6
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 1 True Y: 1
[True] Prediction: 1 True Y: 1
[True] Prediction: 1 True Y: 1
[True] Prediction: 1 True Y: 1
[True] Prediction: 3 True Y: 3
[True] Prediction: 3 True Y: 3
[True] Prediction: 2 True Y: 2
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 1 True Y: 1
[True] Prediction: 6 True Y: 6
[True] Prediction: 3 True Y: 3
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 2 True Y: 2
[True] Prediction: 6 True Y: 6
[True] Prediction: 1 True Y: 1
[True] Prediction: 1 True Y: 1
[True] Prediction: 2 True Y: 2
[True] Prediction: 6 True Y: 6
[True] Prediction: 3 True Y: 3
[True] Prediction: 1 True Y: 1
[True] Prediction: 0 True Y: 0
[True] Prediction: 6 True Y: 6
[True] Prediction: 3 True Y: 3
[True] Prediction: 1 True Y: 1
[True] Prediction: 5 True Y: 5
[True] Prediction: 4 True Y: 4
[True] Prediction: 2 True Y: 2
[True] Prediction: 2 True Y: 2
[True] Prediction: 3 True Y: 3
[True] Prediction: 0 True Y: 0
[True] Prediction: 0 True Y: 0
[True] Prediction: 1 True Y: 1
[True] Prediction: 0 True Y: 0
[True] Prediction: 5 True Y: 5
[True] Prediction: 0 True Y: 0
[True] Prediction: 6 True Y: 6
[True] Prediction: 1 True Y: 1

전체 코드

In [ ]:
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('./static/data-04-zoo.csv', delimiter=',', dtype=np.float32)
x_data = xy[:, 0:-1]
y_data = xy[:, [-1]]

print(x_data.shape, y_data.shape)

nb_classes = 7  # 0 ~ 6

X = tf.placeholder(tf.float32, [None, 16])
Y = tf.placeholder(tf.int32, [None, 1])  # 0 ~ 6

Y_one_hot = tf.one_hot(Y, nb_classes)  # one hot
print("one_hot", Y_one_hot)            # one_hot은 N 차원을 받으면 N+1 차원을 return 함
Y_one_hot = tf.reshape(Y_one_hot, [-1, nb_classes])
print("reshape", Y_one_hot)

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

# tf.nn.softmax computes softmax activations
# softmax = exp(logits) / reduce_sum(exp(logits), dim)
logits = tf.matmul(X, W) + b
hypothesis = tf.nn.softmax(logits)

# Cross entropy cost/loss
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)

prediction = tf.argmax(hypothesis, 1)
correct_prediction = tf.equal(prediction, tf.argmax(Y_one_hot, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
# Launch graph
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    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("Step: {:5}\tLoss: {:.3f}\tAcc: {:.2%}".format(
                step, loss, acc))

    # 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
    for p, y in zip(pred, y_data.flatten()):
        print("[{}] Prediction: {} True Y: {}".format(p == int(y), p, int(y)))


댓글