seq2seq 인터랙티브 노트
Sutskever's List · Bridge 4 → 5 · 2014

seq2seq — 시퀀스가
시퀀스를 만든다

2014년, Sutskever·Vinyals·Le는 LSTM 두 개를 이어붙였다. 하나는 문장을 고정 길이 벡터 하나로 압축하고(인코더), 다른 하나는 그 벡터를 풀어 새 문장을 만든다(디코더). 신경망만으로 기계번역이 통계 기반 시스템을 이긴 첫 순간 — 그리고 그 구조의 병목이 곧 어텐션과 트랜스포머를 부른다. 이 페이지의 모든 데모는 외부 라이브러리 없이 브라우저에서 직접 실행되며, 미니 seq2seq가 지금 이 페이지 안에서 실제로 학습된다.

2014.06Cho et al., RNN Encoder–Decoder
(GRU의 탄생)
2014.09Sutskever·Vinyals·Le,
seq2seq (arXiv:1409.3215)
2014.09Bahdanau·Cho·Bengio,
어텐션 (RNNsearch)
2014.12NeurIPS 발표 —
"최소한의 혁신, 최대의 결과"
2016.09Google 번역 GNMT 전환
(seq2seq + 어텐션 실서비스)
2017.06Transformer —
순환 없는 seq2seq

§1두 개의 LSTM: 인코더와 디코더

4장까지의 RNN은 입력과 출력이 한 스텝씩 맞물려 있었다. 문자 하나를 읽으면 다음 문자 하나를 예측한다. 그런데 번역은 다르다 — 입력은 영어 5단어, 출력은 프랑스어 7단어일 수 있다. 길이도 다르고, 어순도 다르다. 가변 길이 시퀀스를 가변 길이 시퀀스로 사상하는 문제.

seq2seq의 답은 문제를 둘로 쪼개는 것이다. 인코더 LSTM이 입력을 끝까지 읽고 마지막 상태(은닉 상태 h와 셀 상태 C)를 문맥 벡터 c로 삼는다. 디코더 LSTM은 c를 초기 상태로 받아, 직전에 자기가 생성한 단어를 다시 입력으로 넣으며(자기회귀) <EOS>가 나올 때까지 한 단어씩 출력한다.

단, 논문의 LSTM은 한 층이 아니라 4층으로 쌓여 있다. 그래서 실제 c는 벡터 하나가 아니라 층마다 하나씩 있는 (h, C) 묶음이고, 인코더 층 l의 마지막 상태가 디코더 층 l의 초기 상태로 1:1로 넘어간다. 아래 첫 데모는 흐름을 보기 위해 1층으로 단순화했고, 두 번째 데모가 층을 쌓은 실제 구조다.

층 l = 1…L,  C는 셀 상태.  층 1의 입력은 단어,  층 l>1의 입력은 바로 아래층의 h
인코더:  (h_t^l, C_t^l) = LSTM_enc^l((h_{t-1}^l, C_{t-1}^l), h_t^{l-1})      h_t^0 = x_t
문맥:    c = {(h_T^l, C_T^l)}_{l=1…L}           ← 문장 전체가 층별 (h, C) 묶음 하나로
디코더:  (s_j^l, S_j^l) = LSTM_dec^l((s_{j-1}^l, S_{j-1}^l), s_j^{l-1})      s_j^0 = y_{j-1}
         (s_0^l, S_0^l) = (h_T^l, C_T^l)        ← 같은 층끼리 이어받음
         p(y_j | y_<j, x) = softmax(W · s_j^L)   ← 출력은 맨 위층에서만
목적:    P(y_1…y_U | x_1…x_T) = Π_j p(y_j | c, y_<j)
DEMO

인코더 → c → 디코더, 한 스텝씩

"I am a student"가 프랑스어 "je suis étudiant"로 번역되는 과정을 스텝별로 따라가 보자. 인코더가 단어를 읽을 때마다 은닉 상태(색 띠)가 갱신되고, 문장 전체가 벡터 c 하나에 담긴 뒤, 디코더가 그것만 보고 단어를 하나씩 뽑아낸다.

