티스토리 뷰

728x90

이번 포스팅은 cs231n 강의의 Lecture 11 Attention and Transformers, EECS Lecture 17 Attention 자료를 참고하였습니다. 또한, Transformer 관련 내용으론 해당 블로그의 번역 글을 참고하였습니다. (The Illustrated Transformer)

 

Sequence to Sequence with RNNs

Problem: Input sequence bottlenecked through fixedsized vector. What if T=1000?

Idea: use new context vector at each step of decoder!

 

Sequence to Sequnece의 아이디어로는 컨텍스트 벡터를 인코더와 디코더 사이에 연결하는 것입니다. 

 

Sequence to Sequnece는 RNN Encoder와 Decoder를 결합한 형태로 초기 기계 번역에서 사용되던 딥러닝 모델입니다. 먼저 인코더에서 어떤 문장을 입력 받으면 이를 하나의 고정된 길이의 Context vector로 생성합니다. 이는 입력 받은 문장의 특성을 의미합니다. 디코더에서는 특성 벡터를 입력 받아 앞에서부터 단어를 순차적으로 한 개씩 생성하여 번역된 문장을 생성합니다.

 

문장이 짧은 경우에는 하나의 고정된 Context vector를 만들어도 크게 무리 없이 번역을 수행할 수 있습니다. RNN 기반의 Seq2seq는 input/output data가 길어지면 문제가 발생하는데, Long term dependency와 Vanishing/Exploding gradient입니다.

 

첫 번째는 뒤로 갈수록 앞의 정보를 잃어버리는 문제이며, 두 번째는 딥러닝 모델이다 보니 Backrpop 과정을 거치며 gradient가 소실하거나 폭발해버리는 문제가 발생합니다.

 

Sequence to Sequnece는 완전한 문장을 읽고 모든 정보를 고정 길이 벡터로 압축하는 것에 의존합니다. 그러면 수백 개의 단어가 여러 단어로 표현되는 문장은 정보가 손실되거나 부적절한 번역으로 이어질 수 있습니다. 

 

Sequence to Sequence with RNNs and Attention

Intuition: Context vector attends to the relevant part of the input sequence “estamos” = “we are” so maybe $a_{11}=a_{12}=0.45, a_{13}=a_{14}=0.05$

 

Attention을 적용한 Seq2seq는 모든 정보를 고정 길이 벡터로 인코딩해야 하는 부담에서 인코더를 구합니다. 디코더가 특정 단어를 예측해야 되는 시점에 까먹지 않고 정보를 가져와야 하는데, 그 특정 단어에 대해 가중치를 둔 Context vector를 활용해서 예측할 수 있습니다.

 

  1. 과정을 살펴 보면, alignment scores를 계산합니다.
  2. attention weight를 얻기 위해 이를 정규화합니다.
  3. hidden state랑 곱해서(linear combination) context vector를 얻습니다.
  4. 디코더에서 context vecter를 이용해 $s_t=g_u(y_{t-1}, s_{t-1}, c_t)$를 계산합니다.

 

해당 과정은 반복됩니다. 구한 $s_1$을 통해서 새로운 context vector $c_2$를 계산합니다. 그리고 $c_2$를 통해서 $s_2, y_2$를 계산합니다.

 

디코더의 각 timestep에서 다른 context vector 사용하므로써

  • 입력 시퀀스는 단일 벡터를 통해 병목 현상이 발생하지 않습니다.
  • 디코더의 각 timestep에서 context vector는 입력 시퀀스의 다른 부분을 "살펴 봅니다"

 

즉, 이전 방식과의 차이점은 fixed-length vector가 매 시간 인덱스마다 다르게 반영된다는 점입니다.

 

영어를 프랑스어로 번역하는 작업의 attention wieght $a_{ij}$를 시각화한 표입니다. 해당 그림을 통해서 번역된 결과가 어떠한 입력에 align 되었는지 확인할 수 있습니다다. 한 단어가 무조건 다른 한 단어와 매핑되는 것이 아닌, 한 단어가 여러 단어와의 관계를 나타내는 분포로서 표현이 됩니다. 이를 통해 번역에 더 좋은 성능에 기여하게 됩니다.

 

 

디코더는 $h_i$가 순서가 있는 시퀀스를 형성한다는 사실을 사용하지 않습니다. 순서가 없는 세트 {$h_i$}로 처리합니다. 임의의 입력 hidden vector set {$h_i$}가 주어지면 유사한 아키텍처를 사용할 수 있습니다!

 

 

Image Captioning with RNNs and Attention

 

CNN을 사용해서 이미지의 feature grid를 계산합니다.

 

Alignment scores를 계산하고, Softmax를 통해 Attention weights를 계산합니다. 이를 디코더에 전달하고 해당 과정은 앞에서 설명했던 것과 동일합니다.

 

어텐션 메커니즘을 사용하여 이미지를 먼저 $n$개의 부분으로 나누고 각 부분 $h_1,…,h_n$의 CNN(Convolutional Neural Network) 표현으로 계산합니다. RNN이 새로운 단어를 생성할 때 어텐션 메커니즘은 이미지의 관련 부분에 초점을 맞추고 있으므로 디코더는 이미지의 특정 부분만 사용합니다.

 

아래 그림(상단 행)에서 캡션의 각 단어에 대해 이미지의 어떤 부분(흰색)이 캡션을 생성하는 데 사용되었는지 확인할 수 있습니다.

 

 

 

 

Image Captioning with RNNs and Attention

 

RNN과 Attention을 이용한 이미지 캡셔닝의 결과는 이와 같습니다. 이미지의에서 집중하고 있는 부분을 살펴보고 밑줄이 그어진 단어를 생성하는 것을 볼 수 있습니다.

 

 

이제 Attention model이 어떻게 작동하는지 더 자세히 살펴보고, 마지막에 Transformer에 대한 설명까지 이어집니다.

 

Attention Layer

Attention 계산의 가장 첫 단계는 encoder에 입력된 벡터들에게서 부터 각 3개의 벡터를 만들어내는 일입니다. 우리는 각 단어에 대해서 Query 벡터, Key 벡터, 그리고 Value 벡터를 생성합니다. 이 벡터들은 입력 벡터에 대해서 세 개의 학습 가능한 행렬들을 각각 곱함으로써 만들어집니다.

$x_1$를 weight 행렬인 $W^Q$로 곱하는 것은 현재 단어와 연관된 query 벡터인 $q_1$를 생성합니다. 같은 방법으로 우리는 입력 문장에 있는 각 단어에 대한 query, key, value 벡터를 만들 수 있습니다.

 

두 번째 단계는 점수를 계산하는 것이었습니다. 단어와 입력 문장 속의 다른 모든 단어들에 대해서 각각 점수를 계산합니다. 이 점수는 현재 위치의 이 단어를 인코딩할 때 다른 단어들에 대해 얼마나 집중을 해야 할지를 결정합니다.

 

점수는 현재 단어의 query vector와 점수를 매기려 하는 다른 위치에 있는 단어의 key vector의 내적으로 계산됩니다. 다시 말해, 우리가 위치 #1에 있는 단어에 대해 attention을 계산한다고 했을 때, 점수는 q1 k1의 내적입니다. 그리고 동일하게 두 번째 점수는 q1 k2의 내적입니다.

세 번째와 네 번째 단계는 이 점수들을 일정 크기로 나누는 것입니다. 이 숫자는 key 벡터의 사이즈의 제곱 근이라는 식으로 계산이 된 것입니다. 이 나눗셈을 통해 우리는 더 안정적인 gradient를 가지게 됩니다. 그리고 난 다음 이 값을 softmax 계산을 통과시켜 모든 점수들을 양수로 만들고 그 합을 1으로 만들어 줍니다.

이 softmax 점수는 현재 위치의 단어의 encoding에 있어서 얼마나 각 단어들의 표현이 들어갈 것인지를 결정합니다. 당연하게 현재 위치의 단어가 가장 높은 점수를 가지며 가장 많은 부분을 차지하게 되겠지만, 가끔은 현재 단어에 관련이 있는 다른 단어에 대한 정보가 들어가는 것이 도움이 됩니다.

 

다섯 번째 단계는 이제 입력의 각 단어들의 value 벡터에 이 점수를 곱하는 것입니다. 이것을 하는 이유는 우리가 집중을 하고 싶은 관련이 있는 단어들은 그래도 남겨두고, 관련이 없는 단어들은 0.001 과 같은 작은 숫자 (점수)를 곱해 없애버리기 위함입니다.

마지막 여섯 번째 단계는 이 점수로 곱해진 weighted value 벡터들을 다 합해 버리는 것입니다. 이 단계의 출력이 바로 현재 위치에 대한 self-attention layer의 출력이 됩니다.

 

이 여섯 가지 과정이 바로 self-attention의 계산 과정입니다. 우리는 이 결과로 나온 벡터를 feed-forward 신경망으로 보내게 됩니다. 그러나 실제 구현에서는 빠른 속도를 위해 이 모든 과정들이 벡터가 아닌 행렬의 형태로 진행됩니다. 

 

 

  1. $Similarity(key, value)$: key와 value의 유사도 계산
  2. $SimxValue(Sim, Value)$: 유사도와 value를 곱함
  3. $Result(outputs)$: 유사도와 value를 곱한 값의 합을 리턴함
  4. $result = \Sigma similarity(key, value) * value$

 

 

유사도를 계산하기 위해 matrix multiplication을 통해 한 번에 계산합니다. 

 

Scaled dot product는 나누어주는 $를 의미합니다. 벡터의 차원이 매우 높을 경우, 내적의 결과 값이 매우 커지게 되는데 이 값이 softmax에 들어가게 되면 vanishing gradient 문제가 발생합니다.

 

 

 

 

Attention Layer의 동작 방식은 이렇습니다.

  • Input vectors $X$가 주어질 때, $K=XW_k$ 연산을 통해 Key vectors $K$를 생성합니다.
  • Query vectors $Q$와 Key vector $K$를 통해 $E_{i,j}=Q_iK_j / sqrt(D_Q)$를 계산하여 Similarity Matrix $E$를 생성합니다.
  • Similarity Matrix E를 softmax에 통과 시켜 Attention Weight Matrix $A$를 생성합니다.
  • Input vectors $X$에 $W_V$를 곱해 Value vectors $V$를 생성합니다.
  • Attention Weights $A$와 Value vectors $V$를 $Y_j=\Sigma_j A_{i,j}V_j$를 계산하면 Output vectors $Y$를 구할 수 있습니다.

 

 

 

 

Self-Attention Layer

그렇다면 이 Query, Key, Value 벡터란 무엇을 의미하는 걸까요?

Q = Query : t 시점의 디코더 셀에서의 hidden states
K = Keys : 모든 시점의 인코더 셀의 hidden states
V = Values : 모든 시점의 인코더 셀의 hidden states


가장 첫 스텝은 입력 문장에 대해서 Query, Key, Value 행렬들을 계산하는 것입니다. 이를 위해 우리는 우리의 입력 벡터들 (혹은 embedding 벡터들)을 하나의 행렬 X로 쌓아 올리고, 그것을 우리가 학습할 weight 행렬들인 $W_Q, W_K, W_V$로 곱합니다. 

행렬 X의 각 행은 입력 문장의 각 단어에 해당합니다. 우리는 여기서 다시 한번 embedding 벡터들 (크기 512, 그림에서는 4)과 query/key/value 벡터들 (크기 64, 그림에서는 3) 간의 크기 차이를 볼 수 있습니다.

 

마지막으로, 우리는 현재 행렬을 이용하고 있으므로 앞서 설명했던 self-attention 계산 단계 2부터 6까지를 하나의 식으로 압축할 수 있습니다.

 

행렬 형태로 표현한 self-attention 계산

 

 

 

 

 

 

Self-Attention Layer

모델이 입력 문장 내의 각 단어를 처리해 나감에 따라, self-attention은 입력 문장 내의 다른 위치에 있는 단어들을 보고 거기서 힌트를 받아 현재 타겟 위치의 단어를 더 잘 encoding 할 수 있습니다.

 

RNN이 hidden state를 유지하고 업데이트함으로써 현재 처리 중인 단어에 어떻게 과거의 단어들에서 나온 맥락을 연관시켰나요? 그와 동일하게 Transformer에게는 이 self-attention이 현재 처리 중인 단어에 다른 연관 있는 단어들의 맥락을 불어 넣어주는 method입니다.

 

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

 

 

 

 

 

 

 

 

Masked Self-Attention Layer

 

Masked Self-Attention Layer는 토큰을 임베딩 벡터로 표현할 때, 패딩을 수행하게 될 경우가 존재합니다. 이때 패딩이 유의미한 가중치 값을 가지면 안 돼서, 패딩에 대한 attention score가 0이 되도록 만드는 과정입니다. 이를 보통 Masking이라고 합니다.

 

self-attention 계산 과정에서 softmax를 취하기 전에 현재 스텝 이후의 위치들에 대해서 -inf로 치환하는 것을 해줌으로써 가능해집니다.

 

그 다음은 multi-head self-attention 개념입니다. “Encoder-Decoder Attention” layer와 한 가지를 제외하고는 똑같은 방법으로 작동하는데요, 그 한가지 차이점은 Query 행렬들을 그 밑의 layer에서 가져오고 Key 와 Value 행렬들을 encoder의 출력에서 가져온다는 점입니다.

 

 

Multi-Head Attention

 

Transformer는 이 self-attention layer에다 “multi-headed” attention이라는 메커니즘을 더해 더욱더 이를 개선합니다. 이것은 두 가지 방법으로 attention layer의 성능을 향상시킵니다:

