[TensorFlow] 기초 개념 및 수행 결과_ 2. 모델 설계하기



소스 코드는 https://github.com/melonicedlatte/tensorflow_basic/tree/master 에 모두 올라와 있습니다. 


In [1]:
import tensorflow as tf
import numpy as np
In [2]:
from tensorflow.examples.tutorials.mnist import input_data

input과 label 데이터 설정

먼저 간단한 모델을 살펴보자

In [3]:
input_data = [[1,5,3,7,8,10,12],
              [5,8,10,3,9,7,1]]
label_data = [[0,0,0,1,0],
              [1,0,0,0,0]]
In [4]:
INPUT_SIZE = 7 
HIDDEN_SIZE_1 = 10
HIDDEN_SIZE_2 = 8
CLASSES = 5

shape 에서 첫 번째 요소는 batch의 크기. 일반적으로 잘 모르기 때문에 None으로 써도 된다.

In [5]:
x = tf.placeholder(tf.float32, shape = [None, INPUT_SIZE] )
y = tf.placeholder(tf.float32, shape = [None, CLASSES] )
In [6]:
tensor_map = {x : input_data, y : label_data}

input weight 정의

In [7]:
weight_hidden_1 = tf.Variable( tf.truncated_normal(shape=[INPUT_SIZE, HIDDEN_SIZE_1]) , dtype=tf.float32 ) 

bias 정의

In [8]:
bias_hidden_1 = tf.Variable( tf.zeros(shape=[HIDDEN_SIZE_1]) , dtype=tf.float32 )
In [9]:
tf.matmul( x , weight_hidden_1 )
Out[9]:
<tf.Tensor 'MatMul:0' shape=(?, 10) dtype=float32>
In [10]:
print (x)
print (weight_hidden_1)
Tensor("Placeholder:0", shape=(?, 7), dtype=float32)
Tensor("Variable/read:0", shape=(7, 10), dtype=float32)
In [11]:
hidden_1 = tf.matmul( x , weight_hidden_1 ) + bias_hidden_1
In [12]:
weight_hidden_2 = tf.Variable( tf.truncated_normal(shape=[HIDDEN_SIZE_1, HIDDEN_SIZE_2]) , dtype=tf.float32 ) 
bias_hidden_2 = tf.Variable( tf.zeros(shape=[HIDDEN_SIZE_2]) , dtype=tf.float32 )
In [13]:
hidden_2 = tf.matmul( hidden_1 , weight_hidden_2 ) + bias_hidden_2
In [14]:
weight_output = tf.Variable( tf.truncated_normal(shape=[HIDDEN_SIZE_2, CLASSES]) , dtype=tf.float32 ) 
bias_output = tf.Variable( tf.zeros(shape=[CLASSES]) , dtype=tf.float32 )
In [15]:
answer = tf.matmul( hidden_2 , weight_output ) + bias_output

위의 내용을 한 번에 모아서 해보자

신경망을 미리 설계해 놓고 아래에서 연산을 수행하여 답을 도출해낸다

In [16]:
weight_hidden_1 = tf.Variable( tf.truncated_normal(shape=[INPUT_SIZE, HIDDEN_SIZE_1]) , dtype=tf.float32 ) 
bias_hidden_1 = tf.Variable( tf.zeros(shape=[HIDDEN_SIZE_1]) , dtype=tf.float32 )
weight_hidden_2 = tf.Variable( tf.truncated_normal(shape=[HIDDEN_SIZE_1, HIDDEN_SIZE_2]) , dtype=tf.float32 ) 
bias_hidden_2 = tf.Variable( tf.zeros(shape=[HIDDEN_SIZE_2]) , dtype=tf.float32 )
weight_output = tf.Variable( tf.truncated_normal(shape=[HIDDEN_SIZE_2, CLASSES]) , dtype=tf.float32 ) 
bias_output = tf.Variable( tf.zeros(shape=[CLASSES]) , dtype=tf.float32 )
In [17]:
hidden_1 = tf.matmul( x , weight_hidden_1 ) + bias_hidden_1
hidden_2 = tf.matmul( hidden_1 , weight_hidden_2 ) + bias_hidden_2
answer = tf.matmul( hidden_2 , weight_output ) + bias_output