인코더 입력 (영어)
인코더 은닉 상태 h_t → 문맥 벡터 c
디코더 출력 (프랑스어)
스텝 ▶ 버튼을 눌러 시작.
DEMO

층을 쌓으면: 다층 LSTM 인코더–디코더

가로는 시간, 세로는 층이다. 층 1은 단어를 입력으로 받고, 그 위층은 바로 아래층의 은닉 상태 h를 입력으로 받는다. 주황 화살표가 문맥 벡터 c의 정체다. 인코더의 각 층이 마지막 (h, C)를 디코더의 같은 층에 넘긴다. 층 수를 바꿔 보자.

층을 쌓은 이유: 논문은 깊은 LSTM이 얕은 LSTM보다 확연히 좋았고 층을 하나 더할 때마다 perplexity가 10% 가까이 줄었다고 보고한다. 원논문의 실제 규모: 4층 LSTM × 층당 1,000셀, 1,000차원 단어 임베딩, 입력 어휘 16만 / 출력 어휘 8만, 총 3억 8,400만 파라미터. 8-GPU 머신에서 약 10일 학습. WMT'14 영→불에서 5개 모델 앙상블 + 빔 서치로 BLEU 34.8 — 구문 기반 SMT 베이스라인(33.3)을 신경망 단독으로 처음 넘어섰다.

§2고정 길이 병목

구조를 다시 보자. 입력이 5단어든 50단어든, 디코더에게 전달되는 것은 고정 차원 벡터 c 하나다. 문장이 길어질수록 같은 크기 벡터에 더 많은 정보를 밀어 넣어야 하고, 압축은 점점 손실적이 된다. 인코더가 문장 끝에 도달할 무렵, 앞부분의 정보는 이미 흐려져 있다.

이 병목은 추측이 아니라 측정된 사실이다. 이듬해 Bahdanau·Cho·Bengio가 고정 벡터 인코더–디코더(RNNencdec)의 번역 품질을 문장 길이별로 재 보니, 약 20단어를 넘어서면 BLEU가 급락했다.

DEMO

문장이 길어지면 벡터에 무슨 일이?

슬라이더로 입력 문장 길이를 늘려보자. 단어(파란 칸)는 늘어나는데 문맥 벡터의 칸 수는 그대로다. 앞쪽 단어일수록 인코더 끝에 도달할 때까지 더 많은 스텝을 살아남아야 해서 정보가 흐려진다(투명해지는 칸).

⤵ 전부 이 벡터 하나로
CHART

문장 길이 vs BLEU — 병목의 증거

Bahdanau et al. (2015) 그림 2의 고정 벡터 모델(RNNencdec-50) 곡선을 근사 재구성한 것. 20단어 부근을 정점으로, 문장이 길어질수록 번역 품질이 무너진다. 이 곡선이 어떻게 해소됐는지는 §6에서 본다.

RNNencdec-50 (고정 벡터 인코더–디코더, 50단어 이하 문장으로 학습)
주의: RNNencdec은 게이트 유닛·은닉 1,000의 Cho 계열 인코더–디코더로, Sutskever의 4층 LSTM + 입력 역순 모델과 같은 모델이 아니다. Sutskever 논문은 오히려 자기 모델이 35단어 미만에서는 성능 저하가 없었고 가장 긴 문장에서만 약간 떨어졌다고 보고한다. 병목이 사라진 것이 아니라, 깊은 층과 역순 트릭(§3)이 무너지는 지점을 뒤로 밀어낸 셈이다.

§3입력을 거꾸로 넣었더니

논문에서 가장 유명한 발견은 어이없을 만큼 단순하다. 소스 문장의 단어 순서만 뒤집어서 넣었더니 — 타깃은 그대로 두고 — 퍼플렉시티가 5.8 → 4.7로 내려가고 단일 모델 BLEU가 25.9 → 30.6으로 뛰었다.

왜일까? 순방향이면 소스의 첫 단어를 읽고 나서 타깃의 첫 단어를 생성할 때까지 항상 문장 길이만큼의 스텝이 걸린다. 역순이면 소스 첫 단어가 인코더의 맨 마지막에 읽히므로, 타깃 첫 단어와의 거리가 1로 줄어든다. 전체 평균 거리는 정확히 같지만, 짧은 의존성이 여럿 생겨서 경사가 흐를 첫 통로가 열리고 최적화가 굴러가기 시작한다.

DEMO

단어 사이 거리 재보기

소스 x₁…x_T를 읽은 뒤 타깃 y₁…y_T를 생성한다고 하자(단조 정렬 가정). x_j를 읽은 시점부터 y_j를 생성하는 시점까지의 스텝 수가 곧 "정보가 살아남아야 하는 거리"다. 역순 토글을 눌러 거리들이 어떻게 재배치되는지 보자.

인코더가 읽는 순서
디코더가 생성하는 순서 · 아래 숫자 = x와 y 사이 거리
퍼플렉시티
5.8 → 4.7
역순 입력만으로
단일 모델 BLEU
25.9 → 30.6 ▲4.7
타깃은 그대로, 소스만 역순
평균 의존 거리
변화 없음
짧은 의존성 여럿 ↔ 긴 의존성 여럿의 재배치
이 트릭이 필요했다는 사실 자체가 병목의 증거다. 벡터 하나가 문장 전체를 무리 없이 담을 수 있다면 읽는 순서는 중요하지 않았을 것이다. 역순 트릭은 한동안 seq2seq 번역의 표준 관행이 됐고 — 어텐션이 병목 자체를 없애면서 조용히 은퇴했다.

§4브라우저에서 직접 학습하는 미니 seq2seq

역순 트릭이 정말 효과가 있는지 지금 여기서 실험해 보자. 아래 데모는 진짜 LSTM 인코더–디코더 두 벌을 자바스크립트로 구현한 것이다(은닉 32차원, 어휘 6개). 과제는 복사: a b c d 네 글자로 된 무작위 문자열(길이 2–6)을 읽고 똑같이 출력하면 성공. 단순해 보이지만 첫 글자를 출력하려면 인코더 처음에 읽은 정보가 문장 끝까지 살아남아야 하는, 병목이 그대로 드러나는 과제다.

모델 A는 입력을 그대로, 모델 B는 역순으로 읽는다. 그 외 조건(구조·초기화·학습 데이터)은 동일하다. 복사 과제에서 순방향은 모든 글자의 의존 거리가 똑같이 T지만, 역순은 첫 글자의 거리가 1이 된다 — §3의 상황 그대로다.

LIVE TRAINING

모델 A(순방향) vs 모델 B(역순) — 동일 조건 학습 경쟁

학습은 CPU에서 실행되며 수십 초면 충분하다(1,500 배치 전후부터 차이가 벌어진다). 손실 곡선도 곡선이지만, 진짜 차이는 아래 길이별 정확도에서 드러난다 — 학습 중간중간 눌러 비교해 보자.

0 batch
모델 A — 입력 그대로 모델 B — 입력 역순 y축: 토큰당 교차 엔트로피 (무작위 추측 ≈ 1.79)
모델 A — 순방향 입력
아직 학습 전
모델 B — 역순 입력
아직 학습 전

길이별 정확도 — 병목과 일반화

학습은 길이 2–6에서만 했다. 길이 7–9는 모델이 한 번도 본 적 없는 학습 범위 밖(extrapolation) 구간 — 문장이 길어질수록 BLEU가 떨어지던 §2 곡선의 미니어처를 여기서 재현할 수 있다.

직접 번역시켜 보기

이 데모의 구현 노트 (LSTM 수식과 학습 설정)
인코더/디코더 각각: 표준 LSTM 1층, 은닉 32차원
  [i, f, o, g] = W·[x; h_prev] + b,  c = σ(f)∘c_prev + σ(i)∘tanh(g),  h = σ(o)∘tanh(c)
