Recommanded Free YOUTUBE Lecture: <% selectedImage[1] %>

TensorFlow 시작하기

이 문서는 TensorFlow를 이용한 프로그래밍을 가이드 한다. 이 문서를 읽기전에 TensorFlow를 설치해야 한다. 이 문서를 활용하기 위해서는 아래의 사항을 알고 있어야 한다.
  • 파이썬으로 프로그래밍 하는 법
  • 적어도 배열이 뭔지는 알아야 한다.
  • 가능 하면 기계 학습에 대한 것을 알고 있는게 좋다. 그러나 기계 학습에 대해서 전혀 모르더라도 읽을 수 있도록 만들었다.
TensorFlow는 다양한 API들을 제공한다. 가장 낮은 레벨의 API(TensorFlow Core)는 완전한 프로그래밍 제어 기능을 제공한다. TensorFlow Core는 기계 학습 연구자 및 모델을 정밀하게 제어해야 할 필요가 있는 사람들에게 권한다. 높은 수준의 API는 TensowFlow Core 위에 구축이된다. 상위 수준의 API는 TensorFlow Core 보다 배우기가 쉽다. 또한 상위 수준 API는 반복적인 작업을 보다 쉽고 일관되게 처리 하도록 도와준다. tf.contrib.learn과 같은 고급 API를 사용하면 데이터 세트, 트래이닝과 인터페이스등을 쉽게 관리 할 수 있다. 고수준 TensorFlow 중 이름에 contrib가 포함된 API는 아직 개발 중이라는 걸 참고하자. contrib 메서드는 변경되거나 아예 사용하지 않을 수도 있다.

이 문서는 TensorFlow Core에 대한 학습으로 부터 시작한다. 나중에는 tf.contrib.learn으로 동일한 모델을 구현하는 방법을 보여줄 것이다. TensorFlow Core를 학습하는 것보다는 높은 수준의 API를 사용할 때, 모델의 작동방식을 좀 더 명확히 이해할 수 있을 것이다.

TenSors

TensorFlow에서 데이터의 기본 단위는 텐서(Tensor)이다. 텐서는 임의의 수의 차원의 배열의 집합이다. 텐서의 랭크(rank)는 차원의 갯수를 의미한다. 아래는 텐서의 예제다.
3            # 0 랭크 텐서. 스칼라 값으로 [ ]로 나타낸다.
[1., 2., 3.] # 1 랭크 텐서. 벡터로 [3]으로 나타낸다.
[[1., 2., 3.], [4., 5., 6.]]  # 2 랭크 텐서. [2, 3]의 매트릭스
[[[1., 2., 3.]], [[7., 8., 9.]]]  # 3 랭크 텐서, 2, 1, 3

TensorFlow Core 튜토리얼

TensorFlow Import

TemsorFlow 프로그래밍을 위해서 tensorflow 모듈을 임포트 한다.
import tensorflow as tf
이제 파이썬은 TensorFlow의 모든 클래스, 메서드, 심볼에 엑세스 할 수 있다. 이 문서의 모든 내용은 tensorflow 모듈을 임포트했다고 가정하고 진행 한다.

Computational Graph

TensorFlow Core 프로그램은 두 개의 개별 영역으로 구성되어 있다고 볼 수 있다.
  1. Computational graph를 만들고
  2. Computational graph를 실행한다.
