위치 인코딩(Positional Encoding)은 트랜스포머(Transformer)가 순서 정보가 없는 셀프 어텐션의 한계를 보완하기 위해 입력 임베딩에 위치 정보를 추가하는 기법이다. 트랜스포머는 병렬 처리를 위해 RNN을 사용하지 않아 본질적으로 순서를 모른다.
사인/코사인 위치 인코딩 (원본 트랜스포머)
PE(pos, 2i) = sin(pos / 10000^(2i/d_model))
PE(pos, 2i+1) = cos(pos / 10000^(2i/d_model))
pos: 시퀀스 내 위치, i: 차원 인덱스, d_model: 임베딩 차원
구현
python
import torch
import math
def positional_encoding(max_len, d_model):
pe = torch.zeros(max_len, d_model)
position = torch.arange(0, max_len).unsqueeze(1).float()
div_term = torch.exp(
torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)
)
pe[:, 0::2] = torch.sin(position * div_term)
pe[:, 1::2] = torch.cos(position * div_term)
return pe # (max_len, d_model)
pe = positional_encoding(512, 256)
print(pe.shape) # (512, 256)
위치 인코딩 방식 비교
| 방식 | 특징 | 사용 모델 |
|---|
| 사인/코사인 (절대) | 고정, 학습 불필요 | 원본 Transformer |
| 학습 가능 절대 PE | 포지션별 임베딩 학습 | BERT, GPT-2 |
| 상대적 PE | 거리 관계 인코딩 | Transformer-XL |
| RoPE | 회전 행렬로 상대 위치 | LLaMA, PaLM |
| ALiBi | 어텐션 바이어스 방식 | MPT |
RoPE (Rotary Position Embedding)
python
def apply_rotary_emb(q, k, freqs):
# q, k: (batch, seq, heads, dim)
q_rot = (q * freqs.cos()) + (rotate_half(q) * freqs.sin())
k_rot = (k * freqs.cos()) + (rotate_half(k) * freqs.sin())
return q_rot, k_rot
RoPE는 현대 LLM(LLaMA, Mistral 등)에서 널리 채택된 방식으로, 컨텍스트 길이 확장에 유리하다.
관련 개념