본문 바로가기
AI

Transformer

by floraj 2023. 6. 25.

Transformer (2017)

Reference

https://wikidocs.net/31379

 

 

구글이 발표한 논문인 "Attention is all you need"에서 나옴.

 

기존의 seq2seq의 구조인 인코더-디코더를 따르면서도,

논문의 이름처럼 어텐션(Attention)만으로 구현한 모델

 

기존의 seq2seq 모델의 한계

 

기존의 seq2seq 모델은 인코더-디코더 구조로 구성

인코더는 입력 시퀀스를 하나의 벡터 표현으로 압축하고, 디코더는 이 벡터 표현을 통해서 출력 시퀀스를 만들어냄.

인코더가 입력 시퀀스를 하나의 벡터로 압축하는 과정에서 입력 시퀀스의 정보가 일부 손실된다는 단점 이를 보정하기 위해 어텐션이 사용.

어텐션을 RNN의 보정을 위한 용도로서 사용하는 것이 아니라 어텐션만으로 인코더와 디코더를 만들어봄.

 

 트랜스포머(Transformer)의 주요 하이퍼파라미터

 

인코더와 디코더가 6개씩 존재

인코더에서 입력 시퀀스를 입력받고, 디코더에서 출력 시퀀스를 출력하는 인코더-디코더 구조

seq2seq 구조에서는 인코더와 디코더에서 각각 하나의 RNN이 t개의 시점(time step)을 가지는 구조였다면

이번에는 인코더와 디코더라는 단위가 N개로 구성

 

 

인코더로부터 정보를 전달받아 디코더가 출력 결과를 만들어내는 트랜스포머 구조

시작 심볼 <sos>를 입력으로 받아 종료 심볼 <eos>가 나올 때까지 연산을 진행

 

 

트랜스포머 입력방식: 포지셔널 인코딩(Positional Encoding)

RNN이 자연어 처리에서 유용했던 이유는 단어의 위치에 따라 단어를 순차적으로 입력받아서

각 단어의 위치 정보(position information)를 가졌다는 점에 있었음

 

트랜스포머는 단어 입력을 순차적으로 받는 방식이 아니므로

단어의 위치 정보를 다른 방식으로 알려줄 필요가 있음

 

각 단어의 임베딩 벡터에 위치 정보들을 더하여 모델의 입력으로 사용하는

포지셔널 인코딩(positional encoding) 사용

 

임베딩 벡터와 포지셔널 인코딩의 덧셈.

임베딩 벡터가 모여 만들어진 문장 행렬 +  포지셔널 인코딩 행렬 덧셈. (행렬 덧셈이라는 것)

 

=> 임베딩 벡터들이 트랜스포머의 입력으로 사용되기 전에 포지셔널 인코딩의 값이 더해짐.

 

 

 

위치 정보를 가진 값을 만들기 위한 두 개의 함수

 

pos: 입력 문장에서의 임베딩 벡터의 위치

i: 임베딩 벡터 내의 차원.

d model: 트랜스포머의 모든 층의 출력 차원. 그림에서는 4지만 실제 논문에서는 512.

 

임베딩 벡터 내의 각 차원의 인덱스가 짝수인 경우에는 사인 함수의 값을 사용하고

홀수인 경우에는 코사인 함수의 값을 사용

 

포지셔널 인코딩을 사용하면 순서 정보가 보존됨.

각 임베딩 벡터에 포지셔널 인코딩의 값을 더하면,

같은 단어라고 하더라도 문장 내의 위치에 따라서 트랜스포머의 입력으로 들어가는 임베딩 벡터의 값이 달라짐.

트랜스포머의 입력은 순서 정보가 고려된 임베딩 벡터가 되는 것.

 

 

트랜스포머의 세 가지 어텐션(Attention)

 

 

 

첫 번째 셀프 어텐션은 인코더에서, 

두 번째 셀프 어텐션과 세번째 인코더-디코더 어텐션은 디코더에서 이루어짐.

 

셀프 어텐션은 본질적으로 Query, Key, Value가 동일한 경우를 말함.

(벡터의 값이 같다는 것이 아니라 벡터의 출처가 같다는 것)

인코더-디코더 어텐션에서는 Query는 디코더의 벡터, Key와 Value는 인코더의 벡터이기 때문에 셀프 어텐션이 아님.

 

 

 

 

num_layers 개수만큼 인코더 층을 쌓음. 논문에서는 총 6개 인코더 층 사용.

하나의 인코더 층은 크게 셀프 어텐션과 피드 포워드 신경망 총 2개의 서브층(sublayer)으로 나뉨.

