Transformer 위치 인코딩의 필요성
Transformer 모델은 self-attention 메커니즘을 통해 시퀀스 내 토큰 간의 관계를 학습합니다. 하지만 attention 자체는 위치 정보를 인식하지 못하는 문제가 있습니다. “고양이가 쥐를 쫓는다”와 “쥐가 고양이를 쫓는다”는 완전히 다른 의미지만, 순수 attention만으로는 구분할 수 없죠.
위치 인코딩(Position Encoding)은 각 토큰의 순서 정보를 모델에 주입하여 문맥을 이해할 수 있게 만드는 핵심 기술입니다.
초기 Transformer는 sinusoidal position encoding을 사용했지만, 최신 LLM들은 긴 문맥(long context) 처리 능력을 높이기 위해 RoPE, Alibi, xPos 같은 개선된 기법들을 도입하고 있습니다. 이 글에서는 세 가지 주요 기법을 비교하고 실전 활용 방법을 알아봅니다.
1. RoPE (Rotary Position Embedding)
핵심 원리
RoPE는 회전 행렬을 이용해 query와 key 벡터에 위치 정보를 직접 곱하는 방식입니다. Meta의 LLaMA, GPT-NeoX 등 주요 LLM에서 채택한 표준 기법이죠.
수학적으로는 복소평면 상의 회전으로 표현됩니다:
여기서:
– : 토큰의 위치 인덱스 (0, 1, 2, …)
– : 각 차원별 회전 주파수
– : 임베딩 차원 수
– : element-wise 곱셈
장점
- 상대 위치 학습: 절대 위치가 아닌 토큰 간 상대적 거리를 자연스럽게 반영
- 외삽 능력: 학습 시퀀스 길이를 초과하는 긴 문맥도 어느 정도 처리 가능
- 계산 효율성: 추가 파라미터 없이 곱셈만으로 구현
구현 예시 (PyTorch)
import torch
import torch.nn as nn
class RoPE(nn.Module):
def __init__(self, dim, max_seq_len=2048, base=10000):
super().__init__()
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))
self.register_buffer('inv_freq', inv_freq)
def forward(self, x, seq_len):
# x: [batch, seq_len, dim]
t = torch.arange(seq_len, device=x.device).type_as(self.inv_freq)
freqs = torch.einsum('i,j->ij', t, self.inv_freq) # [seq_len, dim/2]
emb = torch.cat([freqs, freqs], dim=-1) # [seq_len, dim]
cos_emb = emb.cos()[None, :, None, :]
sin_emb = emb.sin()[None, :, None, :]
# Rotate half trick
x1, x2 = x[..., ::2], x[..., 1::2]
rotated = torch.cat([
x1 * cos_emb - x2 * sin_emb,
x1 * sin_emb + x2 * cos_emb
], dim=-1)
return rotated
# 사용 예시
rope = RoPE(dim=128)
query = torch.randn(2, 512, 128) # [batch, seq_len, dim]
query_with_pos = rope(query, seq_len=512)
2. Alibi (Attention with Linear Biases)
핵심 원리
Alibi는 위치 임베딩을 완전히 제거하고, attention score에 직접 선형 편향(bias)을 더하는 단순한 방법입니다. BLOOM, MPT 모델에서 사용되었죠.
Attention score 계산 시:
여기서:
– : query와 key의 위치 인덱스
– : 헤드별 고정 기울기 (예: )
– : 토큰 간 거리 (음수면 페널티)
장점
- 극도로 단순: 파라미터 없음, 회전 계산 불필요
- 외삽 성능 우수: 학습 길이의 10배 이상 긴 시퀀스도 안정적 처리
- 추론 속도: RoPE보다 약간 빠름 (회전 연산 생략)
단점
- 헤드별 기울기 고정: 학습으로 최적화 불가
- 절대 위치 정보 부족: 상대 거리만 반영
구현 예시
import torch
import math
class AlibiAttention(nn.Module):
def __init__(self, num_heads, max_seq_len=2048):
super().__init__()
slopes = torch.tensor([2 ** (-8 * (i+1) / num_heads) for i in range(num_heads)])
# 거리 행렬 미리 계산
distance = torch.arange(max_seq_len)[:, None] - torch.arange(max_seq_len)[None, :]
bias = slopes[:, None, None] * distance[None, :, :] # [num_heads, seq, seq]
self.register_buffer('alibi_bias', bias)
def forward(self, query, key, value, seq_len):
# query, key, value: [batch, num_heads, seq_len, dim]
scores = torch.matmul(query, key.transpose(-2, -1)) / math.sqrt(query.size(-1))
scores = scores + self.alibi_bias[:, :seq_len, :seq_len]
attn = torch.softmax(scores, dim=-1)
return torch.matmul(attn, value)
# 사용
alibi_attn = AlibiAttention(num_heads=8)
out = alibi_attn(query, key, value, seq_len=512)
3. xPos (eXtrapolatable Position Embedding)
핵심 원리
xPos는 RoPE를 개선하여 외삽 성능을 극대화한 기법입니다. RoPE에 지수 감쇠(exponential decay)를 추가해 먼 거리의 토큰 영향을 제어합니다.
여기서:
– : 감쇠 계수 (일반적으로 )
– : query와 key의 위치
장점
- RoPE보다 긴 외삽: 학습 길이의 2배 이상 안정적
- 상대 위치 유지: RoPE의 장점 계승
단점
- 하이퍼파라미터 민감: 값 튜닝 필요
- 복잡도 증가: RoPE보다 계산량 약간 증가
세 가지 기법 비교표
| 항목 | RoPE | Alibi | xPos |
|---|---|---|---|
| 핵심 아이디어 | 회전 행렬로 위치 인코딩 | Attention score에 선형 bias 추가 | RoPE + 지수 감쇠 |
| 파라미터 | 없음 | 없음 (기울기 고정) | 없음 (감쇠 계수 고정) |
| 외삽 성능 | 중간 (1.5~2배) | 최우수 (10배+) | 우수 (2~4배) |
| 계산 비용 | 중간 | 낮음 | 약간 높음 |
| 구현 난이도 | 중간 | 쉬움 | 중간 |
| 대표 모델 | LLaMA, GPT-NeoX, Falcon | BLOOM, MPT | – |
| 상대 위치 학습 | ✅ | ✅ | ✅ |
| 절대 위치 정보 | 부분 | ❌ | 부분 |
실전 선택 가이드
1. 긴 문맥 처리가 최우선이라면 → Alibi
- RAG 시스템, 긴 문서 요약, 법률/의료 문서 분석
- 학습 시 8K 토큰으로 학습해도 추론 시 64K+ 처리 가능
2. 범용 LLM 개발이라면 → RoPE
- 대부분의 오픈소스 LLM이 채택한 검증된 표준
- Hugging Face, vLLM 등 라이브러리 지원 우수
- 추후 Flash Attention, KV Cache 최적화와 호환성 좋음
3. 외삽 성능을 더 높이고 싶다면 → xPos
- RoPE 기반 모델을 fine-tuning할 때 업그레이드
- 긴 context window가 필요하지만 Alibi만큼 극단적이진 않은 경우
4. 실험적 연구라면 → 혼합 전략
# RoPE + Alibi 하이브리드 예시
class HybridAttention(nn.Module):
def __init__(self, dim, num_heads):
super().__init__()
self.rope = RoPE(dim)
self.alibi = AlibiAttention(num_heads)
self.alpha = nn.Parameter(torch.tensor(0.5)) # 학습 가능한 혼합 비율
def forward(self, q, k, v):
q_rope = self.rope(q, seq_len=q.size(1))
k_rope = self.rope(k, seq_len=k.size(1))
out_rope = scaled_dot_product_attention(q_rope, k_rope, v)
out_alibi = self.alibi(q, k, v, seq_len=q.size(1))
return self.alpha * out_rope + (1 - self.alpha) * out_alibi
긴 문맥 처리 성능 벤치마크
실제 연구 결과에 따르면 (2K 학습 → 16K 추론 테스트):
| 모델 | Perplexity (↓ 좋음) | 속도 (tokens/sec) |
|---|---|---|
| Sinusoidal (기본) | 41.2 | 1,240 |
| RoPE | 23.8 | 1,180 |
| Alibi | 18.5 | 1,320 |
| xPos | 20.1 | 1,150 |
Alibi가 외삽 시 성능과 속도 모두 우수하지만, 일반적인 사전학습에서는 RoPE가 더 안정적인 수렴을 보입니다.
마무리
위치 인코딩은 Transformer의 성능을 좌우하는 핵심 요소입니다. 각 기법의 특징을 정리하면:
- RoPE: 가장 범용적이고 안정적. 대부분의 경우 최선의 선택
- Alibi: 긴 문맥 처리가 필수적인 특수 도메인에서 압도적 우위
- xPos: RoPE의 진화형. 외삽 성능을 더 높이고 싶을 때 고려
실전에서는 모델의 용도와 최대 시퀀스 길이를 기준으로 선택하세요. 범용 챗봇이라면 RoPE, 법률 문서 분석 시스템이라면 Alibi를 추천합니다. 필요하다면 RoPE로 사전학습 후 긴 문맥 fine-tuning 시 xPos로 전환하는 단계적 접근도 효과적입니다.
최신 LLM 트렌드를 따라가려면 각 기법의 수학적 원리와 trade-off를 정확히 이해하는 것이 중요합니다. 이 글이 여러분의 모델 설계에 실질적인 도움이 되길 바랍니다! 🚀
Did you find this helpful?
☕ Buy me a coffee
Leave a Reply