본문 바로가기

AI/Deep Learning

[DL] Attention 파헤치기 - Seq2Seq부터 Transformer까지 (1)

 

  현재 자연어처리 분야에서 가장 잘 알려진 BERT나 GPT 모두 트랜스포머를 기반으로 한 분류/생성 모델이기 때문에, 어텐션 메커니즘과 트랜스포머 block을 이해하는 과정은 매우 중요하다고 할 수 있다. 이를 위해 지난 포스트에서 다룬 순환신경망 계열의 셀(cell)들을 인코더와 디코더로 구조화한 Seq2Seq부터, 해당 모델의 단점을 개선한 트랜스포머까지의 전반적인 개념을 정리해보려 한다.

※ 참고

 - BERT : Bidirectional Encoder Representations from Transformers

 - GPT : Generative Pre-trained Transformer

 

 

 

1. Sequence to sequence (시퀀스-투-시퀀스)

  Seq2Seq은 쉽게 말하면 시퀀스 형태의 입력값을 시퀀스 형태의 출력값으로 만들 수 있게 하는 모델이다. 즉, 한 도메인(예:영어로 된 문장)에서 다른 도메인(예:프랑스어로 번역된 동일한 문장)의 시퀀스로 시퀀스를 변환하기 위한 모델을 학습하는 것에 관한 것이다. RNN셀을 기반으로 하며, 기계번역이나 자유질문 답변(자연어 문제가 주어지면 자연어 답안을 생성하는 것)에 사용될 수 있다.

 

 

 

RNN셀이 구성을 달리해 사용되었을 뿐 원리가 바뀐 것은 아니다. Seq2Seq 모델은 인코더(encoder)와 디코더(decoder) 구조로 이루어져 있으며 각각의 역할은 다음과 같다.

 

 

  • Encoder: 입력 순서를 처리하고 자체 내부 상태(state)를 반환한다. 재귀 순환 신경망의 스텝마다 입력값 \( (x_1, x_2, ..., x_T) \)가 들어가고, 마지막 부분에 하나의 벡터값(위의 사진에서는 \( C \))이 나온다. 인코더 RNN 계층의 출력은 폐기되고 이 state만 유지된다. \( C\)는 컨텍스트 벡터(context vector)라 부르며, 인코더 부분의 정보를 요약해 담고 있다고 말할 수 있다. 이 state는 다음 단계인 디코더에서 활용된다.
  • Decoder: 대상 시퀀스의 이전 문자를 고려하여 다음 문자를 예측하도록 한다. 인코더에서 만들어낸 \( C \)를 통해 재귀적으로 출력값을 만들며, 각 스텝마다의 출력값은 다음 스텝의 입력값으로 사용된다. 구체적으로는, 목표 시퀀스를 같은 시퀀스로 바꾸되 향후 하나의 타임스텝으로 상쇄하는 것으로, 교사 강요(teacher forcing)라고 하는 방법으로 훈련된다.

출처 - https://wikidocs.net/24996

 

"I am a student"라는 영어 문장을 "je suis étudiant"라는 프랑스어 문장으로 변환하는 과정을 예시로 설명해보자.

 

  • 인코더와 디코더에서의 입력값은 하나의 단어가 된다(각 단어는 임베딩 벡터로 바뀐 후 입력값으로 사용됨)
  • 최초 입력값: <sos>라는 special token 사용
  • 최종 출력값: <eos>라는 special token이 나오면 문장의 끝으로 간주

즉, 고정된 문장 길이를 정하기 위해 데이터 전처리 과정에서 특정 문장 길이로 자른 후, 패딩 처리 및 <sos>, <eos> 등의 각종 토큰을 넣어야 한다(굳이 <sos>와 같을 필요는 없다). 그래야 디코더에서 최종 출력값으로 토큰이 형성됐을 때 generation을 멈출 수 있다.

  훈련 과정에서는 디코더에게 인코더가 보낸 컨텍스트 벡터 \( C\)와 실제 정답인 je suis étudiant <eos>를 번역할 문장과 함께 훈련시킨다. 반면 테스트 과정에서 디코더는 \( C\)와 시작 토큰인 <sos>만을 입력으로 받게 된다. <sos>로 시작해서 그 뒤에 나올 단어들을 소프트맥스 함수를 통해 연이어 예측한다.

 

 

 

Seq2Seq의 문제점과 Attention의 등장

  문장이 길어질수록 더 많은 정보를 고정된 길이(\( C \))에 담아야 하므로 정보의 손실이 있다. 이는 저번 포스트에서 설명했던 장기 의존성 문제(long-term dependencies problem)이다. 짧게 설명하면, 은닉층의 과거 정보가 마지막까지 전달되지 못하는 현상이다. 이때 등장한 것이 어텐션(attention)이다. 어텐션은 디코더에서 출력 단어를 예측하는 매 스텝마다, 인코더에서의 전체 입력 문장을 다시 한 번 참고함으로써 이를 해결한다.

뒤에서는 어텐션과 셀프 어텐션에 대해 설명하도록 하겠다. 

 

 

2-1. Attention

 

  은닉 상태의 값을 통해 인코더에서 어텐션을 계산한 후, 디코더의 각 스텝마다 계산된 어텐션을 입력으로 넣는다. 디코더의 각 시퀀스 스텝마다 적용되는 어텐션의 가중치는 다른데, 즉 전체 입력 문장을 전부 동일한 비율로 참고하지 않는다는 것이다. 해당 시점에서 예측해야 할 단어와 연관이 있는 입력 단어 부분만 참고할 수 있도록 하는 것이 어텐션의 기본 원리라고 보면 된다. 

