Sequence-to-Sequence Models

Imagine building a machine translator. The input is an English sentence of arbitrary length. The output is a French sentence of a possibly different arbitrary length. Classic classifiers assign a fixed-size output to a fixed-size input. They cannot naturally handle this mismatch. Sequence-to-sequence (seq2seq) modeling solves exactly this problem. It maps an input sequence to an output sequence. This works without assuming they are the same length or aligned position-by-position. The idea, introduced for neural machine translation, turned out to be far more general. Summarization, speech recognition, question answering, code generation, and dialogue systems all reduce to the same abstract task. Consume a sequence, produce a sequence. Before seq2seq, these problems required hand-built pipelines. These pipelines had separate alignment, translation, and reordering models. A single trainable encoder-decoder network replaced that entire pipeline. It learned everything end-to-end from paired examples. The big picture is deceptively simple. An encoder, typically a recurrent network, reads the input sequence. It compresses the input into a fixed-size vector. This is a "thought vector" or context vector. It is meant to summarize everything relevant about the input. A decoder, another recurrent network, then generates the output sequence one token at a time. It is conditioned on that context vector and on its own previously generated tokens. Training uses paired input-output sequences and standard maximum-likelihood objectives. There is no need for explicit alignment supervision. This article builds the seq2seq framework from first principles. It covers the encoder-decoder split, the mechanics of teacher forcing during training, and the mechanics of autoregressive decoding at inference. It also covers the classic bottleneck that this architecture exposes. The resolution of this bottleneck motivates the Attention Mechanism in NLP and modern The Encoder-Decoder Architecture designs. We build on Recurrent Models for NLP. We assume familiarity with RNNs, hidden states, and backpropagation through time.

Key takeaways
  • Seq2seq maps variable-length input sequences to variable-length output sequences using two coupled networks.
  • The encoder reads the whole input and compresses it into a single fixed-size context vector.
  • The decoder generates output tokens one at a time, conditioned on the context vector and prior outputs.
  • Training uses teacher forcing (feeding true previous tokens) and cross-entropy loss over the vocabulary at each step.
  • Inference uses greedy or beam search decoding since the true previous tokens are unavailable.
  • The fixed-size bottleneck limits performance on long sequences, motivating attention mechanisms.
The core insight

Seq2seq models decouple input length from output length by compressing the input into a fixed-size vector that a separate decoder network unrolls into the output sequence, one token at a time.

The idea

A sequence-to-sequence model learns a conditional distribution P(y1,…,ym∣x1,…,xn)P(y_1, \dots, y_m \mid x_1, \dots, x_n) over output sequences yy given input sequences xx, where nn and mm need not be equal and need not correspond position-by-position. This distinguishes seq2seq from sequence labeling tasks (like part-of-speech tagging), where each input token gets exactly one aligned output label. The architecture that realizes this is the encoder-decoder pair. The encoder is a recurrent network (originally an LSTM or GRU) that processes the input tokens x1,…,xnx_1, \dots, x_n one at a time, updating a hidden state at each step. After consuming the last input token, the encoder's final hidden state cc — the context vector — is taken as a compressed summary of the entire input sequence. Crucially, cc has a fixed dimensionality regardless of nn: a 50-word sentence and a 5-word sentence are both squeezed into the same size vector. The decoder is a separate recurrent network that generates the output sequence autoregressively: it predicts y1y_1 conditioned on cc, then predicts y2y_2 conditioned on cc and y1y_1, and so on, until it emits a special end-of-sequence token. Formally, the decoder factors the joint output distribution using the chain rule:

P(y1,…,ym∣x1,…,xn)=∏t=1mP(yt∣y1,…,yt−1,c)P(y_1, \dots, y_m \mid x_1, \dots, x_n) = \prod_{t=1}^{m} P(y_t \mid y_1, \dots, y_{t-1}, c)

Each factor is computed by a softmax over the vocabulary, taking as input the decoder's current hidden state, which itself depends on the previous output token and the running decoder state initialized from cc. This factorization is exact by the chain rule of probability — no independence assumption is smuggled in, since each term conditions on all previous outputs. The key architectural commitment of the vanilla seq2seq model is that all information the decoder ever receives about the input must pass through the single vector cc. This is both the elegance and the weakness of the design, discussed under complexity and pitfalls below.

