IT Study/ML & DL

[RNN] RNN, LSTM, GRU 모델

짹짹체유 2023. 12. 31. 13:13

 

RNN 실습 1

  • IMDB 데이터셋을 활용
  • LSTM 모델 활용
  • 리뷰 감성분류, 긍정/부정으로 이진 분류 라벨링
  • IMDB 데이터는 훈련데이터와 테스트 데이터를 5:5 비율로 제공

 

  • 라이브러리 불러오기
import tensorflow as tf
from tensorflow.keras import layers, Sequential
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.datasets import imdb
from tensorflow.keras.preprocessing.sequence import pad_sequences

 

 

  • IMDB 데이터셋 불러오기
def load_data(num_words, max_len):
    (X_train, y_train), (X_test, y_test) = imdb.load_data(num_words=num_words)
    X_train = pad_sequences(X_train, maxlen=max_len)
    X_test = pad_sequences(X_test, maxlen=max_len)

    return X_train, X_test, y_train, y_test

 

 

  • LSTM 모델 구축
layers.Embedding: max_words에서 embedding_size로 각 문장을 구성하는 벡터의 크기를 줄이는 임베딩 레이어 추가
    input_dim: 어휘의 크기, 즉 최대 정수 인덱스 + 1
    output_dim: 임베딩의 차수

 

def build_lstm_model(num_words, embedding_len):
    model = Sequential()

    model.add(layers.Embedding(input_dim = num_words, output_dim=embedding_len))
    model.add(layers.LSTM(16))
    model.add(layers.Dense(1, activation='sigmoid'))

    return model
  • LSTM hidden state 크기: 16
  • 출력층은 긍정/부정 중 하나의 값으로 출력되기에, 노드의 개수는 1
  • 출력층 활성화 함수는 로지스틱 회귀를 위해 시그모이드 함수 설정

 

  • 모델 학습
def run_model(model, X_train, X_test, y_train, y_test, epochs=5):
    optimizer = Adam(learning_rate=0.001)
    loss='binary_crossentropy'
    model.compile(optimizer=optimizer, loss=loss, metrics=['accuracy'])
    
    hist = model.fit(X_train, y_train, batch_size=128, epochs=epochs, shuffle=True, verbose=2)
    
    test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)
    print()
    print("테스트 loss: {:.5f}, 테스트 정확도: {:.3f}%".format(test_loss, test_acc * 100))
    
    return optimizer, hist

 

 

  • 전체 코드 실행
def main():
    tf.random.set_seed(2022)

    num_words = 6000
    max_len =  130
    embedding_len = 100

    X_train, X_test, y_train, y_test = load_data(num_words, max_len)

    model = build_lstm_model(num_words, embedding_len)
    run_model(model, X_train, X_test, y_train, y_test)

if __name__ == "__main__":
    main()
  • load_data(num_words: 등장 빈도 순위 -> 단어 집합 크기, max_len: 리뷰 최대 길이)
  • X_train 개수: 25000
  • X_train 리뷰 길이: 130
  • 임베딩 차원: 100

 

 


RNN 실습 2

  • 캐글의 아마존 식품 리뷰 데이터 셋을 활용
  • RNN, LSTM, GRU 모델 활용
  • 평점 분류, 라벨링 1~5까지로

https://www.kaggle.com/datasets/snap/amazon-fine-food-reviews

 

 

  • 라이브러리 불러오기
import tensorflow as tf
from tensorflow.keras import layers, Sequential
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.optimizers import Adam
from sklearn.model_selection import train_test_split

 

 

  • 데이터셋 불러오기
def load_data(max_len):
    data = pd.read_csv("./review_score.csv")
    X = data['Review']
    y = data['Score']
    y = y - 1 # 값을 1~5에서 0~4로 변경

    tokenizer = Tokenizer()
    tokenizer.fit_on_texts(X)
    X = tokenizer.texts_to_sequences(X)

    # 전체 단어 중에서 가장 큰 숫자로 mapping된 단어의 숫자
    max_features = max([max(_in) for _in in X]) + 1

    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

    X_train = pad_sequences(X_train, maxlen=max_len)
    X_test = pad_sequences(X_test, maxlen=max_len)

    return X_train, X_test, y_train, y_test, max_features
  • 문자열로 되어있는 데이터 -> tokenizer 및 시퀀스로 변환
  • 학습 데이터 80% / 테스트 데이터 20%로 분리
  • 모든 문장이 가장 긴 문장의 단어 개수와 일치하도록 패딩 추가

 

  • Simple RNN 모델