구조

Input -  ㅁ  - ㅁ  - ㅁ - ㅁ   - ㅁ - ㅁ  - answer
         |     |    |    |     |    |
         w1   b2    w2   b2    wo   bo


인풋   히든1  2  결과  

7     10    8   5
In [18]:
print (x)
print (hidden_1)
print (hidden_2)
print (answer)
Tensor("Placeholder:0", shape=(?, 7), dtype=float32)
Tensor("add_3:0", shape=(?, 10), dtype=float32)
Tensor("add_4:0", shape=(?, 8), dtype=float32)
Tensor("add_5:0", shape=(?, 5), dtype=float32)
In [19]:
print (weight_hidden_1)
print (bias_hidden_1)
print (weight_hidden_2)
print (bias_hidden_2)
print (weight_output)
print (bias_output)
Tensor("Variable_6/read:0", shape=(7, 10), dtype=float32)
Tensor("Variable_7/read:0", shape=(10,), dtype=float32)
Tensor("Variable_8/read:0", shape=(10, 8), dtype=float32)
Tensor("Variable_9/read:0", shape=(8,), dtype=float32)
Tensor("Variable_10/read:0", shape=(8, 5), dtype=float32)
Tensor("Variable_11/read:0", shape=(5,), dtype=float32)

sigmoid 함수 적용 법

In [20]:
weight_hidden_1 = tf.Variable( tf.truncated_normal(shape=[INPUT_SIZE, HIDDEN_SIZE_1]) , dtype=tf.float32 ) 
bias_hidden_1 = tf.Variable( tf.zeros(shape=[HIDDEN_SIZE_1]) , dtype=tf.float32 )
hidden_1 = tf.sigmoid(tf.matmul( x , weight_hidden_1 ) + bias_hidden_1)
weight_hidden_2 = tf.Variable( tf.truncated_normal(shape=[HIDDEN_SIZE_1, HIDDEN_SIZE_2]) , dtype=tf.float32 ) 
bias_hidden_2 = tf.Variable( tf.zeros(shape=[HIDDEN_SIZE_2]) , dtype=tf.float32 )
hidden_2 = tf.sigmoid(tf.matmul( hidden_1 , weight_hidden_2 ) + bias_hidden_2)
weight_output = tf.Variable( tf.truncated_normal(shape=[HIDDEN_SIZE_2, CLASSES]) , dtype=tf.float32 ) 
bias_output = tf.Variable( tf.zeros(shape=[CLASSES]) , dtype=tf.float32 )
answer = tf.sigmoid(tf.matmul( hidden_2 , weight_output ) + bias_output)

cost 엔트로피 ( tip : 매뉴얼을 항상 자주 보자 )

In [21]:
cost = -y*tf.log(answer)-(1-y)*tf.log((1-answer))
In [22]:
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
sess.run(cost, feed_dict = tensor_map)
Out[22]:
array([[ 1.33245099,  0.17650527,  3.64532757,  0.4300445 ,  0.0531444 ],
       [ 0.48834652,  0.2071031 ,  3.64621139,  0.91910106,  0.06918658]], dtype=float32)

recude sum 과 reduce mean 사용해보기

In [23]:
cost = tf.reduce_sum(-y*tf.log(answer)-(1-y)*tf.log((1-answer)))
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
sess.run(cost, feed_dict = tensor_map)
Out[23]:
7.1844816
In [24]:
cost = tf.reduce_mean(-y*tf.log(answer)-(1-y)*tf.log((1-answer)))
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
sess.run(cost, feed_dict = tensor_map)
Out[24]:
0.98683512

수행

  • cost를 최소화 하는 방향으로 최적화 해야 되니까 gradient descent가 필요.
  • learning rate 사용

조대협님의 블로그에서 가져온 내용 (Mnist data를 기준으로 한다. 자세한 내용은 링크 참조)

