10 Train A Transformer to Translate English to French
This chapter walks through building an end-to-end English-to-French translation system with a Transformer encoder-decoder, using a dataset of over 47,000 parallel sentence pairs. It uses the project as a concrete case study to reinforce how self-attention, embeddings, and positional encodings work together inside the Transformer. The workflow covers preparing data with subword tokenization, constructing vocabularies, turning tokens into numerical sequences, training a Transformer from scratch, and finally translating English sentences into French with the trained model.
Data preparation begins with subword tokenization for both languages, adding BOS/EOS markers and reserving PAD/UNK tokens. Token-to-index and index-to-token dictionaries are built to convert phrases to sequences and back. Because sentences have variable lengths, sequences are batched with padding and length-based sorting to minimize wasted computation. Masks are created to hide padding in the encoder and to conceal both padding and future tokens in the decoder. Word embeddings compress sparse token indices into dense vectors (scaled by sqrt(d_model)), and sinusoidal positional encodings inject order information so attention can respect token positions. The Batch utility assembles inputs, shifted targets, and the required masks for efficient training.
Training uses a configurable Transformer (e.g., d_model=256, 8 heads), label smoothing to improve generalization and calibration, and Adam with a Noam warm-up schedule for stable optimization. A simple training loop accumulates token-normalized loss across epochs and saves the learned weights. At inference, a translate function encodes an English sentence and performs greedy, autoregressive decoding on the French side from BOS until EOS, then stitches subwords back into clean text. The model reliably translates common sentences, producing consistent outputs for semantically equivalent inputs (e.g., “don’t” vs. “do not”), demonstrating that the encoder captures meaning in a shared vector space and the decoder turns it into fluent French, setting up the transition to decoder-only Transformers in later chapters.
What does the Bach() class do? The Bach() class takes two inputs: src and trg, sequences of indexes for the source language and the target language, respectively. It adds several attributes to the training data: src_mask, the source mask to conceal padding; modified trg, the input to the decoder; trg_y, the output to the decoder; trg_mask, the target mask to hide padding and future tokens.
Summary
- Transformers process input data such as sentences in parallel, unlike Recurrent Neural Networks (RNNs) which handle data sequentially. This parallelism enhances their efficiency but doesn't inherently allow them to recognize the sequence order of the input. To address this, transformers add positional encodings to the input embeddings. These positional encodings are unique vectors assigned to each position in the input sequence and align in dimension with the input embeddings.
- Label smoothing is commonly used in training deep neural networks to improve the generalization of the model. It is used to address overconfidence problems (the predicted probability is greater than the true probability) and overfitting in classifications. Specifically, it modifies the way the model learns by adjusting the target labels, aiming to reduce the model's confidence in the training data, which can lead to better performance on unseen data.
- Based on the encoder’s output that captures the meaning of the English phrase, the decoder in the trained Transformer starts translating in an autoregressive manner, starting with the beginning token "BOS". In each time step, the decoder generates the most likely next token based on previously generated tokens, until the predicted token is "EOS", which signals the end of the sentence.
FAQ
Why does the chapter use subword tokenization (XLMTokenizer) instead of word- or character-level tokenization?
Subword tokenization balances vocabulary size and expressiveness: frequent words remain whole while rare or complex words are split into smaller pieces. The XLM tokenizer is multilingual, handles English and French well, and marks word boundaries with the </w> suffix. This reduces out-of-vocabulary issues while keeping sequence lengths and model size manageable.What are the roles of BOS, EOS, PAD, and UNK tokens?
- BOS: Beginning of sentence; signals the decoder to start generating.- EOS: End of sentence; tells decoding to stop.
- PAD: Padding token (index 0) used to make all sequences in a batch the same length.
- UNK: Unknown token (index 1) used when a token isn’t in the vocabulary.
Adding BOS/EOS defines clear sequence boundaries; PAD enables batching; UNK handles rare/unseen tokens.
How are vocabularies built and why are PAD and UNK assigned to 0 and 1?
Tokens are collected from all sentences (with BOS/EOS added), counted, and the most frequent are kept (e.g., up to 50k). A token-to-index dict is created with reserved indices: PAD=0 and UNK=1. Using fixed low indices for PAD/UNK simplifies masking and loss computation (e.g., ignore PAD in loss) and keeps their handling consistent across the pipeline.Why do reconstructed phrases become lowercase and lose accents (e.g., français → francais)?
The pre-trained XLM tokenizer lowercases text and strips accents to reduce the number of unique tokens. This normalization improves robustness and efficiency but means reconstructed text may lack original casing and diacritics even though the semantics are preserved.Why is sequence padding necessary and how do the masks (src_mask, trg_mask, subsequent_mask) work?
Sequences in a batch have different lengths; padding makes them equal length so they can be processed in parallel. Masks ensure the model ignores padding and enforces causality:- src_mask: True where source tokens are real (not PAD).
- subsequent_mask: Upper-triangular mask that hides future positions.
- trg_mask: Combines target non-PAD mask with subsequent_mask so the decoder attends only to past tokens and non-PAD positions.
What does the Batch class do with trg and trg_y, and why shift targets?
The class prepares decoder inputs/outputs for teacher forcing:- trg: target sequence without the last token (input to decoder, starting with BOS).
- trg_y: target sequence without the first token (expected outputs, ending with EOS).
By shifting one position, the model learns to predict the next token given previous tokens, which is standard for autoregressive training.
How do word embeddings and positional encodings work together, and why scale embeddings by sqrt(d_model)?
- Embeddings map token indices to dense vectors (dimension d_model, e.g., 256), capturing token semantics.- Positional encodings (fixed sin/cos) are added to embeddings to inject token order information since attention alone is position-agnostic.
- Scaling by sqrt(d_model) stabilizes the magnitude of embeddings relative to attention score scaling, improving training stability.
Learn Generative AI with PyTorch ebook for free