def build_rnn_model(max_features, embedding_size):
    model = Sequential()

    model.add(layers.Embedding(input_dim=max_features, output_dim=embedding_size))
    model.add(layers.SimpleRNN(32))
    model.add(layers.Dense(5, activation='softmax'))

    return model
  • 은닉층에 SimpleRNN layer 추가
  • 출력 값이 1~5라서 출력 노드의 개수는 5 & 활성화함수는 softmax

 

  • LSTM 모델
def build_lstm_model(max_features, embedding_size):
    model = Sequential()

    model.add(layers.Embedding(input_dim=max_features, output_dim=embedding_size))
    model.add(layers.LSTM(32))
    model.add(layers.Dense(5, activation='softmax'))

    return model
  • 은닉층에 LSTM layer 추가
  • 출력 값이 1~5라서 출력 노드의 개수는 5 & 활성화함수는 softmax

 

  • GRU 모델
def build_gru_model(max_features, embedding_size):
    model = Sequential()

    model.add(layers.Embedding(input_dim=max_features, output_dim=embedding_size))
    model.add(layers.GRU(32))
    model.add(layers.Dense(5, activation='softmax'))

    return model
  • 은닉층에 GRU layer 추가
  • 출력 값이 1~5라서 출력 노드의 개수는 5 & 활성화함수는 softmax

 

  • 모델 학습
def run_model(model, X_train, X_test, y_train, y_test, epochs=10):
    optimizer = Adam(learning_rate=0.001)
    loss = 'sparse_categorical_crossentropy'
    model.compile(optimizer=optimizer, loss=loss, metrics=['accuracy'])

    hist = model.fit(X_train, y_train, batch_size=256, epochs=epochs, shuffle=True, verbose=2)
    test_loss, test_acc = model.evaluate(X_test, y_test, verbose=0)

    return test_loss, test_acc, optimizer, hist
  • 다중 분류 문제이기 때문에 손실함수는 sparse_categorical_crossentropy

 

  • 전체 코드 실행
def main():
    tf.random.set_seed(2022)
    max_len = 150
    embedding_size = 128

    X_train, X_test, y_train, y_test, max_features = load_data(max_len)
    rnn_model = build_rnn_model(max_features, embedding_size)
    lstm_model = build_lstm_model(max_features, embedding_size)
    gru_model = build_gru_model(max_features, embedding_size)

    rnn_test_loss, rnn_test_acc, _, _ = run_model(rnn_model, X_train, X_test, y_train, y_test)
    lstm_test_loss, lstm_test_acc, _, _ = run_model(lstm_model, X_train, X_test, y_train, y_test)
    gru_test_loss, gru_test_acc, _, _ = run_model(gru_model, X_train, X_test, y_train, y_test)

    print()
    print("=" * 20, "모델 별 Test Loss와 정확도", "=" * 20)
    print("[RNN ] 테스트 Loss: {:.5f}, 테스트 Accuracy: {:.3f}%".format(rnn_test_loss, rnn_test_acc * 100))
    print("[LSTM] 테스트 Loss: {:.5f}, 테스트 Accuracy: {:.3f}%".format(lstm_test_loss, lstm_test_acc * 100))
    print("[GRU ] 테스트 Loss: {:.5f}, 테스트 Accuracy: {:.3f}%".format(gru_test_loss, gru_test_acc * 100))

if __name__ == "__main__":
    main()

 

 

 

  • 모델 학습 결과

  • LSTM > GRU > RNN 순으로 정확도가 높게 나옴
  • 간단한 실습으로 은닉층의 개수를 한 개씩만 설정하여 정확도 낮음

 

 

참고자료

https://wikidocs.net/24586

 

 

 

반응형