TigerCow.Door

4_Overfitting_and_Underfitting


안녕하세요. 문범우입니다.

이번 포스팅에서 다뤄볼 내용은, 텐서플로우 튜토리얼의 4번째 overfitting and underfitting 입니다.


In [41]:
# TensorFlow and tf.keras
# 텐서플로우와 keras를 import한다. 이떄 tensorflow는 tf라는 별칭으로 사용할 것임.
import tensorflow as tf
from tensorflow import keras

# Helper libraries
# numpy와 matplotlib을 사용한다.
import numpy as np
import matplotlib.pyplot as plt
# jupyter notebook에서 matplotlib을 사용하기 위한 매직커맨드
%matplotlib inline

print("사용되는 tensorflow의 버전:",tf.__version__)
사용되는 tensorflow의 버전: 1.9.0

ㄱ. 데이터준비

이번에 사용될 데이터는 지난번 test classification에서 사용되었던 IMDB 영화 데이터입니다.

In [43]:
NUM_WORDS = 10000

(train_data, train_labels), (test_data, test_labels) = keras.datasets.imdb.load_data(num_words=NUM_WORDS)
In [44]:
# 0번째 데이터의 값 확인해보기
print(train_data[0][0:5],". . .",train_data[0][-5:])
[1, 14, 22, 16, 43] . . . [16, 5345, 19, 178, 32]
In [45]:
def multi_hot_sequences(sequences, dimension):
    # Create an all-zero matrix of shape (len(sequences), dimension)
    # sequences의 길이만큼 행을 만들고, dimension만큼 열을 만든다.
    results = np.zeros((len(sequences), dimension))
    # sequence
    for i, word_indices in enumerate(sequences):
        # i번째의 데이터에 대해서 포함되어 있는 단어의 숫자값을 인덱스로 하여 1값으로 가져간다.
        results[i, word_indices] = 1.0  # set specific indices of results[i] to 1s
    return results


train_data = multi_hot_sequences(train_data, dimension=NUM_WORDS)
test_data = multi_hot_sequences(test_data, dimension=NUM_WORDS)

우리는 이번에 overfitting에 대해 공부해볼 예정입니다.

위의 multi_hot_sequences 함수는, 모델이 훈련데이터셋에 대해서 보다 빨리 overfitting이 되도록 합니다.

In [46]:
# 0번째 데이터의 값 확인해보기
print(train_data[0][0:5],". . .",train_data[0][-5:])
[0. 1. 1. 0. 1.] . . . [0. 0. 0. 0. 0.]
In [48]:
# 0번째 데이터 값을 그래프로 확인해보기
plt.plot(train_data[0])
Out[48]:
[<matplotlib.lines.Line2D at 0xb28f28550>]

ㄴ. 기준 모델 만들기

오버피팅을 확인해보기 위해 먼저 기준 모델을 만들어본다.

