🤖 AI/ML

어텐션

Attention Mechanism

입력의 중요한 부분에 가중치를 부여하는 메커니즘. "Attention Is All You Need" 논문으로 혁신.

📖 상세 설명

어텐션(Attention)은 딥러닝에서 입력 시퀀스의 각 부분에 서로 다른 중요도(가중치)를 부여하는 메커니즘입니다. 사람이 문장을 읽을 때 모든 단어에 동일한 주의를 기울이지 않는 것처럼, 모델도 관련성이 높은 부분에 더 "집중"할 수 있게 해줍니다.

어텐션의 핵심은 Query(질의), Key(키), Value(값)의 세 가지 요소입니다. Query는 "무엇을 찾고 있는가", Key는 "각 입력이 무엇인가", Value는 "각 입력의 실제 정보"를 나타냅니다. Query와 Key의 유사도를 계산하여 어텐션 가중치를 만들고, 이를 Value에 곱해 가중 합을 구합니다.

2017년 "Attention Is All You Need" 논문에서 제안된 Self-Attention(자기 어텐션)은 같은 시퀀스 내에서 모든 위치 간의 관계를 학습합니다. 이는 RNN의 순차적 처리 한계를 극복하고, 병렬 연산을 가능하게 하여 Transformer 아키텍처의 핵심이 되었습니다.

Multi-Head Attention은 여러 개의 어텐션을 병렬로 수행하여 다양한 관점에서 관계를 포착합니다. Cross-Attention은 서로 다른 시퀀스 간(예: 인코더-디코더)의 관계를 학습합니다. 현대 LLM의 모든 핵심 기능(문맥 이해, 긴 문서 처리, 관련 정보 추출)은 어텐션에 기반합니다.

💻 코드 예제

# Scaled Dot-Product Attention 구현
import torch
import torch.nn.functional as F
import math

def scaled_dot_product_attention(query, key, value, mask=None):
    """
    Scaled Dot-Product Attention 계산

    Args:
        query: [batch, heads, seq_len, d_k]
        key:   [batch, heads, seq_len, d_k]
        value: [batch, heads, seq_len, d_v]
        mask:  선택적 마스크 (패딩, 캐쥬얼 등)

    Returns:
        output: 어텐션 적용된 출력
        attention_weights: 시각화용 어텐션 가중치
    """
    d_k = query.size(-1)

    # 1. Query와 Key의 내적 → 유사도 점수
    scores = torch.matmul(query, key.transpose(-2, -1))

    # 2. 스케일링 (gradient 안정화)
    scores = scores / math.sqrt(d_k)

    # 3. 마스킹 (선택적)
    if mask is not None:
        scores = scores.masked_fill(mask == 0, float('-inf'))

    # 4. Softmax → 확률 분포 (어텐션 가중치)
    attention_weights = F.softmax(scores, dim=-1)

    # 5. Value와 가중 합
    output = torch.matmul(attention_weights, value)

    return output, attention_weights

# 예제: 문장 내 단어 간 어텐션
batch_size, seq_len, d_model = 1, 5, 64

# 가상의 Q, K, V (실제로는 학습된 선형 변환에서 생성)
query = torch.randn(batch_size, 1, seq_len, d_model)
key = torch.randn(batch_size, 1, seq_len, d_model)
value = torch.randn(batch_size, 1, seq_len, d_model)

output, attn_weights = scaled_dot_product_attention(query, key, value)

print(f"Input shape: [{batch_size}, 1, {seq_len}, {d_model}]")
print(f"Output shape: {output.shape}")
print(f"Attention weights shape: {attn_weights.shape}")
print(f"\n어텐션 가중치 (각 행의 합 = 1):")
print(attn_weights.squeeze().numpy().round(3))

🗣️ 실무 대화 예시

LLM 성능 분석 회의에서

"어텐션 맵을 시각화해보니 모델이 질문의 핵심 키워드에 제대로 집중하고 있어요. 하지만 문맥이 길어지면 어텐션이 분산되는 경향이 있네요. 더 긴 문서에서는 retrieval augmentation을 추가하는 게 좋겠습니다."

모델 최적화 논의 중

"어텐션의 O(n²) 복잡도가 병목입니다. Flash Attention으로 바꾸면 메모리는 O(n)으로 줄고 속도도 2-4배 빨라져요. 긴 컨텍스트가 필요하면 Sliding Window Attention이나 Sparse Attention도 고려해볼 만합니다."

기술 면접에서

"Self-Attention과 Cross-Attention의 차이는 Q, K, V의 출처입니다. Self-Attention은 같은 시퀀스에서 모두 생성되고, Cross-Attention은 Q가 디코더에서, K와 V가 인코더에서 옵니다. 번역 모델에서 소스 문장 정보를 타겟 생성에 활용할 때 Cross-Attention이 쓰입니다."

📊 어텐션 종류 비교

종류 설명 사용 예
Self-Attention 같은 시퀀스 내 관계 학습 BERT, GPT 인코딩
Cross-Attention 서로 다른 시퀀스 간 관계 번역, 이미지 캡셔닝
Multi-Head 여러 관점의 어텐션 병렬 수행 대부분의 Transformer
Causal/Masked 미래 토큰 참조 방지 GPT 생성, 디코더
Flash Attention 메모리 효율적 구현 대규모 LLM 학습/추론

💡 실무 팁: GPT 계열은 Causal Self-Attention (이전 토큰만 참조), BERT는 Bidirectional Self-Attention (양방향), T5는 인코더-디코더 간 Cross-Attention을 사용합니다.

⚠️ 주의사항

1
O(n²) 메모리/시간 복잡도

표준 어텐션은 시퀀스 길이의 제곱에 비례하는 리소스가 필요합니다. 긴 문서(수만 토큰)에서는 Flash Attention, Sparse Attention, 또는 Longformer 같은 효율적인 변형을 사용해야 합니다.

2
어텐션 != 설명가능성

어텐션 가중치가 높다고 해서 그 토큰이 결과에 "중요"하다고 단정할 수 없습니다. 어텐션은 해석 가능성의 힌트일 뿐, 인과 관계를 보장하지 않습니다. XAI 목적으로는 추가 분석이 필요합니다.

3
KV 캐시 메모리

추론 시 Key와 Value를 캐싱하면 속도가 빨라지지만, 긴 컨텍스트에서 메모리가 급증합니다. GQA(Grouped Query Attention)나 MQA(Multi-Query Attention)로 캐시 크기를 줄일 수 있습니다.

🔗 관련 용어

📚 더 배우기