Transformer의 self-attention은 입력 vector 사이의 관계를 계산하지만, token이 원래 몇 번째 위치에 있었는지는 스스로 알 수 없다. 따라서 token embedding에 위치정보를 별도로 넣어주어야 한다.

Sinusoidal positional encoding은 token의 위치 ii를 여러 주파수의 sin과 cos로 변환하여 dd차원 vector 하나로 표현하는 방법이다.

Positional encoding이 필요한 이유

Self-attention에 다음 두 sequence를 입력한다고 하자.

[dog,bites,man][\text{dog},\text{bites},\text{man}] [man,bites,dog][\text{man},\text{bites},\text{dog}]

두 문장은 token의 구성은 같지만 순서에 따라 의미가 달라진다. 그러나 위치정보가 없는 self-attention은 입력 순서를 바꾸면 출력도 같은 방식으로 재배열되는 permutation equivariant 연산이다. 어느 token이 첫 번째이고 어느 token이 마지막인지 구분하는 기준이 연산 자체에는 없다.

그래서 위치 ii의 token embedding xix_i에 같은 차원의 positional vector pip_i를 더한다.

x~i=xi+pi\tilde{x}_i=x_i+p_i

xix_i와 pip_i의 shape는 모두 다음과 같다.

xi,pi∈Rdx_i,p_i\in\mathbb{R}^{d}

여기서 dd는 embedding dimension이며, Transformer 표기에서는 보통 dmodeld_{\text{model}}에 해당한다. 이렇게 만든 x~i\tilde{x}_i에는 token의 내용과 위치정보가 함께 들어간다.

Sinusoidal positional encoding의 정의

위치 ii에 대한 positional vector를 다음과 같이 두자.

pi=[pi,0,pi,1,…,pi,d−1]p_i= [p_{i,0},p_{i,1},\ldots,p_{i,d-1}]

각 원소는 다음 식으로 정한다.