In [49]:
baseline_model = keras.Sequential([
    # `input_shape` is only required here so that `.summary` works. 
    keras.layers.Dense(16, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(16, activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

baseline_model.compile(optimizer='adam',
                       loss='binary_crossentropy',
                       metrics=['accuracy', 'binary_crossentropy'])

baseline_model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense (Dense)                (None, 16)                160016    
_________________________________________________________________
dense_1 (Dense)              (None, 16)                272       
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 17        
=================================================================
Total params: 160,305
Trainable params: 160,305
Non-trainable params: 0
_________________________________________________________________
In [50]:
# 기준 모델을 훈련해보고 측정해본다.
baseline_history = baseline_model.fit(train_data,
                                      train_labels,
                                      epochs=20,
                                      batch_size=512,
                                      validation_data=(test_data, test_labels),
                                      verbose=2)
Train on 25000 samples, validate on 25000 samples
Epoch 1/20
 - 9s - loss: 0.4707 - acc: 0.8128 - binary_crossentropy: 0.4707 - val_loss: 0.3284 - val_acc: 0.8775 - val_binary_crossentropy: 0.3284
Epoch 2/20
 - 7s - loss: 0.2428 - acc: 0.9134 - binary_crossentropy: 0.2428 - val_loss: 0.2843 - val_acc: 0.8873 - val_binary_crossentropy: 0.2843
Epoch 3/20
 - 6s - loss: 0.1789 - acc: 0.9366 - binary_crossentropy: 0.1789 - val_loss: 0.2911 - val_acc: 0.8858 - val_binary_crossentropy: 0.2911
Epoch 4/20
 - 6s - loss: 0.1431 - acc: 0.9512 - binary_crossentropy: 0.1431 - val_loss: 0.3177 - val_acc: 0.8778 - val_binary_crossentropy: 0.3177
Epoch 5/20
 - 7s - loss: 0.1188 - acc: 0.9606 - binary_crossentropy: 0.1188 - val_loss: 0.3433 - val_acc: 0.8732 - val_binary_crossentropy: 0.3433
Epoch 6/20
 - 8s - loss: 0.0975 - acc: 0.9696 - binary_crossentropy: 0.0975 - val_loss: 0.3757 - val_acc: 0.8680 - val_binary_crossentropy: 0.3757
Epoch 7/20
 - 7s - loss: 0.0786 - acc: 0.9776 - binary_crossentropy: 0.0786 - val_loss: 0.4244 - val_acc: 0.8616 - val_binary_crossentropy: 0.4244
Epoch 8/20
 - 8s - loss: 0.0623 - acc: 0.9832 - binary_crossentropy: 0.0623 - val_loss: 0.4540 - val_acc: 0.8631 - val_binary_crossentropy: 0.4540
Epoch 9/20
 - 7s - loss: 0.0478 - acc: 0.9895 - binary_crossentropy: 0.0478 - val_loss: 0.4929 - val_acc: 0.8604 - val_binary_crossentropy: 0.4929
Epoch 10/20
 - 8s - loss: 0.0356 - acc: 0.9938 - binary_crossentropy: 0.0356 - val_loss: 0.5390 - val_acc: 0.8580 - val_binary_crossentropy: 0.5390
Epoch 11/20
 - 6s - loss: 0.0261 - acc: 0.9962 - binary_crossentropy: 0.0261 - val_loss: 0.5758 - val_acc: 0.8578 - val_binary_crossentropy: 0.5758
Epoch 12/20
 - 4s - loss: 0.0186 - acc: 0.9983 - binary_crossentropy: 0.0186 - val_loss: 0.6208 - val_acc: 0.8558 - val_binary_crossentropy: 0.6208
Epoch 13/20
 - 6s - loss: 0.0127 - acc: 0.9989 - binary_crossentropy: 0.0127 - val_loss: 0.6513 - val_acc: 0.8558 - val_binary_crossentropy: 0.6513
Epoch 14/20
 - 7s - loss: 0.0090 - acc: 0.9997 - binary_crossentropy: 0.0090 - val_loss: 0.6821 - val_acc: 0.8548 - val_binary_crossentropy: 0.6821
Epoch 15/20
 - 7s - loss: 0.0065 - acc: 1.0000 - binary_crossentropy: 0.0065 - val_loss: 0.7090 - val_acc: 0.8548 - val_binary_crossentropy: 0.7090
Epoch 16/20
 - 6s - loss: 0.0050 - acc: 1.0000 - binary_crossentropy: 0.0050 - val_loss: 0.7358 - val_acc: 0.8552 - val_binary_crossentropy: 0.7358
Epoch 17/20
 - 7s - loss: 0.0040 - acc: 1.0000 - binary_crossentropy: 0.0040 - val_loss: 0.7585 - val_acc: 0.8551 - val_binary_crossentropy: 0.7585
Epoch 18/20
 - 4s - loss: 0.0032 - acc: 1.0000 - binary_crossentropy: 0.0032 - val_loss: 0.7811 - val_acc: 0.8550 - val_binary_crossentropy: 0.7811
Epoch 19/20
 - 4s - loss: 0.0026 - acc: 1.0000 - binary_crossentropy: 0.0026 - val_loss: 0.8007 - val_acc: 0.8552 - val_binary_crossentropy: 0.8007
Epoch 20/20
 - 4s - loss: 0.0022 - acc: 1.0000 - binary_crossentropy: 0.0022 - val_loss: 0.8192 - val_acc: 0.8548 - val_binary_crossentropy: 0.8192

이번에는 기준 모델보다 hidden units이 적은 모델을 만들어 본다.

In [52]:
smaller_model = keras.Sequential([
    keras.layers.Dense(4, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(4, activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

smaller_model.compile(optimizer='adam',
                loss='binary_crossentropy',
                metrics=['accuracy', 'binary_crossentropy'])

smaller_model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_6 (Dense)              (None, 4)                 40004     
_________________________________________________________________
dense_7 (Dense)              (None, 4)                 20        
_________________________________________________________________
dense_8 (Dense)              (None, 1)                 5         
=================================================================
Total params: 40,029
Trainable params: 40,029
Non-trainable params: 0
_________________________________________________________________
In [53]:
smaller_history = smaller_model.fit(train_data,
                                    train_labels,
                                    epochs=20,
                                    batch_size=512,
                                    validation_data=(test_data, test_labels),
                                    verbose=2)
Train on 25000 samples, validate on 25000 samples
Epoch 1/20
 - 5s - loss: 0.6317 - acc: 0.6360 - binary_crossentropy: 0.6317 - val_loss: 0.5714 - val_acc: 0.7279 - val_binary_crossentropy: 0.5714
Epoch 2/20
 - 6s - loss: 0.5187 - acc: 0.8149 - binary_crossentropy: 0.5187 - val_loss: 0.5109 - val_acc: 0.8128 - val_binary_crossentropy: 0.5109
Epoch 3/20
 - 6s - loss: 0.4623 - acc: 0.8725 - binary_crossentropy: 0.4623 - val_loss: 0.4787 - val_acc: 0.8519 - val_binary_crossentropy: 0.4787
Epoch 4/20
 - 7s - loss: 0.4248 - acc: 0.9022 - binary_crossentropy: 0.4248 - val_loss: 0.4587 - val_acc: 0.8713 - val_binary_crossentropy: 0.4587
Epoch 5/20
 - 5s - loss: 0.3962 - acc: 0.9184 - binary_crossentropy: 0.3962 - val_loss: 0.4449 - val_acc: 0.8781 - val_binary_crossentropy: 0.4449
Epoch 6/20
 - 4s - loss: 0.3721 - acc: 0.9321 - binary_crossentropy: 0.3721 - val_loss: 0.4394 - val_acc: 0.8686 - val_binary_crossentropy: 0.4394
Epoch 7/20
 - 5s - loss: 0.3505 - acc: 0.9414 - binary_crossentropy: 0.3505 - val_loss: 0.4345 - val_acc: 0.8696 - val_binary_crossentropy: 0.4345
Epoch 8/20
 - 7s - loss: 0.3317 - acc: 0.9494 - binary_crossentropy: 0.3317 - val_loss: 0.4253 - val_acc: 0.8758 - val_binary_crossentropy: 0.4253
Epoch 9/20
 - 7s - loss: 0.3147 - acc: 0.9567 - binary_crossentropy: 0.3147 - val_loss: 0.4255 - val_acc: 0.8738 - val_binary_crossentropy: 0.4255
Epoch 10/20
 - 7s - loss: 0.2993 - acc: 0.9617 - binary_crossentropy: 0.2993 - val_loss: 0.4202 - val_acc: 0.8758 - val_binary_crossentropy: 0.4202
Epoch 11/20
 - 7s - loss: 0.2854 - acc: 0.9659 - binary_crossentropy: 0.2854 - val_loss: 0.4210 - val_acc: 0.8738 - val_binary_crossentropy: 0.4210
Epoch 12/20
 - 6s - loss: 0.2714 - acc: 0.9697 - binary_crossentropy: 0.2714 - val_loss: 0.4225 - val_acc: 0.8729 - val_binary_crossentropy: 0.4225
Epoch 13/20
 - 4s - loss: 0.2589 - acc: 0.9732 - binary_crossentropy: 0.2589 - val_loss: 0.4269 - val_acc: 0.8699 - val_binary_crossentropy: 0.4269
Epoch 14/20
 - 4s - loss: 0.2474 - acc: 0.9754 - binary_crossentropy: 0.2474 - val_loss: 0.4230 - val_acc: 0.8698 - val_binary_crossentropy: 0.4230
Epoch 15/20
 - 4s - loss: 0.2368 - acc: 0.9781 - binary_crossentropy: 0.2368 - val_loss: 0.4355 - val_acc: 0.8676 - val_binary_crossentropy: 0.4355
Epoch 16/20
 - 4s - loss: 0.2266 - acc: 0.9802 - binary_crossentropy: 0.2266 - val_loss: 0.4397 - val_acc: 0.8671 - val_binary_crossentropy: 0.4397
Epoch 17/20
 - 3s - loss: 0.2175 - acc: 0.9816 - binary_crossentropy: 0.2175 - val_loss: 0.4456 - val_acc: 0.8663 - val_binary_crossentropy: 0.4456
Epoch 18/20
 - 4s - loss: 0.2084 - acc: 0.9832 - binary_crossentropy: 0.2084 - val_loss: 0.4333 - val_acc: 0.8686 - val_binary_crossentropy: 0.4333
Epoch 19/20
 - 3s - loss: 0.2002 - acc: 0.9843 - binary_crossentropy: 0.2002 - val_loss: 0.4555 - val_acc: 0.8657 - val_binary_crossentropy: 0.4555
Epoch 20/20
 - 3s - loss: 0.1927 - acc: 0.9848 - binary_crossentropy: 0.1927 - val_loss: 0.4654 - val_acc: 0.8643 - val_binary_crossentropy: 0.4654

이번에는 기준 모델보다 hidden units이 많은 모델을 만들어 본다.

In [54]:
bigger_model = keras.models.Sequential([
    keras.layers.Dense(512, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(512, activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

bigger_model.compile(optimizer='adam',
                     loss='binary_crossentropy',
                     metrics=['accuracy','binary_crossentropy'])

bigger_model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_9 (Dense)              (None, 512)               5120512   
_________________________________________________________________
dense_10 (Dense)             (None, 512)               262656    
_________________________________________________________________
dense_11 (Dense)             (None, 1)                 513       
=================================================================
Total params: 5,383,681
Trainable params: 5,383,681
Non-trainable params: 0
_________________________________________________________________
In [55]:
bigger_history = bigger_model.fit(train_data, train_labels,
                                  epochs=20,
                                  batch_size=512,
                                  validation_data=(test_data, test_labels),
                                  verbose=2)
Train on 25000 samples, validate on 25000 samples
Epoch 1/20
 - 18s - loss: 0.3478 - acc: 0.8466 - binary_crossentropy: 0.3478 - val_loss: 0.2992 - val_acc: 0.8776 - val_binary_crossentropy: 0.2992
Epoch 2/20
 - 18s - loss: 0.1441 - acc: 0.9471 - binary_crossentropy: 0.1441 - val_loss: 0.3556 - val_acc: 0.8651 - val_binary_crossentropy: 0.3556
Epoch 3/20
 - 19s - loss: 0.0532 - acc: 0.9839 - binary_crossentropy: 0.0532 - val_loss: 0.4296 - val_acc: 0.8650 - val_binary_crossentropy: 0.4296
Epoch 4/20
 - 18s - loss: 0.0100 - acc: 0.9985 - binary_crossentropy: 0.0100 - val_loss: 0.5852 - val_acc: 0.8694 - val_binary_crossentropy: 0.5852
Epoch 5/20
 - 19s - loss: 0.0011 - acc: 1.0000 - binary_crossentropy: 0.0011 - val_loss: 0.6643 - val_acc: 0.8680 - val_binary_crossentropy: 0.6643
Epoch 6/20
 - 20s - loss: 2.8284e-04 - acc: 1.0000 - binary_crossentropy: 2.8284e-04 - val_loss: 0.7065 - val_acc: 0.8680 - val_binary_crossentropy: 0.7065
Epoch 7/20
 - 20s - loss: 1.6760e-04 - acc: 1.0000 - binary_crossentropy: 1.6760e-04 - val_loss: 0.7332 - val_acc: 0.8684 - val_binary_crossentropy: 0.7332
Epoch 8/20
 - 20s - loss: 1.1922e-04 - acc: 1.0000 - binary_crossentropy: 1.1922e-04 - val_loss: 0.7526 - val_acc: 0.8683 - val_binary_crossentropy: 0.7526
Epoch 9/20
 - 20s - loss: 9.0721e-05 - acc: 1.0000 - binary_crossentropy: 9.0721e-05 - val_loss: 0.7692 - val_acc: 0.8683 - val_binary_crossentropy: 0.7692
Epoch 10/20
 - 19s - loss: 7.1760e-05 - acc: 1.0000 - binary_crossentropy: 7.1760e-05 - val_loss: 0.7820 - val_acc: 0.8682 - val_binary_crossentropy: 0.7820
Epoch 11/20
 - 23s - loss: 5.8391e-05 - acc: 1.0000 - binary_crossentropy: 5.8391e-05 - val_loss: 0.7941 - val_acc: 0.8682 - val_binary_crossentropy: 0.7941
Epoch 12/20
 - 22s - loss: 4.8347e-05 - acc: 1.0000 - binary_crossentropy: 4.8347e-05 - val_loss: 0.8046 - val_acc: 0.8684 - val_binary_crossentropy: 0.8046
Epoch 13/20
 - 21s - loss: 4.0705e-05 - acc: 1.0000 - binary_crossentropy: 4.0705e-05 - val_loss: 0.8139 - val_acc: 0.8682 - val_binary_crossentropy: 0.8139
Epoch 14/20
 - 19s - loss: 3.4762e-05 - acc: 1.0000 - binary_crossentropy: 3.4762e-05 - val_loss: 0.8229 - val_acc: 0.8681 - val_binary_crossentropy: 0.8229
Epoch 15/20
 - 18s - loss: 2.9985e-05 - acc: 1.0000 - binary_crossentropy: 2.9985e-05 - val_loss: 0.8312 - val_acc: 0.8682 - val_binary_crossentropy: 0.8312
Epoch 16/20
 - 19s - loss: 2.6114e-05 - acc: 1.0000 - binary_crossentropy: 2.6114e-05 - val_loss: 0.8379 - val_acc: 0.8681 - val_binary_crossentropy: 0.8379
Epoch 17/20
 - 19s - loss: 2.2936e-05 - acc: 1.0000 - binary_crossentropy: 2.2936e-05 - val_loss: 0.8461 - val_acc: 0.8687 - val_binary_crossentropy: 0.8461
Epoch 18/20
 - 19s - loss: 2.0306e-05 - acc: 1.0000 - binary_crossentropy: 2.0306e-05 - val_loss: 0.8517 - val_acc: 0.8683 - val_binary_crossentropy: 0.8517
Epoch 19/20
 - 19s - loss: 1.8037e-05 - acc: 1.0000 - binary_crossentropy: 1.8037e-05 - val_loss: 0.8579 - val_acc: 0.8683 - val_binary_crossentropy: 0.8579
Epoch 20/20
 - 19s - loss: 1.6142e-05 - acc: 1.0000 - binary_crossentropy: 1.6142e-05 - val_loss: 0.8643 - val_acc: 0.8686 - val_binary_crossentropy: 0.8643

이렇게 까지해서, baseline, small, bigger 총 세가지 모델을 만들고, 같은 데이터셋으로 훈련과 validation을 진행하였다.

그래프를 통해 오차율을 확인해보자.

In [56]:
def plot_history(histories, key='binary_crossentropy'):
  plt.figure(figsize=(16,10))
    
  for name, history in histories:
    val = plt.plot(history.epoch, history.history['val_'+key],
                   '--', label=name.title()+' Val')
    plt.plot(history.epoch, history.history[key], color=val[0].get_color(),
             label=name.title()+' Train')

  plt.xlabel('Epochs')
  plt.ylabel(key.replace('_',' ').title())
  plt.legend()

  plt.xlim([0,max(history.epoch)])


plot_history([('baseline', baseline_history),
              ('smaller', smaller_history),
              ('bigger', bigger_history)])

위의 그래프를 확인해보면 train데이터를 통한 오차보다 validation데이터를 통한 오차가 어떤 모델에서든 크다는 것을 볼 수 있다.

특히나 bigger와 baseline 모델에서는 epoch이 늘어날 수록 validation의 오차가 크게 증가함을 볼 수 있다.

이렇게 testdataset에만 지나치게 적합되어있는 현상을 과적합, overfitting이라고 한다.

이러한 overfitting은 어떻게 해결할 수 있을까?

Overfitting 전략 - 정규화

튜토리얼 상의 내용을 보면, weight를 학습하는데 있어서 보다 적은 값을 이용하도록 한다.

그러한 과정을 '정규화'라고 하는데, L1 정규화와 L2 정규화가 존재한다.

각각에 대해서는 문서의 본문을 그대로 참고한다.

L1 regularization, where the cost added is proportional to the absolute value of the weights coefficients (i.e. to what is called the "L1 norm" of the weights).

L2 regularization, where the cost added is proportional to the square of the value of the weights coefficients (i.e. to what is called the "L2 norm" of the weights). L2 regularization is also called weight decay in the context of neural networks. Don't let the different name confuse you: weight decay is mathematically the exact same as L2 regularization.

위와 같은 정규화를 케라스에서 사용하여 모델을 만들어본다.

In [57]:
l2_model = keras.models.Sequential([
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
                       activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
                       activation=tf.nn.relu),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

l2_model.compile(optimizer='adam',
                 loss='binary_crossentropy',
                 metrics=['accuracy', 'binary_crossentropy'])

l2_model_history = l2_model.fit(train_data, train_labels,
                                epochs=20,
                                batch_size=512,
                                validation_data=(test_data, test_labels),
                                verbose=2)
Train on 25000 samples, validate on 25000 samples
Epoch 1/20
 - 10s - loss: 0.5400 - acc: 0.8033 - binary_crossentropy: 0.5021 - val_loss: 0.3943 - val_acc: 0.8726 - val_binary_crossentropy: 0.3546
Epoch 2/20
 - 7s - loss: 0.3134 - acc: 0.9049 - binary_crossentropy: 0.2687 - val_loss: 0.3354 - val_acc: 0.8869 - val_binary_crossentropy: 0.2869
Epoch 3/20
 - 5s - loss: 0.2578 - acc: 0.9270 - binary_crossentropy: 0.2066 - val_loss: 0.3366 - val_acc: 0.8860 - val_binary_crossentropy: 0.2833
Epoch 4/20
 - 4s - loss: 0.2316 - acc: 0.9386 - binary_crossentropy: 0.1765 - val_loss: 0.3484 - val_acc: 0.8836 - val_binary_crossentropy: 0.2921
Epoch 5/20
 - 6s - loss: 0.2178 - acc: 0.9463 - binary_crossentropy: 0.1598 - val_loss: 0.3613 - val_acc: 0.8794 - val_binary_crossentropy: 0.3022
Epoch 6/20
 - 7s - loss: 0.2043 - acc: 0.9511 - binary_crossentropy: 0.1445 - val_loss: 0.3762 - val_acc: 0.8767 - val_binary_crossentropy: 0.3158
Epoch 7/20
 - 5s - loss: 0.1969 - acc: 0.9543 - binary_crossentropy: 0.1354 - val_loss: 0.3911 - val_acc: 0.8725 - val_binary_crossentropy: 0.3287
Epoch 8/20
 - 4s - loss: 0.1882 - acc: 0.9582 - binary_crossentropy: 0.1251 - val_loss: 0.4013 - val_acc: 0.8716 - val_binary_crossentropy: 0.3379
Epoch 9/20
 - 5s - loss: 0.1819 - acc: 0.9599 - binary_crossentropy: 0.1178 - val_loss: 0.4190 - val_acc: 0.8702 - val_binary_crossentropy: 0.3543
Epoch 10/20
 - 7s - loss: 0.1795 - acc: 0.9620 - binary_crossentropy: 0.1141 - val_loss: 0.4350 - val_acc: 0.8670 - val_binary_crossentropy: 0.3691
Epoch 11/20
 - 7s - loss: 0.1736 - acc: 0.9633 - binary_crossentropy: 0.1071 - val_loss: 0.4417 - val_acc: 0.8660 - val_binary_crossentropy: 0.3746
Epoch 12/20
 - 6s - loss: 0.1699 - acc: 0.9648 - binary_crossentropy: 0.1028 - val_loss: 0.4632 - val_acc: 0.8618 - val_binary_crossentropy: 0.3955
Epoch 13/20
 - 4s - loss: 0.1688 - acc: 0.9660 - binary_crossentropy: 0.1002 - val_loss: 0.4665 - val_acc: 0.8632 - val_binary_crossentropy: 0.3975
Epoch 14/20
 - 4s - loss: 0.1588 - acc: 0.9710 - binary_crossentropy: 0.0899 - val_loss: 0.4748 - val_acc: 0.8610 - val_binary_crossentropy: 0.4062
Epoch 15/20
 - 3s - loss: 0.1523 - acc: 0.9744 - binary_crossentropy: 0.0838 - val_loss: 0.4883 - val_acc: 0.8620 - val_binary_crossentropy: 0.4196
Epoch 16/20
 - 4s - loss: 0.1498 - acc: 0.9744 - binary_crossentropy: 0.0809 - val_loss: 0.5009 - val_acc: 0.8597 - val_binary_crossentropy: 0.4318
Epoch 17/20
 - 5s - loss: 0.1474 - acc: 0.9760 - binary_crossentropy: 0.0782 - val_loss: 0.5079 - val_acc: 0.8590 - val_binary_crossentropy: 0.4383
Epoch 18/20
 - 4s - loss: 0.1455 - acc: 0.9756 - binary_crossentropy: 0.0756 - val_loss: 0.5240 - val_acc: 0.8574 - val_binary_crossentropy: 0.4537
Epoch 19/20
 - 4s - loss: 0.1423 - acc: 0.9772 - binary_crossentropy: 0.0719 - val_loss: 0.5285 - val_acc: 0.8601 - val_binary_crossentropy: 0.4580
Epoch 20/20
 - 3s - loss: 0.1401 - acc: 0.9790 - binary_crossentropy: 0.0693 - val_loss: 0.5415 - val_acc: 0.8562 - val_binary_crossentropy: 0.4702

L2 정규화를 사용하는 l2_model을 구성하였다.

앞의 2개의 레이어에 정규화를 진행시켰는데, kernel_regularizer에 사용할 정규화를 케라스 라이브러리를 통해 입력해준다. 이때 뒤에 소괄호를 통해 넣어주는 값은 정규화의 세기를 의미한다.

l2_model을 그래프로 살펴보고 기준 모델과 비교해본다.

In [58]:
plot_history([('baseline', baseline_history),
              ('l2', l2_model_history)])

Overfitting 전략 - Drop out

이번에 알아볼 Overfitting 전략은 Drop out 방법이다.

이는 쉽게 이야기해서, 학습할 때 모든 노드들이 일하는 것이 아니고, 랜덤하게 특정 노드들은 학습을 하지 않도록 하는 것이다.

이번에도 바로 드랍아웃을 적용한 모델을 만들어 본다.

In [59]:
dpt_model = keras.models.Sequential([
    keras.layers.Dense(16, activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(16, activation=tf.nn.relu),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

dpt_model.compile(optimizer='adam',
                  loss='binary_crossentropy',
                  metrics=['accuracy','binary_crossentropy'])

dpt_model_history = dpt_model.fit(train_data, train_labels,
                                  epochs=20,
                                  batch_size=512,
                                  validation_data=(test_data, test_labels),
                                  verbose=2)
Train on 25000 samples, validate on 25000 samples
Epoch 1/20
 - 9s - loss: 0.6336 - acc: 0.6349 - binary_crossentropy: 0.6336 - val_loss: 0.5118 - val_acc: 0.8349 - val_binary_crossentropy: 0.5118
Epoch 2/20
 - 7s - loss: 0.4848 - acc: 0.7913 - binary_crossentropy: 0.4848 - val_loss: 0.3582 - val_acc: 0.8785 - val_binary_crossentropy: 0.3582
Epoch 3/20
 - 5s - loss: 0.3747 - acc: 0.8632 - binary_crossentropy: 0.3747 - val_loss: 0.3021 - val_acc: 0.8882 - val_binary_crossentropy: 0.3021
Epoch 4/20
 - 4s - loss: 0.2978 - acc: 0.8969 - binary_crossentropy: 0.2978 - val_loss: 0.2791 - val_acc: 0.8865 - val_binary_crossentropy: 0.2791
Epoch 5/20
 - 5s - loss: 0.2509 - acc: 0.9136 - binary_crossentropy: 0.2509 - val_loss: 0.2811 - val_acc: 0.8858 - val_binary_crossentropy: 0.2811
Epoch 6/20
 - 7s - loss: 0.2168 - acc: 0.9277 - binary_crossentropy: 0.2168 - val_loss: 0.2903 - val_acc: 0.8854 - val_binary_crossentropy: 0.2903
Epoch 7/20
 - 8s - loss: 0.1900 - acc: 0.9368 - binary_crossentropy: 0.1900 - val_loss: 0.3101 - val_acc: 0.8832 - val_binary_crossentropy: 0.3101
Epoch 8/20
 - 8s - loss: 0.1656 - acc: 0.9456 - binary_crossentropy: 0.1656 - val_loss: 0.3192 - val_acc: 0.8840 - val_binary_crossentropy: 0.3192
Epoch 9/20
 - 8s - loss: 0.1520 - acc: 0.9488 - binary_crossentropy: 0.1520 - val_loss: 0.3468 - val_acc: 0.8814 - val_binary_crossentropy: 0.3468
Epoch 10/20
 - 7s - loss: 0.1376 - acc: 0.9524 - binary_crossentropy: 0.1376 - val_loss: 0.3632 - val_acc: 0.8808 - val_binary_crossentropy: 0.3632
Epoch 11/20
 - 4s - loss: 0.1230 - acc: 0.9580 - binary_crossentropy: 0.1230 - val_loss: 0.3925 - val_acc: 0.8796 - val_binary_crossentropy: 0.3925
Epoch 12/20
 - 5s - loss: 0.1120 - acc: 0.9611 - binary_crossentropy: 0.1120 - val_loss: 0.4139 - val_acc: 0.8791 - val_binary_crossentropy: 0.4139
Epoch 13/20
 - 6s - loss: 0.1025 - acc: 0.9632 - binary_crossentropy: 0.1025 - val_loss: 0.4263 - val_acc: 0.8769 - val_binary_crossentropy: 0.4263
Epoch 14/20
 - 4s - loss: 0.0960 - acc: 0.9658 - binary_crossentropy: 0.0960 - val_loss: 0.4587 - val_acc: 0.8750 - val_binary_crossentropy: 0.4587
Epoch 15/20
 - 4s - loss: 0.0876 - acc: 0.9680 - binary_crossentropy: 0.0876 - val_loss: 0.4755 - val_acc: 0.8755 - val_binary_crossentropy: 0.4755
Epoch 16/20
 - 5s - loss: 0.0842 - acc: 0.9687 - binary_crossentropy: 0.0842 - val_loss: 0.4955 - val_acc: 0.8747 - val_binary_crossentropy: 0.4955
Epoch 17/20
 - 4s - loss: 0.0808 - acc: 0.9702 - binary_crossentropy: 0.0808 - val_loss: 0.5094 - val_acc: 0.8769 - val_binary_crossentropy: 0.5094
Epoch 18/20
 - 5s - loss: 0.0787 - acc: 0.9700 - binary_crossentropy: 0.0787 - val_loss: 0.5444 - val_acc: 0.8757 - val_binary_crossentropy: 0.5444
Epoch 19/20
 - 5s - loss: 0.0744 - acc: 0.9712 - binary_crossentropy: 0.0744 - val_loss: 0.5404 - val_acc: 0.8730 - val_binary_crossentropy: 0.5404
Epoch 20/20
 - 7s - loss: 0.0739 - acc: 0.9715 - binary_crossentropy: 0.0739 - val_loss: 0.5570 - val_acc: 0.8724 - val_binary_crossentropy: 0.5570

drop out을 적용한, dpt_model을 구성하였다.

각각의 레이어 다음에 0.5만큼의 drop out을 하도록 설정하였다.

dpt_model 또한 기준 모델과 비교해본다.

In [60]:
plot_history([('baseline', baseline_history),
              ('dropout', dpt_model_history)])

이렇게, 우리는 overfitting을 해결하기 위해 정규화와, 드랍아웃 두가지를 살펴보았다.

이 외에도 아래와 같은 방법을로 overfitting을 해소할 수 있다.

  • Get more training data.
  • Reduce the capacity of the network.
  • Add weight regularization.
  • Add dropout.

tensorflow 튜토리얼의 overfitting and underfitting의 문서는 위의 내용까지이다.

추가적으로 L2정규화와, 드랍아웃을 함께 적용한 모델을 만들고 테스트 해보았다.

In [61]:
l2_dpt_model = keras.models.Sequential([
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
                       activation=tf.nn.relu, input_shape=(NUM_WORDS,)),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(16, kernel_regularizer=keras.regularizers.l2(0.001),
                       activation=tf.nn.relu),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(1, activation=tf.nn.sigmoid)
])

l2_dpt_model.compile(optimizer='adam',
                 loss='binary_crossentropy',
                 metrics=['accuracy', 'binary_crossentropy'])

l2_dpt_model_history = l2_dpt_model.fit(train_data, train_labels,
                                epochs=20,
                                batch_size=512,
                                validation_data=(test_data, test_labels),
                                verbose=2)
Train on 25000 samples, validate on 25000 samples
Epoch 1/20
 - 8s - loss: 0.6572 - acc: 0.6607 - binary_crossentropy: 0.6204 - val_loss: 0.5217 - val_acc: 0.8572 - val_binary_crossentropy: 0.4884
Epoch 2/20
 - 7s - loss: 0.4884 - acc: 0.8236 - binary_crossentropy: 0.4540 - val_loss: 0.3850 - val_acc: 0.8816 - val_binary_crossentropy: 0.3488
Epoch 3/20
 - 8s - loss: 0.3984 - acc: 0.8780 - binary_crossentropy: 0.3599 - val_loss: 0.3424 - val_acc: 0.8878 - val_binary_crossentropy: 0.3015
Epoch 4/20
 - 7s - loss: 0.3490 - acc: 0.8994 - binary_crossentropy: 0.3059 - val_loss: 0.3301 - val_acc: 0.8874 - val_binary_crossentropy: 0.2848
Epoch 5/20
 - 7s - loss: 0.3162 - acc: 0.9143 - binary_crossentropy: 0.2684 - val_loss: 0.3309 - val_acc: 0.8865 - val_binary_crossentropy: 0.2806
Epoch 6/20
 - 7s - loss: 0.2951 - acc: 0.9214 - binary_crossentropy: 0.2429 - val_loss: 0.3382 - val_acc: 0.8872 - val_binary_crossentropy: 0.2840
Epoch 7/20
 - 7s - loss: 0.2763 - acc: 0.9281 - binary_crossentropy: 0.2201 - val_loss: 0.3501 - val_acc: 0.8837 - val_binary_crossentropy: 0.2922
Epoch 8/20
 - 7s - loss: 0.2663 - acc: 0.9337 - binary_crossentropy: 0.2065 - val_loss: 0.3682 - val_acc: 0.8826 - val_binary_crossentropy: 0.3066
Epoch 9/20
 - 7s - loss: 0.2606 - acc: 0.9355 - binary_crossentropy: 0.1975 - val_loss: 0.3688 - val_acc: 0.8818 - val_binary_crossentropy: 0.3043
Epoch 10/20
 - 7s - loss: 0.2468 - acc: 0.9412 - binary_crossentropy: 0.1811 - val_loss: 0.3903 - val_acc: 0.8787 - val_binary_crossentropy: 0.3231
Epoch 11/20
 - 8s - loss: 0.2433 - acc: 0.9438 - binary_crossentropy: 0.1746 - val_loss: 0.4041 - val_acc: 0.8788 - val_binary_crossentropy: 0.3340
Epoch 12/20
 - 8s - loss: 0.2386 - acc: 0.9456 - binary_crossentropy: 0.1674 - val_loss: 0.4017 - val_acc: 0.8767 - val_binary_crossentropy: 0.3291
Epoch 13/20
 - 8s - loss: 0.2349 - acc: 0.9481 - binary_crossentropy: 0.1615 - val_loss: 0.4302 - val_acc: 0.8774 - val_binary_crossentropy: 0.3557
Epoch 14/20
 - 7s - loss: 0.2293 - acc: 0.9500 - binary_crossentropy: 0.1538 - val_loss: 0.4414 - val_acc: 0.8772 - val_binary_crossentropy: 0.3648
Epoch 15/20
 - 8s - loss: 0.2261 - acc: 0.9516 - binary_crossentropy: 0.1487 - val_loss: 0.4367 - val_acc: 0.8774 - val_binary_crossentropy: 0.3582
Epoch 16/20
 - 7s - loss: 0.2263 - acc: 0.9516 - binary_crossentropy: 0.1471 - val_loss: 0.4329 - val_acc: 0.8755 - val_binary_crossentropy: 0.3529
Epoch 17/20
 - 7s - loss: 0.2254 - acc: 0.9534 - binary_crossentropy: 0.1448 - val_loss: 0.4579 - val_acc: 0.8750 - val_binary_crossentropy: 0.3768
Epoch 18/20
 - 8s - loss: 0.2202 - acc: 0.9548 - binary_crossentropy: 0.1386 - val_loss: 0.4616 - val_acc: 0.8748 - val_binary_crossentropy: 0.3797
Epoch 19/20
 - 7s - loss: 0.2215 - acc: 0.9546 - binary_crossentropy: 0.1393 - val_loss: 0.4714 - val_acc: 0.8759 - val_binary_crossentropy: 0.3889
Epoch 20/20
 - 8s - loss: 0.2199 - acc: 0.9564 - binary_crossentropy: 0.1370 - val_loss: 0.4605 - val_acc: 0.8749 - val_binary_crossentropy: 0.3772
In [62]:
plot_history([('baseline', baseline_history),
              ('L2 with dropout', l2_dpt_model_history)])

위와 같이 보다 좋은 결과를 확인할 수 있었다.


블로그 이미지

Tigercow.Door

Data-Analysis / AI / back-end / Algorithm / DeepLearning / etc


안녕하세요. 문범우입니다.

이번 포스팅에서는 텐서플로우의 새로운 기능인 dynamic rnn에 대해서 알아보도록 하겠습니다.


1. Dynamic RNN



우리가 그동안 다루어보았던 RNN모델을 다시한번 생각해보도록 하겠습니다.

이전의 모델을 이용해서 'hello'와 같은 문자열을 다루어볼때는, 우리가 다루고자하는 문자열의 크기에 따라서 RNN을 구성하였습니다.

하지만 실제의 데이터에서는 문자열의 크기가 가변적입니다.

예를 들어, 누군가가 전달하는 문자열 데이터를 처리한다고 했을 때, 그 데이터가 항상 고정된 길이는 아닙니다. 오히려 우리가 매번 고정된 길이로 보내달라고 한다면, 우리의 모델을 사용하는 사용자 입장에서는 매우 불편한 일이 될 것입니다.


이러한 것을 다루기 위해, 기존의 방법으로는 아래와 같이, 문자열의 뒤에 padding을 붙여주었습니다.


하지만 사실상 이러한 padding을 넣어도, 각 모델에 있는 weight에 의해서 어떠한 값이 나오게 됩니다.

그리고 이렇게 나오는 값 때문에 우리의 loss함수가 헷갈려할 수 있어 결과가 좋지 않을 수도 있습니다.


그럼 이것을 어떻게 해결할까요?


텐서플로우에서는 이것을 해결하기 위해 각 문자열의 길이를 구해서 sequence_length 라는 list로 만들어서 dynamic rnn 모델을 사용합니다.

코드를 통해 확인해보도록 하겠습니다.



이때 입력은 어떠한 문자열이라고 가정합니다.

그리고 cell을 만드는 것과 다른 과정도 이전의 알아본 것과 일치합니다.

하지만 rnn을 구현할때, dynamic_rnn을 사용하며 이때 앞에서구한 sequence_length를 넣은것을 볼 수 있습니다.


그리고 이에 따른 우측의 결과를 보시면, 길이가 5인 문자열에 대해서는 올바르게 결과가 나오고, 길이가 3인 문자열에 대해서는 앞의 3개 문자열에 대해서만 값을 주고 뒤의 2개의 값은 0으로 만듭니다.

그리고 길이가 4인 문자열에 대해서도 동일하게 맨 뒤의 1개에 대해서는 값을 0으로 만들어 버립니다.


즉, 문자열이 없는 곳은 아예 값을 0으로 만들어서 우리의 Loss함수가 잘 작동하도록 합니다.


블로그 이미지

Tigercow.Door

Data-Analysis / AI / back-end / Algorithm / DeepLearning / etc


안녕하세요. 문범우입니다.

이번 포스팅에서는, 그 동안 배운 RNN 내용을 통해서, RNN을 보다 wide하고 deep하게 만들어 보도록 하겠습니다.


1. Long sentence


우리가 지난 번 내용을 통해 'hihello'라는 문자열에 대해 RNN을 이용하여 문자열을 예측하는 모델을 구성해 보았습니다.


그럼, 이러한 모델이 아래와 같은 긴 문장에서도 잘 작동할까요?


결과는 No. 입니다.


위와 같은 긴 문장은 우리가 그전에 만들어보았던 모델에서 제대로 작동되지 않습니다. 왜 그럴까요?

간단하게 생각해보면, 우리의 모델이 보다 wide하거나 deep하지 않기 때문입니다. 즉, 위와 같은 긴 문자열을 다루기에는 우리의 모델이 너무 작습니다.


그럼 당연히 생각해볼 문제는, 우리의 RNN 모델을 더 쌓을수는 없을까? 입니다.



2. Wide & Depp RNN


그럼 RNN 모델을 어떻게 쌓을까요?

이는 어렵지 않습니다.

기존의 코드를 크게 수정할 필요도 없습니다.



이를 Stacked RNN 이라고 하는데, 위의 코드에서 보시다 시피 이전의 코드와 같이 cell을 만드는데 그 아래에서 MultiRNNCell이라는 함수를 새롭게 사용하고 있습니다.

해당 함수를 통해 우리가 얼마나 RNN을 쌓아올릴지 손쉽게 구성할 수 있습니다.



3. Softmax layer


또한 우리가 CNN을 알아보면서 Softmax layer를 사용했던 것처럼, 우리의 RNN모델을 통해 나온 결과를 그대로 사용하지 않고 그 뒤에 Softmax layer를 붙여주면 보다 더 잘 작동할 것 입니다.



이를 위해서 위의 그림과 같이 RNN 모델에서 나오는 결과 값을 softmax 에 넣기 위해 reshape을 진행합니다. 즉, X_for_softmax 를 먼저 만들어주고 이를 softmax layer를 통과시킨후 outputs으로 펼쳐줍니다.



이를 실제로 코드로 살펴보면 위와 같습니다.

위에서 말했던 것처럼, X_for_softmax에 RNN의 outputs를 넣어주며 reshape을 하고 softmax의 w와 b를 정해줍니다.

w를 정할때 입력사이즈(hidden size), 출력사이즈(num classes), 즉 우리가 예측하고자 하는 것의 one-hotd의 크기를 넣어줍니다.

그리고 bias의 값에는 출력사이즈를 넣어줍니다.

이렇게 softmax layer를 통과시키고 나서 다시한번 reshape를 통해 결과를 펼쳐줍니다.


그리고 이러한 outputs를 우리의 sequence_loss에 넣어줍니다.

이전에는 사실, RNN의 결과로 나온 outputs를 그대로 넣었는데 그 값들은 state 값을 가지고 있기 때문에 사실상 틀린 것 입니다. 위와 같이 softmax layer를 통과시켜서 나온 output을 logits으로 넣어주어야 합니다.


그리고 마지막에는 그전과 같이 훈련을 시켜주고, 결과를 출력해주면 됩니다.

블로그 이미지

Tigercow.Door

Data-Analysis / AI / back-end / Algorithm / DeepLearning / etc


안녕하세요. 문범우입니다.

이번 포스팅에서는 RNN을 이용하여 hihello를 학습시켜 보도록 하겠습니다.



1. 'hihello' 학습시키기

이번에는 위와 같이 우리가 hihello 라는 문자열을 주었을 때, 각 문자에 대해 다음 문자를 예측해보도록 학습시킬 것 입니다.

이 문제가 간단해보일 수 있지만, 좀 더 자세히 살펴보면 h를 입력했을 때, 어쩔때는 i를, 어쩔 때는 e를 반환해야 합니다. 이는 RNN의 특성인, 이전 문자가 무엇이 나왔는지 알아야 값을 제대로 출력할 수 있습니다.



2. RNN basic 정리


그럼 먼저 간단히 RNN의 기본적인 내용에 대해 정리해보도록 하겠습니다.

우리가 그동한 RNN을 공부하면서 그 자체에 대해서는 간단히 여겨질 수 있으나 실제로 RNN에 어떤 값을 어떻게 넣어줘야 할지 복잡할 수 있습니다.

하나씩 살펴보겠습니다.

우리가 넣고자 하는 text는 'hihello'입니다. 그리고 그 문자에는 5개의 유니크한 문자로 존재합니다. 그리고 이 문자열을 인덱스로 표현하면,

h:0 , i:1 , e:2 , l:3 , o:4 이고 이를 one-hot 인코딩으로 나타내면 위 그림과 같습니다.


우리가 전체적으로 구성할 모델은 위와 같을 것입니다.

그럼, 이제 입력 dimension, 출력 dimension, batch size 등에 대해서 생각해보도록 하겠습니다.

그림에서 보듯이 input dimension 은 5입니다.

그리고 총 6개로 구성되기 때문에 sequence = 6 입니다.

또한 hidden 또한 5 입니다.

마지막으로 batch size는 하나의 문자이므로 1 입니다.



3. RNN 만들기


먼저 rnn cell을 만듭니다.

이때 기본적으로 BasicRNNCell 을 이용할 수도 있겠지만, 많이 사용되는 LSTM 이나 GRU를 이용할 수도 있습니다. 이때 중요한 것은 rnn_size입니다.

rnn size는 출력값으로써 5로 정해집니다.


두번째로 중요한 것은 입력입니다.

이는 위에서 알아봤던 것처럼, input dimension = 5, sequence = 6 으로 넣어주면 될 것입니다.


그럼 이를 바탕으로 데이터를 만들어 보도록 하겠습니다.


먼저 입력, x_data 로 hihell을 인덱스로써 넣어주었고 이를 one_hot encoding으로 변환하여, x_one_hot 으로 구성하였습니다.

그리고 우리가 학습하고자 하는 결과값, y_data 또한 위와 같이 구성하였습니다.


그리고 X 와 Y에 우리가 설정한 값들을 넣어줍니다.

위에서 알아본 것과 같이 sequence_length = 6 이며, input_dim = 5 입니다.

이후, cell을 만들고 이때 결과의 크기, hidden_size를 입력합니다.

또한 위에서는 initial_state를 만드는데 전부 0으로 만들었습니다.

그리고 우리가 만든 cell과 state를 이용하여 결과를 내도록 하였습니다.


이렇게 만든 모델이 얼마나 잘 맞는지 알기 위해서 loss를 구해야 합니다.

즉, cost를 구해야하는데 텐서플로우에서는 이를 쉽게할 수 있도록 sequence_loss 라는 함수를 제공합니다.


sequence_loss 함수를 활용하여 위와 같이 구성합니다.

우리의 모델을 통해 나오는 outputs를 sequence_loss의 logits으로 넣어줍니다. 이는 우리의 예측값을 넣어주는 것 입니다.

그리고 targets는 우리의 훈련값을 넣어주는 것으로써 Y를 넣어줍니다. 그리고 여기서 weights는 단순히 1인 값으로 넣어주도록 합니다.


그리고 이것을 평균을 내서 AdamOptimize로 넣어줌으로써 loss를 최소화 시켜줍니다.



그리고 학습과정은 그 동안했던 것과 유사하게 진행해줍니다.



이를 통한 결과는 위와 같습니다.

결과의 초반에 보면 예측이 아주 잘못되고 있지만 시간이 지나면서 loss가 점점떨어지고, 예측또한 잘 되는 것을 볼 수 있습니다.


블로그 이미지

Tigercow.Door

Data-Analysis / AI / back-end / Algorithm / DeepLearning / etc


안녕하세요. 문범우입니다.

이번 포스팅에서는 TensorFlow에서 CNN을 이용하여 MNIST를 99%로 예측해보도록 하겠습니다.


1. 기본 구조


이번 실습에서 우리가 진행해볼 구조는 위의 그림과 같습니다.

Convolution layer와 pooling layer가 두번 반복된 구조를 통해 나온 결과를 Fully-Connected layer를 통해 10개의 숫자들 중에서 예측합니다.


2. Layer 1


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import tensorflow as tf
import matplotlib.pyplot as plt
import random
from tensorflow.examples.tutorials.mnist import input_data
 
# input, 784개의 값을 가지며 n개의 이미지이다.
= tf.placeholder(tf.float32, [None,784]) 
# input 을 이미지로 인식하기 위해 reshape을 해준다. 28*28의 이미지이며 단일색상, 개수는 n개이므로 -1
X_img = tf.reshape(X, [-1,28,28,1]) 
# output
= tf.placeholder(tf.float32, [None,10]) 
 
# layer 1
# 3*3크기의 필터, 색상은 단일, 총 32개의 필터
W1 = tf.Variable(tf.random_normal([3,3,1,32], stddev=0.1)) 
# conv2d 를 통과해도 28*28 크기를 가짐, 대신 32개의 필터이므로 총 32개의 결과가 생김
L1 = tf.nn.conv2d(X_img, W1, strides=[1,1,1,1], padding='SAME'
L1 = tf.nn.relu(L1)
# max pooling을 하고 나면 스트라이드 및 패딩 설정에 의해 14*14크기의 결과가 나옴
L1 = tf.nn.max_pool(L1, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME'
cs


먼저 첫번째 레이어는 위와 같이 구성합니다.

초기에 mnist 데이터를 받아오는 것은 그동안 몇번 실습을 하며 익숙해지셨을 것입니다. 들어오는 input 데이터를 처리하고, 이를 이미지로 인식시킵니다.


그리고 첫번째 레이어를 확인해보면, strid는 1, padding은 SAME으로 설정하여 convolution layer를 통과시키고, 이후 relu를 통과시킨 후에 max pooling을 합니다. 이렇게 첫번째 레이어를 통과하면 그 결과는 14*14의 형태를 가집니다.



3. Layer 2


1
2
3
4
5
6
7
8
9
10
# layer 2
# 이번에는 64개의 필터
W2 = tf.Variable(tf.random_normal([3,3,32,64], stddev = 0.1))
# conv2d layer를 통과시키면, [?,14,14,64] 형태를 가짐
L2 = tf.nn.conv2d(L1, W2, strides=[1,1,1,1], padding='SAME')
L2 = tf.nn.relu(L2)
# max pooling 에서 stride가 2 이므로, 결과는 7 * 7 형태를 가질 
L2 = tf.nn.max_pool(L2, ksize=[1,2,2,1], strides=[1,2,2,1], padding='SAME')
# 이후 쭉 펼친다.
L2 = tf.reshape(L2, [-1,7 * 7 * 64])
cs


이후 두번째 레이어도 위에서와 동일한 방식으로 처리합니다.

그리고 마지막에서 fully-connected layer에 넣기 위해 reshape을 처리합니다.



4. Fully-connected layer


1
2
3
4
5
6
7
# fully-connected layer
W3 = tf.get_variable("W3", shape=[7 * 7 * 6410],initializer = tf.contrib.layers.xavier_initializer())
= tf.Variable(tf.random_normal([10]))
hypothesis = tf.matmul(L2, W3) + b
 
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=hypothesis, labels=Y))
optimizer = tf.train.AdamOptimizer(learning_rate=0.001).minimize(cost)
cs


그리고 두번째 레이어를 통과한 결과 값을 fully-connected layer에 통과시킵니다.



5. Train & Test


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# init
sess = tf.Session()
sess.run(tf.global_variables_initializer())
mnist = input_data.read_data_sets("~/deep_learning_zeroToAll/", one_hot=True)
training_epochs = 15
batch_size = 100
 
# train
print('Learning started. It takes sometimes.')
for epoch in range(training_epochs):
    avg_cost = 0
    total_batch = int(mnist.train.num_examples / batch_size)
    for i in range(total_batch):
        batch_xs, batch_ys = mnist.train.next_batch(batch_size)
        feed_dict = {X: batch_xs, Y: batch_ys}
        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
correct_prediction = tf.equal(tf.argmax(hypothesis, 1), tf.arg_max(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}))
cs


이후 그동안 했던 것처럼 train을 하고 test를 실시합니다.


이렇게 하여 전체 코드를 실행시켜 결과를 확인하면 다음과 같습니다.



99% 이상은 아니지만 약 99%에 가까운 정확도가 나왔습니다.

그리고 추가적으로 99%이상의 정확도를 갖기 위해서, 우리가 진행했던 구조에서 convolution layer와 fully-connected layer를 하나씩 추가하면 됩니다.

위에서 진행한 전체코드는 하단에 첨부하겠습니다. 추가적으로 layer를 더해보는 것은 각자 해보시면 좋을 것 같습니다, :)


전체 코드 보기



블로그 이미지

Tigercow.Door

Data-Analysis / AI / back-end / Algorithm / DeepLearning / etc


안녕하세요. 문범우입니다.

이번 포스팅에서는 Tensorflow에서 CNN을 다루는 기본적인 내용에 대해서 알아보도록 하겠습니다.


1. CNN


CNN은 이미지 분류나 텍스트 분류 등 다양한 분야에서 굉장히 좋은 성능을 내고 있습니다. 이에 대한 이론적인 내용은 ML&DL 카테고리에서 다루었습니다.

CNN에서는 크게 3가지로 나눠볼 수 있는데, 첫번째로는 입력되는 이미지, 입력되는 벡터와 같은 것을 convoultion을 통해 filter를 사용하는 방법. 그리고 뽑아낸 값에 대해 데이터를 작게 만드는 subsampling 과정. 그리고 이미지나 벡터에서의 특징을 뽑아내는 feature extraction 과정이 있습니다. 그리고 이렇게 뽑아진 특징들은 우리가 이전에 일반적으로 사용했던 일반적인 Neural Network을 이용하여 classification 등을 하게 됩니다.


CNN이 이미지에 큰 기여를 하고 있는데, 그 중 하나의 예가 위와 같은, CT이미지를 분석하는 것 입니다.



CNN은 우리가 이론에서 알아보았던 것처럼 주어진 이미지에 filter를 통해 stride 만큼 움직이면서 각각 하나의 값을 추출합니다. 그리고 이렇게 얻은 값들을 통해 sampling을 진행합니다.

이러한 것들을 우리가 직접 tensorflow로 진행해볼텐데, 처음인 만큼 간단한 이미지를 통해 진행해보도록 하겠습니다.


위와 같이 3x3 이미지에 2x2 filter를 이용하고 이때 stride 는 1x1로 진행합니다.

이러한 과정을 통하면 총 2x2의 데이터가 나올 것 입니다.


2. TensorFlow 실습


그럼 먼저 image를 만들어보도록 하겠습니다.

실습은 jupyter notebook으로 진행합니다.



위와 같이 필요한 라이브러리를 import 하고 이미지를 만들었습니다.

아래에서 출력된 이미지와 함께 비교해보면 높은 값일수록 어두운 색을 내도록 하는 라이브러리를 이용했음을 알 수 있습니다.



위 그림에서 제일 좌측에 있는 입력이미지를 방금 만들었습니다.

그리고 filter는 2x2로 만들것이고 하나의 색상을 가지고, 1개의 필터를 만들 것이기 때문에 Filter: 2,2,1,1 로 표현되었습니다.

그리고 필터의 값이 이미지에서 대응되는 값과 곱해지고 그 합이 출력되는 값에 입력될 것 입니다. 즉 출력되는 2x2 에서 제일 상단 왼쪽의 값은, 1*1+2*1+4*1+5*1 = 12 가 될 것입니다.


이제 이것을 직접 tensorflow에서 구현해보면 아래와 같습니다.



코드의 가운데에서 사용되는 conv2d 함수가 바로 우리가 위에서 계산했던 것들을 손쉽게 해결해주는 함수입니다.

image와 weight를 알맞게 설정하여 strides와 함께 해당 함수에 넣어주면 위에서 볼 수 있는 올바른 결과가 출력되는 것을 볼 수 있습니다.


이때 우리가 padding을 valid로 주었는데, padding 을 same으로 두면 우리의 결과가 입력의 shape과 일치하도록 텐서플로우에서 자동으로 필요한 모서리를 0으로 채우게 됩니다.



즉 우리의 입력이미지에 대해서 padding을 SAME으로 둔다면 위의 왼쪽그림과 같이 0이 채워질 것입니다.


그리고 이를 코드로 구현해본다면,

위와 같이 padding 을 SAME으로 설정해주고 for 문에서 진행하는 reshape을 3,3으로 설정해주면 올바른 결과가 나오는 것을 볼 수 있습니다.


이제 이렇게 우리가 convolution을 진행해보았는데 다음으로는 pooling이라는 작업을 할 수 있습니다.


물론 pooling 또한 convoultion에 대해 이해를 하셨으면 쉽게 진행할 수 있습니다.

우리가 주어지는 입력 이미지에 대해서 filter 사이즈를 정하고, stride와 padding을 정해주면 됩니다.

그리고 많이 사용하는 max_pooling을 사용해볼 것 입니다.

위의 내용을 코드로 구현해보면 아래와 같습니다.


3. MNIST data


이번에는 예전에 다루어보었던 mnist데이터를 다뤄보도록 하겠습니다.


위와 같이 코드를 구현하면 그 결과와 같이 mnist이미지가 나옵니다.

그리고 이를 convolution layer에 통과시킬 수 있습니다.


코드를 대략적으로 살펴보면, 우리의 입력 imgsms 28x28 크기의 한가지 색상을 갖는 이미지이고 n개의 이미지이기 때문에 그 갯수는 정해져 있지 않습니다. 따라서 -1의 값을 주었습니다.

그리고 strides에서는 2x2를 주었는데, 이렇게 되면 출력은 14x14가 될 것입니다.

그리고 아래의 코드는 단지 이미지를 출력하기 위한 코드이니 아직은 대략적으로 넘기시면 됩니다.


그리고 결과에서 볼 수 있듯이 하나의 이미지에서 약간씩 다른 결과 5개를 확인할 수 있습니다.


그리고 이어서 pooling 을 진행해보도록 하겠습니다.



이또한 strides를 2x2로 하였기 때문에 그 크기가 줄어들어 결과에서 7x7로 나타나는 것을 볼 수 있습니다.


블로그 이미지

Tigercow.Door

Data-Analysis / AI / back-end / Algorithm / DeepLearning / etc


안녕하세요. 문범우입니다.

이번 포스팅에서는 우리가 Deep Neural Network 에 대해 이론으로 배웠던 내용들을 실제로 텐서플로우로 구현해보도록 하겠습니다.


우리가 아래 포스팅에서 softmax classifier를 이용하여 mnist 데이터를 예측해보는 모델을 만들어봤었는데, 이때 정확도가 약 83%도 나왔습니다. 이를 DNN으로 구현해보면서 정확도를 최대 98%까지 끌어올려보도록 하겠습니다.


텐서플로우(Tensor Flow) #10_ MNIST DATA



1. MNIST Data 다루기


우리가 MNIST Data에 대해서는 위에서 언급했던 아래 포스팅에서 다루어 보았습니다.

보다 자세한 내용은 해당 글을 참고하시면 되겠습니다.


텐서플로우(Tensor Flow) #10_ MNIST DATA


이때 작성했던 코드를 기본으로 이번 포스팅을 시작할 것이며 그 코드는 아래와 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt
import random
from tensorflow.examples.tutorials.mnist import input_data
 
# read data
mnist = input_data.read_data_sets("/~/deep_learning_zeroToAll/", one_hot=True)
 
nb_classes = 10
 
= tf.placeholder(tf.float32,[None,784])
= tf.placeholder(tf.float32,[None,nb_classes])
 
= tf.Variable(tf.random_normal([784,nb_classes]))
= tf.Variable(tf.random_normal([nb_classes]))
 
hypothesis = tf.nn.softmax(tf.matmul(X, W) + b)
 
cost = tf.reduce_mean(-tf.reduce_sum(Y * tf.log(hypothesis), axis = 1))
optimizer = tf.train.GradientDescentOptimizer(learning_rate = 0.1).minimize(cost)
 
is_correct = tf.equal(tf.arg_max(hypothesis,1), tf.arg_max(Y, 1))
accuracy = tf.reduce_mean(tf.cast(is_correct,tf.float32))
 
training_epochs = 15
batch_size = 100
 
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for epoch in range(training_epochs):
        avg_cost = 0
        total_batch = int(mnist.train.num_examples / batch_size)
 
        for i in range(total_batch):
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            c, _= sess.run([cost,optimizer], feed_dict={X: batch_xs, Y: batch_ys})
            avg_cost += c / total_batch
 
        print('Epoch:''%04d' % (epoch + 1), 'cost = ''{:.9f}'.format(avg_cost))
    print("Learning finished")
    print("Accuracy: ", accuracy.eval(session=sess, feed_dict={X: mnist.test.images, Y: mnist.test.labels}))
 
    # Get one and predict using matplotlib
    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]}))
 
    plt.imshow(
        mnist.test.images[r:r + 1].reshape(2828),
        cmap='Greys',
        interpolation='nearest')
    plt.show()
 
 
cs


( mnist dataset 경로를 알맞게 설정하세요. )

해당코드로 코드를 돌려보면 아래와 같은 결과가 나옵니다.



위의 결과 처럼, 약 84%의 결과를 보이고 있습니다.

이제 하나씩 우리가 배웠던 내용을 추가해보면서 정확도를 올려보도록 하겠습니다.



2. Deep, Wide and ReLU

딥러닝(DeepLearning) #4_ ReLU::Rectified Linear Unit


먼저 우리가 적용해볼 것은 모델을 보다 deep하고, wide하게 layer를 만들면서 sigmoid 함수 대신에 ReLU 함수를 적용시키는 것 입니다.


또한 optimizer 함수를 AdamOptimizer 함수로 바꾸었는데, 이에 대해서는 크게 생각하지 않고, 더 좋은 것이기 때문에 사용한다는 점만 알아두도록 하겠습니다.


따라서 코드를 아래와 같이 수정하였습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import tensorflow as tf
import matplotlib.pyplot as plt
import random
from tensorflow.examples.tutorials.mnist import input_data
 
tf.set_random_seed(777)
# read data
mnist = input_data.read_data_sets("/~/deep_learning_zeroToAll/", one_hot=True)
 
nb_classes = 10
 
= tf.placeholder(tf.float32,[None,784])
= tf.placeholder(tf.float32,[None,nb_classes])
 
# W = tf.Variable(tf.random_normal([784,nb_classes]))
# b = tf.Variable(tf.random_normal([nb_classes]))
 
W1 = tf.Variable(tf.random_normal([784,256]))
b1 = tf.Variable(tf.random_normal([256]))
L1 = tf.nn.relu(tf.matmul(X, W1) + b1)
 
W2 = tf.Variable(tf.random_normal([256,256]))
b2 = tf.Variable(tf.random_normal([256]))
L2 = tf.nn.relu(tf.matmul(L1, W2) + b2)
 
W3 = tf.Variable(tf.random_normal([256,10]))
b3 = tf.Variable(tf.random_normal([10]))
hypothesis = tf.matmul(L2, W3) + b3
 
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits = hypothesis, labels=Y))
optimizer = tf.train.AdamOptimizer(learning_rate = 0.001).minimize(cost)
 
is_correct = tf.equal(tf.arg_max(hypothesis,1), tf.arg_max(Y, 1))
accuracy = tf.reduce_mean(tf.cast(is_correct,tf.float32))
 
training_epochs = 15
batch_size = 100
 
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for epoch in range(training_epochs):
        avg_cost = 0
        total_batch = int(mnist.train.num_examples / batch_size)
 
        for i in range(total_batch):
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            c, _= sess.run([cost,optimizer], feed_dict={X: batch_xs, Y: batch_ys})
            avg_cost += c / total_batch
 
        print('Epoch:''%04d' % (epoch + 1), 'cost = ''{:.9f}'.format(avg_cost))
    print("Learning finished")
    print("Accuracy: ", accuracy.eval(session=sess, feed_dict={X: mnist.test.images, Y: mnist.test.labels}))
 
    # Get one and predict using matplotlib
    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]}))
 
    plt.imshow(
        mnist.test.images[r:r + 1].reshape(2828),
        cmap='Greys',
        interpolation='nearest')
    plt.show()
 
 
cs


이렇게, 3개의 ReLU함수를 적용한 layer로 학습을 진행하니 아래 결과와 같이 약 94%의 정확도를 가지게 되었습니다.




3. Xavier initialize

딥러닝(DeepLearning) #5_ Restricted Belief Machine & Xavier initialize


이번에는 초기값을 건드려 보겠습니다.

Xavier initialize를 이용하여 아래와 같이 코드를 수정하였습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import tensorflow as tf
import matplotlib.pyplot as plt
import random
from tensorflow.examples.tutorials.mnist import input_data
 
tf.set_random_seed(777)
# read data
mnist = input_data.read_data_sets("/~/deep_learning_zeroToAll/", one_hot=True)
 
nb_classes = 10
 
= tf.placeholder(tf.float32,[None,784])
= tf.placeholder(tf.float32,[None,nb_classes])
 
# W = tf.Variable(tf.random_normal([784,nb_classes]))
# b = tf.Variable(tf.random_normal([nb_classes]))
 
W1 = tf.get_variable("W1",shape=[784,256], initializer=tf.contrib.layers.xavier_initializer())
b1 = tf.Variable(tf.random_normal([256]))
L1 = tf.nn.relu(tf.matmul(X, W1) + b1)
 
W2 = tf.get_variable("W2",shape=[256,256], initializer=tf.contrib.layers.xavier_initializer())
b2 = tf.Variable(tf.random_normal([256]))
L2 = tf.nn.relu(tf.matmul(L1, W2) + b2)
 
W3 = tf.get_variable("W3",shape=[256,10], initializer=tf.contrib.layers.xavier_initializer())
b3 = tf.Variable(tf.random_normal([10]))
hypothesis = tf.matmul(L2, W3) + b3
 
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits = hypothesis, labels=Y))
optimizer = tf.train.AdamOptimizer(learning_rate = 0.001).minimize(cost)
 
is_correct = tf.equal(tf.arg_max(hypothesis,1), tf.arg_max(Y, 1))
accuracy = tf.reduce_mean(tf.cast(is_correct,tf.float32))
 
training_epochs = 15
batch_size = 100
 
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for epoch in range(training_epochs):
        avg_cost = 0
        total_batch = int(mnist.train.num_examples / batch_size)
 
        for i in range(total_batch):
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            c, _= sess.run([cost,optimizer], feed_dict={X: batch_xs, Y: batch_ys})
            avg_cost += c / total_batch
 
        print('Epoch:''%04d' % (epoch + 1), 'cost = ''{:.9f}'.format(avg_cost))
    print("Learning finished")
    print("Accuracy: ", accuracy.eval(session=sess, feed_dict={X: mnist.test.images, Y: mnist.test.labels}))
 
    # Get one and predict using matplotlib
    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]}))
 
    plt.imshow(
        mnist.test.images[r:r + 1].reshape(2828),
        cmap='Greys',
        interpolation='nearest')
    plt.show()
 
 
