BRICKSTUDY

Attention, Transformer를 알아보자 본문

AI

Attention, Transformer를 알아보자

c-park-2 2024. 11. 5. 05:43

0. 개요

안녕하세요 브릭스터디 박찬영입니다. 이번에는 Attention과 transformer에 대한 개념 공부를 했는데, 이를 공유하도록 하겠습니다. 이제는 거의 필수적인 인공지능 개념이 되어버린 녀석들인데, 저는 이제야 공부를 해봅니다. 열심히 제가 이해한 내용을 바탕으로 작성해보도록 하겠습니다. 

 


1. Attention

1) The bottleneck problem

지난 포스팅에서 살펴봤었던, Encoder, Decoder 구조를 보면, 모든 Encoder의 정보가 Decoder의 첫번째 스테이지에서 처리가 되는 것을 볼 수가 있습니다. 여기서 bottleneck 문제가 발생하는 것이고, 이러한 경우에 input sequence가 길면, 문제가 발생할 수 있습니다. 

 

그래서 문제를 해결하기 위한 간단한 아이디어를 제시를 합니다. 

 

2) Idea : Can we "peek" at the input? 

그럼 우리가 input sequence에서 하나씩 볼 수 없을까?라는 아이디어입니다. 일종의 길을 하나 더 만들어주자! 는 것인데요 그림으로 살펴보면 다음과 같습니다.

그림과 같이 encoder 부분에서 decoder로 가는 '하이패스' 같은 길을 만들어주는 것입니다. 이렇게 하면 우리가 encoder에 있는 정보를 decoder 끝단에서도 볼 수가 있게 되는 것입니다. 

 

문제는 어떻게 저걸 구현할 수 있는가?입니다. 

 

3) Attention

자 그래서 아이디어를 구현하는 것을 살펴볼 텐데 굉장히 재밌게 구현을 합니다. 먼저 아이디어 구현을 위해서 등장한 몇 가지 용어 및 개념부터 정리를 하겠습니다. 

 

Key vector
해당 단계에서 어떤 유형의 정보가 존재하는지를 나타낸다.

Query vector
해당 단계에서 우리가 찾고 있는 것을 나타낸다

 

이제 그림으로 한 번 살펴보겠습니다. 

의미적으로는 각 decoder step에서의 필요한 정보를 encoder에 있는 정보에서 참고하기 위해서 encoder의 어떤 정보가 가장 현재 step에서 중요한 정보일까?를 보는 과정이라고 생각할 수 있습니다. 이제는 한 번 수식으로 살펴보도록 하겠습니다. 

 

그림에서 다시 수식으로 작성하면 다음과 같습니다. 

key vector 하고 query vector는 위 수식으로 표현한 것이고, 중요한 것은 attention score를 계산하는 것입니다. attention score를 key vector와 query vector의 내적으로 계산을 합니다. 내적으로 계산하는 것의 의미는 가장 비슷한 vector를 보겠다는 것입니다. 두 벡터의 내적은 일종의 두 벡터가 얼마나 유사한 지를 나타낼 수 있습니다. (decoder 입장에서 내가 찾는 것과 가장 유사한 key를 보겠다는 느낌)

 

그래서 attention score에 기반해서 score가 가장 높은 key를 보내주면 되겠죠? 그런데, arg max operation은 미분이 불가능하기 때문에 우리가 일종의 "continuous relaxation"을 진행합니다. 방법은 간단하게 attention score에 softmax를 취해주면 됩니다. softmax의 결과 값을 하나의 중요도?(가중치)로 보고 h들과 가중합 결과를 decoder에 보내주게 됩니다. 가중합은 의미적으로 보면, 더 중요한 것을 선택해서 보겠다"는 의미를 가집니다. 

 

결과적으로 수식으로 살펴보겠습니다. 

그래서 개념적으로 attention이 작동하는 것을 살펴보면 다음과 같이 그림을 그려볼 수 있겠습니다. 

 

여기까지 attention에 대해서 살펴봤습니다. 잠깐 정리하자면 이렇습니다. 

Every encoder step t produces a key
Every decoder step l produces a query
Decoder gets encoder activation corresponding to largest value of "attention score"

 

Attention은 왜 좋을까? 

Attention 덕분에 이제 모든 decoder step이 encdoer step과 연결된 것입니다. 

그리고 gradient flow 적으로도 하나의 쉬운 루트가 개척된 격이라서 장점이 있고, 긴 시퀀스 처리에 있어서 중요한 역할을 수행합니다. 

 

 


 

2. Self-Attention

이전 파트에서 Attention에 대해서 살펴봤습니다. attention을 잘 살펴보면, 이런 생각을 가질 수 있습니다. "이거 어차피 attention이 decoder에서 필요한 정보가 무엇인지 잘 선택해서 connection을 가져오는데 굳이 recurrent connection이 필요한 거야?" 

 

그렇다면 "한 번 RNN 기반의 구조를 완전히 attention 기반의 구조로 만들 수 있을까?"를 생각해 봅시다. 

