Thomas Piacentini
← Atelier

Fiche

RNNs, Seq2Seq and N-gram Models

Texte original · anglais

TextCNN, LSTM and GRU, encoder-decoder with teacher forcing, beam search, BLEU, Kneser-Ney and why attention won.

Seq2seq encoder-decoder

bottleneckinit hiddeninput_tokenfeed backSource tokenssrc idsclientEncoder GRUoutputs, hiddenmodelContext vectorfinal hidden statestorebos_id tokenthen the last tokenclientDecoder GRUone step at a timemodelVocabulary logitsargmax or beamprocess
Nodes and connections
NodeRoleKind
Source tokenssrc idsclient
Encoder GRUoutputs, hiddenmodel
Context vectorfinal hidden statestore
bos_id tokenthen the last tokenclient
Decoder GRUone step at a timemodel
Vocabulary logitsargmax or beamprocess
FromToConnection
Source tokensEncoder GRU
Encoder GRUContext vectorbottleneck
Context vectorDecoder GRUinit hidden
bos_id tokenDecoder GRUinput_token
Decoder GRUVocabulary logits
Vocabulary logitsbos_id tokenfeed back
Sources

Core formulas

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.
Sources

Tasks in code

TaskCode
Gradient left after N stepsvanishing_gradient_sim(seq_len, recurrent_weight=0.9)
Decode without a teachergreedy_decode(encoder, decoder, src, bos_id, eos_id, max_len=50)
Toy BLEUsimple_bleu(hypothesis, reference, max_n=4)
Character F-scorechrf(hypothesis, reference, n=6, beta=2)
Count trigramstrain_ngram(corpus_tokens, n=3)
Smoothed bigram modelkneser_ney_bigram_model(corpus_tokens, discount=0.75)
Score held-out textperplexity(prob_fn, sentences)
Serial vs parallel depthrnn_style(xs, decay=0.9) vs attention_style(xs)
Sources

Train with teacher forcing

_, 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()
Sources

TextCNN forward pass

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).valuesmax-pool beats last state
Sources

Translate and score

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)
Sources

Defaults and numbers

SettingDefaultNote
teacher_forcing_ratio0.9Start at 1.0, anneal to ~0.5
Beam width3-5MT uses 4-5 for general content
KN discount0.75Subtracted from every bigram count
TextCNN filters64Widths (2, 3, 4), dropout 0.3
0.9 ^ 1002.7e-5Gradient left after 100 steps
Copy accuracy at length 4023%98% at length 5. The bottleneck
BLEU bands3040 is good, 50 exceptional, under 1 is noise
4-gram KN perplexity, Brown140A transformer LM gets 15-30
Sources

Troubleshooting

SymptomCauseFix
Drift on long outputsExposure biasScheduled sampling, anneal the ratio
Long inputs lose detailOne fixed context vectorAttention over all encoder states
Plain RNN learns no long rangeVanishing gradientUse an LSTM or GRU
Greedy output repeats and loopsCommits to each tokenBeam search, width 4-5
Output in the wrong languageOff-target generationCheck forced_bos_token_id, run language ID
Short input gives long outputLength penalty under ~5 tokensCap length by source length
Fluent output with new factsHallucinationConstrained decoding, human review
N-gram gives probability 0Unseen n-gramSmooth with Kneser-Ney
Sources

Use X when

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.
Sources

Abbreviations

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.
Sources

Tips

  • 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.
Sources
Original source
---
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.
Code et livrables 1
Ce que vous en retenez

Enregistré dans votre carnet sur cet appareil.

Sources et limites

Les repères de lecture sont déclaratifs. Les résultats de tests sont enregistrés séparément ; ils valent pour les cas exécutés.

AI Engineering from Scratch · 3f9715c · MIT

Télécharger ce fichier ↓