cs


각 레이어의 초기값을 랜덤하게 지정하지 않고, xavier initialize를 이용하여 결과를 확인해보니 아래와 같습니다.



위와 같이 약 97%의 정확도를 보여주고 있습니다.



4. Drop out

딥러닝(DeepLearning) #6_ Dropout and Ensemble


그럼 이번에는 우리의 모델을 더 깊고, 더 넓게 만들어 보겠습니다.

현재까지는 3개의 layer를 가진 모델이었는데 아래코드와 같이, 5단으로 넓히면서 더 wide하게 모델을 만들어봅니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import tensorflow as tf
import matplotlib.pyplot as plt
import random
from tensorflow.examples.tutorials.mnist import input_data
 
tf.set_random_seed(777)
# read data
mnist = input_data.read_data_sets("/~/deep_learning_zeroToAll/", one_hot=True)
 
nb_classes = 10
 
= tf.placeholder(tf.float32,[None,784])
= tf.placeholder(tf.float32,[None,nb_classes])
 
# W = tf.Variable(tf.random_normal([784,nb_classes]))
# b = tf.Variable(tf.random_normal([nb_classes]))
 
W1 = tf.get_variable("W1",shape=[784,512], initializer=tf.contrib.layers.xavier_initializer())
b1 = tf.Variable(tf.random_normal([512]))
L1 = tf.nn.relu(tf.matmul(X, W1) + b1)
 
