본문 바로가기

코딩/텐서플로우

비전공자의 코딩 독학 - 파이썬&텐서플로우(11) <과적합>

반응형

안녕하세요.

오늘의 파이썬 코딩 독학 주제는 과적합(Overfitting)입니다.

 

 

1. 과적합이란?

학습데이터를 과도하게 학습하여 학습데이터에 대해서는 정확도가 높지만

실제데이터나 테스트데이터에 대해서는 정확도가 낮은 현상을 의미합니다.

 

이를 해결하기 위해서는

(1) 데이터의 양을 늘리는 방법

(2) 가중치 규제(Regularization)를 적용하는 방법

(3) 드롭아웃(Dropout)을 사용하는 방법

이 있습니다.

 

하나씩 알아보도록 하겠습니다.

 

 

2. 데이터의 양을 늘리는 방법

과적합은 간단히 말해서 머신러닝 모델이 테스트데이터에 너무 맞춰지는 현상 이므로

테스트데이터가 실제데이터와 비슷해질수록 모델이 실제데이터를 더 잘 예측하게 되므로

자연스레 과적합 현상이 해결됩니다.

 

 

3. 가중치 규제를 적용하는 방법

모델이 테스트데이터에 맞춰져 더 복잡해질수록 과적합될 확률이 높습니다.

복잡한 모델을 간단하게 만드는 방법 중 하나가 바로 가중치 규제를 적용하는 것 입니다.

 

간단하게 가중치W의 절대값 합이나 제곱합을 비용 함수에 추가하여 적용할 수 있으며

이때 람다(λ)라는 하이퍼파라미터가 사용되는데, 규제의 강도를 정해주는 인자입니다.

 

람다가 클 수록, 테스트데이터에 대해 적합한 값을 찾는 것 보다는

규제를 위해 추가된 항들을 작게 유지하는 것을 우선한다는 의미가 됩니다.

 

 

4. 드롭아웃을 사용하는 방법

드롭아웃은 간단히 말해서 신경망의 일부를 사용하지 않고 학습을 진행하는 방법입니다.

만약 드롭아웃 비율이 60%라면 매 학습과정마다 랜덤으로 60%정도의 뉴런만 사용하여

학습을 진행하게 됩니다.

 

드롭아웃을 사용하면 매번 새로운 뉴런의 조합을 사용하게 되므로

학습시에 특정 뉴런이나 조합에 의존하지 않도록 해줍니다.

 

 

5. 오늘의 코드

오늘은 드롭아웃을 사용하여 과적합 현상을 해결해보도록 하겠습니다.

전체 코드는 다음과 같습니다.

import tensorflow as tf

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("./mnist/data/", one_hot=True)

keep_prob = tf.placeholder(tf.float32)

X = tf.placeholder(tf.float32, [None, 784])
Y = tf.placeholder(tf.float32, [None, 10])

W1 = tf.Variable(tf.random_normal([784, 256], stddev=0.01))
L1 = tf.nn.relu(tf.matmul(X, W1))
L1 = tf.nn.dropout(L1, 0.8)

W2 = tf.Variable(tf.random_normal([256, 256], stddev=0.01))
L2 = tf.nn.relu(tf.matmul(L1, W2))
L2 = tf.nn.dropout(L2, 0.8)

W3 = tf.Variable(tf.random_normal([256, 10], stddev=0.01))
model = tf.matmul(L2, W3)

cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=model, labels=Y))
optimizer = tf.train.AdamOptimizer(0.001).minimize(cost)

init = tf.global_variables_initializer()
sess = tf.Session()
sess.run(init)

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

for epoch in range(30):
    total_cost = 0

    for i in range(total_batch):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)

        _, cost_val = sess.run([optimizer, cost], feed_dict = {X:batch_xs, Y:batch_ys, keep_prob: 0.8})


        total_cost += cost_val

    print('Epoch:', '%04d' % (epoch + 1), 'Avg. cost=', '{:.3f}'.format(total_cost / total_batch))

print('최적화 완료')

is_correct = tf.equal(tf.argmax(model, 1), tf.argmax(Y, 1))

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

print('정확도:', sess.run(accuracy, feed_dict={X: mnist.test.images, Y: mnist.test.labels, keep_prob: 1}))

