파이썬 이것저것/파이썬 딥러닝 관련

[Python] 딥러닝 순환 신경망 (RNN)

agingcurve 2022. 7. 15. 17:45
반응형

순환 신경망(RNN)

자연어 처리를 위한 딥러닝 모델

 

 

MLP 기반 신경망의 자연어 분류 방식

일반적인 뉴럴 네트워크로 학습 한다면, 단어들이 순서에 대해서 기존의 뉴럴 네트워크는 신경을 쓰지 않고 학습을 함
철수가 영희를 좋아한다. 라는 문장이 있다면, 영희가 철수를 좋아한다 이렇게 될경우 의미가 달라지게 됨

자연어 문장을 기존 MLP 모델에 적용시키기에는 한계가 있음

자연어 분류를 위한 순환 신경망(Recurrent Neural Network)

 

RNN 모델은 순서를 고려해서 학습을 실시한다.
RNN 단어가 들어가서 다음 단어를 예측하려고 한다.
이 다음 단어가 수업 + 이 라는 예측을 하게 하고 그 다음 단어가 예측을 할때, 수업 + 이  가 같이 들어가서
Hidden State랑 합쳐지는 방식으로 다음단어를 예측하고 다시 합쳐져서 학습 하는 방식으로 실시함

 

출력 값을 두 갈래로 나뉘어 신경망에게 ‘기억’ 하는 기능을 부여

 

순환 신경망 기반 자연어 분류 예시

 

 

순환 신경망(RNN) 모델 파이썬으로 구현하기

순환 신경망(Recurrent Nueral Networks, RNN)은 다양한 형태의 시계열 자료 학습에 적합

 기계 번역, 자율 주행 자동차 개발 등에 널리 사용되고 있으며, 다양한 변형 모델이 제안된 바 있음 다양한 순환 신경망 모델들의 핵심은 이전 데이터를 현재 데이터의 계산에 반영

import numpy as np

np.random.seed(100)

'''
1. 간단한 RNN 모델을 구현

'''

def rnn(inputs, input_size, output_size, bias = False):
    
    input_size = len(inputs[0])
    
    state = np.zeros((output_size,))
    
    w = np.ones((output_size, input_size))
    
    u = np.ones((output_size, output_size))
    
    b = np.random.random((output_size,))
    
    if not bias:
        b = np.zeros((output_size,))
    
    outputs = []
    
    for _input in inputs:
        
        _output = np.tanh(np.dot(w, _input) + np.dot(u, state) + b)
        outputs.append(_output)
        state=_output
        
    return np.stack(outputs, axis=0)

# 케이스에 따라 RNN 모델의 결과가 어떻게 바뀌는지 확인

def main():
    
    print("-----------------CASE 1-----------------")
    _input1 = [[0], [0], [0], [0], [0]]
    
    # 입력이 모두 0이고 출력 벡터의 크기가 1일 때 값의 추세가 어떠한지 확인
    case1_a = rnn(_input1, input_size=1, output_size=1)
    print('\nCASE 1_a:', case1_a)
    # Bias가 있으면 값이 어떻게 변화하는지 확인
    case1_b = rnn(_input1, input_size=1, output_size=1, bias = True)
    print('\nCASE 1_b:', case1_b)
    
    
    print("\n-----------------CASE 2-----------------")
    _input2 = [[1], [1], [1], [1], [1]]
    
    # 입력이 모두 1이고 출력 벡터의 크기가 1일 때 값의 추세가 어떠한지 확인
    case2_a = rnn(_input2, input_size=1, output_size=1)
    print('\nCASE 2_a:', case2_a)
    # Bias가 있으면 값이 어떻게 변화하는지 확인
    case2_b = rnn(_input2, input_size=1, output_size=1, bias = True)
    print('\nCASE 2_b:', case2_b)
    
    
    print("\n-----------------CASE 3-----------------")
    _input3 = [[1], [2], [3], [4], [5]]
    
    # 입력값이 증가하고 출력 벡터의 크기가 2일 때 값의 추세가 어떠한지 확인
    case3_a = rnn(_input3, input_size=1, output_size=2)
    print('\nCASE 3_a:', case3_a)
    # Bias가 있으면 값이 어떻게 변화하는지 확인
    case3_b = rnn(_input3, input_size=1, output_size=2, bias = True)
    print('\nCASE 3_b:', case3_b)
    
    return case1_a, case1_b, case2_a, case2_b, case3_a, case3_b

if __name__ == '__main__':
    main()

 

Keras를 활용한 RNN 모델 구현

영화 리뷰 데이터를 바탕으로 감정 분석을 하는 모델을 학습

영화 리뷰와 같은 자연어 자료는 곧 단어의 연속적인 배열로써, 시계열 자료

시계열 자료(연속된 단어)를 이용해 리뷰에 내포된 감정(긍정, 부정)을 예측하는 분류기 구현

RNN in Keras

일반적으로 RNN 모델은 입력층으로 Embedding 레이어를 먼저 쌓고, RNN 레이어를 몇 개 쌓은 다음, 이후 Dense 레이어를 더 쌓아 완성

import numpy as np
import tensorflow as tf
from keras.datasets import imdb
from keras.preprocessing import sequence

import logging, os
logging.disable(logging.WARNING)
os.environ["TF_CPP_MIN_LOG_LEVEL"] = "3"

np.random.seed(0)
tf.random.set_seed(0)

np_load_old = np.load
np.load = lambda *a,**k: np_load_old(*a, allow_pickle=True, **k)

# 데이터를 불러오고 전처리하는 함수입니다.

def load_data(n_of_training_ex, n_of_testing_ex, max_review_length):
    
    PATH = "./data/"
    
    X_train = np.load(PATH + "X_train.npy")[:n_of_training_ex]
    y_train = np.load(PATH + "y_train.npy")[:n_of_training_ex]
    X_test = np.load(PATH + "X_test.npy")[:n_of_testing_ex]
    y_test = np.load(PATH + "y_test.npy")[:n_of_testing_ex]
    
    X_train = sequence.pad_sequences(X_train, maxlen=max_review_length)
    X_test = sequence.pad_sequences(X_test, maxlen=max_review_length)
    
    return X_train, y_train, X_test, y_test
    
'''
1. SimpleRNN을 적용할 하나의 모델을 자유롭게 생성합니다.
'''
    
def SimpleRNN(embedding_vector_length, max_review_length):
    
    model = tf.keras.models.Sequential()
    model.add(tf.keras.layers.Embedding(input_dim = 1000, output_dim = embedding_vector_length, input_length = max_review_length))
    model.add(tf.keras.layers.SimpleRNN(5))
    model.add(tf.keras.layers.Dense(1, activation="sigmoid"))

    return model

'''
2. LSTM을 적용할 하나의 모델을 자유롭게 생성합니다.
'''

def LSTM(embedding_vector_length, max_review_length):
    
    model = tf.keras.models.Sequential()
    model.add(tf.keras.layers.Embedding(input_dim = 1000, output_dim = embedding_vector_length, input_length = max_review_length))
    model.add(tf.keras.layers.LSTM(5))
    model.add(tf.keras.layers.Dense(1, activation="sigmoid"))
    
    return model

'''
3. GRU를 적용할 하나의 모델을 자유롭게 생성합니다.
'''

def GRU(embedding_vector_length, max_review_length):
    
    model = tf.keras.models.Sequential()
    model.add(tf.keras.layers.Embedding(input_dim = 1000, output_dim = embedding_vector_length, input_length = max_review_length))
    model.add(tf.keras.layers.GRU(5))
    model.add(tf.keras.layers.Dense(1, activation="sigmoid"))
    
    return model

'''
4. 세 모델을 불러온 후 학습시키고 테스트 데이터에 대해 평가

   Step01. SimpleRNN, LSTM, GRU 함수를 이용해 세 모델
   
   Step02. 세 모델의 손실 함수, 최적화 알고리즘, 평가 방법을 설정
   
   Step03. 세 모델의 구조를 확인하는 코드를 작성
   
   Step04. 세 모델을 각각 학습시킵니다. 검증용 데이터는 설정하지 하지 않음
           세 모델 모두 'epochs'는 3, 'batch_size'는 256으로 설정
   
   Step05. 세 모델을 테스트하고 각각의 Test Accuracy 값을 출력 
           셋 중 어느 모델의 성능이 가장 좋은지 확인
'''

def main():
    
    max_review_length = 300
    embedding_vector_length = 32
    
    n_of_training_ex = 25000
    n_of_testing_ex = 3000
    
    X_train, y_train, X_test, y_test = load_data(n_of_training_ex, n_of_testing_ex, max_review_length)
    
    model_simple_rnn = SimpleRNN(embedding_vector_length, max_review_length)
    model_lstm = LSTM(embedding_vector_length, max_review_length)
    model_gru = GRU(embedding_vector_length, max_review_length)
    
    model_simple_rnn.compile(loss = "binary_crossentropy",
    optimizer = "adam", metrics = ["accuracy"])
    model_lstm.compile(loss = "binary_crossentropy",
    optimizer = "adam", metrics = ["accuracy"])
    model_gru.compile(loss = "binary_crossentropy",
    optimizer = "adam", metrics = ["accuracy"])
    
    model_simple_rnn.summary()
    model_lstm.summary()
    model_gru.summary()
    
    model_simple_rnn_history = model_simple_rnn.fit(X_train,y_train,
    epochs=3, batch_size=256, verbose = 0)
    print('\n')
    model_lstm_history = model_lstm.fit(X_train,y_train,
    epochs=3, batch_size=256, verbose = 0)
    print('\n')
    model_gru_history = model_gru.fit(X_train,y_train,
    epochs=3, batch_size=256, verbose = 0)
    
    scores_simple_rnn = model_simple_rnn.evaluate(X_test, y_test, verbose=0)
    scores_lstm = model_lstm.evaluate(X_test, y_test, verbose=0)
    scores_gru = model_gru.evaluate(X_test, y_test, verbose=0)
    
    print('\nTest Accuracy_simple rnn: ', scores_simple_rnn[-1])
    print('Test Accuracy_lstm: ', scores_lstm[-1])
    print('Test Accuracy_gru: ', scores_gru[-1])
    
    return model_simple_rnn_history, model_lstm_history, model_gru_history

if __name__ == '__main__':
    main()