[API] Tensorboard: Visualizaing Learning 

(텐서보드: 학습 시각화)

Tensorboard: Visualizaing Learning

거대한 deep neural network을 학습하는 것처럼 TensorFlow를 사용한 계산은 복잡하고 이해하기 어려울 수 있다. TensorFlow 프로그램을 더 쉽게 이해하고, 디버깅 하고 그리고 최적화 하기위해서, TensorBoard라 부르는 시각화 도구 세트를 포함했다. TensorBoard를 사용하여, TensorFlow 그래프를 시각화 하고, Graph의 실행에 대한 양적지표(quantitative metrics)을 도표로 나타내고, 그리고 그것을 통하여 전달된 이미지와 같은 추가적인 데이터를 보여줄 수 있다. TensorBoard가 완전히 구성되면, 아래와 같이 보일 것이다.

이 튜토리얼은 간단한 TensorBoard 사용법을 담고 있으며 사직 할 수 있도록 돕고자 하는 목적이 있다. 또한 다른 사용 가능한 자원도 있다.  TensorBoard's GitHub는 tips 과 트릭 그리고 디버깅 정보를 포함하는 TensorBoard 사용법에 대한 더 많은 정보를 가지고 있다.

Serializing the data

TensorBoard는 Tensorflow 이벤트 파일을 읽어서 동작한다. Tensorflow 이벤트 파일은 Tensorflow를 수행할 때 생성한 summary 데이터를 포함한다. TensorBoard에는 summary 데이터를 위한 일반적인 라이프사이클이 있다.

첫 번째, summary 데이터를 수집하고 싶은 Tensorflow 그래프를 생성하고, summary operations 에 주석을 달고 싶은 노드를 결정한다.

예를 들어, MNIST 숫자를 인식하기 위해 CNN을 학습한다고 가정한다. 시간에 따라 학습율이 어떻게 달라지는지, 목표 함수가 어떻게 바뀌어가는지 기록하고 싶어할 것이다. 학습율과 손실을 각각 출력하는 노드에 tf.summary.scalar ops을 추가함으로써 데이터를 수집한다. 그러면, scalar_summary에는 'learning rate' 또는 'loss function' 과 같은 의미있는 tag를 제공한다.

아마도 특정 계층의 activations 분포 또는 gradients 또는 weights의 분포를 시각화하고 싶을 수 있다. gradient 결과물이나 가중치를 가지는 변수에 각각 tf.summary.histogram ops를 추가하여 데이터를 수집한다.

사용가능한 모든 summary operation에 대한 자세한 내용은 summary operations 문서를 확인하면 된다.


Tensorflow에서의 Operation은 operation을 수행하거나 결과에 의존성이 있는 operation이 수행 될 때까지 아무것도 하지 않는다. 그리고 방금 생성했던 summary 노드들은  그래프에서 지엽적(주변장치)이다. 현재 수행중인 어떠한 operation도  summary 노드들과 연관성이 있지 않다. 그래서 summaries를 만들기 위해서, 모든 summary 노드들을 수행 할 필요가 있다. 직접 수동으로 모든 summary 노드들을 관리하는 것은 지루한 일이 될 것이다, 그래서 모든 summary 데이터를 생성하는 single operation으로 여러 summary operation을 합치기 위해서 tf.summary.merge_all을 사용하자.

그러면, 주어진 단계에 모든 summary 데이터를 담은 직렬화된 Summary 프로토버프 오브젝트를 생성하는 합쳐진 summary op을 실행시킬 수 있다. 마지막으로, 이러한 summary 데이터를 디스크에 쓰기 위해서, summary 프로토버프를  tf.summary.FileWriter.으로 전달한다.

 FileWriter는 생성자에서 로그디렉토리를 사용해야 한다. - 로그 디렉토리는 꽤 중요하다, 모든 이벤트들이 쓰여질 디렉토리이다. 또한, FileWriter는 생성자에서 Graph를 선택적으로 사용할 수 있다. 그래프 오브젝트를 받으면, Tensorboard는 tensor shape 정보에 때라 Graph를 시각화 할 것이다. Graph를 통하여 어떠한 흐름인지 훨씬 더 나은 정보를 주게 될 것이다.   Tensor shape information.참고

Graph를 수정했고 하나의 FileWriter를 갖게 되었기 때문에, 네트워크를 실행할 준비가 되었다. 원한다면, 합쳐진 summary op를 매 단계마다 실행시키고, 많은 양의 학습데이터를 기록할 수 있다. 그렇지만 필요한 것보다 더 많은 데이터가 될 가능성이 있다. 대신, n 단계 마다 합쳐진 summary op를 수행하도록 고려해보자.

아래의 예제 코드는  simple MNIST tutorial의 수정본이며, 몇 개의 summary ops를 추가하고, 10 단계마다 수행하게 된다. 이것을 수행하고 tensorboard --logdir=/tmp/tensorflow/mnist을 실행하게 되면, 학습이 진행되는 동안 weights 또는 accuracy가 어떻게 변화하는지에 대한 통계들을 시각화 할 수 있다. 아래의 코드는 발췌 된 것이고; 전체 소스는 here.에서 확인

def variable_summaries(var):
 
"""Attach a lot of summaries to a Tensor (for TensorBoard visualization)."""
 
with tf.name_scope('summaries'):
    mean
= tf.reduce_mean(var)
    tf
.summary.scalar('mean', mean)
   
with tf.name_scope('stddev'):
      stddev
= tf.sqrt(tf.reduce_mean(tf.square(var - mean)))
    tf
.summary.scalar('stddev', stddev)
    tf
.summary.scalar('max', tf.reduce_max(var))
    tf
.summary.scalar('min', tf.reduce_min(var))
    tf
