Softmax Function


Logistic regression이란 아래의 식 처럼 0~1사이의 값을 출력해 준다.

$$ Z=H(X), g(z)$$
$$ g(z) = \frac{1}{1+e^{-z}}$$

이것을 그림으로 간소화 시켜보면 아래와 같다.

결국, Logistic Regression이라고 하는 것은 아래와 같은 두개의 데이터 분포에서
하나의 선을 그어서 데이터를 분할 하는 것을 말한다.

Activation Function으로 Sigmoid를 사용한다면 Logistic Regression과 Perceptron은 같은 개념 같기도 하다.

Multinomial Classification

여러개의 class로 확장을 해보자.

데이터 셋은 아래와 같다.

x1(hours)x2(attendance)y(grade)
105A
95A
32B
24B
111C

A, B, C 세 개가 있을 때

  • A or B, C
  • B or A, C
  • C or A, C 이렇게 세개의 Classifier가 있으면 가능 하다. 

그리고 이것을 각각 Matrix 연산을 하게 된다.

계산이 복잡하므로 이것을 합치면 아래와 같다.

그리고 세개의 값 중에서 가장 큰 값을 선택해서 그것으로 class label을 prediction 해도 괜찮다.

결국 20, 10, 0.1 이런식으로 나올 것이다.
하지만 이것은 우리가 원하는 것이 아니다.

0~1의 값을 가지며, 모든 class를 합치면 1이 되는 그러한 형태로 만들고 싶다.

그래서 사용하는것이 아래와 같은 Softmax함수이다.
그러면 0~1값과 모두 확률 값이므로 더하면 1이된다.

마지막으로 이중에서 가장 큰 확률을 가지는것만 1로 설정하고 나머지들은 모두 0으로 하기 위해서 아래와 같이
one hot encoding방식을 이용하게 된다.

이렇게해서 hypothesis는 완성이 되었다.

Cost Function 생성
예측값과 실제값 간의 차이를 나타내는 함수를 이제 설계 한다.
이것을 최소화 함으로써 학습을 완성하게 된다.

아래의 그림과 같이 예측값 $\hat{y}$과 실제값 $L=y$에대한 모습을 나타낸다.
그리고 이것의 차이를 나타내는 cost function을 cross entropy로 설정하게 된다.
즉 이전에 logistic regression의 cost function과 같은 형태인 것이다.

로그를 한것과 element wise multiplicatoin을 수행하는 형태이다.

수식으로 좀 더 자세히 표현하면 아래와 같다.

$$-\sum_{i}{L_{i}\log(S_{i})} = -\sum_{i}{L_{i} \log{(\hat{y}_{i})}}$$

여기서 곱은 내적 즉 element wise multiplication 이다.

결국 이것은 Logistic regression에서 다루었던 cost function
$$ C(H(x),y) = -y\log{(H(x))}+(1-y)\log{(1-H(x))}$$
과 같은 형태를 가진다.

각각을 예제에 따라서 계산해보면 아래와 같이 일치하면 cost가 0이고
불일치 하면 cost가 무한대로 계산 되는 것을 알 수 있다.

그리고 이것을 일반화 하면 아래와 같이 나오고 똑같이 미분해서 gradient descent알고리즘을 수행 시키면 된다.

Multinomial Classification 구현

구현 코드

import tensorflow as tf
import numpy as np

xy = np.loadtxt('softmaxTrain.txt', unpack=True, dtype='float')

x_data = np.transpose(xy[0:3])
y_data = np.transpose(xy[3:])
# tensorflow graph input
X = tf.placeholder('float', [None, 3]) # x1, x2, and 1 (for bias)
Y = tf.placeholder('float', [None, 3]) # A, B, C = > three classes
# set model weights
W = tf.Variable(tf.random_uniform([3,3],-1.0, 1.0))

# Our hypothesis
hypothesis = tf.nn.softmax(tf.matmul(X, W)) # softmax

# Cost function: cross entropy
cost = tf.reduce_mean(-tf.reduce_sum(Y*tf.log(hypothesis), reduction_indices=1))

# Minimize
a = tf.Variable(0.2) # Learning rate, alpha
optimizer = tf.train.GradientDescentOptimizer(a)
train = optimizer.minimize(cost)

# Before starting, initialize the variables. We will `run` this first.
init = tf.initialize_all_variables()

# Launch the graph,
with tf.Session() as sess:
    sess.run(init)

    # Fit the line.
    for step in xrange(10000):
        sess.run(train, 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}), sess.run(W)

    # Test model
    correct_prediction = tf.equal(tf.floor(hypothesis+0.5), Y)
    # Calculate accuracy (re-substitution error)
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    print sess.run([hypothesis, tf.floor(hypothesis+0.5), correct_prediction, accuracy], feed_dict={X:x_data, Y:y_data})
    print "Accuracy:", accuracy.eval({X:x_data, Y:y_data})

    # Test & one-hot encoding
    a = sess.run(hypothesis, feed_dict={X:[[1, 11, 7]]})
    print a, sess.run(tf.arg_max(a,1))

    b = sess.run(hypothesis, feed_dict={X: [[1, 3, 4]]})
    print b, sess.run(tf.arg_max(b, 1))

    c = sess.run(hypothesis, feed_dict={X: [[1, 1, 0]]})
    print b, sess.run(tf.arg_max(c, 1))

    all = sess.run(hypothesis, feed_dict={X:[[1, 11, 7], [1, 3, 4], [1, 1, 0]]})
    print all, sess.run(tf.arg_max(all, 1))

재치환 에러 (re-substitution)은 0이다. 결국 정확도는 1이 나온다.

두 번째는 샘플을 주고 각각의 argmax를 실행하는 것이다.
참값은 모르기 때문에 그냥 생성된 모델이 저렇게 예측한다는 것을 보기 위함이다.

실행결과

9800 0.0927773 [[-21.29355621   2.04889441  21.23555946]
 [  0.84294367   0.75854331   0.5262934 ]
 [  4.56429529   0.49110752  -3.74019885]]

[array([[  1.98164840e-15,   4.48229486e-07,   9.99999523e-01],
       [  1.17479602e-11,   4.03313388e-05,   9.99959707e-01],
       [  1.81849638e-04,   1.70287594e-01,   8.29530597e-01],
       [  6.83906451e-02,   8.93268943e-01,   3.83404866e-02],
       [  8.11137408e-02,   8.94745708e-01,   2.41405368e-02],
       [  5.18718772e-02,   8.72947454e-01,   7.51806125e-02],
       [  8.34491730e-01,   1.65429384e-01,   7.89094338e-05],
       [  9.97000158e-01,   2.99978442e-03,   1.59018363e-08]], dtype=float32), array([[ 0.,  0.,  1.],
       [ 0.,  0.,  1.],
       [ 0.,  0.,  1.],
       [ 0.,  1.,  0.],
       [ 0.,  1.,  0.],
       [ 0.,  1.,  0.],
       [ 1.,  0.,  0.],
       [ 1.,  0.,  0.]], dtype=float32), array([[ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True],
       [ True,  True,  True]], dtype=bool), 1.0]

재치환 에러는 0이고

Accuracy: 1.0
[[  9.97858584e-01   2.14142259e-03   4.48543203e-09]] [0]
[[  1.81849638e-04   1.70287609e-01   8.29530597e-01]] [2]
[[  1.81849638e-04   1.70287609e-01   8.29530597e-01]] [2]
[[  9.97858584e-01   2.14142259e-03   4.48543203e-09]
 [  1.81849638e-04   1.70287594e-01   8.29530597e-01]
 [  3.34250399e-19   4.98129182e-09   1.00000000e+00]] [0 2 2]

각각에 대한 출력값은 0,2,2 이다.
즉 학점으로 보면 A,C,C 인것이다.

출처

모두를 위한 머신러닝/딥러닝 강의, 김성훈 교수 (홍콩과기대)
http://hunkim.github.io/ml/


+ Recent posts