트랜스포머·PEFT 2일 과정4장 · Transformer Decoder와 작은 번역기5 / 17← 이전목차다음 →MetaContents

4장. Transformer Decoder와 작은 번역기

Cross-Attention: 원문을 흘끗 보기

번역가는 번역문을 쓰다가 막히면 원문을 다시 들여다봅니다. "지금 학생 다음을 써야 하는데, 원문의 어느 낱말을 봐야 하지?" 이 물음이 Query 이고, 원문의 낱말들이 Key 와 Value 입니다. 1장의 Seq2Seq 에 붙였던 Attention 이 Transformer 에서는 Cross-Attention 이라는 이름으로 Decoder 블록 안에 들어갑니다.

왼쪽 Encoder 가 I am a student 의 문맥 표현을 Key 와 Value 로, 오른쪽 Decoder 의 Masked Self-Attention 이 시작, 저는, 학생으로 Query 를 보내 가운데 Cross-Attention 에서 가중치 shape 3, 4 를 만들고 다음 토큰 입니다를 내는 강사자료 그림

그림 왼쪽 Encoder 상자는 입력 4토큰(I am a student)의 문맥 표현을 만들어 Key 와 Value 로 보냅니다. 오른쪽 Decoder 상자는 지금까지 쓴 3토큰(<시작> 저는 학생)으로 Query 를 만듭니다. 가운데에서 softmax(QKᵀ / √d_k) V 를 계산하면 가중치 표의 shape 은 (3, 4) 입니다. 출력 위치 3개가 각각 입력 4개를 얼마나 참고할지 정한 표입니다. Query 와 Key 의 길이가 달라도 됩니다.

Encoder Self-Attention, Masked Self-Attention, Cross-Attention 세 가지의 재료와 가림을 견준 그림

세 Attention 의 계산식은 같습니다. 다른 것은 Q·K·V 를 어디서 가져오는지와 가림판을 쓰는지 둘뿐입니다.

세 가지 Attention 견주기

종류Query 출처Key·Value 출처가림가중치 shape(이 예)
Encoder Self-Attention입력 문장입력 문장패딩만(4, 4)
Masked Self-Attention출력 문장출력 문장패딩 + 미래(3, 3)
Cross-Attention출력 문장(Decoder)입력 문장(Encoder 출력)입력의 패딩만(3, 4)

짧은 예시

Python
import numpy as np

# default_rng(0): 씨앗 0 으로 고정한 난수 생성기. 매번 같은 숫자가 나온다
rng = np.random.default_rng(0)
d_k = 4                               # 벡터 한 줄의 길이(작게 잡았다)

Q = rng.normal(size=(3, d_k))         # Decoder 쪽 3토큰: <시작> 저는 학생
K = rng.normal(size=(4, d_k))         # Encoder 출력 4토큰: I am a student
V = rng.normal(size=(4, d_k))         # Key 와 같은 4토큰의 내용

# 점수 = Q @ K.T / √d_k. K.T 는 (4, 4) 를 뒤집은 (d_k, 4) 라서 (3, 4) @ (4, 4) = (3, 4)
scores = Q @ K.T / np.sqrt(d_k)
# 행마다 Softmax. Cross-Attention 에서는 원문 전체를 봐도 되므로 미래 가림판이 없다
weights = np.exp(scores) / np.exp(scores).sum(axis=1, keepdims=True)
out = weights @ V                     # (3, 4) @ (4, 4) = (3, 4)

print(scores.shape, weights.shape, out.shape)   # 결과: (3, 4) (3, 4) (3, 4)
print(weights.sum(axis=1).round(2))             # 결과: [1. 1. 1.]

이 코드가 뜻하는 것

번역문 3토큰이 원문 4토큰을 얼마나 들춰 볼지 정하는 비율표를 만든 코드입니다. 원문을 다 읽었으므로 미래를 가릴 필요가 없습니다. 여기서 "무엇을 찾나"가 Q, "원문 낱말의 제목표"가 K, "원문 낱말의 내용"이 V 입니다.

줄하는 일쉽게 말하면
Q = rng.normal(size=(3, d_k))Decoder 쪽 3행번역문에서 나온 질문 3개
K, V 의 size=(4, d_k)Encoder 쪽 4행원문 낱말 4개의 제목과 내용
Q @ K.T / np.sqrt(d_k)(3, 4) 점수표질문마다 원문 낱말과 맞춰 본 점수
weights @ V비율대로 내용 섞기원문을 참고해 만든 메모 3장

shape 만 보면 됩니다. 행 수는 Query(번역문 길이), 열 수는 Key(원문 길이)를 따릅니다. 실습 2의 번역기는 이 계산을 Decoder 층마다 한 번씩, 4개 헤드로 나눠 합니다.

주의할 점

  • Cross-Attention 의 Key·Value 는 Encoder 의 마지막 층 출력에서 옵니다. Decoder 의 모든 층이 같은 Encoder 출력을 참고합니다.
  • Decoder-only 모델(GPT, Qwen)에는 Encoder 가 없으므로 Cross-Attention 도 없습니다. 5장에서 이 구조를 봅니다.
← 이전 절4장 · Masked Self-Attention: 뒷장을 가리고 풀기다음 절 →4장 · Decoder 블록과 전체 조립