computational graph는 일련의 TensorFlow 작업을 그래프의 노드로 배열 한 것이다. 각 노드는 0개 이상의 텐서를 입력 받아서, 텐서를 출력한다. 상수는 텐서의 타입중 하나다. 아래에 float point 텐서인 node1과 node2를 만들었다.
node1 = tf.constant(3.0, dtype=tf.float32)
node2 = tf.constant(4.0) # also tf.float32 implicitly
print(node1, node2)
실행해 보자.
Tensor("Const:0", shape=(), dtype=float32) Tensor("Const_1:0", shape=(), dtype=float32)
3.0과 4.0을 출력 할 것이라는 예상과는 달리, 3.0과 4.0을 생성하는 노드의 정보를 출력했다. 노드를 실제로 평가하기 위해서는 세션(session) 내에서 그래프를 실행해야 한다. 세션은 런타임을 제어하고 그 상태를 캡술화 한다. 이제 세션을 만들고, node1과 node2를 계산 할 수 있는 그래프를 실행해보자.
sess = tf.Session()
print(sess.run([node1, node2]))
이제 우리가 기대했던 결과를 볼 수 있다.
[3.0, 4.0]
텐서 노드와 연산자를 이용해서 좀 더 복잡한 계산을 해보자. 예를 들어서 두 개의 노드를 더 해서 새로운 노드를 만들 수 있다.
node3 = tf.add(node1, node2)
print("node3: ", node3)
print("sess.run(node3): ",sess.run(node3))
실행 결과다.
node3:  Tensor("Add:0", shape=(), dtype=float32)
sess.run(node3):  7.0
TensorFlow가 제공하는 TensorBoard 유틸리티를 이용해서, 그래프의 연산 흐름을 표시 할 수 있다. 아래는 TehnsorBoard를 이용해서 시각화한 그림이다.

 graph

이 예제는 상수만을 포함하며, 따라서 항상 일정한 결과를 출력하므로 재미가 없다. placeholders를 이용해서 외부 입력을 허용하도록 코드를 수정해보자.
import tensorflow as tf

a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
adder_node = a + b
sess = tf.Session()
print(sess.run(adder_node, {a:3, b:4.5}))
print(sess.run(adder_node, {a:[1,3], b:[2,4]}))
실행 결과다.
7.5
[ 3.  7.]
TensorBoard 그래프는 아래와 같을 것이다.

 graph2

연산을 추가하면 더 복잡한 computational graph가 만들어진다.
import tensorflow as tf
a = tf.placeholder(tf.float32)
b = tf.placeholder(tf.float32)
add_node = a + b
add_and_triple = add_node * 3
print(sess.run(add_and_triple, {a:3, b:4.5}))
이 과정을 TensorBoard로 그렸다.

 graph3

일반적인 기계학습에서는 위와 같이 임의의 값을 입력 할 수 있는 모델을 원할 것이다. 모델을 학습 가능하게 만들려면 동일한 입력으로 새로운 출력을 얻기 위해서 그래프를 수정 할 수 있어야 한다. 변수(Variable)를 이용하면 그래프에 학습 가능한 매개 변수를 추가 할 수 있다. 이것들은 타입과 초기 값으로 구성된다.
import tensorflow as tf
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
x = tf.placeholder(tf.float32)
linear_model = W * x + b
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)
print(sess.run(linear_model, {x:[1,2,3,4]}))
상수(Constant)는 tf.constant를 호출 할 때 초기화되며, 그 후로는 바굴 수 없다. 반대로 tf.Variable를 호출 할 때 초기화되지 않는다. 변수를 초기화 하려면 tf.initialize_all_variables를 호출해서 명시적으로 초기화 해야 한다. 이제 sess.run을 호출하면 변수가 초기화 된다. 이제 단순한 선형모델을 만들고, x에 값을 입력해서 평가를 수행했다. 수행 결과는 다음과 같다.
[ 0.          0.30000001  0.60000002  0.90000004]
우리는 모델을 만들었지만 이 모델이 얼마나 좋은지는 아직 모른다. 학습 데이터에 대한 모델을 평가하려면, y 값이 필요하며 손실 함수를 만들어야 한다.

