[논문 리뷰] Attention Is All You Need

이정민·2025년 11월 8일

[논문 리뷰]

목록 보기
2/19
post-thumbnail

1. Introduction

RNN, LSTM, 특히 GRU, LSTM은 언어모델링이나 기계 번역과 같은 시퀸스 처리 (Sequence modeling) 문제에서 ‘최고 수준(state-of-the-art)’ 기술로 자리 잡았었다.

📌 RNN은 문장처럼 순서가 있는 데이터를 처리하는 데 특화된 모델이다. 하지만 이런 RNN 모델의 한계를 뛰어넘으려는 많은 노력이 있었다.

RNN의 근본적인 문제 : 순차적 계산

RNN은 문장의 단어 위치를 따라 순서대로 계산을 수행한다. 즉, tt시점의 상태 (hth_t)를 계산하기 위해서는 반드시 그 이전의 시점인 t1t-1의 상태 (h(t1))(h_{(t-1)})가 필요하다.

이러한 본질적인 순차적 특성 때문에 훈련 데이터 내의 문장들을 병렬화(Parrallelization)하기 어렵다.

→ 이러한 부분을 다른 연구들이 계산 효율성을 일부 개선하긴 했지만 RNN이 가진 ‘순서대로 계산하는 방법’의 핵심 문제는 아직까지 해결 방법이 나오지 않았다. 이것이 바로 이 논문이 Solving Problem이다.

기존의 보조 기술 : Attention Mechanism

Attention 매커니즘이 이미 시퀸스 모델링 분야의 필수적인 요소가 되었다.

Attention은 입/출력 시퀸스 내 단어들의 거리에 상관없이 단어 간의 의존성을 파악할 수 있게 해준다!
하지만 이 시점까지는 Attention은 대부분 RNN과 함께 사용되었다.
즉, RNN기반 번역 모델이 어디에 집중을 해야할까? 에 대한 보조 도구로 사용되었던 것이다.

새로운 모델 제안 : Transformer

본 연구에서 Transformer라는 모델 아키텍쳐를 제안한다. 이 모델은 순환(Recurrence)구조를 배제하는 대신 입출력간의 전역적인 의존성을 파악하기 위해 오직 어텐션 메커니즘에만 전적으로 의존한다.

이제는 더이상 이전처럼 RNN의 보조 도구가 아닌, 모델의 모든 계산을 오직 어텐션만으로 처리한다.

  • 순차적 계산 (RNN)이 사라졌기 때문에, 문장 내 모든 단어를 동시에 병렬로 처리할 수 있게 되었다.
    학습 속도를 비약적으로 향상 시킨다.
  • 속도가 빨라진 것 뿐만 아니라, 번역 품질 성능 측면에서도 최고 수준을 달성한다.

2. Background.

RNN의 대안 : CNN

RNN의 순차적 계산을 줄이려는 목표는 사실 Transformer가 처음은 아니다. Extended Neural GPU, ByteNet, ConvS2S 와 같은 모델들이 이미 CNN을 기본 구성 요소로 사용하여 이 문제를 풀기 위해 시도했다.

CNN이 RNN보다는 낫지만, 문장 내에서 멀리 떨어진 두 단어의 관계를 파악하려면 필요한 연산의 횟수가 단어 사이의 거리에 따라 증가한다. (ConvS2S는 선형적, ByteNet은 로그적으로 증가.)

이 논문이 사용할 핵심 기술인 Self-Attention이 여기서 등장한다.

💡Self Attention이란?
‘하나’의 문장 (a single sequence) 내에서, 여러 다른 위치의 단어들의 관계를 파악해 해당 문장의 의미를 파악하는 메커니즘이다.

  • 예시 : “Jungmin held back to eat because he knew he was getting heavier.”
    → 여기서 ‘he’가 ‘Jungmin’을 가리킨다는 것을 파악하는 것이 바로 Self-Attention이다!!

End-to-end memory networks라는 또다른 연구가 등장한다.

해당 모델은 RNN처럼 순차적인 Recurrence 대신 반복적인 어텐션 (recurrent Attention)을 사용하여 Q&A와 같은 간단한 작업에서 좋은 성능을 보였다고 한다.

❓이 논문에서 중요하진 않지만.. End-to-End momery Network가 나와서 알아보았다.

  1. Sequence-aligned recurrence
    • 위에서 계속 언급했던 일반적인 RNN(LSTM, GRU)이다.
    • 문장의 1,2,3 … 번째 단어들을 순서대로 하나씩 처리하는 Recurrent 방식이다.
  2. Recurrent attention mechanism
    • 이것도 Reccurent라는 단어가 들어가지만 RNN과는 다르다.
    • ‘Attention’을 한 번만 하는것이 아니라 ‘Attention’ 자체를 여러 번 반복적으로 수행한다.

이러한 모델(RNN)은 전체 문장의 흐름을 보는 것이 아니라 이전의 hidden state만 보는 순차적인 특성으로 문장의 길이가 아주 길어지면 batch와 메모리에 한계가 생긴다는 것이다. 또한 한 input의 토큰으로 한 output의 토큰을 예상하는 것으로 길이가 다른 시퀸스에서는 예상이 쉽지 않고, 전체적 문장의 흐름이 아니라 각 단어마다의 hidden state를 보고 계산하는 Locality의 문제도 있다.

→ 때문에 Encoder - Decoder 구조인 Seq2Seq 가 제안되었다.

→ 하지만,, Seq2Seq 모델에서도 한계가 발생하는데..

Seq2Seq Architecture.

위 그림은 Seq2Seq 모델의 Architecture를 간단히 그림으로 보여준다.

핵심은 Context Vector zz 에 소스 문장의 정보를 압축한다. 이 때 병목현상이 발생할 수 있기 때문에 성능 하락의 원인이 된다. 왼쪽 “How are you ?” 라는 하나의 시퀀스 문장이 들어왔을 때 하나의 고정된 Context Vector zz로 바꾼 뒤에 해당 Context Vector로부터 출력 문장을 만들어 낸다.

이름이 Seq2Seq인데 하나의 Sequence에서 다른 Sequence를 만들어낸다는 의미이다.

다만 이 때, 이러한 Seq2Seq에서 매번 단어가 입력 될 때마다 Hidden State를 갱신한다는 것이다!

각각의 단어가 차례로 입력 될 때마다 hidden state가 갱신되어 마지막 단어의 hidden state는 source 문장을 대표하는 하나의 context vector로 사용될 수 있다는 것이다.

이러한 식으로 Decoder 파트에서는 hidden state를 갱신하면서 출력값이 EOS가 나올 때까지 반복한다.

다만, Source 문장을 대표하는 Context Vector를 만들어야 한다는 점에서 입력 문장이 짧고 길고, 다양한 경우의 수에서 고정된 크기로 Context Vector를 가지는 것은 병목 현상의 주된 원인이다.

다시 말해, 결정적인 문제는 Decoder가 출력 단어를 생성할 때, 오직 이 Context Vector zz 하나에만 의존해야 한다는 것이다.

따라서 해당 Seq2Seq의 한계는 다음으로 정리할 수 있다.

  • Information Bottleneck : 모든 입력 정보를 고정된 크기의 Context Vector zz에 압축하면서 정보가 손실된다. (문장이 길면 길수록 심화된다.)
  • 장기 의존성 문제 심화 : 입력 문장이 길어질 수록 문장 맨 앞의 정보는 zz에 거의 남지 않게 되어 Decoder가 활용하기 어렵다.
  • ‘선택적 집중’ 불가능 : Decoder가 출력 단어를 생성할 때, 입력 문장의 특정 부분을 선택적으로 참고할 수가 없다.

→ Seq2Seq 모델의 한계를 극복하기 위해 어텐션(Attention) 메커니즘을 사용한다.

이렇게 다른 논문들이 CNN을 사용하거나 RNN과 Attention을 섞어서 썼지만, 해당 논문은 RNN과 CNN을 전부 버리고 오직 Self-Attention 하나만으로 모델 전체를 만드는 것을 보여준다.

[물론 이후에 RNN을 사용한 모델들도 보이긴 하지만, 전반적인 양상을 보자면 Attention 기법을 사용하여 다양한 고성능 모델들이 제안된다.]

3. Model Architecture

이것이 바로 Transformer의 가장 큰 틀이다. 왼쪽을 Encoder, 오른쪽을 Decoder 이렇게 두 부분으로 나눈다.

Encoder에서 입력된 단어의 흐름을 순차적으로 입력받아 이 정보들을 하나의 벡터로 압축하는데 이것을 Context Vector라고 한다. 이 압축된 Context Vector를 Decoder로 전송하여 번역된 단어를 한 개씩 순차적으로 출력하는 구조이다.

음.. 말은 참 쉽다.

먼저 Encoder와 Decoder의 역할과 작동 방식을 간단하게 알아보자.

Encoder

Encoder는 입력 문장을 받아서 의미를 잘 압축한 문맥적 표현 (z)(z)으로 만든다.
입력 문장을 통째로 읽고 “아~ 이 문장은 이런 의미구나” 라고 이해하는 과정이라고 생각하면 된다.

Decoder

Decoder는 Encoder가 만든 문맥 (z)(z)를 보고 “I”를 생성한다. zz와 “I”를 보고 “am”을 생성한다. 그 다음 zz와 “I am”을 보고 “a”를 생성한다.
이처럼 자신이 이전에 생성한 단어를 다시 입력으로 사용하는 방식을 Autro-Regressive. 자기회귀라고 부른다.

