본문 바로가기
Deep Learning/자연어처리

Keras를 통한 SimpleRNN, LSTM 출력값의 이해

by 대소기 2021. 12. 16.

 

임의의 입력 생성하기

import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import SimpleRNN, LSTM, Bidirectional

train_X = [[0.1, 4.2, 1.5, 1.1, 2.8],
           [1.0, 3.1, 2.5, 0.7, 1.1], 
           [0.3, 2.1, 1.5, 2.1, 0.1], 
           [2.2, 1.4, 0.5, 0.9, 1.1]]
train_X=np.array(train_X, dtype=np.float32)
train_X=train_X[np.newaxis, :]
train_X

# array([[[0.1, 4.2, 1.5, 1.1, 2.8],
#         [1. , 3.1, 2.5, 0.7, 1.1],
#         [0.3, 2.1, 1.5, 2.1, 0.1],
#         [2.2, 1.4, 0.5, 0.9, 1.1]]], dtype=float32)

* 5차원 vector로 이뤄진 단어 4개로 구성된 문장을 데이터로 구현하면 train_X가 된다. 이 train_X를 우리는 입력으로 사용할 것이다.

* 하지만, 곧바로 keras RNN모델에 집어넣을 수는 없다. RNN은 input으로 3차원 텐서만 입력받을 수 있기 때문이다. 그 때문에 np.newaxis를 사용해 batch_size에 해당하는 차원을 더해줬다. 우리는 간단한 데이터로 실험하기 위해 1개의 batch만 사용하기 때문에 shape은 (1,4,5)가 될 것이다.

 

SimpleRNN

rnn=SimpleRNN(3) #hidden_size를 3으로
hidden_state=rnn(train_X)

print('hidden_state : {}, shape: {}'.format(hidden_state, hidden_state.shape))
# hidden_state : [[-0.85970896  0.9997586   0.571153  ]], shape: (1, 3)

* SimpleRNN의 경우 여러가지 인자가 있지만 우리가 지금 살펴볼 것은 return_sequences, return_state이다.

* 먼저 return_sequences의 경우 모든 timestep의 hidden state를 return할지 여부를 나타내는 parameter이다.

* 다음으로 return_state의 경우 마지막 timestep의 hidden state를 return할지 여부를 나타낸다.

* 두 parameter 모두 default value가 false이기 때문에 따로 설정하지 않으면 false인 모델이 생성된다. 위 코드는 default value를 그대로 사용한 모델로 RNN모델의 return 값이 마지막 timestep의 hidden state인 것을 볼 수 있다.

* 출력된 hidden state는 우리가 설정한 hidden_size의 값을 크기로 하는 vector이다.

 

rnn=SimpleRNN(3, return_sequences=True, return_state=True) #hidden_size를 3으로
hidden_state, last_state=rnn(train_X)

print('hidden_state : {}, shape: {}'.format(hidden_state, hidden_state.shape))
print('last_state : {}, shape: {}'.format(last_state, last_state.shape))

# hidden_state : [[[ 0.05460734 -0.9995881  -0.77756953]
#   [-0.72908634 -0.9995552  -0.16867231]
#   [-0.3917665  -0.88125503  0.05371289]
#   [ 0.978806   -0.8431315  -0.93293816]]], shape: (1, 4, 3)
# last_state : [[ 0.978806   -0.8431315  -0.93293816]], shape: (1, 3)

* 두 parameter 모두 True로 설정한 모델이다. return_state의 경우 return_sequences의 True, False 여부와 상관 없이 True로 설정되면 마지막 timestep의 hidden state를 return한다.

 

LSTM

lstm=LSTM(3, return_state=True)
hidden_state, last_state, last_cell_state = lstm(train_X)

print('hidden states: {}, shape: {}'.format(hidden_state, hidden_state.shape))
print('last hidden states: {}, shape: {}'.format(last_state, last_state.shape))
print('last cell states: {}, shape: {}'.format(last_cell_state, last_cell_state.shape))

