[NLP] RNN, LSTM, Attention

2024. 3. 31. 15:04ML/NLP

순차적인 데이터 (Sequence Data)

시퀀스 데이터는 순차적으로(=순서에 따라 연속적으로) 들어오는 데이터를 의미하며 대표적인 예로 시계열 데이터가 존재한다.

시퀀스 데이터는 순서에 따라 데이터가 들어오기 때문에  i.i.d(independent and identically distribution) 가정을 잘 위배한다.

그렇기 때문에 데이터 포인트의 순서가 바뀌거나 이전 데이터 포인트의 손실이 발생할 경우 데이터의 확률분포가 완전히 바뀌게 된다.

Sequential Model

아래와 같이, 시퀀스 데이터의 확률분포는 조건부 확률을 활용해 모델링할 수 있다.

$$P(X_1, \cdots, X_T) = \prod_{t=1}^T P(X_t|X_{t-1}, \cdots, X_1)$$

그렇기 때문에, 시퀀스 데이터의 확률분포를 모델링하는 것은, 시퀀스 데이터의 조건부 확률분포를 모델링하는 것과 같다.

$$X_t \sim P(X_t|X_{t-1}, \cdots, X_1)$$

하지만, 시퀀스 데이터의 길이는 가변적이기 때문에 가면 갈수록 고려해야 하는 조건이 점점 많아진다는 어려움이 있다.

$$X_t \sim P(X_t|X_{t-1}, \cdots, X_1)$$

$$X_{t+1} \sim P(X_{t+1}|X_t, \cdots, X_1)$$

 

언어 모델 (Language Model)

언어 모델은 텍스트 데이터에 대한 확률분포 $p(w_1, w_2, \cdots, w_n)$를 의미하며, 이도 조건부 확률분포인 $p(w_t|w_{t-1}, w_{t-2}, \cdots, w_1)$로 모델링할 수 있다.

참고로, 대부분 (조건부) 언어 모델은 분포 $p_{Y|X}$를 multinoulli 분포로 가정하기 때문에, 손실 함수로 cross-entropy를 사용한다.

자기회귀모델 (Auto-regressive Model)

시퀀스 데이터의 조건부 확률분포를 모델링할 때 이전 데이터 포인트 전부가 항상 필요한 것은 아니다.

그렇기 때문에, 고정된 길이 $\tau$ 만큼의 이전 데이터 포인트만 사용해 조건부 확률분포를 모델링하는 방식이 제안되었으며, 해당 방식으로 모델링한 것을 자기회귀모델이라 한다.

$$X_t \sim P(X_t|X_{t-1}, \cdots, X_{t-\tau})$$

$$X_{t+1} \sim P(X_{t+1}|X_t, \cdots, X_{t+1-\tau})$$

참고로, 대표적인 AR 모델로는 직전의 데이터 포인트만 조건으로 사용하는 markov model이 있다.

$$X_t \sim P(X_t|X_{t-1})$$

잠재 자기회귀모델 (Latent Auto-regessive Model)

auto-regressive model은 과거의 많은 정보를 버려야 한다는 단점 뿐만 아니라,

적절한 $\tau$를 찾는 것이 매우 어려울 뿐만 아니라 데이터가 변함에 따라 적절한 $\tau$도 바뀔 수 있다는 단점이 있다.

 

해당 단점을 보완하기 위해, 직전 데이터 포인트를 제외한 나머지 데이터 포인트를 $H_t$라는 잠재변수로 인코딩해 이전 정보를 요약하는 방식이 제안되었으며, 해당 방식으로 조건부 확률분포를 모델링한 것을 잠재 자기회귀모델이라 한다.

$$X_t \sim P(X_t|X_{t-1}, H_{t-1})$$

$$X_{t+1} \sim P(X_{t+1}|X_t, H_t)$$

해당 모델은 이전 정보($\mathbf x_{<t}$)를 모두 활용할 수 있을 뿐만 아니라, 가변적인 데이터를 고정적인 데이터로 변환해 이전 한계점들을 해결했다.

RNN (Recurrent Neural Network)

시퀀스 데이터 포인트의 인코딩하는 방식으로 다음과 같은 인공 신경망 구조가 제안되었다.

$$\mathbf h_t = \text{Net}_\theta(\mathbf h_{t-1}, \mathbf x_{t-1})$$

