본문 바로가기
ML & DL/tensorflow

감성분류 on IMDB datasets (2)

by 별준 2020. 12. 24.

(tensorflow v2.4.0)

 

2020/12/24 - [ML & DL/tensorflow] - 감성분류 on IMDB datasets (1)

 

감성분류 on IMDB datasets (1)

(tensorflow v2.4.0) IMDB dataset을 사용해서 감성분류를 해보도록 하겠습니다. IMDB dataset은 영화 리뷰 데이터이며, 구현해볼 것은 해당 리뷰가 긍정적인 리뷰인지 부정적인 리뷰인지 분류하는 것입니다

junstar92.tistory.com

이전 게시글에 이어서 이번에는 IMDB 분류 문제를 RNN layer를 사용해서 수행해보도록 하겠습니다.

import tensorflow as tf
import tensorflow.keras as keras
import tensorflow.keras.layers as layers
import tensorflow.keras.models as models

import numpy as np
import matplotlib.pyplot as plt

데이터부터 다시 읽어와서 시작해보도록 하겠습니다.

max_features = 10000
maxlen = 500
batch_size = 128

(x_train, y_train), (x_test, y_test) = keras.datasets.imdb.load_data(num_words=max_features)
print(len(x_train), '훈련 시퀀스')
print(len(x_test), '테스트 시퀀스')

print('시퀀스 패딩 (samples x time)')
x_train = keras.preprocessing.sequence.pad_sequences(x_train, maxlen=maxlen, padding='post')
x_test = keras.preprocessing.sequence.pad_sequences(x_test, maxlen=maxlen, padding='post')
print('x_train 크기:', x_train.shape)
print('x_test 크기:', x_test.shape)

사용되는 단어는 10000개, 시퀀스의 최대 길이는 500으로 설정했습니다.

1. SimpleRNN layer 사용

model = models.Sequential(
    [layers.Embedding(max_features, 100),
     layers.SimpleRNN(32),
     layers.Dense(1, activation='sigmoid')]
)

model.compile(optimizer='adam', loss='binary_crossentropy', metrics='acc')
model.summary()

history = model.fit(x_train, y_train,
                    epochs=10,
                    batch_size=batch_size,
                    validation_split=0.2)

plt.figure(figsize=(12, 4))
plt.subplot(121)
plt.plot(history.history['loss'], 'r-', label='train loss')
plt.plot(history.history['val_loss'], 'r--', label='valid loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.subplot(122)
plt.plot(history.history['acc'], 'r-', label='train acc')
plt.plot(history.history['val_acc'], 'r--', label='valid acc')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

학습이 시작되자마자 과적합되는 모습을 보여주고 있습니다. training data의 정확도는 100%이고, validation data의 정확도는 83%입니다. 이전 게시글에서 학습한 기본 Dense layer보다 낮은 정확도를 보여주고 있습니다.

Dense layer로 구성된 기존 모델은 각 batch data의 전체 시퀀스를 입력으로 받고 있지만, 이 모델에서는 500으로 길이가 제한되어 있기 때문에 Dense model보다 더 적은 정보를 가지고 학습하고 있기 때문에 더 낮은 모습을 보이는 것으로 추측됩니다. 

또한 SimpleRNN은 긴 시퀀스를 처리하기에 적합하지 않습니다.

 

아래는 test data의 평가 결과입니다.

model.evaluate(x_test, y_test)

 

2. LSTM layer 사용

model = models.Sequential(
    [layers.Embedding(max_features, 100),
     layers.LSTM(32),
     layers.Dense(1, activation='sigmoid')]
)

model.compile(optimizer='adam', loss='binary_crossentropy', metrics='acc')
model.summary()

history = model.fit(x_train, y_train,
                    epochs=10,
                    batch_size=batch_size,
                    validation_split=0.2)

plt.figure(figsize=(12, 4))
plt.subplot(121)
plt.plot(history.history['loss'], 'r-', label='train loss')
plt.plot(history.history['val_loss'], 'r--', label='valid loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.subplot(122)
plt.plot(history.history['acc'], 'r-', label='train acc')
plt.plot(history.history['val_acc'], 'r--', label='valid acc')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

LSTM을 사용했을 때에는 기존 Dense 모델과 유사한 validation data의 정확도를 보여주고 있습니다. SimpleRNN과 큰 차이는 없지만 그래도 조금 더 나은 모습을 보여주고 있습니다. 

하지만, 획기적인 결과를 보여주고 있지는 않는데, 이는 임베딩 차원이나 LSTM output dimension의 하이퍼파라미터 튜닝과 regularization을 전혀 적용하지 않았기 때문으로 추측됩니다.

model.evaluate(x_test, y_test)

 

3. GRU layer 사용

마지막으로 GRU layer를 사용해서 학습해보도록 하겠습니다.

model = models.Sequential(
    [layers.Embedding(max_features, 100),
     layers.GRU(32),
     layers.Dense(1, activation='sigmoid')]
)

model.compile(optimizer='adam', loss='binary_crossentropy', metrics='acc')
model.summary()

history = model.fit(x_train, y_train,
                    epochs=10,
                    batch_size=batch_size,
                    validation_split=0.2)

plt.figure(figsize=(12, 4))
plt.subplot(121)
plt.plot(history.history['loss'], 'r-', label='train loss')
plt.plot(history.history['val_loss'], 'r--', label='valid loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.subplot(122)
plt.plot(history.history['acc'], 'r-', label='train acc')
plt.plot(history.history['val_acc'], 'r--', label='valid acc')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()

model.evaluate(x_test, y_test)

LSTM layer를 사용한 모델과 큰 차이가 없는 것을 볼 수 있습니다.

 

 

결론

RNN layer를 사용해서 리뷰를 단순히 전체적으로 길게 분석하는 것은 감성 분류 문제에 도움이 별로 되지 않는 것으로 보입니다. 

이는 학습 데이터의 순서를 뒤집어서 학습시켜보면 확실하게 확인할 수 있습니다.

(x_train, y_train), (x_test, y_test) = keras.datasets.imdb.load_data(num_words=max_features)

x_train = [x[::-1] for x in x_train]
x_test = [x[::-1] for x in x_test]

x_train = keras.preprocessing.sequence.pad_sequences(x_train, maxlen=maxlen, padding='post')
x_test = keras.preprocessing.sequence.pad_sequences(x_test, maxlen=maxlen, padding='post')

model = models.Sequential(
    [layers.Embedding(max_features, 100),
     layers.LSTM(32),
     layers.Dense(1, activation='sigmoid')]
)

model.compile(optimizer='adam', loss='binary_crossentropy', metrics='acc')
model.summary()

history = model.fit(x_train, y_train,
                    epochs=10,
                    batch_size=batch_size,
                    validation_split=0.2)
model.evaluate(x_test, y_test)

시퀀스를 거꾸로 해도 학습결과는 원래 데이터와 큰 차이가 없는 것을 볼 수 있습니다.

 

댓글