Home
Implementing the Transformer Architecture From the Attention Is All You Need Paper From Scratch
The 2017 paper "Attention Is All You Need" by Vaswani et al. revolutionized natural language processing by introducing the Transformer, a model architecture that completely abandoned recurrence and convolution in favor of self-attention mechanisms. While the high-level concept is widely discussed, implementing the architecture from scratch reveals the intricate engineering required to make these models performant and stable.
This technical deep dive explores the step-by-step implementation of the Transformer, focusing on the mathematical underpinnings and the specific coding logic required to reproduce the results found in the original paper.
The Core Philosophy of the Transformer Implementation
Traditional sequence models like LSTMs or GRUs process tokens sequentially, which limits parallelization and makes it difficult to capture long-range dependencies due to vanishing gradients. The Transformer solves this by allowing every token in a sequence to "attend" to every other token simultaneously. This massive parallelization is the primary reason why Transformers can be trained on much larger datasets than previous architectures.
An implementation of the Transformer is generally divided into several key modules:
- Input Pipeline: Word Embeddings and Positional Encodings.
- Attention Mechanism: Scaled Dot-Product Attention and Multi-Head Attention.
- Position-wise Feed-Forward Networks (FFN).
- Encoder-Decoder Stacks.
- Final Linear and Softmax Layer.
Building the Input Pipeline: Embeddings and Positional Encoding
Why Scaled Embeddings Matter
The first step in any Transformer implementation is converting tokens into dense vectors. In the paper, the authors use an embedding dimension of $d_{\text{model}} = 512$. One detail often overlooked in casual implementations is the scaling of these embeddings.
When implementing the embedding layer, you must multiply the output weights by $\sqrt{d_{\text{model}}}$. In our internal testing, we observed that this scaling helps prevent the positional encodings from dominating the signal. Since the positional encodings are added directly to the embeddings, keeping the relative magnitude of the embedding values higher ensures that the semantic meaning of the word is preserved while still incorporating spatial information.
How to Implement Sinusoidal Positional Encoding
Because the Transformer has no recurrence, it has no inherent sense of the order of the tokens. To fix this, positional encodings are added to the input embeddings. The paper uses sine and cosine functions of different frequencies:
$$PE_{(pos, 2i)} = \sin(pos / 10000^{2i/d_{\text{model}}})$$ $$PE_{(pos, 2i+1)} = \cos(pos / 10000^{2i/d_{\text{model}}})$$
When implementing this in code (using PyTorch or NumPy), it is most efficient to precompute a positional encoding matrix up to a maximum sequence length. You apply the sine function to even indices and the cosine function to odd indices. A common mistake is to apply them sequentially; however, interleaving them or applying them to halves of the vector both work, provided the decoder uses the same logic.
The Heart of the Model: Multi-Head Attention
The defining feature of the Transformer is the Multi-Head Attention (MHA) mechanism. Before implementing MHA, we must first build the Scaled Dot-Product Attention.
Scaled Dot-Product Attention Logic
The attention mechanism takes three inputs: Queries (Q), Keys (K), and Values (V). The formula is:
$$\text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V$$
The division by $\sqrt{d_k}$ (where $d_k = d_{\text{model}} / h = 64$) is critical. Without this scaling factor, the dot products could grow very large in magnitude for high-dimensional vectors, pushing the softmax function into regions where the gradients are extremely small. In practical implementation, failing to include this scaling factor usually results in the model failing to converge or experiencing "exploding" loss during the first few iterations.
Implementing Multi-Head Parallelism
Instead of performing a single attention function with 512-dimensional vectors, the paper splits the $d_{\text{model}}$ into $h=8$ heads. This allows the model to jointly attend to information from different representation subspaces at different positions. For example, one head might focus on syntactic relationships while another focuses on semantic consistency.
When implementing this, you don't actually create eight separate attention modules. Instead, you use linear layers to project Q, K, and V, and then reshape the tensors to move the "head" dimension into the batch dimension. This allows for highly optimized matrix multiplications. The tensor shapes typically follow this flow:
- Input:
(batch_size, seq_len, d_model) - After Linear Projection:
(batch_size, seq_len, h, d_k) - Transpose for Attention:
(batch_size, h, seq_len, d_k)
Position-wise Feed-Forward Networks (FFN)
Each layer in the encoder and decoder contains a fully connected feed-forward network. This is applied to each position separately and identically. It consists of two linear transformations with a ReLU activation in between:
$$\text{FFN}(x) = \max(0, xW_1 + b_1)W_2 + b_2$$
The inner layer has a dimensionality of $d_{ff} = 2048$, while the input and output remain $d_{\text{model}} = 512$. This "expansion-contraction" structure allows the model to project the attention-weighted representations into a higher-dimensional space to perform non-linear transformations before compressing them back. In implementation, this is simply two Linear layers and a ReLU (or GELU in modern variants like BERT/GPT).
The Importance of Residual Connections and LayerNorm
The Transformer uses a "Residual + LayerNorm" structure for every sub-layer. Specifically, the output of each sub-layer is $\text{LayerNorm}(x + \text{Sublayer}(x))$.
There is a significant debate in the implementation community regarding the placement of the LayerNorm:
- Post-LayerNorm (Original Paper): Normalization is applied after the residual addition. This can be harder to train from scratch without a very specific learning rate warmup.
- Pre-LayerNorm (Modern Standard): Normalization is applied before the sub-layer (Attention or FFN). This is generally more stable and is the preferred method for modern large-scale models.
If you are strictly following the Attention Is All You Need implementation, you should use Post-LayerNorm, but be prepared to carefully tune your learning rate scheduler.
Understanding the Encoder-Decoder Differences
While both stacks consist of $N=6$ identical layers, their internal structures differ.
The Encoder Stack
The encoder is straightforward. Each layer has two sub-layers: Multi-head self-attention and the FFN. It processes the entire input sequence and creates a continuous representation.
The Decoder Stack and the Masking Challenge
The decoder adds a third sub-layer: a multi-head attention over the output of the encoder stack (often called "Encoder-Decoder Cross-Attention"). Here, the Queries come from the previous decoder layer, and the Keys and Values come from the encoder output.
However, the most difficult part of implementing the decoder is the Masked Multi-Head Attention. During training, the decoder is auto-regressive, meaning it should not be able to "look ahead" at future tokens in the target sequence. To implement this, we apply a look-ahead mask to the attention scores. We set the scores for all "future" positions to $-\infty$ (or a very large negative number) before the softmax. This ensures that the probability of attending to future tokens becomes zero.
A common pitfall is forgetting to handle the padding mask simultaneously. If your batch contains sequences of different lengths, you must mask out the [PAD] tokens so they do not influence the attention scores or the final loss calculation.
Final Assembly: The Transformer Model
The complete model is assembled by stacking the encoder and decoder. The final output of the decoder passes through a linear layer and a softmax to produce the probabilities for the next token in the vocabulary.
Weight Tying Strategy
The paper mentions that they share the same weight matrix between the two embedding layers (encoder and decoder) and the pre-softmax linear transformation. Implementing weight tying reduces the total number of parameters significantly and often improves generalization, especially when working with smaller datasets.
Optimization: The Noam Scheduler
Implementing the model architecture is only half the battle; training it requires the specific optimizer settings described in the paper. The authors used the Adam optimizer with $\beta_1 = 0.9$, $\beta_2 = 0.98$, and $\epsilon = 10^{-9}$.
More importantly, they used a custom learning rate scheduler, often called the "Noam Scheduler." The learning rate increases linearly for the first $warmup_steps$ (usually 4000) and then decreases proportional to the inverse square root of the step number. Without this specific warmup, the Transformer often fails to learn anything at all because the initial gradients are too noisy for the deep stack of attention layers.
Common Pitfalls in Transformer Implementation
In our experience of building and debugging Transformer models, these are the top three areas where implementations fail:
- Masking Errors: Mixing up the look-ahead mask with the padding mask, or applying the mask at the wrong stage of the attention calculation.
- Tensor Dimensions: Getting lost in the transpositions and reshapes of the Multi-Head Attention. Always verify that your query-key dot product results in a
(batch, heads, query_len, key_len)shape. - Initialization: Standard Xavier or Kaiming initialization is usually sufficient, but the original paper uses specific initialization for the embeddings. If your loss doesn't drop, check your initialization and the scaling factor $\sqrt{d_{model}}$.
Summary of Implementation Specifications
| Component | Specification in Paper |
|---|---|
| Layers (N) | 6 Encoder, 6 Decoder |
| $d_{model}$ | 512 |
| Attention Heads (h) | 8 |
| Inner FFN Dimension ($d_{ff}$) | 2048 |
| Dropout | 0.1 |
| Warmup Steps | 4000 |
| Optimizer | Adam |
Conclusion
Implementing the Attention Is All You Need paper is a fundamental exercise for anyone serious about deep learning. While modern libraries like Hugging Face provide optimized versions of these layers, building it from scratch forces you to understand the delicate balance of scaling, masking, and optimization that makes the Transformer the backbone of current AI breakthroughs. By paying close attention to the $\sqrt{d_k}$ scaling and the nuances of the decoder mask, you can build a robust model capable of state-of-the-art performance in sequence transduction tasks.
FAQ
What is the purpose of the $\sqrt{d_k}$ in the attention formula?
It scales the dot product of the Query and Key. Without it, in high dimensions ($d_k=64$), the dot products can become large, leading to extremely small gradients in the softmax layer, which stalls training.
How does the Transformer handle variable sequence lengths?
It uses padding masks. During the attention calculation, a mask is applied to the positions containing padding tokens so the model ignores them.
Can I use the Transformer for tasks other than translation?
Yes. By using only the encoder, you can build models like BERT for classification and NER. By using only the decoder, you can build generative models like GPT for text completion.
Why is Positional Encoding added instead of concatenated?
Adding the encoding saves model parameters and memory. Since the encoding uses specific frequencies, the model can still distinguish the positional signal from the semantic embedding signal within the same vector space.
-
Topic: Attention Is All You Needhttps://proceedings.neurips.cc/paper_files/paper/2017/file/3f5ee243547dee91fbd053c1c4a845aa-Paper.pdf?ref=coloradoai.news
-
Topic: GitHub - MaryFllh/attention_is_all_you_need: Implementation of Transformers as described by the Attention Is All You Need paper · GitHubhttps://github.com/MaryFllh/attention_is_all_you_need
-
Topic: GitHub - AbSomeone/Attention-is-all-you-need: Implementation of Google Brain's 2017 research paper. Attention is all you need! Trained and validated on Opus Books datasethttps://github.com/AbSomeone/Attention-is-all-you-need