본문 바로가기
Ai/Notion

Transformer 에서 cos, sin 함수를 사용한 이유(position encoding)

by yooom 2023. 10. 17.

 

 

Transformer를 공부하면서 무시무시한 수식이 나오는데,

이 함수가 왜 사용되는지, 어떻게 유도되었는지, 무슨 의미인지 살펴보도록 하자.

오늘 포스팅은 순차적으로 진행되는 것이 아니라 내용이 왔다갔다 할 것이라, 흐름 잘 잡아야할 것 같다.

오늘의 최종 목표로 position embedding을 완벽히 뜯어보자.

 

 

오늘 다룰 부분은 Positional Encoding을 하는 영역이다.

 

First step

이를 이해하기 위해서는 embedding과 position embedding을 알고있어야한다.

말 그대로 embedding은 문자에 ID를 부여하는 것. position embedding은 문자의 위치를 부여하는 것이다.

 

Encoder input은 embedding과 position embedding의 합으로 나타내는데,

embedding은 단어마다 고유의 ID를 부여하는 과정이라서 있는 그대로 받아드리면 된다.

하지만 position embedding에는 몇 가지 신경써야하는 점이 있다.

 

RNN 구조를 살짝만 보고 오자.

RNN은 정보가 입력되고 처리된 것을 뒷부분으로 전달하면서 최종 output에서 앞부분의 정보가 손실된다는 단점이 있었다. 하지만 어쨌거나 저쨌거나 정보가 순차적으로 입력되기 때문에 position embedding과같은 위치를 알려주는 정보를 따로 입력할 필요가 없었다.

하지만 tansformer는 정보를 순차적으로 입력하는 것이 아닌 한 뭉치의 문장이 한꺼번에 입력되어 자기들끼리 내적하고 조물조물 되기 때문에 위치를 따로 알려줘야했고 그래서 position embedding이 필요했다.

 

Second step

이제 position embedding을 어떻게 구성하면 좋을지 생각해보자.

8글자의 문장을 받았을 때 가장 먼저 떠올릴 수 있는 생각인 0~7의 인덱스를 주는 것부터 고려하자. 

이때 발생하는 문제점은

<1> 문장의 단어가 50, 100, 1000 개 등, 길어져버리면  embedding을 상쇄할 정도로 weight가 너무 커져버려서 exploding  gradients가 나타날 수 있다. 그리고 weight는 0 근처에 머물지 않으면 unstable train 될 가능성이 높다.

 

 

 weight작게 만들기 위해서는 마지막 인덱스로 모든 숫자를 나누는 단순한 해결법이 있다.

<2> 하지만 시퀀스의 길이가  20이고 5번째 위치한 weight는 16/20 = 4/5 =0.8이 되고,

시퀀스의 길이가 5이고 4번째 위치한 요소는 4/5=0.8이 되므로

0.8이라는 숫자만으로는 다양한 길이의 시퀀스에 대처할 수 없다.

// position embedding의 유일성에 문제가 있다.

 

 

다음 시도는 2진수 해석이다. 이전까지는 1차원 해석이었지만 이제 2차원 해석으로 넘어왔다.

<1> 모든 숫자는 0,1 이므로 y = 2x-1 를 통과시키면 모든 숫자는 -1, 1로 표현할 수 있다.

<2> \(2^{n}\) 개 미만의 모든 수를 표현할 수 있고, position embedding의 유일성을 보장할 수 있다.

 

하지만 이진수는 이산적이라서 발생하는 두 가지 문제가 있다.

<3> weight는 gradient 계산 후 부드럽게 갱신되어야할 값이므로 이산함수가 아닌 부드러운 연속함수 위의 값이어야한다.

<4> 점들 간의 거리가 유지되지 못한다.

 

문제점 <3> 은 넘어가고 문제점 <4>만 살펴보자.

// 그림이 다소 잘못된 것 같으나, 의미 전달은 되므로 그대로 가져왔다.

0 -> 3 으로 거리를 측정하는 두 가지 인코딩을 보자.

 

(1) : 0 -> 1 -> 2 -> 3  // 1차원, 10진법  // 그림과 달라도 넘기자

(2) : (0,0) -> (0,1) -> (1,0) -> (1,1) // 2차원, 2진법

 

이때 (1)의 경우 점 간의 거리는 1로 유지되지만, (2)의 경우 

$$(0,0) → (0,1) : 1$$

$$ (0,1) → (1,0) : \sqrt{2} $$

$$ (1,0) → (1,1) : 1 $$

가 되어 점 간의 거리가 유지되지 못한다.

시퀀스 내에서 같은 거리에 있다고 상정해도 다른 거리에 있는 것처럼 판단하는 것이다. 이것은 차원이 커질 수록 정도가 심해져서 큰 문제거리가 된다.

 