# hidden states: [[-0.23919672  0.32927644  0.15150729]], shape: (1, 3)
# last hidden states: [[-0.23919672  0.32927644  0.15150729]], shape: (1, 3)
# last cell states: [[-0.7521684   0.38797036  0.2520657 ]], shape: (1, 3)

* SimpleRNN과 다른 점은 return_state를 True로 설정했을 때 return 되는 값이 2개라는 점이다. return 되는 값은 마지막 hidden state, 마지막 cell state 두 개가 return된다.

 

Bidirectional(LSTM)

k_init = tf.keras.initializers.Constant(value=0.1)
b_init = tf.keras.initializers.Constant(value=0)
r_init = tf.keras.initializers.Constant(value=0.1)

bilstm=Bidirectional(LSTM(3, return_sequences=True, return_state=True,
                          kernel_initializer=k_init, bias_initializer=b_init,
                          recurrent_initializer=r_init))
hidden_states, forward_h, forward_c, backward_h, backward_c = bilstm(train_X)

print('hidden states: {}, shape: {}'.format(hidden_states, hidden_states.shape))
print('forward hidden states: {}, shape: {}'.format(forward_h, forward_h.shape))
print('backward hidden states: {}, shape: {}'.format(backward_h, backward_h.shape))

# hidden states: [[[0.35906473 0.35906473 0.35906473 0.7038734  0.7038734  0.7038734 ]
#   [0.5511133  0.5511133  0.5511133  0.58863586 0.58863586 0.58863586]
#   [0.59115744 0.59115744 0.59115744 0.3951699  0.3951699  0.3951699 ]
#   [0.63031393 0.63031393 0.63031393 0.21942244 0.21942244 0.21942244]]], shape: (1, 4, 6)
# forward hidden states: [[0.63031393 0.63031393 0.63031393]], shape: (1, 3)
# backward hidden states: [[0.7038734 0.7038734 0.7038734]], shape: (1, 3)

* 이 번엔 양방향 LSTM의 출력에 대해 살펴보겠다. return_sequence=True, return_state=True로 설정했다.

* 양방향 LSTM의 경우 return_sequences=True로 설정했을 때 각 timestep의 hidden state는 foward, backward의 hidden state를 모두 출력하게 된다. 즉 다음 층의 입력으로 사용하게 된다고 할 수 있다. 위 그림과 같이 forward와 backward의 hidden state가 짝을 이뤄 다음 층의 입력으로 사용된다.

* return_state를 True로 설정했을 경우 마지막 hidden state를 출력하게 되는데, 이는 foward의 마지막 time step의 hidden state와 backward의 첫 번째 timestep의 hidden state를 출력하게된다.

 

bilstm=Bidirectional(LSTM(3, return_sequences=False, return_state=True,
                          kernel_initializer=k_init, bias_initializer=b_init,
                          recurrent_initializer=r_init))
hidden_states, forward_h, forward_c, backward_h, backward_c = bilstm(train_X)

print('hidden states: {}, shape: {}'.format(hidden_states, hidden_states.shape))
print('forward hidden states: {}, shape: {}'.format(forward_h, forward_h.shape))
print('backward hidden states: {}, shape: {}'.format(backward_h, backward_h.shape))

# hidden states: [[0.63031393 0.63031393 0.63031393 0.7038734  0.7038734  0.7038734 ]], shape: (1, 6)
# forward hidden states: [[0.63031393 0.63031393 0.63031393]], shape: (1, 3)
# backward hidden states: [[0.7038734 0.7038734 0.7038734]], shape: (1, 3)

* 만약 위와 같이 return_sequences를 False로 설정하면 return 되는 hidden states는 그림과 같이 마지막 time step의 forward hidden state와 첫 번째 time step의 backward hidden state라는 것을 알 수 있다. 이는 다음 층의 입력으로 사용된다.

'Deep Learning > 자연어처리' 카테고리의 다른 글

RNN을 이용한 텍스트 생성  (0) 2021.12.17
RNN 언어 모델(RNNLM)  (0) 2021.12.17
피드포워드 신경망 언어 모델(NNLM)  (0) 2021.12.16
LSTM, GRU  (0) 2021.12.16
RNN(Recurrent Neural Network)  (0) 2021.12.16