Transformer와 Self-Attention

src/content/documents/deep-learning/transformer-and-self-attention.json

순서대로 읽지 않고, 한 번에 보고 집중한다

RNN·LSTM은 문장을 앞에서부터 순서대로 읽는다. 문장이 길어지면 앞부분의 정보가 옅어지는 장기 의존성 문제를 완전히 벗어나지 못했다. Transformer는 착안점을 바꿨다 — “모든 단어를 다 보되, 중요한 단어에 더 집중하면 되지 않을까?” 문장을 읽으며 마지막에 정리하는 대신, 읽는 동안 중요한 단어에 형광펜을 긋듯 가중치를 매기는 것이 Attention이고, 이 메커니즘을 잘 쓰기 위해 만든 아키텍처가 Transformer다.

Self-Attention: 문장 안에서 서로를 참고한다

Self-Attention은 문장 내 각 단어가 다른 모든 단어와 얼마나 관련 있는지를 계산한다. “고양이가 창문에서 햇살을 받으며 잔다”라는 문장에서, 잔다는 문장 속 다른 단어와의 관계를 계산하면서 특히 고양이가와 강하게 연결된다 — 누가 자는지를 알아야 “잔다”의 의미가 완성되기 때문이다. RNN이 순서대로 처리하는 것과 달리, Self-Attention은 문장 내 모든 단어를 동시에(병렬로) 처리한다는 점도 중요한 차이다.

Query, Key, Value: 관련성을 숫자로 계산하는 방법

요소

역할

비유

Query (질문)

현재 단어가 다른 단어들과 얼마나 연관 있는지 묻는 값

“잔다”가 “누가 자는지”를 묻는 질문

Key (단서)

각 단어가 “나는 이런 단어야”라고 스스로 소개하는 값

“고양이가”의 Key는 “나는 주어야, 잠을 잘 수 있는 대상이야”

Value (정보)

그 단어가 실제로 담고 있는 의미 자체

“고양이가”가 선택됐을 때 “잔다”에게 넘겨줄 “주어=고양이”라는 내용

계산 흐름은 세 단계다. ① Query와 모든 단어의 Key를 비교해 관련성 점수(유사도)를 구하고, ② 그 점수를 Softmax로 합이 1인 가중치로 바꾼 뒤, ③ 이 가중치로 각 단어의 Value를 가중합해 최종 표현을 만든다. 이 과정 전체를 Scaled Dot-Product Attention이라 부른다 — 벡터 차원이 커지면 점수(내적, Dot-Product)도 함께 커져 Softmax가 한쪽으로 쏠리기 쉬운데, 이를 완화하려고 벡터 차원의 제곱근으로 나눠(Scaled) 점수를 조정한다.

코드로 Attention 가중치 계산해보기

실제 학습된 벡터는 아니지만, 메커니즘을 체감하기 위해 “고양이가/창문에서/햇살을/받으며/잔다” 5개 토큰에 임의의 Key·Value 벡터를 부여하고, “잔다”의 Query가 “고양이가”의 Key와 가깝게 설계된 상황을 계산해본다.

import numpy as np

np.random.seed(3)
tokens = ["고양이가", "창문에서", "햇살을", "받으며", "잔다"]
d = 4  # 벡터 차원

K = np.random.randn(5, d)  # 각 단어의 Key 벡터
V = np.random.randn(5, d)  # 각 단어의 Value 벡터

# '잔다'의 Query를 '고양이가'의 Key와 관련 있게 설계 (실제로는 학습으로 정해짐)
q_sleep = K[0] * 0.9 + K[4] * 0.5 + np.random.randn(d) * 0.15

scores = (q_sleep @ K.T) / np.sqrt(d)          # Query-Key 유사도, Scaled
weights = np.exp(scores - scores.max())
weights = weights / weights.sum()               # Softmax

for token, w in zip(tokens, weights):
    print(f"{token}: {w:.3f}")
print("가중치 합:", round(weights.sum(), 3))
고양이가: 0.743
창문에서: 0.055
햇살을: 0.007
받으며: 0.061
잔다: 0.134
가중치 합: 1.0

“잔다”가 만드는 새 표현은 “고양이가”의 Value를 74.3% 반영하고, 나머지 단어는 조금씩만 반영한다. 이렇게 만들어진 “잔다”의 새 표현에는 “고양이가 잔다”라는 문맥이 녹아든다 — 이것이 Self-Attention이 문맥을 이해하는 방식이다.

Multi-Head Attention: 여러 관점에서 동시에 본다

문장 안의 중요한 관계가 하나뿐인 것은 아니다. “고양이가 창문에서 햇살을 받으며 잔다”에서 “잔다”는 “고양이가”(누가)와도, “받으며”(어떻게)와도 관계가 있을 수 있다. Multi-Head Attention은 서로 다른 Query·Key·Value 조합(Head)을 여러 개 두어 각 Head가 다른 종류의 관계에 집중하게 하고, 그 결과를 모두 이어붙여(Concat) 더 풍부한 문맥 표현을 만든다.

문장을 생성하는 Decoder에서는 여기에 Masked Multi-Head Attention이 더해진다 — 다음 단어를 만들 때 아직 만들어지지 않은 미래 단어를 미리 참고하면 안 되므로, 가림막(Mask)으로 미래 위치에는 가중치가 가지 않도록 막는다.

Transformer 구조 한눈에 보기

구성

역할

Encoder

입력 문장을 읽고 Multi-Head Self-Attention과 Feed-Forward로 문맥을 압축한 정보를 만든다

Decoder

Masked Self-Attention으로 지금까지 생성한 부분만 보고, Encoder의 정보를 참고(Cross-Attention)해 다음 단어를 생성한다

Positional Encoding

모든 단어를 동시에 처리하다 보니 순서 정보가 사라지는 것을 보완하기 위해, 각 단어에 위치 정보를 더해준다

RNN처럼 순서대로 처리하지 않고 모든 단어를 병렬로 처리하기 때문에, 학습 속도와 긴 문맥 처리 모두에서 이득을 얻는다. 다만 모든 단어 쌍의 관계를 계산해야 해서, 문장 길이가 n일 때 연산량이 O(n²)로 늘어난다는 비용도 함께 따라온다.

정리

Transformer는 순차 처리 대신 Self-Attention으로 문장 내 모든 단어 쌍의 관계를 한 번에 계산해, RNN·LSTM의 장기 의존성 문제와 순차 처리로 인한 속도 한계를 함께 풀었다. Query·Key·Value로 관련성을 계산하고, Multi-Head로 여러 관점을 동시에 보며, Positional Encoding으로 순서 정보를 보완한다. 이 구조가 다음 글에서 다룰 BERT와 GPT 계열의 공통 기반이 된다.

참고 자료

Attention Is All You Need — Vaswani et al. (2017) — Transformer와 Self-Attention을 처음 제안한 원 논문 (2026-08-07 확인)

댓글 0

댓글을 불러오는 중…