이번 포스팅은 Transformer에 대해 알아보겠습니다.

 

seq2seq 모델은 인코더-디코더 구조로 구성되어져 있었습니다.

 

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

 

하지만 이러한 구조는 인코더가 입력 시퀀스를 하나의 벡터로 압축하는 과정에서 입력 시퀀스의 정보가 일부 손실된다는 단점이 있었고, 이를 보정하기 위해 어텐션이 사용되었습니다.

 

그런데 어텐션을 RNN의 보정을 위한 용도로서 사용하는 것이 아니라 어텐션만으로 인코더와 디코더를 만든게 Transformer 입니다.

 

 

Transformer 하이퍼 파라미터

 

  • \(d_{model}\) = 512 : 
    • 인코더와 디코더에서의 정해진 입력과 출력의 크기
    • 각 인코더와 디코더가 다음 층의 인코더와 디코더로 값을 보낼 때에도 이 차원을 유지
  • num_layers = 6 : 
    • 인코더와 디코더가 총 몇 층으로 구성되었는지를 의미
  • num_haeds = 8 : 
    • 어텐션을 사용할 때, 한 번 하는 것 보다 여러 개로 분할해서 병렬로 어텐션을 수행하고 결과값을 다시 하나로 합치는 방식을 택했습니다. 이때 이 병렬의 개수
  • \(d_{ff}\) = 2048 : 
    • 피드 포워드 신경망이 존재하며 해당 신경망의 은닉층의 크기를 의미

 

 

Transformer

 

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

 

이번에는 인코더와 디코더라는 단위가 N개로 구성되는 구조입니다.

Transformer

 


 

 

Positional Encoding

 

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

 

RNN의 특성으로 인해 각 단어의 위치 정보(position information)를 가질 수 있다는 점에 있었습니다.

 

하지만 트랜스포머는 단어 입력을 순차적으로 받는 방식이 아니므로 단어의 위치 정보를 다른 방식으로 알려줄 필요가 있습니다.

 

트랜스포머는 단어의 위치 정보를 얻기 위해서 각 단어의 임베딩 벡터에 위치 정보들을 더하여 모델의 입력으로 사용하는데,

 

이를 포지셔널 인코딩(positional encoding)이라고 합니다.

 

 

임베딩 벡터가 인코더의 입력으로 사용되기 전 포지셔널 인코딩값이 더해지는 과정입니다.

 

Positional Encoding가 구해지는 식을 보겠습니다.

 

Positional Encoding

 

  • \(pos\) : 입력 문장에서의 임베딩 벡터의 위치
    • \(i\) : 임베딩 벡터 내의 차원의 인덱스를 의미
      • \(2i + 1\) (홀수) 일때는 \(cos\) 함수 사용
      • \(2i\) (짝수) 일때는 \(sin\) 함수 사용
  • \(d_{model}\) : 트랜스포머의 모든 층의 출력 차원을 의미, 위에서 512라고 설정해놓은 하이퍼파라미터 값.

 

위와 같은 포지셔널 인코딩 방법을 사용하면 순서 정보가 보존되는데,

 

예를 들어 각 임베딩 벡터에 포지셔널 인코딩의 값을 더하면 같은 단어라고 하더라도 문장 내의 위치에 따라서 트랜스포머의 입력으로 들어가는 임베딩 벡터의 값이 달라집니다.

 


 

Attention

 

Transformer에서 사용하는 Attention의 종류는 3가지입니다.

 

Encoder와 Decoder의 구성을 보면

 

  1. Encoder
    • Encoder Self-Attention : Multi-head Self-Attention은 Self-Attention을 병렬적으로 사용하였다는 의미
    • Position-wise FFNN
  2. Decoder
    • Masked Decoder Self-Attention
    • Encoder-Decoder Attention

 

그러면 먼저 Encoder Self-Attention 부터 알아보겠습니다.

 

 

Encoder Self-Attention

 

어텐션을 자기 자신에게 수행한다는 의미입니다.

 

Seq2Seq

앞서 배운 seq2seq에서 어텐션을 사용할 경우의 Q, K, V의 정의를 다시 생각해보겠습니다.

 

사실 t 시점이라는 것은 계속 변화하면서 반복적으로 쿼리를 수행하므로 결국 전체 시점에 대해서 일반화를 할 수도 있습니다.

그런데 셀프 어텐션에서는 Q, K, V가 전부 동일합니다. 트랜스포머의 셀프 어텐션에서의 Q, K, V는 아래와 같습니다.

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

 

