이 노트북에서 RNN을 사용해 감성에 따라 IMDB 영화 리뷰를 분류합니다.
from tensorflow import keras
from tensorflow.keras.datasets import imdb
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Embedding, SpatialDropout1D
from tensorflow.keras.layers import SimpleRNN # new!
from tensorflow.keras.callbacks import ModelCheckpoint
import os
from sklearn.metrics import roc_auc_score
import matplotlib.pyplot as plt
%matplotlib inline
# 출력 디렉토리
output_dir = 'model_output/rnn'
# 훈련
epochs = 16 # 더 많이!
batch_size = 128
# 벡터 공간 임베딩
n_dim = 64
n_unique_words = 10000
max_review_length = 100 # 시간에 따른 그레이디언트 소실 때문에 낮춤
pad_type = trunc_type = 'pre'
drop_embed = 0.2
# RNN 층 구조
n_rnn = 256
drop_rnn = 0.2
# 밀집 층 구조
# n_dense = 256
# dropout = 0.2
(x_train, y_train), (x_valid, y_valid) = imdb.load_data(num_words=n_unique_words) # n_words_to_skip 삭제
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb.npz 17464789/17464789 [==============================] - 1s 0us/step
x_train = pad_sequences(x_train, maxlen=max_review_length, padding=pad_type, truncating=trunc_type, value=0)
x_valid = pad_sequences(x_valid, maxlen=max_review_length, padding=pad_type, truncating=trunc_type, value=0)
model = Sequential()
model.add(Embedding(n_unique_words, n_dim, input_length=max_review_length))
model.add(SpatialDropout1D(drop_embed))
model.add(SimpleRNN(n_rnn, dropout=drop_rnn))
# model.add(Dense(n_dense, activation='relu')) # 일반적으로 NLP에서는 밀집 층을 위에 놓지 않습니다.
# model.add(Dropout(dropout))
model.add(Dense(1, activation='sigmoid'))
model.summary()
Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= embedding (Embedding) (None, 100, 64) 640000 spatial_dropout1d (SpatialD (None, 100, 64) 0 ropout1D) simple_rnn (SimpleRNN) (None, 256) 82176 dense (Dense) (None, 1) 257 ================================================================= Total params: 722,433 Trainable params: 722,433 Non-trainable params: 0 _________________________________________________________________
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
modelcheckpoint = ModelCheckpoint(filepath=output_dir+"/weights.{epoch:02d}.hdf5")
if not os.path.exists(output_dir):
os.makedirs(output_dir)
model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_valid, y_valid), callbacks=[modelcheckpoint])
Epoch 1/16 196/196 [==============================] - 32s 145ms/step - loss: 0.7060 - accuracy: 0.5008 - val_loss: 0.6956 - val_accuracy: 0.5116 Epoch 2/16 196/196 [==============================] - 30s 151ms/step - loss: 0.6901 - accuracy: 0.5316 - val_loss: 0.6784 - val_accuracy: 0.5811 Epoch 3/16 196/196 [==============================] - 29s 147ms/step - loss: 0.6686 - accuracy: 0.5772 - val_loss: 0.6505 - val_accuracy: 0.6022 Epoch 4/16 196/196 [==============================] - 28s 142ms/step - loss: 0.5806 - accuracy: 0.6909 - val_loss: 0.5614 - val_accuracy: 0.7136 Epoch 5/16 196/196 [==============================] - 28s 141ms/step - loss: 0.5432 - accuracy: 0.7330 - val_loss: 0.6053 - val_accuracy: 0.6990 Epoch 6/16 196/196 [==============================] - 28s 142ms/step - loss: 0.4877 - accuracy: 0.7744 - val_loss: 0.6213 - val_accuracy: 0.6602 Epoch 7/16 196/196 [==============================] - 28s 141ms/step - loss: 0.6153 - accuracy: 0.6772 - val_loss: 0.6432 - val_accuracy: 0.6290 Epoch 8/16 196/196 [==============================] - 28s 142ms/step - loss: 0.5928 - accuracy: 0.7010 - val_loss: 0.5688 - val_accuracy: 0.7085 Epoch 9/16 196/196 [==============================] - 29s 150ms/step - loss: 0.5478 - accuracy: 0.7166 - val_loss: 0.6301 - val_accuracy: 0.6164 Epoch 10/16 196/196 [==============================] - 28s 142ms/step - loss: 0.4784 - accuracy: 0.7787 - val_loss: 0.5283 - val_accuracy: 0.7663 Epoch 11/16 196/196 [==============================] - 28s 144ms/step - loss: 0.5241 - accuracy: 0.7458 - val_loss: 0.8046 - val_accuracy: 0.6140 Epoch 12/16 196/196 [==============================] - 28s 144ms/step - loss: 0.4789 - accuracy: 0.7847 - val_loss: 0.6048 - val_accuracy: 0.7252 Epoch 13/16 196/196 [==============================] - 28s 143ms/step - loss: 0.4990 - accuracy: 0.7623 - val_loss: 0.5962 - val_accuracy: 0.7204 Epoch 14/16 196/196 [==============================] - 28s 143ms/step - loss: 0.4153 - accuracy: 0.8120 - val_loss: 0.5443 - val_accuracy: 0.7659 Epoch 15/16 196/196 [==============================] - 28s 144ms/step - loss: 0.4223 - accuracy: 0.8146 - val_loss: 0.5668 - val_accuracy: 0.7026 Epoch 16/16 196/196 [==============================] - 28s 141ms/step - loss: 0.5206 - accuracy: 0.7359 - val_loss: 0.7328 - val_accuracy: 0.6922
<keras.callbacks.History at 0x7f4ae3f73040>
model.load_weights(output_dir+"/weights.07.hdf5")
y_hat = model.predict(x_valid)
782/782 [==============================] - 8s 11ms/step
plt.hist(y_hat)
_ = plt.axvline(x=0.5, color='orange')
"{:0.2f}".format(roc_auc_score(y_valid, y_hat)*100.0)
'69.33'