2019년

텐서보드

위지원 2019. 2. 20. 18:30

준비물은

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)




전체 소스코드는 이곳에 있다.

https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/tutorials/mnist/mnist_with_summaries.py



한쪽에서 코드를 실행시켜서 데이터를 생성하고 텐서보드를 실행해주면 log_dir에 test/train폴더가 생기고 log파일이 생겨서 텐서보드에서는 그 폴더에 기록되는 log를 보고 화면에 출력해준다.





코드를 좀 보자..(+_+)


#Train

1. input_data.read_data_sets를 이용하여 데이터를 읽어오고 tensorflow의 기본 Session을 만든다.

텐서플로우에서 Session은 그래프의 실행환경을 캡슐화한것으로 캡슈로하된 실행환경을 객체화하기 위해 Session객체를 만들어 그래프를 실행한것이다. 자세한 설명은 https://dohkstalks.blogspot.com/2017/01/tensorflow-concept-tensorflow.html

세션은 fetche와 feeds 두가지 방법으로 처리가 된다.
연산의 결과를 fetch(가져오는)방법 / placeholder에 값을 넣어 실행하는 방법( feed_dict 을 이용하여 값을 넣어줘야합니당)

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

*코드에 FLAGS.data_dir로 되어있는건 깃 헙 코드에 보면 프로그램(.py파일)실행시 파라미터로 받아서 parser를 이용해 삽입하고 받지 않으면 기본으로 값을 지정해주는 부분이 있기 때문!

one_hot=Ture 는 one_hot Encoding을 이야기한다.

2. 텐서보드에서 노드 이름을 표시하기 위해 with tf.name_scope를 사용하여

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, [-128281])
        tf.summary.image('input', image_shaped_input, 10)    
cs

line 6: tf.reshape를 이용하여 입력 1차원 데이터를 28x28이미지로 변환한다.
line 7: tf.summary.image 함수를 이용하여 데이터를 요약하여 텐서보드에 표시할 수 있다. 아래처럼


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, 784500'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, 50010'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가 과다한지를 알 수 있다고 한다.)



히스토그램도 당연 보여준다




그리고 정확도와 손실함수가 점점 좋아지는 모습도 보여준다.