W2 = tf.get_variable("W2",shape=[512,512], initializer=tf.contrib.layers.xavier_initializer())
b2 = tf.Variable(tf.random_normal([512]))
L2 = tf.nn.relu(tf.matmul(L1, W2) + b2)
 
W3 = tf.get_variable("W3",shape=[512,512], initializer=tf.contrib.layers.xavier_initializer())
b3 = tf.Variable(tf.random_normal([512]))
L3 = tf.nn.relu(tf.matmul(L2, W3) + b3)
 
W4 = tf.get_variable("W4",shape=[512,512], initializer=tf.contrib.layers.xavier_initializer())
b4 = tf.Variable(tf.random_normal([512]))
L4 = tf.nn.relu(tf.matmul(L3, W4) + b4)
 
W5 = tf.get_variable("W5",shape=[512,10], initializer=tf.contrib.layers.xavier_initializer())
b5 = tf.Variable(tf.random_normal([10]))
hypothesis = tf.matmul(L4, W5) + b5
 
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits = hypothesis, labels=Y))
optimizer = tf.train.AdamOptimizer(learning_rate = 0.001).minimize(cost)
 
is_correct = tf.equal(tf.arg_max(hypothesis,1), tf.arg_max(Y, 1))
accuracy = tf.reduce_mean(tf.cast(is_correct,tf.float32))
 
