Seq2Seq의 Decoder구현하기: Input Feeding 기반으로~
앞서 Encoder와 Attention 메커니즘을 직접 구현해보았는데요, 이번에는 Decoder를 구현해봅니다.
이 글에서는 특히 Input Feeding 구조를 사용하는 LSTM 기반 Decoder를 소개합니다.
1. Decoder의 구조와 역할은?
Seq2Seq 모델의 Decoder는 번역할 문장의 출력 시퀀스를 생성하는 역할을 합니다.
Decoder는 매 타임스텝마다 다음과 같은 과정을 반복합니다:
- 이전에 생성한 출력 벡터(h_t_1_tilde)와 현재 입력 단어 임베딩(emb_t)을 결합하여 RNN에 전달
- RNN을 통해 현재 시점의 hidden state와 output을 계산
- 이 output은 다음 토큰을 예측하거나 다음 time-step의 context로 사용됩니다
2. Input Feeding이란?
기존 RNN 기반 Decoder는 매 시점마다 단순히 단어 임베딩만 입력으로 받았습니다. 하지만 Input Feeding 구조는 다음과 같은 방식으로 개선됩니다:
"이전 time-step에서 생성된 출력 벡터(또는 context vector)를 현재 입력 임베딩과 함께 RNN에 넣어주는 방식입니다."
이렇게 하면 Decoder는 직전 예측 결과를 참고하여 더 안정적인 예측을 수행할 수 있고, Attention 정보를 매 시점 반영할 수 있습니다.
Luong et al.(2015)의 논문에서 처음 제안되었으며, attention과의 궁합도 매우 좋습니다.
3. Teacher Forcing이란?
학습 시에는 다음 단어를 예측할 때 모델의 예측 결과 대신 정답(ground truth)을 입력으로 사용하는 전략이 자주 사용됩니다. 이를 Teacher Forcing이라고 부릅니다.
- 학습 시: 정답 토큰 → 입력
- 추론 시: 모델의 예측 토큰 → 입력
이 전략은 학습 속도를 빠르게 하고, 초기에는 더 정확한 문장을 생성하는 데 도움을 줍니다. 하지만 추론 시 입력 분포가 달라지는 문제(Exposure Bias)를 야기할 수 있어 적절한 비율 조절이 중요합니다.
👉 이때 Input Feeding을 병행하면 이러한 bias를 어느 정도 완화할 수 있습니다.
Decoder 구현 코드
class Decoder(nn.Module):
def __init__(self, word_vec_size, hidden_size, n_layers=4, dropout_p=.2):
super().__init__()
self.rnn = nn.LSTM(
word_vec_size + hidden_size, # It is for input feeding
hidden_size,
num_layers=n_layers,
dropout=dropout_p,
bidirectional=False,
batch_first=True,
)
def forward(self, emb_t, h_t_1_tilde, h_t_1):
'''
Decoder은 학습때는 input_feeding & Teacher Forcing, inference 때는 당연히 1-step씩 들어간다.
'''
# |emb_t| = (batch_size, 1, word_vec_size)
# |h_t_1_tilde| = (batch_size, 1, hidden_size)
# |h_t_1[0]| = (n_layers, batch_size, hidden_size) -> Hidden state at previous time step
batch_size = emb_t.size(0)
hidden_size = h_t_1[0].size(-1)
if h_t_1_tilde is None:
# If it is the first time-step,
h_t_1_tilde = emb_t.new(batch_size, 1, hidden_size).zero_()
# Input Feeding
x = torch.cat([emb_t, h_t_1_tilde], dim=-1)
# Decoder must take an input for sequentially.
y, h = self.rnn(x, h_t_1)
# |y| = (batch_size, 1, hidden_state)
# |h[0]]| = (n_layers, batch_size, hidden_state)
return y, h
개념 설명
Input Feeding | 이전 출력 벡터를 다음 입력 임베딩과 함께 사용 |
Teacher Forcing | 학습 시 정답 토큰을 다음 입력으로 사용 |
LSTM 기반 Decoder | 매 시점마다 입력을 받아 다음 hidden state를 생성 |
다음 글 예고
Decoder까지 구현을 마쳤습니다!
다음 글에는 Decoder의 Output을 처리하는 Generator 부분을 다뤄보겠습니다.
읽어주셔서 감사합니다.