포스팅 참고 문헌

1. Do it! 딥러닝 교과서 (윤성진 지음)
2. MIT 6.S191: Recurrent Neural Networks, Transformers, and Attention (바로가기)
3. https://colah.github.io/posts/2015-08-Understanding-LSTMs/
4. SK플래닛 T아카데미 강사님 수업자료

RNN

[1] 시퀀스 데이터

흔히 '시계열 데이터', '순차 데이터'라고도 부르는 Sequence data에는 시공간적 순서 관계가 포함되어 있습니다. 예를 들어서 지금 저는 커피 한 모금을 마시고 컵을 내려놓은 뒤 타자를 치고 있고, 창 밖에는 차와 사람들이 움직이고 있으며, 옆에 있는 친구는 음악을 듣고 있어요. 이러한 일들이 일어날 때 자연스레 시간이 흐르고 공간상의 움직임도 나타나게 되지요. 이런 시퀀스 데이터는 문맥(context)을 가지기 때문에 어느 한 순간의 데이터만 살펴봐서는 그 특성을 이해하기가 어렵습니다.

예를 들어 우리가 위의 그림만 보고 공이 다음에 어느 방향으로 움직일지 논리적으로 예측하기는 무척 어렵습니다. 공이 옆에서 굴러왔을지, 밑에서 떨어졌을지, 위에서 던졌을지, 시공간 정보에 대한 어떤 문맥도 주어지지 않았기 때문입니다.

반면에 이렇게 공이 움직여 온 과정 대한 정보가 주어진다면, 우리는 아주 자연스럽게 공이 오른쪽 방향으로 움직일 것이라고 합리적으로 예측할 수 있게 됩니다. 이렇게 데이터의 순차 구조를 인식하고 처리할 수 있는 인공 신경망이 바로 RNN : 순방향 신경망(Recurrent Neural Network)입니다. RNN은 아래와 같은 구조로 이루어져 있습니다.


[2] RNN 기본 구조와 원리

RNN의 구조

첫 번째 입력 x1에 weight X를 곱한 값 => 히든 레이어 h1
{(두 번째 입력 x2에 weight X를 곱한 값) + (전 단계 h1에 weight H를 곱하고 bias를 더한 값)}에 하이퍼탄젠트(tanh) 액티베이션 펑션을 걸어주면 => 히든 레이어 h2
{(세 번째 입력 x3에 weight X를 곱한 값) + (전 단계 h2에 weight H를 곱하고 bias를 더한 값)}에 하이퍼탄젠트(tanh) 액티베이션 펑션을 걸어주면 => 히든 레이어 h3
....
{(t 번째 입력 xt에 weight X를 곱한 값) + (전 단계 h(t-1)에 weight H를 곱하고 bias를 더한 값)} 하이퍼탄젠트(tanh) 액티베이션 펑션을 걸어주면 => 히든 레이어 ht

이를 수식으로 나타내면 아래와 같아집니다.


[3] RNN의 weight

RNN에서 사용되는 가중치 Wx, Wh, Wy는 모든 시간 단계에서 공유되는데, 그 이유는 다음과 같습니다.

  1. 순차 구조를 포착할 수 있기 때문입니다.
    :  RNN의 주된 목적 중 하나는 시퀀스 데이터의 순차적 특성을 학습하는 것입니다. 이를 위해서는 각 시간 단계에서 입력과 은닉 상태를 동일한 방식으로 처리해야 합니다. Wx(입력 가중치), Wh(은닉 상태 가중치), Wy(출력 가중치)를 시간 단계마다 공유함으로써 네트워크는 시간 순서에 따라 일관된 방식으로 데이터를 처리할 수 있습니다.
  2. 가변 길이 데이터 처리가 용이하기 때문입니다.
    :  RNN은 고정된 길이의 입력만 처리하는 것이 아니라 가변 길이의 시퀀스 데이터도 처리할 수 있습니다. 모든 시간 단계에서 동일한 가중치를 사용하면, 시퀀스의 길이가 어떻게 되든 간에 동일한 모델 구조로 일관된 학습과 예측이 가능해집니다. 따라서 입력 시퀀스의 길이가 다르더라도 동일한 가중치 매트릭스를 사용하여 각 단계의 데이터를 처리할 수 있습니다.
  3. 파라미터 수가 절약되고, 정규화 효과가 생깁니다.
    :  각 시간 단계마다 다른 가중치를 사용한다면 파라미터 수가 급격히 증가하여 학습이 비효율적이 될 수 있습니다. 모든 시간 단계에서 가중치를 공유함으로써 파라미터 수를 크게 줄일 수 있습니다. 이는 모델의 복잡도를 낮추고, 과적합(overfitting)을 방지하는 데 도움이 됩니다. 또한, 적은 수의 파라미터를 통해 더 나은 일반화 성능을 얻을 수 있습니다. 이는 정규화 효과와 유사한 역할을 하여 모델이 더 일반화된 패턴을 학습하는 데 기여합니다.

