주뇽's 저장소
LSTM (Long Short-Term Memory) 본문
LSTM은 RNN의 단점 중 하나인 장기 의존성 문제를 해결하기 위해 제안된 변형된 RNN 구조이다. LSTM은 시간적인 의존성을 잘 다룰 수 있도록 설계되었다. LSTM은 게이트를 이용하여 특정 시간 단계에서 중요한 정보를 기억하고, 필요에 따라 이를 장기적으로 전달하거나 삭제할 수 있다.
- 특징: 장기 의존성을 다루기 위한 메모리 셀, 입력 게이트, 삭제 게이트, 출력 게이트 등의 구조
- 장점: 장기 의존성 문제를 해결, 시계열 데이터 처리에 적합
- 단점: 많은 파라미터와 연산이 필요하여 학습과정이 복잡함, 계산량이 크고 처리 속도가 상대적으로 느릴 수 있음
LSTM을 이용하여 IMDB 영화 리뷰 감성 분석
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import imdb
(X_train, y_train), (X_test, y_test) = imdb.load_data()
print('훈련용 리뷰 개수 : {}'.format(len(X_train)))
print('테스트용 리뷰 개수 : {}'.format(len(X_test)))
num_classes = len(set(y_train))
print('카테고리 : {}'.format(num_classes))
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb.npz
17464789/17464789 [==============================] - 1s 0us/step
훈련용 리뷰 개수 : 25000
테스트용 리뷰 개수 : 25000
카테고리 : 2
word_to_index = imdb.get_word_index()
index_to_word = {}
for key, value in word_to_index.items():
index_to_word[value+3] = key
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb_word_index.json
1641221/1641221 [==============================] - 0s 0us/step
for index, token in enumerate(("<pad>", "<sos>", "<unk>")):
index_to_word[index] = token
print(' '.join([index_to_word[index] for index in X_train[0]]))
import re #-- 정규표현식을 사용하기 위한 모듈 임포트
from tensorflow.keras.datasets import imdb #-- IMDB 데이터셋을 로드하기 위한 모듈 임포트
from tensorflow.keras.preprocessing.sequence import pad_sequences #-- 시퀀스 패딩을 위한 모듈 임포트
from tensorflow.keras.models import Sequential #-- Sequential 모델을 사용하기 위한 모듈 임포트
from tensorflow.keras.layers import Dense, Embedding, SimpleRNN, LSTM #-- 다양한 레이어를 사용하기 위한 모듈 임포트
from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint #-- 훈련 중단 및 모델 체크포인트를 위한 모듈 임포트
from tensorflow.keras.models import load_model #-- 모델 로드를 위한 모듈 임포트
vocab_size = 10000 #-- 사용할 단어의 개수를 지정하는 변수
max_len = 500 #-- 문장의 최대 길이를 지정하는 변수
(X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=vocab_size)
#-- IMDB 데이터셋을 로드하고, num_words를 통해 빈도 기준 상위 vocab_size 개의 단어만 사용하여 데이터를 로드
#-- 훈련 데이터와 테스트 데이터로 구분
X_train = pad_sequences(X_train, maxlen=max_len)
X_test = pad_sequences(X_test, maxlen=max_len)
#-- pad_sequences를 사용하여 시퀀스 데이터인 X_train과 X_test의 길이를 맞춤
#-- maxlen을 통해 문장의 최대 길이를 설정하고, 부족한 길이의 문장은 0으로 패딩
모델정의
def lstm_model():
model = Sequential() #-- LSTM 모델 생성
model.add(Embedding(vocab_size, embedding_dim)) #-- Embedding 층 추가: 입력 데이터를 임베딩 벡터로 변환
model.add(LSTM(hidden_units))#-- LSTM 층 추가: LSTM 레이어를 모델에 추가
model.add(Dense(1, activation='sigmoid'))#-- Dense 층 추가: 이진 분류를 위한 출력층
es = EarlyStopping(monitor='val_loss', mode='min', verbose=1, patience=4)
mc = ModelCheckpoint('lstm_model.h5', monitor='val_acc', mode='max', verbose=1, save_best_only=True)
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])
history = model.fit(X_train, y_train, epochs=15, callbacks=[es, mc], batch_size=64, validation_split=0.2)
return model
import re
from tensorflow.keras.preprocessing.sequence import pad_sequences
word_to_index = tf.keras.datasets.imdb.get_word_index()
index_to_word = {}
for key, value in word_to_index.items():
index_to_word[value+3] = key
def sentiment_predict(new_sentence, loaded_model):
# 알파벳과 숫자를 제외하고 모두 제거 및 알파벳 소문자화
new_sentence = re.sub('[^0-9a-zA-Z ]', '', new_sentence).lower()
encoded = []
# 띄어쓰기 단위 토큰화 후 정수 인코딩
for word in new_sentence.split():
try :
# 단어 집합의 크기를 10,000으로 제한.
if word_to_index[word] <= 10000:
encoded.append(word_to_index[word]+3)
else:
# 10,000 이상의 숫자는 <unk> 토큰으로 변환.
encoded.append(2)
# 단어 집합에 없는 단어는 <unk> 토큰으로 변환.
except KeyError:
encoded.append(2)
pad_sequence = pad_sequences([encoded], maxlen=max_len)
score = float(loaded_model.predict(pad_sequence)) # 예측
if(score > 0.5):
print("{:.2f}% 확률로 긍정 리뷰입니다.".format(score * 100))
else:
print("{:.2f}% 확률로 부정 리뷰입니다.".format((1 - score) * 100))
모델 학습
embedding_dim = 100
hidden_units = 128
lstm = lstm_model()
from tensorflow.keras.utils import plot_model
plot_model(lstm, show_shapes=False, to_file='lstm_model.png')
모델 평가
lstm_loaded_model = load_model('lstm_model.h5')
print("\n LSTM Model 테스트 정확도: %.4f" % (lstm_loaded_model.evaluate(X_test, y_test)[1]))
LSTM Model 테스트 정확도: 0.8764
782/782 [==============================] - 6s 8ms/step - loss: 0.4111 - accuracy: 0.8642
모델 예측
# 긍정적인 리뷰
positive_review = "I watched this film last night and it was an amazing experience. \
The performances by the actors were top notch and the storyline was gripping. \
The cinematography was beautiful, it really transported me into the movie's world. \
I highly recommend this film to anyone who enjoys quality cinema."
# 부정적인 리뷰
negative_review = "I really wanted to like this movie but it just didn't hit the mark for me. \
The plot was full of holes and the character development was almost non-existent. \
Despite having a strong cast, the performances were lackluster due to the weak script. \
I wouldn't recommend wasting your time on this one."
print("======================== 긍정적인 리뷰 =============================")
print("===========================LSTM model 예측===========================")
sentiment_predict(positive_review, lstm_loaded_model)
print("======================== 부정적인 리뷰 =============================")
print("===========================LSTM model 예측===========================")
sentiment_predict(negative_review, lstm_loaded_model)
======================== 긍정적인 리뷰 =============================
===========================LSTM model 예측===========================
1/1 [==============================] - 0s 44ms/step
98.44% 확률로 긍정 리뷰입니다.
======================== 부정적인 리뷰 =============================
===========================LSTM model 예측===========================
1/1 [==============================] - 0s 38ms/step
97.79% 확률로 부정 리뷰입니다.