Vanilla Seq2Seq - 마지막 상태에 의존하던 구조
Seq2Seq의 기본 구조를 이해하려면 먼저 "입력 정보를 하나의 벡터로 압축한다"는 사실부터 받아들여야 합니다. 마지막 hidden state에 모든 정보를 담는 방식, 그리고 그 구조가 가진 근본적 한계.
들어가며
이 시리즈는 Seq2Seq에서 Transformer까지의 진화를 따라가면서, 각 단계에서 어떤 문제가 있었고 어떻게 해결했는지 살펴본다. 핵심 주제는 하나다: 정보를 어떻게 전달할 것인가.
첫 번째 편에서는 가장 기본적인 형태인 Vanilla Seq2Seq를 본다.
Encoder와 Decoder
Seq2Seq 모델은 두 부분으로 나뉜다.
- Encoder: 입력 문장을 읽고 하나의 벡터로 압축한다
- Decoder: 그 벡터를 받아 출력 문장을 한 단어씩 생성한다
두 부분 모두 보통 RNN, LSTM, GRU 계열로 구성된다.
문맥의 누적: Encoder의 동작 방식
Encoder는 입력 토큰을 순서대로 읽으며 hidden state를 업데이트한다. 입력이 $x_1, x_2, x_3$일 때:
\[h_1 = \text{encoder}(\text{emb}(x_1))\] \[h_2 = \text{encoder}(h_1,\; \text{emb}(x_2))\] \[h_3 = \text{encoder}(h_2,\; \text{emb}(x_3))\]여기서 눈여겨 봐야할 부분은 $h_3$이 세 번째 토큰만의 정보가 아니라는 점이다. $h_1 \rightarrow h_2 \rightarrow h_3$으로 흐르며 앞선 문맥이 순서대로 누적된 상태다.
정보의 병목: Decoder에게 넘어가는 단 하나의 벡터
Encoder의 계산이 끝나면 Decoder가 출력을 시작한다. Vanilla Seq2Seq에서 Decoder는 $h_1, h_2, h_3$을 전부 보지 않는다. 오직 마지막 hidden state만 전달받는다. 이를 문맥 벡터(context vector, $c$)라고 부른다.
\[c = h_T\]Decoder는 이 벡터 하나를 시작으로, 문장이 끝날 때까지 매 시점 동일한 $c$에 의존해 출력을 이어나간다.
\[S_k = f(S_{k-1},\; \text{emb}(y_{k-1}),\; c)\]Vanilla Seq2Seq의 한계
이 구조는 단순하고 구현이 쉽지만, 문장이 길어질수록 문제가 생긴다.
정보 병목: 고정된 크기의 벡터 $c$ 하나에 입력 문장 전체의 정보를 담아야 한다. 문장이 길수록 앞쪽 정보가 $h_T$에 달하기까지 여러 단계를 거치며 희석된다. LSTM의 forget gate가 이를 어느 정도 완화하지만, 구조적 한계는 그대로 남는다.
고정된 참조: Decoder “제인이”를 생성할 때와 “가게에”를 생성할 때, 참고하는 정보는 항상 같은 $c$다. 출력 시점마다 입력의 다른 부분을 집중해서 봐야 한다는 직관과 맞지 않는다.
요약
| Vanilla Seq2Seq | |
|---|---|
| Encoder 출력 | $h_T$ 하나 |
| Context vector | 고정 ($c = h_T$) |
| Decoder 참조 | 항상 같은 $c$ |
| 긴 문장 성능 | 급격히 저하 |
핵심은 이것이다.
Vanilla Seq2Seq는 입력 문맥을 순서대로 누적하고, 마지막 상태 하나에 의존한다.
다음 편 예고
다음 편에서는 이 병목을 해결하는 방법을 본다. Decoder가 $h_1 \sim h_n$을 전부 보고, 필요한 상태를 매 시점마다 직접 참조하는 방식이다.
Enjoy Reading This Article?
Here are some more articles you might like to read next: