텐서보드
준비물은
0. 버츄어 박스 6버전
1. 버츄어 박스에 설치한 우분투 18.0.4.2.LTS
2. pip3
3. tensorflow로 텐서플로우 설치
4. virtualenv 설치
텐서플로우 원리와 응용을 읽고 공부한 내용
텐서보드란?
- 텐서플로우의 공식 시각화 도구로 scala,이미지,오디오등 여러 요약 데이터를 표시 할 수 있다.
- 설계한 신경망을 이해하고, 디버그, 최적화를 위해 사용할 수 있다.
어떻게?
1. 텐서플로우 계싼 그래프를 실행한는 동한 데이터를 요약하고 로그에 기록한다.
2. 이 로그 파일을 텐서보드에서 읽어 해석및 시각화 하는 웹페이지를 생성한다.
사용방법은?
아래와 같이 --logdir로 텐서플로우 로그 경로를 지정한 뒤 실행하면 바로 다음에 오는 경로로 TensorBorad 웹페이지로 접속 할 수 있다.
(tensorEnv) weejiwon@weeserver:~/tensorEnv/exampleCode$ tensorboard --logdir=/tmp/tensorflow/mnist/logs/mnist_with_summaries
TensorBoard 1.12.2 at http://weeserver:6006 (Press CTRL+C to quit)
전체 소스코드는 이곳에 있다.
한쪽에서 코드를 실행시켜서 데이터를 생성하고 텐서보드를 실행해주면 log_dir에 test/train폴더가 생기고 log파일이 생겨서 텐서보드에서는 그 폴더에 기록되는 log를 보고 화면에 출력해준다.
코드를 좀 보자..(+_+)
1 2 3 4 | mnist = input_data.read_data_sets(FLAGS.data_dir, fake_data=FLAGS.fake_data) //책에는 두번째 argu가 one_hot=True로 되어있다. sess = tf.InteractiveSession() | cs |
1 2 3 4 5 6 7 | with tf.name_scope('input'): x = tf.placeholder(tf.float32, [None, 784], name='x-input') y_ = tf.placeholder(tf.int64, [None], name='y-input') with tf.name_scope('input_reshape'): image_shaped_input = tf.reshape(x, [-1, 28, 28, 1]) tf.summary.image('input', image_shaped_input, 10) | cs |
3. 신경망 모델의 매개 변수의 초기화 메서드를 정의한다. weight와 bias값을 초기화 해주는 코드
weight를 초기화해줄때는 truncated_normal 함수를 자주 사용한다고 한다. 이는 찾아보니 평균이 0에 가깝고 값이 0에 가까운 정규 분포에서 난수를 선택하는 것이다(ex:=0.1~0.1)
1 2 3 4 5 6 7 8 9 | def weight_variable(shape): """Create a weight variable with appropriate initialization.""" initial = tf.truncated_normal(shape, stddev=0.1) return tf.Variable(initial) def bias_variable(shape): """Create a bias variable with appropriate initialization.""" initial = tf.constant(0.1, shape=shape) return tf.Variable(initial) | cs |
4. Variable 변수에 대한 데이터 요약 함수
Variable의 mean,max,min등을 요약하는 함수로 tf.summary.scalar를 사용하여 스칼라 데이터를 요약하고 기록한다. 같은 느낌으로 summary.histogram 함수는 변수 var의 히스토그램 데이터를 기록한다.
1 2 3 4 5 6 7 8 9 10 | def variable_summaries(var): 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) | cs |
5. MLP( 멀티 레이어 신경망 )을 설계 후 데이터 훈련
파라미터는 입력 데이터/입력 차원/출력 차원/레이어 이름/활성화 함수 이며, 활성화 함수는 기본적으로 ReLU를 사용한다.
ReLU는 Rectified Linear Unit의 약자로 기존의 linear 함수인 sigmoid를 개선한 함수이다. sigmoid함수의 문제인 Graient Vanishing문제(sigmoid 함수는 0~1 값을 가지는데 gradient descent를 사용해 backpropagation을 수행할때 gradient를 계속 곱하다 보면 0으로 수렴해서 layer가 많아지면 잘 작동하지 못함)를 해결하려고 한것.
ReLu는 입력값이 0보다 작으면 0이고 0보다 크면 입력값이 곧 출력값이 된다.
더 자세한 설명은 https://mongxmongx2.tistory.com/25
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | def nn_layer(input_tensor, input_dim, output_dim, layer_name, act=tf.nn.relu):= with tf.name_scope(layer_name): 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 | cs |
1) 신경망의 weight와 bias를 초기화 한다.
2) 10line에서 행렬 곱셈을 실행하고 vias를 더하고 활성화되지 않은 결과에 대해 히스토 그램을 계산 (11line)
3) 12line 활성화 후 다시 히스토그램 계산
6. 신경망 레이어 생성과 dropout 설정
hidden1이라는 변수를 이용해 방금 정의한 함수를 이용해 784(28*28)크기의 입력차원과 숨겨진 노드 수 500으로 출력차원을 설정한다.
dropout 함수를 정의한 후 출력레이어 y를 정의한다. 숨겨진 노드 수 500, 차원 범주 수 10, 활성화 함수는 identity로 맵핑하여 softmax는 당분간 사용하지 않고 나중에 처리한다.
keep_prob는 dropout을 위한 scala placeholder이다.
dropout은 네트워크의 일부를 생략해 오버피팅의 문제를 해결함 자세한 설명은 http://blog.naver.com/PostView.nhn?blogId=laonple&logNo=220818841217&categoryNo=0&parentCategoryNo=0&viewDate=¤tPage=1&postListTopCurrentPage=1&from=postView
1 2 3 4 5 6 7 8 | 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) y = nn_layer(dropped, 500, 10, 'layer2', act=tf.identity) | cs |
7. 출력레이어에 대한 softmax처리를 하고 cross entropy를 계산하고 계산의 내용을 요약한다.
cross entropy는 손실함수다. 자세한 설명은 http://blog.naver.com/PostView.nhn?blogId=gyrbsdl18&logNo=221013188633&parentCategoryNo=3&categoryNo=&viewDate=&isShowPopularPosts=true&from=search 이 블로그가 좀 잘해주셨다.
1 2 3 4 | with tf.name_scope('cross_entropy'): with tf.name_scope('total'): cross_entropy = tf.losses.sparse_softmax_cross_entropy(labels=y_, logits=y) tf.summary.scalar('cross_entropy', cross_entropy) | cs |
8. Adam Optimizer를 이용해 손실 최적화하 정화학 sample수 예측 accuracy를 계산한다. (동일하게 요약을 진행한다)
1 2 3 4 5 6 7 8 9 10 11 | 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), y_) with tf.name_scope('accuracy'): accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) tf.summary.scalar('accuracy', accuracy) | cs |
9. merge_all함수를 이용해서 앞서 요약한 모든 작업을 가져와서 이후에 실행한다.
그리고..로그 파일을 저장하고 global_bariables_initializer().run()으로 모든 변수를 초기화 한다.
1 2 3 4 | merged = tf.summary.merge_all() train_writer = tf.summary.FileWriter(FLAGS.log_dir + '/train', sess.graph) test_writer = tf.summary.FileWriter(FLAGS.log_dir + '/test') tf.global_variables_initializer().run() | cs |
10. feed_dict의 손실함수를 정의한다.
train이 True이면 mnist.train에서 batch 샘플을 얻고 dropout값을 설정한다
train이 False이면 test data를 얻고 keep_prob을 1로 설정한다(dropout효과가 없는 것과 같다) ..사실 지금은 뭔소린지 모르겠다. 일단 한번 더 읽을거니까...
1 2 3 4 5 6 7 8 | def feed_dict(train): 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} | cs |
11. 실제로 작업을 실행하는 부분
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | for i in range(FLAGS.max_steps): if i % 10 == 0: 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: if i % 100 == 99: run_options = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE) run_metadata = tf.RunMetadata() summary, _ = sess.run([merged, train_step], feed_dict=feed_dict(True), options=run_options, run_metadata=run_metadata) train_writer.add_run_metadata(run_metadata, 'step%03d' % i) train_writer.add_summary(summary, i) print('Adding run metadata for', i) else: summary, _ = sess.run([merged, train_step], feed_dict=feed_dict(True)) train_writer.add_summary(summary, i) train_writer.close() test_writer.close() | cs |
1) line2 : 10단계 마다 merged(데이터 요약) accuracy(테스트 set을 이용한 예측 정확도를 구하는 과정)을 수행한다. 다음 라인에서 이작업 역시 요약하여 log파일에 작성한다.
2) line7 : 100단계마다 8line에 사용된 RunOption을 이용하여 텐서플로우 실행 옵션을 정의하고 9line에서 metaData까지 설정하면 훈련 중 연산 시간, 메모리 사용과 같은 정보를 기록 가능하다.
3) line10 : 실제로 작업을 수행하고 요약결과를 write해준다.
텐서보드를 좀 더 구경해보자
아래처럼 그래프도 그려주고... 텐서플로우는 그래프식이니껜..
여기서 layer2를 클릭해보면 아래와 같이 가중치나 바이어스 연산 을 활성하하는 연산을 볼 수 있다.
오~..이렇게 distributions도 볼 수 있고..(신경망 레이어 출력의 분산을 보여주는 것이다. 그래서 신경망 노드의 출력이 유효한디 dead neurons가 과다한지를 알 수 있다고 한다.)
히스토그램도 당연 보여준다
그리고 정확도와 손실함수가 점점 좋아지는 모습도 보여준다.