수식에서 알 수 있듯이, 직전 출력값이 다시 입력값으로 들어오는 순환 구조를 갖는 인공 신경망으로 기존 인공 신경망 구조와 결이 다르다.

 

그럼, 위와 같은 구조의 인공 신경망으로 시퀀스 데이터의 조건부 확률분포를 모델링하면 다음이 표현할 수 있으며, 이를 Recurrent Nerual Network라 정했다.

$$\hat{\mathbf y}_t = \mathbf h_t W_y + \mathbf b_y$$

$$\mathbf h_t = \tanh(\mathbf x_t \mathbf W_x + \mathbf h_{t-1} \mathbf W_h + \mathbf b)$$

 

 

RNN은 순환 구조이기 때문에, $\mathbf W_x$, $\mathbf W_h$, $\mathbf W_y$, $\mathbf b$, $\mathbf b_y$는 시점 $t$에 따라 변하지 않는다. 즉, 고정되어 있다.

참고로, sigmoid 함수 대신 tanh 함수를 사용한 이유는 기울기 손실에 유리하기 때문이다.

(sigmoid의 최대 기울기=1/4, tanh의 최대 기울기=1)

그리고, sigmoid 함수를 사용하면 $\mathbf h_t$의 각 요소가 점점 saturated 되어 유의미한 정보를 가지기 어렵다.

RNN의 구조적 한계 (특성?)

1. forward propagation(no long-term dependency): $\mathbf h_t$가 갖고 있는 $\mathbf x_{<t}$의 정보시간이 흐름에 따라 흐려질 뿐만 아니라 왜곡된다. $\mathbf W_h$과 $\tanh$ 연산은 각각 정보를 왜곡시키고 흐려지게 하기 때문이다.

$$\mathbf h_t = \tanh(\mathbf x_t \mathbf W_x + \mathbf h_{t-1} \mathbf W_h + \mathbf b), \quad \mathbf h_{t-1} = \tanh(\mathbf x_{t-1} \mathbf W_x + \mathbf h_{t-2} \mathbf W_h + \mathbf b)$$

$$\mathbf h_t = \tanh(\mathbf x_t \mathbf W_x + \tanh(\mathbf x_{t-1} \mathbf W_x + \mathbf h_{t-2} \mathbf W_h + \mathbf b) \mathbf W_h + \mathbf b)$$

 

슬라임으로 비유하자면, $\mathbf W_h$ 연산은 $\mathbf W_h$색 슬라임을 $\mathbf h_{t-1}$색 슬라임에 추가하는 행위다.

$\tanh$ 연산은 슬라임 크기를 -1 ~ 1로 조절하는(압축하는 or 줄이는) 행위다.

$\mathbf W_h$색 슬라임을 반복적으로 추가하면 기존 색(=의미)을 변형(=왜곡)시킨다.

슬라임 크기를 반복적으로 줄이면 기존 색 비중이 점점 줄어든다. 다시 말해, 기존 색이 점점 흐려진다.

요약하자면, $\mathbf h_t$가 갖고 있는 $\mathbf x_{<t}$의 정보는 $t$와 가까울수록 정확하고 뚜렷하다. 반대로, 멀수록 왜곡되고 흐려진다.

 

2. backward propagation(gradient vanishing): $\mathbf y_t$를 추정할 때, $\mathbf x_{<<t}$을 활용하지 않는 방향으로 $\mathbf W_x$ 학습이 진행된다.

$L_t = \text{cross-entropy}(\widehat y_t, y_t)$로 $\mathbf W_x$를 업데이트할 때, $\mathbf x_{<t}$가 주는 영향력은 $t$와 멀어질수록 줄어든다.

$${\partial L_t \over \partial \mathbf W_x} = {\partial L_t \over \partial \widehat y_t}{\partial \widehat y_t \over \partial \mathbf h_t}{\partial \mathbf h_t \over \partial \mathbf W_x} + {\partial L_t \over \partial \widehat y_t}{\partial \widehat y_t \over \partial \mathbf h_t}{\partial \mathbf h_t \over \partial \mathbf h_{t-1}}{\partial \mathbf h_{t-1} \over \partial \mathbf W_x} + {\partial L_t \over \partial \widehat y_t}{\partial \widehat y_t \over \partial \mathbf h_t}{\partial \mathbf h_t \over \partial \mathbf h_{t-1}}{\partial \mathbf h_{t-1} \over \partial \mathbf h_{t-2}}{\partial \mathbf h_{t-2} \over \partial \mathbf W_x} + \cdots$$

