다변수 분류(Multinomial classification) : Softmax classification 연습
Softmax 함수
- \(n\)개의 값을 예측할 때 Softmax 분류 함수를 사용하여 확률분포로 만들어 준다.
- 아래 그림 같이 학습할 데이터 \(\mathbf{X}\)에 학습할 weight \(\mathbf{W}\)를 곱해서 예측값 \(\mathbf{Y}\)를 만드는 것으로 부터 시작한다.
- 즉, 다변수 분류에서 기본 가설식(logit) \(\mathbf{Y}\)는 식 (1)과 같다.
\begin{eqnarray} \mathbf{Y} = \mathbf{X} \mathbf{W} + \mathbf{b} \tag{1} \end{eqnarray}
- 그러나 식 (1)의 결과는 그냥 점수(score)에 불과하다.
- 식 (1)의 결과를 Softmax 함수에 통과시키면 결과가 확률로 나타나 분류대상에 대하여 확률분포를 만들 수 있다. 기본 가설식에 Softmax 함수를 적용한 결과가 우리가 원하는 가설식이다. 즉, 식 (2)가 가설식이다.
\begin{eqnarray} H(x) &=& \textrm{Softmax}(\mathbf{Y})\\ &=& \textrm{Softmax}(\mathbf{X} \mathbf{W} + \mathbf{b}) \tag{2} \end{eqnarray}
Softmax 함수를 사용하는 모델
- 아래 그림과 같이 TensorFlow를 사용하여 수식을 그대로 써주면 된다.
- 기본 가설식 식 (1)은 다음과 같은 코드를 사용한다.
tf.matmul(X,W) + b
- 최종 가설식 식 (2) $H(x)$는 다음과 같은 코드를 사용하여 확률분포를 계산할 수 있다.
hypothesis = tf.nn.softmax(tf.matmul(X,W) + b)
- Cost(Loss) 함수 식 (3)처럼 CROSS-ENTROPY로 표현할 수 있으며, 다음과 같은 코드를 사용한다.
\begin{eqnarray} \textrm{Cost(Loss) ft.} = \frac{1}{N}\sum_i\mathcal{D}(S(\mathbf{W}x_i+\mathbf{b}, L_i) \tag{3}\end{eqnarray}
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(hypothesis), axis=1))
- 경사하강법은 다음과 같은 코드를 사용한다.
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)
Softmax 분류 함수를 사용하는 기계 학습 연습
- 학습에 사용할 데이터는 다음과 같다.
- \(y\) 값은 항상 0과 1을 갖는다는 것이 중요하다.
- 데이터 사용 시 중요한 것은 모양(shape)이다.
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]] 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]) nb_classes = 3
- 전체 코드는 다음과 같다.
import tensorflow as tf 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]] # y값은 ONE-HOT encoding을 사용해 표현 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로 설 nb_classes = 3 W = tf.Variable(tf.random_normal([4, nb_classes]), name='weight') b = tf.Variable(tf.random_normal([nb_classes]), name='bias') # 가설식은 softmax 함수를 사용하여 표현 hypothesis = tf.nn.softmax(tf.matmul(X, W) + b) # Cost(Loss) 함수는 cross-entropy를 사용하여 표 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(f'STEP = {step:04}, cost 함수값 = ' f'{sess.run(cost, feed_dict={X: x_data, Y: y_data})}')
- 결과값
STEP = 0000, cost 함수값 = 1.9889715909957886 STEP = 0200, cost 함수값 = 0.5703549385070801 STEP = 0400, cost 함수값 = 0.45723509788513184 STEP = 0600, cost 함수값 = 0.3804630637168884 STEP = 0800, cost 함수값 = 0.3090059161186218 STEP = 1000, cost 함수값 = 0.24136722087860107 STEP = 1200, cost 함수값 = 0.2168642282485962 STEP = 1400, cost 함수값 = 0.19778816401958466 STEP = 1600, cost 함수값 = 0.18168748915195465 STEP = 1800, cost 함수값 = 0.16792559623718262 STEP = 2000, cost 함수값 = 0.15603584051132202
ONE-HOT Encoding 테스트
- 데이터를 가지고 값을 예측해보자.
- 전체 코드의 뒤에 아래 코드를 추가한다.
# ONE-HOT 인코딩 테스트 a = sess.run(hypothesis, feed_dict={X: [[1, 11, 7, 9]]}) print(f'예측 결과 = {a}, ONE-HOT 인코딩 결과 = {sess.run(tf.arg_max(a, 1))}') b = sess.run(hypothesis, feed_dict={X: [[1, 3, 4, 3]]}) print(f'예측 결과 = {b}, ONE-HOT 인코딩 결과 = {sess.run(tf.arg_max(b, 1))}') c = sess.run(hypothesis, feed_dict={X: [[1, 1, 0, 1]]}) print(f'예측 결과 = {c}, ONE-HOT 인코딩 결과 = {sess.run(tf.arg_max(c, 1))}') # 한번에 여러 개의 값을 넣어 테스트 all = sess.run(hypothesis, feed_dict={X: [[1, 11, 7, 9], [1, 3, 4, 3], [1, 1, 0, 1]]}) print(f'예측 결과 = {all}, ONE-HOT 인코딩 결과 = {sess.run(tf.arg_max(all, 1))}')
- ONE-HOT 인코딩의 결과가 제대로 나오는 것을 확인할 수 있다.
STEP = 0000, cost 함수값 = 8.209596633911133 STEP = 0200, cost 함수값 = 0.655610203742981 STEP = 0400, cost 함수값 = 0.5474461317062378 STEP = 0600, cost 함수값 = 0.45507490634918213 STEP = 0800, cost 함수값 = 0.3648858666419983 STEP = 1000, cost 함수값 = 0.27533501386642456 STEP = 1200, cost 함수값 = 0.22607706487178802 STEP = 1400, cost 함수값 = 0.20554673671722412 STEP = 1600, cost 함수값 = 0.1882915496826172 STEP = 1800, cost 함수값 = 0.17360061407089233 STEP = 2000, cost 함수값 = 0.16095450520515442 예측 결과 = [[ 2.96840118e-03 9.97021735e-01 9.90122044e-06]], ONE-HOT 인코딩 결과 = [1] 예측 결과 = [[ 0.90273005 0.08834519 0.00892478]], ONE-HOT 인코딩 결과 = [0] 예측 결과 = [[ 2.43163711e-08 3.81419144e-04 9.99618530e-01]], ONE-HOT 인코딩 결과 = [2] 예측 결과 = [[ 2.96840118e-03 9.97021735e-01 9.90122044e-06] [ 9.02730048e-01 8.83451924e-02 8.92478414e-03] [ 2.43163711e-08 3.81419144e-04 9.99618530e-01]], ONE-HOT 인코딩 결과 = [1 0 2]
Fancy Softmax Classifier
- Cross-Entropy와 One-hot encdoing, reshape을 이용하여 조금 더 멋진 코드를 만드는 연습을 해보자.
logits을 사용하는 Softmax Cross-Entropy 함수
- logits : 기본 가설식 식 (1)의 결과값이다.
\begin{eqnarray} \textrm{logits} = \mathbf{X} \mathbf{W} + \mathbf{b} \end{eqnarray}
- logits을 사용하여 hypothesis와 Cost(Loss) 함수를 아래 그림의 ①과 같이 작성할 수 있었다.
- Cost(Loss) 함수에서 Y의 값은 one-hot 인코딩 값이다.
- ①번 코드는 계산식에 빼기 연산 및 합과 평균 등의 계산으로 다소 복잡하다.
- ①번 식이 다소 복잡하기 때문에 간단히 하기위해 TensorFlow에서 softmax_cross_entropy_with_logits() 함수를 제공한다.
- 입력값 2개
- logits
- one-hot 인코딩된 Y값
- softmax_cross_entropy_with_logits() 함수값에 대하여 평균을 구하면 위 그림의 ②번 식과 같이 Cost(Loss) 값을 구할 수 있다.
softmax_cross_entropy_with_logits 함수를 사용하는 모델
- 아래 그림과 같이 동물에 대한 특징이 주어졌을 때 동물을 분류해보자.
- \(Y\) 데이터의 값을 살펴보자.
- 학습 데이터가 \(n\)개이고, \(Y\) 데이터는 1개이 때문에 \(Y\) 데이터의 차원은 [None, 1]이다.
- Y \(Y\) 의 값은 0~6 사이의 값으로 one-hot encoding 값이 아니기 때문에 변환이 필요하다.
- TensorFlow의 one_hot() 함수를 사용하면 one-hot encoding의 값으로 바꿀 수 있다.
- one-hot() 함수의 입력값은 \(Y\) 값과 \(Y\) 값의 갯수(class)가 된다. 즉, \(0\leqslant Y \leqslant 6\)이기 때문에 \(\texttt{nb_classes} = 7\)이다.
- one-hot() 함수 입력값의 rank가 \(N\)이면 출력값은 \(N+1\)이 된다.
- 예를 들어, 입력값이 [[0], [3]]이라고 하면 rank=2이다. 즉, shape=(2,1)이다.
- 이 때의 출력값은 [[[1000000]], [[0001000]]]이 되어 rank=3이 된다. 즉, shape(2, 1, 7)이 된다.
- 이러한 결과는 우리가 원하는 것이 아니다. 우리는 shape=(2, 7)을 원한다.
- TensorFlow의 reshape() 함수를 사용하면 우리가 원하는 결과를 얻을 수 있다.
- 예를 들어, 입력값이 [[0], [3]]이라고 하면 출력값은 [[1000000], [0001000]]이 되어 우리가 원하는 결과를 얻을 수 있다.
- shape에서 -1은 나머지 모든 것을 의미한다.
softmax_cross_entropy_with_logits 함수를 사용하는 모델의 기계 학습 연습
- 전체 소스코드는 다음과 같다.
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]] print(x_data.shape, y_data.shape) # 0<= Y <= 6 nb_classes = 7 # x1, x2, x3, ..., x16 X = tf.placeholder(tf.float32, [None, 16]) Y = tf.placeholder(tf.int32, [None, 1]) Y_one_hot = tf.one_hot(Y, nb_classes) print("one_hot", Y_one_hot) 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') 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) # 정확도를 파악한다 # 가설식의 값을 확률분포로 변환 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)) 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(f'STEP = {step:05}, Loss = {loss:.3f}, 정확도 = {acc:.2%}') # 예측할 수 있는지 살펴보자 pred = sess.run(prediction, feed_dict={X: x_data}) for p, y in zip(pred, y_data.flatten()): print(f'예측여부 : [{p == int(y)}], 예측값={p:2}, 실제 Y값={int(y):2}')
- 결과값
(101, 16) (101, 1) one_hot Tensor("one_hot:0", shape=(?, 1, 7), dtype=float32) reshape Tensor("Reshape:0", shape=(?, 7), dtype=float32) STEP = 00000, Loss = 7.292, 정확도 = 0.99% STEP = 00100, Loss = 0.954, 정확도 = 70.30% STEP = 00200, Loss = 0.566, 정확도 = 84.16% STEP = 00300, Loss = 0.420, 정확도 = 89.11% STEP = 00400, Loss = 0.335, 정확도 = 90.10% STEP = 00500, Loss = 0.279, 정확도 = 94.06% STEP = 00600, Loss = 0.238, 정확도 = 95.05% STEP = 00700, Loss = 0.207, 정확도 = 97.03% STEP = 00800, Loss = 0.182, 정확도 = 97.03% STEP = 00900, Loss = 0.162, 정확도 = 97.03% STEP = 01000, Loss = 0.146, 정확도 = 97.03% STEP = 01100, Loss = 0.132, 정확도 = 97.03% STEP = 01200, Loss = 0.120, 정확도 = 97.03% STEP = 01300, Loss = 0.110, 정확도 = 99.01% STEP = 01400, Loss = 0.101, 정확도 = 99.01% STEP = 01500, Loss = 0.094, 정확도 = 99.01% STEP = 01600, Loss = 0.087, 정확도 = 99.01% STEP = 01700, Loss = 0.082, 정확도 = 99.01% STEP = 01800, Loss = 0.076, 정확도 = 99.01% STEP = 01900, Loss = 0.072, 정확도 = 100.00% 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 3, 실제 Y값= 3 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 3, 실제 Y값= 3 예측여부 : [True], 예측값= 3, 실제 Y값= 3 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 3, 실제 Y값= 3 예측여부 : [True], 예측값= 6, 실제 Y값= 6 예측여부 : [True], 예측값= 6, 실제 Y값= 6 예측여부 : [True], 예측값= 6, 실제 Y값= 6 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 3, 실제 Y값= 3 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 5, 실제 Y값= 5 예측여부 : [True], 예측값= 4, 실제 Y값= 4 예측여부 : [True], 예측값= 4, 실제 Y값= 4 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 5, 실제 Y값= 5 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 3, 실제 Y값= 3 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 3, 실제 Y값= 3 예측여부 : [True], 예측값= 5, 실제 Y값= 5 예측여부 : [True], 예측값= 5, 실제 Y값= 5 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 5, 실제 Y값= 5 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 6, 실제 Y값= 6 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 5, 실제 Y값= 5 예측여부 : [True], 예측값= 4, 실제 Y값= 4 예측여부 : [True], 예측값= 6, 실제 Y값= 6 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 3, 실제 Y값= 3 예측여부 : [True], 예측값= 3, 실제 Y값= 3 예측여부 : [True], 예측값= 2, 실제 Y값= 2 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 6, 실제 Y값= 6 예측여부 : [True], 예측값= 3, 실제 Y값= 3 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 2, 실제 Y값= 2 예측여부 : [True], 예측값= 6, 실제 Y값= 6 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 2, 실제 Y값= 2 예측여부 : [True], 예측값= 6, 실제 Y값= 6 예측여부 : [True], 예측값= 3, 실제 Y값= 3 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 6, 실제 Y값= 6 예측여부 : [True], 예측값= 3, 실제 Y값= 3 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 5, 실제 Y값= 5 예측여부 : [True], 예측값= 4, 실제 Y값= 4 예측여부 : [True], 예측값= 2, 실제 Y값= 2 예측여부 : [True], 예측값= 2, 실제 Y값= 2 예측여부 : [True], 예측값= 3, 실제 Y값= 3 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 1, 실제 Y값= 1 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 5, 실제 Y값= 5 예측여부 : [True], 예측값= 0, 실제 Y값= 0 예측여부 : [True], 예측값= 6, 실제 Y값= 6 예측여부 : [True], 예측값= 1, 실제 Y값= 1
'모두를 위한 머신러닝' 카테고리의 다른 글
Lesson 6 연습 : Application & Tips (0) | 2018.04.04 |
---|---|
Lesson 6 : Application & Tips (0) | 2018.04.04 |
Lesson 5 : Multinomial Classification: Softmax classification (0) | 2017.05.19 |
Lesson 4 연습 : Logisitc Regression Classification (0) | 2017.04.19 |
Lesson 4 : Logistic (regression) classification (0) | 2017.04.19 |