training_epochs = 15
batch_size = 100
 
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for epoch in range(training_epochs):
        avg_cost = 0
        total_batch = int(mnist.train.num_examples / batch_size)
 
        for i in range(total_batch):
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            c, _= sess.run([cost,optimizer], feed_dict={X: batch_xs, Y: batch_ys})
            avg_cost += c / total_batch
 
        print('Epoch:''%04d' % (epoch + 1), 'cost = ''{:.9f}'.format(avg_cost))
    print("Learning finished")
    print("Accuracy: ", accuracy.eval(session=sess, feed_dict={X: mnist.test.images, Y: mnist.test.labels}))
 
    # Get one and predict using matplotlib
    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]}))
 
    plt.imshow(
        mnist.test.images[r:r + 1].reshape(2828),
        cmap='Greys',
        interpolation='nearest')
    plt.show()
 
 
cs


위와 같이, 다른 것들은 모두 그대로 두고 layer를 5개로 확장하면서 보다 wide 하게 만들었습니다.

결과는 어떨까요?



미세하지만, 오히려 이전보다 정확도가 떨어졌습니다.

보다 더 깊고, 넓게 모델을 만들었는데, 왜그럴까요?

바로 우리가 배웠던 overfitting 때문입니다.

이를 해결하기 위해서 우리는 dropout 이라는 것을 배웠고, 바로 코드에 적용시켜보도록 하겠습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
import tensorflow as tf
import matplotlib.pyplot as plt
import random
from tensorflow.examples.tutorials.mnist import input_data
 