$${\partial L_t \over \partial \mathbf W_x} = {\partial L_t \over \partial \widehat y_t}{\partial \widehat y_t \over \partial \mathbf h_t}\left({\partial \mathbf h_t \over \partial \mathbf W_x} + {\partial \mathbf h_t \over \partial \mathbf h_{t-1}}{\partial \mathbf h_{t-1} \over \partial \mathbf W_x} + {\partial \mathbf h_t \over \partial \mathbf h_{t-1}}{\partial \mathbf h_{t-1} \over \partial \mathbf h_{t-2}}{\partial \mathbf h_{t-2} \over \partial \mathbf W_x}\right) + \cdots$$

$${\partial L_t \over \partial \mathbf W_x} = {\partial L_t \over \partial \widehat y_t}{\partial \widehat y_t \over \partial \mathbf h_t}\left(\tanh^\prime(\cdots)\mathbf x_t + \tanh^\prime(\cdots)\mathbf W_h \tanh^\prime(\cdots)\mathbf x_{t-1}+ \tanh^\prime(\cdots)\mathbf W_h\tanh^\prime(\cdots)\mathbf W_h\tanh^\prime(\cdots)\mathbf x_{t-2}\right) + \cdots$$

tanh의 기울기가 최대 1이기 때문에, $\tanh^\prime(\cdots)$을 곱하면 곱할수록 0에 수렴할 가능성이 높다.

 

$\partial \mathbf L_t \over \partial \mathbf W_x$는 시점 $t$에서 $\mathbf y_t$가 나오게끔 하는 $\mathbf W_x$의 업데이트 방향이다. 근데 RNN은 해당 방향 구할 때 $\mathbf x_{<<t}$를 거의 고려하지 않고, $\mathbf x_t$를 가장 많이 고려해도록 설계되었다.

 

결론, RNN은 "$\mathbf y_t$를 예측할 때" 혹은 "$L_t$로 $\mathbf W_x$를 학습할 때", 시간이 많이 흐른 과거 데이터 정보를 제대로 활용하지 못하고, 오직 최신 데이터 정보 위주로만 사용하도록 설계되어 있다.

LSTM (Long Short Term Memory)

작관적으로, LSTM은 gate를 활용해 기존에 요약된 정보($c_{t-1}$)에서 이제 중요치 않은 정보를 빼고 새로 들어온 정보($x_t$) 중에서 앞으로 중요한 정보만 추출하고 추가해 요약 정보를 업데이트($c_t$)하는 과정을 반복적으로 수행하는 컨베이너 벨트다.

gate는 "데이터 흐름 제어 장치"다. 쉽게 말해, gate는 앞쪽으로 흐르는 정보를 막거나 통과시킬 수 있다.

더 나아가, 얼마나 막을지 혹은 얼마나 통과시킬지 "비율"을 조절할 수 있다.

직관적으로 요약하자면, 밸브(=gate)를 조절해 데이터를 얼마나 내보낼지 조절하는 방식을 사용한다.

gate 비유

 

LSTM에는 3가지 gate가 있다.

1. forget gate: 불필요한 과거 정보($\mathbf c_{t-1}$)를 잊게 해주는 게이트다.

2. input gate: 현재 데이터($\mathbf x_t$ or $\tilde{\mathbf{c}}_t$)에서 중요한 정보(=원소)를 찾아주는 게이트다.

3. output gate: $\tanh(\mathbf c_t)$의 각 원소(=정보)가 외부 계층에서 얼마나 중요한지 조정해주는 게이트다.

 

($\tanh$의 출력은 -1.0 ~ 1.0 이기 때문에, $\tanh(\mathbf c_t)$를 "정보 $\mathbf c_t$의 강약(정도)"로 해석할 수 있다. sigmoid의 출력은 0 ~ 1이기 때문에, 이를 "데이터 통과 비율"로 볼 수 있다. 그래서 게이트에서는 sigmoid 함수, 실질적인 정보를 지닌 데이터에서는 $\tanh$를 사용하는 것이다.)

 

슬라임으로 비유하자면, gate는 슬라임을 일정 비율 떼어내는 역할을 한다.

