TensorFlow Fundamentals · lesson 25/27
Machine Translation
Machine translation maps a source sequence to a target sequence whose length and alignment are unknown in advance. The sequence-to-sequence model handles that with an encoder that reads the source and a decoder that emits the translation one token at a time. Attention is what lets the decoder look back at the right source position.
The idea
- Encoder — an
Embeddingplus anLSTMthat consumes the source and returns its final states. - Decoder — an
Embeddingplus anLSTMinitialized from the encoder states; at each step it predicts the next target token from the previous token and its own hidden state. - Teacher forcing — during training the decoder input at step
tis the true previous token, not its own prediction. This trains faster but creates a train/inference mismatch. - Attention (Bahdanau or Luong) — at each decoder step, score the encoder's per-token outputs, softmax to weights, and take a weighted sum as extra decoder input.
- Evaluation — BLEU compares n-gram overlap between generated and reference translations.
Word-level tokenization with a small vocabulary, say 4,000 tokens per language, and <start>/<end> markers is enough to see the mechanism work.
Worked example
English to Spanish on short sentence pairs.
- Source padded to
T_in = 20, target toT_out = 20. Embedding(4000, 128),LSTM(256, return_sequences=True, return_state=True).- Attention over encoder outputs with the decoder query via
tf.keras.layers.Attention(). - Loss is
SparseCategoricalCrossentropy(from_logits=True, reduction="none")with a mask that zeroes positions where the target is padding. - Inference: greedy decode, feeding each predicted token back in, stopping at
<end>.
Masking the padding is essential. Without it the loss is dominated by pad tokens and the model learns to emit padding.
In code
import tensorflow as tf
enc_in = tf.keras.Input((20,))
enc_emb = tf.keras.layers.Embedding(4000, 128, mask_zero=True)(enc_in)
enc_out, h, c = tf.keras.layers.LSTM(
256, return_sequences=True, return_state=True)(enc_emb)
dec_in = tf.keras.Input((19,))
dec_emb = tf.keras.layers.Embedding(4000, 128, mask_zero=True)(dec_in)
dec_out = tf.keras.layers.LSTM(256, return_sequences=True)(
dec_emb, initial_state=[h, c])
context = tf.keras.layers.Attention()([dec_out, enc_out])
logits = tf.keras.layers.Dense(4000)(
tf.keras.layers.Concatenate()([dec_out, context]))
model = tf.keras.Model([enc_in, dec_in], logits)
model.compile(optimizer="adam",
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=["accuracy"])The decoder input is target[:-1] and the label is target[1:]: the one-token shift that makes next-token prediction supervised.
Check yourself
- What problem does attention solve that a fixed-size context vector cannot?
- Why does teacher forcing hurt at inference time?
- Why is the decoder input shifted one token from its label?
Key takeaways
- Seq2seq splits the problem into an encoder, a decoder, and a token-by-token objective.
- Attention replaces a single bottleneck vector with a learned, dynamic alignment.
- Masking padding and shifting the target are the two details that make training work.