그래서 recurrenct connection을 지운 구조를 생각해봅시다. attention의 key와 query를 통해서 decoder step에서 encoder의 모든 hidden state를 볼 수 있습니다. 하지만, decoder의 이전 state는 접근할 수가 없는 문제가 발생합니다. 그래서 완전히 attention base model을 만들려면 해당 문제를 해결해야만 합니다.

이 문제를 해결하기 위해서 등장하는 개념이 바로 self-attention입니다. 이런 구조를 생각을 해봅시다. 

recurrent model은 아니지만, weight sharing을 하는 구조가 있는 것입니다. 

 

 

뭔가 복잡해 보이지만, 이전에 다루었던, attention과 큰 차이는 없습니다. 차이라고 하면 value 값인 v가 추가된 것과 각 step에서 스스로 attention을 적용한다는 점입니다. 그래서 이러한 방법을 self-attention이라고 합니다. 

 

각 hidden state는 shared weight를 가진 linear layer + non-linear를 통해서 도출되고, 각 hidden state 마다 key, query, value를 계산합니다. 각 계산은 단순 linear transformation으로 생각하는 게 간단합니다. 

 

그리고 이전과 같이 key와 query의 dot product를 통해서 attention score를 계산합니다. 이후에 마찬가지로 softmax 함수를 통해서 soft score를 계산하고 가중합을 통해 최종 activation을 계산하는 과정입니다. 

 

이 과정을 하나의 layer로 볼 수 있습니다. 그래서 layer로 표현하면 다음과 같습니다. 

이런 방법으로 self-attention layer를 더 깊게 쌓을 수 있는 것입니다. 

지금까지 살펴본 것은 self-attention의 기본적인 아이디어입니다. 그런데, 이를 그대로 seq2seq 모델에 사용할 수가 없습니다. 왜냐하면, 위와 같은 방식은 순서에 대한 정보가 들어있지 않습니다. 그래서 우리가 시퀀스의 순서를 바꿔도 self-attention은 같은 결과를 도출할 것입니다.  이외에도 multi-headed attention, adding nonlinearities, masked decoding과 같은 컴포넌트들을 추가해야 우리가 transformer로 넘어갈 수 있습니다. 


 

3. Transformer

1) Positional encoding

Positional encoding이 필요한 이유는 sequence를 처리하기 때문입니다. 위에서 설명한 기본 attention 구조를 생각해 보면 다음과 같습니다.

일반적으로 문장에서 단어의 위치는 정보를 전달하기 때문에, 위치가 바뀌면 일부는 의미 자체를 바꿀 수 있습니다. 그래서 이를 해결하는 방법으로 아이디어는 이렇습니다. 

 

1-1) Idea : add some information!!

아이디어는 단순합니다. 초반에 위치 정보를 추가해 주자!입니다. sequence를 input으로 줄 때, 시간 정보 t를 같이 주는 것입니다. 

 

하지만 이 방법은 엄청 좋은 방법은 아닙니다. 이와 같이 position을 encoding 하는 것은 절대 위치를 주는 것인데, 절대 위치보다는 사실 더 중요한 것은 단어의 상대적인 위치입니다. 

 

예를 들어

"I walk my dog every day"

"every single day i walk my dog"

두 문장이 있을 때, 두 문장에서 절대적인 위치는 다 다르지만, 문장의 의미는 같습니다. 여기서 중요한 것은 "my dog"가 "I walk" 바로 뒤에 나오는 것이 문장의 의미에 있어서 중요한 것입니다. 

 

결과적으로 absolute position 보다 relative position에 더 집중할 필요가 있습니다. 

 

이런 면에 있어서 단순 index를 position으로 encoding 하는 것은 긴 position의 값은 굉장히 커질 수 있기 때문에 안정적이지 못합니다. 

1-2) Idea : what if we use frequency-based representations? 

다음 아이디어는 sin/cos function을 이용하는 것입니다. sin, cos function은 일정한 주기를 가지고 있고, 다음과 같이 여러 차원으로 encoding을 진행하기 때문에, 서로 다른 문장들이 있어도 각 토큰의 상대적인 위치를 안정적으로 유니크하게 인코딩할 수 있습니다. 

 

https://youtu.be/T3OT8kqoqjc

그래서 positonal encoding 결과로 positional vector를 embedding vector에 더해주거나, concatenate 해주는 방법으로 위치 정보를 추가해 줍니다. 

 

2) Multi-headed attention

현재까지는 one time step만 보고 있는데, 더 많은 time step을 한 번에 보고 싶은 것입니다. 

그림과 같이 softmax를 취한 결과를 가지고 value를 일종의 선별 작업을 하기 때문에, softmax 값이 큰 time step의 영향력이 클 수밖에 없습니다. 즉 하나의 time step의 영향이 매우 크다는 것인데요. 이를 더 넓은 time step에서 정보를 받고자 할 때 방법을 생각해보려고 합니다.

 

2-1) Idea : have multiple keys, queries and values for every time step!

이렇게 각 time step 마다 여러 개의 keys, queries, values를 두어서 서로 다른 부분에 attention을 줄 수 있도록 해줄 수가 있습니다. 인덱싱이 복잡할 수도 있는데, 천천히 맞춰보면 충분히 볼 수 있을 것입니다. 

 

 

3) Adding non-linearities

self-attention만 보면 완전 linear 합니다. linear operation 밖에 없다는 의미인데, 수식을 다시 살펴봅시다. 간단한 버전으로 다시 살펴보면, 

이러면, 모든 self-attention layer는 이전 layer의 linear transformation(with non-linear weight)인 것입니다. 이는 표현력이 많다고 할 수 없습니다. 

 

3-1) Alternating self-attention & non-linearity

그래서 결국에는 non-linearity를 더 추가하고 싶은 것인데요. 굉장히 간단하게 self-attention layer 다음에 non-linear layer처럼 하나를 추가하자! 형식입니다. 그림으로 살펴보겠습니다. 

 

이렇게 각 self-attention layer 이후마다 non-linear function(작은 neural net)을 배치해서 비선형성을 추가해 주어 모델 자체의 표현력을 높이는 것입니다. 

 

4) Masked decoding

self-attention을 또 잘 보면 미래를 볼 수 있다는 것입니다. self-attention 구조로 이루어진 decoder 부분을 생각해 봅시다. 

Step 1을 보면 Step 1에서 다음 입력의 기반이 되는 값을 출력을 하는데, attention 과정에서 사실상 그 값을 미리 key 값으로 참조를 할 수 있었다는 것이죠. 그러면, 현재 step의 출력이 결국에는 미래 시점의 정보를 기반으로 예측을 한 결과이므로 훈련과 테스트 과정에서 불안정함을 선사할 수 있는 것입니다. (모든 값들은 병렬로 처리되는 것이기 때문에, 순차적으로 들어간다고 생각하면 머리 아픔)

 

그래서 결국에는 self-attention 과정에서 이전 정보는 허락할 수 있지만, 미래 정보는 허락할 수 없게 만들어야 합니다. 

간단하게 미래 시점이면 attention score를 - 무한대로 넣어주는 것입니다. 실제로는 softmax 안에 값을 0으로 대체해 주는 것으로 진행합니다. 

 

 

5) 요약

지금까지 살펴본 개념들로 우리는 이제 완전히 self-attention에 기반한 practical sequence model을 만들 수 있게 됐습니다. 

self-attention layer와 position-wise feedforward networks를 번갈아 배치하고, positional encoding을 사용하고, multi-head attention 구조를 추가하고, decoding이라면, masked attention을 사용한다. 

 

이렇게 정리해 볼 수 있을 것 같습니다. 

 

6) Transformer

우리가 지금까지 배운 내용들을 가지고 sequence 처리에 사용하는 많은 모델 디자인들이 있는데, 일반적으로 그런 모델을 우리는 "Transformers"라고 부릅니다. sequence를 다른 것으로 변환하기 때문에 Transformer라고 부르는데, 구조를 조금 더 디테일하게 살펴보도록 하겠습니다. (어떤 식으로 self-attention과 그 외를 이용하는지)

 

 

6-1) The "classic" Transformer

먼저 Seq2Seq RNN model과 비교를 해보겠습니다. 

 

classic transformer 역시 seq2seq 문제를 풀기 때문에, encoder part와 decoder part가 나누어지는데, 구성요소가 self-attention layer와 position-wise nonlinear network로 이루어져 있는 차이입니다. 

 

그런데, 우리가 못 봤던 녀석이 있습니다. "cross attention"이 뭐 하는 녀석인지 살펴보도록 하겠습니다. 

 

6-2) Cross-attention

cross-attention은 단순합니다. 우리가 처음 seq2seq model에서의 attention 개념과 일치하는데, encoder의 key, value, decoder의 query 그리고 서로 attention 한다는 의미에서 "cross"가 붙었습니다. 

 

식으로 살펴봅시다. 

기본적인 attention과 다를 게 없습니다. 

 

6-3) Layer normalization

마지막으로 진짜 Transformer를 보기 전에 알아야 할 개념입니다. 

 

아이디어는 다음과 같습니다. 

batch normalization은 우리가 알다시피 매우 유용한 방법인데, seq model에서는 사용하기가 어렵습니다. seq 길이가 다르기 때문에 batch 전체에 걸쳐 정규화하는 것이 어렵기 때문인데요

 

그래서 batch normalization 대신에 layer 내에서만 정규화를 진행하는 것입니다. 

 

6-4) 이제 진짜 Transformer

지금까지 알아본 거 다 합치면 진짜 Transformer가 나옵니다. 

짜잔!

 

4. 마치며

이번 포스팅을 통해서 Attention, Transformer에 대해서 조금이라도 도움이 됐으면 좋겠습니다. 감사합니다. 

 

'AI' 카테고리의 다른 글

RNN, Sequence-to-Sequence model  (0) 2024.11.04
인공지능 기초 Optimization  (0) 2024.10.26
Supervised Learning 기초  (6) 2024.10.11
Embodied AI : Vision-Language Navigation Challenges  (3) 2024.09.28
Embodied AI : Survey(2)  (3) 2024.09.01