tf.set_random_seed(777)
# read data
mnist = input_data.read_data_sets("/~/deep_learning_zeroToAll/", one_hot=True)
 
nb_classes = 10
keep_prob = tf.placeholder(tf.float32)
 
= tf.placeholder(tf.float32,[None,784])
= tf.placeholder(tf.float32,[None,nb_classes])
 
# W = tf.Variable(tf.random_normal([784,nb_classes]))
# b = tf.Variable(tf.random_normal([nb_classes]))
 
W1 = tf.get_variable("W1",shape=[784,512], initializer=tf.contrib.layers.xavier_initializer())
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=[512,512], initializer=tf.contrib.layers.xavier_initializer())
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=[512,512], initializer=tf.contrib.layers.xavier_initializer())
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=[512,512], initializer=tf.contrib.layers.xavier_initializer())
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=[512,10], initializer=tf.contrib.layers.xavier_initializer())
b5 = tf.Variable(tf.random_normal([10]))
hypothesis = tf.matmul(L4, W5) + b5
 
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits = hypothesis, labels=Y))
optimizer = tf.train.AdamOptimizer(learning_rate = 0.001).minimize(cost)
 
is_correct = tf.equal(tf.arg_max(hypothesis,1), tf.arg_max(Y, 1))
accuracy = tf.reduce_mean(tf.cast(is_correct,tf.float32))
 
