티스토리 뷰
자연어처리_TRANSFORMER
HAN_PY 2020. 10. 22. 02:510. 들어가면서
'Attention is All You Need'라는 말에서 알 수 있 듯, Transformer은 Attention으로만 이루어져 있다. 기계 번역(언어 번역)을 예로 깊숙한 곳으로 조금씩 들어가 보려고 한다.
1. Model
위의 그림을 보면 한 언어의 문장이 INPUT으로 넣으면 OUTPUT으로 다른 번역된 언어가 나오는 것을 알 수 있다. 그렇다면 조금 더 디테일 하게 들어가 보자.
Transformer의 내부를 보면 ENCODERS와 DECODERS로 나눠져 있고, 그 둘 사이에 연결이 있는 것을 알 수 있다.
encoding component는 encoders가 쌓여서 만들어져 있다. 그리고 decoder도 6개가 쌓여있는 것을 볼 수 있다. 인코더의 구조가 모두 동일하지만 가중치를 공유하지는 않는다. 아래의 그림을 보면 인코더는 두 개의 하위 레이어로 나뉜다는 것을 알 수 있다.
인코더의 input값은 먼저 self-attention layer를 통과한다. 그 layer는 특정 단어를 인코드 하면서 들어온 문장 중 다른 단어를 인코더가 볼 수 있도록 돕는다.
self-attention later의 output은 feed-forward neural network로 향한다. 각각의 feed-forward network는 각각의 위치에서 독립적으로 적용된다. DECODER에도 이러한 self-Attention과 Feed Forward를 가진다. 그리고 그 두개의 layer 사이에 input 문장의 관련된 부분에 집중할 수 있도록 도움을 주는 attention layer가 하나더 있는 것을 사진에서 확일 할 수 있다.
2. tensor, vector의 이해
NLP의 시작은 embedding 알고리즘을 사용하여 각 입력 단어를 vector로 변환하는 것으로 시작한다. 임베딩은 가장 아래의 encoder에서만 일어나고 각 단어의 크기는 512의 벡터가 된다. 그리고 우리는 이러한 벡터는 아래의 녹색 박스처럼 나하낼 것이다. 그리고 모든 encoder는 크기가 512인 벡터들의 리스트를 입력 값으로 받는다. 한 문장이 하나의 리스트 라고 생각한다면, 우리의 학습 데이터 셋에서 가장 긴 리스트는 가장 긴 문장일 것이다.
입력 문장의 단어들을 임베딩하면 위의 녹색 박스처럼 벡토로 바뀌고, 이러한 벡터는 리스트에 모여서 encoder 내의 두개의 sub-layer로 들어가게 된다. 이때 Self-attention layer에서는각각의 층이 path를 보면 의존성이 있지만, feed-forward 층은 의존성이 없어서 path를 병렬로 할 수 있다. 아래의 그림을 참고하여 ENCODER를 좀더 세부적으로 보자.
위 그림은 보이는 것과 같이 아래서 부터 layer을 하나씩 지나간다는 것을 알 수 있다.
3. Self-Attention
"The animal didn't cross the street because it was too tired"
라는 문장이 있을 때, it이 가리키는 것이 무엇일까? self-attention에서는 it과 animal을 연결 할 수 있다. self-attention은 입력 문장 내의 각 단어를 처리해 나가면서 문장 내의 다른 위치에 있는 단어들을 참고하여 힌트를 받아 현재 타겟 위치를 encoding 한다.
위의 그림에서 알 수 있듯 가장 위에 있는 encoder #5에서 'it'이라는 단어를 encoding 할 때, attention 메커니즘은 입력의 여러 단어들 중에서 "The animal"이라는 단어에 집중하고 이 단어의 의미 중 일부를 "it"이라는 단어를 encoding 할 때 이용하는 것을 볼 수 있다. 그렇다면 이러한 Self-Attention이 어떻게 계산이 되는지 처음부터 알아보자.
self-attention 계산의 가장 첫 단계는 encoder에 입력된 벡터들(embedding 벡터)에서부터 각 3개의 벡터를 만들어 내는 것이다. 3개의 벡터의 종류는 Query벡터, Key 벡터, 그리고 Value 벡터를 생성한다. 그리고 이 벡터들은 입력된 벡터에 대해 세 개의 학습 가능한 행렬들을 각각 곱합으로 만들어 진다.
여기서의 포인트는 새로운 벡터들이 기존의 벡터들 보다 더 작은 사이즈를 가진다는 것입니다. 기존의 입력 벡터들은 크기가 512인 반면 새롭게 생긴 벡터들은 크기가 64이다. 이러한 이유는 multi-head attention의 계산 복잡도를 일정하게 하기 위함이다. query, key, value 벡터에 대한 설명은 뒤에서 자연스럽게 알게 된다.
두 번째 단계는 score를 계산하는 것이다. 아래의 그림을 보면 "Thinking"에 대한 self-attention을 계산하고 있는 것이다.
각 단어들에 대한 score를 계산해야한다. 이 점수는 현재 위치의 단어를 encode 할 때 다른 단어들에 대해서 얼마나 집중을 해야 할지를 결정한다. score의 계산은 현재 단어의 query vector와 다른 위치에 있는 단어의 key vector의 내적으로 계산 된다. 위의 그림에서 볼 수 있듯이 q1과 k1을 계산하고 q1과 k2를 계산한다.
세 번째와 네 번째 단계에서는 112와 96을 8로 나눠준다. 8이라는 숫자는 key 벡터의 size인 64의 제곱근 값으라고 생각하면 된다. 그 다음 이 값을 softmax 게산을 통하여 모든 점수들을 양수로 만들고 각각의 값의 합을 1로 만들어 준다. Softmax 값인 0.88과 0.12값은 단어의 encoding 시 각 단어들이 얼마나 특정 위치에 들어갈 것인지를 결정시켜 준다. 현재 위치인 단어는 당연하게 가장 높은 점수를 가질 것이며 관련 없는 단어는 낮은 값을 가질 것이다. 즉, 현재 위치에 관련된 단어에 대한 정보도 알 수 있다.
다섯 번째 단계에서는 단어의 value 벡터의 softmax 값을 곱해주는 것이다. 이러한 것을 하는 가장 큰 이유는 중요한 단어는 남겨두고 관련이 없는 단어는 0.001과 같은 적은 숫자를 곱하여 없애버리기 때문이다.
마지막인 여섯 번째 단계에서는 앞에서 곺해진 weighted value 벡터들을 다 합해준다. 그리고 이 단계에서 self-attention layer가 출력이 된다. 이렇게 여섯 가지 과정이 바로 self-attention의 과정이며 이 결과로 나온 벡터를 feed-forward 신경망으로 보낸다. 그러나 실제 구현에서는 빠른 속도를 위해 위의 모든 과정을 벡터가 아닌 행렬로 진행한다. 지금까지는 게산과 이유에 대해 살펴 봤으니 이제는 행렬 레벨의 계산을 보자.
4. Self-attention 행렬 계산
가장 먼저 해야할 일은 입력 문장에 대하여 Query, Key, Value 행렬들로 계산하는 것이다. 계산을 위해서는 먼저 입력 벡터(embedding 백터)를 하나의 행렬 X로 쌓고 그것을 학습할 weight 행렬 들은 WQ, WK, WV로 곱한다. 이 때 행렬 X의 각 행은 입력 문장의 각 단어이다. 각각의 행의 크기는 512이지만, 그림에서는 4개로 나타냈 점을 인지하자. 그리고 query/key/value 벡터들도 크기가 64이지만 그림에서는 3으로 나타냈다.
마지막으로, 행렬을 이용하고 있으므로 앞서 설명했던 self-attention 계산 단계에서 2단계 부터 6 단계를 위의 그림으로 하나의 식으로 압축할 수 있음을 알 수 있다.
5. 여러 Heads를 활용한 layer 개선
multi-headed attention 이라는 메커니즘을 이용한 두 가지 방법으로 attention layer의 성능을 향상시킬수 있다.
위에서 제시한 "The animal didn't cross the street because it was too tired" 라는 예를 참고해서 보자.
첫 번째 방법.
다른 위치에 집중하는 능력을 확장시킨 모델을 만든다. 위에서 말한 내용에서는 encoding 시 특정 단어 하나가 모든 다른 단어들에 조금씩 포함 됐다. 그러나 이러한 것 보다 처음부터 실제 자기 자신에게만 높은 점수를 줘도 포함 됐을 것이다. 이러한 방법은 위의 예시에서 'it'이 무엇을 가리키는지를 알아 낼 때 유용하다.
두 번째 방법
attention layer가 여러 개의 'representation 공간'을 가지게 해준다. 우리는 multi-headed attention을 이용하기 때문에 여러개의 query/key/value weight 행렬을 가진다. 만약 8개의 attention heads를 가지면, encoder/decoder 각각 마다 이런 8개의 세트를 가지게 되는 것이다. 그리고 query/key/value set은 랜덤으로 초기화 되어 있으며, 학습 이후에는 각각의 set은 입력 벡터들에 곱해져 목적에 맞게 투영된다. 즉, set가 여러게 있다는 것은 set의 각각의 벡터들은 다른 representation 공간으로 나타낸다는 것을 의미한다.
multi-headed attention을 이용하기 위해서 우리는 각 head를 위해서 각각의 다른 query/key/value weight 행렬들을 모델에 가지게 된다. 이전에 설명한 것과 같이 우리는 입력 벡터들의 모음인 행렬 X를 WQ/WK/WV 행렬들로 곱해 각 head에 대한 Q/K/V 행렬들을 생성한다.
위에 설명했던 대로 같은 self-attention 계산 과정을 8개의 다른 weight 행렬들에 대해 8번 거치게 되면, 우리는 8개의 서로 다른 Z 행렬을 가지게 된다. 그러나 문제는 이 8개의 행렬을 바로 feed-forward layer으로 보낼 수 없다. 왜냐하면 feed-forward layer 은 한 위치에 대해 오직 한 개의 행렬만을 input으로 받을 수 있기 때문에 우리는 이 8개의 행렬을 하나의 행렬로 합치는 방법을 알아야한다. 아래의 그림을 보자.
위와 같이 모두 이어 붙여버려서 하나의 행렬로 만들어 버리고, 그 다음 하나의 또 다른 weight 행렬인 W0를 곱해 버린다. 여기까지가 multi-headed self-attention이다. 지금까지의 과정을 한눈에 정리하면 다음과 같다.
정리
6. multi-heat attention를 포함한 흐름
attention heads에 대해 알아봤다. 이제 예제 문정에 multi-head attention과 함께 적용해 보자.
"The animal didn't cross the street because it was too tired"
위 그림을 보고 'it'이라는 단어를 encode 할 때 여러 개의 attention 이 각각 어디에 집중하는지를 알아보자. 우리가 'it'이란 단어를 encode 할 때, 주황색인 attention head는 'The'와 'animal'에 가장 집중하고 있는 반면, 녹색인 head는 "tire"이라는 단어에 집중하고 있는 것을 알 수 있다. 모델은 이 두 개의 attention head를 이용하여 “동물”과 “피곤” 두 단어 모두에 대한 representation 을 “it” 단어에 대한 모델의 representation에 포함시킬 수 있다. 그러나 이 모든 attention head 들을 하나의 그림으로 표현하면, 아래의 그림에서 보듯이 it의 의미를 해석하기 어려워진다.
그래서 추가해야 할 부분이 바로 임력 문장에서 단어들의 순서에 대해 고려하는 부분이다.
7. Positional Encoding
Positional Encoding을 사용하여 단어들의 순서를 고려하도록 하자. Transformer 모델은 각각의 입력 embedding에 'positional encoding' 이라고 불리는 하나의 벡터를 추가한다. 이 벡터들은 모델이 학습하는 특정한 태턴을 따르고, 이러한 패턴은 모델이 각 단어의 위치와 시퀀스 내의 다른 단어 간의 위치 차이에 대한 정보를 알게 해준다.
위의 사진과 같이 embeddings에 posigional encoding을 추가하면, 추후 query/key/value 벡터들에도 위치에 대한 정보가 들어간다. 만약 embedding의 사이즈가 4라고 가정한다면, 실제로 각 위치에 따른 positional encoding 은 아래와 같다. 즉, 아래의 그림은 크기가 4인 embedding의 positional encoding에 대한 실제 예이다.
그렇다면 단어에 대한 패턴이 어떻게 나타나는지 아래의 그림을 보자.
그림에서 각 행은 하나의 벡터(하나의 단어)에 대한 positional encoding에 해당한다. 각 행은 사이즈 512인 즉 512개의 셀을 가진 벡터이며 각 셀의 값은 1과 -1 사이를 가진다. 위 그림에서는 이 셀들의 값들에 대해 색깔을 다르게 나타내어 positional encoding 벡터들이 가지는 패턴을 볼 수 있도록 시각화한 것이다.
위 그림에서 볼 수 있듯이 이 벡터들은 중간 부분이 반으로 나눠져있다. 그 이유는 바로 왼쪽 반은 (크기 256) sine 함수에 의해서 생성되었고, 나머지 오른쪽 반은 또 다른 함수인 cosine 함수에 의해 생성되었기 때문입니다. 그 후 이 두 값들은 연결되어 하나의 positional encoding 벡터를 이루고 있습니다. 그리고 이러한 방식은 이미 학습된 모델이 자신의 학습 데이터보다도 더 긴 문장에 대해서 번역을 해야 할 때에도 현재의 sine 과 cosine으로 이루어진 식은 positional encoding을 생성해낼 수 있다.
8. The Residuals
용어 설명 - 오차(error)와 잔차(residual)의 차이를 이해하자. 만약 모집단에서 회귀식을 얻었다면, 그 회귀식을 통해 얻은 예측값과 실제 관측값의 차이가 오차이다. 반면 표본집단에서 회귀식을 얻었다면, 그 회귀식을 통해 얻은 예측값과 실제 관측값의 차이가 잔차이다. 둘의 차이는 모집단에서 얻은 것이냐 표본집단에서 얻은 것이냐 뿐이다. 나도 그렇지만, 많은 사람들이 오차와 잔차를 구분없이 혼동해서 사용한다.
위 그림을 참고해 보면 각 encoder 내의 sub-layer 가 residual connection으로 연결되어 있으며, 그 후에는 layer-normalization 과정을 거친다. layer-normalization 과정을 시각화해 보면 아래와 같다.
decoder 내에 있는 sub-layer 들에도 똑같이 적용되어 있습니다. 만약 우리가 2개의 encoder과 decoder으로 이루어진 단순한 형태의 Transformer를 생각해본다면 다음과 같은 모양이다.
9. The Decoder Side
지금까지 encoder를 알아봤으니 Decoder를 알아보자. encoder가 먼저 입력 시퀀스를 처리하기 시작합니다. 그다음 가장 윗단의 encoder의 출력은 attention 벡터들인 K와 V로 변형된다다. 이 벡터들은 이제 각 decoder의 “encoder-decoder attention” layer에서 decoder 가 입력 시퀀스에서 적절한 장소에 집중할 수 있도록 도와준다.
이 encoding 단계가 끝나면 이제 decoding 단계가 시작된다. decoding 단계의 각 스텝은 출력 시퀀스의 한 element를 출력합니다 (현재 기계 번역의 경우에는 영어 번역 단어입니다).
디코딩 스텝은 decoder가 출력을 완료했다는 special 기호인 <end of sentence>를 출력할 때까지 반복됩니다. 각 스텝마다의 출력된 단어는 다음 스텝의 가장 밑단의 decoder에 들어가고 encoder와 마찬가지로 여러 개의 decoder를 거쳐 올라갑니다. encoder의 입력에 했던 것과 동일하게 embed를 한 후 positional encoding을 추가하여 decoder에게 각 단어의 위치 정보를 더해줍니다.
decoder 내에 있는 self-attention layer들은 encoder와는 조금 다르게 작동한다.
Decoder에서의 self-attention layer은 output sequence 내에서 현재 위치의 이전 위치들에 대해서만 attend 할 수 있다. 이것은 self-attention 계산 과정에서 softmax를 취하기 전에 현재 스텝 이후의 위치들에 대해서 masking을 해줌으로써 가능해진다.
“Encoder-Decoder Attention” layer 은 multi-head self-attention 과 한 가지를 제외하고는 똑같은 방법으로 작동하는데요, 그 한가지 차이점은 Query 행렬들을 그 밑의 layer에서 가져오고 Key 와 Value 행렬들을 encoder의 출력에서 가져온다는 점이다.
10. Linear Layer와 Softmax Layer
decoder에서 나온 값들을 보면 하나의 벡터만 나온다. 이렇게 하나만 나올 수 있게 해주는 것이 Linear layer와 Softmax layer가 하는 일이다. Linear layer은 fully-connected 신경망으로 decoder가 마지막으로 출력한 벡터를 그보다 훨씬 더 큰 사이즈의 벡터인 logits 벡터로 투영한다.
우리의 모델이 training 데이터에서 총 10,000개의 영어 단어를 학습하였다고 가정하자 (이를 우리는 모델의 “output vocabulary”라고 부른다). 그렇다면 이 경우에 logits vector의 크기는 10,000이 될 것이다 – 벡터의 각 셀은 그에 대응하는 각 단어에 대한 점수가 된다. 이렇게 되면 우리는 Linear layer의 결과로서 나오는 출력에 대해서 해석을 할 수 있게 된다.
그다음에 나오는 softmax layer는 이 점수들을 확률로 변환해주는 역할을 한다. 셀들의 변환된 확률 값들은 모두 양수 값을 가지며 다 더하게 되면 1이 됩니다. 가장 높은 확률 값을 가지는 셀에 해당하는 단어가 해당 스텝의 최종 결과물로서 출력되게 됩니다.
위의 그림에 나타나 있는 것과 같이 decoder에서 나온 출력은 Linear layer 와 softmax layer를 통과하여 최종 출력 단어로 변환된다.
+참고문헌
jalammar.github.io/illustrated-transformer/
'인공지능(Artificial Intelligence) > 자연어 처리(natural language processing)' 카테고리의 다른 글
[tensorflow] 자연어처리(NLP) 1. 기초다지기(layers) (0) | 2020.10.31 |
---|---|
[BERT] 버트 활용하기 기초 (1) | 2020.10.30 |
[자연어 처리] 텍스트 데이터(text data)_1 (0) | 2020.10.28 |
WordPiece Model(WPM)_tokenizing (0) | 2020.10.19 |
자연어처리_BERT 기초개념(완전 초보용) (0) | 2020.10.16 |
- Total
- Today
- Yesterday
- django
- pandas
- NextJS
- 자연어처리
- Express
- Deque
- error:0308010C:digital envelope routines::unsupported
- DFS
- Python
- useState
- JavaScript
- react
- useHistory 안됨
- BFS
- login
- TensorFlow
- UserCreationForm
- Queue
- Vue
- 자료구조
- vuejs
- read_csv
- mongoDB
- react autoFocus
- 클라우데라
- next.config.js
- typescript
- logout
- nextjs autoFocus
- nodejs
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |