본문 바로가기
NaverBoost Camp 4기/DL BASIC

[DL Basic] Transformer (Attemtion is All You Need).2017

by 하람 Haram 2023. 3. 14.
728x90

Tranformer는 엄밀하게 말하면 앞에서 연결되는 RNN, LSTM, GRU와는 좀 다른 방법으로 접근한다

-> 해결하고자 하는 것은 동일함

 

<배경아이디어>

왜 Sequential modeling이 다루기 어려울까?

 

우리의 일상생활을 생각해보자

표준 문장을 적어보면 "승종아, 오늘 점심에 밥 먹었어?"

이런 문장이

"승종, 밥 먹었어?" , "승종, 점심에 밥 먹었어?" , "승종, 점심 먹었어?" 등등 길이가 달라지고 어순이 달라지고 등등

하나의 동일한 의미에 다양한 문장을 만들 수 있다

 

즉 Original sequence에 대해서

  • Trimmed Sequence(마지막 몇개의 단어의 생략)
  • Omitted Sequence (중간에 몇개의 단어의 생략)
  • Permuted Sequence (어순이 달라지는 경우)

등 많은 변화가 있을 수 있다 <-  이런 걸 해결하고자 Transformer가 등장함

 

Transformer는 기본적으로 Self attention이라는 구조를 사용

 

<관련 논문 : Attention is all you need>

https://arxiv.org/pdf/1706.03762.pdf

https://arxiv.org/abs/1706.03762

<Transformer>

Keypoint는 다음과 같다

1. N개의 단어가 어떻게 한번에 처리가 되는지
2. Encoder와 Decoder 사이에 어떤 정보를 주고 받는지
3. Decoder가 어떻게 Generation 할 수 있는지

 

참고자료 : http://jalammar.github.io/illustrated-transformer/

 

Transformer is the first sequence transduction model based entirely on attention.
  • Transformer는 Recursive (재귀적) 구조를 없앴다
  • Transformer에는 재귀적인 구조가 존재하지 않고 Attention 이라는 구조를 사용했다
  • Transformer는 Sequential한 데이터를 처리하고 encoding하는 방법이다 -> 그래서 번역 뿐만 아니라 이미지 분류, detection 등등 을 사용한다
  • Sequence to Sequence model

 

 

Core Idea : Self Attention & Encoder Decoder Attention

 

<Transformer의 구조>

 

 

1. Input Sequence 와 Output Sequence의 dimension(길이)는 다를 수 있다

2. 위 그림과 같이 동일한 구조를 가지지만 parameter가 다르게 학습되는 Encoder/ Decoder가 stack 되어 이루어져 있다

3. 위와 같은 구조를 가졌기에 N개에 단어에 대해 반복은 1번만 된다 

-> ex) RNN :  3단어가 들어가면 -> 3번 반복 , Transformer :  100단어가 들어가도 1번만 실행

-> 그래서 Attention is all you need 라는 말을 쓰지 않았을까 짐작해 본다

 

 

<Self  Attention> 

다음 그림과 같이 Encoder에 내부를 살펴보면 Self- Attention 부분과 Feed Forward NN 부분이 있다

Feed Forward Neural Network는 우리가 그동안 알았던 NN 과 별반 차이가 없는데

핵심은 Self - Attention 이다

 

굉장히 러프하게 설명을 하면

Input x1이 Self -Attention을 거쳐서 z1으로 나오게 되는데 이 과정에서

z1 은 x1 만 고려하여 만든 것이 아닌 x2, x3 도 같이 고려하여 만든 결과이다 (밑에 그림 참조)

이런 식으로 한 Word 끼리의 관계를 엮어서 하나의 출력을 만들어 주는 것이 Self- Attention 이다

 

<Self Attention : Step by Step> 

1, 먼저 단어마다 특정 숫자의 벡터로 표현을 해준다

여기서 단어를 어떻게 벡터로 바꾸냐는 질문에는 Word Embedding 이 있는데

이는 나중에 정리하고 일단 word를 숫자로 바꿨다고 생각하자

Reference : https://medium.com/deeper-learning/glossary-of-deep-learning-word-embedding-f90c3cec34ca

 

 

2. Self Attention을 통해 변환된 벡터를 단어마다 만들어 준다

 

위 설명을 보면 아래의 Self Attention은 dependency가 있지만 위에 Feed Forward는 그냥 하나만 고려한다

 

3. Self Attention에서 Score를 구하는 방법