How it works

Training phase. Given a paired dataset of (x,y)(x, y) sequences, the encoder processes xx to produce cc. The decoder is then run in teacher-forcing mode: at each decoding step tt, instead of feeding back its own (possibly wrong) prediction from step t−1t-1, it is fed the true token yt−1y_{t-1} from the training pair. This stabilizes training because errors do not compound — the decoder always sees a "clean" history — and it allows the whole sequence to be processed as one parallelizable forward pass with a single backward pass for gradient computation (backpropagation through time, across both networks). The loss is the sum (or average) of per-token cross-entropy losses:

L(x,y)=−∑t=1mlog⁡P(yt∣y<t,c;θ)\mathcal{L}(x, y) = -\sum_{t=1}^{m} \log P(y_t \mid y_{<t}, c; \theta)

summed over training pairs and minimized by gradient descent, exactly as in standard Recurrent Models for NLP language modeling, but now conditioned on an external context vector cc.

Inference phase. At test time, the true output sequence is unknown, so teacher forcing is impossible. Decoding proceeds autoregressively: generate a token, feed it back as input to generate the next token, and repeat until an end-of-sequence marker is produced or a maximum length is reached. Two common strategies:

  • Greedy decoding: at each step, pick the single highest-probability token. Fast, O(m)O(m) decoder calls, but can commit to locally optimal but globally suboptimal choices.
  • Beam search: maintain the kk highest-scoring partial sequences ("beams") at each step, expanding each by all vocabulary tokens and pruning back to the top kk. This better approximates the sequence with highest total log-probability, at k×k\times the computational cost.

``` function TRAIN_SEQ2SEQ(dataset, encoder, decoder, epochs, learning_rate): for epoch in 1..epochs: for (x, y) in dataset: # x = x_1..x_n, y = y_1..y_m

# ---- Encode ---- h = encoder.init_hidden() for t in 1..n: h = encoder.step(x[t], h) c = h # final hidden state = context vector

# ---- Decode with teacher forcing ---- h_dec = c loss = 0 prev_token = START_TOKEN for t in 1..m: logits, h_dec = decoder.step(prev_token, h_dec) probs = softmax(logits) loss += -log(probs[y[t]]) prev_token = y[t] # feed TRUE token, not prediction gradients = backprop(loss, encoder.params + decoder.params) update(encoder.params, decoder.params, gradients, learning_rate) function GREEDY_DECODE(x, encoder, decoder, max_len): h = encoder.init_hidden() for t in 1..length(x): h = encoder.step(x[t], h) c = h h_dec = c output = [] prev_token = START_TOKEN for t in 1..max_len: logits, h_dec = decoder.step(prev_token, h_dec) prev_token = argmax(softmax(logits)) if prev_token == END_TOKEN: break output.append(prev_token) return output function BEAM_SEARCH_DECODE(x, encoder, decoder, max_len, k): h = encoder.init_hidden() for t in 1..length(x): h = encoder.step(x[t], h) c = h beams = [ (score=0.0, tokens=[START_TOKEN], hidden=c) ] completed = [] for t in 1..max_len: candidates = [] for (score, tokens, h_dec) in beams: if tokens[-1] == END_TOKEN: completed.append((score, tokens, h_dec)) continue logits, h_new = decoder.step(tokens[-1], h_dec) logp = log_softmax(logits) for token in vocabulary: candidates.append((score + logp[token], tokens + [token], h_new)) beams = top_k(candidates, k) # keep k highest-scoring partials if all beams end in END_TOKEN: break completed.extend(beams) return argmax_by_score(completed) # or length-normalized score ```

Figure
The encoder-decoder pipeline: fixed-size context vector as the sole channel between input and output
Encoder (reads input) x1 x2 x3 xn h1 h2 h3 hn c context vector (fixed size!) Decoder (writes output) s1 s2 sm y1 y2 EOS feedback y(t-1) All input information must flow through c — the single-vector bottleneck.

Complexity & correctness

