Long Short-Term Memory(LSTM)

박재한·2022년 2월 23일
0

Deep Learning

목록 보기
9/22

참고1
참고2
이 글은 Vanilla RNN에서 기울기 소실 문제(vanishing gradient problem)를 해결한 LSTM(Long Short-Term Memory)을 이해하기 위해 정리한 것이다.

1. RNN(Recurrent Neural Network)

인간은 모든 생각을 밑바닥부터 시작하지 않는다. 지금 이 글을 읽는 당신도 매 단어를 그 전 단어들을 바탕으로 이해할 것이 분명하다. 지금까지 봐왔던 것들을 모두 집어던지고 아무 것도 모르는 채로 생각하지 않을 것이다. 생각은 계속 나아가는 것이다.
전통적인 neural network이 이렇게 지속되는 생각을 하지 못한다는 것이 큰 단점이다. 예를 들어, 영화의 매 순간 일어나는 사건을 분류하고 싶다고 해보자. 전통적인 neural network는 이전에 일어난 사건을 바탕으로 나중에 일어나는 사건을 생각하지 못한다.
Recurrent neural network (이하 RNN)는 이 문제를 해결하고자 하는 모델이다. RNN은 스스로를 반복하면서 이전 단계에서 얻은 정보가 지속되도록 한다.

위 그림에서 A는 RNN의 한 덩어리이다. A는 input으로 xtx_t를 받아서 hth_t를 내보낸다. A를 둘러싼 반복(recurrent)은 다음 단계에서의 network가 이전 단계의 정보를 받는다는 것을 보여준다.
이러한 RNN의 반복 구조는 불가사의해 보일 수도 있겠지만, 조금 더 생각해보면 RNN은 기존 neural network와 그렇게 다르지 않다는 것을 알 수 있다. RNN을 하나의 network를 계속 복사해서 순서대로 정보를 전달하는 network라고 생각하는 것이다. 아예 반복을 풀어버리면 좀 더 이해하기 쉬울 것이다.

이렇게 RNN의 체인(chain)처럼 이어지는 성질은 곧장 기존의 neural network를 다루기에 최적화된 구조인 sequence나 list와 매우 가깝게 보인다.
그리고 진짜로 그렇게 사용되고 있다! 지난 몇 년 동안, RNN은 음성 인식, 언어 모델링, 번역, 이미지 주석 생성 등등등등의 다양한 분야에서 굉장한 성공을 거두었다. RNN으로 얻을 수 있는 놀라운 이점에 대한 논의는 Andrej Karpathy의 훌륭한 글인 "The Unreasonable Effectiveness of Recurrent Neural Networks"로 넘기겠다. 어쨌든 RNN은 멋진 놈(amazing)이다.

2. RNN에서 긴 시간차에 의한 문제점

RNN의 성공의 열쇠는 "Long Short-Term Memory Network" (이하 LSTM)의 사용이다. LSTM은 RNN의 굉장히 특별한 종류로, 아까 얘기했던 영화를 frame 별로 이해하는 것과 같은 문제들을 단순 RNN보다 정말 훨씬 진짜 잘 해결한다. 기존 RNN(vanilla RNN)도 LSTM만큼 이런 일을 잘 할 수 있다면 RNN은 대단히 유용할텐데, 아쉽게도 RNN은 그 성능이 상황에 따라 그때 그때 다르다.
우리가 현재 시점의 뭔가를 얻기 위해서 멀지 않은 최근의 정보만 필요로 할 때도 있다. 예를 들어 이전 단어들을 토대로 다음에 올 단어를 예측하는 언어 모델을 생각해 보자. 만약 우리가 "the clouds are in the sky"에서의 마지막 단어를 맞추고 싶다면, 저 문장 말고는 더 볼 필요도 없다. 마지막 단어는 sky일 것이 분명하다. 이 경우처럼 필요한 정보를 얻기 위한 시간 격차가 크지 않다면, RNN도 지난 정보를 바탕으로 학습할 수 있다.

짧은 기간에 의존하는 RNN

하지만 반대로 더 많은 문맥을 필요로 하는 경우도 있다. "I grew up in France... I speak fluent French"라는 문단의 마지막 단어를 맞추고 싶다고 생각해보자. 최근 몇몇 단어를 봤을 때 아마도 언어에 대한 단어가 와야 될 것이라 생각할 수는 있지만, 어떤 나라 언어인지 알기 위해서는 프랑스에 대한 문맥을 훨씬 뒤에서 찾아봐야 한다. 이렇게 되면 필요한 정보를 얻기 위한 시간 격차는 굉장히 커지게 된다.
안타깝게도 이 격차가 늘어날 수록 RNN은 학습하는 정보를 계속 이어나가기 힘들어한다.(좀 더 설명을 하자면 기존 RNN으로는 바로 직전의 RNN으로부터의 입력인 "I speak fluent"만으로는 다음에 올 단어가 "French"인지를 맞추기가 어렵다. 보다 더 이전으로부터의 입력인 "I grew up in France"라는 정보가 있어야 "French"를 맞출 수가 있을 것이다. 이렇게 기존 RNN(Vanilla RNN)으로는 시간차가 많이 나는 정보는 기울기 소실 등의 문제로 인해 제대로 학습이 이루어 지지가 않아 성능이 떨어지는(예측력이 떨어지는) 문제가 있다.)

긴 기간에 의존하는 RNN

이론적으로는 RNN이 이러한 "긴 기간의 의존성(long-term dependencies)"를 완벽하게 다룰 수 있다고 하나 실제로는 아주 단순한 문제에서도 해결하지 못했다. 이 사안에 대해 Hochreiter (1991)과 Bengio 외(et al.) (1994)가 심도있게 논의했는데 기존 RNN만으로는 문제를 해결 할 수 없는 근본적인 이유를 찾아내었다.
고맙게도 LSTM은 이러한 문제가 없다!

3. LSTM Networks

LSTM(Long Shor-Term Memory)은 RNN의 특별한 한 종류로, 긴 의존 기간을 필요로 하는 학습을 수행할 능력을 갖고 있다. LSTM은 Hochreiter & Schmidhuber (1997)에 의해 소개되었고, 그 후에 여러 추후 연구로 계속 발전하고 유명해졌다. LSTM은 여러 분야의 문제를 굉장히 잘 해결했고, 지금도 널리 사용되고 있다.
LSTM은 긴 의존 기간의 문제를 피하기 위해 명시적으로(explicitly) 설계되었다. 긴 시간 동안의 정보를 기억하는 것은 모델의 기본적인 행동에 포함시켜서 굳이 인위적으로 억지로 기억할려고 하게 하지 않도록 하였다.
모든 RNN은 neural network 모듈을 반복시키는 체인과 같은 형태를 하고 있다. 기본적인 RNN에서 이렇게 반복되는 모듈은 굉장히 단순한 구조를 가지고 있다. 예를 들어 tanh layer 한 층을 들 수 있다.

RNN의 반복 모듈이 단 하나의 layer를 갖고 있는 표준적인 모습이다

LSTM도 똑같이 체인과 같은 구조를 가지고 있지만, 각 반복 모듈은 다른 구조를 갖고 있다. 단순한 neural network layer 한 층 대신에, 4개의 layer가 특별한 방식으로 서로 정보를 주고 받도록 되어 있다.

LSTM의 반복 모듈에는 4개의 상호작용하는 layer가 들어있다.

가장 위쪽의 새로 생긴 라인 1개, σ\sigma(sigmoid 함수)가 있는 부분 3개로 모두 4개의 상호작용하는 layer가 추가되었다.
뜬금없이 복잡한 구조를 보고 너무 걱정하지 말자. 곧 하나씩 하나씩 LSTM의 구조를 뜯어 볼 것이다. 지금은 앞으로 계속 사용할 기호에 대해 친숙해지도록 정리해보자.

