주뇽's 저장소

LSTM (Long Short-Term Memory) 본문

NLP/LSTM

LSTM (Long Short-Term Memory)

뎁쭌 2023. 7. 1. 02:18
728x90
반응형

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% 확률로 부정 리뷰입니다.