본문 바로가기
DeepLearning Framework & Coding/Tensorflow 1.X

[코드로 이해하는 딥러닝 14] - Drop out

by 노마드공학자 2020. 12. 31.

[코드로 이해하는 딥러닝 0] - 글연재에 앞서 https://limitsinx.tistory.com/27

[코드로 이해하는 딥러닝 1] - Tensorflow 시작 https://limitsinx.tistory.com/28 

[코드로 이해하는 딥러닝 2] - Tensorflow 변수선언 https://limitsinx.tistory.com/29

[코드로 이해하는 딥러닝 3] - Tensorflow placeholder변수 https://limitsinx.tistory.com/30

[코드로 이해하는 딥러닝 4] - 선형회귀(Linear Regression) https://limitsinx.tistory.com/31

[코드로 이해하는 딥러닝 5] - 다중선형회귀(Multiple Linear Regression) https://limitsinx.tistory.com/32

[코드로 이해하는 딥러닝 6] - 회귀(Regression)에 대한 다른 접근 https://limitsinx.tistory.com/33

[코드로 이해하는 딥러닝 7] - .txt(.csv)파일 불러오기 https://limitsinx.tistory.com/34

[코드로 이해하는 딥러닝 8] - Logistic Regression(sigmoid) https://limitsinx.tistory.com/35

[코드로 이해하는 딥러닝 9] - Softmax Regression(multiple classification) https://limitsinx.tistory.com/36

[코드로 이해하는 딥러닝 10] - MNIST 데이터 분류/One hot encoding https://limitsinx.tistory.com/37

[코드로 이해하는 딥러닝 11] - Deep Neural Network/XOR https://limitsinx.tistory.com/38

[코드로 이해하는 딥러닝 11-EX] - MNIST를 DNN으로 학습해보기/Adam optimizer https://limitsinx.tistory.com/39

[코드로 이해하는 딥러닝 12] - RELU(Rectified Linear Unit) https://limitsinx.tistory.com/40

[코드로 이해하는 딥러닝 13] - .txt(.csv)파일로 저장하기 https://limitsinx.tistory.com/44

 

※이 전글에서 정리한 코드/문법은 재설명하지 않으므로, 참고부탁드립니다

※해당 글은 PC에서 보기에 최적화 되어있습니다.

 

Drop out, 출처 : https://jjeongil.tistory.com/578

 

Drop out은 Alexnet이라는 딥러닝모델에서 처음 제안된 기술입니다.

 

기존까지 사용하고 있던 Neural Network방식은 FCNN(Fully Connected Neural Network)로써, 모든 노드들이 전부 연결되어있죠 (왼쪽이미지)

 

그런데 Drop out이 적용된 방식은 오른쪽이미지처럼, 중간중간의 노드들을 죽여버리고 랜덤하게 연결하여 학습을 진행하는 것입니다.

 

상식적으로는

 

"모든 노드들이 서로 연결된게, 연산량은 많겠지만 모든 경우의 수를 학습하니 더 성능이 좋은거 아니야??"

 

라고 생각하실 수 있습니다. 저도 그렇게 생각했었구요..

 

항상 제가 하는말이 있죠?

딥러닝은 "왜?" 라는 질문 보다는, "그래서 성능이 더좋은 방법은 뭔데??"를 찾는 Heuristic한 학문이라구요!

 

Drop out한게 결과적으로 성능이 훨씬 좋게 나왔습니다.. 그로 인해 Alexnet은 과거기준 압도적인 성능을 보여주었구요!

 

이 기술은 앞으로 다룰 CNN(Convolutional Neural Network)에서 특히 엄청난 성능 효과를 가져오는데요,

 

워낙 연산량이 많은 CNN이다보니.. 연산량 감소도 잡고, 성능 증가도 잡는 정말 두마리 토끼를 모두잡는 기술입니다.

 

출처 : https://m.blog.naver.com/laonple/220827359158

한가지 주의하셔야 할점

 

"학습할때는 Drop out을 해주지만, 검증할때는 Drop out이 없는 FCNN 상태로 진행해야 합니다."

 

중간중간 끊어진 다리로 학습을하고, 끊어두었던 다리를 다시 보수공사하여 검증을 진행하면 성능이 향상되는 원리이기 때문이죠!

 

즉, 조금은 다른의미지만 간단하게 예시를 들어보겠습니다.

내가 친구A를 확인할때 A의 눈,코,입 3개의 특징으로 판단한다고 가정해보죠

 

눈이 아주 매력적인 친구라 특히 눈에띄어, 0.7만큼의 특징을 가지고, 코는 0.1, 입은 0.2라고 생각해보면

Drop out을 통해 "눈"만을 가지고 친구의 얼굴사진을 학습시킵니다.

 

그러면 "눈"만으로 대부분 친구의 사진을 정확히 찾을수 있겠죠

검증할때는 이 "눈"에서 "코"와 "입"까지 추가해서, 눈만으로도 충분히 잘 찾을수있지만 코와 입까지 같이 보고 찾는거죠

 

결과적으론 이런 원리에 의해 성능이 향상됩니다.

 

이제는 코드로 한번 넘어가보겠습니다.

 

[코드 전문]

import tensorflow.compat.v1 as tf

tf.disable_v2_behavior()

import random

# import matplotlib.pyplot as plt

 

from tensorflow.examples.tutorials.mnist import input_data

 

