Skip to main content

[LLM] 10. Casual Attention


Casual Attention


Casual Attention은 미래의 단어를 보지 않고 예측하는 방법입니다.

GPT 같은 Autogressive 모델에서 중요한 개념이라고 합니다. 모델이 다음 단어를 예측할 때 과거의 정보만 사용하도록 강제할 수 있습니다.

그래서 간단하게 말하면 미래 단어를 가릴 수 있도록 마스킹 하는 기술이라고 합니다.

왜 마스킹 하나?

  • AI가 학습할 때 미래 단어를 미리 보면 답을 보고 문제를 푸는 것과 같아서 학습이 안된다고 합니다.

동작하는 방식

  • 이전 단어들만 참고하고 미래 단어는 못보게 가린다는데 솔직히 이해는 가지 않습니다.

실습 코드


import torch

# 1. 입력 데이터 (단순한 3개 단어 문장, 4차원 임베딩)
seq_len = 3 # 문장 길이 (예: "I love AI")
embed_dim = 4 # 임베딩 차원 (각 단어가 4차원 벡터로 표현)

# 예제 입력 (랜덤 값, 실제는 Transformer 임베딩 사용)
x = torch.randn(seq_len, embed_dim)
print("입력 데이터 (토큰 임베딩):\n", x)

# 2. Query, Key, Value 생성 (Self-Attention에서 사용됨)
W_q = torch.randn(embed_dim, embed_dim) # Query 변환 행렬
W_k = torch.randn(embed_dim, embed_dim) # Key 변환 행렬
W_v = torch.randn(embed_dim, embed_dim) # Value 변환 행렬

Q = x @ W_q # (3,4) x (4,4) = (3,4)
K = x @ W_k
V = x @ W_v



# 3. Attention Score 계산 (Q @ K.T)
attn_scores_no_scaling = torch.matmul(Q, K.T)
attn_scores = torch.matmul(Q, K.T) / (embed_dim ** 0.5)
print("\nAttention Score (원본):\n", attn_scores)

# 4. 마스킹 생성 (미래 단어 가리기)
mask = torch.triu(torch.ones(seq_len, seq_len), diagonal=1) # 상삼각 행렬 생성
mask = mask.bool() # Boolean 형태로 변환
print("\n마스킹 행렬:\n", mask)

# 5. Attention Score에 마스킹 적용
attn_scores.masked_fill_(mask, float('-inf')) # 미래 단어를 -∞로 설정
print("\n마스킹 적용된 Attention Score:\n", attn_scores)

# 6. Softmax 적용 (확률값으로 변환)
attn_weights = torch.softmax(attn_scores, dim=-1)
print("\nSoftmax 후 Attention Weight:\n", attn_weights)

# 7. Attention 가중치 적용하여 최종 값 계산 (가중합)
output = attn_weights @ V # (3,3) x (3,4) = (3,4)
print("\n최종 Attention Output:\n", output)

입력 데이터

입력 데이터 (토큰 임베딩):
tensor([[ 0.9811, 0.1954, -0.8982, -0.1720],
[-0.2018, 0.2038, 1.6621, 1.8928],
[ 0.3604, -0.5018, 1.4016, -0.6515]])

예시 입력 데이터 입니다.

Attention Score (원본)

Attention Score (원본):
tensor([[-7.7534, 9.9981, 4.0247],
[ 0.6387, 9.6488, 5.9596],
[ 1.3511, 10.7251, 7.8433]])

Self-Attention 방식의 점수입니다.

마스킹 행렬

마스킹 행렬:
tensor([[False, True, True],
[False, False, True],
[False, False, False]])

상삼각행렬을 이용하여 마스킹을 설정했습니다.

mask = torch.triu(torch.ones(seq_len, seq_len), diagonal=1)

pytorch에서 triu함수를 쓰면 상삼각행렬을 사용할 수 있는데 아래 처럼 나옵니다.

1 1 1 1
0 1 1 1
0 0 1 1
0 0 0 1

diagonal=1을 사용하면

0 1 1 1
0 0 1 1
0 0 0 1
0 0 0 0

이렇게 변환할 수 있습니다.

  • ✅ 마스킹을 왜 이렇게 하나요?
      - 이렇게 마스킹 방식으로 하기로 알고리즘 적으로 정해져있는 것입니다.
단어단어1단어2단어3
단어1
단어2
단어3

위와 같은 마스킹 방식이 널리 사용되고 있다고 하네요.

마스킹 적용된 Attention Score

마스킹 적용된 Attention Score:
tensor([[-7.7534, -inf, -inf],
[ 0.6387, 9.6488, -inf],
[ 1.3511, 10.7251, 7.8433]])

Attention Score (원본) 중 마스킹 값 true에 위치하는 애들을 -inf로 돌립니다.

Softmax 후 Attention Weight

Softmax 후 Attention Weight:
tensor([[1.0000e+00, 0.0000e+00, 0.0000e+00],
[1.2215e-04, 9.9988e-01, 0.0000e+00],
[8.0390e-05, 9.4686e-01, 5.3057e-02]])

Softmax함수를 돌려서 보면 -inf인 곳은 모두 0으로 변했습니다.

최종 Attention Output

최종 Attention Output:
tensor([[-1.3495, -0.0827, -0.4479, -0.8731],
[ 0.3756, -0.4200, -0.1823, 2.7832],
[ 0.2240, -0.2482, -0.3019, 2.6438]])

value 값과 합쳐진 최종 값을 확인해본다면 masking이 적용됐다고 볼 수 있습니다.