23.06.15
DEVOTEE를 활성화 시키면
지금 작성한 커뮤니티 글에 대해 1개의 댓글을 달아줍니다.
버튼을 누르면 글 수정 시 ChatGPT가 작성한 댓글이 수정됩니다.
| 컨텐츠 유형 | 제목 | 저장일 | 삭제 |
|---|
본인인증 로그인에 실패하였습니다.
회원이 아니시거나 본인인증 등록이
완료되지 않은 사용자입니다.
딥러닝과 자연어 처리(NLP)에서 빠질 수 없는 개념이 바로 Attention 기법입니다.
입력데이터를 처리할 때, 모든 정보를 동일하게 바라보는 대신 더 중요한 정보에 집중할 수 있도록 하는 기법입니다.
사람들이 긴 문장을 읽을 때, 핵심 키워드에 더 주의를 기울이는 방식과 유사한 방식이라고 보면 될 것 같습니다.
기존의 RNN(Recurrent Neural Network)이나 LSTM(Long Short-Term Memory) 모델은 긴 시퀀스 데이터를 처리할 때, 앞부분의 정보가 점점 희미해지는 문제가 있었습니다.
예를 들어, “나는 어제 친구와 영화를 봤는데, 그 영화는 정말 재미있었다”라는 문장에서 "재미있었다." 라는 표현을 이해하려면 앞의 "영화" 라는 단어와 연결해야 합니다.
하지만 기존의 전통적인 모델은 앞의 단어를 잃어버리는 장기 의존성 문제(Long-Term Dependency)를 가지고 있었습니다.
Attention 기법은 입력 시퀀스 전체를 살펴보면서, 현재 출력에 필요한 단어와 그렇지 않은 단어에 가중치를 매겨서 구합니다.
즉, 모델이 “어떤 단어에 집중해야 할지” 스스로 학습하게 됩니다.
특히 2017년 등장한 Transformer 모델은 Self-Attention을 기반으로 설계되어, RNN 없이도 병렬 처리가 가능해졌습니다.
이로 인해 번역, 요약, 질의응답 등 다양한 NLP 작업에서 비약적인 성능 향상이 이루어졌습니다.
지금 우리가 흔히 접하는 ChatGPT나 BERT 같은 모델도 모두 이 Attention 메커니즘을 활용합니다.
간단히 말해, Attention은 **가중치 기반의 ‘집중도 점수’**를 계산하는 과정입니다.
각 입력 토큰(token)이 현재 문맥에서 얼마나 중요한지 수치로 평가하고, 그 점수를 바탕으로 모델이 더 정확한 출력을 내놓습니다.
이를 통해 문맥 이해력이 뛰어나고, 긴 문장도 효율적으로 다룰 수 있는 강력한 언어 모델이 가능해졌습니다.
Attention 은 입력 정보에 더 큰 가중치를 두는 메커니즘 입니다.
Attention 에 대한 정리와 간단한 예제를 만들었습니다.
Attention 은 토큰 → 임베딩 → Q/K/V 값 변환 → 스코어 계산 → 가중치 계산 → 출력 순으로 작동하는 기법입니다.
Query (Q)(질문): “지금 내 입장에서 누구를 참고하면 좋지?”, “내가 지금 필요한 게 뭐지?”
Key (K)(단서): “각 단어가 가진 힌트/특징”,“내가 가진 단서는 이런 거야.”
Value (V)(정보): “그 단어를 참고하면 실제로 가져갈 정보”, “내가 줄 수 있는 실제 정보야.”
Q로 K와 얼마나 잘 맞는지 점수(유사도)를 매기고, 그 점수로 V를 섞어 평균(가중치)을 만드는 게 Attention입니다.
즉, Q는 질문, K는 질문과 맞출 단서, V는 최종 대답이라고 보면 될 것 같습니다.
예시 ① 도서관에서 책 찾기
Q (Query): “나는 지금 ‘역사’ 관련 책을 찾고 있어.”
K (Key): “ ‘역사’라는 주제 태그가 달린 책이야.”
V (Value): “내가 가진 실제 내용은 ‘조선시대 역사’야.”
Q가 ‘역사’라는 관심사를 던지면, K 중에서 맞는 걸 찾아서 V(책 내용)를 가져옵니다.
예시 ② 친구에게 질문하기
Q (Query): “오늘 저녁 뭐 먹을까?”
K (Key): “나는 ‘피자’를 좋아하는 친구야.”
V (Value): “내 대답은 ‘피자 먹자!’”
Q가 질문을 던지면, 친구들의 성향(K)과 가장 잘 맞는 Value(대답)가 선택됩니다.
텍스트를 모델이 처리할 수 있는 정수 시퀀스로 변환합니다.
예시
. 토큰: ["나는", "회사에", "간다."]
. 단어사전(vocab) 매핑: {"나는":0, "회사에":1, "간다.":2}
. 입력 시퀀스: [0, 1, 2]
각 정수 토큰을 길이 d_model의 실수 벡터로 매핑합니다.(단어 임베딩)
Embedding(vocab_size=3, output_dim=4)
입·출력 모양(Shape)
. 입력: 길이 L=3(세 토큰)
. 출력 임베딩: embeddings의 모양 (L=3, d_model=4)
→ 각 단어를 길이 4개 짜리 실수 벡터로 바꿈.
embeddings 결과는 (L=3, d_model=4) 텐서로 변환됨.
. Q=EWq, K=EWk, V=EWv
. 같은 임베딩을 서로 다른 가중치로 변환해 질문(Q)·단서(K)·답정보(V) 역할을 하게 함.
. shape는 모두 (3, 4)
. score = QKᵀ , Shape (3,3)
. scores_scaled =
softmax를 사용하여 가중치 확률로 변환
A = softmax(scores_scaled )
output = AV
입력 토큰 수 L=3, 차원 d=4
. E(임베딩) : (3,4)
. Wq,Wk,Wv : (4,4)
. Q,K,V : (3,4)
. QKᵀ(score) : (3,3) <- 쿼리수, 키
. softmax → attention weights A : (3, 3)
. O=AV: (3, 4)
[PyTorch 사용 예제]
import torch
import torch.nn as nn
import torch.nn.functional as F
def scaled_dot_product_attention(Q, K, V, mask=None):
"""
Scaled Dot-Product Attention (직접 Softmax 계산 포함).
Args:
Q, K, V: (L, d_model)
mask: (L, L) boolean tensor. True=마스킹 아웃
"""
d_k = Q.size(-1)
scores = Q @ K.transpose(-2, -1) / (d_k ** 0.5) # (L,L)
if mask is not None:
scores = scores.masked_fill(mask, float("-inf"))
weights = F.softmax(scores, dim=-1) # (L,L)
output = weights @ V # (L,d_model)
return output, weights, scores
def demo():
tokens = ["나는", "회사에", "간다."]
input_ids = torch.tensor(list(range(len(tokens))), dtype=torch.long)
print("Tokens:", tokens)
print("IDs :", input_ids.tolist())
vocab_size = len(tokens)
d_model = 4
torch.manual_seed(42)
embedding = nn.Embedding(vocab_size, d_model)
x = embedding(input_ids) # (L,d_model)
print("\n[임베딩]\n", x.detach())
# Q, K, V 선형변환
W_Q = nn.Linear(d_model, d_model, bias=False)
W_K = nn.Linear(d_model, d_model, bias=False)
W_V = nn.Linear(d_model, d_model, bias=False)
Q, K, V = W_Q(x), W_K(x), W_V(x)
out, attn, scores = scaled_dot_product_attention(Q, K, V)
print("\n[Scores]\n", scores.detach())
print("\n[Attention Weights]\n", attn.detach())
print("\n[Output]\n", out.detach())
if __name__ == "__main__":
torch.set_printoptions(precision=6, sci_mode=False)
demo()[결과]
[Tensorflow 사용 예제]
from __future__ import annotations
import numpy as np
import tensorflow as tf
def scaled_dot_product_attention(Q, K, V, mask=None):
"""
Scaled Dot-Product Attention 계산.
"""
d_k = tf.cast(tf.shape(K)[-1], tf.float32)
scores = tf.matmul(Q, K, transpose_b=True) / tf.sqrt(d_k) # (L,L)
if mask is not None:
mask = tf.cast(mask, tf.bool)
very_neg = tf.constant(-1e9, dtype=scores.dtype)
scores = tf.where(mask, scores, very_neg)
weights = tf.nn.softmax(scores, axis=-1) # (L,L)
output = tf.matmul(weights, V) # (L,d_k)
return output, weights, scores
def demo():
tokens = ["나는", "회사에", "간다."]
input_ids = list(range(len(tokens)))
print("Tokens:", tokens)
print("IDs :", input_ids)
vocab_size = len(tokens)
d_model = 4
tf.random.set_seed(42)
embedding = tf.keras.layers.Embedding(vocab_size, d_model)
x = embedding(tf.constant(input_ids, dtype=tf.int32)) # (L, d_model)
print("\n[임베딩]\n", x.numpy())
# Q, K, V
W_Q = tf.keras.layers.Dense(d_model, use_bias=False)
W_K = tf.keras.layers.Dense(d_model, use_bias=False)
W_V = tf.keras.layers.Dense(d_model, use_bias=False)
Q, K, V = W_Q(x), W_K(x), W_V(x)
out, attn, scores = scaled_dot_product_attention(Q, K, V)
print("\n[Scores]\n", scores.numpy())
print("\n[Attention Weights]\n", attn.numpy())
print("\n[Output]\n", out.numpy())
if __name__ == "__main__":
np.set_printoptions(precision=6, suppress=True)
demo()[결과]
DEVOTEE를 활성화 시키면
지금 작성한 댓글에 AI가 댓글을 달아줍니다.