그래서 어텐션은 어떻게 계산되는가?

 

'딥러닝'이라는 Query에 대한 어텐션 값(attention score)

 

어텐션 함수는 주어진 '쿼리(Query)'에 대해서 모든 '키(Key)'와의 유사도를 각각 구합니다. 그리고 구해낸 이 유사도를 키와 맵핑되어있는 각각의 '값(Value)'에 반영해줍니다. 그리고 유사도가 반영된 '값(Value)'을 모두 더해서 리턴합니다. 여기서는 이를 어텐션 값(Attention Value)이라고 하겠습니다.

 - 출처 : https://wikidocs.net/22893

 

  • Query(Q) : 영향을 받는 단어 A를 나타내는 변수 (위의 예시에서는 '딥러닝')
  • Key(K) : 영향을 주는 단어 B를 나타내는 변수  (위의 예시에서는 '자연어', '처리', '아주', '좋아요')
  • Value(V) : 영향에 대한 가중치

즉, 어텐션 함수는 다음과 같다.

 

Attention(Q, K, V) = Attention Value

 

이를 통해 생성된 어텐션 값(attention score 혹은 attention value)는 각 단어 간의 관계를 측정한 값이라고 할 수 있다. 또, 위의 어텐션 값을 하나의 테이블로 만들면 어텐션 맵(attention map)이 된다.

 

 

2-2. Self Attention

여기서 잠깐! 위에서 어텐션 얘기를 했는데 갑자기 셀프 어텐션은 또 무엇일까... 둘은 다른가?

 

그렇다.. 둘은 다르다.... 필자는 둘의 차이를 이해하지 못해 고통을 겪었다ㅜㅠ 간단하게 트랜스포머 구조를 가져와 설명해보겠다(갑자기? 하지만 적절한 예시를 찾을 수 없었음...)

 

 

그림에서 빨간 글자로 표시된 부분이 트랜스포머에서의 어텐션 block이다. 총 세 가지의 block이 있다.

 

  1. 인코더의 Self-Attention : Query = Key = Value
  2. 디코더의 Maked Self-Attention : Query = Key = Value
  3. 디코더의 Encoder-Decoder Attention : Query : 디코더 벡터 / Key = Value : 인코더 벡터

눈치 챘는가? query와 key, 그리고 value가 동일한 부분에 있을 때 셀프 어텐션이 되고, 디코더와 인코더에 나누어져 있으면 그냥 어텐션이 된다. 정확히는 다음과 같다.

 

셀프 어텐션은 본질적으로 Query, Key, Value가 동일한 경우를 말합니다. 반면, 세번째 그림 인코더-디코더 어텐션에서는 Query가 디코더의 벡터인 반면에 Key와 Value가 인코더의 벡터이므로 셀프 어텐션이라고 부르지 않습니다.

 - 출처 : https://wikidocs.net/31379

 

Here's the list of difference that I know about attention (AT) and self-attention (SA).
1. In neural networks you have inputs before layers, activations (outputs) of the layers and in RNN you have states of the layers. If AT is used at some layer - the attention looks to (i.e. takes input from) the activations or states of some other layer. If SA is applied - the attention looks at the inputs of the same layer where it's applied
2. AT is often applied to transfer information from encoder to decoder. I.e. decoder neurons receive addition input (via AT) from the encoder states/activations. So in this case AT connects 2 different components - encoder and decoder. If SA is applied - it doesn't connect 2 different components, it's applied within one component. There may be no decoder at all if you use SA, as for example in BERT architecture.
3. SA may be applied many times independently within a single model (e.g. 18 times in Transformer, 12 times in BERT BASE) while AT is usually applied once in the model and connects some 2 components (e.g. encoder and decoder).

 - 출처 : https://datascience.stackexchange.com/questions/49468/whats-the-difference-between-attention-vs-self-attention-what-problems-does-ea

 

이제 위의 어텐션 값이 어떻게 도출되고 반영되는지 보자(셀프 어텐션 기준).

 

1. 각 단어의 벡터값을 통해 어텐션 값을 구한다.

  텍스트의 의미 정보를 벡터로 표현해서 유사도 점수를 계산한다. 가령 트랜스포머 모델에서는 단어 벡터끼리의 내적 연산(dot product)을 통해 계산한다.

 

dot product: \( QK^T \)

 

2. 소프트맥스 함수를 통해 어텐션 값을 확률값으로 표현한다.

  어텐션 값이 모여 있는 어텐션 맵에 소프트맥스 함수를 적용한다. 이렇게 되면 어텐션 맵이 특정 단어에 대한 다른 단어와의 연관도 값의 확률로 나타나게 된다.

 

3. 확률값과 기존의 각 단어 벡터를 가중합한다.

  여기서의 가중합이란, 각 확률값과 각 단어 벡터를 곱한 후 더하는 연산이다.

해당 사진은 1, 2, 3 단계를 거쳐 '딥러닝'이라는 단어에 대한 컨텍스트 벡터 \( C \)를 도출하는 과정이다.

 

 

모든 단계를 거쳐 셀프 어텐션이 진행되는 과정은 다음과 같다.

출처 - https://towardsdatascience.com/illustrated-self-attention-2d627e33b20a