(멀티 헤드 셀프 어텐션은 셀프 어텐션을 병렬적으로 사용하였다는 의미,

포지션 와이즈 피드 포워드 신경망은 일반적인 피드 포워드 신경망).

 

 

인코더의 셀프 어텐션

 

의미와 이점

셀프 어텐션의 Q, K, V 

 

어텐션 함수는 주어진 '쿼리(Query)'에 대해서 모든 '키(Key)'와의 유사도를 각각 구하고, -> 구해낸 이 유사도를 가중치로 하여 키와 맵핑되어있는 각각의 '값(Value)'에 반영 -> 유사도가 반영된 '값(Value)'을 모두 가중합하여 리턴

 

 

쿼리(Q):

문장의 각 단어에 대한 쿼리는 해당 단어의 의미나 특성. "love"에 대한 쿼리(Q)는 "love"의 임베딩 벡터.

 

키(K):

각 단어의 키는 다른 단어와의 관계를 나타내는 역할. 키는 어텐션을 계산하는 데 사용.

 

값(V):

은 키와 관련된 정보. 어텐션 계산 결과에서 가중합을 구성하는 데 사용.

 

 

 

셀프 어텐션(self-attention)은 어텐션을 자기 자신에게 수행한다는 것. 

 

seq2seq의 Q,K,V 정의

모든 시점으로 일반화 가능.

(입력의 모든 시점에 대해 쿼리를 수행하고 처리한다는 의미.

각 시점의 쿼리 어텐션 계산은 독립적으로 이루어지지만, 전체 시점에 걸쳐서 반복)

트랜스포머 셀프 어텐션의 Q,K,V

 

셀프 어텐션의 효과

 

 

셀프 어텐션은 입력 문장 내의 단어들끼리 유사도를 구하기 때문에

it이 animal과 관련될 확률이 높다는 것을 찾아냄.

 

 

셀프 어텐션 순서

  • 각 인코더의 입력 벡터(각 단어의 임베딩)에서 Q, K, V 생성.
  • 다음으로 각 Q벡터의 모든 K벡터에 대해서 어텐션 스코어를 구하고,
    (어텐션 스코어: *i번째 단어가 다른 단어와 얼마나 유사도가 있는지 계산)
  • 어텐션 분포를 구한 뒤에 스케일링 해서 어텐션 레이트로 바꿈. 
  • 모든 V벡터를 가중합하여 어텐션 값 또는 컨텍스트 벡터를 구함.
  • 이를 모든 Q벡터에 대해서 반복.

 

Q, K, V 벡터 얻기

  • 셀프 어텐션은 인코더의 초기 입력인 d_model 차원을 갖는 단어 벡터들을 사용하여 셀프 어텐션을 수행하는 것이 아니라, 우선 각 단어 벡터들로부터 Q벡터, K벡터, V벡터를 얻는 작업을 먼저 거침.
  • (Q벡터, K벡터, V벡터들은 초기 입력인 d의 차원을 가지는 단어 벡터들보다 더 작은 차원을 가지는데,
    논문에서는 d=512의 차원을 64의 차원으로 변환. 64라는 값은 트랜스포머의 num_heads로 인해 결정.)
  • Q, K, V의 차원은 d _model을  num_heads로 나눈 값인 가중치 행렬을 곱해서 완성되고,
  • 가중치 행렬은 훈련 과정에서 학습 됨.

 

가중치 행렬 크기

 

student를 Q, K, V 벡터로 변환하는 과정.

 

 

 

스케일드 닷-프로덕트 어텐션(Scaled dot-product Attention)

 

트랜스포머에서는 여러 어텐션 함수 중 닷-프로덕트 어텐션(dot-product attention)에 스케일링이 추가된

스케일드 -을 사용. .

  • 각 인코더의 입력 벡터(각 단어의 임베딩)에서 Q, K, V 생성.
  • (기존 어텐션과 동일) 다음으로 각 Q벡터의 모든 K벡터에 대해서 어텐션 스코어를 구하고,
    (어텐션 스코어: *i번째 단어가 다른 단어와 얼마나 유사도가 있는지 계산)
  • 어텐션 분포를 구해서 어텐션 레이트로 바꿈. 
  • 모든 V벡터를 가중합하여 어텐션 값 또는 컨텍스트 벡터를 구함.
  • 이를 모든 Q벡터에 대해서 반복.

 

스케일드 닷-프로덕트 어텐션

score(Q, K) = Q * K^T / sqrt(d_k)

 

-> 단어 I에 대한 Q벡터가 모든 K벡터에 대해서 어텐션 스코어를 구하는 과정

 

(어텐션 스코어는 각각 단어 I가 단어 I, am, a, student와 얼마나 연관되어 있는지를 보여주는 수치)

 

두 벡터의 내적값을 스케일링하는 값으로 K벡터의 차원을 나타내는 sqrt(d_k) 사용. 논문에서는 8. 

 

 

어텐션 스코어에 소프트맥스 함수를 사용하여 어텐션 분포(Attention Distribution)을 구하고,

각 V벡터와 가중합하여 어텐션 값(Attention Value)을 구함.

= 단어 I에 대한 어텐션 값 또는 단어 I에 대한 컨텍스트 벡터(context vector)

 

위의 계산은 모두 행렬 연산으로 일괄 처리 가능

 

 

왜 멀티 헤드 어텐션(Multi-head Attention)?

 

논문에서는 512의 차원의 각 단어 벡터를 8로 나누어 64차원의 Q, K, V 벡터로 바꾸어서 어텐션을 수행.

 

왜 축소시킨 벡터로 했냐.

여러번의 어텐션을 병렬로 사용하는 것이 더 효과적 = 다른 시각으로 정보들을 수집하겠다

 

그래서 d_model의 차원을 num_heads로 나눈 d_model/num_heads의 차원을 가지는 O, K, V에 대해 

num_heads개의 병렬 어텐션을 수행한 것.

 

이때 각각의 어텐션 값 행렬을 어텐션 헤드라 함.

(가중치 행렬 W^Q, W^K, W^V의 값은 8개의 어텐션 헤드마다 다 다름) 

 

어텐션 헤드를 모두 연결한 행렬 * 가중치 행렬 W_o

  • 병렬 어텐션을 모두 수행하고 나면 모든 어텐션 헤드를 연결(concatenate)함.
  • 어텐션 헤드를 모두 연결한 행렬에 또 다른 가중치 행렬 W^o을 곱하고 그 행렬이 멀티-헤드 어텐션의 최종 결과물.

 

  • 멀티-헤드 어텐션 행렬은 인코더의 입력이었던 문장 행렬의 (seq_len, d model) 크기와 동일.
    = 인코더의 첫번째 서브층인 멀티-헤드 어텐션 단계를 끝마쳤을 때, 인코더의 입력으로 들어왔던 행렬의 크기가 아직 유지되고 있다는 것.
  • 첫번째 서브층인 멀티-헤드 어텐션과 두번째 서브층인 포지션 와이즈 피드 포워드 신경망을 지나면서 인코더의 입력으로 들어올 때의 행렬의 크기는 계속 유지되어야 함. 트랜스포머는 동일한 구조의 인코더를 쌓은 구조로, 인코더에서의 입력의 크기가 출력에서도 동일 크기로 계속 유지되어야만 다음 인코더에서도 다시 입력이 될 수 있기 때문.

 

 

패딩 마스크(Padding Mask)

구현을 해보면, 스케일드 닷 프로덕트 어텐션 함수 내부에서,

mask라는 값을 인자로 받아 이 mask값에 -1e9 (-무한대에 가까운)을 곱한 후 어텐션 스코어 행렬에 더해주는 부분.

 

입력 문장에 <PAD> 토큰이 있을 경우 어텐션에서 사실상 제외하기 위한 연산

 

예를 들어, 문장 "I love playing soccer"와 "He enjoys swimming"의 최대 길이가 5라고 가정하면,

두 문장 모두 5개의 단어로 맞추기 위해 부족한 부분은 <PAD> 토큰으로 채우는 것.

 

"I love playing soccer" -> ["I", "love", "playing", "soccer", "<PAD>"]
"He enjoys swimming" -> ["He", "enjoys", "swimming", "<PAD>", "<PAD>"]

 

 

소프트맥스 함수를 지나면 각 행의 어텐션 가중치의 총 합은 1이 되는데,

단어 <PAD>의 경우에는 0이 되어 어떤 유의미한 값을 갖지 않게 됨.

 

입력된 정수 시퀀스에서 패딩 토큰의 인덱스인지, 아닌지를 판별하는 함수를 구현해서 사용.

정수 시퀀스에서 0인 경우에는 1로 변환하고, 그렇지 않은 경우에는 0으로 변환

 

 포지션-와이즈 피드 포워드 신경망(Position-wise FFNN)

 

