--- id: rnns-seq2seq title: RNNs, Seq2Seq and N-gram Models code: RS subtitle: TextCNN, LSTM and GRU, encoder-decoder with teacher forcing, beam search, BLEU, Kneser-Ney and why attention won. hue: 330 sources: phases/05-nlp-foundations-to-advanced/08-cnns-rnns-for-text, phases/05-nlp-foundations-to-advanced/09-sequence-to-sequence, phases/05-nlp-foundations-to-advanced/11-machine-translation, phases/05-nlp-foundations-to-advanced/16-text-generation-pre-transformer, phases/07-transformers-deep-dive/01-why-transformers source_hash: 534e047c38ab5109 --- ## Seq2seq encoder-decoder type: architecture from: phases/05-nlp-foundations-to-advanced/09-sequence-to-sequence/docs/en.md ```arch node | src | 1,1 | Source tokens | src ids | client node | enc | 2,1 | Encoder GRU | outputs, hidden | model node | ctx | 3,1 | Context vector | final hidden state | store node | bos | 1,2 | bos_id token | then the last token | client node | dec | 2,2 | Decoder GRU | one step at a time | model node | out | 3,2 | Vocabulary logits | argmax or beam | process edge | src | enc | edge | enc | ctx | bottleneck edge | ctx | dec | init hidden edge | bos | dec | input_token edge | dec | out | edge | out | bos | feed back ``` ## Core formulas type: concepts from: phases/05-nlp-foundations-to-advanced/08-cnns-rnns-for-text/docs/en.md, phases/05-nlp-foundations-to-advanced/16-text-generation-pre-transformer/docs/en.md, phases/05-nlp-foundations-to-advanced/11-machine-translation/docs/en.md, phases/07-transformers-deep-dive/01-why-transformers/docs/en.md - **RNN**: $h_t = f(W x_t + U h_{t-1} + b)$. W, U and b are shared across time. - **LSTM**: input, forget and output gates plus a cell state. Stable gradients. - **GRU**: two gates. Similar accuracy, fewer parameters. - **TextCNN**: a width-k filter is a learnable k-gram. Global max-pool per filter. - **N-gram**: $P(w \mid \mathrm{ctx}) = \mathrm{count}(\mathrm{ctx}, w) / \mathrm{count}(\mathrm{ctx})$ - **Perplexity**: $\exp(-\frac{1}{N} \sum_i \log P(w_i \mid \mathrm{ctx}_i))$. Lower is better. - **Kneser-Ney**: absolute discount plus continuation probability for the lower order. - **BLEU**: n-gram precision for n of 1 to 4, geometric mean, brevity penalty. 0 to 100. ## Tasks in code type: task-table span: 2 from: phases/05-nlp-foundations-to-advanced/08-cnns-rnns-for-text/code/main.py, phases/05-nlp-foundations-to-advanced/09-sequence-to-sequence/docs/en.md, phases/05-nlp-foundations-to-advanced/11-machine-translation/code/main.py, phases/05-nlp-foundations-to-advanced/16-text-generation-pre-transformer/docs/en.md, phases/07-transformers-deep-dive/01-why-transformers/code/main.py | Task | Code | |---|---| | Gradient left after N steps | `vanishing_gradient_sim(seq_len, recurrent_weight=0.9)` | | Decode without a teacher | `greedy_decode(encoder, decoder, src, bos_id, eos_id, max_len=50)` | | Toy BLEU | `simple_bleu(hypothesis, reference, max_n=4)` | | Character F-score | `chrf(hypothesis, reference, n=6, beta=2)` | | Count trigrams | `train_ngram(corpus_tokens, n=3)` | | Smoothed bigram model | `kneser_ney_bigram_model(corpus_tokens, discount=0.75)` | | Score held-out text | `perplexity(prob_fn, sentences)` | | Serial vs parallel depth | `rnn_style(xs, decay=0.9)` vs `attention_style(xs)` | ## Train with teacher forcing type: annotated-code lang: python from: phases/05-nlp-foundations-to-advanced/09-sequence-to-sequence/docs/en.md ```python _, hidden = encoder(src) # context vector input_token = torch.full((batch_size, 1), bos_id, dtype=torch.long) loss_fn = nn.CrossEntropyLoss(ignore_index=0) # skip padding for t in range(tgt_len): logits, hidden = decoder(input_token, hidden) loss += loss_fn(logits.squeeze(1), tgt[:, t]) use_teacher = torch.rand(1).item() < teacher_forcing_ratio if use_teacher: input_token = tgt[:, t].unsqueeze(1) # ground truth at t-1 else: input_token = logits.argmax(dim=-1) # own prediction loss.backward() ``` ## TextCNN forward pass type: annotated-code lang: python from: phases/05-nlp-foundations-to-advanced/08-cnns-rnns-for-text/docs/en.md ```python x = self.embed(token_ids).transpose(1, 2) # [batch, embed_dim, seq_len] for conv in self.convs: # one per width in (2, 3, 4) c = F.relu(conv(x)) p = F.max_pool1d(c, c.size(2)).squeeze(2) # strongest activation pooled.append(p) h = torch.cat(pooled, dim=1) # fixed size for any length out, _ = self.lstm(x) # LSTM classifier instead pooled = out.max(dim=1).values # max-pool beats last state ``` ## Translate and score type: annotated-code lang: python from: phases/05-nlp-foundations-to-advanced/11-machine-translation/docs/en.md ```python model_id = "facebook/nllb-200-distilled-600M" tok = AutoTokenizer.from_pretrained(model_id, src_lang="eng_Latn") out = model.generate(**inputs, forced_bos_token_id=tok.convert_tokens_to_ids("fra_Latn"), # target num_beams=5, length_penalty=1.0, max_new_tokens=64) print(tok.batch_decode(out, skip_special_tokens=True)[0]) bleu = sacrebleu.corpus_bleu(hypotheses, references) chrf = sacrebleu.corpus_chrf(hypotheses, references) ``` ## Defaults and numbers type: defaults from: phases/05-nlp-foundations-to-advanced/09-sequence-to-sequence/docs/en.md, phases/05-nlp-foundations-to-advanced/08-cnns-rnns-for-text/docs/en.md, phases/05-nlp-foundations-to-advanced/11-machine-translation/docs/en.md, phases/05-nlp-foundations-to-advanced/16-text-generation-pre-transformer/docs/en.md | Setting | Default | Note | |---|---|---| | `teacher_forcing_ratio` | 0.9 | Start at 1.0, anneal to ~0.5 | | Beam width | 3-5 | MT uses 4-5 for general content | | KN `discount` | 0.75 | Subtracted from every bigram count | | TextCNN filters | 64 | Widths (2, 3, 4), dropout 0.3 | | `0.9 ^ 100` | 2.7e-5 | Gradient left after 100 steps | | Copy accuracy at length 40 | 23% | 98% at length 5. The bottleneck | | BLEU bands | 30 | 40 is good, 50 exceptional, under 1 is noise | | 4-gram KN perplexity, Brown | 140 | A transformer LM gets 15-30 | ## Troubleshooting type: troubleshooting from: phases/05-nlp-foundations-to-advanced/09-sequence-to-sequence/docs/en.md, phases/05-nlp-foundations-to-advanced/08-cnns-rnns-for-text/docs/en.md, phases/05-nlp-foundations-to-advanced/11-machine-translation/docs/en.md, phases/05-nlp-foundations-to-advanced/16-text-generation-pre-transformer/docs/en.md | Symptom | Cause | Fix | |---|---|---| | Drift on long outputs | Exposure bias | Scheduled sampling, anneal the ratio | | Long inputs lose detail | One fixed context vector | Attention over all encoder states | | Plain RNN learns no long range | Vanishing gradient | Use an LSTM or GRU | | Greedy output repeats and loops | Commits to each token | Beam search, width 4-5 | | Output in the wrong language | Off-target generation | Check `forced_bos_token_id`, run language ID | | Short input gives long output | Length penalty under ~5 tokens | Cap length by source length | | Fluent output with new facts | Hallucination | Constrained decoding, human review | | N-gram gives probability 0 | Unseen n-gram | Smooth with Kneser-Ney | ## Use X when type: qa from: phases/05-nlp-foundations-to-advanced/08-cnns-rnns-for-text/docs/en.md, phases/05-nlp-foundations-to-advanced/09-sequence-to-sequence/docs/en.md, phases/05-nlp-foundations-to-advanced/16-text-generation-pre-transformer/docs/en.md, phases/07-transformers-deep-dive/01-why-transformers/docs/en.md, phases/05-nlp-foundations-to-advanced/11-machine-translation/docs/en.md - **TextCNN?** Edge and on-device. It is 10-100x smaller than a transformer. - **LSTM?** Streaming text, one token at a time. BiLSTM-CRF for 1k-10k labeled sentences. - **RNN seq2seq?** Almost never. Streaming translation or on-device generation only. - **N-gram LM?** On-device autocomplete, rescoring, and a baseline before any neural LM. - **Transformer?** Everything else. Serial depth is 1, not N. Memory is $O(N^2)$. - **BLEU or chrF?** Report both. chrF counts better on morphologically rich languages. ## Abbreviations type: glossary from: phases/05-nlp-foundations-to-advanced/08-cnns-rnns-for-text/docs/en.md, phases/05-nlp-foundations-to-advanced/09-sequence-to-sequence/docs/en.md, phases/05-nlp-foundations-to-advanced/11-machine-translation/docs/en.md, phases/07-transformers-deep-dive/01-why-transformers/docs/en.md - **LSTM**: gated RNN with input, forget and output gates and a cell state. - **GRU**: gated RNN with two gates. - **NMT**: neural MT. Transformer encoder-decoder trained on parallel text. - **NLLB**: No Language Left Behind. A 200-language MT model family. - **chrF**: character-level F-score. - **SSM**: state-space model. Recurrence with parallel training. ## Tips type: tips from: phases/05-nlp-foundations-to-advanced/11-machine-translation/docs/en.md, phases/05-nlp-foundations-to-advanced/16-text-generation-pre-transformer/docs/en.md - Always use `sacrebleu`. Your own BLEU code gives scores you cannot compare. - Ship at least two metric families. COMET is the default where quality matters. - Calibrate each metric on 50-100 human-labeled examples. - Compare perplexity only under identical tokenization. - A few thousand clean parallel pairs beat a few hundred thousand noisy ones.