엄밀하게 이야기하면 2번과 3번의 순서가 바뀌었지만 가독성을 위해 이렇게 순서를 역순으로 설명하였다

 

먼저, 구하고자 하는 Score Vector에 대해 이해를 하자

Score Vector : 비교 기준이 되는 녀석과 얼마나 관계가 있는지에 대한 수치

여기서 말하는 관계성이란

The animal didn't cross the street because it was too tired  이라는 단어로 예시를 들어 보면 

 

위 문장에 있는 it은 어떤 것 일까? 

As the model processes each word (each position in the input sequence), self attention allows it to look at other positions in the input sequence for clues that can help lead to a better encoding for this word.

우리는 이를 위해 독해를 하고 여러가지 생각을 거쳐서 The animal 이라고 말을 한다

이와 같이 AI도 어떠한 프로세스를 통해 관계성을 파악하여 가장 연관 있는 단어가 무엇인지 찾아낸다.

 

-> 좀 더 쉽게 설명을 하면 it 이라는 단어가 나왔다는 것은 앞에 사물이 나왔다는 것이라고 우리는 학습을 통해 말한다

이런 걸 관계성이라 말하고 Transformer는 이를 이용한다

 

즉, 위의 예시를 한국어로 번역을 해보자면

"동물은 거리를 건널 수 없을 것이다, 왜냐하면 ("그분" / "그것"  / "그녀" / "그들" / "그 동물")은 매우 피곤하기 때문이다"

중에 "그 동물"이라는 단어를 선택할 것이다

 

이를 구하기 위해서는 다음과 같은 단계를 거친다

 

 

3-1 각 단어마다 Queries, Keys, Values 값 구하기

 

예시로 "Thinking Machines"이라는 단어가 들어 왔다고 가정하자 

So for each word, we create a Query vector, a Key vector, and a Value vector. These vectors are created by multiplying the embedding by three matrices that we trained during the training process.

이 단어들을 x1, x2 라고 할 때 (이미 vector로 임베딩 되었다고 가정)

These vectors are created by multiplying the embedding by three matrices that we trained during the training process.

그러면 x1,x2 에 대해서 WQ, WK, WV를 곱해서

각각 Queries, Keys, Values Vector를 만든다

 

즉, 각각의 embedding된 단어마다 matrices를 곱하여서 Key, Query, Value vector를 만든다

 

3-2 각 단어마다 Score Vector 구하기

 

예시를 위해 위의 예시에서 Thinking 의 Score Vector를 구한다고 생각해보자

구하고자 하는 단어의 Queries에 대해

모든 단어의 (자기자신 포함) Keys 값을 내적한다

ex) q1 dot k1 = (10,1,3)(10,6,4) = 112

 

위의 과정에서 내적을 해야 하기 때문에 Queries vector 와 Keys vector의 차원은 같아야 한다

 

즉, 내가 encoding 하고자 하는 단어의 Queries 벡터와 나머지 모든 N에 대한 keys vector를 내적하여 각각 단어끼리의

유사도를 파악 한다 -> 이것이 Attention (특정 time step에 어떤 입력을 주의 깊게 볼지 결정)

 

4. Self Attention에서 Attention Weight를 구함

 

먼저 중간에 8 로 나누어 준 것은 Score 값이 너무 커지지 않게 하기 위해서 key vector의 dimension(hyperparameter)인 64의 제곱근 8을 나누어 준다 (정규화 느낌)

 

그 다음 Softmax를 통과 시켜 주면 이것이 Attention Weight이다

 

5. Attention Weight에 Value를 곱해서 Resulting Vector z를 만들어 준다

위에서 구한 Attention Weight는 스칼라 값이므로

여기에 각각의 단어의 Value를 곱해서 더해주면 최종 출력이 나온다

이러한 과정을 거치기 떄문에 최종 출력인 Encoding Vector는 Value vector와 동일한 차원을 가지게 된다

 

즉, Value Vector들의 weight를 구하는 방법이 ~ softmax까지 하여서 Attention Weight를 구하는 것이고

최종적으로 나오는 encoding vector는 value vector와 weighted Sum을 진행한 값이다

 

 

 

위에서 설명한 방법을 Matrix로 표현해보자

<Matrix Calculation of Self-Attention>

The first step is to calculate the Query, Key, and Value matrices. We do that by packing our embeddings into a matrix X, and multiplying it by the weight matrices we’ve trained (WQ, WK, WV).

위의 그림에서 X는 앞에서 예시를 들었던 "Thinking Machines"를 Matrix로 embedding 한 것이다

 

가로는 Embedding 할 때 정의하는 demension이고

세로는 단어의 개수 즉, 2 이다

 

그림과 같은 방법으로 Q K V를 구하고

다음 연산을 진행하면 z가 나오게 된다

 

굉장히 복잡해보이지만 Python을 통해 한 줄로 구현이 가능한 수식이다

Scores = Q.matmul(K.transpose(-2,-1)) / np.sqrt(d_K)

 

위에서 볼 수 있듯이  각각 단어들에 대해서 동일한 WQ, WK, WV를 통해서 Q,K,V를 만들어 낸다

 

지금 머리 속에 생각한 걱정

이러면 조금 성급한 일반화가 되지 않을까? 성능이 좋게 나올까? 라는 생각을 나도 했는데

조금 더 읽고 나서 이러한 걱정이 해결되었다

 

 

<Matrix Calculation의 한계 극복> : MHA (Multi-head Attention) 

위와 같은 고민을 덜어주기 위해서 multi head Attention 이라는 개념을 설명한다

(이전 까지는 Single head Attention)

 

이는 앞에 Attention 과정을 여러번 거쳐서 하나의 입력에 대해 WQ, WK, WV를 여러 개 만드는 방법이다

 

즉, N개의 head가 있으면 N개의 Encoding Vector가 나온다

(논문에서는 8개의 Head를 두었다)

 

이렇게 했을때 문제점이 발생한다

 

<MHA의 문제점과 해결방법>

 

 

 

8개의 Head를 썼다고 가정을 하고 설명하면

z가 총 8개 나오게 되는데

맨 처음 transformer의 구조를 살펴보면 Encoder가 다른 Encoder와 Stack되어 있고 같은 구조이다

즉, Enbedding Vector와 Encoding Vector의 차원이 동일해야 하지만 MHA에 경우 Encoding Vector가 8배 더 크다

 

이를 해결하기위해 추가적인 Matrix를 아래 그림과 같이 두어

Encoding Vector 와 Embedding Vector의 차원을 동일하게 만들어 주었다

 

 

<최종>

모든 걸 요약해보면 다음과 같다

위의 과정을 모두 거치면 문제가 없어 보이지만 이 또한 문제가 있다

 

 

<추가적인 문제점 해결 방법> : Positional Encoding

 

Transformer의 과정을 잘 살펴보면 각각 단어를 따로 따로 분리해서 계산을 진행하는 방식이므로

Sequential한 정보는 없어지게 된다

 

이를 해결하기 우해 Positional Encoding을 진행한다 (bias 처럼 계산)

If we assumed the embedding has a dimensionality of 4, the actual positional encodings would look like this:

Positional encoding을 구하는 방법은 Pre- defined도니 값을 가져와서 쓰면 된다

get_timing_signal_1d()

https://github.com/tensorflow/tensor2tensor/blob/23bd23b9830059fbc349381b70d9429b5c40a139/tensor2tensor/layers/common_attention.py

 

GitHub - tensorflow/tensor2tensor: Library of deep learning models and datasets designed to make deep learning more accessible a

Library of deep learning models and datasets designed to make deep learning more accessible and accelerate ML research. - GitHub - tensorflow/tensor2tensor: Library of deep learning models and data...

github.com

 

값을 그림으로 나타내면 다음과 같다

A real example of positional encoding for 20 words (rows) with an embedding size of 512 (columns)

가운데에 나누어져 있는 것 처럼 보이는 이유는 중앙을 기준으로 다른 함수를 적용햐서 그렇다고 한다

(왼 : sine , 오 : cosine)

 

위에 정의된 값을 사용하는 것이 유일한 방법은 아니지만  train이 된 모델이 train data보다 긴 문장을 번역하도록 요청받을 때 처리할 수 있는 이점을 제공한다고 한다

 

최근 2020.07 에 업데이트 된 positional encoding은 다음과 같다

The positional encoding shown above is from the Tranformer2Transformer implementation of the Transformer. The method shown in the paper is slightly different in that it doesn’t directly concatenate, but interweaves the two signals

여기서는 위에와 다르게 단순히 붙인 것이 아닌 두 신호를 잘 합쳤다고 한다

https://github.com/jalammar/jalammar.github.io/blob/master/notebookes/transformer/transformer_positional_encoding_graph.ipynb

 

GitHub - jalammar/jalammar.github.io: Build a Jekyll blog in minutes, without touching the command line.

Build a Jekyll blog in minutes, without touching the command line. - GitHub - jalammar/jalammar.github.io: Build a Jekyll blog in minutes, without touching the command line.

github.com

 

 

<Layer Normalization>

논문에 따르면 Feed Forward로 z를 넘기기 전에 layer normalization을 거친다고 한다

관련 논문 : https://arxiv.org/abs/1607.06450

 

이름은 어려워 보이지만 예시를 들어보면 쉽다

batch size :3 , # of Feature : 6

layer 즉, Channel 단위로 평균과 분산을 구하여 정규화를 진행한다

 

레이어 정규화 : (a - 데이터별 평균(a)) / root(데이터별 분산(a)+epsilon) * gamma + beta

(정규화 이후에 Relu 등의 활성 함수를 사용해 준다. gamma 의 초기값은 1, beta의 초기값은 0을 사용하는 것이 보통이다.)

 

batch 정규화를 하지 않고 layer 정규화를 하는 이유는 BN은 시퀀스의 길이를 마음대로 변경할 수 없지만

LN은 시퀀스의 길이를 자유롭게 변경할 수있고 이는 Transformer의 목적과 잘 부합된다

 

 

 

 

<Encoder-Decoder Attention>

The “Encoder-Decoder Attention” layer works just like multiheaded self-attention, except it creates its Queries matrix from the layer below it, and takes the Keys and Values matrix from the output of the encoder stack.

Encoder에서 Decoder로는 어떤 정보가 날라갈까?

 

먼저 마지막 최상단의 Encoder는 Decoder에게 Keys(K) 와 Values matrix(V)을 넘겨 준다 (Queries(Q)는 넘기지 않는다)

 

그러면 Decoder는 the layer below it (이전까지 나온 단어들을 가지고) Queries Matrix을 만들어 낸다

즉, Decoder의 Queries Matrix은 Decoder에 들어가는 단어들로 만들어진 Matrix이다

(출력을 만드는 방법은 Encoder와 동일하게 Queries와 나머지 keys의 내적을 value에 곱하고 Sum을 해준다)

 

만약 출력으로 <end of sentence> 즉, Special token이 나올 때 까지 아래같이 반복해준다

 

 

<Train Method of Decoder> : masking

Decoder는 어떻게 학습을 할까 ?

In the decoder, the self-attention layer is only allowed to attend to earlier positions in the output sequence which is done by masking future positions before the softmax step.

학습할 때는 입력과 출력을 알고 있는데 (train data이니깐 label도 있겠지?) i번째를 만들 때 모든 문장을 알면 학습에 의미가 없으므로 masking을 하여 이전 것들만 영향받고, 미래 (즉, 뒤에 나오는 단어들)의 정보는 활용하지 않았다

(전체를 사용하는 것을 masking 방식을 통해 방지)

 

 

 

 

<Decoder : How to Make Output> 

The final layer converts the stack of decoder outputs to the distribution over words.

 

단어 들의 분포를 만들어서 Softmax layer를 통과시켜 그 중에 값이 제일 큰 값을 Sampling하는 방식으로 출력을 만든다


<추가 자료>

응용 분야로는 다음과 같이 있다

 

1. Vision Transformer (VIT)

[2010.11929] An Image is Worth 16x16 Words: Transformers for Image Recognition at Scale (arxiv.org)

Encoder만 활용

 

사진의 영역을 나눈 다음에 Encoder를 하나 통과 한 다음 나온 Encoded Vector를 바로 Classifier에 집어 넣는다

(Positional Embedding은 들어감)

 


2. DALL-E

Decoder만 활용

DALL·E: Creating images from text (openai.com)

아직 블로그 밖에 공개가 되지 않았다

 

openAI에서 만들었고 GPT 3 기반이다

 

 

 


<참고 자료>

https://www.youtube.com/watch?v=kCc8FmEb1nY 

http://jalammar.github.io/illustrated-transformer/

 

The Illustrated Transformer

Discussions: Hacker News (65 points, 4 comments), Reddit r/MachineLearning (29 points, 3 comments) Translations: Arabic, Chinese (Simplified) 1, Chinese (Simplified) 2, French 1, French 2, Japanese, Korean, Persian, Russian, Spanish 1, Spanish 2, Vietnames

jalammar.github.io

 

 

 

 

728x90

'NaverBoost Camp 4기 > DL BASIC' 카테고리의 다른 글

[DL Basic] RNN, LSTM, GRU  (1) 2023.03.09
[DL Basic] NN & MLP  (0) 2022.10.06
[DL Basic] 딥러닝의 기초와 흐름  (0) 2022.10.04