tf.set_random_seed(777)  # reproducibility

 

mnist = input_data.read_data_sets("MNIST_data/"one_hot=True)

 

# parameters

learning_rate = 0.001

training_epochs = 15

batch_size = 100

total_batch = int(mnist.train.num_examples / batch_size)

 

# input place holders

X = tf.placeholder(tf.float32, [None784])

Y = tf.placeholder(tf.float32, [None10])

 

dropout (keep_prob) rate  0.7 on training, but should be 1 for testing

keep_prob = tf.placeholder(tf.float32)

 

W1 = tf.get_variable("W1"shape=[784512],

                      initializer = tf.truncated_normal_initializer(stddev=0.1))

b1 = tf.Variable(tf.random_normal([512]))

L1 = tf.nn.relu(tf.matmul(X, W1) + b1)

L1 = tf.nn.dropout(L1, keep_prob=keep_prob)

 

W2 = tf.get_variable("W2"shape=[512512],

                      initializer = tf.truncated_normal_initializer(stddev=0.1))

b2 = tf.Variable(tf.random_normal([512]))

L2 = tf.nn.relu(tf.matmul(L1, W2) + b2)

L2 = tf.nn.dropout(L2, keep_prob=keep_prob)

 

W3 = tf.get_variable("W3"shape=[512512],

                      initializer = tf.truncated_normal_initializer(stddev=0.1))

b3 = tf.Variable(tf.random_normal([512]))

L3 = tf.nn.relu(tf.matmul(L2, W3) + b3)

L3 = tf.nn.dropout(L3, keep_prob=keep_prob)

 

W4 = tf.get_variable("W4"shape=[512512],

                      initializer = tf.truncated_normal_initializer(stddev=0.1))

b4 = tf.Variable(tf.random_normal([512]))

L4 = tf.nn.relu(tf.matmul(L3, W4) + b4)

L4 = tf.nn.dropout(L4, keep_prob=keep_prob)

 

W5 = tf.get_variable("W5"shape=[51210],

                     initializer = tf.truncated_normal_initializer(stddev=0.1))

b5 = tf.Variable(tf.random_normal([10]))

hypothesis = tf.matmul(L4, W5) + b5

 

# define cost/loss & optimizer

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(

    logits=hypothesis, labels=Y))

optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)

 

# initialize

sess = tf.Session()

sess.run(tf.global_variables_initializer())

 

# train my model

for epoch in range(training_epochs):

    avg_cost = 0

 

    for i in range(total_batch):

        batch_xs, batch_ys = mnist.train.next_batch(batch_size)

        feed_dict = {X: batch_xs, Y: batch_ys, keep_prob0.7}

        c, _ = sess.run([cost, optimizer], feed_dict=feed_dict)

        avg_cost += c / total_batch

 

    print('Epoch:''%04d' % (epoch + 1), 'cost =''{:.9f}'.format(avg_cost))

 

print('Learning Finished!')

 

# Test model and check accuracy

correct_prediction = tf.equal(tf.argmax(hypothesis, 1), tf.argmax(Y, 1))

accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

print('Accuracy:', sess.run(accuracy, feed_dict={

      X: mnist.test.images, Y: mnist.test.labels, keep_prob: 1}))

 

# Get one and predict

r = random.randint(0, mnist.test.num_examples - 1)

print("Label: ", sess.run(tf.argmax(mnist.test.labels[r:r + 1], 1)))

print("Prediction: ", sess.run(

    tf.argmax(hypothesis, 1), feed_dict={X: mnist.test.images[r:r + 1], keep_prob1}))

 

 

[코드 분석-1]

한개 레이어만 보도록 하겠습니다.

tf.nn.relu까지는 이전글까지 모두 정리하였고, Drop out을 위한 딱 한줄만 추가된 형태인데요

 

각 Layer가 끝날때 tf.nn.dropout(L1, keep_prob=A) 이부분만 작성해주시면 됩니다.

A는 "얼마나 남겨둘래??"라는 의미로, keep_prob는 default로 0.7이 되어있습니다.

 

즉, "70%의 노드는 남겨두고 30%를 죽이고 학습할래!" 라는 의미입니다.

 

 

[코드 분석-2]

해당 코드 맨끝의 keep_prob : 1만 봐주시면 됩니다.

 

검증할때는 Drop out이 없는 상태로 진행해야한다고 위에서 설명드렸었는데요

그부분을 표시할때는, keep_prob : 1이라는 코드만 적어주시면 됩니다.

 

 

[결과값]

 

softmax에서 ReLU를 사용하여, MNIST데이터 인식성능을 94%까지 끌어올렸었는데요

 

이번에는 여기에 drop out을 추가하여 97%까지 성능을 3%이상 끌어올려보았습니다. 이정도면 사실상 인간보다 더 판단을 잘한다는 정도인데요(사람은 약 95%)

 

Ensemble과 CNN이라는 기술을 이용하여 99%까지 무자비하게 성능을 끌어올릴 수 있습니다.

 

물론, 컴퓨팅파워와 연산량은 이전 대비 압도적으로 높아지게됩니다!

 

일반인들은 보통 CNN(Convolutional Neural Network)이라고 하면 딥러닝이라고 생각할정도로, 상징성이 있는 기술인데요

 

앞으로 정리를 해나가도록 하겠습니다!

댓글