이 문제를 해결하기 위해 연속 이진 벡터(continuous binary vector)를 사용한다.

마치 다이얼을 돌리듯이 이진수의 0과 1을 sin 함수를 주기를 적절히 이용해 표현하는 방법이다.

만약 8개의 다이얼을 이용한다면 \(2^{8}=512\)개의 숫자를 표현할 수 있다.

각 다이얼 sin을 일반화 한 식은 \(sin(\frac{\pi}{2^{i}} t)\) 이다.

 

<1> sin, cos 함수의 특징인 -1, 1을 진동한다는 것으로 문제를 해결한다.

<3> ,<4> 연속함수여서 점 간의 거리가 유지되므로 둘 다 해결된다.

 

<2> 하지만 이 문제는 아직 해결하지 못했다. 주어진 것처럼 다이얼이 3개 주어진 경우를 보자.

t=0일 때는 (0,0,0)이고 \(sin(\frac{ \pi }{8}t)\) 가 반 주기 돌았을 t=8인 시점 또한 (0,0,0)이 된다.

닫힌 함수이므로 다이얼이 몇 개 있는 함수이든 반드시 가장 느린 sin 의 반 주기 때 원점으로 돌아오며 같은 좌표를 갖게 된다.

다른 시점에 같은 좌표를 같게 되어 (0,0,0)이라는 위치가 유일함을 보장할 수 없다.

 

\((sin(\frac{\pi}{2}t), sin(\frac{\pi}{4}t), sin(\frac{\pi}{8}t))\)

그럼 유일성 문제를 해결 못 하나? 아니다. t=8가 되기 전에 position embedding을 끝내버리면 된다.

즉, 반 주기를 엄청 길게 만들어버리면 된다ㅋㅋ

\(PE_{(pos,2i)} = sin(\frac{pos}{10000^{2i/d_{model}}})\) 이 식에서 볼 수 있듯, 분모를 10000으로 보내버렸다.

10000에 딱히 큰 의미가 있는 것은 아니고, 저자가 생각하기에 이 정도면 충분한 수라고 판단한 것 같다.

왜 그렇게 판단했냐면...논문에 아무 설명이 없기 때문이다...

 

하지만 아직 문제 하나가 남았다. 이론은 확실하나, position embedding의 거리 차이를 계산하는 법을 모른다.

이제 마지막 계산 노가다만 남았다. 

 

Third step

우리는 몇 개의 다이얼을 이용해 꽤 긴 길이의 문장을 Position Embedding(=PE)할 수 있게 됐다. 그리고 그 embedding은 sin 함수만을 사용했다. PE를 보자.

\(\omega\)는 \(\frac{\pi}{2}\), \(\frac{\pi}{4}\) 같은 각속도를 보기 쉽게 바꾼 것이고, \(x_{i}\)는 position embedding이 결정되는 어느 시점을 의미한다고 보면 될 것 같다. 

// 256 으로 적어둔 이유는 바로 뒤에 내용에서 알 수 있을 것이다.

위 식을 곰곰히 생각해보자. 만일 두 위치의 차이를 구해야된다할 때, 위치가 \(\frac{\pi}{3}\) , \(\frac{\pi}{6}\)이 주어졌고 sinx 하나만 주어져있다면, 두 position의 차이는

sin( \(\frac{\pi}{2}\) ) - sin( \(\frac{\pi}{6}\) ) = 1 - \(\frac{1}{2}\) = 1/2 이 아니라

\(\frac{\pi}{2}\) - \(\frac{\pi}{6}\) = \(\frac{\pi}{3}\) 이다. 

즉, 거리를 구하기 위해 \(\Delta x\)를 구해야 한다.

 

한편, 식에서 \(\Delta x\)는 각도의 변화를 의미한다

아니..! 삼각함수에서 각도? 그렇다 회전행렬을 사용하자.

꼬마씽씽카로 외웠었다 껄껄껄

하지만 우리가 쓰던 PE 행렬은 sin으로만 구성돼있어서 회전행렬을 쓸 수 없다.

다른 방법을 찾아야 하나? 그럴 필요 없다. cos을 그냥 사이사이에 집어넣어 버리면 된다.

엥? 웬 비약이?? 왜 그래야되나요? 에 대한 대답은
" 하니까 되던데? " → 먼저 길을 닦아두신 현인들의 친절한 설명이 되겠다.

이렇게 요소 개수가 2배가 되었다.

 

이제 중요한 식이 나온다.

$$PE(x+\Delta x) = PE(x)T(\Delta x)$$

