-
LSTMDataScience/ML \ DL 2021. 8. 31. 21:53
수료하고도 세션 발표를 하는 흑우가 있다?
그건 바로 나 벗어날 수 없는 보아즈의 굴레...
Recurrent Neural Network
수능 영어 지문 빈칸 문제가 나왔다. 우린 그 빈칸을 전 단어들을 바탕으로 궁예할 것이다.
우리는 전에 봐왔던 걸 바탕으로 생각하지 그 전 정보들을 몽땅 집어치우고 생각을 하지 않는다. 이렇게 생각이 계속 나아가는 것인데, 전통적인 neural network는 이전에 일어난 사건을 바탕으로 나중에 일어나는 사건을 생각하지 못한다. RNN은 이 문제를 해결하려고 스스로를 반복하면서 이전 단계의 정보가 계속 지속되도록 한다.
-
CNN를 생각해보면 이미지를 input으로 넣을 때 tensor size를 똑같이 64*64, 128*128, .. 로 맞춰서 넣었었다.
그런데 sequential data의 경우 잠깐 문장들만 생각해봐도 그 사이즈가 다 제각각이다. 이렇게 input sequence, output sequence가 모두 가변 길이일 수 있는데, RNN은 이 가변적 길이에 대응할 수 있는 general한 tool이다.
_ A는 RNN의 한 덩어리이다. A는 input x_t를 받아서 를 내보낸다. A를 둘러싼 반복은 다음 단계에서의 network가 이전 단계의 정보를 받는다는 것을 보여준다.
이러한 RNN의 반복 구조는 혹여 불가사의해 보일 수도 있겠지만, 조금 더 생각해보면 RNN은 기존 neural network와 그렇게 다르지 않다는 것을 알 수 있다. RNN을 하나의 network를 계속 복사해서 순서대로 정보를 전달하는 network라고 생각하는 것이다. 아예 반복을 풀어버리면 좀 더 이해하기 쉬울 것이다.
RNN에서 주목해야 하는 특징 !! 바로 저 input에서 output으로 가는 과정에서 Recurrent하게 다시 들어가는 저 state다.
RNNs have an 'internal state' that is updated as a sequence is processed.
이렇게 RNN의 체인처럼 이어지는 성질은 곧장 sequence나 list로 이어지는 것을 알려준다. 이런 데이터를 다루기에 최적화된 구조의 neural network인 것이다.
그리고 진짜로 그렇게 사용되고 있다! 지난 몇 년 동안, RNN은 음성 인식, 언어 모델링, 번역, 이미지 주석 생성 등등등등의 다양한 분야에서 굉장한 성공을 거두었다.
-
긴 의존 기간으로 인한 문제점
RNN의 성공의 열쇠는 "Long Short-Term Memory Network" (이하 LSTM)의 사용이다. LSTM은 RNN의 굉장히 특별한 종류로, 아까 얘기했던 영화를 frame 별로 이해하는 것과 같은 문제들을 단순 RNN보다 정말 훨씬 진짜 잘 해결한다. 기존 RNN도 LSTM만큼 이런 일을 잘 할 수 있다면 RNN은 대단히 유용할텐데, 아쉽게도 RNN은 그 성능이 상황에 따라 그 때 그 때 다르다.
우리가 현재 시점의 뭔가를 얻기 위해서 멀지 않은 최근의 정보만 필요로 할 때도 있다. 예를 들어 이전 단어들을 토대로 다음에 올 단어를 예측하는 언어 모델을 생각해 보자. 만약 우리가 "the clouds are in the sky"에서의 마지막 단어를 맞추고 싶다면, 저 문장 말고는 더 볼 필요도 없다. 마지막 단어는 sky일 것이 분명하다. 이 경우처럼 필요한 정보를 얻기 위한 시간 격차가 크지 않다면, RNN도 지난 정보를 바탕으로 학습할 수 있다.
하지만 반대로 더 많은 문맥을 필요로 하는 경우도 있다. "I grew up in France... I speak fluent French"라는 문단의 마지막 단어를 맞추고 싶다고 생각해보자. 최근 몇몇 단어를 봤을 때 아마도 언어에 대한 단어가 와야 될 것이라 생각할 수는 있지만, 어떤 나라 언어인지 알기 위해서는 프랑스에 대한 문맥을 훨씬 뒤에서 찾아봐야 한다. 이렇게 되면 필요한 정보를 얻기 위한 시간 격차는 굉장히 커지게 된다.
안타깝게도 이 격차가 늘어날 수록 RNN은 학습하는 정보를 계속 이어나가기 힘들어한다.
이론적으로는 RNN이 이러한 "긴 기간의 의존성(long-term dependencies)"를 완벽하게 다룰 수 있다고 한다. 그리고 단순한 예제에 대해서는 사람이 신중하게 parameter를 골라서 그 문제를 해결할 수도 있다. 하지만 RNN은 실제 문제를 해결하지 못 하는 것이 슬픈 현실이다. 이 사안에 대해 Hochreiter (1991)과 Bengio 외 (1994)가 심도있게 논의했는데, RNN이 긴 의존 기간의 문제를 어려워하는 꽤나 핵심적인 이유들을 찾아냈다.
고맙게도 LSTM은 문제 없다!
짧은 기간에 의존하는 RNN 긴 기간에 의존하는 RNN rnn 번역체는 나중에 더 뜯어고치기로 하자.
왜냐 난 시간이 없어
-
RNN의 한계 ; Grandient Vanishing/Exploding
RNN은 과거의 데이터값들을 기억하지만, Layer가 Deep해질수록 점점 과거의 값들이 "희석"되는 문제가 발생한다. 예를 들면, t-1의 값들은 t 상태에서 잘 가지고 있지만, t-100의 값들은 거의 영향력이 없을 것이다. 이러한 과거 데이터들이 희석되는 문제점을 고쳐준 것이 바로 "LSTM(Long Short Term Memory"다.
-
LSTM은 긴 의존 기간이 필요할 때 사용하는 RNN의 특별 케이스다. 긴 의존 기간이 필요할 때, 즉 기억해야 하는 정보의 시점이 길어질 때 RNN에서 나타나는 Gradient Vanishing, Grandient Exploding 문제를 cell state를 추가한 구조로 해결하는게 LSTM의 핵심이다.
-
LSTM은 긴 의존 기간의 문제를 피하기 위해 명시적으로(explicitly) 설계되었다. 여기서 "명시적으로"라는게 앞 문장의 cell state 다. 긴 시간 동안의 정보를 기억하는 것은 모델의 기본적인 소양이지, 모델이 그것을 배우기 위해서 애쓰는건 모델로써 가오가 안살기 때문이다.
모든 RNN은 neural network 모듈을 반복시키는 체인과 같은 형태를 하고 있다. 기본적인 RNN에서 이렇게 반복되는 모듈은 굉장히 단순한 구조를 가지고 있다. tanh layer 한 층만 가지고 있으니 말이다.
RNN의 반복 모듈이 단 하나의 layer를 갖고 있는 표준적인 모습이다. 수식으로 보자.
RNN의 score function은
얘였는데 backpropgation으로 downstream gradient를 구하면
이런식(...)이다. 라텍스로 이걸 엌케 찍누 사진 찍으면 자동 수식으로 예쁘게 변환해주는 모델 주세요 이거 나중에 해봐야지! 나..중에^^
여기서 볼 수 있듯이 backward로 downstream gradient를 구할 때 매번 recurrent unit을 지나오는 과정에서 W_hh(T) 행렬이 제곱으로 계속 곱해진다. 그럼 이 W_hh(T) 행렬의 largest singular value가 1보다 작으면 singular value composition 정의에 의해 W_hh(T) 에 곱해지는 x 입장에서는 x의 모든 축에 대해 1보다 작은 수를 곱하는 것이다. 즉, 들어오는 gradient x가 vanishing되는 문제가 발생한다.
해당 문제는 RNN 구조를 LSTM 과 같은 구조로 바꿈으로써 해결할 수 있다. 앞에서 한 두 번 정도 스포한 것 같은데 LSTM은 정보 갱신을 책임지고 관할하는 cell state C_t 를 채용해서 hidden state h_t 는 정보 출력만 관할할 수 있도록 한다. 이를 통해 C_t 쪽으로 gradient가 방해받지 않으면서 흐를 수 있는 것이다.
일단 또 이미지화해서 보면 아래 그림과 같다. LSTM도 RNN처럼 체인같은 구조를 가지고 있지만, 각 반복 모듈의 구조는 다르다. 단순한 neural network layer 한 층 대신에, 4개의 layer가 특별한 방식으로 서로 정보를 주고 받도록 되어 있다.
LSTM의 반복 모듈에는 4개의 상호작용하는 layer가 들어있다. 복잡해 보인다. 당연함. 이제 이 복잡해 보이는 LSTM의 구조를 뜯어 볼 것이다. 일단 저 이미지들의 기호가 나타내는 걸 보면
각 선(line)은 한 노드의 output을 다른 노드의 input으로 vector 전체를 보내는 흐름을 나타낸다. 분홍색 동그라미는 vector 합과 같은 pointwise operation을 나타낸다. 노란색 박스는 학습된 neural network layer다. 합쳐지는 선은 concatenation을 의미하고, 갈라지는 선은 정보를 복사해서 다른 쪽으로 보내는 fork를 의미한다.
수식으로 보면 아까 Vanilla RNN score function은
이렇게 생겼었는데, LSTM의 score function은
이렇다. i, f, o, g는 각각 input gate, forget gate, output gate, gate gate이다. 각 gate에 대한 자세한 설명은 뒤에서 좀 더 풀고 일단 이런 LSTM구조가 왜 앞에 gradient vanishing 문제를 해결하는지 수학적으로 오케이이제말하부자.(나랑마크가하겠다)
c_t는 cell state고 h_t는 hidden state인데, 각 timestamp에서의 두 벡터는 위의 수식처럼 연산된다.
식을 보면 h_t는 t번째 cell state(c_t)에 tanh 비선형 활성함수 먹여서 output gate에서 얼만큼 남길건지, 얼만큼 죽일건지 0~1사이 값으로 정해서 내보낸다. 즉, 정보 출력만 관여하고 실제 정보의 갱신은 cell state에서 관할한다.
t번째 timestamp에서의 cell state c_t도 뜯어보면 t-1번째 cell state 값에 0~1 사이 값을 곱해서 얼만큼 forget 할건지(1에 가까운 값일수록 더 살리는 거겠쥬?) + c_t를 업데이트하는 단계에서 얼마나 c_t cell state가 새로 얼마나 쓸지 -1 ~ 1 사이값을 갖는 gate 벡터를 통해 정한다. 그니까 cell state로 gradient가 쭉쭉 올라올때 downstream gradient 구하면 c_t 에서 c_t-1로의 backpropagation은 W랑 matrix multiplication이 아니라 단순히 f 와의 elementwise multiplication이다.
LSTM 구조 더 뜯어보기
LSTM의 핵심은 cell state인데, 모듈 그림에서 수평으로 그어진 윗 선에 해당한다.
Cell state는 컨베이어 벨트와 같아서, 작은 linear interaction만을 적용시키면서 전체 체인을 계속 구동시킨다. 정보가 전혀 바뀌지 않고 그대로 흐르게만 하는 것은 매우 쉽게 할 수 있다.
LSTM의 cell state LSTM은 cell state에 뭔가를 더하거나 없앨 수 있는 능력이 있는데, 이 능력은 gate라고 불리는 구조에 의해서 조심스럽게 제어된다.
Gate는 정보가 전달될 수 있는 추가적인 방법으로, sigmoid layer와 pointwise 곱셈으로 이루어져 있다.
LSTM의 첫 번째 gate Sigmoid layer는 0과 1 사이의 숫자를 내보내는데, 이 값은 각 컴포넌트가 얼마나 정보를 전달해야 하는지에 대한 척도를 나타낸다. 그 값이 0이라면 "아무 것도 넘기지 말라"가 되고, 값이 1이라면 "모든 것을 넘겨드려라"가 된다.
LSTM은 3개의 gate를 가지고 있고, 이 문들은 cell state를 보호하고 제어한다.
단계별로 두들겨보는 LSTM
LSTM의 첫 단계로는 cell state로부터 어떤 정보를 버릴 것인지를 정하는 것으로, sigmoid layer에 의해 결정된다. 그래서 이 단계의 gate를 "forget gate layer"라고 부른다. 이 단계에서는 ht−1과 xt를 받아서 0과 1 사이의 값을 Ct−1에 보내준다. 그 값이 1이면 "모든 정보를 보존해라"가 되고, 0이면 "죄다 갖다버려라"가 된다.
아까 얘기했던 이전 단어들을 바탕으로 다음 단어를 예측하는 언어 모델 문제로 돌아가보겠다. 여기서 cell state는 현재 주어의 성별 정보를 가지고 있을 수도 있어서 그 성별에 맞는 대명사가 사용되도록 준비하고 있을 수도 있을 것이다. 그런데 새로운 주어가 왔을 때, 우리는 기존 주어의 성별 정보를 생각하고 싶지 않을 것이다.
LSTM의 forget gate layer 다음 단계는 앞으로 들어오는 새로운 정보 중 어떤 것을 cell state에 저장할 것인지를 정한다. 먼저, "input gate layer"라고 불리는 sigmoid layer가 어떤 값을 업데이트할 지 정한다. 그 다음에 tanh layer가 새로운 후보 값들인 C~t 라는 vector를 만들고, cell state에 더할 준비를 한다. 이렇게 두 단계에서 나온 정보를 합쳐서 state를 업데이트할 재료를 만들게 된다.
다시 언어 모델의 예제에서, 기존 주어의 성별을 잊어버리기로 했고, 그 대신 새로운 주어의 성별 정보를 cell state에 더하고 싶을 것이다.
LSTM의 input gate layer 이제 과거 state인 Ct−1를 업데이트해서 새로운 cell state인 Ct를 만들 것이다. 이미 이전 단계에서 어떤 값을 얼마나 업데이트해야 할 지 다 정해놨으므로 여기서는 그 일을 실천만 하면 된다.
우선 이전 state에 ft를 곱해서 가장 첫 단계에서 잊어버리기로 정했던 것들을 진짜로 잊어버린다. 그리고나서 it∗C~t를 더한다. 이 더하는 값은 두 번째 단계에서 업데이트하기로 한 값을 얼마나 업데이트할 지 정한 만큼 scale한 값이 된다.
또 다시 언어 모델 문제로 돌아가보면, 이 단계에서 실제로 이전 주어의 성별 정보를 없애고 새로운 정보를 더하게 되는데, 이는 지난 단계들에서 다 정했던 것들을 실천만 하는 단계임을 다시 확인할 수 있다.
LSTM의 cell state 업데이트 마지막으로 무엇을 output으로 내보낼 지 정하는 일이 남았다. 이 output은 cell state를 바탕으로 필터된 값이 될 것이다. 가장 먼저, sigmoid layer에 input 데이터를 태워서 cell state의 어느 부분을 output으로 내보낼 지를 정한다. 그리고나서 cell state를 tanh layer에 태워서 -1과 1 사이의 값을 받은 뒤에 방금 전에 계산한 sigmoid gate의 output과 곱해준다. 그렇게 하면 우리가 output으로 보내고자 하는 부분만 내보낼 수 있게 된다.
이제 언어 모델 예제를 생각해보면, 우리는 주어를 input으로 받았으므로 주어 다음에 오게 될 예측값인 output으로 적절한 답은 아마도 동사 개념의 무언가가 될 것이다. 예를 들어 최종적인 Output은 앞에서 본 주어가 단수형인지 복수형인지에 따라 그 형태가 달라질 수도 있는 것이다.
LSTM의 output gate layer LSTM의 변형 모델들
Gated Recurrent Unit (이하 GRU)가 Cho 외 (2014)에서 소개되었다. 이 모델은 forget gate와 input gate를 하나의 "update gate" 합쳤고, cell state와 hidden state를 합쳤고, 또 다른 여러 변경점이 있다. 결과적으로 GRU는 기존 LSTM보다 단순한 구조를 가진다. GRU는 점점 더 유명해지고 있다.