즉, 기존 색(=의미)은 건드리지 않고 훼손시키지 않는다.

 

직관적으로, 게이트는 불필요한 정보는 적게 통과시켜 기억을 잊게한다. 중요한 정보는 많이 통과시켜 기억을 유지한다.

LSTM은 $\mathbf x_t$와 $\mathbf h_{t-1}$를 기반으로 불필요한 정보가 무엇인지 혹은 중요한 정보가 무엇인지를 학습한다.
($\mathbf h_{t-1}$는 직전에 외부로 보낸 출력값이기 때문에, 앞으로 필요 없는 정보 혹은 필요 있는 정보를 파악하는데 도움을 줄 수 있을거라 생각한다.)

쉽게 말해, LSTM은 이전 정보를 얼마나 끌고 갈지, 현재 정보를 얼마나 담을지 학습한다.

 

LSTM의 동작 방식 및 과정을 그림과 수식으로 표현하면 다음과 같다.

$$\mathbf f_t = \sigma(\mathbf x_t \mathbf W_x^f + \mathbf h_{t-1} \mathbf W_h^f + \mathbf b^f)$$

(Decide which information to throw away)

$$\mathbf i_t = \sigma(\mathbf x_t \mathbf W_x^i + \mathbf h_{t-1} \mathbf W_h^i + \mathbf b^i)$$

$$\tilde{\mathbf{c}}_t = \tanh(\mathbf x_t \mathbf W_x^c + \mathbf h_{t-1} \mathbf W_h^c + \mathbf b^c)$$

(Decide which information to store in the cell state)

$$\mathbf c_t = \mathbf f_t * \mathbf c_t + \mathbf i_t \tilde{\mathbf{c}}_t$$

(Update the cell state)

$$\mathbf o_t = \sigma(\mathbf x_t \mathbf W_x^o + \mathbf h_{t-1} \mathbf W_h^o + \mathbf b^o)$$

(Make output using the updated cell state)

 


LSTM은 vanilla RNN의 한계점을 개선한 모델이다.

1. RNN에서는 정보를 누적시킬 때 $\mathbf W_h$와 $\tanh$ 연산을 반복적으로 수행해 과거 정보($\mathbf h_{t-1}$)를 흐려진다.

하지만, LSTM에서는 정보를 누적시킬 때 forget gate(=얼마나 덜어낼지)로 과거 정보($\mathbf c_{t-1}$)를 필요한 만큼 덜어내게 만들어 정보가 왜곡되는 것을 완화했다.

 

2. RNN에서는 $L_t = \text{cross-entropy}(\widehat{\mathbf y}_t, \mathbf y_t)$로 $\mathbf W_x$를 업데이트할 때, 입력 데이터가 $t$와 멀어질수록 학습 영향력이 줄어든다.

LSTM은 멀수록 학습 영향력이 줄어드는 현상을 보다 잘 억제한다. 다른 말로, 기울기 손실 현상을 보다 잘 억제한다.

${\partial L \over \partial \mathbf c_t}$와 ${\partial L \over \partial \mathbf c_{t-1}}$ 간의 관계는 다음과 같다.

$${\partial L \over \partial \mathbf c_{t-1}} = \left({\partial L \over \partial \mathbf c_t} + {\partial L \over \partial \mathbf h_t}{\partial \mathbf h_t \over \partial \mathbf c_t}\right){\partial \mathbf c_t \over \partial \mathbf c_{t-1}}, \quad {\partial \mathbf h_t \over \partial \mathbf c_t} = {\partial \mathbf h_t \over \partial \tanh(\mathbf c_t)}{\partial \tanh(\mathbf c_t) \over \partial \mathbf c_t}$$

$${\partial \mathbf h_t \over \partial \tanh(\mathbf c_t)}  = \mathbf o_t, \ {\partial \tanh(\mathbf c_t) \over \partial \mathbf c_t} = 1-\tanh^2(\mathbf c_t), \ {\partial \mathbf c_t \over \partial \mathbf c_{t-1}} = \mathbf f_t \ (\text{which is sigmoid function})$$

$${\partial L \over \partial \mathbf c_{t-1}} = \left({\partial L \over \partial \mathbf c_t} + {\partial L \over \partial \mathbf h_t}\mathbf o_t(1-\tanh^2(\mathbf c_t))\right)\mathbf f_t$$

