reniew's blog
cs and deep learning

CS20(TensorFlow) Lecture Note (4): Eager execution and interface

|

스탠포드의 TensorFlow 강의인 cs20 강의의 lecture note를 정리한 글입니다. 강의는 오픈되지 않아서 Lecture note, slide 위주로 정리된 글임을 참고 해주시길 바랍니다. 강의의 자세한 Syllabus 및 자료들을 아래 링크를 참고해 주세요.

CS20: TensorFlow for Deep Learning Research


Post list

4. Eager execution and interface

이때까지의 강의를 통해 TensorFlow는 크게 두개의 흐름으로 구성된다는 것을 배웠다.

  • assembling the computation graph
  • executing that graph

위와 같이 그래프를 구성하고, 실행하는 것이 구분되어 있었다. 하지만 파이썬의 구동과 같이 TensorFlow도 imperatively하게 실행될 수 있다면 어떨까? 가능하다면 TensorFlow 모델을 만드는데 있어서 직관적이고 디버깅도 쉬워질 것이다.

TensorFLow의 eager 모드를 통해 TensorFlow도 imperatively하게 작성할 수 있다.

Eager execution

Eager execution에 대한 소개는 다음과 같다.

  • GPU가속과 자동 미분계산을 지원하는 수치 계산을위한 넘파이를 기본으로 하는 라이브러리이다.
  • 머신러닝 연구와 실험을 위한 유연한 플랫폼이다.

Eager모드의 핵심 장점은 다음과 같다.

  • Eager 모드는 파이썬 디버깅 툴에 적합하다.(pdb.set_trace())
  • 즉각적인 에러 report
  • 파이썬 데이터 구조를 사용할 수 있다.
  • 사용이 쉽고, Pythonic하다.

그렇다면 eager모드를 사용하는 기본적인 방법을 보자, 단 몇줄로 쉽게 사용 가능하다.

import tensorflow as tf
import tensorflow.contrib.eager as tfe
tfe.enable_eager_execution()

위의 문장만 사용하면 eager모드로 코딩이 가능하다. 따라서 파이썬 자료형으로도 아래와 같이 작성할 수 있다.

x = [[2.]]
m = tf.matmul(x, x)

print(m) # Session이 필요없다.

예제만 보더라도 기존의 Operator, Variable, Session을 사용할 때보다 훨씬 직관적이고 쉽다. 아직은 eager모드에서 기존의 모드처럼 많은 기능들을 제공하지는 않지만 점점 추가될 예정이다.

eager모드로 미분을 하는 방법도 매우 간단하다. 정의된 연산을 미분 함수에 넣으면 자동으로 미분을 계산해준다. 아래의 예시를 보자.

def square(x):
  return x ** 2

grad = tfe.gradients_function(square)

print(square(3.))    # tf.Tensor(9., shape=(), dtype=float32)
print(grad(3.))     # [tf.Tensor(6., shape=(), dtype=float32))]

그렇다면 이제 lecture 4에서 만들었던 Linear regression 모델을 eager모드로 만들어 보자.

우선은 eager를 포함해 필요한 라이브러리를 임포트한다.

import time

import tensorflow as tf
import tensorflow.contrib.eager as tfe
import matplotlib.pyplot as plt

import utils

2장에서 했던 방법 그대로 데이터를 불러오자. 그리고 tfe.enable_eager_execution()를 통해 eager를 실행한다.

DATA_FILE = 'data/birth_life_2010.txt'

tfe.enable_eager_execution()

# Read the data into a dataset.
data, n_samples = utils.read_birth_life_data(DATA_FILE)
dataset = tf.data.Dataset.from_tensor_slices((data[:,0], data[:,1]))

이후 우리가 사용할 parameter를 정의한다.

w = tfe.Variable(0.0)
b = tfe.Variable(0.0)

이제 우리가 사용할 linear모델을 만들고, 사용할 loss함수를 정의한다. loss는 square와 huber 두 가지 모두 정의한다.

def prediction(x):
  return x * w + b

def squared_loss(y, y_predicted):
  return (y - y_predicted) ** 2  

def huber_loss(y, y_predicted, m=1.0):
  # 기본 m 값은 1.0으로 준다.
  t = y - y_predicted
  return t ** 2 if tf.abs(t) <= m else m * (2 * tf.abs(t) - m)  

이제 optimizer를 포함해서 하나씩 뽑아서 loss를 구하는 함수와 학습과정들을 모두포함해서 하나의 함수로 만든다.

def train(loss_fn):
  print('Training; loss function: ' + loss_fn.__name__)
  optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01)

  def loss_for_example(x, y):
    return loss_fn(y, prediction(x))

  grad_fn = tfe.implicit_value_and_gradients(loss_for_example)

  start = time.time()
  for epoch in range(100):
    total_loss = 0.0
    for x_i, y_i in tfe.Iterator(dataset):
      loss, gradients = grad_fn(x_i, y_i)
      optimizer.apply_gradients(gradients)
      total_loss += loss
    if epoch % 10 == 0:
      print('Epoch {0}: {1}'.format(epoch, total_loss / n_samples))
  print('Took: %f seconds' % (time.time() - start))

마지막으로 학습함수를 실행시키고 시각화를 위해 matplotlib을 사용한다.

train(huber_loss)
plt.plot(data[:,0], data[:,1], 'bo')
plt.plot(data[:,0], data[:,0] * w.numpy() + b.numpy(), 'r',
         label="huber regression")
plt.legend()
plt.show()

코드를 보면 기존의 방법과는 달리 좀 더 파이썬스럽고 직관적으로 보인다. 이전 lecture에서 placeholderdata 둘다 알아보고 익힌것 처럼 session을 통한 TensorFlow 코드와 eager를 통한 TensorFlow 코드 모두 익히도록 하자.

그렇다면 Eager는 어떤 경우에 사용하는 것이 좋을까? 다음의 경우에 사용하는 것이 이점이 있다.

  • 연구자들이 사용하기에 적합하다.
  • 유연한 Framework을 원하는 사람
  • 새로운 모델을 만드는 사람들
  • TensorFlow를 새롭게 접하는 사람들

Eager모드의 장점인 디버깅이 쉽다는 점 때문에 위와 같은 경우에는 eager모드를 사용하는 것이 더욱 적합할 것이다.

하지만 모든 경우에 eager모드를 사용할 수 있는 것이 아니고, 1.5 버전 이상의 TensorFlow에서만 사용할 수 있다.

eager모드에 대해서 더 자세한 내용은 user guide를 참고하자.

Comments