3.1 Encoder and Decoder Stacks

1. Encoder

인코더가 N=6N=6개의 동일한 Layer로 구성된다고 한다. [Figure 1]의 Nx가 바로 이 뜻이다. Encoder의 큰 회색 박스가 6번 구성된다는 뜻이다.

🔥하나의 Layer 구조 : 6개 중 1개의 Layer는 2개의 하위 레이어 (sub-layers)로 구성된다.

  1. Multi-Head Self-Attention
    • 이것이 Transformer의 핵심이다. 입력 문장을 스스로 참조하여 단어 간의 관계를 파악한다.
  2. Feed Forward 신경망
    • Attention에서 나온 정보를 처리하는 간단한 Fully-Connected Layer이다.

Multi-Head Encoder Self-Attention, Feed Forward. 두가지 Sub-Layer 각각 Residual Connection을 사용하고 Layer Normalization을 사용한다.

💡Residual Connection 이란?
Multi-Head Attention을 통과한 화살표와, 통과하지 않고 우회하는 화살표가 “Add & Norm”에서 만난다. 이것이 바로 Residual Connection, 잔차 연결이다.

바로 입력 xx가 어떤 연산 F(x)F(x)안을 통과한 뒤, 그 결과에 원래 xx를 더해주는 구조이다.

즉, Sub layer의 입력과 출력을 더하는 것이다.
Transformer에서는 행렬의 연산으로 Multi-head Attention, FFNN 등을 구하고 마지막에 가중치 값인 WW를 구해서 입력값과 출력값을 동일한 차원을 가지게 만들고 있다.

Residual Connection의 이해를 돕기 위해 아래 사진을 보자.


Layer Normalization 이란?
각 위치 벡터 안에 있는 값들을 평균 0, 분산 1로 맞추는 정규화 과정이다.

Transformer에서는
1. 먼저 입력을 살짝 정리한다. (LayerNorm)
2. Attention으로 관계 계산하기
3. 원래 입력 x와 더하기 (Residual)
4. 그 결과를 다시 정리해서(LayerNorm) FFN으로 보내기.
5. FFN이 만든 결과에 또 다시 원래 값 더하기 (Add & Residual)

♻️ 추가로 Positional Encoding이 나오는데 이건 간단하다.

Transformer는 RNN을 버렸다. 때문에 Self Attention은 문장을 “단어의 집합”으로 보는데, 이건 ‘순서’ 가 아닌 한꺼번에 본다는 것이다.

이를 해결하기 위해 트랜스포머는 단어가 문장의 몇 번째 위치에 있는지에 대한 정보를 인공적으로 만들어서 주입한다. 이것이 바로 Positional Encoding이다.

Residual Connection

Add & Norm을 다시 풀어보기 (Residual Connection)

위에서 “Multi-Head Attention”을 통과한 화살표와 통과하지 않고 우회하는 화살표가 “Add & Norm”에서 만나는 것이 잔차 연결이라고 했다.
LayerNorm(x+Sublayer(x))LayerNorm(x + Sublayer(x))의 수식에서 x+Sublayer(x)x+Sublayer(x)가 바로 Add 부분이다.
xx는 하위 레이어의 입력(우회한 화살표)이고, Sublayer(x)Sublayer(x)는 하위 레이어의 출력(통과한 화살표)이다.

원본 정보를 더해줌으로 정보 손실을 막고 학습을 도와준다.

LayerNorm(...)LayerNorm(...)이 바로 Norm 부분이다. Layer Normalization을 통해 학습을 안정시킨다.

2. Decoder

이제 Encoder를 다 봤으니, 오른쪽 Decoder를 살펴보자.

마찬가지로 N=6N=6, Nx층이 6개 쌓여있다. Decoder는 Encoder와 달리 3개의 하위 레이어를 가진다.

  1. Masked Multi-Head Self-Attention
    • 디코더가 지금까지 가기가 생성한 단어들 (예를 들어 Jungmin is)를 돌아보는 셀프 어텐션이다.
    • Masked가 붙은 이유는 다음과 같다 : Decoder는 “Auto-Regressive(자기 회귀)” 방식으로, 순서대로 단어를 예측해야 한다. 즉, “is”를 예측할 때, “hungry man”처럼 미래의 단어를 봐서는 안된다. 이 카스킹이 바로 미래의 단어를 가려주는 역할이다.
      • 논외로.. CV에서도 Masking이 나왔는데 비슷한 역할을 수행하는 것이라고 보인다.
  2. Multi-Head Attention
    • ‼️가장 중요한 연결부이다.‼️ [Figure 1]을 보면 이 레이어는 인코더 스택(z)(z)에서 화살표를 받는다.
      • Decoder가 “is”라는 단어를 생성하기 위해 Encoder가 넘겨준 “He is Hungry”라는 문맥(z)(z)에서 어떤 단어(”Hungry”)에 집중(Attention)해야 할지 결정하는 부분이다 !!!
  3. Feed Forward
    • Encoder와 동일하게 위에서 나온 모든 정보를 처리하는 신경망이다.