sigmoid의 최댓값이 1이기 때문에, 곱하면 곱할수록 0에 수렴할 가능성이 높다. 하지만, ${\partial L \over \partial \mathbf h_t}{\partial \mathbf h_t \over \partial \mathbf c_t}$을 반복적으로 더해줘 기울기 손실을 억제해준다.


LSTM도 RNN과 동일한 반복 구조이기 때문에 여전히 입력 데이터를 순차적으로 보면서 필요한 정보를 수집해 $\mathbf c_t$에 누적시킨다.

그렇기 때문에 forget gate로 누적된 정보($\mathbf c_t$)를 덜어낼 때, 누적된 정보는 하나의 큰 덩어리기 때문에 지금까지 누적된 정보의 평균적인 특성에서 필요 없는 부분을 덜어낸다고 볼 수 있다. 다른 말로, 덜어낼 때 각 데이터($\mathbf x_{<t}$) 정보의 개별적인 특성을 고려하지 않는다고 볼 수 있다. 이를 다른 말로, 이전 데이터 정보를 간접적으로 바라본다고 할 수 있다. (뿐만 아니라, $\mathbf x{>t}$ 정보도 수집하지 못한다. 하지만 이는 bidirectional LSTM으로 해결 가능하다.)

 

LSTM은 반복해서 정보를 덜어내기 때문에, $\mathbf x_{<t}$의 정보 시간이 흐름에 따라 비중이 점점 줄어들 가능성이 높다. 다른 말로, 점점 흐려질 가능성이 높다. 이는 아직도 long-term dependency 문제가 존재할 가능성이 높다는 것을 의미한다.

 

뿐만 아니라, 멀수록 줄어드는 학습 영향력을 완전히 억제하지 못했다.

Seq2Seq (Sequence to Sequence)

RNN에는 아래와 같이 여러 가지 유형이 존재한다. 그 중 3번째 유형인 seq2seq에 대해 잠깐 살펴보도록 하자.

 

seq2seq는 Encoder-Decoder 모델이라고 부르기도 하며, 이는 서로 다른 특성 (or 성질)을 가진 시계열 데이터를 반환하는 문제에 적합한 모델이다. 출력 데이터를 예측하기 위해 모든 입력 정보를 필요로 하는 경우가 많기 때문이다.

 

seq2seq 모델은 인코더(=encoder)와 디코더(=decoder)로 구성되어 있다. 이 때문에 Encoder-Decoder 모델로도 불린다.

이때, 인코더는 입력 문장을 벡터(context vector=인코더의 마지막 $\mathbf h$)로 잘 표현하는 역할을 하고, 디코더는 Next Token Predictor다.

 

학습 시, teacher forcing 기법(=정답 $\mathbf y_t$을 디코더 입력에 넣어 학습하는 방식)을 사용하고,

추론 시, 출력 $\widehat{\mathbf{y}}_t$를 입력 $\mathbf x_{t+1}$로 사용한다.

 

RNN (or LSTM) 모델로 seq2seq를 구성하면 구조는 다음과 같다.

인코더(초록색)와 디코더(노란색)는 서로 다른 RNN을 가지고 있다.

Seq2Seq가 RNN (or LSTM)일 때 발생하는 문제점

인코더는 디코더에게 context vector 즉, 인코더의 마지막 $\mathbf h$만 제공한다.

그렇기 때문에, context vector에는 정답을 추론하는데 필요한 입력 데이터의 모든 정보가 들어가 있어야 한다.

하지만, 크기는 고정되어 있어 저장할 수 있는 정보 양이 한정되어 있다.

그렇기 때문에, 입력 데이터 길이가 길면 물리적으로 필요한 정보를 모두 저장할 수 없다.

뿐만 아니라, 멀어질수록 정보가 흐려지는 구조적 문제 때문에 멀리 있는 과거 데이터 정보가 거의 없다.

반대로 말해, context vector에는 최신 데이터 정보가 주를 이루고 있다.

RNN (or LSTM) +Attention

시간이 흐름에 따라 비중이 점점 줄어들 가능성이 높다는 것은 $\mathbf h_t$는 현재 데이터($\mathbf x_t$) 정보 양을 가장 많이 보유할 가능성이 높다는 것을 의미한다.

