본문 바로가기
  • 기술을 이야기하지만 사람을 생각합니다.
20. 인공지능과 딥러닝

밑바닥부터 시작하는 딥러닝2 :: Ch 08 어텐션 (2) 양방향 LSTM

by WE DONE IT. 2019. 7. 14.

이 글은 <밑바닥부터 시작하는 딥러닝 2> 책 <8장. 어텐션>을 스터디를 하면서 제가 리딩한 파트를 설명/공유하기 위해 작성하였습니다. 추가적인 설명을 하기 위해 관련 논문이나 아티클 등도 참고하였습니다. 혹시 잘못 작성한 부분이나 코멘트는 댓글로 남겨주세요!

 


 

LSTM의 각 시각의 은닉 상태 벡터는 hs로 모아진다. 

LSTM의 시각별 은닉 상태 벡터를 모은 hs의 각 행에는 그 행에 대응하는 단어의 성분(예: 나, 는, 고양이, 로소, 이다)을 많이 포함하고 있다. 그러나 여기에서 짚어야할 점은 글을 왼쪽에서 오른쪽으로 읽는다는 점이다. 그렇기에 "고양이"에 대응하는 벡터에는 "나", "는", "고양이"까지 총 세 단어의 정보가 인코딩 된다.

 

문장이 길어질 수록 한 벡터에 포함하고 있는 단어의 정보는 점점 많아질 것이다. 대응하는 단어(고양이)의 주변 정보(나, 는, 로소, 이다)를 균형 있게 담기 위한 방법"양방향 LSTM(양방향 RNN)"이다. [그림 8-30]

 

양방향 LSTM은 지금까지의 LSTM 계층에 역방향으로 처리하는 LSTM 계층도 추가한다.

 

양방향 LSTM

양방향 LSTM은 기존의 LSTM 계층에 (1) 역방향으로 처리하는 LSTM 계층을 추가한다. 최종 은닉 상태는 두 LSTM 계층의 은닉 상태를 연결한 벡터를 출력한다. 연결 이외에도 (2) 더하거(3) 평균을 내는 방법 등 다양하게 적용할 수 있다.

 

RNN이나 LSTM은 입력 순서를 시간 순대로 입력하기 때문에 결과물이 직전 패턴을 기반으로 수렴하는 경향을 보인다는 한계가 있다. 이 단점을 해결하는 목적으로 양방향 순한신경망(Bi-RNN)이 제안되었다. Bi-RNN은 기존의 순방향에 역방향을 추가하여, 은닉층에 추가하여 성능을 향상시켰다.
 그러나 데이터 길이가 길고 층이 깊으면, 과거의 정보가 손실되는 단점이 있다. 이를 극복하기 위해 제안된 알고리즘이 양방향 LSTM이다. (Ko et al., 2018)

양방향 LSTM 특징

양방향 LSTM은 최근 머신러닝 분야에서 좋은 성과에 적용된 모델일 정도로 높은 성능의 알고리즘 중 하나이다. (Ko et al., 2018)

  1. 출력값에 대한 손실을 최소화하는 과정에서 모든 파라미터를 동시에 학습되는 종단간 학습 가능
  2. 단어와 구(Phrase)간 유사성을 입력벡터에 내재화하여 성능 개선
  3. 데이터 길이가 길어도 성능이 저하되지 않음
    • LSTM의 기본 성능과 Attention 매커니즘을 도입함

양방향 LSTM 구현 방법

  1. 2개의 LSTM 계층을 사용하여 계층의 단어 순서를 조정한다.
    • 첫 번째 LSTM 계층은 기존과 동일하게 입력 문장을 왼쪽에서 오른쪽으로 처리한다.
    • 추가된 두 번째 LSTM 계층은 입력 문장의 단어 순서를 반대로 처리한다. (예:  A - B - C => C - B - A)
  2. 두 LSTM 계층의 출력을 연결한다.

양방향 LSTM을 구현한 클래스

 

class TimeBiLSTM:
    def __init__(self, Wx1, Wh1, b1,
                 Wx2, Wh2, b2, stateful=False):
        self.forward_lstm = TimeLSTM(Wx1, Wh1, b1, stateful)
        self.backward_lstm = TimeLSTM(Wx2, Wh2, b2, stateful)
        self.params = self.forward_lstm.params + self.backward_lstm.params
        self.grads = self.forward_lstm.grads + self.backward_lstm.grads

    def forward(self, xs):
        o1 = self.forward_lstm.forward(xs)
        o2 = self.backward_lstm.forward(xs[:, ::-1])
        o2 = o2[:, ::-1]

        out = np.concatenate((o1, o2), axis=2)
        return out

    def backward(self, dhs):
        H = dhs.shape[2] // 2
        do1 = dhs[:, :, :H]
        do2 = dhs[:, :, H:]

        dxs1 = self.forward_lstm.backward(do1)
        do2 = do2[:, ::-1]
        dxs2 = self.backward_lstm.backward(do2)
        dxs2 = dxs2[:, ::-1]
        dxs = dxs1 + dxs2
        return dxs

# ====================================================================== #
# 이 아래의 계층들은 책에서 설명하지 않았거나
# 처리 속도보다는 쉽게 이해할 수 있도록 구현했습니다.
#
# TimeSigmoidWithLoss: 시계열 데이터용 시그모이드 + 손실 계층
# GRU: GRU 계층
# TimeGRU: 시계열 데이터용 GRU 계층
# BiTimeLSTM: 양방향 LSTM 계층
# Simple_TimeSoftmaxWithLoss:간단한 TimeSoftmaxWithLoss 계층의 구현
# Simple_TimeAffine: 간단한 TimeAffine 계층의 구현
# ====================================================================== #

 


References

고상준, 윤호영, and 신동명. "양방향 LSTM을 활용한 전력수요 데이터 예측 기법 연구" 한국소프트웨어감정평가학회 논문지 14.1(2018):33-40

 

댓글