어휘: {a, b, c, d, <EOS>, <SOS>} — 원-핫 입력
학습: teacher forcing, Adam(lr 0.003), 그래디언트 클리핑 5.0, 배치 8
디코더 초기 상태 = 인코더의 마지막 (h, c) — 논문과 동일한 "문맥 벡터" 방식
A와 B는 매 배치 같은 문장을 받는다. B만 인코더 입력을 뒤집는다.

§5빔 서치 — 한 단어씩의 탐욕을 넘어서

디코더는 매 스텝 확률 분포를 내놓을 뿐, 문장 전체의 최적 조합을 보장하지 않는다. 매번 가장 확률 높은 단어만 고르면(그리디) 초반의 한 번의 실수가 끝까지 발목을 잡는다. 빔 서치는 상위 B개의 부분 가설을 병렬로 유지하며 전개하다가, 누적 로그확률이 가장 높은 완성 문장을 고른다.

원논문은 빔 폭 12를 썼지만, 재미있게도 빔 폭 2만으로 이득의 대부분을 얻었다고 보고한다. 심지어 빔 폭 1(그리디)도 꽤 잘 동작했다 — 모델이 좋으면 탐색은 거들 뿐.

DEMO

방금 학습한 모델 B로 빔 서치 돌려보기

§4에서 학습한 모델 B(역순 입력)의 실제 확률로 빔 서치를 전개한다. 각 열이 디코딩 한 스텝. 테두리가 초록인 가설만 살아남고, 흐려진 가설은 빔에서 잘린 것. 학습을 먼저 돌려야 의미 있는 확률이 나온다.

§6유산 — 병목이 어텐션을 부르다

seq2seq는 서츠케버 목록에 없다. 하지만 목록의 5장 전체가 이 논문이 깔아놓은 무대 위에서 진행된다. "문장 전체를 벡터 하나로"라는 설계는 힌턴의 생각 벡터(thought vector) 직관의 구현이었고, 동시에 그 직관의 한계 증명이 됐다. 압축이 병목이라면? 답은 압축을 포기하는 것이었다.

Bahdanau 어텐션은 c를 하나로 고정하는 대신 디코더 스텝마다 다시 만든다 — 소스 전체를 훑어 지금 필요한 단어에 가중치를 주면서. 그리고 3년 뒤 트랜스포머는 "그럼 순환이 애초에 왜 필요한가"라고 묻는다. 인코더–디코더라는 뼈대, 자기회귀 생성, 빔 서치, <EOS> 토큰 — 오늘의 LLM이 물려받은 유산 대부분이 이 6페이지 논문에서 왔다.

seq2seq (2014):   c = {(h_T^l, C_T^l)}_l         ← 고정 크기 묶음 하나에 전부
어텐션 (2015):    c_j = Σ_t α_{jt}·h_t            ← 생성 스텝마다 소스 전체를 다시 조회
트랜스포머 (2017): 순환 제거, attention만으로       ← 5장에서 계속
CHART

고정 벡터 vs 어텐션 — 병목이 사라지다

§2에서 본 고정 벡터 곡선(RNNencdec-50)에 같은 논문의 어텐션 모델(RNNsearch-50)을 겹쳤다. 매 생성 스텝마다 소스 전체를 다시 보는 어텐션은 60단어까지 거의 평탄하다. 병목은 실재했고, 어텐션이 그것을 걷어냈다.

RNNencdec-50 (고정 벡터) RNNsearch-50 (어텐션, 5장 예고편)
WMT'14 영→불 BLEU
34.8
앙상블 5 + 빔 12, SMT 33.3을 추월
SMT 1000-best 재순위화
36.5
당시 SOTA(37.0)에 근접
서츠케버의 자평
"최소한의 혁신"
2014 NeurIPS — 새 부품 없이 조립만으로

§7이해도 점검

각 문제의 답을 고르면 해설이 열린다. 0 / 6