본문 바로가기
Paper Review/Language Language Model

[최대한 쉽게 설명한 논문리뷰] Attention Is All You Need(Transformer 논문)

by climba 2022. 3. 23.
- Reference
The Illustrated Transformer
The Positional Encoding 를 어떻게 하는 것인가?
딥 러닝을 이용한 자연어 처리 입문
트랜스포머 (어텐션 이즈 올 유 니드)
[딥러닝 기계 번역] Transformer: Attention Is All You Need (꼼꼼한 딥러닝 논문 리뷰와 코드 실습)

0. 글 쓰기에 앞서

BERT는 Transformer의 인코더(Encoder) 부분을,
GPT는 Transformer의 디코더(Decoder) 부분을 활용하였다.

구글에서 발표한 Transformer는 최근까지 가장 뛰어난 자연어 처리 모델이라 평가 받는 BERT, GPT 등에서도 활용되고 있다.

"Attention is all you need" (너가 필요한것은 Attention 이 전부다.)

논문의 제목에서 알 수 있듯이, 이 논문 즉 Transformer의 핵심 키워드는 Attention이다.

주의할 점은 Attention은 기존 인코더 디코더의 성능을 강화시키며 이미 주목받고 있던 메카니즘이였고 이 논문에서 Attention을 발표한 것이 아닌 RNN을 사용하지 않고 Attention만으로도 입력 데이터에서 중요한 정보들을 찾아내 단어를 인코딩 할 수 있다는 것을 발표한 것이다.

그렇다면 과연 Attention이란 무엇이고 또 Transformer는 이전의 기계 번역 모델들과는 어떤 차별점이 있는 것일까?

1. Transformer 개요

RNN은 LSTM과 함께 기존 자연어 처리 task에서 가장 많이 쓰이는 모델이였다.

자연어 처리에서 문장을 처리할때 문장에 사용된 단어의 위치는 굉장히 중요하다.

기존의 자연어 처리 task에서 RNN, LSTM이 자주 활용되었던 이유는 이러한 모델이 단어의 위치와 순서정보를 잘 활용했기 때문이다.

 

그러나 RNN은 순차적으로 첫번째로 입력된 단어부터 마지막으로 입력된 단어까지 인코딩하기 때문에 문장의 길이가 길어지면 학습 능력이 현저하게 떨어진다. (장기의존성 문제, Long-Term Dependency Problem)

 

Transformer는 이러한 과정을 병렬적으로 처리하기 때문에 RNN보다 성능과 속도면에서 훨씬 뛰어나다.

 

그러나 위에서 언급했듯 자연어 처리 task에서 단어의 위치정보는 굉장히 중요한데,

RNN을 사용하지 않는 Transformer는 어떻게 단어의 위치정보를 활용할 수 있을까?

정답은 바로 Positional encoding이다.

 

Positional Encoding은 Transformer의 굉장히 중요한 특징 중 하나인데 뒤에 transformer의 구조를 살펴볼때 다시 언급하기로 하고 우선 transformer 이전의 자연어 처리 모델들에 대해 살펴보자.

 

2. 딥러닝 기반 기계 번역 발전 과정

Attention 메커니즘이 나온 2015년 전까지만해도 기계번역에서 가장 많이 쓰이던 모델은 Seq2Seq 모델이였다.

Seq2Seq은 LSTM을 활용해서 만든것인데, LSTM을 활용하면 다양한 시퀀스 정보를 모델링 할 수 있다. 

 

다만, Seq2Seq는 고정된 크기의 context vector를 사용하고 있기 때문에 주어진 문장을 전부 고정된 크기의 한 벡터에 압축을 할 필요가 있고 이는 성능적인 한계에 부딪힌다.

 

이를 해결하기 위해 등장한 것이 바로 Attention 메커니즘이고 이 덕분에 기계번역의 모델들의 성능은 크게 향상되었다. 그러나 여전히 RNN을 사용하면서 장기의존성 문제가 존재하였고, 2년이 지난 2017년 구글에서 Transformer 논문을 통해 RNN을 아예 사용하지 않고 Attention만을 이용하면 훨씬 더 좋은 성능을 낼 수 있게 된 것을 발표하였다.

 

2-1. Seq2Seq Model

Seq2Seq모델의 가장 큰 문제점은 context vector v에 소스 문장의 정보를 압축한다는 것이다.

이는 병목(bottleneck)현상을 발생시켜 성능 하락의 원인이 된다.

이때 병목현상이란 한번에 처리 가능한 데이터의 양보다 많은 양의 데이터가 들어와 처리 할 수 없는 상태를 의미한다.

한쪽의 seq으로부터 다른 한쪽의 seq을 만들기때문에 seq2seq이라고 한다.

위 Seq2Seq모델의 예시를 보면 독일어문장을 영어문장으로 바꿀때 고정된 context vector v 를 통해서 영어문장으로 바꿔준다.

 

학습 과정은 다음과 같다.

1. 매번 단어가 입력될 때 마다 hidden state 값을 갱신한다.(h1,h2,h3,h4 ...)

2. 이런 hidden state(h값)은 이전까지 입력되었던 단어들에 대한 정보를 갖고있기 때문에 마지막 단어가 들어왔을때 나오는 hidden state 값은 소스 문장 전체를 대표하는 하나의 context vector로서 사용할 수 있다.

따라서 context vector는 소스문장 문맥적인 정보 전체를 담고있다고 생각 할 수 있다.

3. 디코더 파트에서는 출력단어가 들어올때마다 context vector로부터 hidden state(s1,s2,s3 ...)를 만들어서 매번 출력을 내보낸다.

4. 다음 단계에서는 이전에 출력했던 단어가 다시 입력으로 들어와서 이전 hidden state와 함께 새로운 hidden state(s1,s2,...)를 갱신한다. (end of sentence가 나올때까지(<eos>))

 

문제는 입력문장이 매우 길 경우 문장의 모든 문맥 정보를 하나의 context vector에 넣어두기는 어려움이 있다.

-> 디코더 파트에서 출력 단어를 만들때마다 인코더에서의 모든 출력(hidden state)들을 입력값으로 받는다면?

-> Seq2Seq with Attention

2-2. Seq2Seq with Attention

💡기본 IDEA : 인코더의 모든 출력값들(h1,h2,h3..)을 별도의 배열에 기록해 놓은 후 디코더에서 출력 단어를 생성할때 참고해서 소스문장 전체를 반영할 수 있게 하자 (기존에는 context vector만 반영)

이렇게 등장한것이 바로 Attention 메커니즘이다.

Attention 메커니즘은 디코더부분에서 output을 만들때 인코더의 hidden state들을 전부 참고해서 만드는것이다.

단, 모두 동일한 비율로 참고하는 것이 아닌 예측할 단어와 관련이 있는 단어를 집중(attention)해서 본다.

 

위 그림의 예시에서, 디코더부분의 hidden state s2을 만드는 과정을 생각해보자.

우선 이전의 hidden state인 s1과 소스 문장에서의 hidden state 값들(h1,h2..)을 서로 묶어서 행렬곱 수행해 각각의 에너지 값을 만든다.

여기서의 에너지 값(E)이란 현재 특정 단어를 생성하기 위해서 소스 문장에서 어떤 단어에 초점을 둘 필요가 있는지 수치화해서 표현한 값이다.

그 후 에너지값에 softmax함수를 취해서 확률값(가중치)으로 바꿔준 후 소스문장 각각의 hidden state 값 (h1,h2,h3)에 대해서 어떤 벡터에 더 많은 가중치를 줄 지 참고한다.

가중치를 다 hidden state 값에 곱해주고 그 값을 모두 합해 weighted sum(W)을 구한다.

이 weighted sum를 매번 출력 단어를 만들때 반영하는 것이다. (잘 이해가 되지 않는다면 아래 수식을 보고 다시 읽어보자,,)

 

에너지와 가중치를 조금 더 수식적으로 살펴보면 이해하는데 도움이 될 것이다.

에너지값은 매 i(디코더)마다 모든 j(인코더)들을 고려한다.

따라서 어떤 h값과 가장 많은 연관성을 갖는지 구한 후 그 에너지 값에 softmax를 취해서 확률값을 구한다. 구한 가중치 값을 다시 h값과 곱해서 가중치가 반영된 각각의 인코더의 출력 결과를 더해서 활용하는 것이다.

매번 디코더 파트에서 각각의 단어를 만들기 위해서는 이전 hidden state값과 a값을 이용한다.

여기서 a는 인코더파트의 모든 hidden state값을 묶어서 에너지값을 구한후 softmax를 취해서 구한 비율을 의미한다.

이때 모든 a의 합은 1이 되어야한다.(비율이므로)

 

Attention 메커니즘을 사용하면 그 가중치를 이용해 시각화 할 수 있다는 장점도 있다.

어텐션 가중치를 사용해 각 출력이 어떤 입력 정보를 참고했는지 알 수 있다. (밝게 표시된 부분이 확률값이 높은 것이다.)

요약하자면, 단순히 context vector만 사용하는 것이 아니라(기존의 seq2seq소스 문장에서 출력되었던 모든 hidden state 값들을 반영해 어떤 단어에 더욱 더 주의집중(Attention)해서 출력 결과를 만들 수 있는가를 모델이 고려하도록 만드는 것이다.

3. Transformer with attention

다시 Transformer로 돌아오면, 이 논문(Attention is all you need)의 핵심은 RNN이나 CNN을 전혀 사용하지 않고 Attention만 잘 활용해도 다양한 자연어 처리 task에서 좋은 성능을 낼 수 있다는 것이다.

Transformer의 구조

 

위 구조에서 볼 수 있듯 트랜스포머는 RNN이나 CNN은 전혀 사용하지 않는다. (인코더와 디코더는 사용한다.)

대신 Attention 메커니즘Positional Encoding을 사용하는데 positional encoding은 위에서 언급했듯 문장안에 포함되어있는 각 단어들의 순서정보를 알려주기 위함이다.

Attention 과정을 한번만 사용하는 것이 아니고 여러번 반복해서 사용한다.

 

3-1. Attention

Transformer에서 사용되는 Attention은 여러개의 head를 사용한다는 뜻에서 Multi-head Attention 이라고 불린다.

실제 구조는 다음과 같다.

Multi head attention에서 head란 Scaled Dot-Product Attention을 의미하며 h개의 head를 갖기 때문에 Multi head라고 표현한다.

Multi-head attention의 구조

Attension 메커니즘의 입력값과 출력값은 dimension이 같아야한다.

Attention 메커니즘 : 어떠한 단어가 다른 단어들과 어떠한 연관성을 갖는지 구하는 것이다.

Query : 영향을 받을 단어

Key : 영향을 주는 단어

Value : 영향에 대한 가중치

 

Q와 K를 행렬곱하고 스케일링 -> 마스크 -> 소프트맥스를 취해 어떤 단어와 가장 높은 연관성을 갖는지 비율을 구하고 그 확률값과 Value값을 곱해서 가중치가 적용된 결과적인 attension value(수치)를 구할 수 있다. 이때 이 수치가 높을수록 단어의 연관성이 높다고 할 수 있다.

 

트랜스포머에는 총 세가지 종류의 어텐션이 있다.

1. Encoder Self-Attention

2. Masked Decoder Self-Attention

3. Encoder-Decoder Attention

 

3-1-1. Encoder Self-Attention

Encoder 파트에서 진행되는 Attention은 self-attention인데, 이것은 각각의 단어가 서로에게 어떤 연관성을 갖고있는지 구하기위해 사용된다.(상관관계 느낌)

self attention은 인코더와 디코더 모두에서 사용된다.
-> 매번 입력 문장에서 각 단어가 다른 어떤 단어와 연관성이 높은지 계산 할 수 있다.

I am a teacher의 경우 I, am, a, teacher가 각각 서로에게 attention score를 구해서 어떤 다른 단어와 높은 연관성을 갖는지 알 수 있다.

 

또한 잔여학습과 같은 테크닉을 통해 성능을 향상시켜주는데, 잔여학습은 보통 ResNet과 같은 이미지 분류 네트워크에서 사용된다.

잔여 학습 (Residual Learning)

잔여학습이란 어떠한 값을 레이어를 거쳐서 반복적으로 단순 갱신하는 것이 아니라 특정 레이어를 건너뛰면서 입력 할 수 있도록 만드는 것이다. (블로그 참조)

트랜스포머의 동작 원리 : Encoder(인코더)

인코더에서는 위와 같이 어텐션과 정규화(Norm)과정을 반복하는 방식으로 여러개의 레이어를 중첩해서 사용한다.

이때 각 레이어는 서로 다른 파라미터를 갖는다는 특징이 있다. 또한 입력되는 값과 출력되는 값의 dimension은 서로 동일하다.

트랜스포머의 동작 원리 : Encoder(좌)와 Decoder(우)

인코더에서 가장 마지막 레이어에서 나온 출력값은 디코더에 들어가게 된다.

이렇게 해주는 이유는 디코더 파트에서 매번 출력할때마다 소스 문장에서 어떤 단어에게 초점을 둬야하는지 알려주기 위함이다. 따라서 각 레이어는 인코더의 마지막 레이어에서 나온 출력값을 입력으로 받게된다.

 

디코더의 마지막 레이어에서 나온 값이 바로 실제로 우리가 번역을 수행한 결과(출력 단어)가 되는 것이다.

3-1-2. Masked Decoder Self-Attention

Decoder 파트에서 attention을 수행할 때에는 앞쪽 단어에서만 참고한다.

(아직 출력되지 않은 미래의 단어에 대한 attention을 적용하면 안되기 때문)

 

마스크 행렬(mask matrix)를 이용해 특정 단어는 무시할 수 있도록 한다.

mask matrix는 energy와 차원의 크기가 같아야한다.

마스크 값으로 음수 무한의 값을 넣어 softmax 함수의 출력이 0에 가까워지도록 한다.

MultiHead(Q,K,V)를 수행한 뒤에도 차원은 동일하게 유지된다.

Multi head attention은 만들어진 head들을 다시 concat하기때문에 차원은 원래 입력의 임베딩차원과 동일한 값을 가진다.

3-1-3. Encoder-Decoder Attention

Query는 디코더에 있고 각각의 Key와 Value는 인코더에 있다.

 

하나의 디코더 레이어 에서는 두 종류의 Attention method가 사용되는데 self attention(masked)과 encoder-decoder attention이다.

self attention은 먼저 수행되는 attention으로 인코더파트와 마찬가지로 각각의 단어들이 서로가 서로에게 어떤 가중치를 갖는지 구하도록 만들어 출력 문장의 전반적인 표현을 학습할 수 있도록한다.

encoder-decoder attention은 디코더가 인코더에 대한 정보를 어텐션 할 수 있도록 한다.

즉, 각각의 출력단어가 소스문장에서의 어떤 단어와 연관성이 있는지 구해주는 것이다.

디코더의 레이어 역시 input dimension과 output dimension을 같게 만들어줘서 여러 레이어를 중첩해서 사용할 수 있게 한다.

n_layers = 4일때

트랜스포머에서는 마지막 인코더 레이어의 출력이 모든 디코더 레이어에 입력된다.

(입력된다의 의미는 디코더부분의 두번째 어텐션(encoder-decoder attention)에서 각각의 출력 단어가 소스 문장의 어떤 단어와 연관성이 있는지 구해준다는 의미다.)

또한 일반적으로 인코더와 디코더의 레이어 갯수가 동일하게 설정해준다.

기본적으로 RNN, LSTM을 사용할 때에는 입력 단어의 갯수만큼 레이어를 거쳐서 매번 hidden state를 만들었다면,

Transformer에서는 입력 단어 자체가 쭉 연결되어서 한번에 입력되기 때문에 병렬적으로 출력값을 구할 수 있는것이다.

 

3-2. Multi-head Attention의 동작 원리

트랜스포머의 동작 원리 : Encoder(좌)와 Decoder(우)

Multi-head Attention은 전체 아키텍쳐에서 동일한 함수로서 동작한다.

단, 사용되는 위치마다 query,key,value를 어떻게 사용할지가 다르다.

encoder-decoder attention의 경우 디코더의 출력 단어가 query가 되는 것이고, 각각의 출력 단어를 만들기 위해서 인코더 파트의 어떤 단어를 참고하면 좋은지를 구하기 위해서 key,value 값은 인코더의 출력값을 쓰는것이다.

Multi-Head Attention의 수식 표현

Multi-head Attention의 동작원리를 차례대로 살펴보면 다음과 같다.

 

1. Attention(Q, K, V) -> 하나의 Attention은 Query, Key, Value를 값으로 받는다.

 

2. Query랑 Key를 곱해서 각 Key에 대한 energy 값을 구해준 후 softmax를 취해 확률값으로 만들어준다.

-> 어떤 Key에 대해 높은 가중치를 갖는지 알 수 있다.

 

3. 이때, scale factor로서 sqrt(dk)를 사용하는데 dk는 각각의 key dimension이다.

scale factor로 나눠주는 이유는 softmax의 함수는 0근처에서 gradient가 높게 형성되는 것에 비해 오른쪽이나 왼쪽으로 이동하게 되면 기울기 값이 크게 줄어드는 문제(gradient vanishing)가 일어날 수 있고, dot product 계산시 값이 증대되는 문제를 보완하기 위해서이다.

 

4. softmax를 통해 각 Query가 각 Key에 대해서 어떤 가중치를 갖는지 그 score값을 구한 후 Value값과 곱해줘서 Attention value를 구할 수 있다.

 

5. 이때 입력으로 들어오는 각각의 값에 대해서 서로 다른 Linear Layer를 거치게 만들어서 h개의 서로 다른 Query, Key, Value값을 만들어준다.

 

6. h개의 서로 다른 concept을 네트워크가 구분해서 학습 할 수 있게해서 attention을 수행하기 위한 다양한 feature들을 학습한다.

 

7. Attention score를 시각화해보면 h의 갯수만큼 attention score의 그림이 나온다.

 

8. 각 head에 대한 출력값을 concat으로 붙인 후 output matrix와 곱해서 결과적인 multi head attention의 값을 구한다.

 

3-3. Positional Encoding

앞서 말했듯 Transformer의 중요한 특징 중 하나는 Positional Encoding이다. 

이때 순서정보를 주기 위한 Positional Encoding으로 사인,코사인 함수를 사용하는데 왜 하필 이것을 이용하는 것일까?

 

우선 정수를 사용하지 않는데는 다음과 같은 이유가 있다.

1,2,3, .. 의 정수값으로 위치 정보를 표현하게 된다면 시퀀스 길이가 커졌을때 인덱스 역시 커지므로 훈련이 매우 불안정해질 수 있다.

 

그렇다면 마지막 인덱스를 1로 잡고 [0,1] 구간에서 비율로 나누면 되지않을까?

이렇게 비율을 사용하는 경우에는 같은 0.9라는 값이여도 시퀀스의 길이가 10이라면 9번째 원소를 의미하고, 100이라면 90번째 원소를 의미하기 때문에 길이에 따라서 encoding의 의미가 달라진다.

 

이진수를 활용해 스칼라가 아닌 벡터형태로 사용하면 안되나? (ex : [0,1,0,1,0,0,0,1])

벡터형태를 사용하게 되면 고차원 데이터를 사용하는 경우 거리를 계산할때 다른 거리로 판단해 계산할 수 있다.(참조)

pos : 단어 번호, i : 단어에 대한 임베딩값의 위치

따라서 위와같은 sin,cos함수를 사용하는 것이다.

또한 하나의 sin함수 혹은 cos함수를 사용하는 것이 아닌 홀수,짝수로 나누어서 두개를 사용하는 이유는 하나의 함수만 사용한다면 위치가 커질 때마다 그 값이 커지고 작아짐을 반복해 어떤 특정 두 토큰의 위치값이 동일해질 수 있기 때문이다. (명료하게 이해X) (참조)

 

정리해보면 sin,cos 함수는 아래 네가지 조건을 모두 만족하기 때문에 positional encoding으로 사용하는 것이다.

1. 각각의 고유한 토큰 위치값은 유일한 값을 가진다.

2. 서로 다른 두 토큰이 떨어져 있는 거리가 일정해야한다.

(1번째 토큰과 2번째 토큰, 2번째 토큰과 3번째 토큰의 차이가 서로 같아야한다.)

3. 학습 데이터중 가장 긴 문장보다도 긴 문장이 실제 데이터에서 들어와도 에러 없이 인코딩 값을 줄 수 있어야한다.

4. 함수에 따른 토큰 위치의 값을 예측 할 수 있어야 한다.

 

참고로 positional encoding은 backpropagation(역전파) 과정에서 손실될 수 있는데 위에서 설명한 residual connection으로 입력된 값을 다시한번 더해줌으로서 이를 어느정도 예방할 수 있다.

 

4. 정리

Transformer 논문을 읽으려면 알아야하는 배경지식이 상당히 많은 것 같다.

자연어 처리와 관련해서 RNN, LSTM은 기본이고 Attention, Seq2Seq, residual learning 등 다양한 배경지식을 필요로 하는데 아직 기본 지식이 부족해 읽는데 어려움이 많았다.

앞으로 더 공부를 해가며 Transformer에 대해 다시 알게된 내용이나 이해가 안되었다가 된 내용이 있으면 정리해나가야 겠다.

댓글