training_epochs = 15
batch_size = 100
 
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for epoch in range(training_epochs):
        avg_cost = 0
        total_batch = int(mnist.train.num_examples / batch_size)
 
        for i in range(total_batch):
            batch_xs, batch_ys = mnist.train.next_batch(batch_size)
            c, _= sess.run([cost,optimizer], feed_dict={X: batch_xs, Y: batch_ys, keep_prob: 0.7})
            avg_cost += c / total_batch
 
        print('Epoch:''%04d' % (epoch + 1), 'cost = ''{:.9f}'.format(avg_cost))
    print("Learning finished")
    print("Accuracy: ", accuracy.eval(session=sess, feed_dict={X: mnist.test.images, Y: mnist.test.labels, keep_prob: 1}))
 
    # Get one and predict using matplotlib
    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_prob: 1}))
 
    plt.imshow(
        mnist.test.images[r:r + 1].reshape(2828),
        cmap='Greys',
        interpolation='nearest')
    plt.show()
 
 
cs


위와 같이 keep_prob 라는 변수를 새로 만들어서, 각 레이어마다 dropout 함수를 적용시키고 이때 keep_prob 값을 변수값으로 넣었습니다.

이후 훈련할때 keep_prob 값을 feed_dict에서 0.7로 주었으며 실제로 예측할때는 1값을 주었습니다.