.summary.histogram('histogram', var)

def nn_layer(input_tensor, input_dim, output_dim, layer_name, act=tf.nn.relu):
 
"""Reusable code for making a simple neural net layer.

  It does a matrix multiply, bias add, and then uses relu to nonlinearize.
  It also sets up name scoping so that the resultant graph is easy to read,
  and adds a number of summary ops.
  """

 
# Adding a name scope ensures logical grouping of the layers in the graph.
 
with tf.name_scope(layer_name):
   
# This Variable will hold the state of the weights for the layer
   
with tf.name_scope('weights'):
      weights
= weight_variable([input_dim, output_dim])
      variable_summaries
(weights)
   
with tf.name_scope('biases'):
      biases
= bias_variable([output_dim])
      variable_summaries
(biases)
   
with tf.name_scope('Wx_plus_b'):
      preactivate
= tf.matmul(input_tensor, weights) + biases
      tf
.summary.histogram('pre_activations', preactivate)
    activations
= act(preactivate, name='activation')
    tf
.summary.histogram('activations', activations)
   
return activations

hidden1
= nn_layer(x, 784, 500, 'layer1')

with tf.name_scope('dropout'):
  keep_prob
= tf.placeholder(tf.float32)
  tf
.summary.scalar('dropout_keep_probability', keep_prob)
  dropped
= tf.nn.dropout(hidden1, keep_prob)

# Do not apply softmax activation yet, see below.
y
= nn_layer(dropped, 500, 10, 'layer2', act=tf.identity)

with tf.name_scope('cross_entropy'):
 
# The raw formulation of cross-entropy,
 
#
 
# tf.reduce_mean(-tf.reduce_sum(y_ * tf.log(tf.softmax(y)),
 
#                               reduction_indices=[1]))
 
#
 
# can be numerically unstable.
 
#
 
# So here we use tf.nn.softmax_cross_entropy_with_logits on the
 
# raw outputs of the nn_layer above, and then average across
 
# the batch.
  diff
= tf.nn.softmax_cross_entropy_with_logits(targets=y_, logits=y)
 
with tf.name_scope('total'):
    cross_entropy
= tf.reduce_mean(diff)
tf
.summary.scalar('cross_entropy', cross_entropy)

with tf.name_scope('train'):
  train_step
= tf.train.AdamOptimizer(FLAGS.learning_rate).minimize(
      cross_entropy
)

with tf.name_scope('accuracy'):
 
with tf.name_scope('correct_prediction'):
    correct_prediction
= tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))
 
with tf.name_scope('accuracy'):
    accuracy
= tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
tf
.summary.scalar('accuracy', accuracy)

# Merge all the summaries and write them out to /tmp/mnist_logs (by default)
merged
= tf.summary.merge_all()
train_writer
= tf.summary.FileWriter(FLAGS.summaries_dir + '/train',
                                      sess
.graph)
test_writer
= tf.summary.FileWriter(FLAGS.summaries_dir + '/test')
tf
.global_variables_initializer().run()

FileWriter를 초기화 시킨 후에, 모델을 train 하거나 test하기 위해서 FileWriter에 summaries을 추가해야 한다.

# Train the model, and also write summaries.
# Every 10th step, measure test-set accuracy, and write test summaries
# All other steps, run train_step on training data, & add training summaries

def feed_dict(train):
 
"""Make a TensorFlow feed_dict: maps data onto Tensor placeholders."""
 
if train or FLAGS.fake_data:
    xs
, ys = mnist.train.next_batch(100, fake_data=FLAGS.fake_data)
    k
= FLAGS.dropout
 
else:
    xs
, ys = mnist.test.images, mnist.test.labels
    k
= 1.0
 
return {x: xs, y_: ys, keep_prob: k}

for i in range(FLAGS.max_steps):
 
if i % 10 == 0:  # Record summaries and test-set accuracy
    summary
, acc = sess.run([merged, accuracy], feed_dict=feed_dict(False))
    test_writer
.add_summary(summary, i)
   
print('Accuracy at step %s: %s' % (i, acc))
 
else:  # Record train set summaries, and train
    summary
, _ = sess.run([merged, train_step], feed_dict=feed_dict(True))
    train_writer
.add_summary(summary, i)

이제 Tensorboard를 사용하여 이러한 데이터를 시각하기 위한 모든 설정이 되었다.

Launching TensorBoard

Tensorboard를 실행하기 위해서,  아래의 명령을 사용한다.(alternatively python -m tensorboard.main)

tensorboard --logdir=path/to/log-directory

logdir은 FileWriter가 데이터를 직렬화 시켜놓은 디렉토리를 가리킨다. logdir 디렉토리가 개별 실행으로부터 직렬화된 데이터를 포함하는 하위 디렉토리들을 포함하면, Tensorboard는 모든 수행으로부터의 데이터를 시각화 할 것이다. Tensorboard가 수행중이라면, Tensorboard를 보기위해 웹 브라우저에서 localhost:6006을 접속하여 볼 수 있다.

Tensorboard를 보면, 오른쪽 상단 구석에서 navigation 탭을 볼 수 있다. 각각의 탭은 시각화 될 수 있는 직렬화된 데이터 셋을 의미한다.

Graph를 시각화하기 위해서, graph 탭을 사용하는 방법에 대한 자세한 내용은  TensorBoard: Graph Visualization. 을 참고하자.

전반적인 Tensorboard에 대한 사용 정보를 알고 싶으면 TensorBoard's GitHub 을 참고하자.


이 포스팅은 머신러닝/딥러닝 오픈소스 Tensorflow 개발을 위한 선행학습으로 TensorFlow Develop의 TensorBoard 대한 학습노트입니다.


Posted by 이성윤