read

Softmax classification : Multinomial classification


soft

Softmax 함수를 구하기 전에, 간단히 이론을 보면,

Multinomial classification은 각각을 Linear 한 계산을 한번에 해준다고 보면된다.

[w1,w2,w3] * x1 = A, [w1,w2,w3] * x2 =B, [w1,w2,w3] * x3 = C

위와 같이, A냐 아니냐를 아는 weight와 x, B,C도 각각을 나눠주어 계산하는데, 이를 좀더 편하게 하기위해, 3*3 행렬을 이용해 한번에 계산한다.

그리고 그 결과값을 0과 1사이의 수로 만들어, 전체의 합이 1인 확률로 만드는데, 그게 softmax 함수다.

그 결과를 One-hot encoding을 할때는, 가장 확률이 높은 값을 1, 나머지를 0으로 만들면 된다.

그리고, cost function을 알아봐야 하는데, Cross-entropy라는 것을 쓴다.

cross-entropy의 구현과정은 개인적 학습에 맞기고, Logistic costcross entropy는 사실상 같다는 것만 알고 있자.

그럼 코드를 작성해보자.

import tensorflow as tf

# 4개의 element
x_data = [[1,2,1,1], [2,1,3,2], [3,1,3,4], [4,1,5,5], [1,7,5,5], [1,2,5,6], [1,6,6,6],[1,7,7,7]];
# 여러개의 출력 One-hot encoding
# 4개(1,2,1,1)가 들어왔을때 마지막 꺼만 1(0,0,1)
y_data = [[0,0,1],[0,0,1],[0,0,1],[0,1,0],[0,1,0],[0,1,0],[1,0,0],[1,0,0]];

X = tf.placeholder('float', [None, 4]);
Y = tf.placeholder('float', [None, 3]);

# Y의 갯수가 Label의 갯수
nb_classes = 3

# X(4개) * w = b (3개)
W = tf.Variable(tf.random_normal([4, nb_classes]), name='weight');
b = tf.Variable(tf.random_normal([nb_classes]), name='bias');

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);

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    for step in range(2001):
        sess.run(optimizer, feed_dict={X: x_data, Y: y_data});
        if step % 200 == 0:
            print(step, sess.run(cost, feed_dict={X: x_data, Y: y_data}));

    #Testing & One-hot encoding
    a = sess.run(hypothesis, feed_dict={X: [[1,11,7,9], [1,3,4,3],[1,1,0,1]]})
    # argument max인 값의 index를 출력
    print(a, sess.run(tf.arg_max(a, 1)));

code의 설명은 주석으로 처리해 두었다.

그럼 이를 좀더 Fancy하게 보도록 하자.

softmax_cross_entropy_with_logits라는 함수를 소개할 것이다.

logits = tf.matmul(X, W) + b

hypothesis = tf.nn.softmax(logits)

를 알아두자.

우리는 이전에, cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(hypothesis), axis=1));를 사용해 계산했다.

이를 조금더 간단히 하기 위해,

cost_i = tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=Y_one_hot)

cost = tf.reduce_mean(cost_i)

를 사용한다.

그럼 이걸 가지고 하나를 구현해보자.

data는 data-04-zoo.csv를 사용한다.

위 데이터는 동물을 특징(꼬리, 날개 등등)에 따라 분류한 데이터다. 그 데이터는 약 7가지의 분류가 된다.

따라서 Y데이터가 7이 된다.

그런데 One-hot encoding으로 바꿔주어야 한다.

그럴때 사용하는 것이 tf.one_hot이다.

파라미터로는 Y값과 몇개의 갯수가 있는지가 주어져야 한다.

그런데 여기서 중요한 것은, reshape다.

데이터가 [[0],[3]]라 할 때, one-hot을 하면, [[[1000000]],[[0001000]]]이 된다. 즉, 한 차원이 더 증가된다.

따라서 reshape를 쓴다.

Y_one_hot을 위 one_hot 함수를 쓴 것이라 할 때, ((?, 1, 7)의 형태 즉, 3차원)

Y_one_hot = tf.reshape(Y_one_hot, [-1, nb_classes])를 해준다.((?, 7)의 형태 즉, 2차원)

-1은 everything을 의미한다.

import tensorflow as tf
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 #0~6

# 특징 데이터 16개
X = tf.placeholder(tf.float32, [None, 16])
# Y는 한개 0~6
Y = tf.placeholder(tf.int32, [None, 1])

Y_one_hot = tf.one_hot(Y, nb_classes); #one-hot
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
hypothesis = tf.nn.softmax(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)

# 예측값 hypothesis probability의 최대값의 index를 뽑아 0~6 값으로 만듦
# 두번째 파라미터는 적용할 차원을 알려주는 매개변수, 0이면 2차원에서 열을 비교 즉, 한개만 비교하면 1개밖에 나오지 않는다. 1이면 2차원의 행을 비교
prediction = tf.argmax(hypothesis, 1)
# 그 값이, Y_one_hot으로 바꾸기 전 값과 비교
correct_prediction = tf.equal(prediction, tf.argmax(Y_one_hot, 1))
# 그 값을 모아서 평균을 냄
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

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))

    # 예측한 값과 비교
    pred = sess.run(prediction, feed_dict={X: x_data})
    # y 데이터를 [[1],[0]] -> [1,0] flatten 시켜, 각각의 list의 값을 각각 p와 y로 넘김
    for p, y in zip(pred, y_data.flatten()):
        print("[{}] Prediction: {} True Y: {}".format(p==int(y), p, int(y)))

이후는 다음에 진행하도록 하자.

Blog Logo

구찌


Published

Image

구찌의 나도한번 해블로그

구찌의 개발 블로그 입니다.

Back to Overview