이를 통해 나오는 결과는 아래와 같습니다.



위의 결과를 확인하면 정확도가 98%를 넘기는 것을 확인할 수 있습니다.


이렇게 우리가 그동안 배웠던 개념들을 실제로 텐서플로우에서 구현해보고, 그것들이 얼마나 정확도를 높여주는지 확인해보았습니다.

블로그 이미지

Tigercow.Door

Data-Analysis / AI / back-end / Algorithm / DeepLearning / etc


안녕하세요. 문범우입니다.

우리가 지난번 실습에서 텐서플로우를 통해 Neural Network를 이용하여 XOR 문제를 풀어보았습니다.

그런데 우리가 Neural Network를 이용하면서 보다 깊고 복잡한 문제를 해결할 때 그 학습과정등을 시각적으로 볼 수 있도록 하는 Tensorboard라는 것이 있습니다.

이번 포스팅에서는 그런 Tensorboard를 사용하는 방법에 대해서 알아보도록 하겠습니다.


1. Tensorboard


우선 텐서보드를 사용하면 위의 그림에서 보이는 것처럼 우리의 TensorFlow 그래프를 시각적으로 볼 수 있습니다.


그리고 cost에 관한 것도 그래프로 확인하면서 훈련이 잘 되고 있는지도 쉽게 확인할 수 있습니다.



텐서보드를 이용하기 위해서는 위와 같은 간단한 5가지 순서를 따라하면 됩니다.

실제로 지난 시간에 풀어본 XOR문제의 코드를 바탕으로 텐서보드를 사용해보도록 하겠습니다.



2. histogram & name_scope


먼저, 초기의 코드는 아래와 같습니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import tensorflow as tf
import numpy as np
 
x_data = np.array([[0,0], [0,1], [1,0], [1,1]], dtype=np.float32)
y_data = np.array([[0],   [1],   [1],   [0]], dtype=np.float32)
 
= tf.placeholder(tf.float32)
= tf.placeholder(tf.float32)
 
# W = tf.Variable(tf.random_normal([2,1]), name = "weight")
# b = tf.Variable(tf.random_normal([1]), name = "bias")
# hypothesis = tf.sigmoid(tf.matmul(X, W) + b)
 
W1 = tf.Variable(tf.random_normal([2,10]), name="weight1")
b1 = tf.Variable(tf.random_normal([10]), name="bias1")
layer1 = tf.sigmoid(tf.matmul(X, W1) + b1)
 
W2 = tf.Variable(tf.random_normal([10,1]), name="weight2")
b2 = tf.Variable(tf.random_normal([1]), name="bias2")
hypothesis = tf.sigmoid(tf.matmul(layer1, W2) + b2)
 
 
# cost function / minimize cost
cost = -tf.reduce_mean(Y * tf.log(hypothesis) + (1 - Y) * tf.log(1 - hypothesis))
train = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)
 
# predicate / accuracy
predicated = tf.cast(hypothesis > 0.5, dtype=tf.float32)
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicated, Y), dtype=tf.float32))
 
#
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for step in range(10001):
        sess.run(train, feed_dict={X: x_data, Y: y_data})
        if step%1000 == 0:
            print(step, sess.run(cost, feed_dict={X: x_data, Y: y_data}), sess.run([W1, W2]))
    h, c, a = sess.run([hypothesis, predicated, accuracy], feed_dict={X: x_data, Y: y_data})
    print("\nHypothesis: ",h,"\nCorrect: ",c,"\nAccuracy: ",a)
 
cs


이제 첫번째로 해야하는 것은, 우리가 그래프를 보기 위해 histogram을 이용하는 것과, 모델을 계층적으로 확인하기 위해 name_scope를 이용하는 것입니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import tensorflow as tf
import numpy as np
 
x_data = np.array([[0,0], [0,1], [1,0], [1,1]], dtype=np.float32)
y_data = np.array([[0],   [1],   [1],   [0]], dtype=np.float32)
 
= tf.placeholder(tf.float32)
= tf.placeholder(tf.float32)
 
# W = tf.Variable(tf.random_normal([2,1]), name = "weight")
# b = tf.Variable(tf.random_normal([1]), name = "bias")
# hypothesis = tf.sigmoid(tf.matmul(X, W) + b)
 
# name_scope 를 이용하여 계층별로 정리한다.
with tf.name_scope('layer1') as scope:
    W1 = tf.Variable(tf.random_normal([2,10]), name="weight1")
    b1 = tf.Variable(tf.random_normal([10]), name="bias1")
    layer1 = tf.sigmoid(tf.matmul(X, W1) + b1)
    # histogram을 이용하여 그래프를 확인할 수 있다.
    w1_hist = tf.summary.histogram('weight1',W1)
    b1_hist = tf.summary.histogram('bias1',b1)
    layer1_hist = tf.summary.histogram('layer1',layer1)
 
with tf.name_scope('layer2') as scope:
    W2 = tf.Variable(tf.random_normal([10,1]), name="weight2")
    b2 = tf.Variable(tf.random_normal([1]), name="bias2")
    hypothesis = tf.sigmoid(tf.matmul(layer1, W2) + b2)
 
    w2_hist = tf.summary.histogram('weight2', W2)
    b2_hist = tf.summary.histogram('bias2', b2)
    hypothesis_hist = tf.summary.histogram('hypothesis',hypothesis)
 
# cost function / minimize cost
with tf.name_scope('cost') as scope:
    cost = -tf.reduce_mean(Y * tf.log(hypothesis) + (1 - Y) * tf.log(1 - hypothesis))
    cost_summ = tf.summary.scalar('cost',cost)
 
train = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)
 
 
# predicate / accuracy
predicated = tf.cast(hypothesis > 0.5, dtype=tf.float32)
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicated, Y), dtype=tf.float32))
 
with tf.Session() as sess:
    # writer logs and show graph
    merged_summary = tf.summary.merge_all()
    writer = tf.summary.FileWriter('./logs/xor_logs_01')
    writer.add_graph(sess.graph)
 
    sess.run(tf.global_variables_initializer())
    for step in range(10001):
        sess.run(train, feed_dict={X: x_data, Y: y_data})
        if step%1000 == 0:
            # summary 실행
            summary, _ = sess.run([merged_summary, train], feed_dict={X: x_data, Y: y_data})
            writer.add_summary(summary, global_step=step)
 
            print(step, sess.run(cost, feed_dict={X: x_data, Y: y_data}), sess.run([W1, W2]))
    h, c, a = sess.run([hypothesis, predicated, accuracy], feed_dict={X: x_data, Y: y_data})
    print("\nHypothesis: ",h,"\nCorrect: ",c,"\nAccuracy: ",a)
 
cs


코드를 확인해보면, 14~36번줄에 name_scope를 이용하여 계층별로 묶어주고, 각각에서 histogram을 이용한 것을 확인할 수 있습니다.



3. add logs & show graph


이제 우리가 훈련시키는 모델에 대한 로그를 작성하고 그것을 그래프로 보여주도록 하는 코드를 작성합니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import tensorflow as tf
import numpy as np
 
x_data = np.array([[0,0], [0,1], [1,0], [1,1]], dtype=np.float32)
y_data = np.array([[0],   [1],   [1],   [0]], dtype=np.float32)
 
= tf.placeholder(tf.float32)
= tf.placeholder(tf.float32)
 
# W = tf.Variable(tf.random_normal([2,1]), name = "weight")
# b = tf.Variable(tf.random_normal([1]), name = "bias")
# hypothesis = tf.sigmoid(tf.matmul(X, W) + b)
 
# name_scope 를 이용하여 계층별로 정리한다.
with tf.name_scope('layer1') as scope:
    W1 = tf.Variable(tf.random_normal([2,10]), name="weight1")
    b1 = tf.Variable(tf.random_normal([10]), name="bias1")
    layer1 = tf.sigmoid(tf.matmul(X, W1) + b1)
    # histogram을 이용하여 그래프를 확인할 수 있다.
    w1_hist = tf.summary.histogram('weight1',W1)
    b1_hist = tf.summary.histogram('bias1',b1)
    layer1_hist = tf.summary.histogram('layer1',layer1)
 
with tf.name_scope('layer2') as scope:
    W2 = tf.Variable(tf.random_normal([10,1]), name="weight2")
    b2 = tf.Variable(tf.random_normal([1]), name="bias2")
    hypothesis = tf.sigmoid(tf.matmul(layer1, W2) + b2)
 
    w2_hist = tf.summary.histogram('weight2', W2)
    b2_hist = tf.summary.histogram('bias2', b2)
    hypothesis_hist = tf.summary.histogram('hypothesis',hypothesis)
 
# cost function / minimize cost
cost = -tf.reduce_mean(Y * tf.log(hypothesis) + (1 - Y) * tf.log(1 - hypothesis))
train = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(cost)
 
# predicate / accuracy
predicated = tf.cast(hypothesis > 0.5, dtype=tf.float32)
accuracy = tf.reduce_mean(tf.cast(tf.equal(predicated, Y), dtype=tf.float32))
 
with tf.Session() as sess:
    # writer logs and show graph
    merged_summary = tf.summary.merge_all()
    writer = tf.summary.FileWriter('./logs/xor_logs_01')
    writer.add_graph(sess.graph)
 
    sess.run(tf.global_variables_initializer())
    for step in range(10001):
        sess.run(train, feed_dict={X: x_data, Y: y_data})
        if step%1000 == 0:
            print(step, sess.run(cost, feed_dict={X: x_data, Y: y_data}), sess.run([W1, W2]))
    h, c, a = sess.run([hypothesis, predicated, accuracy], feed_dict={X: x_data, Y: y_data})
    print("\nHypothesis: ",h,"\nCorrect: ",c,"\nAccuracy: ",a)
 
cs


위 코드의 43~45번 줄에 추가된 코드를 통해 로그를 작성하고, 그래프를 추가합니다.


그리고 각 step에서 세션을 실행시키고 우리가 그리고자 하는 그래프에 그 결과를 더해줍니다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33