눈치가 빠른 분들은 코드를 읽으면서 뭔가 알아채셨겠지만 지난 시간에 알아본

MNIST코드를 그대로 가져왔습니다.

2020/03/11 - [코딩/텐서플로우] - 비전공자의 코딩 독학 - 파이썬&텐서플로우(10)

 

비전공자의 코딩 독학 - 파이썬&텐서플로우(10)

안녕하세요. 오늘의 파이썬 코딩 독학 주제는 MNIST 입니다. MNIST는 손으로 쓴 숫자들의 이미지를 모아놓은 데이터셋으로써 0부터 9까지의 숫자를 28*28 픽셀 크기로 구성해놓은 이미지 집합입니다. MNIST는 머신..

bebutae.tistory.com

자 그럼 본격적으로 시작해보겠습니다.

 

 

6. 소스코드의 목적

지난시간에 배운 손글씨 인식 코드를 활용하여

과적합 현상을 해결하는 방법인 드롭아웃을 사용해보도록 하겠습니다.

 

 

7. 소스코드 분석

기존의 코드에 몇가지 코드만 추가하면

드롭아웃을 사용할 수 있습니다.

 

우선 다음 코드를 봐주세요

W1 = tf.Variable(tf.random_normal([784, 256], stddev=0.01)) 
L1 = tf.nn.relu(tf.matmul(X, W1)) 
L1 = tf.nn.dropout(L1, 0.8) 

W2 = tf.Variable(tf.random_normal([256, 256], stddev=0.01)) 
L2 = tf.nn.relu(tf.matmul(L1, W2)) 
L2 = tf.nn.dropout(L2, 0.8) 

각 계층 구성의 마지막 부분에 드롭아웃 함수를 적용하였습니다.

텐서플로우에서 기본 제공하는 tf.nn.dropout()함수를 사용하였으며

tf.nn.dropout(L1, 0.8)에서 0.8은 사용할 뉴런의 비율을 의미합니다.

다시말하면 여기서 80%의 뉴런만 사용하도록 설정해준 겁니다.

 

여기서 주의하실 점이 학습시에는 80%의 뉴런만 사용하더라도

실제데이터를 활용하여 예측을 진행할때는 100%의 뉴런을 다 사용해야합니다.

따라서 다음과 같은 코드를 이용해 상황에 따라 뉴런의 사용개수를 다르게 만들어 줄

플레이스홀더를 생성해줍니다. 

keep_prob = tf.placeholder(tf.float32)

 

그리고 다음과 같이 테스트시에는 keep_prob에 0.8을 넣어주고,

for epoch in range(30): 
    total_cost = 0 

    for i in range(total_batch): 
        batch_xs, batch_ys = mnist.train.next_batch(batch_size) 

        _, cost_val = sess.run([optimizer, cost], feed_dict = {X:batch_xs, Y:batch_ys, keep_prob: 0.8}) 

실제데이터로 예측할때에는 keep_prob에 1을 넣어주도록 합니다.

print('정확도:', sess.run(accuracy, feed_dict={X: mnist.test.images, Y: mnist.test.labels, keep_prob: 1}))

 

이제 필요한 코드는 다 짜넣었습니다.

여기서 꼭 알아두셔야 할 사실이 있습니다.

과적합은 말그대로 테스트데이터에 과하게 적합해지는 현상입니다.

과적합이 일어났는데 학습횟수를 늘리면 더욱 더 과적합되겠죠?

하지만 우리는 방금 드롭아웃을 활용하여 과적합을 해결했으니

이제 학습횟수를 늘리면 더욱 정확한 결과를 얻을 수 있게됩니다.

 

다음과 같이 코드를 수정하여 학습횟수를 50회로 늘려주겠습니다.

for epoch in range(50):

 

 

8. 결과확인

좌측 사진은 드롭아웃을 적용하지 않은 MNIST 학습 결과이고

우측 사진은 드롭아웃을 적용한 MNIST 학습 결과입니다.

 

정확도가 오른게 보이시나요?

드라마틱하게 오르진 않았지만 그래도 정확도를 끌어올릴 수 있었습니다.

 

반응형