pi,j={sin⁡(i⋅10000−j/d),j가 짝수cos⁡(i⋅10000−(j−1)/d),j가 홀수p_{i,j} = \begin{cases} \sin\left(i\cdot10000^{-j/d}\right), & j\text{가 짝수}\\[4pt] \cos\left(i\cdot10000^{-(j-1)/d}\right), & j\text{가 홀수} \end{cases}

기호의 의미는 다음과 같다.

  • ii: sequence 안에서 token의 위치이며 보통 0,1,2,…0,1,2,\ldots로 센다.
  • jj: positional vector 안의 dimension 또는 channel 번호이다.
  • dd: token embedding과 positional vector의 차원이다.

짝수와 홀수 dimension을 2k2k와 2k+12k+1로 묶으면 인접한 홀수, 짝수 두개의 채널이 같은 주파수를 공유함을 볼 수 있다.

PE(i,2k)=sin⁡(i100002k/d)PE(i,2k) = \sin\left(\frac{i}{10000^{2k/d}}\right) PE(i,2k+1)=cos⁡(i100002k/d)PE(i,2k+1) = \cos\left(\frac{i}{10000^{2k/d}}\right)

두 식은 10000−2k/d=1/100002k/d10000^{-2k/d}=1/10000^{2k/d}이므로 같은 의미이다. 인접한 두 dimension은 같은 주파수를 공유하고, 하나는 sin, 다른 하나는 cos를 사용한다.

d=6d=6인 경우

Embedding dimension을 d=6d=6으로 두면 jj는 00부터 55까지이다. 같은 주파수를 사용하는 dimension을 한 쌍으로 묶으면 다음과 같다.

ω0=1,ω1=10000−2/6,ω2=10000−4/6\omega_0=1, \qquad \omega_1=10000^{-2/6}, \qquad \omega_2=10000^{-4/6}

위치 ii의 positional vector는 다음과 같이 만들어진다.

pi=[sin⁡(i),cos⁡(i),sin⁡(iω1),cos⁡(iω1),sin⁡(iω2),cos⁡(iω2)]p_i= [ \sin(i), \cos(i), \sin(i\omega_1), \cos(i\omega_1), \sin(i\omega_2), \cos(i\omega_2) ]

예를 들어 i=0i=0이면 모든 sin 항은 00, 모든 cos 항은 11이므로 다음과 같다.

p0=[0,1,0,1,0,1]p_0=[0,1,0,1,0,1]

ii가 11, 22, 33으로 증가하면 각 sin과 cos 쌍은 서로 다른 속도로 값을 바꾸며, 위치마다 다른 vector를 만든다.

여러 주파수를 사용하는 이유

하나의 주파수 ω\omega를 사용하는 sin과 cos 쌍은 다음과 같이 쓸 수 있다.

ri(ω)=[sin⁡(iω)cos⁡(iω)]r_i(\omega)= \begin{bmatrix} \sin(i\omega)\\ \cos(i\omega) \end{bmatrix}

이 vector는 단위원 위에서 각도 iωi\omega만큼 회전한 점으로 볼 수 있다. 위치가 증가할 때마다 원 위를 일정한 속도로 이동하는 셈이다.

하지만 sin과 cos는 주기함수이므로 한 주파수만 사용하면 멀리 떨어진 위치에서 같은 값이 반복된다. Sinusoidal positional encoding은 이를 보완하기 위해 dimension마다 서로 다른 주파수를 사용한다.

ωk=10000−2k/d\omega_k=10000^{-2k/d}

kk가 작을 때는 ωk\omega_k가 커서 위치가 조금만 달라져도 값이 빠르게 변한다. 반대로 kk가 커질수록 ωk\omega_k가 작아져 값이 천천히 변한다. 따라서 하나의 positional vector 안에 짧은 거리의 차이에 민감한 dimension과 긴 범위에서 천천히 변하는 dimension이 함께 들어간다.

각 주파수의 wavelength는 다음과 같다.

λk=2πωk=2π⋅100002k/d\lambda_k = \frac{2\pi}{\omega_k} = 2\pi\cdot10000^{2k/d}

이를 속도가 서로 다른 여러 개의 시계로 생각할 수 있다. 시계 하나의 상태는 주기적으로 반복되지만, 여러 속도의 시계를 함께 보면 각 위치를 훨씬 풍부한 조합으로 나타낼 수 있다.

상대적 위치를 다루기 좋은 이유

같은 주파수의 두 positional vector를 내적하면 다음과 같다.

ri(ω)Trj(ω)=sin⁡(iω)sin⁡(jω)+cos⁡(iω)cos⁡(jω)r_i(\omega)^T r_j(\omega) = \sin(i\omega)\sin(j\omega) + \cos(i\omega)\cos(j\omega)

삼각함수 항등식을 적용하면 절대 위치 ii와 jj가 아니라 두 위치의 차이가 나타난다.

ri(ω)Trj(ω)=cos⁡((i−j)ω)r_i(\omega)^T r_j(\omega) = \cos((i-j)\omega)

예를 들어 (i,j)=(3,7)(i,j)=(3,7)과 (13,17)(13,17)은 절대 위치가 다르지만 두 경우 모두 위치 차이가 44이다. 따라서 같은 주파수 쌍의 내적값도 같다.

전체 positional encoding은 이런 sin과 cos 쌍을 여러 주파수에 걸쳐 사용한다. 덕분에 각 위치 자체를 표현하면서도 token 사이의 상대적 거리 i−ji-j가 내적과 선형변환을 통해 드러나기 좋은 구조를 가진다.

Sequence 전체의 shape

Token이 NN개라면 각 위치의 positional vector를 행으로 쌓아 positional encoding matrix를 만든다.

P=[p0Tp1T⋮pN−1T]∈RN×dP= \begin{bmatrix} p_0^T\\ p_1^T\\ \vdots\\ p_{N-1}^T \end{bmatrix} \in \mathbb{R}^{N\times d}

Token embedding matrix도 같은 shape를 가진다.

X∈RN×dX\in\mathbb{R}^{N\times d}

따라서 두 matrix를 원소별로 더할 수 있다.

X~=X+P\tilde{X}=X+P [N,d]+[N,d]→[N,d][N,d]+[N,d]\rightarrow[N,d]

Positional encoding을 더해도 Transformer에 들어가는 입력 shape는 바뀌지 않는다. 같은 단어의 embedding이 xdogx_{\text{dog}}라고 하더라도 위치에 따라 입력 vector는 달라진다.

x~1=xdog+p1\tilde{x}_1=x_{\text{dog}}+p_1 x~10=xdog+p10\tilde{x}_{10}=x_{\text{dog}}+p_{10}

따라서 모델은 같은 token이라도 어느 위치에 나타났는지를 구분할 수 있다.

Sinusoidal 방식과 learned positional embedding

고전적인 sinusoidal positional encoding은 학습할 parameter가 없다. 위치 ii가 주어지면 정해진 식으로 pip_i를 바로 계산한다.

i⟶pii\longrightarrow p_i

반면 learned positional embedding은 최대 길이 Nmax⁡N_{\max}에 대한 embedding matrix 자체를 parameter로 둔다.

P∈RNmax⁡×dP\in\mathbb{R}^{N_{\max}\times d}

Sinusoidal 방식은 임의의 위치에 대한 vector를 식으로 생성할 수 있고, learned 방식은 학습 데이터에 맞는 위치 표현을 직접 학습할 수 있다는 차이가 있다. 두 방식 모두 입력에 위치정보를 더하는 구조에서는 최종적으로 xi+pix_i+p_i를 사용한다.

식에 등장하는 1000010000은 수학적으로 반드시 정해지는 상수가 아니라, 넓은 범위의 wavelength를 만들기 위해 선택한 설계값이다.

RoPE와의 연결

Sin과 cos 한 쌍을 2차원 회전으로 보는 관점은 RoPE(Rotary Position Embedding)와도 연결된다. 다만 RoPE는 positional vector를 token embedding에 단순히 더하는 대신, 위치에 따라 query와 key의 channel 쌍을 회전시킨다.

두 방법의 구현은 다르지만, 여러 주파수의 회전으로 위치를 표현하고 상대적 위치 차이가 attention score에 드러나게 한다는 직관은 이어진다.

정리

Sinusoidal positional encoding은 위치 ii를 여러 속도의 sin과 cos 파동에 넣어 embedding과 같은 dd차원 vector로 표현한다.

  • 빠르게 변하는 dimension은 가까운 위치의 차이에 민감하다.
  • 천천히 변하는 dimension은 더 긴 범위의 위치 변화를 나타낸다.
  • 같은 주파수의 sin과 cos를 쌍으로 사용하면 위치를 회전 상태로 볼 수 있다.
  • 두 위치 vector의 내적에는 i−ji-j가 나타나므로 상대적 위치를 다루기 좋은 구조가 된다.
  • XX와 PP의 shape가 모두 [N,d][N,d]이므로 위치정보를 더해도 Transformer 입력 차원은 유지된다.