해당 글은 아래의 참고문헌을 각색한 글입니다. 그림들의 저작권은 해당 저작자들에게 있습니다.
1. Input embedding
💡 input embedding 이라 함은, 입력된 문장을 컴퓨터가 이해할 수 있는 행렬 값으로 변환하는 작업을 말한다.
“This is my car”라는 문장이 있다. 이 문장에 대해서 string 형태로 넣는다면 모델은 해당 단어가 어떤 단어인지 모른다. 따라서 우리는 “단어” → “숫자”를 해줄 수 있는 embedding matrix를 만들어야한다. 그래서 “This is my car”라는 문장을 embedding matrix와의 연산을 통해 [3412, 5281, 6899, 8678]이라는 embedding vector가 만들어졌다.
여기서는 문장의 길이가 4개라서 4차원 벡터로 되어있지만, 문장의 길이가 길수록 벡터 차원은 증가하게 되어있다. Transformer 논문에서는 input 차원이 512 차원이다. 각각의 벡터 차원은 단어의 feature 값을 가지고 있으며, 서로 다른 단어의 feature 값들이 유사할 수록 embedding vector들의 거리는 가까울 것이다.
Embedding vector
embedding vector는 Word2Vec에서 많이 언급된 개념 중 하나다. “This is my car”라는 문장에서 “This”와 “Zombie” 단어는 해당 문장에서 서로 관련이 없다. 그렇다면 feature 값의 차이는 클 것이고, embedding 공간 상에서 거리가 멀 것이다.
반대로 “This”와 “car” 단어는 문장에서 의미가 아주 유사하기 때문에 서로의 embedding vector들의 feature 값들은 서로 유사할 것이다. 그 의미는 embedding 공간 상에서 거리가 아주 가까울 것이다 라는 것과 같은 맥락이다.
정리하자면, Input embedding을 하는 부분은 문장을 컴퓨터가 이해할 수 있는 숫자로 변환해주는 작업이다. training 하기 전에는 해당 lookup table이 임의의 숫자로 되어있을 것이다. 해당 lookup table은 backward를 거치면서 최적화될 것이다.
(혹시 ChatGPT처럼 LLM들이 model size이 커짐에 따라 성능이 점점 좋아진다고 알고 있는데, 그만큼 lookup table의 차원이 크면 클수록 많은 단어들을 표현할 수 있어서 그런가 싶음)
여기까지는 기존의 embedding vector로 만드는 방식과 다를 것이 없다. 과연 저자는 왜 기존의 LSTM, GRU, SeqToSeq가 있는데 굳이 Transformer를 만들었을까?
2. Transformer 특징: Parallel?
정답은 기존 모델의 단점, 정보의 유실과 오래 걸리는 연산 속도에 있다.
기존의 RNN, LSTM, GRU 등의 모델들은 데이터를 모델이 읽어들일 때, window size가 정해져 있다. 이런 모델들의 경우에는 계속되는 단편적인 feature의 업데이트 때문에 제일 앞에 있던 feature의 정보가 유실될 가능성이 높다. 즉 weight에 미리 학습했던 정보가 유실될 수 있다는 것이다. 또한, 데이터를 window size를 정해 놓고 training을 하기 때문에 하나의 문장이 엄청나게 길다면, training 속도는 exponential로 증가하게 될 것이다.
Tranformer는 이에 비해, 하나의 문장을 한 번에 읽어 학습하여 training 속도를 현저하게 줄일 수 있었다. 즉 병렬 학습이 가능하다는 것이다. 이렇게 병렬 학습을 통해 오래 걸리는 연산 속도 문제를 해결하였다.
또한, 기존의 모델들은 문장을 한 번에 넣어도 window size에 따라서 순차적으로 학습하기 때문에 순서가 어느 정도 반영된다. 하지만, Transformer는 문장을 한 번에 학습하기 때문에 순서를 반영할 수 없다. 기존의 embedding vector들은 만약 단어가 같다면 같은 vector를 가지기 때문이다.
과연 어떻게 해결해야할까?
Positional Encoding
저자는 기존의 embedding vector에 Positional Encoding이라는 방법을 추가하여 해결하였다.
3.1 단어의 위치 정보가 중요한 이유
위의 단어는 같은 의미를 가지는 “not”이지만, 문장의 안에서의 순서는 서로 다르다. 따라서 문맥적인 의미는 같은 “not”이라도 서로 다른 의미로 해석되어야한다. 하지만, 기존의 embedding 방식으로는 같은 단어는 같은 vector를 가질 것이다.
위의 그림에서 빨간색 vector는 embedding vector를 의미한다. 초록색 vector는 positional encoding을 통해 얻은 위치 정보를 의미한다. 이 위치 정보들의 값은 2가지의 조건을 만족해야한다.
1. 모든 위치 값은 sequence의 길이나 input에 상관없이 동일한 feature를 무조건 가져야한다. 첫 번째 위치 정보에 대한 값이 sequence 길이나 input에 따라 달라진다면, model은 매번 positional encoding 할 때마다 첫 번째 위치 정보에 대한 값이 바뀔 것이다.
2. 각 위치들의 index에서 나온 feature들의 값은 너무 크면 안된다. 위치 값이 너무 커져버리면 단어들의 상관관계 및 의미를 유추할 수 있는 정보들의 값이 상대적으로 작아질 수 밖에 없다. (node의 값이 엄청 크면, weight의 값은 상대적으로 엄청 작아질 것이다) 또한, attention layer에서 제대로 학습이 되지 않을 수 있다.
3-2. 위치 벡터를 얻는 2가지 방법
1) 시퀀스 길이에 비례해서 부여하는 방법
위치 벡터를 sequence의 길이에 따라서 부여하는 방법이다. 첫 번째 단어에는 1, 두 번째 단어에는 2 이런식으로 부여하는 것이다. 이 방법의 경우는 나중에 단어 embedding vector와 더했을 경우 단어의 순서가 뒤로 갈수록 위치 정보의 의미가 너무 커지게 되어있다. (나는 뒤로 갈수록 뒤에 있는 단어의 의미가 너무 커질 것으로 생각함. 위치 정보의 의미가 커진다기 보다는… 잘 못 생각했음) 또한, 위치 벡터가 특정 범위를 가지지 않아, 모델의 일반화 역시 어려워진다.
2) 첫번째는 0, 마지막은 1, 가운데 값은 normalization을 통해 숫자 부여
해당 방법의 경우에는 문장의 길이가 달라진다면, 같은 위치에 대한 정보 값들이 매번 달라지게 된다.
따라서 위치 정보들의 값은 너무 커서도 작아서도 안되며, 같은 위치에 대한 위치정보는 항상 같은 위치정보를 지녀야한다.
3-3. Positional Encoding
그래서 저자는 Positional Encoding이라는 방법을 사용하였고, 해당 방법은 sin함수와 cos함수를 번갈아가며 사용하는 것이다.
그럼 위의 기준을 만족할까?
- 위치 정보들의 값은 너무 커서도 작아서도 안된다.
→ sin, cos 함수는 -1부터 1 사이의 값을 매번 가진다. 따라서 NN model에서 학습하기에 값이 적절하게 배치 가능하다.
→ 사실 어떤 구간의 값을 가지는 함수는 sin, cos 함수 말고도 sigmoid 함수가 있다. 왜 sigmoid 함수는 쓰지 않았을까?
sigmoid는 0 근방에 있는 값들은 서로 gap이 어느 정도 있지만, 양 끝 단에는 0과 1에 수렴하기 때문에, 위치 정보가 서로 차이가 나야 하는 조건을 만족하지 못한다. 만약 긴 문장이 주어진다면, 위치 정보들의 값은 크게 차이가 없을 것이다. 그래서 패스!!! - 같은 위치에 대한 위치 정보는 항상 같은 위치 정보를 가져야 한다.
3. → 같은 위치에 대한 위치 정보는 항상 같아야 하지만, 위치가 다를 경우 위치 정보는 항상 달라야한다. 여기서 문제가 발생한다. 바로 sin, cos 함수는 주기 함수라는 것이다. 주기 함수이기 때문에 위에처럼 숫자가 반복될 수 밖에 없다.
하지만, 우리는 잊으면 안된다. positional encoding을 통해 나온 값은 스칼라 값이 아니라 vector의 값이라는 것이다. 따라서 각 차원마다 다양한 주기를 가진 sin, cos 함수를 섞어서 사용하는 것이다. (물론, 문장의 길이가 엄청나게 긴 경우, 모든 주기의 공배수를 했을 때는 위치 정보가 겹치긴 할 것이다. 근데… embedding table이 10,000개의 단어를 다룬다면 10,000!x2 갯수만큼 문장 길이가 들어가야하는데 이는 좀 어렵지 않을까??)
이 부분의 그림에서 i가 커질수록 원래 주기가 더 길어져야하는데, 만드신 분이 좀 헷갈리셨나 봄. 반대로 주기가 길어져야한다.
sin, cos함수를 홀수, 짝수 번째에 넣는 이유: sin함수에서 첫 번째와 두 번째 위치 정보를 추출한다면, 둘의 위치 정보 값은 차이가 미미할 것이다. 따라서 홀수 번째에서 sin함수, 짝수 번째에서 cos함수를 도입해서 위치 정보가 겹치지 않도록 하였다.
그래서 위에 식처럼 Sin, Cos 함수를 홀수, 짝수번째에 기입한다.
4. Embedding vector & Positional Encoding 간 연산
Concatenation vs Summation: 왜 저자는 과연 Concatenation을 하지않고, Summation을 진행했을까?
왜 저자는 과연 concatenation을 하지않고, summation을 진행했을까? 원래라면 concatenation을 하는게 맞을텐데…
concatenation을 하게 된다면, 단어 embedding vector 바로 옆에 단어의 위치 정보 vector, positional embedding vector가 위치하게 될 것이다. 이 경우, 단어의 의미 정보는 자체 차원 공간을 가지게 되고, 위치 정보 역시 자체 공간을 가지게 된다. 따라서 직교성질에 의해 둘은 서로 관계없는 공간에 있는 것이다. concatenation의 이점은, 정보가 뒤섞이는 혼란을 막아주지만, memory, parameter, runtime 등 비용 문제가 발생한다.
summation을 하게 된다면, 단어의 의미 정보 + 단어의 위치 정보를 적절하게 하나의 벡터 안에 담을 수 있다. 하지만 summation을 하게 되면, 정보가 뒤섞이는 문제가 발생할 수 있다. 따라서 GPU 문제만 아니라면, concatenation을 추천한다고 한다.
Reference
기본 설명 잘 되어있음
[Transformer]-1 Positional Encoding은 왜 그렇게 생겼을까? 이유
트랜스포머(Transformer) 파헤치기—1. Positional Encoding
참고문헌
Understanding Positional Encoding in Transformers - Blog by Kemal Erdem
'AI' 카테고리의 다른 글
Pytorch + RTX3080 (1) | 2021.03.08 |
---|---|
RTX 3080 병렬로 tensorflow 위에 올려보기 (0) | 2020.12.23 |
DQN (Deep Q-Networks) (0) | 2020.10.03 |
Off-Policy Control (0) | 2020.09.24 |
RL : RL 용어정리 (0) | 2020.09.08 |
댓글