[4] RNN Loss Function & Backpropagation

RNN의 전체 Loss Function은 모든 단계의 Loss Function을 더해서 정의합니다. 각 단계의 Loss Function은 회귀 문제라면 주로 MSE, 분류 문제라면 주로 Cross Entropy로 정의하게 됩니다.

RNN의 Backpropagation은 BPTT(Back Propagation Through Time), 시간펼침 역전파 알고리즘이라고도 불리는데요. 말그대로 시간 순서대로 네트워크를 펼쳐서 역전파를 수행하는 알고리즘입니다. BPTT는 아래와 같은 단계로 이루어집니다.

BPTT

1. 모든 시간 단계(t)마다 오차를 계산하고, 이를 이전 시간 단계로 전파합니다.
2. 모든 단계에서 가중치 및 바이어스에 대한 기울기를 구합니다.
3. 구한 기울기를 이용하여 각 가중치와 바이어스를 업데이트합니다.
-> 이를 통해 모델이 점차 학습하여 더 나은 예측을 할 수 있게 됩니다.

 


[5] RNN 한계점

예를 들어서, 한국에서 태어난 수리링은 인공지능 공부를 열심히 하고 있는데, 수리링은 영어도 잘 하지만 사실 한국말을 제일 잘한다. 라는 문장이 있다고 해 봅시다. RNN 모델에게 빈칸에 들어갈 말이 무엇인지 추측하도록 시킨다고 할 때, 모델이 정답을 잘 맞추기 위해서는 문장의 가장 처음에 있는 '한국'이라는 단어의 정보를 제대로 활용할 수 있어야 합니다. 만약 '한국'이라는 단어의 중요도가 점점 소실된다면 뜬금없이 빈칸에 '스페인어'나 '영어' 등의 오답이 들어가는 경우가 발생하겠죠. 이것이 바로 RNN의 근본적인 문제점입니다. (아, 참고로 빈 칸에 들어갈 정답은 '한국말' 입니다. ^^)

Long-term Dependency

RNN은 오차가 멀리 전파될수록(시간이 지날수록) 기울기가 점차 작아지는(0으로 수렴하는) 'Vanishing Gradient'로 인해 입력 데이터의 영향이 점점 사라지는 'Long-term Dependency'라는 명확한 한계를 가지고 있습니다. 또 가중치가 반복적으로 곱해지는 과정에서 기울기가 폭발적으로 발산하는 불상사로 인해 정상적인 학습이 불가능해지는 Exploding Gradient 문제도 쉽게 발생하곤 합니다. 이러한 문제점을 해결하기 위해 gradient clipping이나 오차를 몇 단계까지만 전파시키는 생략된-BPTT(truncated BPTT) 등을 사용하기도 했지만, 시간이 지나면서 사람들은 LSTM 및 GRU를 많이 사용하게 되었습니다.



LSTM

[1] 핵심

LSTM은 기본 RNN 구조를 변경해서 만든 모델입니다. LSTM의 핵심 아이디어는 바로 Gate & Cell State인데요.

이전의 RNN은 모든 정보를 연쇄적으로 곱해주는 방식으로 계산했기 때문에 역전파 과정에서 Vanishing/Exploding Gradient 같은 문제점이 발생했습니다. 이를 방지하고자 LSTM은 게이트가 있는 Gated cell을 사용하여 선택적으로 정보를 조절해 학습할 수 있도록 합니다. 이는 장기 기억(Long Term Memory)과 단기 기억(Short Term Memory)이라는 두 가지 메커니즘(LSTM)으로 구현되는 것으로 볼 수 있어 LSTM이라는 이름이 붙게 되었습니다.