$\mathbf h_t$가 $\mathbf x_t$의 정보를 가장 많이 가지고 있을 확률이 높으면, $\mathbf x_t$의 표현 벡터(embedding vector)로 볼 수 있다. 다시 말해, $\mathbf h_t$는 입력 데이터 $\mathbf x_t$의 의미를 벡터로 담아낸 embedding vector다.

 

그럼, 모든 입력 embedding vector를 디코더로 넘겨주고 각 출력 데이터 추론에 필요한 벡터만 골라 사용하면 문제는 해소할 수 있을 것이다.

다시 말해, 각 출력 데이터 추론을 위해 각각의 입력 embedding vector를 얼마나 필요로 하는지(=중요도) 파악하고, weighted sum으로 중요도 만큼 해당 embedding vector를 사용하면 문제는 어느 정도 해소될 것이다. 

$$\mathbf c_{t_{out}} = a_1 \mathbf h_1 + a_2 \mathbf h_2 + \cdots + a_{T_{in}} \mathbf h_{T_{in}}$$

 

그럼, 각 출력 데이터 추론에 대한 각각의 입력 embedding vector의 중요도를 어떻게 구할 수 있을까?

가장 단순한 방법은 중요도를 학습 파라미터로 잡는 것이다. 하지만 이 방법은 그다지 좋은 방법이 아니다.

왜냐하면, 해당 파라미터는 위치 정보만 갖기 때문이다. (e.g., 출력 시점 $t_{out}$에는 대체적으로 입력 시점 $t_{in}$의 데이터를 중요하게 생각한다.)

우선 중요도를 알기 위해서는 해당 입력 데이터가 어떤 의미를 갖는지 알아야 한다. 뿐만 아니라, 현 시점 출력에서 무엇을 중요하게 생각하는지 알아야 한다. 다른 말로, 현 시점 출력을 위해 수집한 중요한 정보를 알아야 한다.

즉, 출력 시점 $t_{out}$에서 $\mathbf h_{t_{in}}$의 중요도 $a_{t_{out}, t_{in}}$는 $\mathbf h_{t_{in}}$$\mathbf s_{t_{out}}$을 고려해야 한다. 이를 수식으로 표현하면 다음과 같다.

$$a_{t_{in}, t_{out}} = f(\mathbf h_{t_{in}}, \mathbf s_{t_{out}}), \quad (w_{t_{out}, t_{in}} \text { is scalar})$$

 

이제부터, $f$를 어떻게 만들지는 자유다. 

여러 후보가 존재하지만, 우리는 $\mathbf h_{t_{in}}$과 $\mathbf s_{t_{out}}$의 내적(=유사도)을 사용할 것이다.

현 시점 출력에서 중요하게 생각하는 것과 유사할수록 중요도를 높게 주는게 자연스럽기 때문이다. 

위 과정은 필요한 embedding vector이 필요할수록 더 많이 주목하기 때문에, 우리는 이를 "Attention"이라고 부르며, 수식은 다음과 같다.

$$<\mathbf s_t \cdot \mathbf h_i> = \mathbf s_t \mathbf h_i^\top$$

$$a_{t, i} = \text{softmax}(<\mathbf s_t \cdot \mathbf h_i>) = {e^{<\mathbf s_t \cdot \mathbf h_i>} \over \sum_{j=1}^\text{max_len} e^{<\mathbf s_t \ \cdot \mathbf h_j>}}$$

$$\mathbf c_{t} = a_{t, 1} \mathbf h_1 + a_{t, 2} \mathbf h_2 + \cdots + a_{t, \text{max_len}} \mathbf h_{\text{max_len}}$$

$({\mathbf s_t}=t\text{th output embedding vector}, \ {\mathbf h_i}=i\text{th input embedding vector})$

 

Attention을 요약하자면, 모든 입력 embedding vector를 디코더로 넘겨주고 각 출력 데이터 추론에 필요한 embedding vector만 골라(by dot product & softmax) 사용(by weighted sum)하는 과정이다.

 

추가로, 디코더는 Next Token Predictor이기 때문에, 만약, $\mathbf s_{t_{out}}$을 $\mathbf y_{t_{out}}$의 embedding vector로 해석하면, $\mathbf s_{t_{out}}$는 $\mathbf y_{{t+1}_{out}}$과 연관성이 깊은 녀석(=입력 embedding vector)과 가까워지게 학습된다.

Transformer: Self-Attention