3.2 Attention

Attention 이란 무엇일까?

Attention은 같은 문장 내에서 단어들의 관계를 나타내며, Query, Key-Value 쌍의 집합을 output으로 매핑하는 것으로 설명할 수 있다.

아직 내 수준으로는 한번에 와닿지 않는다.

우리집 강아지 망고를 예로 들어보겠다. “Maggo is a Dog.”
Query : Manggo

Key :

Value :

🔥Attention의 작동 방식은 다음과 같다.

  1. Query를 문장 속 모든 단어의 Key와 비교하기 : 얼마나 관련이 있는지 유사도 계산
  2. 이 유사도를 바탕으로 가중치를 계산한다.
  3. 가중치를 각 단어의 Value에 곱한다.
  4. 가중치가 곱해진 Value들을 모두 더한다. (가중합)

    결과로, 나의 Query와 관련이 높은 단어들의 Value정보가 많이 반영된 새로운 Output이 나온다.

한 개의 Attention (왼), 여러 개의 Attention (오)

먼저 Scaled Dot-Product Attention. 즉, 하나의 Attention을 먼저 살펴보자.
Tranformer가 사용하는 기본적인 어텐션의 형태이다.

  1. Q,K,VQ, K, V 세가지 벡터가 들어온다.

  2. MatMul : QQKK를 행렬 곱한다. (QKT)(Q *K^T). 이것이 바로 ‘유사도’를 계산하는 과정이다. Dot-Product는 내적이라는 뜻인데, 이것이 유사도를 구하는 방법이다.

  3. Scale : 계산된 유사도 값을 특정값 dk\sqrt{d_k}으로 나누어 준다. 값이 너무 커지는 것을 방지하여 학습을 안정시키기 위해서이다. 그래서 Scaled라는 이름이 붙은 것이다.

  4. Mask (opt.) : 이것이 바로 Decoder에서 쓰인 그 ‘마스킹’ 이다!! Decoder가 미래의 단어를 살펴보지 못하도록 관련성이 없어야 하는 부분(미래 단어)의 유사도 값을 아주 낮게 (보통은 -\infin) 만들어 준다.

  5. SoftMax : 마스킹된 유사도 값들을 0과 1 사이의 확률 값으로 변환 한다. 모든 값을 합치면 1이 된다. 이것이 바로 가중치이다.

  6. MatMul : 이 가중치를 VV와 행렬 곱한다.

  7. VV들의 가중합이 최종 결과로 나오게 된다.

초반에 트랜스포머는 사실 Attention을 한번 쓰지 않고 여러 개를 병렬로 동시에 실행한다고 했다.

→ 이것이 바로 Multi-Head !!

  1. Q,K,VQ, K, V가 입력으로 들어온다.
  2. Linear : Q,K,VQ, K, V를 각각 여러 조각으로 나눈다. 더 정확히는 Q,K,VQ, K, V를 각각 8개의 서로 다른 관점으로 변환시킨다. (각각 다른 Linear Layer를 통과하고, 이 8개의 조각이 바로 Head이다.)
  3. Scaled Dot-Product Attention : 8개의 헤드가 각자 독립적으로 동시에 위에서 배운 Scaled Dot-Product Attention을 수행한다.
    • 이 때, 여러 관점으로 어텐션을 수행할 수 있다. 예를 들어 어떤 헤드는 ‘누가’ 라는 관계에 집중하고, 다른 헤드는 ‘무엇을’ 이라는 관계에 집중할 수 있다.
  4. Concat : 8개의 헤드가 각자 계산한 8개의 출력 결과를 다시 하나로 이어 붙인다.
  5. Linear : 이어 붙여진 결과를 하나의 최종 출력 벡터로 만들기 위해 Linear Layer를 한 번 더 통과시킨다.

Scaled Dot-Product Attention

Scaled Dot-Product Attention의 수식은 다음과 같다.

Attention(Q,K,V)=softmax(QKTAttention(Q,K,V) = softmax(QK^Tdk\sqrt{d_k})V)V

수식을 하나하나 분해하면서 살펴보자. 이해를 돕기 위해 위에서 사용했던 “Maggo is a Dog.”이라는 단어를 다시 사용해보자.

1. QKTQK^T : MatMul (유사도 계산)

해당 과정은 유사도 계산. 즉, MatMul 과정이다.

  • QQ : “Manggo”, “is”, “a”, “Dog” 4개의 단어 qq 벡터를 쌓아놓은 쿼리 행렬이다.
  • KK : 4개 단어의 kk벡터를 쌓아놓은 키 행렬이다.
  • KTK^T : KK행렬을 전치(Transpose) 시킨 것이다.
  • QKTQK^T : QQKTK^T행렬곱 (MatMul) 한다.
    • “Manggo”의 qq벡터와 [’Manggo’, ‘is’, ‘a’, ‘Dog’] 각각의 kk 벡터를 내적 (Dot-Product) 하여 점수를 계산한다. 이 과정을 모든 qq 벡터 (is, a, Dog) 에 대해 한꺼번에 수행한다.
      • 그 결과로 단어 간의 “유사도 점수 행렬”이 나오게 된다.

      • ‘Maggo’의 qq 벡터 X [’Manggo’의 kk, “is”의 kk, “a”의 kk, “Dog”의 kk] = 4개의 점수

      • “is”의 qq벡터 X [’Manggo”의 k,k, “is”의 kk, “a”의 k,k, “Dog”의 kk] = 4개의 점수

      • … 계속 반복한다.

        → “Manggo”와 “Dog”이 얼마나 관련이 있는지 나오는 숫자 점수가 계산되는데, 점수가 높을수록 두 단어가 서로에게 “집중” 해야 한다는 뜻이다.

2. dk\sqrt{d_k} : Scaling

  • dkd_k : Key(KK) 벡터의 차원이다. 논문에서는 d(model)d_{(model)} = 512, 헤드가 8개 이므로 dkd_k = 512/8 = 64가 된다.
  • dk\sqrt{d_k} : 이 차원값에 제곱근을 씌운 값이다. dk\sqrt{d_k} = 8 과 같은 과정을 보여준 것이다.
  • dkd_k 값이 크면 QKTQK^T로 계산된 유사도 점수 (Dot-Product)가 너무 커질 수 있다. 이 값이 너무 커진다면 SoftmaxSoftmax함수를 통과할 때 기울기가 0에 가까워져서 학습이 잘 되지 않는 ‘Vanishing Gradient’가 발생한다.
    • 점수들을 적절한 값 (dk\sqrt{d_k})으로 나누어서 SoftmaxSoftmax가 잘 작동하도록 크기를 Rescaling 해준다고 보면 된다.
      • 근데 왜 나누지?Q,KQ, K를 내적하면 dkd_k가 클수록 편차가 커지는 문제가 있다. 점수의 스케일을 줄여서 Softmax가 더 부드러운 값을 내도록 안정화 시키는 것!

3. Softmax()Softmax() : 가중치 변환

  • Rescaled된 유사도 점수들을 0에서 1 사이의 값으로 변환하고, 모든 값을 더하면 1이 되도록 하는 일반적인 Softmax 역할을 수행한다.
  • 각 단어에 ‘집중’할 비율을 0~1로 만드는 것이다.

4. VV (value와의 가중합)

  1. V(Value) : 4개의 단어의 vv벡터들이다. vv벡터는 각 단어의 내용물을 담고 있다.
  2. 가중합 : 3단계에서 만든 가중치 점수와 VV 벡터들을 곱한다.




Multi-Head Attention

우리가 이 전에 배운 “Scaled Dot-Product Attention” 만으로는 한 번에 파악하기 어렵다.

그래서 나온 해법이 바로 “Multi-Head Attention” !

논문에서는 hh를 8개의 헤드를 병렬로 수행한 후 연결하고 최종적으로 투영하였다. (h=8h = 8)

  • dkd_k = 64차원 x hh = 8개 헤드 = 512차원

1단계 : 입력 분할 (Projection) - Linear Layer.

“Manggo” 라는 단어의 512차원 입력 벡터 (xManggox_{Manggo})가 들어왔다고 가정해보자.

  1. 이 입력 벡터로 기본적인 qtextManggo,ktextManggo,vtextManggoq_{\text{text{Manggo}}}, k_{\text{text{Manggo}}}, v_{\text{text{Manggo}}}을 만든다.

  2. 생성된 3개의 입력 벡터를 8개의 헤드에게 “나눠줘야” 한다. 그냥 8등분 하는 것이 아니라 8개의 서로 다른 가중치 행렬을 각각 곱해준다.

    1. 이 전체 512차원 입력 벡터를 8개의 서로 다른 Linear 층에 각각 집어 넣는다.
    2. 각 Linear 층은 이 512차원 정보를 입력받아 새로운 64차원 벡터를 생성한다.

    → 8등분 쪼개는 것이 아니라 통째로 계속 Linear 층마다 넣어 주는 것

  • 1번 Head : 512차원 정보 (xmanggox_{manggo})를 통째로 보고 → ‘문법적 관점’의 64차원 요약본 (Q1,K1,V1)Q_1, K_1, V_1)을 만든다.

  • 2번 Head : 512차원 정보 (xmanggox_{manggo})를 통째로 보고 → ‘의미적 관점’의 64차원 요약본 (Q2,K2,V2)Q_2, K_2, V_2)을 만든다.

  • 8번 Head : 512차원 정보 (xmanggox_{manggo})를 통째로 보고 → ‘주변 단어 관계 관점’의 64차원 요약본 (Q8,K8,V8)Q_8, K_8, V_8)을 만든다.

    1. 이렇게 8개의 헤드 세트 (Q1,K1,V1Q_1, K_1, V_1 ~ Q8,K8,V8)Q_8, K_8, V_8)은 서로 전혀 상관 없이 완전 병렬로 Scaled Dot-Product Attention을 동시에 수행한다.

2단계 : Scaled Dot-Product Attention 수행

8개의 헤드 세트는 서로 전혀 상관 없이 완전 병렬로 수행한다.

  • head_1 (결과) = Attention(Q1,K1,V1)Attention(Q_1, K_1, V_1)
  • head_2 (결과) = Attention(Q2,K2,V2)Attention(Q_2, K_2, V_2)
  • head_8 (결과) = Attention(Q8,K8,V8)Attention(Q_8, K_8, V_8)

이렇게 “Manggo”라는 단어에 대해 8개의 서로 다른 문맥이 반영된 64차원짜리 벡터 8개가 생성된다.

3단계 : Concat + Linear 수행

  1. Concat : 8개의 64차원 결과 벡터를 그냥 옆으로 쭉 이어 붙인다.
    1. [head_1, head_2, … head_8]

      → 64 X 8 = 512 차원의 하나의 거대한 벡터 생성

  2. Linear : 이 512차원짜리 벡터는 8개의 헤드의 정보가 ‘날것’으로 합쳐진 상태이다. 일종의 처리 후에 ‘Feed Forward’가 잘 처리할 수 있도록 512차원 (dmodeld_{model}) 벡터로 만들어줘야 한다.
    • 또다른 하나의 가중치 행렬 WoW^o을 이 거대한 벡터에 곱해준다.
    • WoW^o 행렬은 8개의 헤드의 결과를 어떻게 조합하는것이 가장 효과적인지를 학습한다.

Multi-Head Attention의 수식

MultiHead(Q,K,V)=Concat(head1,...,headh)WoMultiHead(Q,K,V) = Concat(head1, ... , head_h)W^o

headihead_iAttention(QWiQ,KWiK,VWiVAttention(QW_i^Q, KW_i^K, VW_i^V) 이다.




3.2.3 Applications of Attention in our Model

트랜스포머는 Multi-Head Attention을 세 가지 방식으로 사용한다.

1. Encoder Self-Attention

  • 왼쪽(Encoder)에 있는 “Multi-Head Attention” 블록이다.
  • 입력 문장이 자기 자신을 참조하여 문맥을 파악한다.
  • Q,K,VQ, K, V 모두 이전 인코더 레이어의 출력에서 나온다.

2. Masked Decoder Self-Attention

  • 오른쪽(Decoder)에 있는 첫번째 “Masked Multi-Head Attention” 블록이다.
  • Decoder가 지금까지 생성한 출력 문장이 자기 자신을 참조하여 문맥을 파악한다.
  • 각 Decoder 위치는 자신보다 이전 위치까지만 집중할 수 있도록 마스킹 처리된다. → 자기회귀적 속성을 유지하기 위함이다.
    • Decoder는 번역문을 “i” → “am” → “a” → “student” 처럼 순서대로 생성해야 하는데, “am”을 생성할 때 “a” or “student”같은 미래의 단어를 미리 본다면 올바른 학습이 아니다. → Masking으로 방지하기

3. Encoder-Decoder Attention

  • 오른쪽(Decoder)에 있는 두번째 “Multi-Head Attention” 블록이다. [Encoder ↔ Decoder를 연결하는 핵심 다리]
  • Decoder가 다음 단어를 생성할 때, 입력 문장의 어느 부분에 집중해야 할지 결정한다.

쿼리는 이전 디코더 레이어에서 오고, 키와 값은 인코더 스택의 출력에서 온다. 이를 통해 디코더의 모든 위치가 입력 시퀀스의 모든 위치에 집중할 수 있는 것이다.


3.3 Position-wise Feed-Forward Networks

Figure 1에서 “Multi-Head Attention”과 “Add & Norm” 바로 뒤에 오는 “Feed Forward” 블록에 대한 설명이다.

Attention 하위 레이어 외에도, Encoder, Decoder의 각 레이어는 “완전 연결 피드-포워드 네트워크 (FFN)” 을 포함한다. 이것은 각 위치 (position)에 개별적으로 (separately), 동일하게(identically) 적용된다.

  • 각 위치(position)에 개별적으로(separately)?
    • Attention Layer를 통과한 “Manggo is a Dog”은 4개의 벡터 (zManggo,zis,za,zDogz_{Manggo}, z_{is}, z_{a}, z_{Dog})이 된다.
    • FFN은 이 4개의 벡터를 하나씩 따로따로 처리한다.
    • “Manggo”를 처리할 때 “Dog”의 정보는 전혀 보지 않는다. Attention과 달리, 이 단계는 단어 간의 상호작용이 전혀 없다.
  • 동일하게 (identically)?
    • zManggoz_{Manggo}를 처리할 때 사용한 FFN(네트워크 가중치 W1,W2W_1, W_2)와, zDogz_{Dog}을 처리할 때 사용한 FFN이 완전히 같은 네트워크 이다. (가중치 공유)

      이것은 두 개의 선형 변환(Linear Transformations)와 그 사이의 ReLU 활성화 함수로 구성된다.

FFN(x)=max(0,xW1+b1)W2+b2FFN(x) = max(0, xW_1 + b_1)W_2 + b_2 (입력 xxdmodeld_{model} = 512차원 벡터)

  1. xW1+b1xW_1 + b_1 :
    1. 입력 xx에 가중치 행렬 W1W_1을 곱한다.
    2. 이 레이어는 텍스트에 나온대로 dffd_{ff} = 2048 차원으로 차원을 확장시킨다.
    3. 512 dimension → 2048 dimension
  2. max(0,...)max(0, ...) :
    1. 확장된 2048 차원 벡터에 비선형성(non-lenearity)을 추가한다.
    2. max(0,...)max(0,...)은 ReLU 함수의 정의이다. (0보다 작은 값은 0으로)
    3. Attention, Add & Norm, 선형 변환은 모두 Linear 계산이다. 만약 FFN에도 비선형 함수가 없다면, 트랜스포머 전체가 아무리 깊게 쌓여도 결국 하나의 거대한 선형 변환과 다를 바가 없음
  3. (...)W2+b2(...)W_2 + b_2
    1. ReLU를 통과한 2048 차원 벡터에 다시 가중치 행렬 W2W_2를 곱한다.
    2. 이 레이어는 다시 원래 차원인 d_model = 512로 축소 시킨다.
    3. 2048 dimension → 512 dimension

    🔥 왜 굳이.. 이런 짓을 할까?

    Attention Layer가 정보를 수집했다면, FFN은 수집된 정보를 처리하고 소화하는 역할을 한다.

    # 512→2048→512 구조는 왜..?

    1. 512차원에 압축되어 있던 정보를 2048 차원이라는 더 넓은 공간으로 펼치기
    2. ReLU가 이 정보들 간의 더 복잡한 관계를 쉽게 처리할 수 있도록 함
    3. 다시 512 차원으로 압축하여 다음 Layer로 전달



3.4 Embeddings and Softmax

이 표는 트랜스포머가 왜 RNN, CNN 대신 Self-Attention을 선택했는지 보여준다. (nn : 문장의 길이 (단어 개수) dd : 벡터 차원(e.g. 512)

1. Complexity per Layer

  • Self-Attention : O(n2O(n^2· dd)
    • Q,KTQ, K^T의 행렬 곱은 (nn x dd) x (dd x nn) = (nn x nn) 행렬을 만든다. 여기에 V(nV(n x dd)를 곱하므로, n2n^2· dd 의 계산량이 필요하다.
    • 문장이 길어지면 계산량이 제곱으로 폭발한다.
  • Recurrent (RNN) : O(nO(n· d2d^2))
    • nn개의 단어를 순서대로 d2d^2 복잡도의 계산을 한다.
    • 문장 길이에 선형적으로 증가한다

2. Sequential Operations

  • Self-Attention : O(1)O(1)
    • 모든 단어를 한번에 병렬로 처리하여 순서대로 기다릴 필요가 없다.
  • Recurrent (RNN) : O(n)O(n)
    • RNN의 한계가 바로 보인다
    • 단어의 개수만큼 단어 계산이 모두 끝날 때까지 기다려야 한다. 병렬 처리가 불가능하다.

3. Maximum Path Length

  • Self-Attention : O(1)O(1)
    • 문장의 첫번째 단어와 100번째 단어는 단 한번의 계산(QKV)Q-K-V)로 직접 연결된다.
    • 장기 의존성 문제에 완벽하다
  • Recurrent(RNN) : O(n)O(n)
    • 1번째 단어의 정보가 100번째 단어까지 전달되려면 99개의 단계를 거쳐야 한다.
    • 이 과정에서 정보가 손실되거나 왜곡되어버린다.
  • Convolutional (CNN) : O(logk(n))O(log_k(n))
    • CNN은 RNN보다는 낫지만, 층을 여러 개 쌓아야만 멀리 있는 단어가 연결된다. Attention보다는 성능이 잘 나오지 않는다.


3.5 Positional Encoding

Transformer는 Recurrence, Convolutional 도 포함하지 않기 때문에 Sequence의 순서를 활용하기 위해서는 Token의 순서에 대한 정보가 필요하다.

‘순서’ 정보를 인공적으로 만들어서 모델에 주입하는 방식이다.

짧게 말하자면, Input Embedding에 Positional Encoding을 더한다. 이렇게 두 벡터를 더하므로, Positional Encoding 벡터도 dmodeld_{model} = 512 차원이어야 한다.

서로 다른 주파수를 가진 Sine과 Cosine 함수를 사용한다.

PE(pos,2i)=sin(pos/10002i/dmodel)PE_{(pos,2i)} = sin(pos/1000^{2i/d_{model}})

PE(pos,2i+1)=cos(pos/100002i/dmodel)PE_{(pos,2i+1)} = cos(pos/10000^{2i/d_{model}})

이 두가지 수식의 핵심 변수는 pos : 문장내 단어의 위치 , i : 512차원 벡터 내의 차원 인덱스 이다.

이 함수가 모델의 상대적 위치로 주의를 기울이는 법을 쉽게 배울 수 있게 해줄 것이라고 가설을 설정했다.

삼각함수의 덧셈 정리에 따라, PEpos+kPE_{pos+k}PEposPE_{pos}의 선형 변환으로 표현될 수 있다.

“Manggo”(pos=0)와 “a”(pos=2)의 관계, “is”(pos=1)와 “Dog”(pos=3)의 관계는 모두 2간 차이 (k=2k=2)이다.

이렇게 모델은 2칸 차이라는 상대적 관계를 쉽게 학습할 수 있게 된다.




4. Why Self-Attention

Self-Attention이 RNN, CNN보다 어떻게 더 좋은지 더 자세히 알아보자.

논문은 총 3가지 기준으로 왜 어텐션이 좋은지 증명한다.

  1. Total Computational complexity : 1개 layer를 처리하는데 총 몇 번의 계산이 필요할까?
  2. Amount of computation that can be paralleized : 얼마나 많은 계산을 ‘동시에’ 처리할 수 있을까?
  3. Path length between long-range dependencies : 문장의 1번째 단어와 100번째 단어가 ‘대화’ 하려면 몇 단계를 거쳐야 할까?



5. Training

5.1 Training Data and Batching

훈련 데이터 :

  • English-German : WMT 2014 데이터셋을 사용했다. 약 450만개의 문장 쌍으로 이루어져 있다.
  • English-French : WMT 2014 데이터셋으로, 약 3,600만개의 문장 쌍이다.

Tokenizing :

  • 단어를 ‘Byte-Pair Encoding (BPE)’ 라는 기법으로 쪼갰다.
  • BPE는 “loved”, “loving”, “loves” 같은 단어를 “lov”, “ed”, “ing”, “es”드응로 쪼개는 것처럼 더 작은 단위로 분리한다.
    • 처음 보는 단어에도 효과적으로 처리할 수 있다.

Batching :

  • 훈련 속도를 높이기 위해 비슷한 길이의 문장들끼리 묶어서 하나의 배치로 만들었다.
  • 만약 5단어 문장 ↔ 100단어 문장을 한 배치로 묶으면 5단어 문장은 95개의 빈칸(padding)을 채워야 해서 매우 비효율적이다.
  • 논문에서 각 배치는 25,000 개의 Source Token 과 25,000개의 Target Token을 포함하도록 구성했다.

5.2 Hardware and Schedule

Hardware : 8개의 NVIDIA P100 GPU

Base Model :

  • 한 번의 스텝 (batch 처리)에 약 0.4초 소요
  • “Base Model”은 총 100,000 스텝을 훈련했고, 총 12시간 소요

Big Model :

  • “Big Model”은 스텝당 1.0초 소요, 300,000 스텝을 훈련하여 총 3.5일이 걸렸다.

5.3 Optimizer

Optimizer : Adam Optimizer

Core Strategy : Learning Rate Schedule

  • 학습률을 훈련 내내 고정시킨 것이 아니라 훈련 스텝에 따라 동적으로 변화시켰다.
  • 이것이 바로 유명한 “Warmup and Decay” 전략이며, 다음 수식이 이를 설명한다 lrate=dmodel0.5lrate = d^{-0.5}_{model} · min(stepmin(stepnum0.5num^{-0.5}, stepstepnumnum · warmupwarmup_steps1.5steps^{-1.5})

0개의 댓글