[NLP] Transformer (1)

박경민·2023년 7월 22일
0

Transformer 는 "Attention is all you need" 라는 논문에서 등장한 모델로, 인코더 디코더 구조를 유지하지만 RNN 사용 없이 Attention 만으로 구현한 모델이다. 어떻게 가능했을까?

기존 모델의 한계

seq2seq 은 말그래도 시퀀스를 시퀀스로, 바꿔주기 위해 인코더-디코더 구조를 사용한다. RNN 을 포함한 seq2seq 는 time step 을 따라 정보를 처리할 수 있다는 점에서 아이디어가 있었지만 입력 시퀀스를 하나의 벡터 표현으로 압축하여 정보의 손실이라는 한계를 마주쳤다. 이에따라, 한계의 벡터 표현이 아닌 현재 시점 예측 때마다 인코더의 시퀀스를 보고, 어디에 집중할 지 결정하는 attention 구조가 등장했고 긴 문장에 대한 성능을 높였다.

트랜스포머는 여기서 아이디어를 따와 인코더, 디코더를 구성할 때 RNN이 아닌 어텐션만 사용하는 구조를 말한다.

Transformer Hyperparameter

트랜스포머 논문에 소개된 하이퍼파라미터 값들을 알아보자.

입력과 출력의 크기, 즉 임베딩 벡터의 차원은 512를 유지한다.

하나의 인코더와 디코더로 이루어진 구조를 층이라고 한다면, 트랜스포머에서는 총 6층을 쌓는다.

트랜스포머에서 어텐션을 할 때 한 번 하는 것보다 분할하여 병렬로 수행한 후, 합친다. 병렬 계산을 하는 단위를 head 라 하며, 병렬의 개수는 8개이다.

어텐션 이외에 트랜스포머에는 feed-foward 신경망이 존재하며 은닉층의 크기는 2048이다.

Transformer

트랜스포머는 RNN 없이 인코더, 디코더 구조를 유지한다고 하였다. 이전 seq2seq 모델에서는 인코더, 디코더에 각각 1개의 RNN을 사용하고, t개의 시점을 가지는 구조였다. 트랜스포머는 기본적으로 인코더, 디코더를 각각 6개 사용하여 쌓아올린다. (encoders, decoders)

그 중 인코더-디코더 하나씩 이루어진 1층을 보자! 인코더로부터 정보를 전달받아 디코더가 출력을 만들어내는 구조이다.

  • 디코더는 시작 < sos > 를 입력으로 받고 종료 < eos > 가 나올 때까지 연산을 진행
  • 각 토큰에 대하여 RNN 을 사용하는 대신 입력 시퀀스에 대해 인코더1개, 출력 시퀀스에 대해 디코더 1개로 인코더-디코더 구조 유지
  • 인코더, 디코더의 내부는?

Transformer's Input

인코더, 디코더 내부 구조를 보기 전 입력에 대해 알아보자. 단순히 워드임베딩을 가져다 입력으로 쓰는 게 아니라 무엇인가 차이가 있다.

  • 기존 RNN의 경우 time step t에 따라 순차적으로 입력받아 자연스럽게 단어의 위치정보를 가질 수 있다.
  • Transformer 의 경우 순차적으로 인코딩하지 않으므로 단어의 위치정보에 대한 추가적인 입력이 필요하며, 이를 positional encoding이라 한다.

어떻게 위치정보를 인코딩하느냐? 단어에 대한 임베딩 벡터와 positional encoding 값을 더한다. (그 후에 encoder 입력)

실제로는 임베딩 벡터를 모아 문장 행렬을 만들고, positional encoding 또한 matrix 를 만들어 이 둘을 더한다.

구체적으로 positional encoding 은 어떤 값으로 구성되는가? 함수를 보자.

  • pos 는 입력 문장에서의 임베딩 벡터의 위치를 나타내며, (그림에선 pos = 2)
  • i 는 임베딩 벡터 내에서의 인덱스를 의미한다 (그림에선 i = 3)
  • 수식에서도 알 수 있듯 임베딩 벡터 내에서 i가 짝수이면 사인, 홀수이면 코사인 함수를 사용한다
  • d(model) 은 트랜스포머 모든 층의 출력 차원을 의미한다 (임베딩 벡터의 차원과 같으며, 예시에선 4이고 실제 논문은 512이다.)

최종적으로 같은 단어라 하더라도 문장 내 어디에 위치하느냐에 따라서 달라지는 임베딩 벡터를 유도하는 것이 positional encoding 이다.

식의 이유 알아보자

Attention

트랜스포머에서 사용하는 어텐션은 3가지가 있다.

  • Encoder Self-Attention: 트랜스포머의 인코더에서 사용(쿼리, 키, 값이 동일한 경우)
  • Masked Decoder Self-Attention: 디코더에서 사용
  • Encoder-Decoder Attention : 디코더에서 사용(쿼리는 디코더의 벡터, 키와 값은 인코더의 벡터)

Encoder Self-Attention 은 encoder에서, Masked Decoder Self-Attention은 Decoder에서, Encoder-Decoder Attention은 그 후 Decoder에 적용된다. 모든 attention 이름 앞에 달린 Multi-head 라는 것은 어텐션을 병렬적으로 수행하는 것을 의미한다.
![](https://velog.velcdn.com/images/kyungmin1029/post/2fa05237-e99b-4786-ad23-6c0f3b922e24
/image.png)

