1986년에 공개된 로이터(Reuter) 데이터셋은 짧은 뉴스 기사와 토픽의 집합으로 이루어져 있다. 알다시피 뉴스 기사는 텍스트 데이터이며, 단어 순서가 유지되어야 하는 시퀀스 데이터다. 총 46개의 토픽이 있으며, 각 토픽마다 기사 데이터 수가 일정하지는 않다.
1. 데이터 준비하기
from keras.datasets import reuters
(train_data, train_labels), (test_data, test_labels) = reuters.load_data(num_words=10000)
로이터 데이터셋도 IMDB 데이터셋과 마찬가지로 Keras에 포함되어 있으며, 같은 형태를 취하고 있다. 학습 데이터는 정의된 단어 사전 내 해당 단어의 인덱스를 저장한 리스트 형태다.
ximport numpy as np
from keras.utils.np_utils import to_categorical
def vectorize_sequences(sequences, dimension=10000):
results = np.zeros((len(sequences), dimension))
for i, sequence in enumerate(sequences):
results[i, sequence] = 1.
return results
x_train = vectorize_sequences(train_data)
x_test = vectorize_sequences(test_data)
one_hot_train_labels = to_categorical(train_labels)
one_hot_test_labels = to_categorical(test_labels)
딥러닝 모델에 주입하기 위해 원-핫 인코딩을 통해 리스트를 벡터로 변환하였다.
2. 모델 구성하기
xxxxxxxxxx
from keras import models
from keras import layers
model = models.Sequential()
model.add(layers.Dense(64, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(64, activation='relu'))
model.add(layers.Dense(46, activation='softmax'))
10000차원 텐서를 주입하기 때문에 input_shape를 (10000,)으로 설정해놓는다. 만약 데이터셋의 형태가 (samples, d1, d2, ...) 이라면 samples를 제외한 (d1, d2, ...)를 input_shape로 설정하면 된다. 활성화(activation) 함수는 relu를 사용하고 46개의 토픽으로 다중 분류하는 것이므로 softmax를 마지막 활성화 함수로 설정하고 output은 46으로 설정한다. 그러면 softmax의 46개 output 중 가장 큰 값이 예측 값이 되게 된다.
여기서 중요한 점은 최종 출력이 46으로 크기 때문에 앞의 layer의 출력 크기는 그보다 충분히 커야 한다. 이미지를 예로 들어보자. 512x512 이미지를 256x256 크기로 reduction하고나서 다시 512x512로 회복하면 정상적으로는 보이겠지만 값은 약간 손실된다. 마찬가지로, layer의 출력이 작게 하면 그만큼 데이터의 특징이 손실되어 제대로 된 결과를 얻을 수 없을지도 모른다. 이러한 현상을 정보 병목이라고도 한다.
실제로 하나의 hiddle layer의 출력 크기를 32로 했을 때 테스트 데이터에 대한 정확도는 77.2%, 64로 했을 때는 77.8%, 128로 늘렸을 때는 79.6%가 나왔다.
3. 모델 컴파일하기
xxxxxxxxxx
model.compile(optimizer='rmsprop', loss='categorical_crossentropy', metrics=['accuracy'])
모델을 구성을 마쳤으면, 딥러닝 시 사용될 함수들을 지정해주어야 한다. 여기선 optimizer는 RMSprop, loss 함수는 categorical cross entropy 함수를 사용했다. 세부적으로 하이퍼파라미터를 정하기 위해 인수로 다음과 같이 함수를 전달할 수도 있다.
xxxxxxxxxx
model.compile(optimizer=optimizers.rmsprop(lr=0.001), loss=losses.categorical_crossentropy, metrics=['accuracy'])
4. 모델 훈련하기
xxxxxxxxxx
x_val = x_train[:1000]
partial_x_train = x_train[1000:]
y_val = one_hot_train_labels[:1000]
partial_y_train = one_hot_train_labels[1000:]
훈련하기에 앞서 앞쪽에 있는 1000개의 데이터를 검증 데이터로 분리한다. 그런 다음 하이퍼파라메터를 결정하여 훈련시킨다.
xxxxxxxxxx
history = model.fit(partial_x_train, partial_y_train, epochs=20, batch_size=512, validation_data=(x_val, y_val))
xxxxxxxxxx
Train on 7982 samples, validate on 1000 samples
...
Epoch 11/20
7982/7982 [==============================] - 1s 165us/step - loss: 0.1780 - acc: 0.9453 - val_loss: 1.1492 - val_acc: 0.8040
Epoch 12/20
7982/7982 [==============================] - 1s 163us/step - loss: 0.1028 - acc: 0.9569 - val_loss: 1.3348 - val_acc: 0.7950
Epoch 13/20
7982/7982 [==============================] - 1s 167us/step - loss: 0.0987 - acc: 0.9587 - val_loss: 1.3358 - val_acc: 0.7940
Epoch 14/20
7982/7982 [==============================] - 1s 168us/step - loss: 0.1068 - acc: 0.9570 - val_loss: 1.3650 - val_acc: 0.8060
Epoch 15/20
7982/7982 [==============================] - 1s 163us/step - loss: 0.1163 - acc: 0.9575 - val_loss: 1.3171 - val_acc: 0.8060
Epoch 16/20
7982/7982 [==============================] - 1s 165us/step - loss: 0.1326 - acc: 0.9494 - val_loss: 1.7539 - val_acc: 0.7490
Epoch 17/20
7982/7982 [==============================] - 1s 170us/step - loss: 0.0984 - acc: 0.9558 - val_loss: 1.3958 - val_acc: 0.7840
Epoch 18/20
7982/7982 [==============================] - 1s 165us/step - loss: 0.0856 - acc: 0.9589 - val_loss: 1.4494 - val_acc: 0.7930
Epoch 19/20
7982/7982 [==============================] - 1s 159us/step - loss: 0.0843 - acc: 0.9588 - val_loss: 1.4449 - val_acc: 0.7950
Epoch 20/20
7982/7982 [==============================] - 1s 162us/step - loss: 0.0855 - acc: 0.9610 - val_loss: 1.5704 - val_acc: 0.7890
5. 모델 평가하기
이제 학습된 모델로 테스트 데이터를 평가한다.
xxxxxxxxxx
model.evaluate(x_test, one_hot_test_labels)
xxxxxxxxxx
2246/2246 [==============================] - 0s 179us/step
[1.8362030299348908, 0.7769367765180787]
훈련데이터에 대한 정확도는 약 96.1%, 검증 데이터에 대한 정확도는 약 78.9%, 테스트 데이터에 대한 정확도는 77.6%가 나왔다. 분명 훈련 데이터에 대한 정확도는 높은데 다른 데이터에 대해서는 정확도가 높지 못 하다. 그 이유는 바로 학습 모델이 훈련 데이터에 overfitting(과적합) 되었기 때문이다. 이를 해결하기 위해선 하이퍼파라미터를 조정하거나 다른 여러 방법들이 필요하다. 여기선 순수하게 하이퍼파라미터를 조정해서 정확도를 높여보자.
6. 하이퍼 파라미터 수정
먼저, optimizer를 바꿔보자. Adam 함수는 흔하게 쓰이며 좋은 결과를 내는 최적화 함수 중 하나다.
결과
xxxxxxxxxx
train acc : 96.3%, val acc : 80.0%, test acc : 78.4%
다음으로, input layer와 hidden layer 출력 수를 128로 설정하고, 과적합을 피하기 위해 epoch을 10으로 설정해보자.
결과
xxxxxxxxxx
train acc: 95.9%, val acc : 80.2%, test acc : 79.4%
이런식으로 사용한 함수, 레이어 수를 바꿔보거나 하이퍼파라미터를 조정하여 정확도를 높일 수 있다. 하지만 과적합을 피해서 정확도를 높이기에는 한계가 있다. 이를 위해 dropout과 같은 기법이 요구된다.
7. 훈련 결과 그래프 그리기
훈련이 잘 되었는지 수치 상으로도 확인할 수 있지만 epoch 수가 많아지면 그런 식으로 확인하는 건 힘들어지게 된다. 그래서 matplotlib를 이용해 그래프를 그려 한 눈에 학습 과정을 보는 것이 좋다.
xxxxxxxxxx
import matplotlib.pyplot as plt
loss = history.history['loss']
val_loss = history.history['val_loss']
acc = history.history['acc']
val_acc = history.history['val_acc']
epochs = range(1, len(loss) + 1)
plt.plot(epochs, acc, 'ro', label='Training acc')
plt.plot(epochs, val_acc, 'bo', label='Validation acc')
plt.plot(epochs, loss, 'r', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
Training loss를 보면 훈련 데이터에 대해서는 잘 학습되고 있다는 것을 알 수 있지만, Validation loss를 보면 검증 데이터에 대해서는 2 epoch 이후에는 거의 학습이 안 되는 것을 볼 수 있다.
'A·I' 카테고리의 다른 글
[keras] Boston Housing 데이터를 통한 주택 가격 예측(regression) (0) | 2019.01.05 |
---|---|
[keras] 정확한 평가를 위한 검증(validation) 데이터 나누기 (0) | 2019.01.05 |
[keras] tensorflow-gpu ImportError 해결 및 keras 간단 설치 (0) | 2019.01.04 |
딥러닝, 머신러닝, 패턴인식 뭐가 다를까? (0) | 2018.12.26 |
[Keras] 영화 리뷰 데이터로 알아보는 시퀀스 데이터 (0) | 2018.12.26 |
댓글