우리가 구하고자 하는 값은 x 값으로 학습을 시켜서 0~9를 가장 잘 구별해내는 W와 b의 값을 찾는 일이다.

여기서 코드를 주의깊게 봤다면 하나의 의문이 생길것이다.

x의 데이타는 총 55000개로, 55000x784 행렬이 되고, W는 784x10 행렬이다. 이 둘을 곱하면, 55000x10 행렬이 되는데, b는 1x10 행렬로 차원이 달라서 합이 되지 않는다.

텐서플로우와 파이썬에서는 이렇게 차원이 다른 행렬을 큰 행렬의 크기로 늘려주는 기능이 있는데, 이를 브로드 캐스팅이라고 한다. (브로드 캐스팅 개념 참고 - http://bcho.tistory.com/1153)

브로드 캐스팅에 의해서 b는 55000x10 사이즈로 자동으로 늘어나고 각 행에는 첫행과 같은 데이타들로 채워지게 된다.

소프트맥스 알고리즘을 이해하고 사용해도 좋지만, 텐서플로우에는 이미 tf.nn.softmax 라는 함수로 만들어져 있고, 대부분 많이 알려진 머신러닝 모델들은 샘플들이 많이 있기 때문에, 대략적인 원리만 이해하고 가져다 쓰는 것을 권장한다.

보통 모델을 다 이해하려고 하다가 수학에서 부딪혀서 포기하는 경우가 많은데, 디테일한 모델을 이해하기 힘들면, 그냥 함수나 예제코드를 가져다 쓰는 방법으로 접근하자.

우리가 일반적인 프로그래밍에서도 해쉬테이블이나 트리와 같은 자료구조에 대해서 대략적인 개념만 이해하고 미리 정의된 라이브러리를 사용하지 직접 해쉬 테이블등을 구현하는 경우는 드물다.

코스트(비용) 함수

이 소프트맥스 함수에 대한 코스트 함수는 크로스엔트로피 (Cross entropy) 함수의 평균을 이용하는데, 복잡한 산식 없이 그냥 외워서 쓰자. 다행이도 크로스엔트로피 함수역시 함수로 구현이 되어있다.

Cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_withlogits(tf.matmul(x, W) + b, y))

가설에 의해 계산된 값 y를 넣지 않고 tf.matmul(x, W) + b 를 넣은 이유는 tf.nn.softmax_cross_entropy_withlogits 함수 자체가 softmax를 포함하기 때문이다. y은 학습을 위해서 입력된 값이다.

-> 코스트 함수로 위 함수는 써 본 적은 없고, 자세한 내용은 저도 잘 모르겠으나 일단 사용해보겠습니다.

In [25]:
Learning_Rate = 0.05
cost = tf.reduce_mean(-y*tf.log(answer)-(1-y)*tf.log((1-answer)))
train = tf.train.GradientDescentOptimizer(Learning_Rate).minimize(cost)
sess = tf.Session()
init = tf.global_variables_initializer()
sess.run(init)
for i in range(10):
    print (sess.run([train, cost], feed_dict = tensor_map))
    print ("Step : ",i )
[None, 1.005991]
Step :  0
[None, 0.9897567]
Step :  1
[None, 0.97342128]
Step :  2
[None, 0.95689833]
Step :  3
[None, 0.94007456]
Step :  4
[None, 0.92279834]
Step :  5
[None, 0.90486622]
Step :  6
[None, 0.88602316]
Step :  7
[None, 0.86601162]
Step :  8
[None, 0.84476393]
Step :  9

학습 100 번 수행

In [26]:
for i in range(100):
    print (sess.run([train, cost], feed_dict = tensor_map))
    print ("Step : ",i )