손실 함수(loss function)는 제공된 데이터로 부터 현재 모델이 얼마나 떨어져 있는지를 측정한다. 현재 모델과 제공된 데이터 사이의 차이의 제곱을 합하는 표준 손실 모델을 사용 할 수 있다. lenear_model -y는 차이에 대한 벡터를 만든다. tf.square를 호출해서 오류를 제곱한다. 그 다음 모든 제곱된 오류를 tf.reduce_sum을 이용해서 더 해서, 오류를 나타내는 단일 스칼라를 만든다.
y = tf.placeholder(tf.float32)
squared_deltas = tf.square(linear_model - y)
loss = tf.reduce_sum(squared_deltas)
print(sess.run(loss, {x:[1,2,3,4], y:[0, -1, -2, -3]}))
loss value는 아래와 같다.
23.66
썩 만족스럽지 않은 모델이다. 우리는 Wb의 값을 -1과 1로 재 설정했다. 변수는 tf.Variable에 제공된 값으로 초기화되지만 tf.assign으로 값을 바꿀 수 있다. 모델을 수정하기 위해서 W=-1, b=1로 값을 변경한 예제다.
y = tf.placeholder(tf.float32)
squared_deltas = tf.square(linear_model - y)
loss = tf.reduce_sum(squared_deltas)
fixW = tf.assign(W, [-1.])
fixb = tf.assign(b, [1.])
sess.run([fixW, fixb])
print(sess.run(loss, {x:[1,2,3,4], y:[0, -1, -2, -3]}))
이제 loss가 0이 됐다.
0.0
loss가 0이라는 것은 완전한 추측이 가능한 모델을 개발했음을 의미한다. 하지만 기계학습의 요점은 올바른 매개변수를 기계가 자동으로 찾도록 하는 것이다. 다음 장에서 이를 수행하는 방법을 살펴볼 것이다.

tf.train API

머신러닝에 대한 완전한 내용을 다루는 것은 이 문서의 범위를 벗어난다. 다행히 TensorFlow는 loss function을 최소화하기 위해서 각 변수를 변경하는 옵티마이저를 제공한다. 가장 간단한 옵티마이저는 경사하강법(gradient descent)이다. 이 방법을 사용하면 loss를 최소화 하도록 변수를 수정 할 수 있다. 앞서 했던 것 처럼 사람이 수작업으로 모델을 최적화 하는 것은 많은 시간이 걸리고 오류가 발생하기 쉽다. TensorFlow의 tf.gradients 함수는 자동으로 최적화 할 수 있다. 옵티마이저는 아래와 같이 사용 한다.
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)
옵티마이저를 적용한 코드다.
import tensorflow as tf
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
x = tf.placeholder(tf.float32)
linear_model = W * x + b
init = tf.initialize_all_variables()
sess = tf.Session()


y = tf.placeholder(tf.float32)
squared_deltas = tf.square(linear_model - y)
loss = tf.reduce_sum(squared_deltas)

optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)
sess.run(init)

for i in range(1000):
  sess.run(train, {x:[1,2,3,4], y:[0,-1,-2,-3]})

print(sess.run([W, b]))
실행결과는 아래와 같다.
[array([-0.9999969], dtype=float32), array([ 0.99999082], dtype=float32)]
결과적으로 우리는 y = -0.9999969 * x + 0.99999082라는 모델을 얻었다. 만약 x 값이 5라면 y가 -3.99999386이라는 걸 예측 할 수 있다.

이렇게 해서 우리는 머신러닝 프로그램을 만들었다. 우리는 단지 입력값과 출력 값을 학습시키는 것으로 기계로 하여금 적절한 모델을 찾게 만들었다.

완전한 프로그램

지금까지의 내용을 정리해서 완전히 작동하는 프로그램을 만들었다.
import numpy as np
import tensorflow as tf

# Model parameters
W = tf.Variable([.3], dtype=tf.float32)
b = tf.Variable([-.3], dtype=tf.float32)
# Model input and output
x = tf.placeholder(tf.float32)
linear_model = W * x + b
y = tf.placeholder(tf.float32)
# loss
loss = tf.reduce_sum(tf.square(linear_model - y)) # sum of the squares
# optimizer
optimizer = tf.train.GradientDescentOptimizer(0.01)
train = optimizer.minimize(loss)
# training data
x_train = [1,2,3,4]
y_train = [0,-1,-2,-3]
# training loop
init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init) # reset values to wrong
for i in range(1000):
  sess.run(train, {x:x_train, y:y_train})