Time complexity. Let nn be input length, mm output length, dd hidden dimension, and ∣V∣|V| vocabulary size. Encoding is O(n⋅d2)O(n \cdot d^2) time (each RNN step costs O(d2)O(d^2) for the matrix multiplications inside the recurrence). Decoding during training (teacher forcing) is O(m⋅(d2+d∣V∣))O(m \cdot (d^2 + d|V|)), where the d∣V∣d|V| term is the cost of the output softmax at each step. Both phases are linear in sequence length, and the two RNNs run sequentially, so total training time per example is O((n+m)(d2+d∣V∣))O((n+m)(d^2 + d|V|)). At inference, greedy decoding costs the same O(m(d2+d∣V∣))O(m(d^2+d|V|)). Beam search with beam width kk multiplies the decoder cost by kk, giving O(k⋅m⋅(d2+d∣V∣))O(k \cdot m \cdot (d^2 + d|V|)), since at each of the mm steps we expand kk beams and score ∣V∣|V| continuations for each.

Space complexity. Storing hidden states for backpropagation through time requires O((n+m)d)O((n+m)d) space for a single example (one hidden vector per timestep must be retained for the backward pass), plus O(d2+d∣V∣)O(d^2 + d|V|) for the model parameters themselves, independent of sequence length. Beam search adds O(k⋅m⋅d)O(k \cdot m \cdot d) space to track kk hypotheses' hidden states.

Why teacher forcing is correct as a training procedure. The maximum-likelihood objective factorizes exactly via the chain rule shown above — this is not an approximation, it is an algebraic identity for any joint distribution over a sequence. Teacher forcing implements maximum likelihood by plugging in the ground-truth prefix y<ty_{<t} at every step, so the gradient of the loss with respect to parameters exactly matches the gradient of the true log-likelihood objective evaluated on the training pair. The mismatch this introduces is only at inference time: the model is trained conditioned on true prefixes but must generate conditioned on its own (possibly imperfect) prefixes, an issue known as exposure bias. This does not make training incorrect — it correctly optimizes likelihood under teacher forcing — but it does mean training loss is not a perfectly faithful proxy for generation quality, a known and studied gap.

Why greedy/beam decoding is a reasonable approximation. Exact inference would require computing

arg⁡max⁡y∏t=1mP(yt∣y<t,c)\arg\max_{y} \prod_{t=1}^{m} P(y_t \mid y_{<t}, c)

which is intractable to search exhaustively (exponential in mm, since the number of possible sequences is ∣V∣m|V|^m). Beam search is a bounded-width approximate dynamic-programming-style search: because the RNN decoder's state is not Markovian over a small fixed window (it depends on the whole generated prefix), true dynamic programming with polynomial states is not directly available, so we resort to keeping only the kk best partial hypotheses at each depth — a standard heuristic that provably contains the greedy solution as the special case k=1k=1, and that empirically improves log-likelihood of the returned sequence monotonically in kk up to diminishing returns.

The bottleneck problem — an honest tradeoff. The context vector cc has fixed dimensionality dd, independent of nn. As nn grows, cc must represent proportionally more information in the same number of dimensions, so information loss becomes unavoidable for long inputs. Empirically, translation quality (measured by BLEU score) degrades sharply for sentences beyond roughly 20–30 tokens in the original architecture. This is not a bug fixable by better optimization; it is a structural property of forcing all input information through one vector, and it is precisely the limitation that the Attention Mechanism in NLP is designed to remove by letting the decoder access all encoder hidden states, not just the last one.

Worked example

Consider a toy translation task: English "the cat sat" → French "le chat assis" (a simplified gloss, ignoring real French grammar, for pedagogical tracing). Vocabulary indices: `the=1, cat=2, sat=3, =0` (input side); `le=1, chat=2, assis=3, =0` (output side). Hidden dimension d=2d=2 for hand-traceability.

Encoding pass (illustrative hidden-state values, not from a real trained model):

stepinput tokenhidden state hth_t
1the(0.10,−0.05)(0.10, -0.05)
2cat(0.35,0.20)(0.35, 0.20)
3sat(0.42,0.31)(0.42, 0.31)

Context vector c=h3=(0.42,0.31)c = h_3 = (0.42, 0.31). Note: tokens 1 and 2 ("the", "cat") no longer exist as separate accessible states for the decoder — only their residue inside cc remains.

Decoding pass with teacher forcing (training):