RNN + Attention는 여전히 반복 구조의 고질적인 문제가 존재한다. 

입력 데이터 $\mathbf x_t$의 의미를 벡터로 담아내는 것이 $\mathbf h_t$의 본분이다. 하지만 RNN의 반복 구조 때문에 본분을 다하지 못한다. 이는 출력 데이터의 embedding vector인 $\mathbf s_t$에도 해당되는 문제다.

RNN은 체인으로 이어져 있기 때문에 시간이 흐름에 따라 경로가 길어지며, 이는 $\mathbf x_t$ 멀리 있는 $\mathbf x_{<<t}$ 간의 연관성 정보를 정확히 파악하기 힘들게 만든다.

그렇기 때문에, $\mathbf x_t$(e.g., 쓰다)와 $\mathbf x_{<<t}$(e.g., 모자를, 글을, 맛이)가 서로 연관이 깊은 경우 RNN의 $\mathbf h_t$는 $\mathbf x_t$의 정보를 정확히 갖지 못해 embedding vector의 본분을 제대로 수행하지 못한다. (=long term denpendency 문제)

 

Transformer는 이 문제를 해소시키기 위해 RNN의 반복 구조를 완전히 버렸다. 쉽게 말해, 시간이 흐름에 따라 경로가 길어지는 것을 막기 위해 이어져 있는 체인을 끊어 버렸다.

대신, Attention 방식을 차용하기로 했다. 구체적으로, 모든 입력 데이터를 직접 다 보고 각 입력 데이터의 의미를 담아내는데 필요한 정보를 수집(by dot product & softmax)하고 사용(by weighted sum)해 embedding vector를 구하는 방식을 사용한다. 우리는 위 과정을 "Self-Attention"이라고 부른다. self-attention은 (RNN의 반복 구조와 다르게) 어느 시점에서 시작해도 동일한 경로를 가지게 된다.

 

출력 데이터의 embedding vector를 구할 때도 self-attention으로 사용한다. 이때, 주의해야할 점은 인코더와 다르게 $\mathbf s_t$을 구할 때 $\mathbf y_{>t}$는 보지 않는다. $\mathbf y_t$를 구할 때 $\mathbf y_{>t}$를 보는 것을 부정행위이기 때문이다. 위 과정을 "Masked Self-Attention"이라고 부른다.

 

반복 구조 vs self-attention

Transformer의 self-attention은 RNN의 반복 구조와 달리 누구를 먼저보고 누구를 나중에 보지 않는다. 즉, 각각의 입력 데이터를 경로가 서로 다르지 않고 동일하다. 직관적으로, 서로 차별하지 않고 동등하게 보고 필요한 정보를 수집한다고 볼 수 있다.

 

LSTM은 이전 데이터 정보$(\mathbf c_{t-1}$)를 일정 비율 덜어내고 현재 데이터($\mathbf x_t$) 정보를 일정 비율 담는 방식을 사용한다. 그렇기 때문에 이전 데이터 정보를 덜어낼 때, 각 데이터 정보의 개별적인 특성을 고려하지 않고 이전 데이터 정보의 평균적인 특성을 고려한다고 볼 수 있다.

하지만, Transformer의 self-attention은 모든 입력 데이터를 직접 보고 필요한 정보를 수집하기 때문에, 각 입력 데이터를 개별적으로 보고 필요한 정보를 수집한다고 볼 수 있다.

직관적으로 요약하자면, $\mathbf x_t$를 제외한 입력 데이터를 볼 때 LSTM은 간접적으로 보고 self-attention은 직접적으로 본다고 할 수 있다.

 

이러한 self-attention의 특징은 RNN의 반복 구조보다 뛰어나고 단단한 long-term dependency를 가지게 해준다. 뿐만 아니라, 모든 입력 데이터를 동일하게 대하기 때문에 각 입력 데이터는 동일한 학습 영향력을 가지게 된다.

 

더 나아가, Transformer의 self-attention은 RNN(LSTM)의 반복 구조보다 효율적인 병렬 처리를 가능케 한다.

RNN은 입력 데이터를 순차적으로 처리하는 반면, Transformer는 동시에(=parallel)에 처리하고, 연산 과정이 보다 간단하기 때문이다.

 

'ML > NLP' 카테고리의 다른 글

[NLP] Transformer  (2) 2024.08.19