위 그림에서 각 선(line)은 한 노드의 output을 다른 노드의 input으로 vector 전체를 보내는 흐름을 나타낸다. 분홍색 동그라미는 vector 합과 같은 pointwise operation을 나타낸다. 노란색 박스는 학습된 neural network layer다. 합쳐지는 선은 concatenation을 의미하고, 갈라지는 선은 정보를 복사해서 다른 쪽으로 보내는 fork를 의미한다.

4. LSTM의 핵심 아이디어(core idea)

LSTM의 핵심은 cell state인데, 모듈 그림에서 수평으로 그어진 윗 선에 해당한다.
cell state는 컨베이어 벨트와 같은데, 약간의 linear 상호작용만 적용할 뿐 정보를 그대로 계속 흐르게 한다. 따라서 시간차가 큰 과거로부터의 입력도 쉽게 전달이 된다.

LSTM의 cell state

LSTM은 cell state에 뭔가를 더하거나 없앨 수 있는 능력이 있는데, 이 능력은 gate라고 불리는 구조에 의해서 조심스럽게 제어된다.
gate는 정보가 전달될 수 있는 추가적인 방법으로, sigmoid layer(σ\sigma표시된 사각형)와 pointwise 곱셈으로 이루어져 있다.(gate를 통해서 call state 내부의 값들을 중요도에 따라 조절할 수 있다.)

LSTM의 첫번째 gate

sigmoid layer는 0과 1 사이의 숫자를 내보내는데, 이 값은 각 컴포넌트가 얼마나 정보를 전달해야 하는지에 대한 척도를 나타낸다. 그 값이 0이라면 "아무 것도 넘기지 말라"가 되고, 값이 1이라면 "모든 것을 넘겨드려라"가 된다. 이 둘 사이의 어떠한 값으로 정보의 중요도에 따라 값의 크기가 조절된다.
LSTM은 3개의 gate를 가지고 있고(σ\sigma로 표시된 layer), 이 문들은 cell state를 보호하고 제어한다.

5. LSTM을 단계별로 알아보자.(Step-by-Step LSTM Walk Through)

5.1 forget gate layer

LSTM의 forget gate layer

LSTM의 첫 단계로는 cell state로부터 어떤 정보를 버릴 것인지를 정하는 것으로, sigmoid layer에 의해 결정된다. 그래서 이 단계의 gate를 "forget gate layer"라고 부른다. 이 단계에서는 ht1h_{t-1}xtx_t를 받아서 0과 1 사이의 값을 Ct1C_{t-1}에 보내준다. sigmoid 함수를 거치므로 그 값이 1이면 "모든 정보를 보존해라"가 되고, 0이면 "죄다 갖다버려라"가 된다. 1과 0사이의 값이면 중요도에 따라 전달할 값의 크기가 조절된다.
아까 얘기했던 이전 단어들을 바탕으로 다음 단어를 예측하는 언어 모델 문제로 돌아가보겠다. 여기서 cell state는 현재 주어의 성별 정보를 가지고 있을 수도 있어서 그 성별에 맞는 대명사가 사용되도록 준비하고 있을 수도 있을 것이다. 그런데 새로운 주어가 왔을 때, 우리는 기존 주어의 성별 정보를 생각하고 싶지 않을 것이다.(즉 새로운 정보로 업데이트되어 이전의 정보는 더 이상 의미가 없을 때 sigmoid에서 0에 가까운 값을 곱해주어 불필요한 정보는 대폭 줄여버린다.)

5.2 input gate layer

LSTM의 input gate layer

다음 단계는 앞으로 들어오는 새로운 정보 중 어떤 것을 cell state에 추가(저장)할 것인지를 정한다. 먼저, "input gate layer"라고 불리는 sigmoid layer가 어떤 값을 업데이트할 지 정한다. 그 다음에 tanh layer가 새로운 후보 값들인 C~t\tilde C_t 라는 vector를 만들고, cell state에 더할 준비를 한다. 이렇게 두 단계에서 나온 정보를 합쳐서 state를 업데이트할 재료를 만들게 된다.
다시 언어 모델의 예제에서, 기존 주어의 성별을 잊어버리기로 했고, 그 대신 새로운 주어의 성별 정보를 cell state에 더하고 싶을 것이다.(입력 정보들 중 기존 주어의 성별은 버리고 새로운 주어의 성별만 선택하는 것이 바로 input gate layer의 sigmoid layer의 역할이다.)

5.3 cell state update

LSTM의 cell state update

이제 과거 state인 Ct1C_{t-1} 를 업데이트해서 새로운 cell state인 CtC_t를 만들 것이다. 이미 이전 단계에서 어떤 값을 얼마나 업데이트해야 할 지 다 정해놨으므로 여기서는 그 일을 실천만 하면 된다.
우선 이전 state에 ftf_t를 곱해서 가장 첫 단계에서 잊어버리기로 정했던 것들을 진짜로 잊어버린다. 그리고 나서 itC~ti_t\ast \tilde C_t를 더한다. 이 더하는 값은 두 번째 단계에서 업데이트하기로 한 값을 얼마나 업데이트할 지 정한 만큼 scale한 값이 된다.
또 다시 언어 모델 문제로 돌아가보면, 이 단계에서 실제로 이전 주어의 성별 정보를 없애고 새로운 정보를 더하게 되는데, 이는 지난 단계들에서 다 정했던 것들을 실천만 하는 단계임을 다시 확인할 수 있다.

5.4 otput gate layer

LSTM의 output gate layer

마지막으로 무엇을 얼마만큼 output으로 내보낼 지 정하는 일이 남았다. 이 output은 cell state를 바탕으로 필터된 값이 될 것이다. 가장 먼저, sigmoid layer에 input 데이터를 태워서 cell state의 어느 부분을 얼마만큼 output으로 내보낼 지를 정한다. 그리고나서 cell state를 tanh layer에 태워서 -1과 1 사이의 값을 받은 뒤에 방금 전에 계산한 sigmoid gate의 output과 곱해준다. 그렇게 하면 우리가 output으로 보내고자 하는 부분만 내보낼 수 있게 된다. cell state값은 계속 누적되는 값이라 매우 클수도 아니면 음수로 매우 작을 수도 있다. 이를 -1~1사이의 값으로 맞추어 줄려고 tanh를 거치는 것이다.
(즉 cell state(Long Term Momory)에 output으로 내보낼 정보를 골라서(sigmoid layer를 거친 oto_t와 곱하기 연산이 걸러주는 역할을 한다.), 그림에는 안나와 있지만 여기에 각종 가중치들이 곱해져서 새로운 정보로 가공되어 출력 및 다음 단계의 입력으로 나간다.)
언어 모델로 예를 들어 생각해 보면, "I want to drink a cup of coffee. She also drink a cup of coffee with ___ favorite cup."문장에서 cell state(Long Term Memory)에서 주어에 해당하는 단어 I의 중요도는 20%로 줄어들고 She의 중요도 80%로 새로 추가가 되었다. 여기서 sigmoid를 통해 출력으로 She를 선택하면 이후 가중치 연산을 통해 She의 소유격인 'her'가 출력(output) 및 다음 단계의 입력으로 나간다. 주어가 단수형이냐 복수형이냐에 따라 소유격도 "her"가 될수도 "their"가 될 수도 있다.
예로 든 설명이 각 layer의 기능에 치중해서 설명하느라 충분하지 않고 좀 답답할 수도 있는데 일단 이렇게 이해하고 다음 기회에 보충 설명을 하도록 하겠다.

profile
바쁘게 부지런하게 논리적으로 살자!!!

0개의 댓글