Skip to main content

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 2014Seq2Seq 아키텍처 제안
Neural Machine Translation by Jointly Learning to Align and Translate (Bahdanau et al.)ICLR 2015Additive Attention 도입
Effective Approaches to Attention-based NMT (Luong et al.)EMNLP 2015Multiplicative Attention 제안
Attention Is All You Need (Vaswani et al.)NeurIPS 2017Transformer (NLP 탭에서 상세)