# evaluate training accuracy
curr_W, curr_b, curr_loss = sess.run([W, b, loss], {x:x_train, y:y_train})
print("W: %s b: %s loss: %s"%(curr_W, curr_b, curr_loss))
실행 결과는 아래와 같다.
W: [-0.9999969] b: [ 0.99999082] loss: 5.69997e-11
손 실 값이 0에 가까운 매우 좋은 모델이다. 이 프로그램을 TensorBoard로 그려보았다.

 tensorboard

tf.contrib.learn

tf.contrib.learn은 머신러닝 매커니짐을 사용하기 쉽게 단순화한 높은 수준의 라이브러리로 아래의 기능을 가지고 있다.
  • running training loops
  • running evaluation loops
  • managing data set
  • managing feeding

기본 사용 방법

import tensorflow as tf
# 데이터의 조작및 사전처리를 위해서 NumPy를 사용 한다. 
import numpy as np

# Declare list of features. We only have one real-valued feature. There are many
# other types of columns that are more complicated and useful.
features = [tf.contrib.layers.real_valued_column("x", dimension=1)]

# An estimator is the front end to invoke training (fitting) and evaluation
# (inference). There are many predefined types like linear regression,
# logistic regression, linear classification, logistic classification, and
# many neural network classifiers and regressors. The following code
# provides an estimator that does linear regression.
estimator = tf.contrib.learn.LinearRegressor(feature_columns=features)

# TensorFlow provides many helper methods to read and set up data sets.
# Here we use two data sets: one for training and one for evaluation
# We have to tell the function how many batches
# of data (num_epochs) we want and how big each batch should be.
x_train = np.array([1., 2., 3., 4.])
y_train = np.array([0., -1., -2., -3.])
x_eval = np.array([2., 5., 8., 1.])
y_eval = np.array([-1.01, -4.1, -7, 0.])
input_fn = tf.contrib.learn.io.numpy_input_fn({"x":x_train}, y_train, batch_size=4, num_epochs=1000)
eval_input_fn = tf.contrib.learn.io.numpy_input_fn({"x":x_eval}, y_eval, batch_size=4, num_epochs=1000)

# We can invoke 1000 training steps by invoking the  method and passing the
# training data set.
estimator.fit(input_fn=input_fn, steps=1000)

# Here we evaluate how well our model did.
train_loss = estimator.evaluate(input_fn=input_fn)
eval_loss = estimator.evaluate(input_fn=eval_input_fn)
print("train loss: %r"% train_loss)
print("eval loss: %r"% eval_loss)
실행 결과는 아래와 같다.
train loss: {'loss': 2.1927842e-06, 'global_step': 1000}
eval loss: {'loss': 0.0026721444, 'global_step': 1000}

코드만 읽어서는 무슨 내용인지 모르겠다. 코드의 내용을 그래프로 그려봤다.

핵심은 훈련 데이터(x_train, y_train)로 함수를 유추 한 다음, 평가 데이터를 적용해서 성능을 평가하겠다는 거다. 그래프를 보면, 훈련데이터와 평가 데이터가 거의 일치하는 것을 알 수 있는데, 실제 손실도 거의 0에 가깝게 나왔다. 올바르게 학습하고 있음을 알 수 있다.

custom model

미리 정의된 모델 뿐만 아니라, TensorFlow에 내장되지 않은 모델도 만들 수 있다. tf.contrib.learn에서 작동하는 사용자 정의 모델을 정의하려면 tf.contrib.learn.Estimator를 이용해야 한다. 실제 tf.contrib.learn.LinearRegressor는 tf.contrib.learn.Estimator의 하위 클래스다. 모델 개발자는 Estimator에게 예측, 트레이닝, 손실을 평가 할 수 있는 방법을 model_fn 함수로 만들면 된다. 코드는 아래와 같다.