Bidirectional RNN(Bi-RNN)란 무엇인가?

과거의 RNN 모델인 LSTM과 GRU는 문장의 끝 부분의 정보를 이용할 수 없어 개체명인식과 같은 문제에서 성능이 좋지 않았습니다. 이러한 한계를 극복하기 위해, 양방향 RNN 모델이 제안되었습니다. 양방향 RNN은 시퀀스의 이전 부분과 이후 부분을 결합하여 예측하기 때문에 더욱 정확한 결과를 얻을 수 있습니다. 예를 들어, 개체명인식에서 "black"이란 단어가 검은색을 의미하는지 사람이름을 의미하는지를 알기 위해서는 해당 단어 뒤에 단어들이 어떻게 쓰였는지를 고려해야합니다. 이러한 정보를 고려하여 예측하는 것이 양방향 RNN의 큰 장점입니다.

 


1. Bi-RNN의 개념

 

양방향 RNN은 Bi-RNN이라고도 불리며, 두 개의 독립적인 RNN을 사용하여 입력 시퀀스를 처리합니다. 하나의 RNN은 정방향으로 입력을 받고, 다른 하나의 RNN은 역방향으로 입력을 받습니다. 이러한 구조는 네트워크가 각 time step에서 양방향 정보를 모두 갖게 하여 더욱 정확한 결과를 예측할 수 있도록 합니다. 양방향 RNN은 긴 시퀀스에서 패턴을 추출하는 데 효과적이며,  양쪽 방향에서의 정보를 참조하여 더 높은 정확도를 가집니다. Bi-RNN의 출력은 정방향 RNN과 역방향 RNN의 출력을 결합하여 결정됩니다. 

 

양방향 RNN 이미지

 


2. Bi-RNN의 구조

 

양방향 RNN의 구조는 양쪽으로 향하는 두 개의 RNN 구조로 구성됩니다. 각 RNN은 입력 시퀀스의 양쪽 방향으로 메모이제이션(계산 결과를 저장하여 다음 계산이 필요할 때 그 결과를 사용하는 기술)을 수행합니다. 이렇게 얻어진 출력은 각 time step기준으로 concatenated되어 최종 출력이 결정됩니다.

 

 

Bi-RNN의 상세 구조 이미지

 


수식으로 표현하면 다음과 같습니다.

 

 

$$h_t^{\rightarrow} = σ(W_f h_{t-1}^{\rightarrow} + U_f x_t + b_f)$$

 

여기서 \(h_t^{\rightarrow}\)은 시점 \(t\)에서의 Hidden state, \(x_t\)는 시점\(t\)에서의 입력, \(W_f\)와 \(U_f\)는 가중치, \(b_f\)는 편향, σ는 활성 함수를 나타냅니다.

 

 

$$h_t^{\leftarrow} = σ(W_b h_{t+1}^{\leftarrow} + U_b x_t + b_b)$$

 

여기서 \(h_t^{\leftarrow}\)은 시점 \(t\)에서의 Hidden state, \(x_t\)는 시점 \(t\)에서의 입력, \(W_b\)와 \(U_b\)는 가중치 , \(b_b\)는 편향, σ는 활성 함수를 나타냅니다.

 

 

$$y_t = V[h_t^{\rightarrow} h_t^{\leftarrow}] + b_c$$

 

여기서 \(y_t\)는 시점 \(t\)에서의 출력,  \(V\)와 \(c\)는 가중치와 편향을 나타냅니다. \([h_t^{\rightarrow} h_t^{\leftarrow}]\)는 순방향 RNN과 역방향 RNN의 출력을 연결한 벡터를 나타냅니다.

 


양방향 RNN은 기존 RNN과 마찬가지로 시간 역전파(BPTT) 방법을 사용하여 학습됩니다. 그러나 양방향 RNN은 각 방향마다 별도의 Hidden state가 존재하며, 이 두 가지 Hidden state가 최종 출력을 계산하는 데 사용됩니다. 학습 중에는 그라디언트가 계산되고 Hidden state를 통해 역전파되어 네트워크 가중치가 업데이트됩니다. Loss를 계산하는 방법은  마찬가지로 sequence loss를 계산하여 역전파를 통해 학습됩니다. 이를 통해 네트워크가 입력 시퀀스에서 패턴을 추출하고, 예측 결과를 더욱 정확하게 출력할 수 있습니다.

 

 


3. Bi-RNN의 특징

 

Bi-RNN의 가장 큰 특징은 양방향 정보 전달 능력입니다. 이전의 RNN은 순방향으로 입력 정보를 처리하기 때문에 과거 정보만을 이용합니다. 그러나 Bi-RNN은 과거와 미래의 정보를 모두 이용하기 때문에 보다 정확한 예측을 할 수 있습니다.  예를 들어, 기계 번역에서 Bi-RNN은 이전의 단어와 이후의 단어를 모두 고려하여 문장을 번역합니다. 이로 인해 보다 자연스러운 번역 결과를 얻을 수 있습니다. 또한, Bi-RNN은 시계열 데이터에서 매우 유용합니다. 이는 시계열 데이터가 과거와 미래의 정보가 모두 필요한 경우가 많기 때문입니다. 예를 들어, 주식 가격 예측에서는 과거의 주가 데이터와 이후의 경제 동향 정보가 모두 필요합니다. 

 


4. Bi-RNN의 예시 코드

import tensorflow as tf
import matplotlib.pyplot as plt
from tensorflow.keras.datasets import imdb
from tensorflow.keras.preprocessing import sequence

# Load the IMDB dataset
(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=10000)

# Pad the sequences to the same length
max_len = 500
x_train = sequence.pad_sequences(x_train, maxlen=max_len)
x_test = sequence.pad_sequences(x_test, maxlen=max_len)

# Build the model
model = tf.keras.Sequential()
model.add(tf.keras.layers.Embedding(10000, 128))
model.add(tf.keras.layers.Bidirectional(tf.keras.layers.SimpleRNN(128, dropout=0.2, recurrent_dropout=0.2)))
model.add(tf.keras.layers.Dense(1, activation='sigmoid'))

# Compile the model
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])

# Train the model
history = model.fit(x_train, y_train, batch_size=32, epochs=10, validation_data=(x_test, y_test))

# Plot the loss and accuracy results
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Model Loss')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Validation'], loc='upper right')
plt.show()

plt.plot(history.history['accuracy'])
plt.plot(history.history['val_accuracy'])
plt.title('Model Accuracy')
plt.ylabel('Accuracy')
plt.xlabel('Epoch')
plt.legend(['Train', 'Validation'], loc='lower right')
plt.show()

 

 


5. 참고문헌

 

 

[python/Tensorflow2.0] bidirectional RNN(Recurrent Neural Network) ; many to many

1. bidirectional(양방향) RNN 이란 ? 이전 강의까지는 모두 RNN을 모두 단방향으로만 활용을 하였는데, 사실 이 방식은 정보의 불균형이 존재한다. 풀어서 설명하자면 다음과 같다. 단방향 RNN이 시퀀스

engineer-mole.tistory.com