포지션 와이즈 FFNN은 인코더와 디코더에서 공통적으로 가지고 있는 서브층.

완전 연결 FFNN(Fully-connected FFNN)이라고 해석 가능.

어텐션을 거치면서 입력 시퀀스의 정보를 효과적으로 변환하고, 다음 계층으로 전달

 

FFNN 수식
FFNN 그림

 

  • x = 멀티 헤드 어텐션의 결과로 나온 (seq_len, d_model)의 크기를 가지는 행렬.
  • W^1은 (d_model, d_ff) 크기, W^2는 (d_ff, d_model) 크기.
  • d_ff는 은닉층 크기. 논문에서는 2,048의 크기.
  • 각각의 매개변수들은 하나의 인코더 층 내에서는 다른 문장, 다른 단어들마다 정확하게 동일하게 사용되고,
    인코더 층마다는 다른 값을 가짐.

 

 

두 번째 서브층을 지난 인코더의 최종 출력이 인코더의 입력 크기로 보존되고 있음을 확인.

하나의 인코더 층을 지난 이 행렬은 다음 인코더 층으로 전달되고, 다음 층에서도 동일한 인코더 연산 반복

 

 

잔차 연결(Residual connection)과 층 정규화(Layer Normalization)

 

 

두 개의 서브층을 가진 인코더에 추가적으로 사용하는 기법. Add & Norm

서브층 이전의 입력에서 시작되어 서브층의 출력 부분을 향하고 있음.

 

잔차 연결(Residual connection)

잔차 연결은 서브층의 입력과 출력을 더하는 것.

(서브층의 입력과 출력은 동일한 차원을 갖고 있으므로, 덧셈 연산 가능)

그래디언트 소실 문제 해결, 정보의 보존과 학습 향상, 모델의 수렴 속도 향상

 

멀티 헤드 어텐션일 경우 잔차 연결 연산

층 정규화(Layer Normalization)

  • 층 정규화는 텐서의 마지막 차원(d_model)에 대해 평균과 분산을 구해 정규화 해 학습을 돕는 역할.
  • 잔차 연결의 입력을 x, 잔차 연결과 층 정규화를 한 후 결과 행렬을 LN이라 했을때,

 

 

 

 

디코더의 첫번째 서브층 : 셀프 어텐션과 룩-어헤드 마스크

디코더도 인코더와 동일하게 임베딩 층과 포지셔널 인코딩을 거친 후의 문장 행렬이 입력되고

 seq2seq처럼 문장 행렬을 한 번에 입력받아 각 시점의 단어를 예측하도록 훈련.

 

 

트랜스포머는 문장 행렬로 입력을 한 번에 받으므로 현재 시점의 단어를 예측하고자 할 때,

입력 문장 행렬로부터 미래 시점의 단어까지도 참고할 수 있는 현상이 발생. 

현재 시점의 예측에서 현재 시점보다 미래에 있는 단어들을 참고하지 못하게 룩-어헤드 마스크(look-ahead mask)를 도입

 

룩-어헤드 마스크(look-ahead mask)

룩-어헤드 마스크(look-ahead mask)는 디코더의 첫번째 서브층에서 이루어짐.

첫번째 서브층인 멀티 헤드 셀프 어텐션 층은 인코더의 첫번째 서브층인 멀티 헤드 셀프 어텐션 층과 동일한 연산을 수행, 어텐션 스코어 행렬에서 마스킹을 적용한다는 점만 다름.

 

마스킹 된 후 어텐션 스코어 행렬

자기 자신과 그 이전 단어들만을 참고.

 

디코더의 두번째 서브층 : 인코더-디코더 어텐션

멀티 헤드 어텐션을 수행한다는 점에서 인코더와 디코더의 첫번째 서브층과는 비슷하지만 셀프 어텐션이 아님.

인코더-디코더 어텐션은 Query가 디코더인 행렬인 반면, Key와 Value는 인코더 행렬이기 때문

 

두번째 서브층 밑의 두 개의 화살표는 각각 Key와 Value를 의미. 인코더의 마지막 층에서 온 행렬로부터 얻는다는 것.

반면 Query는 디코더의 첫번째 서브층의 결과 행렬로부터 얻음.

 

Query가 디코더 행렬, Key가 인코더 행렬일 때, 어텐션 스코어 행렬을 구하는 과정 그림.

이외 멀티 헤드 어텐션 수행 과정은 같음.

 

 

'AI' 카테고리의 다른 글

생성모델  (0) 2023.08.06
ViT  (0) 2023.08.06
강화학습  (0) 2023.07.23