Seq2Seq에서 Transformer까지: 문맥 누적에서 직접 참조로 · 2편

Attention Seq2Seq - 마지막 상태만 보지 말고 직접 보자

Vanilla Seq2Seq의 병목을 어떻게 해결할까? Decoder가 Encoder의 모든 hidden state를 "필요에 따라" 직접 참고하는 방식.

지난 편 복습

1편의 핵심은 하나였다. Vanilla Seq2Seq는 Encoder의 마지막 hidden state 하나($h_T$)에 모든 정보를 압축해서 Decoder에 넘긴다. 문장이 길어질수록 앞쪽 정보가 희석되고, Decoder는 항상 같은 벡터 하나만 본다.

이번 편의 질문은 간단하다. 왜 마지막 상태만 봐야 하지?

Attention의 아이디어

Vanilla Seq2Seq는 $c = h_T$ 하나에 의존했다. Attention은 이 구조를 바꾼다. Decoder가 $h_1, h_2, \ldots, h_n$을 전부 볼 수 있게 개방하고, 현재 Decoder 상태 $S_k$에 따라 어떤 $h_i$를 더 많이 참고할지 동적으로 결정한다.

h1, h2, h3
↑   ↑   ↑
|___|___|
    ↑
Decoder (S_k)
    ↓
c_k = 가중 합 (매 시점 다름)

핵심은 context vector가 고정되지 않는다는 것이다. Decoder 상태가 바뀔 때마다 $c_k$도 달라진다.

Query, Key, Value로 읽는 Attention

Attention의 변수들은 $Q, K, V$에 정확히 대응된다.

개념 Attention Seq2Seq에서의 실체 역할
Query ($Q$) 디코더의 현재 상태 $S_k$ “지금 어떤 입력을 봐야 하지?”
Key ($K$) 인코더의 은닉 상태 $h_i$ “내가 무슨 정보인지 알려줄게”
Value ($V$) 인코더의 은닉 상태 $h_i$ “관련 있다면 내 실제 정보를 가져가”

여기서 $K$와 $V$가 모두 $h_i$로 같다는 점이 중요하다. 이 사실이 나중에 Self-Attention으로 이어지는 결정적인 연결고리가 된다. 이후 편에서 다시 돌아온다.

Attention 계산 단계

1단계: 관련도 점수 계산

현재 Decoder 상태($Q = S_k$)와 각 Encoder 상태($K = h_i$)를 내적으로 비교한다.

\[\text{score}(Q, K_i) = \langle S_k,\, h_i \rangle\]

내적값이 클수록 “$h_i$가 지금 Decoder 상태와 관련이 높다”는 의미다.

2단계: 가중치 변환

점수들을 합이 1이 되는 확률 분포로 바꾼다.

\[w_{ki} = \text{softmax}(\text{score}(Q, K_i)) = \frac{\exp(\langle S_k, h_i \rangle)}{\sum_j \exp(\langle S_k, h_j \rangle)}\]

3단계: 동적 context vector 생성

가중치를 $V_i\,(= h_i)$에 곱해 합산한다.

\[c_k = \sum_i w_{ki} \cdot h_i\]

세 단계를 하나로 묶으면 Attention의 전체 수식이 된다.

\[c_k = \sum_i \text{softmax}(\langle S_k, h_i \rangle) \cdot h_i\]

구체적으로 어떻게 달라지나

예를 들어 “Jane went to the store”를 번역한다고 하자. Encoder는 각 토큰을 읽으며 $h_1(\text{Jane}),\; h_2(\text{went}),\; h_3(\text{to the}),\; h_4(\text{store})$를 만든다.

“제인이”를 생성할 때 $Q = S_1$은 $h_1$(“Jane”)과 높은 유사도를 보인다. 결과적으로 $w \approx [0.90,\, 0.04,\, 0.03,\, 0.03]$이 되어 $c_1 \approx h_1$에 집중된다.

“가게에”를 생성할 때는 Decoder 상태가 $S_2$로 바뀌면서 $h_4$(“store”)와의 유사도가 높아진다. $w \approx [0.02,\, 0.03,\, 0.03,\, 0.92]$로 이번엔 $c_2 \approx h_4$에 집중된다.

Vanilla Seq2Seq에서는 두 시점 모두 같은 $c = h_T$를 사용했다. Attention은 매 시점마다 다른 $c_k$를 계산한다.

Attention이 해결한 것, 그리고 남은 것

Attention으로 Encoder 쪽 문제는 해결됐다. 마지막 상태 하나로의 병목이 사라지고, Decoder가 필요한 입력 위치를 매 시점마다 직접 참조할 수 있게 됐다.

하지만 Decoder는 여전히 이전 상태에 의존하는 순차 구조다.

\[S_k = f(S_{k-1},\; \text{emb}(y_{k-1}),\; c_k)\]

$c_k$는 이제 Attention으로 동적으로 계산되지만, $S_k$를 만들기 위해서는 여전히 $S_{k-1}$이 필요하다. 출력 쪽 문맥은 여전히 순서대로 누적 전달된다.

이것이 다음 편에서 다룰 문제다.

요약

  Vanilla Seq2Seq Attention Seq2Seq
Encoder 참조 $h_T$ 하나 $h_1 \sim h_n$ 전부
Context vector 고정 동적 (매 시점 다름)
Q, K, V 해당 없음 $Q=S_k,\; K=h_i,\; V=h_i$
Encoder 병목 있음 없음
Decoder 순차성 있음 여전히 있음

핵심은 이것이다.

Attention은 마지막 상태 하나에 의존하지 않고, 필요한 encoder 상태를 매번 직접 참조한다.

다음 편 예고

Attention은 Encoder 쪽 정보 접근을 해결했지만, Decoder 자체는 여전히 순차 구조를 유지한다. 다음 편에서는 이 남은 문제가 왜 Transformer 등장의 동기가 되는지 살펴본다.