
거대 언어 모델(LLM)의 한계를 결정짓는 가장 중요한 요소 중 하나는 바로 컨텍스트 윈도우(Context Window)입니다. 모델이 한 번에 처리할 수 있는 토큰의 양이 늘어날수록 긴 문서 요약, 복잡한 코드 분석, 그리고 정교한 RAG(Retrieval-Augmented Generation) 시스템 구축이 가능해집니다. 본 포스팅에서는 학습 시의 한계를 넘어 추론 시 컨텍스트를 확장하는 핵심 기술인 RoPE Scaling과 ALiBi의 이론적 차이를 분석하고, 파이썬으로 이를 직접 구현하는 7가지 실무 방법을 제시합니다.
1. 컨텍스트 확장의 난제: 외삽(Extrapolation) 문제 해결
대부분의 트랜스포머 모델은 학습할 때 설정한 최대 시퀀스 길이(예: 2048 토큰)를 넘어서는 순간 성능이 급격히 저하됩니다. 이는 위치 인코딩(Positional Encoding)이 학습되지 않은 미지의 영역으로 확장될 때 '외삽' 능력이 부족하기 때문입니다. 이를 해결하기 위해 등장한 기법이 바로 상대적 위치 정보에 가중치를 두거나 기존 위치 정보를 압축하는 방식입니다.
2. RoPE Scaling vs ALiBi: 핵심 아키텍처 및 구현 차이 비교
Llama 계열에서 주로 사용하는 RoPE Scaling과 MPT/Bloom 계열에서 선호하는 ALiBi의 기술적 차이를 정리했습니다.
| 비교 항목 | RoPE Scaling (Rotary Positional Embeddings) | ALiBi (Attention with Linear Biases) |
|---|---|---|
| 핵심 아이디어 | 회전 행렬을 이용해 각도를 조정하여 위치 압축 | 어텐션 스코어에 거리에 따른 선형 페널티 부여 |
| 추가 학습 필요성 | Fine-tuning 필수 (성능 유지 위해) | 추가 학습 없이 Zero-shot 외삽 가능 |
| 연산 효율성 | 복소수 회전 연산으로 약간의 오버헤드 존재 | 매우 효율적 (단순 덧셈 연산) |
| 외삽 능력 | 학습된 길이의 수배 정도 확장 가능 | 이론상 무한대에 가까운 외삽 가능성 제공 |
| 주요 적용 모델 | Llama 2, Llama 3, Mistral | MPT, Bloom, Jais |
| 해결 핵심 | 위치 인덱스의 보간(Interpolation) | 거리 비례 편향(Distance-based Bias) |
3. 실무 컨텍스트 확장을 위한 7가지 파이썬 구현 및 최적화 예제
개발자가 모델 아키텍처를 직접 수정하거나 라이브러리를 통해 컨텍스트를 확장하는 구체적인 방법들입니다.
Example 1: RoPE (Rotary Embedding) 기본 클래스 구현
위치 정보를 회전 각도로 변환하여 쿼리와 키에 적용하는 핵심 로직입니다.
import torch
import torch.nn as nn
class RotaryPositionalEmbedding(nn.Module):
def __init__(self, dim, max_position_embeddings=2048, base=10000):
super().__init__()
# 주파수(Theta) 계산
inv_freq = 1.0 / (base ** (torch.arange(0, dim, 2).float() / dim))
self.register_buffer("inv_freq", inv_freq)
self.max_seq_len = max_position_embeddings
def forward(self, x, seq_len):
t = torch.arange(seq_len, device=x.device).type_as(self.inv_freq)
freqs = torch.einsum("i,j->ij", t, self.inv_freq)
# Cos, Sin 캐시 생성
emb = torch.cat((freqs, freqs), dim=-1)
return emb.cos(), emb.sin()
Example 2: Linear Scaling을 이용한 RoPE 확장 방법
시퀀스 길이를 2배로 늘리기 위해 위치 인덱스를 절반으로 압축하는 가장 단순한 방법입니다.
def apply_linear_scaling(position_ids, scale=2.0):
# 위치 인덱스를 scale로 나누어 기존 학습 범위 내로 보간
return position_ids / scale
# Llama-2-7b-hf의 config.json에서 "rope_scaling" 항목을 수정하는 것과 동일한 원리
Example 3: NTK-Aware Scaling 구현 (비선형 보간)
고주파 정보는 유지하고 저주파 정보만 압축하여 성능 저하를 최소화하며 길이를 확장하는 고급 방법입니다.
def ntk_aware_rope_base(base, scale, dim):
# 새로운 base 값을 계산하여 주파수 대역폭 조정
new_base = base * (scale ** (dim / (dim - 2)))
return new_base
Example 4: ALiBi Attention Bias 행렬 생성
어텐션 맵에 직접 거리에 따른 페널티를 더해주는 ALiBi의 핵심 구현 코드입니다.
import math
def get_alibi_slope(num_heads):
# 헤드마다 다른 기울기(Slope) 할당
closest_power_of_2 = 2 ** math.floor(math.log2(num_heads))
base = 2 ** (-(2 ** -(math.log2(closest_power_of_2) - 3)))
powers = torch.arange(1, closest_power_of_2 + 1)
slopes = base ** powers
return slopes
def apply_alibi_bias(attention_scores, slopes):
# attention_scores: (batch, num_heads, seq_len, seq_len)
seq_len = attention_scores.size(-1)
# 거리 행렬 생성 [0, 1, 2, ...]
relative_positions = torch.arange(seq_len).unsqueeze(0) - torch.arange(seq_len).unsqueeze(1)
relative_positions = -torch.abs(relative_positions)
bias = slopes.view(1, -1, 1, 1) * relative_positions.view(1, 1, seq_len, seq_len)
return attention_scores + bias
Example 5: Hugging Face Dynamic NTK Scaling 적용
from transformers import LlamaConfig, LlamaForCausalLM
config = LlamaConfig.from_pretrained("meta-llama/Llama-2-7b-hf")
config.rope_scaling = {
"type": "dynamic",
"factor": 4.0 # 기존 2048 -> 8192로 확장
}
model = LlamaForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf", config=config)
Example 6: YaRN (Yet another RoPE extensioN) 스케일링 적용
보간 시 발생하는 에너지 손실을 보정하기 위한 최신 기법입니다.
# YaRN은 온도(Temperature) 계수를 조절하여 어텐션 소프트맥스 분포가
# 뭉개지는 현상을 방지합니다.
def yarn_attention_scaling(factor):
if factor <= 1.0:
return 1.0
return 0.1 * math.log(factor) + 1.0
Example 7: Flash Attention과 ALiBi 결합 시 고려사항
# ALiBi는 어텐션 스코어에 직접 개입하므로 커스텀 CUDA 커널을 사용하는
# Flash Attention 적용 시 Bias 지원 여부를 확인해야 합니다.
# Triton 커널을 사용하여 ALiBi 편향을 인라인으로 계산하는 것이 최적의 해결 방법입니다.
4. 어떤 기법을 선택해야 하는가? 실무 가이드
- 성능 최우선: 이미 RoPE로 학습된 Llama 모델을 사용 중이라면 YaRN이나 NTK-Aware Scaling을 적용한 파인튜닝이 가장 효과적입니다.
- 학습 리소스 부족: 추가 학습 없이 즉시 긴 컨텍스트를 처리해야 한다면 ALiBi 아키텍처 모델을 선택하거나 Dynamic NTK를 적용해 보세요.
- 메모리 효율: 컨텍스트가 길어지면 인코딩 방식보다 KV 캐시 압축 기술이 병행되어야 함을 잊지 마세요.
5. 결론: 무한한 컨텍스트를 향한 기술 여정
컨텍스트 윈도우 확장은 단순히 숫자상의 증가가 아니라, LLM이 '단기 기억'을 넘어 '문서 전체의 맥락'을 파악하게 만드는 도약입니다. RoPE Scaling의 정교함과 ALiBi의 강력한 외삽 능력은 각각의 장단점이 뚜렷합니다. 본 포스팅에서 다룬 7가지 방법과 기술적 차이를 바탕으로, 여러분의 서비스 환경에 최적화된 긴 문맥 처리 시스템을 구축해 보시기 바랍니다.