stepdecoder inputtrue targetlogits (toy)predicted probs (softmax, rounded)loss term
1STARTle[1.2,2.8,0.5,−0.3][1.2, 2.8, 0.5, -0.3][0.10,0.75,0.06,0.03][0.10, 0.75, 0.06, 0.03]−log⁡0.75≈0.29-\log 0.75 \approx 0.29
2le (true)chat[0.3,0.5,2.6,−0.1][0.3, 0.5, 2.6, -0.1][0.07,0.09,0.78,0.05][0.07, 0.09, 0.78, 0.05]−log⁡0.78≈0.25-\log 0.78 \approx 0.25
3chat (true)assis[0.1,0.2,0.4,2.9][0.1, 0.2, 0.4, 2.9][0.04,0.05,0.07,0.83][0.04, 0.05, 0.07, 0.83]−log⁡0.83≈0.19-\log 0.83 \approx 0.19
4assis (true)EOS[3.1,0.2,0.1,0.3][3.1, 0.2, 0.1, 0.3][0.86,0.05,0.04,0.05][0.86, 0.05, 0.04, 0.05]−log⁡0.86≈0.15-\log 0.86 \approx 0.15

Total sequence loss ≈0.29+0.25+0.19+0.15=0.88\approx 0.29 + 0.25 + 0.19 + 0.15 = 0.88, backpropagated through both decoder and encoder.

Decoding pass at inference (greedy, no teacher forcing): suppose the decoder's step-1 prediction were wrong — say it predicted "chat" instead of "le" (probability mass slightly favoring the wrong token due to an undertrained model). Because there is no ground truth to correct it, step 2 now conditions on the wrong token "chat" as if it were the first output word, and the error can propagate through the rest of the sequence. This is exposure bias made concrete: the training procedure never showed the decoder what to do after its own mistake, only after the correct prefix.

Beam search trace (k=2) for the same first step: keep the top two candidates "le" (score log⁡0.75\log 0.75) and "chat" (score log⁡0.10\log 0.10). Expanding both one more step and re-pruning to the top 2 by cumulative score is what lets beam search recover from a locally tempting but globally wrong first guess, something greedy (k=1) cannot do.

Common pitfalls & traps

PitfallWhy it happensConsequence
Treating cc as unlimited-capacity memoryAssuming the RNN hidden state scales with input lengthSevere quality drop on long sequences (the bottleneck)
Forgetting teacher forcing at train time onlyConfusing training-time and inference-time decoder inputsModel trained on ground truth but evaluated with self-generated (buggy) prefixes — train/inference mismatch
Using greedy decoding and expecting optimal outputGreedy is a local, per-step argmax, not a global searchLocally plausible but globally poor translations; repetition loops
No `` token or unbounded decoding loopMissing stopping criterion in the decoder loopInfinite or excessively long generation at inference
Reversing/ignoring input order without justificationSome implementations reverse the source sentence to shorten dependency paths to recent decoder-relevant wordsSilent quality differences between "reversed" and "forward" encoder variants if not controlled for
Ignoring exposure bias when reporting training lossLoss computed only under teacher forcingTraining loss can look excellent while generation quality is mediocre

Pioneers & history

The encoder-decoder framework for sequences was crystallized by researchers extending recurrent language modeling to conditional generation, most prominently in the neural machine translation literature of the early 2010s, building on decades of work on recurrent networks and sequence learning.

Origins · 1 minIlya Sutskever and how this was discovered
IS
Ilya Sutskever
born 1986 · co-author of the foundational 2014 seq2seq paper introducing the encoder-decoder LSTM framework for machine translation

History
1997
— LSTM introduced, solving the vanishing-gradient problem for long sequences, providing the recurrent building block seq2seq would rely on.
2014
— Sequence-to-sequence learning with neural networks popularizes the encoder-decoder LSTM pipeline for machine translation.
2014
— A closely related encoder-decoder paper introduces the RNN-based conditional generation framework, explicitly naming the bottleneck problem.
2015
— Attention mechanisms are introduced to let the decoder access all encoder hidden states, directly addressing the fixed-vector bottleneck.
2017
— The Transformer architecture replaces recurrence entirely with self-attention, subsuming and superseding the RNN-based seq2seq design in most large-scale systems.

Where this matters

Seq2seq established the template underlying essentially all modern text generation systems, even after the underlying encoder and decoder were reengineered from RNNs to Transformers. Neural machine translation systems in production (used in large-scale translation services) are seq2seq models at their core, conditioning an output-language decoder on a source-language encoding. Automatic speech recognition systems frame "audio in, transcript out" as sequence-to-sequence, with the encoder consuming acoustic features and the decoder producing text tokens. Text summarization, image captioning (encoder over image features, decoder over words), and code-generation assistants all reuse the same encode-then-autoregressively-decode template. Even the largest modern language models, though architecturally Transformer-based rather than recurrent, inherit the autoregressive decoding discipline pioneered in the seq2seq framework: generate one token at a time, conditioned on everything generated so far. Studying seq2seq is therefore the natural bridge from Recurrent Models for NLP to the attention-augmented and fully attention-based architectures — The Encoder-Decoder Architecture and the Attention Mechanism in NLP — that dominate contemporary NLP.

Ask the tutor: How does the attention mechanism modify the encoder-decoder pipeline to remove the fixed-size bottleneck?

Do seq2seq models require the input and output sequences to have the same length?

No — that is precisely the problem seq2seq solves. The encoder consumes the entire input sequence, of length nn, and compresses it into a fixed-size context vector regardless of nn. The decoder then generates an output sequence of length mm, stopping only when it emits an end-of-sequence token, with no constraint that mm equal nn. This is what makes seq2seq suitable for machine translation, where source and target sentences routinely differ in word count and word order, unlike sequence-labeling tasks that require one output per input token.

What is the difference between the encoder RNN and the decoder RNN?

The encoder RNN reads the input sequence and updates its hidden state at each step without producing any output token; its job ends by handing off a final hidden state (the context vector) to the decoder. The decoder RNN, initialized from that context vector, produces one output token per step and feeds each generated (or, during training, ground-truth) token back in as the next input. They are typically separate networks with separate parameters, though some implementations tie certain weights, such as embedding matrices, between the two.

Why can't we just use one long RNN instead of splitting into encoder and decoder?

A single RNN reading input and immediately emitting output token-by-token would force strict positional alignment between input and output positions, which fails whenever sentences reorder words (as translation frequently does) or have different lengths. Splitting into encoder and decoder decouples "understanding the whole input" from "generating the whole output," letting the model first build a complete summary before committing to any output decisions, and letting output length vary independently of input length.

What loss function trains a seq2seq model, and why is cross-entropy the natural choice?

Cross-entropy loss on the decoder's per-step softmax output is standard, summed across all output timesteps. This is the natural choice because the model defines a probability distribution over the next token at each step, and cross-entropy is exactly the negative log-likelihood of the true token under that distribution. Minimizing summed cross-entropy over a training set is equivalent to maximum likelihood estimation of the sequence model's parameters, which is the standard, statistically well-justified training objective for any autoregressive generative model.

Is beam search guaranteed to find the highest-probability output sequence?

No. Beam search is a heuristic approximate search, not an exact algorithm; it can miss the true highest-probability sequence because pruning to the top kk partial hypotheses at each step can discard a partial sequence that would have led to the global optimum, even though it looked suboptimal early on. Larger beam widths reduce this risk (and recover exhaustive search as k→∣V∣mk \to |V|^m) at proportionally higher computational cost, and empirically returns diminish quickly, with very large beams sometimes even hurting quality due to length or repetition artifacts.

How does the vanilla seq2seq bottleneck get fixed in practice?

The dominant fix is attention: instead of forcing the decoder to rely solely on the final encoder hidden state, attention lets the decoder compute, at every output step, a weighted combination of all encoder hidden states, with weights learned to focus on the most relevant input positions for that output step. This removes the fixed-size information bottleneck entirely, since the "memory" available to the decoder now scales with input length rather than being squeezed into one vector. This idea is developed fully under the Attention Mechanism in NLP and is a core ingredient of The Encoder-Decoder Architecture used in modern Transformer-based systems.

Are seq2seq models with RNNs still used today, or have they been replaced?

Pure RNN-based seq2seq models have largely been superseded in large-scale production systems by Transformer-based encoder-decoder or decoder-only architectures, which parallelize training far better and handle long-range dependencies more effectively via self-attention. However, the conceptual framework — an encoder producing a representation, a decoder autoregressively generating output conditioned on it — persists essentially unchanged in Transformer seq2seq systems, and understanding the RNN version remains the clearest way to learn the core ideas before tackling attention and Transformers.

Before this

Where this leads