모델은 다른 위치에 집중하는 능력을 확장시킵니다. attention layer 가 여러 개의 “representation 공간”을 가지게 합니다. 아래 자료로 계속해서 보겠지만, multi-headed attention을 이용함으로써 우리는 여러 개의 query/key/value weight 행렬들을 가지게 됩니다 (논문에서 제안된 구조는 8개의 attention heads를 가지므로 우리는 각 encoder/decoder마다 이런 8개의 세트를 가지게 되는 것입니다).

 

이 각각의 query/key/value set는 랜덤으로 초기화되어 학습됩니다. 학습이 된 후 각각의 세트는 입력 벡터들에 곱해져 벡터들을 각 목적에 맞게 투영시키게 됩니다. 이러한 세트가 여러개 있다는 것은 각 벡터들을 각각 다른 representation 공간으로 나타낸 다는 것을 의미합니다.

 

multi-headed attention을 이용하기 위해서 우리는 각 head를 위해서 각각의 다른 query/key/value weight 행렬들을 모델에 가지게 됩니다. 이전에 설명한 것과 같이 우리는 입력 벡터들의 모음인 행렬 X를 $W^Q/W^K/W^V$ 행렬들로 곱해 각 head에 대한 $Q/K/V$ 행렬들을 생성합니다.

 

위에 설명했던 대로 같은 self-attention 계산 과정을 8개의 다른 weight 행렬들에 대해 8번 거치게 되면, 우리는 8개의 서로 다른 Z 행렬을 가지게 됩니다.

 

그러나 문제는 이 8개의 행렬을 바로 feed-forward layer으로 보낼 수 없다는 것입니다. feed-forward layer 은 한 위치에 대해 오직 한 개의 행렬만을 input으로 받을 수 있습니다. 그러므로 우리는 이 8개의 행렬을 하나의 행렬로 합치는 방법을 고안해 내야 합니다.

 

어떻게 할 수 있을까요? 간단합니다. 일단 모두 이어 붙여서 하나의 행렬로 만들어버리고, 그다음 하나의 또 다른 weight 행렬인 W0을 곱해버립니다.

 

사실상 multi-headed self-attention 은 이게 다입니다. 비록 여러 개의 행렬들이 등장하긴 했지만요. 이제 이 모든 것을 하나의 그림으로 표현해서 모든 과정을 한눈에 정리해보도록 하겠습니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Example: CNN with Self-Attention

CNN에 적용한 Self-Attention의 예입니다.

 

 

 

Three Ways of Processing Sequences

 

 

 

 

The Transformer

 

Transformer의 핵심은 multi-head self-attention을 이용해 sequential computation을 줄여 더 많은 부분을 병렬처리가 가능하게 만들면서 동시에 더 많은 단어들 간 dependency를 모델링합니다.

 

 

 

 

 

 

Post-Norm Transformer

Layer normalization is after residual connections

 

Encoder의 구조를 더 자세히 보면, Sub-layer가 residual connection으로 연결되어 있으며, 그 후에 Layer-normalization 과정을 거친다는 것입니다.

 

layer-normalization 과정을 시각화해보면 아래와 같습니다.

 

이것은 decoder 내에 있는 sub-layer 들에도 똑같이 적용되어 있습니다. 만약 우리가 2개의 encoder과 decoder으로 이루어진 단순한 형태의 Transformer를 생각해본다면 다음과 같은 모양일 것입니다.

 

 

 

 

Pre-Norm Transformer

  • Residual 블록 사이에 레이어 정규화를 배치하는 원래 설계된 Post-LN Transformer는 출력 레이어 근처의 매개 변수의 예상 기울기가 큽니다 . 이러한 기울기에서 큰 학습률을 사용하면 훈련이 불안정해 집니다. 워밍업 단계는 이를 방지하는 데 도움이 될 수 있습니다.
  • 반면에 레이어 정규화가 잔차 블록 내부에 배치 되는 Pre-LN Transformer를 사용하는 경우 그래디언트 초기화 시 잘 작동 합니다. 워밍업 단계는 제거할 수 있습니다.

 

 

 

The Transformer

 

 

 

 

The Transformer: Transfer Learning

"자연어 처리를 위한 ImageNet Moment"

Pretraining: 인터넷에서 많은 텍스트를 다운로드

Training: 언어 모델링을 위한 거대한 Transformer 모델 학습

Finetuning: 자체 NLP 작업에서 Transformer fine-tuning

 

 

 

 

Summary

  • RNN 모델에 Attention을 추가하면 각 타임스텝에서 입력의 다른 부분을 볼 수 있습니다.
  • Generalized Self-Attention은 새롭고 강력한 신경망 프리미티브입니다. (*premitive는 이용가능한 가장 작은 처리(processing)의 단위이거나 언어에서 표현의 원자 요소를 의미)
  • 트랜스포머는 attention만 사용하는 새로운 신경망 모델입니다.
728x90
댓글