이제 하나하나씩 뜯어보는 과정을 거치자.

Encoder

트랜스포머는 인코더, 디코더를 하나의 층으로 하여 이를 여러 개 쌓는다고 하였다. 인코더 하나의 구조는 다음 과 같으며, num_layers 만큼 이를 쌓는다.(논문에선 = 6)

  • 하나의 인코더 층은 2개의 sublayer 로 구성되고
  • Self-Attention 과 FFNN 가 구성요소이다

Encoder - Self Attention

첫번째 요소인 Self-Attention 을 알아보자. 구체적인 계산과정까지 다룰 것이기에 내용이 길어질 것이다.

어텐션 함수는 기본적으로 주어진 쿼리에 대해 모든 키와의 유사도를 구한 다음, 유사도를 가중치로 키에 대한 값을 계산한다. (attention weight) 쿼리와 이 값들을 모두 가중합하면 Attention Value 를 계산할 수 있다.

변형된 Self Attention에서의 Q, K, V는 전부 동일하다.

Q: 입력 문장의 모든 단어 벡터들
K: 입력 문장의 모든 단어 벡터들
V: 입력 문장의 모든 단어 벡터들

이러한 Self-Attention 은 어떤 의도가 있을까? 모든 단어 쌍 사이의 관계를 고려한 후 학습할 수 있게 된다. 예컨대 트랜스포머를 통해 한국어 - 영어로 번역하는 문제를 풀 경우, Self-Attention 을 인코더에서 쓴다는 것은 입력 시퀀스인 한국어만 보고 그 내에서 모든 쌍의 관계를 고려해 학습한다는 것을 말한다.

계산 1) Q, K, V 벡터 얻기

셀프 어텐션은 임베딩 디멘션의 차원을 가지는 단어 벡터들을 사용하여 어텐션을 수행하는 것이 아니고, 우선 각 단어들로부터 Q, K, V 벡터를 먼저 얻는다. (참고해야 할 것은 이때는 512차원은 아니고 이보다 작은 차원인 64차원의 Q, K, V 벡터를 얻는다.)

64라는 값은 전체 임베딩 디멘션인 512 차원을 num_head, 그러니까 병렬연산의 개수인 8고 나눈 512 / 8 = 64 에서 나온 값이다. 이제 단어 벡터 하나를 Q, K, V로 변환하는 과정을 보자.

단어 벡터에 곱해지는 가중치 행렬 W는 (단어의 차원; 여기서는 4) X (단어의 차원/num_heads) 가 된다. 이 가중치 행렬은 학습 가능하고, 위 그림처럼 student 벡터 하나로부터 서로 다른 가중치를 곱하여 각각의 Q, K, V 벡터를 얻는다. (이를 I am a student 모든 단어에 대해 수행)

계산 2) Scaled dot-product Attention

각 단어에 대해 Q, K, V 값을 구했으니 각 Q벡터는 모든 K벡터에 대해 어텐션 스코어를 구하고, 분포를 이용하여 V벡터를 가중합하여 컨텍스트 벡터를 구한다. 이 과정을 모든 Q에 대해 반복.

여기선 Scaled dot 이라고 하여 q와 k를 곱한 후 n에 루트를 씌운 값으로 나눈 값을 어텐션 함수로 사용한다. 트랜스포머에서는 k벡터의 차원을 나타내는 dkd_k에 루트를 씌운 값으로 나누어주었다. 따라서 논문에서는 dkd_k 64에 루트를 씌운 8로 나눈 값을 가진다.

어텐션 스코어 => 어텐션 분포를 구하고, 다시 각 V벡터와 가중합하면 Attention Value 값을 구할 수 있다. (= 단어 I에 대한 Context vector)

계산 3) 일괄 처리하기

I, am, a, student 를 따로 연산하지 않고 행렬로 일괄 계산하자. 각 벡터마다 Q, K, V는 (그림의 예시에서) 1 X 2 였으니 4단어가 붙는다면 Q, K, V 행렬은 각각 4 X 2 가 될 것이다. 문장 행렬에 가중치 행렬을 곱하여 Q,K,V 행렬을 구하는 그림이다.

각 단어에 대해 Q, K, V 를 구한 것이니 쿼리 Q에 대해 키 K 행렬을 곱하면 (곱하고 scale 하는 과정을 거치면) Self 연산에 대한 attention distribution 이 완성될 것이다. 이 값에 각 단어의 V를 곱하면 최종 구하고자 하는 값인 Attention Value Matrix 가 계산된다.

아래의 수식까지 확인하며 계산 과정에 대한 설명을 정리해볼 수 있다.

  • 입력이 들어오면 모든 단어에 대해 Q, K, V를 계산하며 이를 행렬로 만든다.
  • Q, K의 크기는 (seq_len, dkd_k) 이며, V의 크기는 (seq_len, dvd_v) 이다.
  • 먼저 Q와 K전치 행렬을 곱하고 scale 한 attention score 을 계산한다
  • 여기에 Softmax 를 적용한 attention weight 에 (어떤 단어에 집중할지)
  • 실제 V 값을 곱하면 (집중할 단어 적용, 확정) Attention Value 가 완성.
profile
Mathematics, Algorithm, and IDEA for AI research🦖

0개의 댓글