[None, 0.82282323]
Step :  0
[None, 0.80167067]
Step :  1
[None, 0.78300524]
Step :  2
[None, 0.76736492]
Step :  3
[None, 0.75414431]
Step :  4
[None, 0.74253953]
Step :  5
[None, 0.73197526]
Step :  6
[None, 0.72209966]
Step :  7
[None, 0.7127009]
Step :  8
[None, 0.70364749]
Step :  9
[None, 0.69485533]
Step :  10
[None, 0.68626755]
Step :  11
[None, 0.67784488]
Step :  12
[None, 0.66955864]
Step :  13
[None, 0.66138804]
Step :  14
[None, 0.65331715]
Step :  15
[None, 0.64533377]
Step :  16
[None, 0.63742936]
Step :  17
[None, 0.62959808]
Step :  18
[None, 0.62183756]
Step :  19
[None, 0.6141488]
Step :  20
[None, 0.60653651]
Step :  21
[None, 0.5990088]
Step :  22
[None, 0.59157741]
Step :  23
[None, 0.58425629]
Step :  24
[None, 0.5770601]
Step :  25
[None, 0.57000315]
Step :  26
[None, 0.56309664]
Step :  27
[None, 0.55634892]
Step :  28
[None, 0.54976398]
Step :  29
[None, 0.54334205]
Step :  30
[None, 0.53708076]
Step :  31
[None, 0.5309751]
Step :  32
[None, 0.52501887]
Step :  33
[None, 0.51920545]
Step :  34
[None, 0.51352805]
Step :  35
[None, 0.50798011]
Step :  36
[None, 0.50255555]
Step :  37
[None, 0.49724874]
Step :  38
[None, 0.49205464]
Step :  39
[None, 0.48696867]
Step :  40
[None, 0.48198685]
Step :  41
[None, 0.47710523]
Step :  42
[None, 0.47232071]
Step :  43
[None, 0.46763015]
Step :  44
[None, 0.46303076]
Step :  45
[None, 0.45852]
Step :  46
[None, 0.45409536]
Step :  47
[None, 0.44975466]
Step :  48
[None, 0.4454959]
Step :  49
[None, 0.44131678]
Step :  50
[None, 0.43721586]
Step :  51
[None, 0.43319097]
Step :  52
[None, 0.42924052]
Step :  53
[None, 0.42536283]
Step :  54
[None, 0.42155623]
Step :  55
[None, 0.41781917]
Step :  56
[None, 0.41415018]
Step :  57
[None, 0.41054779]
Step :  58
[None, 0.40701047]
Step :  59
[None, 0.40353695]
Step :  60
[None, 0.40012574]
Step :  61
[None, 0.3967756]
Step :  62
[None, 0.39348522]
Step :  63
[None, 0.39025325]
Step :  64
[None, 0.38707849]
Step :  65
[None, 0.38395974]
Step :  66
[None, 0.38089576]
Step :  67
[None, 0.37788543]
Step :  68
[None, 0.37492755]
Step :  69
[None, 0.37202102]
Step :  70
[None, 0.36916474]
Step :  71
[None, 0.36635768]
Step :  72
[None, 0.36359864]
Step :  73
[None, 0.36088678]
Step :  74
[None, 0.35822096]
Step :  75
[None, 0.35560024]
Step :  76
[None, 0.35302359]
Step :  77
[None, 0.35049018]
Step :  78
[None, 0.34799904]
Step :  79
[None, 0.34554917]
Step :  80
[None, 0.3431398]
Step :  81
[None, 0.34076998]
Step :  82
[None, 0.33843893]
Step :  83
[None, 0.3361457]
Step :  84
[None, 0.3338896]
Step :  85
[None, 0.33166984]
Step :  86
[None, 0.3294856]
Step :  87
[None, 0.32733601]
Step :  88
[None, 0.3252205]
Step :  89
[None, 0.32313833]
Step :  90
[None, 0.3210887]
Step :  91
[None, 0.31907099]
Step :  92
[None, 0.31708446]
Step :  93
[None, 0.31512851]
Step :  94
[None, 0.31320247]
Step :  95
[None, 0.3113057]
Step :  96
[None, 0.3094376]
Step :  97
[None, 0.30759758]
Step :  98
[None, 0.305785]
Step :  99
In [27]:
sess.close()
In [ ]: