[NLP] Transformer
🧑🏻💻용어 정리
Neural Networks
RNN
LSTM
Attention
Transformer
Generator
discriminator
self-attention
layer normalization
multi-head attention
positional encoding
https://arxiv.org/abs/1706.03762
generator는 generation task를 하는 model입니다.
이것은 input에 대해서 어떠한 output을 만드는 것입니다.
discriminator는 분류기입니다.
이러한 용어는 인공지능에서 자주 쓰이니 알아두고 갑시다.
지금까지 우리가 배운
RNN, LSTM, GRU 는 sequence로 앞에서부터 차례로 계산되게 됩니다.
그렇게 Sequence 길이만큼 시간이 걸리게 됩니다.
이렇게 seqential한 구조 말고 parallel한 구조가 없을까 생각합니다.
parallel한 구조는 input sequence가 모두 한 번에 계산되는 것을 의미합니다.
우리가 Attention을 다시 봅시다.
Decoder의 hidden state와 Encoder의 hiddn state와 attention을 계산해서 새로운 context vector를 구했습니다.
지금은 h_1 ~ h_n을 encoder RNN으로 구한 다음, decoder에서 RNN을 가지고 Dot product를 진행했습니다.
그래서 h_1 ~ h_n을 구하는 과정이 있었습니다.
그러나 transformer는 RNN을 하지 않고 바로 sequence 없이 사용합니다.
이런식으로 모델링이 가능한데, 이것은 독립적이므로 서로간의 sequence 정보가 없기 때문에 성능이 낮습니다.
그래서 고안된 것이 이 Sequence에서 x_1 ~ x_n끼리 attention을 구하는 것입니다.
그럼 Transformer 시작합니다.
Transformer
지금까지는 위와 같이 x_1 ~ x_n을 차례로 넣고 output도 차례로 받았습니다.
그런데, 위와 같이 x_1 ~ x_n을 한 번에 적용해볼 수도 있습니다.
한 번에 Attention 방법을 적용하여 구합니다.
더 자세히 살펴봅시다.
encoder에 있는 sequence를 한 번에 넣으면 어떻게 될까요?
그래서 위와 같이 x_1 ~ x_n을 가지고 o_1을 구합니다.
그리고 또, x_1 ~ x_n과 o_1을 이용하여 o_2를 구합니다.
x_1 ~ x_n은 한 번에 계산을 하고, output부터는 decoder를 이용해 구합니다.
이 Output을 구하는 것은 RNN에서 했던 Inference 과정과 같습니다.
o_1을 구하고 o_2를 구하는 형식이죠.
그래서 위와 같은 계산을 갖죠.
이 Transformer는 2017년에 "Attention is All you need" 라는 논문으로 Google brain과 Google research 팀에서 만들어졌고,
해당 링크는 맨 위에 달아뒀습니다.
이제 Transformer 구조를 봅시다.
왼쪽은 input sequence를 modeling하는 encoder 부분입니다.
오른쪽은 decoder 부분으로 output이 첫 번째 token에 들어갔을 때,
첫번째 단어 나오고, 첫 번째 단어 들어갔을 때 두 번째 단어 나오고 하는 형식입니다.
한 sequence에 대해서 encoder에 들어갔을 때 어떠한 Representation을 학습합니다.
그리고 decoder에서는 하나씩 출력을 뽑아내는 형태입니다.
이제 주의 깊게 봐야할 부분, 가장 큰 아이디어는 multi-head attention입니다.
그리고 positional encoding도 중요합니다.
곱하기 N은 위와 같은 Transformer 구조가 N번 반복됨을 나타냅니다.
하나씩 살펴봅시다.
Encoder
이제 새로운 self-attention이라는 개념이 등장합니다.
위에서 언급했듯이, parallel한 구조를 위해서 self-attention이 사용이 됩니다.
우리는 thinking이라는 단어를 계산할 때,
이 thinking이라는 단어와 thinking을 포함한 sequence의 단어와 attention을 합니다.
이 transformer Layer를 한 번 거치면 이 thinking 단어와 이 단어를 포함한 다른 단어와의 attention을 얻고싶어 합니다.
이전에 배운 것처럼, 이 단어를 RNN decoder의 hidden state로 보고 이 단어 포함 나머지 부분들을 encoder의 hidden state로 사용하면 됩니다.
그럼 dot product후 attention score를 뽑아서 weighted sum이 이루어지고 이 sum한 값을 우리가 다음 layer의 vector라고 하겠다는 것입니다.
그래서 이렇게 self-attention이 이루어집니다.
잠시 Q, K, V를 봅시다.
RNN seq2seq 구조에서는 Decoder의 h_t-1의 hidden state와 x_1 ~ x_n의 sequence와 dot product를 통해 attention 값을 구하고, 해당 값에 대해서 sofrmax func.를 지나 attention score를 각각 구하여 이 값을 다시 x_1 ~ x_n에 weighted summation 하여 context vector를 구하였습니다.
여기서 Q, K, V라는 개념이 도입됩니다.
Q는 Query, K는 Key, V는 Value에 해당됩니다.
위 그림에서 살펴보자면, decoder에서 넘어온 hidden state h_t-1을 query, encoder의 x_1 ~ x_n의 hidden state 값 key,
이렇게 Query와 Key 사이에 dot product를 합니다.
그렇게 attention score를 구하고,
key 값과 value는 계산되는 것은 x_1 ~ x_n으로 같지만, attention score를 계산하려한 것은 key,
최종적으로 weighted sum을 하는 것은 value라고 부릅니다.
용어를 위와 같이 구분했다고 보는 것입니다.
이렇게 식으로 나타내어 attention을 구할 수 있습니다.
논문에서는 위와 같은 수식으로 되어 있습니다.
k는 루트 d_k로 차원입니다.
dot product를 하는 데 있어, 큰 차원 x 큰 차원으로 진행하면 엄청 큰 차원이 나오기 때문에 그것을 방지하고자 루트 d_k를 나눠줌으로써 normalization 효과를 가져오며 너무 커지는 것을 방지합니다.
그래서 Self-attention은 다음과 같습니다.
x_1 query와 x_1 ~ x_n인 key, value 에 대해 query와 key를 dot product 후 softmax 씌우고,
attention score에 대해 value와 weighted sum을 하면 context vector가 나옵니다.
이 Query를 x_1 ~ x_n까지 반복하여 각각의 Context vector를 구합니다.
위 수식은 x_i라는 Query가 들어왔을 때, input sequence의 key 값과 attention score 구하고 그것으로 value 값과 weighted sum을 하는 구조이죠.
그것을 표현한 것입니다.
이것을 x_1 ~ x_n에 대해 반복하면 아래와 같겠죠.
encoder에서는 input sequence 끼리 얼마나 관련이 되어 있는지를 확인하는 것입니다.
Q, K, V를 input의 sequence만을 이용하서 계산하겠다는 것이죠.
각 단어에 대해서 self-attention을 구합니다.
it에 대해서 self-attention을 하여 연산한 attention score값이 좌측과 같이 나옵니다. 이것을 weighted sum한 값이 새롭게 구한 attention입니다. 즉, self-attention 값이죠.
이렇게 self-attention layer를 한 번 통과하면 이 단어와 input sequence와 관련 있는 단어와 연관하여 context를 반영하여 새로운 word embedding으로 바뀌는 것입니다.
원래는 관련 없던 Vector 형태였던 것이 관련 있는 것으로 바뀌게 되는 것입니다.
서로의 정보가 반영이 되어 계산됩니다.
장점 :
- 두 거리가 긴 sequential한 구조에서 RNN이 학습하기 어렵던 long-range dependencies를 self-attention을 통해 단어 계산을 Q, K, V를 통해 동일하게 attention을 계산함으로써 long-range dependencies를 잘 해결했다는 것입니다.
- 원래는 길이가 100이면 100번 계산하지만, 이것은 self-attention 한 번으로 parallelization을 통해, Q, K, V를 통해 한 번에 계산이 가능합니다.Q, K, V를 Matrix로 바꿨기 때문에 한 번에 계산이 가능합니다. 이렇게 효과적인 computation이 이루어집니다.
Multi-head Attention
multi-head의 개수만큼 쪼개어 attention을 계산하는 것입니다.
Input sequence로 들어온 차원만큼을 그대로 사용하지 않고 쪼개어 사용하는 것입니다.
multi-head의 개수만큼 쪼개어 나온 것들을 합칩니다.
이것을 왜 할까요?
장점 :
- 예를 들어 큰 차원을 한 번에 하던 것을, 나누어서 하면, 여러 관점에서 이 sequence를 바라볼 수 있다.
- 다른 관점으로 self-attention이 가능해진다.
- 관점에 따라 attention score가 달라진다.
- 연산은 똑같이 하되 더 다양한 관점으로 바라보기 위함.
식은 위와 같으며,
이를테면 input sequence 256차원에 multi-head개수를 4라고 하면, 이 256차원을 64차원짜리로 바꿔야하는 weighted matrix가 W입니다.
이 W를 곱해서 차원을 줄이는 것입니다.
256차원을 64차원으로 바꾼다음에 계산해라 입니다.
원래 한 번에 하던 것을 multi-head의 개수만큼 줄이라는 것입니다.
원래 Attention score가 하나 밖에 안 나오던 것에서, multi-head attention을 통해 여러 가지 관점을 통해 보는 것입니다.
그래서 아래와 같이 multi-head에 따라 attention score가 바뀔 수 있다는 것입니다.
아래 그림과 같이 256차원짜리를 multi-head 4개로 설정하여 64차원으로 나누어 결과를 4번 내어 그것들을 붙여놓게 됩니다.
Q 256차원 짜리를 64차원으로 줄인 다음에, 그것들에 대한 self attention을 계산하고, Z_1 ~ Z_4로 계산하고, 그것들을 붙인 것입니다.
사실 잘랐다기 보단 256 차원의 vector를 W를 곱하여 64차원으로 4개의 weighted matrix가 있게 됩니다.
이 64차원 짜리는 multi-head 종류별로 나오는 것입니다.
그것들을 가지고 attention을 하겠다는 것입니다.
그래서 multi-head 개수만큼 weight 값이 존재합니다.
이 W는 학습하는 Parameter입니다.
FeedForward
이렇게 Multi-head에 따라 하나의 단어에 대한 multi-head attention을 구했습니다.
이것들은 multi-head attention만 하여 붙이기만 하였으므로 서로가 관련되어 있지 않습니다.
그래서 한 번의 LInear transform이 필요합니다.
그것을 위해서 Fully connected layer를 하나 추가했다고 보시면 됩니다.
이것은 linear transform한 뒤 ReLU의 과정을 가지는데, 이것을 Feed Forward한다고 합니다.
Positional Encoding
만약, 다음과 같은 문장이 있다고 해봅시다.
The animal didn't cross the street because it was too tired
그럼 위 The가 2개 있죠.
여기서 위 the는 각각 다른 Embedding을 가질까요?
아닙니다.
둘은 같은 Embedding을 가지죠.
sequence가 없습니다. 그냥 단어 기준 다른 단어들을 계산할 때 다른 단어들을 계산한 것 뿐이지, 이 단어가 첫 번째 the, 여섯 번째 the임은 알 수 없습니다.
그런데, Self-attention만으로는 이 sentence의 sequence 정보를 담을 수 없습니다.
그래서 Positional Encoding을 통해서 각 단어의 위치 Encoding을 줍니다.
그런데 위 positional encoding 이전에 Input embedding이 존재합니다.
이 input embedding은 단어에 대한 One-hot vector를 특정 vector 값으로 바꿔주는 것입니다.
vocablouary가 256 차원 있을 때,
RNN에서는 순차적으로 첫 번째에 대한 embedding을 가져오게 됩니다.
그렇게 해당 단어에 대한 embedding을 배우게 됩니다.
그것이 input embedding이죠.
그래서 위 그림과 같이 thinking이라는 embedding을 가져오는 것이죠.
그렇다면, 같은 단어에 대해서는 같은 Embedding을 갖는데 transformer에서는 이것을 어떻게 구분할까요?
sequence 정보 없이는 Attention은 똑같은 embedding이 들어갑니다.
그래서 우리는 맨처음에 sequence 정보를 부여하고 시작하는 것입니다.
그 방법은 positional encoding입니다.
그래서 각 단어의 위치가 어디에 있는지를 알려주고 시작하는 것이죠.
이것은 구조 상 보통 맨 아래에 있습니다.
아래 그림과 같이 Positional Embedding을 Word Emedding에 더하고 시작하자는 것이죠.
그렇다면 위치 정보를 어떻게 넣어줄까요?
위 숫자적인 문자적을 고려하면 위 수식에 의해서 위치정보를 계산하는 아이디어를 사용합니다.
그래서 input embedding에다가 positional embedding을 더한다고 했으니,
positional embedding 값을 어떤 위치를 대표하는 encoding 값을 넣어주면 되겠습니다.
위와 같이 sin, cos 값으로 홀수, 짝수 번째에 대해서 다른 값을 넣어줍니다.
위 값이 어디 위치에 따라 값이 정해진다는 것을 알고 있으면 되겠습니다.
그래서 다들 특정한 값을 가진다고 보면 됩니다.
d는 우리가 사용하고자하는 차원수, k는 위치입니다.
이것을 그림 그리면 아래와 같습니다.
그래서 unique한 vector 값을 주기 위해서 Sin, Cos 함수로 이루어진 것을 사용하여 절대 겹치지 않도록 합니다.
정리하자면, sequence에 대해서,
word embedding과 positional encoding을 더한 값을 가지고 시작합니다.
이것을 가지고 첫 번째 multi-head attention이 실행되고 self-attention하며 feed forward합니다.
이것이 Encoder 한 번 통과한 것입니다.
이렇게 N번 통과합니다.
그리고 ResNet을 통해 이전의 정보를 까먹지 않도록 합니다.
그리고 학습 정보를 읽지 않고 학습속도도 빠릅니다.
아래와 같이 Residual connection 추가하고, layer norm. 까지 추가합니다.
이렇게 transformer구조가 생겼습니다.
그래서 Encoder N개를 최종적으로 통과한 vector 값을 사용합니다.
Transformer encoder의 head 개수는 많다고 좋은 것은 아니고, 일반적으로 8개 정도 사용합니다.
word embedding은 단어의 개수나 데이터의 길이에 따라 결정됩니다. 그래서 256, 512, 1024 등등 사용할 수 있습니다.
그래서 이렇게 Transformer encoder를 통해서 layer를 N번 통과한 각각의 word embedding을 보았습니다.
Decoder
decoder도 똑같이 attention을 사용합니다.
decoder는 첫 번째 단어에 대해서 output을 생성하는 것이 RNN의 inference와 일치합니다.
그렇다면, Decoder는 첫 단어가 들어가서 이것이 Query가 됩니다.
만약, "나는 학교에 간다"에 대해서 봅시다.
output이 'i'가 들어갔다고 합시다.
그럼, i와 나는 학교에 간다와 self-attention을 통해 Q, K, V가 정해져 구해지는 것입니다.
Decoder는 attention이 두 번 이루어집니다.
먼저, self-attention을 통해 decoder 내부 끼리 계산하고, Encoder-Decoder self-attention을 통해 encoder와의 관련성도 파악합니다.
금방 말씀드린 것은 Encoder-Decoder와의 self-attention이고, 그 이전에 decoder에서 자기들끼리 self-attention을 미리 합니다.
이렇게 2번이 이루어집니다.
나머지는 같습니다.
feed forward와 등등.
그리고 최종적으로 나온 vector 값에 대해 linear, softmax를 통해 단어가 무엇인지 예측하는 것입니다.
encoder-decoder self-attention에서 보면,
key-value는 위와 같이 encoder에서 오고, Query는 decoder에서 오는 값입니다.
그래서 transformer가 성능이 엄청나게 좋아졌습니다.
아래와 같이 수치로 볼 수도 있습니다.
'Artificial Intelligence > Natural Language Processing' 카테고리의 다른 글
[NLP] Attention (0) | 2023.04.12 |
---|---|
[NLP] Sequential Data Modeling (0) | 2023.04.10 |
[NLP] RNN - LSTM, GRU (0) | 2023.04.04 |
[NLP] RNN (0) | 2023.04.04 |
[NLP] Word Embedding - GloVe [practice] (0) | 2023.03.31 |