Self-Attention의 장점

사람은 그것(it)이 피곤한 주체가 동물이라는 것을 아주 쉽게 알 수 있지만 기계는 그렇지 않습니다.

 

하지만 셀프 어텐션은 입력 문장 내의 단어들끼리 유사도를 구하므로서 그것(it)이 동물(animal)과 연관되었을 확률이 높다는 것을 찾아냅니다.

 

 

Self-Attention의 Q, K, V를 구하는 방법

위 사진은 Self-Attention의 Q, K, V를 구하는 방법입니다.

 

기존의 벡터로부터 더 작은 벡터는 가중치 행렬을 곱하므로서 완성됩니다.

 

각 가중치 행렬은 \(dmodel\times(dmodel/num_heads)\)의 크기를 가집니다.

 

가중치 행렬은 훈련 과정에서 학습됩니다.

 

즉, 논문과 같이 dmodel=512이고 num_heads=8 이라면,

 

가중치 행렬은 각각 512 x (512 / 8) = 512 x 64 크기를 가지게 됩니다.

 

그리고 각 벡터에 3개의 서로 다른 가중치 행렬을 곱하고 64의 크기를 가지는 Q, K, V 벡터를 얻어냅니다.

 

모든 단어 벡터에 위와 같은 과정을 거치면 I, am, a, student는 각각의 Q, K, V 벡터를 얻습니다.

 

이후, Attention에서 해주었던과 같이 계산해줍니다.

 

여기서 \(d_{k} = d_{model}/\)num_heads 입니다.

 

 

행렬 연산으로 일괄 처리하기

 

 

 

위와 같이 행렬을 이용하여 한번에 처리할 수 있습니다.

 

 


 

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

 

병렬 어텐션으로 얻을 수 있는 효과는 다른 시각으로 정보들을 수집하겠다는 겁니다.

 

앞서 사용한 예문 '그 동물은 길을 건너지 않았다. 왜냐하면 그것은 너무 피곤하였기 때문이다.'를 상기해봅시다.

 

단어 그것(it)이 쿼리였다고 해봅시다.

 

즉, it에 대한 Q벡터로부터 다른 단어와의 연관도를 구하였을 때 첫번째 어텐션 헤드는 '그것(it)'과 '동물(animal)'의 연관도를 높게 본다면, 두번째 어텐션 헤드는 '그것(it)'과 '피곤하였기 때문이다(tired)'의 연관도를 높게 볼 수 있습니다.

 

각 어텐션 헤드는 전부 다른 시각에서 보고있기 때문입니다.

 

Multi-head Attention

 

위와 같은 방식으로 Multi-head Attention은 진행해 줍니다.

 

이후,

\(a_{0}, a_{1}, a_{2}, ... \) 를 concatenate 해줍니다.

 

 

이렇게 나온 결과 행렬이 멀티-헤드 어텐션의 최종 결과물입니다.

 

위의 그림은 어텐션 헤드를 모두 연결한 행렬이 가중치 행렬 Wo과 곱해지는 과정을 보여줍니다.

 

이때 결과물인 멀티-헤드 어텐션 행렬은 인코더의 입력이었던 문장 행렬의 (seq_len, dmodel) 크기와 동일합니다.

 

 


 

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

 

Position-wise FFNN은 인코더와 디코더에서 공통적으로 가지고 있는 서브층입니다.

 

쉽게 말하면 완전 연결 FFNN(Fully-connected FFNN)이라고 해석할 수 있습니다.

 

앞서 인공 신경망은 결국 벡터와 행렬 연산으로 표현될 수 있음을 배웠습니다.

 

아래는 포지션 와이즈 FFNN의 수식을 보여줍니다.

 

  • \(d_{ff}\)=2048
  • \(x\)= (seq_len, dmodel) 의 크기
  • \(W_{1}\)= (dmodel, dff) 의 크기
  • \(W_{2}\)= (dff, dmodel) 의 크기

W1, b1, W2, b2는 하나의 인코더 층 내에서는 다른 문장, 다른 단어들마다 정확하게 동일하게 사용됩니다.

 

하지만 인코더 층마다는 다른 값을 가집니다.

 

 


 

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

 

FFNN을 통과한 후 잔차 연결과 정규화를 거치게 됩니다.

 

잔차 연결에 대한 설명은 생략하도록 하고 정규화에 대해 알아보겠습니다.

 

위 사진은 정규화가 되는 과정을 표현한 겁니다.

  • \(\gamma\) 의 초기값은 1
  • \(\beta\) 의 초기값은 0

 

 


 

Decoder - Masked Multi-head Self-Attention

 

디코더는 번역할 문장에 해당되는 문장 행렬을 한 번에 입력받습니다.

 

seq2seq의 디코더에 사용되는 RNN 계열의 신경망은 입력 단어를 매 시점마다 순차적으로 입력받으므로

 

다음 단어 예측에 현재 시점을 포함한 이전 시점에 입력된 단어들만 참고할 수 있습니다.

 

반면, Transformer는 문장 행렬로 입력을 한 번에 받으므로 현재 시점의 단어를 예측하고자 할 때,

 

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

 

가령, suis를 예측해야 하는 시점이라고 해봅시다. Input은 <sos> je suis étudiant 입니다.

 

RNN 계열의 seq2seq의 디코더라면 현재까지 디코더에 입력된 단어는 <sos>와 je뿐일 것입니다.

 

반면, Transformer는 이미 문장 행렬로 <sos> je suis étudiant를 입력받았습니다.

 

이를 위해 Transformer의 디코더에서는 현재 시점의 예측에서 현재 시점보다 미래에 있는 단어들을 참고하지 못하도록 룩-어헤드 마스크(look-ahead mask)를 도입습니다.

 

룩-어헤드 마스크(look-ahead mask)는 디코더의 첫번째 서브층인 Masked Multi-head Self-Attention에서 동작됩니다.

 

디코더의 첫번째 서브층인 멀티 헤드 셀프 어텐션 층은 인코더의 첫번째 서브층인 멀티 헤드 셀프 어텐션 층과 동일한 연산을 수행합니다.

 

오직 다른 점은 어텐션 스코어 행렬에서 마스킹을 적용한다는 점만 다릅니다.

 

우선 다음과 같이 셀프 어텐션을 통해 어텐션 스코어 행렬을 얻습니다.

 

 

마스킹 된 후의 어텐션 스코어 행렬의 각 행을 보면 자기 자신과 그 이전 단어들만을 참고할 수 있음을 볼 수 있습니다.

 

그 외에는 인코더의 첫번째 서브층과 같습니다.

 

여기서 마스크는 Attention Score Matrix의 마스킹 할 위치에 매우 작은 음수값을 더해줍니다.

 

매우 작은 값이므로 소프트맥스 함수를 지나면 행렬의 해당 위치의 값은 0이 됩니다.

 

Transformer 에는 Attetion이 총 3번 쓰이는데 각 어텐션 시 전달하는 마스킹은 아래와 같습니다.

  • 인코더의 셀프 어텐션 : 패딩 마스크를 전달
  • 디코더의 첫번째 서브층인 마스크드 셀프 어텐션 : 룩-어헤드 마스크를 전달 <-- 지금 설명하고 있음.
  • 디코더의 두번째 서브층인 인코더-디코더 어텐션 : 패딩 마스크를 전달

 

 


 

Decoder - Encoder-Decoder Attention

 

디코더의 두번째 서브층은 멀티 헤드 어텐션을 수행한다는 점에서는 이전의 어텐션들과는 공통점이 있으나

이번에는 셀프 어텐션이 아닙니다.

 

셀프 어텐션은 Query, Key, Value가 같은 경우를 말하는데, 인코더-디코더 어텐션은 Query가 디코더인 행렬인 반면,

 

Key와 Value는 인코더 행렬이기 때문입니다. 다시 한 번 각 서브층에서의 Q, K, V의 관계를 정리해봅시다.

  • 인코더의 첫번째 서브층 : Query = Key = Value (Self-Attention)
  • 디코더의 첫번째 서브층 : Query = Key = Value (Self-Attention)
  • 디코더의 두번째 서브층 : Query : 디코더 행렬 / Key = Value : 인코더 행렬

 

Encoder-Decoder Attention

위 그림을 보면 Query는 Decoder 행렬, Key = Value는 Encoder 행렬로 볼 수 있습니다.

 

Attention Score Matrix는 위와 같이 계산이 되겠습니다.

 

다음 계산은 Attention 과 같으니 생략하도록 하겠습니다.

 

 

 

 

 

 

출처:

'Deep Learning > NLP' 카테고리의 다른 글

02. Attention  (0) 2022.05.24
01. RNN, LSTM  (0) 2022.05.23

+ Recent posts