기본 RNN은 위처럼 매우 심플한 구조로 이루어져 있습니다. (Xt * Wx + Ht-1 * Wh)에 활성함수로 하이퍼탄젠트(tanh)를 곧바로 걸어주게 되고, 이것이 순차 반복적으로 곱해지면서 Vanishing/Exloding Gradient 문제가 발생하게 되는 건데요.

LSTM의 경우, 내부 구조가 위의 사진처럼 세부 단계로 나뉘어져 있습니다. 처음 보면 무척 복잡해 보이지만, 한 번 이해하고 나면 꽤나 심플한 아이디어로 구성되어 있음을 알 수 있게 됩니다.


[2] Gate

Cell State : C

LSTM을 이끄는 핵심은 Cell state, 그림 상단에 보이는 Ct 라인입니다. Cell state는 마치 컨베이어 벨트와 역할을 하면서 레이어 사이를 지나가는데요. LSTM은 이 Cell state에 새로운 정보를 선택적으로 추가하기도 하고, 기존의 정보를 삭제하기도 합니다. 근데 도대체 어떻게 이런 일이 가능한 걸까요? 만약 이런 의문이 드신다면, 당신은 정상인입니다. 바로 게이트(Gate)가 있기 때문에 가능합니다.

그럼 정확히 Gate가 무엇이냐?라고 하신다면, 참고문헌 [3]은 They are composed out of a sigmoid neural net layer and a pointwise multiplication operation이라고 기술하고 있습니다.

gate
sigmoid neural net layer
: 시그모이드 함수는 0부터 1 사이의 값을 출력하기 때문에, 비율의 관점에서 바라볼 수 있습니다. 시그모이드 출력값이 0이라면 정보를 삭제하는 것과 같을 것이고, 시그모이드 출력값이 1이라면 정보를 100% 통과시켜야 함을 의미하겠죠.

pointwise multiplication operation
: 
시그모이드 함수의 출력값, 즉 '비율'을 곱한 다음, 이렇게 중요도가 결정된 정보가 게이트를 통과하게 되는 것입니다.

즉, 그냥 단순히 정보를 마구잡이로 곱하는 방식이 아니라, 각 정보의 중요도를 반영한 값을 처리할 수 있는 매커니즘을 구현하겠다는 겁니다. 만약 쓸데 없는 정보가 들어온다면 입뺀을 먹이고 통과를 시켜주지 않을 것이고, 필요한 정보가 들어온다면 중요도에 따라 필터링을해서 통과시켜 주겠다는 것이죠. LSTM은 세 가지 주요 게이트를 사용하여 정보를 조절합니다.


[3] Gate 종류

  • Forget Gate : 과거 정보를 얼마나 유지할 것인지
  • Input Gate : 현 시점의 입력 정보를 Cell State에 얼만큼 반영할 것인지
  • Output Gate : 현 시점에서 정보를 얼만큼 출력해서 다음 시점에 제공할지

3-1. Forget Gate 

현 시점의 입력 정보 Xt와 지난 레이어h(t-1)를 종합한 정보에 시그모이드를 걸어 비율값을 만들어 준 다음, 이전의 Cell State와 곱해줍니다. 시그모이드 값이 작을수록 이전의 정보는 많이 소실되고, 시그모이드 값이 클수록 이전의 정보는 많이 유지되겠죠. 즉, forget gate는 과거 정보를 얼마나 유지할 것인지 판단하는 게이트입니다. 

3-2. Input Gate 

인풋 게이트는 다음과 같은 구조로 흘러갑니다.

현 시점의 입력 정보 Xt와 지난 레이어h(t-1)를 종합한 정보에 

  1. 하나는 시그모이드를 걸어 0과 1사이의 비율값으로 만들어줍니다.
  2. 또 하나는 RNN처럼 활성함수로 하이퍼탄젠트(tanh)를 걸어줍니다.
  3. 두 개의 값을 곱해줍니다.
  4. Forget Gate를 지난 Cell State에 그 값을 더해줍니다.

