Seq2Seq — 인코더-디코더 구조
Seq2Seq(Sequence-to-Sequence)는 가변 길이의 입력 시퀀스를 가변 길이의 출력 시퀀스로 변환하는 아키텍처입니다. 기계 번역, 요약, 대화 생성 등에 사용됩니다.
핵심 아이디어
입력 시퀀스를 **인코더(Encoder)**가 고정 크기 벡터(컨텍스트 벡터)로 압축하고, **디코더(Decoder)**가 이 벡터를 기반으로 출력 시퀀스를 생성합니다.
동작 방식
import torch
import torch.nn as nn
class Encoder ( nn . Module ):
def __init__ ( self , vocab_size , embed_dim , hidden_dim , num_layers = 1 ):
super (). __init__ ()
self .embedding = nn.Embedding(vocab_size, embed_dim)
self .lstm = nn.LSTM(embed_dim, hidden_dim, num_layers, batch_first = True )
def forward ( self , x ):
# x: (배치, 시퀀스)
embedded = self .embedding(x) # (배치, 시퀀스, embed_dim)
outputs, (h_n, c_n) = self .lstm(embedded)
return h_n, c_n # 컨텍스트 벡터
class Decoder ( nn . Module ):
def __init__ ( self , vocab_size , embed_dim , hidden_dim , num_layers = 1 ):
super (). __init__ ()
self .embedding = nn.Embedding(vocab_size, embed_dim)
self .lstm = nn.LSTM(embed_dim, hidden_dim, num_layers, batch_first = True )
self .fc = nn.Linear(hidden_dim, vocab_size)
def forward ( self , x , hidden ):
# x: (배치, 1) — 한 토큰씩 생성
embedded = self .embedding(x)
output, hidden = self .lstm(embedded, hidden)
prediction = self .fc(output) # (배치, 1, vocab_size)
return prediction, hidden
class Seq2Seq ( nn . Module ):
def __init__ ( self , encoder , decoder , device ):
super (). __init__ ()
self .encoder = encoder
self .decoder = decoder
self .device = device
def forward ( self , src , trg , teacher_forcing_ratio = 0.5 ):
batch_size = src.size( 0 )
trg_len = trg.size( 1 )
trg_vocab_size = self .decoder.fc.out_features
outputs = torch.zeros(batch_size, trg_len, trg_vocab_size).to( self .device)
# 인코딩
hidden = self .encoder(src)
# 디코딩 시작 토큰
input_token = trg[:, 0 : 1 ] # <SOS>
for t in range ( 1 , trg_len):
output, hidden = self .decoder(input_token, hidden)
outputs[:, t:t + 1 ] = output
# Teacher Forcing: 확률적으로 정답 또는 예측 사용
if torch.rand( 1 ).item() < teacher_forcing_ratio:
input_token = trg[:, t:t + 1 ] # 정답 사용
else :
input_token = output.argmax( 2 ) # 예측 사용
return outputs
Teacher Forcing
학습 시 디코더의 입력으로 이전 시점의 정답 을 사용하는 기법입니다. 학습을 안정화하고 수렴을 가속하지만, 추론 시에는 정답을 사용할 수 없으므로 노출 편향(Exposure Bias)이 발생합니다.
전략 학습 안정성 추론 성능 Teacher Forcing 100% 높음 노출 편향 발생 자유 실행 (0%) 낮음 편향 없음 스케줄 샘플링 (점진적 감소) 중간 양호
Attention의 등장 배경
기본 Seq2Seq의 근본적 한계는 **정보 병목(Information Bottleneck)**입니다. 아무리 긴 입력 시퀀스라도 고정 크기의 컨텍스트 벡터 하나로 압축해야 합니다. 입력이 길어지면 앞쪽 정보가 소실됩니다.
2015년 Bahdanau et al.은 이 문제를 해결하기 위해 Attention 메커니즘 을 제안했습니다. 디코더가 출력을 생성할 때, 인코더의 모든 시점의 은닉 상태 를 참조하여 현재 생성에 관련 있는 부분에 집중(attend)합니다.
Attention 메커니즘의 상세한 수학적 원리와 Self-Attention, Multi-Head Attention, 그리고 이를 기반으로 한 Transformer 아키텍처는 NLP 탭 에서 다룹니다. Seq2Seq + Attention의 성공이 “Attention만으로 충분하다(Attention Is All You Need)“는 Transformer의 탄생으로 이어졌습니다.
RNN 기반 Seq2Seq는 (1) 인코더의 순차 처리로 병렬화가 불가능하고, (2) 기본 형태에서 정보 병목 문제가 있으며, (3) Attention을 추가해도 RNN의 근본적인 순차 의존성은 해결되지 않습니다. Transformer는 Self-Attention으로 이 모든 문제를 한 번에 해결합니다.
참고 논문
논문 학회/연도 핵심 기여 Sequence to Sequence Learning with Neural Networks (Sutskever et al.) NeurIPS 2014 Seq2Seq 아키텍처 제안 Neural Machine Translation by Jointly Learning to Align and Translate (Bahdanau et al.) ICLR 2015 Additive Attention 도입 Effective Approaches to Attention-based NMT (Luong et al.) EMNLP 2015 Multiplicative Attention 제안 Attention Is All You Need (Vaswani et al.) NeurIPS 2017 Transformer (NLP 탭에서 상세)