2019. 6. 4. 19:55ㆍmachine learning
골빈 해커님이 쓰신 3분 딥러닝을 코드 위주로 설명한 포스팅.
4장 01에서는 2개의 특징 데이터(털, 날개)를 가지고 [기타, 포유류, 조류]를 분류하는 모델을 설명하고 있으며, 전체 코드는 아래와 같다.
import tensorflow as tf | |
import numpy as np | |
x_data = np.array([[0, 0], [1, 0], [1, 1], [0, 0], [0, 0], [0, 1]]) | |
y_data = np.array([ | |
[1, 0, 0], # 기타 | |
[0, 1, 0], # 포유류 | |
[0, 0, 1], # 조류 | |
[1, 0, 0], | |
[1, 0, 0], | |
[0, 0, 1] | |
]) | |
X = tf.placeholder(tf.float32) | |
Y = tf.placeholder(tf.float32) | |
# tf.random_uniform : 정규분포 난수를 생성하는 함수로 배열의 shape, 최소, 최대 값을 파라미터로 받는다. | |
# -1 ~ 1 사이의 난수를 2x3개 생성한다. | |
W = tf.Variable(tf.random_uniform([2, 3], -1., 1.)) | |
b = tf.Variable(tf.zeros([3])) | |
# ex) [1, 0] x [[0.2, 0.3, 0.4] + [0.1, 0.2, 0.3] = [0.3, 0.5, 0.7] | |
# [0.1, 0.2, 0.1]] | |
# 1x2 matmul 2x3 + 1x3 = 1x3 | |
L = tf.add(tf.matmul(X, W), b) | |
L = tf.nn.relu(L) | |
model = tf.nn.softmax(L) | |
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(model), axis=1)) | |
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01) | |
train_op = optimizer.minimize(cost) | |
init = tf.global_variables_initializer() | |
sess = tf.Session() | |
sess.run(init) | |
for step in range(100): | |
sess.run(train_op, feed_dict={X: x_data, Y: y_data}) | |
if (step + 1) % 10 == 0: | |
print(step + 1, sess.run(cost, feed_dict={X: x_data, Y: y_data})) | |
prediction = tf.argmax(model, 1) | |
target = tf.argmax(Y, 1) | |
print('예측값:', sess.run(prediction, feed_dict={X: x_data})) | |
print('실제값:', sess.run(target, feed_dict={Y: y_data})) | |
is_correct = tf.equal(prediction, target) | |
print(sess.run(is_correct, feed_dict={X: x_data, Y: y_data})) | |
print(sess.run(accuracy, feed_dict={X: x_data, Y: y_data})) # 2/6 | |
accuracy = tf.reduce_mean(tf.cast(is_correct, tf.float32)) | |
print('정확도: %.2f' % sess.run(accuracy * 100, feed_dict={X: x_data, Y: y_data})) |
step by step으로 하나씩 살펴보자.
import tensorflow as tf
import numpy as np
텐서플로우와 numpy를 import 하고 있다. 참고로 실행 환경에서의 텐서플로우와 numpy 버전은 각각 1.13.0, 1.16.3을 사용하였다.
x_data = np.array([[0, 0], [1, 0], [1, 1], [0, 0], [0, 0], [0, 1]])
y_data = np.array([ [1, 0, 0], # 기타
[0, 1, 0], # 포유류
[0, 0, 1], # 조류
[1, 0, 0], [1, 0, 0], [0, 0, 1] ])
X = tf.placeholder(tf.float32)
Y = tf.placeholder(tf.float32)
x와 y 데이터를 각각 선언하고, train 시에 x와 y 데이터를 담을 수 있는 placeholder도 선언한다.
x data는 [털, 날개] 여부를 가지는 2차원 데이터로 나타나고, y data는 [기타,포유류,조류]를 각각 one-hot encoding으로 표현하였다.
W = tf.Variable(tf.random_uniform([2, 3], -1., 1.))
b = tf.Variable(tf.zeros([3]))
weight와 bias를 선언한다. weight는 -1 ~ 1 사이의 정규분포를 가지는 2x3 행렬의 난수로 표현이 되고, bias는 1x3의 0값으로 초기화가 된다.
input data가 1x2 행렬이기 때문에 wx + y = [1x2] * [2x3] + [1x3] 으로 행렬 계산이 되고 최종 결과 값은 [1x3]의 행렬 값이 나타난다.
L = tf.add(tf.matmul(X, W), b)
L = tf.nn.relu(L)
model = tf.nn.softmax(L)
input data에 weight를 곱한 후 bias를 더한 식을 L로 정의하고, L에 대해 relu를 적용한다.
그리고 마지막으로 L에 대해 softmax를 적용한다. softmax는 간단히 설명하자면 각각의 가중치 데이터를 총 합이 1이 되게 확률값을 만들어 주는 기능을 한다.
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(model), axis=1))
모델을 정의 했다면 이번에는 cost 함수를 정의한다. cost 함수는 cross entropy로 정의한다. Y 값 * log(모델의 예측확률)의 전체 합이 cross entropy가 되며 마지막에 reduce_mean을 해주는 이유는 해당 함수가 batch size 입력을 받기 때문에 해당 batch에 대한 평균 loss를 구하기 위해 reduce_mean이 필요하다.
reduce_sum의 axis가 헷갈리는 부분인데, axis가 없는 경우는 전체 합, axis가 0일 경우에는 열단위 합, axis가 1일 경우에는 행단위 합을 진행한다고 생각하면 된다.
아래의 예를 보면, 이해가 쉽다.
x = [[0,1,2], [3,4,5]]
print(sess.run(tf.reduce_sum(x))) # 전체 계산 15
print(sess.run(tf.reduce_sum(x, axis=0))) # 열단위 계산 [3,5,7]
print(sess.run(tf.reduce_sum(x, axis=1))) # 행단위 계산 [3, 12]
optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)
train_op = optimizer.minimize(cost)
optimizer로 gradient descent optimizer를 사용하고 learning rate 를 0.01로 주자.
init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)
for step in range(100):
sess.run(train_op, feed_dict={X: x_data, Y: y_data})
if (step + 1) % 10 == 0:
print(step + 1, sess.run(cost, feed_dict={X: x_data, Y: y_data}))
이제 만들어진 모델을 학습해보자.
먼저 tf.global_variables_initializer()를 통해 기존 선언한 변수들에 대한 초기화를 진행하자.
session을 선언한 후 변수 초기화를 실행 시키자.
range 100만큼 돌면서 x_data와 y_data를 집어 넣어서 train_op를 실행시키자.
10 단위로 cost 함수를 실행시켜서 cross_entropy date를 출력해 보자.
prediction = tf.argmax(model, 1)
target = tf.argmax(Y, 1)
print('예측값:', sess.run(prediction, feed_dict={X: x_data}))
print('실제값:', sess.run(target, feed_dict={Y: y_data}))
is_correct = tf.equal(prediction, target)
accuracy = tf.reduce_mean(tf.cast(is_correct, tf.float32))
print('정확도: %.2f' % sess.run(accuracy * 100, feed_dict={X: x_data, Y: y_data}))
마지막으로 모델에 대한 성능 평가를 진행한다.
model에서 행단위로 가장 높은 값을 가지는 index를 리턴하는 함수를 prediction에 정의한다.
그리고 현재 y_data 중 가장 높은 값 (1인 데이터) 의 index 를 리턴하는 함수를 target에 정의한 후 각각 sess.run을 실행시켜서 결과를 확인해 보자.
출력해보면, 예측 값 : [2 2 2 2 2 2], 실제값 : [0 1 2 0 0 2] 로 나타나게 된다.
두 개의 리스트를 tf.equal을 통해 비교하자. 일치하면 True, 틀리면 False를 리턴하게 될 것이다. ex) [False, False, True, False, False, True]
True, False 리스트를 정수로 변환한 후 reduce_mean을 함으로써 평균을 구하자.
약 33%의 정확도를 확인해 볼 수가 있으며, 이 결과가 지금 현재의 모델 성능임을 확인해 볼 수가 있다.