즉, 인풋 게이트는 현 시점의 입력 정보를 Cell State에 얼만큼 반영할 것인지 판단하는 게이트입니다. 인풋 게이트를 통과한 정보가 더해지고 나면, 현 시점 LSTM에서의 Cell State가 완성됩니다. 이 Cell State는 다음 시점의 LSTM으로 전달되어, 또 다시 Forget Gate를 통과한 정보와 곱해지게 되겠죠. 

3-3. Output Gate 

아웃풋 게이트는 다음과 같은 구조로 흘러갑니다.

  1. 현 시점의 입력 정보 Xt와 지난 레이어h(t-1)를 종합한 정보에 시그모이드를 걸어 0-1사이의 비율값으로 만들어 줍니다.
  2. Cell State 값에 활성함수로 하이퍼탄젠트(tanh)를 걸어줍니다.
  3. 두 값을 곱해서 다음 시점의 h값으로 제공합니다.

즉, 현 시점의 output payer를 통과한 값은 다음 시점의 입력 정보와 만나는 h값이 되는 것입니다. 따라서 Output layer는 현 시점에서 정보를 얼만큼 출력해서 다음 시점에 제공할지 판단하는 레이어라고 볼 수 있습니다. 참고문헌 [3]에서는 Output gate를 지난 output을 다음과 같이 표현하고 있습니다. This output will be based on our cell state, but will be a filtered version. 


[4] LSTM의 장점

LSTM에서 셀들의 상태를 연결하는 경로를 다시 한 번 살펴보겠습니다.

LSTM은 셀들의 상태를 연결하는 경로에서 행렬곱을 생략하고, 대신 Cell State 개념을 도입했습니다. 기억 정보들은 Gate를 지나면서 선택적으로 형성, 지속, 망각되는 과정을 거치고, 그 과정이 담긴 Cell State에서 단기 기억과 장기 기억이 상호작용하며 유지됩니다. 이러한 획기적인 아이디어가 기존 RNN에서 Vanishing Gradient를 유발하는 요인이었던 반복적인 행렬 곱 연산을 대체하게 되면서 중요한 정보가 시퀀스의 초반부에서 후반부까지 소멸되지 않고 유지될 수 있었고, Long-term Dependency 문제를 해결할 수 있었습니다.



GRU

GRU(Gated Recurrent Unit)는 LSTM(Long Short-Term Memory)의 단순화된 버전으로, 구조를 단순화해서 계산 효율성을 높인 모델입니다.

출처 : http://dprogrammer.org/rnn-lstm-gru

  • Cell state와 Hidden state의 통합
    • 가장 도드라지는 차이점은 Cell State가 사라졌다는 점입니다.
    • LSTM은 Cell state(상단 C)와 Hidden state(하단 h)를 별도로 유지합니다. Cell state는 장기 기억을 저장하고, Hidden state는 단기 기억과 출력을 담당합니다.
    • 반면에 GRU는 둘을 통합하여 단일 Hidden state로 처리합니다. 이를 통해 모델이 더 간단해지고, 계산 효율성이 향상됩니다.
  • 게이트의 변화
    • LSTM은 세 가지 게이트를 가지고 있습니다. (Forget/Input/Output Gate)
    • GRU는 두 가지 게이트를 가지고 있습니다. (Reset/Update Gate)
    • 리셋 게이트(r)는 이전 은닉 상태를 얼마나 초기화할지를 결정하고, 업데이트 게이트(z)는 새로운 정보와 기존 정보를 어떻게 결합할지를 결정합니다.

GRU는 이러한 구조적 단순화를 통해 LSTM의 복잡성을 줄이면서도 유사한 성능을 유지할 수 있도록 설계되었습니다. 만약 컴퓨팅 리소스가 제한된 환경에 있다면, LSTM보다 계산량이 적으면서도 비슷한 성능을 가진 GRU를 사용하는 것이 효율적이겠습니다.


이것으로 RNN / LSTM / GRU 포스팅을 마치도록 하겠습니다. 다음 포스팅에서는 Transformer 논문 리뷰를 해보겠습니다 :) 감사합니다!

+ Recent posts