본문 바로가기
Study/Deep Learning

[Deep Learning] Attention, Seq2Seq, Transformer

by 유미미Yoomimi 2024. 2. 19.

Vision Transformer를 이해하기 위해 필수적인 개념들을 한데 정리해보려고 한다.

우선 RNN, LSTM, GRU에 관한 포스팅은 아래! 이 개념을 알아야 이해하기 편하다.

 

https://yoomimi.tistory.com/entry/RNN-LSTM-GRU

 

[Deep Learning] RNN, LSTM, GRU 총정리★ (+판서)

RNN(Recurrent Neural Network)우선 더 익숙한 CNN에서 출발해보자. CNN은 input(들)을 이용해 output을 예측하는데, 그 과정에서 data가 재사용되지 않는다. 당연하다. CNN은 input 하나를 한꺼번에 넣어주기 때문

yoomimi.tistory.com

 

 

 

들어가기 전, 기계 번역의 발전 과정을 알고 가면 좋다.

RNN > LSTM > Seq2Seq > Attention > Transformer > GPT-1 > BERT > GPT-3

 

1. Attention & Seq2Seq 

인공지능 신경망으로 기계 번역을 할 때. 우리가 단어 by 단어 번역을 한다면 How are you?를 잘 지내?라고 번역하는 것은 불가능 할 것이다. 그렇기에  many to many에 해당하는 sequence prediction을 수행하게 된다. 이때 아래와 같은 순서로 Encoder와 Decoder를 이용한 번역을 수행하는 모델을 우리는 Sequence to Sequence (Seq2Seq) model이라고 한다.

 

 

Encoder는 input sequence에서 각 단어를 순차적으로 입력받아 context vector를 만드는 역할을 한다. 이때 각 단어는 embedding layer를 통해 벡터로 변환된다. 결국 time step마다 순환 신경망을 이용해 단어를 입력받고, 최종적으로 마지막 time step의 hidden state를 context vector로 사용하는 것이다.

 

Decoder는 context vector를 읽으며 번역하는 역할을 한다.

Decoder 단의 ground truth로 [<sos>, I, am, Iron, man]을 입력받아 [I, am, Iron, man, <eos>]를 출력하도록 학습하는 것이다.

<eos>: End Of Sentence

 

여기서 문제는 뭘까? Basic Seq2Seq에서 Context vector는 하나의 고정된 벡터인데, 문장이 길어지면 context vector에 모든 정보를 담기 어렵다. 만일 context vector를 크게 해 긴 문장의 정보가 다 담긴다 하더라도 앞 순서의 정보(단어)들의 영향력이 줄어들기 쉽다.

 

결국 이 문제를 해결하기 위해 등장한 것이 Seq2Seq with attention mechanism인데, 기본적인 아이디어는 Encoder 단에서 마지막 time step의 state로 context vector를 만들지 말고, 앞의 time step에서 나오는 state 값들도 이용하자는 것이다. 또한 추가된 아이디어는 입력 sentence를 양방향으로 읽자는 것이다.

 

Attention Mechanism:

  • Decoder가 각 단어를 생성할 때마다 Encoder의 모든 hidden state에 대해 가중치를 계산한다.
  • 이 가중치는 현재 Decoder의 hidden state와 각 Encoder hidden state의 유사도를 나타낸다.
  • 가중치에 softmax 함수를 거쳐 attention weight를 얻는다.
  • 각 Encoder hidden state와 attention weight를 곱한 후 합해 context vector를 생성한다.
  • 결국 context vector가 time step마다 달라진다.

이렇게 하면 Decoder는 이전 time step의 hidden state 출력 단어와 context vector를 입력으로 받아 다음 단어를 예측하게 된다. 이는 다시 다음 time step decoder input과 함께 쓰인다.

 

Source: https://www.researchgate.net/figure/An-attention-based-seq2seq-model_fig3_329464533

 

그림을 통해 볼 수 있듯 attention weights는 encoder의 각 hidden state와 현재 time step의 decoder hidden state 간의 유사도를 통해 얻어진다. 이를 합해 context vector를 만들고, context vector와 decoder hidden state를 이용해 다음 단어를 예측한다. 이 예측은 다시 다음 time step의 decoder 입력과 함께 쓰인다. 수식은 다음과 같다.

 

우선 time t에서 decoder hidden state s와 i번째 encoder hidden state간의 유사도를 계산해준다. 사실상 많이 쓰는 건 dot product임. 생각해보면 두 벡터의 내적은 두 벡터가 유사할 수록 값이 크지 않은가! 그리고 softmax를 취해 정규화된 attetion weights를 얻는다. context vector는 다음과 같이 가중합으로 구한다. 결국 우리의 모델은 벡터를 선형변환하는 가중치를 학습하는 것이다.

 

그리고 이 모든 과정에서 단방향이 아닌 Bidirectional RNN을 이용해 순방향 hidden state와 역방향 hidden state를 결합한 hidden state를 이용한다.

 

여기까지가 basic seq2seq, attention, attention-based seq2seq에 대한 개념이다.

 


 

2. Transformer (Attention Is All You Need)

Transformer는 Attention만을 이용해 입출력 사이의 전체적인 연관성(dependencies)를 판단하도록 구상된 모델이다.

결국 RNN이 RNN + Attention으로 발전하고 이것이 Transformer라는 idea를 낳은 셈이다. 꺅!

정확한 탄생 배경은 RNN + Attention에서도 여전히 decoder 단의 'time step이 멀수록 잊혀지는 문제'가 해결이 안 된 것, 두번째는 갈수록 흐려지는 정보에 attention을 하게 된다는 것이다. 양방향 RNN을 쓴다 해도 time step 거리의 영향을 받는 문제는 없애지 못했다. (양방향이 잘 된다고 해서 신기해했던 과거의 나.. 웃기다. 좋은 방법이 전혀 아니었음. ㅎㅎ)

 

그래서 Transformer는 RNN을 버렸다..! 그리고 Self-attention이라는 개념을 도입했다. 어떻게????

'거리 문제를 해결했다.', 'self-attention'. 여기서 느껴지는가?

encoder 단의 hidden들과 decoder 단의 hidden 하나를 weighted sum하는 건 좋다. 그런데 여기서

encoder 단의 hidden을 그냥 쓰는 것이 아니라, h2는 h2_new = <h1, h2>h1 + <h2, h2>h2 이렇게 자기들끼리 내적한 값으로 가져다 쓰겠다는 거다. 말그대로 hidden끼리 그 내부에서도 attention을 써버리자는 거다. decoder의 hidden도, encoder의 hidden도 전부! 이게 Transformer를 이해하는 핵심 Insight다. Recurrent 개념이 빠졌으니 병렬처리(GPU쓰기!)가 쉽게 가능해졌고, 그러니 시간적으로도 엄청난 성능향상을 이뤘다.

 

Transformer의 구조는 기존의 Sequence 모델들과 동일하게 다음과 같은 Encoder-Decoder 구조를 가진다.

 

 

왼쪽 box가 Encoder, 오른쪽 box가 Decoder다.

 

1) Encoder

우선 RNN이 빠져 input의 순서 정보를 추가적으로 제공해줘야 하기 때문에 Positional Encoding단계가 추가되었다. 그 후 sentence 내 단어들에 대한 Multi-Head (Self-)Attention을 계산한다.

그 뒤 각 Attention에 대해 position-wise로 독립적이게 Feed Forward Layer를 통과시킨다. (RNN을 안 쓰고 FFNN을 쓰는 것!) 효율적인 연산을 위해 residual connection과 적절한 normalization, pooling이 추가되었다.

 

2) Decoder

마찬가지로 Positional Encoding이 추가되었으며, 마찬가지로 output embedding에 (Masked) Multi-Head Attention을 취했다. 그리고 Encoder의 출력 (context vector)와 Decoder의 현재 위치의 Query를 사용하여 Attention을 수행한다. 이때 Encoder의 출력이 Key와 Value로 사용되며, Decoder의 현재 위치의 hidden state가 Query로 사용된다. 그 뒤 Encoder와 마찬가지로 FFNN을 거쳐 최종 Prediction을 내놓게 된다.

 

3) Key, Value, Query

Attention layer를 보면 입력으로 세 갈래의 화살표가 들어간다. 이는 각각 Value, Key, Query를 의미한다. 그래서 이게 뭔데? 

  • Query : 현재 시점에서 출력에 영향을 줄 벡터
  • Key : Query를 통해 연관성을 찾을 목표 단어들에 대한 정보와 문맥 정보
  • Value : 목표 단어들의 단어 정보에 대한 벡터

이렇게 보면 와닿지 않는데, Masked MHA 레이어의 출력 벡터들을 Query로 쓰고 Encoder 출력 중 단어에 대한 정보만 포함한 것을 Value로 쓰고, 여기에 문맥 정보까지 더한 것을 Key로 쓴다고 생각하면 된다. 그러니 Query는 현재 위치의 정보를 담고 있고, Key와 Value는 전체에 대한 정보를 담으며, 이중 Key는 문맥까지 담고 있게 된다. 각 Query와 Key의 dot product를 계산해 Attention Score를 얻는다. 이 score에 softmax를 취한 최종 attention을 Value에 곱해 weighted value를 얻는 것이 최종 목표인 것이다. squared dimension term으로 나눠주기에 이를 scaled dot-product attention이라 하며, 이것은 Additive (Bahdanau) Attention보다 훨씬 빠르고 space-efficient하다고 한다.

 

d는 Key의 차원, Q와 K의 전치를 dot product한다.

 

 

scaling을 하는 이유는, dot-product의 문제점인 '값 자체가 커져버리는 것'을 보완하고자, 즉  Softmax 함수가 지나치게 치우쳐지는 문제를 방지하고, 학습을 안정화하고자 도입한 것이다.

 

 

4) Multi-head attention

Multi-head attention는 하나의 Attention 메커니즘을 여러 개의 subspace로 병렬 적용시키는 방법이다. 쉽게 말해 팀 발표 후에서 질문 받는 사람이 한 명인 것보다, 각 팀 직무(subspace)마다 답변자를 나누고 동시에 다른 곳에서 답변하는 것이 훨씬 효율적이듯이, Multi-head Attention에서 subspace는 특정 유형의 정보에 전문화된 space를 의미하여 시간적 효율뿐 아니라 모델의 표현력, 결국 성능 향상에 도움이 되는 방식이다. 또한 놀라운 점은 각 head의 subspace는 모델 학습 과정에서 자동으로 학습된다는 것이다. (마치 LSTM의 forget gate가 알아서 학습되던 것처럼!)


[참고자료]

* (Paper) https://arxiv.org/abs/1409.0473 

* (Paper) https://arxiv.org/abs/1706.03762

* (Blog) https://ctkim.tistory.com/entry/RNN-seq2seq%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80