수식을 째려보면 알 수 있듯, position의 연속적인 변화량을 반영해주는 선형 변환 행렬T를 찾아낸다면 \(\Delta x\)만큼 등간격으로 움직이는 거리(=각도)를 반영할 수 있다 ! 

 

이제 변환행렬 T를 찾아보자. 사실 정답은 단순하다. 회전행렬을 꽝꽝꽝 찍어 블록행렬(block-diagonal)을 만들었다. 사실 진짜 블록행렬은 아니어서 원래 행렬곱 방식으로 계산하면 된다.

 

T는 대각성분으로만 이루어진 행렬이며, 각 성분은 블록행렬처럼 회전행렬이 자리잡고 있다. 큰 그림으로 보면 다음과 같다. 

 

 

\( PE(x)T(\Delta x) =  PE(x+\Delta x) \)연산은 다음과 같다.

 

=

삼각함수의 덧셈법칙으로 해결할 수 있다.
왼쪽1열 오른쪽1행을 행렬곱하면 sin cos + cos sin = 결과 1행1열
왼쪽1열 오른쪽2행을 행렬곱하면 -sin sin + cos cos = 결과 1행2열
결과 1행의 sin cos 교차는 첫 번째 단어의 position embedding이다.

 

이 수식을 통해 \(\Delta x\) 만큼 떨어진 공간에 변환행렬 T를 이용하여 상대적인 위치(relative position)을 찾아내고 거리로 계산해낼 수 있다는 사실을 밝혀냈다. 또한 sin,cos 쌍을 이용하면 <1>정규화, <2>유일성, <3>연속함수, <4>동간격 문제를 모두 피해갈 수 있었으므로 sin, cos 쌍을 이용하여 positional encoding을 하는 것은 적합하다고 볼 수 있다.

 

 

그럼 지금까지 한 것이 뭐냐 !

왜 cos sin 쌍의 선택이 적절했냐는 것이다.

그럼 이제부터 할 것은 cos, sin 쌍을 이용하여 어떻게 position encoding을 할 것인지를 살펴보자.

 

Fourth step

 

다시 등장했다 !

여기서부터 설명되는 각각의 값은 저자의 실험에 의해 가장 합리적인 수치를 표현한 것일 뿐이니 의미와 경향만 확인하자.

1) 분모의 10000은 그냥 저자가 쓴 숫자다. 삼각함수의 분모가 늘어나는 것이니 주기가 늘어난다고 보면 된다. 

2) pos 는 문장에서 단어 요소의 인덱스이다. 문장의 앞에 배치될 수록 삼각함수 안의 각도는 작은 값을 갖는다.

3) \(d_{model}\)은 embedding vector size이다. 우리가 보는 이미지에서는 512를 갖는다.

 

 

이제 이 식의 의미를 이해할 수 있게 됐다 !

 

드디어 position embedding을 마무리 했다.

 

이전에 언급했던 문제점을 다시 돌이켜보자.

<1> -1, 1 내의 값으로 구성돼있다.

<2> sin으로만 해결할 수 없던 문제를  position의 유일성을 확보했다.

<3> 연속함수이다

<4> 등간격으로 나눠진 함수이다.

 

이제 히트맵으로 경향성을 보면서 위의 문제점을지 잘 해결됐는지 확인하고 마무리 하도록 하자.

import numpy as np
import matplotlib.pyplot as plt

def cal(leng, d ,n):
    graph = np.zeros((leng,d))
    for i in range(leng):
        for j in range(int(d/2)):
            under = np.power(n, 2*j/d)
            graph[i, j*2] = np.sin(i/under)
            graph[i, j*2+1] = np.cos(i/under)
    return graph

p = cal(leng = 100, d = 512, n =10000)
plt.matshow(p)
plt.colorbar()

이 이미지의 각 행은 단어를 의미하고, 아래로 갈 수록 문장 뒤에 배치된 단어이다.

각 행은 모두 다른 모양을 가졌으므로 유일성이 보장된 potision embedding임을 알 수 있다.

또한 연속적으로 부드럽게 변화하는 모습을 볼 수 있다.

 

 

 

출처

https://towardsdatascience.com/master-positional-encoding-part-i-63c05d90a0c3

https://kazemnejad.com/blog/transformer_architecture_positional_encoding/

https://blog.timodenk.com/linear-relationships-in-the-transformers-positional-encoding/

728x90

'Ai > Notion' 카테고리의 다른 글

IoU, GIoU, DIoU 개념 !  (0) 2023.11.09
DETR(Detection with Transformers)  (0) 2023.11.08
VIT (Vision Transformer)  (0) 2023.10.12
Transformer  (0) 2023.10.12
VggNet  (0) 2023.10.12

댓글