Self-Attention Concept

Michael BrenndoerferUpdated February 6, 202650 min read

Part of Language AI Handbook

Self-attention relates every token to every other token in a sequence. Covers queries, keys, values, contextual embeddings, masking, and computational cost.

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Self-Attention Concept

In the previous chapter, we explored attention in encoder-decoder models where the decoder attends to encoder states. This is cross-attention: one sequence attending to a different sequence. But what if a sequence could attend to itself? This simple shift in perspective gives rise to self-attention, the mechanism that powers transformer models and modern language AI.

Self-attention allows each position in a sequence to directly interact with every other position. Instead of processing tokens one at a time through recurrent connections, self-attention computes relationships between all pairs of tokens simultaneously. This architectural change enables parallelization during training and captures long-range dependencies without the vanishing gradient problems that plague RNNs.

To understand why self-attention matters so deeply, consider what it means for a word to have meaning. The word "run" can mean a physical act of running, a computer program execution, a hole in a stocking, or the flow of a color dye. None of these interpretations are accessible from the word alone. Meaning emerges from context, from the words that surround it, from the syntactic role it plays, from the broader discourse it inhabits. Any model that processes words independently, assigning each a fixed representation regardless of its surroundings, is fundamentally limited. Self-attention is the mechanism that allows a model to build truly contextual representations by letting every word examine every other word and ask: "How relevant are you to understanding me?"

The shift from cross-attention to self-attention may sound like a minor technical adjustment, but it changes how we model language. Cross-attention is fundamentally about translation: a decoder reaching backward to an encoder to retrieve relevant source information. Self-attention is about comprehension within a single sequence: every part of the text simultaneously building its meaning by consulting every other part. This is closer to how we understand language. When you read the sentence "The trophy didn't fit in the suitcase because it was too big," you don't process each word and forget the previous ones. You hold the whole sentence in mind, and when you hit the word "it," you immediately search backward to find the right referent. Self-attention formalizes this process computationally.

The story of self-attention is also a story about the limitations of the architectures that came before it. Recurrent neural networks process sequences one token at a time, passing a hidden state forward. This sequential design means that two distant tokens can only interact through a long chain of intermediate states, and each step risks losing or corrupting information. Convolutional models can aggregate local neighborhoods of tokens, but connecting tokens that are far apart requires stacking many layers. Self-attention sidesteps both problems by computing direct connections between any two positions in a single operation. That direct access lets a model learn patterns that require reasoning about long-range structure.

From Cross-Attention to Self-Attention

In encoder-decoder attention, we have two distinct sequences: the encoder outputs serve as keys and values, while the decoder state provides the query. The decoder asks, "Which parts of the input are relevant to what I'm generating right now?"

Self-attention simplifies this setup. Instead of attending across two different sequences, a single sequence attends to itself. Every token in the sequence serves simultaneously as a query, a key, and a value. The question becomes: "For each token in this sequence, which other tokens are most relevant to understanding its meaning in context?"

Self-Attention

Self-attention is an attention mechanism where a sequence attends to itself. Each position can directly interact with every other position in the same sequence, enabling the model to capture dependencies regardless of their distance.

Consider the sentence "The animal didn't cross the street because it was too tired." To understand what "it" refers to, you need to connect it back to "animal" rather than "street." Self-attention enables this by allowing "it" to attend strongly to "animal," building a representation that captures this coreference relationship.

The key insight is that the meaning of a word depends heavily on its context. The word "bank" means something different in "river bank" versus "bank account." Self-attention lets each word gather information from surrounding words to disambiguate and enrich its representation.

Think of self-attention as a mechanism where every word in a sentence gets to vote on how much it contributes to every other word's meaning. The word "tired" votes heavily for "animal" when "it" is being interpreted, because "tired" is more naturally predicated of animals than streets. The word "cross" votes for "street" because streets are things you cross. All of this happens simultaneously, in a single computational pass over the sequence. The result is a set of enriched representations where each word's embedding combines its inherent meaning with its meaning in this specific sentence.

The transition from cross-attention to self-attention also has architectural implications. In an encoder-decoder model with cross-attention, the encoder and decoder are separate modules. The encoder reads the full source sequence, and the decoder generates the target sequence one token at a time, querying the encoder at each step. Self-attention enables a different design: a single stack of layers that can read a sequence, build increasingly rich representations, and either produce a classification or generate output. This is the architecture underlying BERT, GPT, and the entire modern transformer ecosystem.

Historical Context: The Origin of Self-Attention

The self-attention mechanism was introduced in the 2017 paper "Attention Is All You Need" by Vaswani et al. at Google. The paper demonstrated that a model built entirely from attention, with no recurrence or convolution, could outperform existing sequence-to-sequence architectures on machine translation benchmarks. The transformer architecture they described, built around self-attention, became the foundation for BERT (2018), GPT-2 (2019), T5 (2019), and nearly every major language model since. The title of the paper proved prophetic: attention, and specifically self-attention, did turn out to be all you need for language modeling at scale.

All-Pairs Interaction

The defining characteristic of self-attention is all-pairs interaction. For a sequence of nn tokens, self-attention computes interactions between all n2n^2 pairs of positions. Why n2n^2? Each of the nn tokens must compute its relationship with every other token, including itself. Token 1 interacts with tokens 1 through nn (that's nn interactions), token 2 does the same (another nn interactions), and so on for all nn tokens, giving us n×n=n2n \times n = n^2 total interactions.

This is fundamentally different from recurrent models, which process tokens sequentially and must pass information through intermediate states.

In an RNN, if you want information from position 1 to reach position 100, it must flow through 99 intermediate hidden states. Each step risks losing or distorting information. Self-attention eliminates this problem by computing direct connections between any two positions.

The all-pairs property gives self-attention its expressive power. Consider trying to model long-distance syntactic agreement. In English, a subject and verb must agree in number: "The keys to the cabinet are on the table" versus "The key to the cabinets is on the table." The head noun "keys" or "key" determines the verb form, but in a complex sentence with intervening phrases, the distance between them can be substantial. An RNN must carry the number information through every intervening token without losing it, relying on the hidden state to serve as a memory buffer. Self-attention can compute a direct edge from the subject to the verb, regardless of distance.

Similarly, consider coreference: understanding that "it" in "The cat knocked over the vase because it was clumsy" refers to the cat, not the vase. The model needs to compare "it" to all potential antecedents simultaneously, evaluate which one fits semantically, and link the pronoun's representation to the correct noun's representation. An RNN would need to carry candidate antecedent information through the hidden state until the pronoun is encountered. Self-attention computes this comparison directly.

Notice that all-pairs interaction implies that self-attention is permutation equivariant without additional components. If you shuffled the order of tokens in the input, you would get the same attention weights between the same pairs of tokens, just in a different arrangement. This is why positional encodings are necessary: self-attention itself contains no positional information, and we must add it externally. We will return to this point in later sections and chapters, but the result follows directly from the all-pairs design.

In[3]:
Code
import numpy as np

# Simulate information flow in RNN vs self-attention
sequence_length = 10

# RNN: information must flow through intermediate states
# Path length from position i to position j is |j - i|
rnn_path_lengths = np.zeros((sequence_length, sequence_length))
for i in range(sequence_length):
    for j in range(sequence_length):
        rnn_path_lengths[i, j] = abs(j - i)

# Self-attention: direct connection between any two positions
# Path length is always 1 (or 0 for self-connection)
self_attn_path_lengths = np.ones((sequence_length, sequence_length))
np.fill_diagonal(self_attn_path_lengths, 0)
Out[4]:
Visualization
Heatmap showing RNN path lengths with gradient from 0 to 9 based on distance between positions.
RNN path lengths: information must traverse multiple sequential steps to connect distant positions. Connecting position 0 to position 9 requires 9 intermediate steps, with each step risking information loss.
Heatmap showing self-attention path lengths uniformly at 1 except 0 on diagonal.
Self-attention path lengths: every position connects directly to every other position in exactly 1 step (0 for self-connections on the diagonal), enabling lossless long-range information exchange.

The contrast is striking. In the RNN heatmap (left), path lengths grow with distance: connecting position 0 to position 9 requires 9 steps, shown by the dark red corners. The self-attention heatmap (right) is nearly uniform: every position connects to every other position in exactly 1 step (with 0 for self-connections on the diagonal). This constant path length helps capture long-range dependencies without information degradation.

The path length difference has a deeper implication for gradient flow during training. In an RNN trained with backpropagation through time, gradients must also flow backward through these same long paths. If a gradient signal needs to travel from position 100 back to position 1 to update early weights, it must pass through 99 matrix multiplications, each potentially shrinking it toward zero (vanishing gradient) or inflating it toward infinity (exploding gradient). LSTM and GRU cells were invented specifically to alleviate this problem, and they help substantially, but they do not eliminate it. Self-attention, because it computes direct connections, gives gradients equally short paths in both the forward and backward passes. The model can update its parameters based on distant dependencies just as easily as local ones.

Why Self-Attention Works for Representation Learning

Self-attention excels at building contextual representations. A word embedding from Word2Vec or GloVe assigns the same vector to "bank" regardless of context. Self-attention creates contextualized embeddings where each token's representation incorporates information from surrounding tokens.

The process works as follows. Each token starts with an initial embedding. Through self-attention, each token gathers information from all other tokens, weighted by relevance. The output is a new set of representations where each token "knows about" the full sequence context.

This contextual awareness enables several capabilities that static embeddings lack:

  • Word sense disambiguation: The representation of "bank" differs based on surrounding words
  • Coreference resolution: Pronouns can gather information from their antecedents
  • Syntactic awareness: Verbs can connect to their subjects and objects regardless of distance
  • Semantic composition: Phrases and sentences build meaning from their constituent words

To appreciate how powerful this is, it helps to compare it against what came before. Pre-transformer NLP relied on static word embeddings like Word2Vec and GloVe, which encode a word's meaning as a fixed vector that never changes regardless of context. These embeddings capture distributional statistics: "bank" ends up somewhere between "river" and "money" because it co-occurs with both kinds of words in training data. But this is a single point in embedding space, a compromise between two entirely different meanings, not a true representation of either. When the model processes "river bank," it uses the same "bank" vector as when it processes "bank account." Any downstream task must somehow disentangle these meanings using only context provided by neighboring tokens.

Self-attention solves this problem directly. When a transformer processes "river bank," the representation of "bank" is computed as a weighted sum of all tokens in the sentence, with "river" receiving very high weight. The resulting vector is shifted toward the "river"-related region of embedding space. When the same model processes "bank account," the high-weight neighbors are "account," "deposit," "money," and the representation shifts in the financial direction. The same input token produces different output representations depending on context. This is what makes transformer embeddings so much more useful for downstream tasks.

The mechanism also enables compositional understanding in a way that static embeddings cannot. Consider the phrase "not happy." In static embeddings, you might try to negate the "happy" vector, but there is no obvious way to do this without training a separate component. In self-attention, "not" directly attends to "happy" with high weight, and "happy" attends back to "not." The resulting representation of "happy" in this context incorporates information from "not," enabling the model to learn that negated words have different downstream behavior. This is the basis for handling composition, including cases such as negation and intensification.

Let's visualize how self-attention might weight different tokens when processing a simple sentence.

In[5]:
Code
# Example sentence
tokens = ["The", "cat", "sat", "on", "the", "mat"]
n_tokens = len(tokens)

# Simulated attention weights for the word "sat" (position 2)
# In practice, these would be learned; here we illustrate the concept
attention_weights_for_sat = np.array([0.05, 0.45, 0.10, 0.15, 0.05, 0.20])

# The verb "sat" attends strongly to its subject "cat" and object "mat"
Out[6]:
Visualization
Bar chart showing attention weights for each word when processing 'sat', with 'cat' receiving highest weight.
Attention weights when processing the word 'sat'. The model attends most strongly to the subject 'cat' and the location 'mat', illustrating how self-attention captures semantic role relationships between verbs and their arguments regardless of word order.

The visualization shows that when building a representation for "sat," the model attends most strongly to "cat" (the subject performing the action) and "mat" (the location). Function words like "the" and "on" receive less attention. This weighted combination creates a rich representation that captures the verb's relationship to other sentence elements.

This pattern, a verb attending to its syntactic arguments, is precisely the kind of structural awareness that transformers develop during training. The attention weights are not hand-coded. They emerge from optimization: the model learns that representing a verb well requires knowing who performed the action (subject) and what it was performed on or where it occurred (object or adjunct). In a real trained model, you would see systematic patterns: determiners attending to their head nouns, adjectives attending to the nouns they modify, verbs forming attention arcs to their subjects and objects. The attention mechanism provides a soft, differentiable way to implement the kinds of syntactic relationships that linguists have described for decades.

The Computational Pattern

Now that we understand why self-attention is useful, let's examine how it works. The core idea is elegantly simple: to build a contextual representation for any token, we take a weighted average of all tokens in the sequence. The weights reflect how relevant each token is to the one we're updating.

Think of it like asking every word in a sentence: "How much should I pay attention to you when trying to understand myself?" Words that are more relevant get higher weights, and their information contributes more to the final representation.

The elegance of this design is that relevance is computed from the same embeddings that we are trying to enrich. There are no separate relevance signals or external knowledge sources. The model learns, from data, which kinds of tokens should attend to which other kinds of tokens. A verb learns to attend to nouns. A pronoun learns to attend to candidate antecedents. An adjective learns to attend to the noun it modifies. All of this emerges from training on text, supervised only by the task objective.

In practice, this means that self-attention is a form of dynamic, input-dependent aggregation. Unlike a convolution, which always applies the same kernel to local neighborhoods regardless of content, self-attention computes different aggregation weights for every input. Two sentences with different words will produce entirely different attention patterns. The same word in two different sentences will aggregate information from different neighbors with different weights. This input-dependence is what allows self-attention to be sensitive to context in a way that convolutions and bag-of-words models cannot be.

The Three-Stage Pipeline

Self-attention follows a consistent three-stage pattern:

  1. Compute similarity scores: For each pair of positions, calculate a number indicating how relevant one is to the other. High scores mean strong relevance.

  2. Normalize to weights: Raw scores can be any real number. We need to convert them into proper weights that sum to 1, so we can interpret them as "how much attention to pay." The softmax function handles this conversion.

  3. Aggregate values: Finally, compute a weighted sum of all positions' representations. Positions with higher weights contribute more to the output.

This pipeline runs for every position simultaneously, producing a new set of contextual embeddings where each token has gathered information from the entire sequence.

These three stages map onto a natural information-theoretic story. In stage one, we are asking a question: "How related are these two tokens?" In stage two, we are converting raw relatedness scores into a probability distribution over which tokens to consult. In stage three, we are reading the answer: a blend of all tokens' information, weighted by how likely each one is to be the right source.

The beauty of this formulation is that it is fully differentiable. Every step can be computed using standard matrix operations, and gradients flow cleanly through all three stages. This is what makes it possible to train self-attention end-to-end with gradient descent. The model does not need to know in advance which tokens should attend to which. It learns this from data by adjusting the embeddings so that tokens that should attend to each other have high dot products.

From Intuition to Formula

Let's formalize this intuition. Suppose we have a sequence of nn tokens, each represented by a dd-dimensional embedding vector. We can write the input as a matrix:

X=[x1,x2,,xn]\mathbf{X} = [\mathbf{x}_1, \mathbf{x}_2, \ldots, \mathbf{x}_n]

where each xiRd\mathbf{x}_i \in \mathbb{R}^d is the embedding for token ii.

Stage 1: Similarity Scores

How do we measure relevance between two tokens? The simplest approach uses the dot product. If two embedding vectors point in similar directions, their dot product is large and positive. If they're orthogonal (unrelated), the dot product is zero. This gives us a natural measure of similarity.

The dot product is not the only possible similarity measure. You could use cosine similarity, a learned bilinear form, or even a neural network. But the dot product has the virtue of simplicity, efficiency, and a clean geometric interpretation. It is also naturally suited to the way embeddings are trained: if you want two tokens to have high similarity under dot product, you train their embeddings to point in the same direction. This is exactly how the model learns to encode semantic relationships.

For positions ii and jj, the similarity score is:

sij=xixj=k=1dxi,kxj,ks_{ij} = \mathbf{x}_i \cdot \mathbf{x}_j = \sum_{k=1}^{d} x_{i,k} \cdot x_{j,k}

where:

  • sijs_{ij}: the raw similarity score between positions ii and jj
  • xixj\mathbf{x}_i \cdot \mathbf{x}_j: the dot product of the two embedding vectors
  • dd: the embedding dimension
  • xi,kx_{i,k}: the kk-th component of the embedding at position ii

The dot product captures semantic similarity: tokens with similar meanings tend to have similar embeddings, producing high dot products. This is only true if the embeddings have been trained appropriately, but in practice, transformer embeddings rapidly learn to encode semantic similarity in ways that the dot product can exploit.

Stage 2: Softmax Normalization

Raw dot products can be any real number, positive or negative, with no upper bound. To use them as weights for averaging, we need to transform them into a probability distribution. The softmax function accomplishes this:

αij=exp(sij)k=1nexp(sik)\alpha_{ij} = \frac{\exp(s_{ij})}{\sum_{k=1}^{n} \exp(s_{ik})}

where:

  • αij\alpha_{ij}: the attention weight from position ii to position jj
  • exp(sij)\exp(s_{ij}): the exponential function applied to the similarity score. This keeps positivity
  • k=1nexp(sik)\sum_{k=1}^{n} \exp(s_{ik}): the normalizing constant that makes all weights from position ii sum to 1

Why softmax? It has two useful properties:

  1. Positivity: The exponential function maps any real number to a positive value, so all weights are positive.
  2. Normalization: Dividing by the sum ensures j=1nαij=1\sum_{j=1}^{n} \alpha_{ij} = 1, giving us valid weights for a weighted average.

Additionally, softmax amplifies differences: if one score is much higher than others, its weight dominates. This allows the model to focus sharply on the most relevant tokens when appropriate.

There is an important practical consideration here: the scale of the dot products. If the embeddings have dimension dd and their components are approximately unit variance, then the dot product of two random embeddings will have variance approximately dd. For large dd, this means dot products can be very large in magnitude, pushing the softmax into a regime where its gradient is nearly zero. This is the motivation for the scaled dot product that you will encounter in the full query-key-value formulation in the next chapter: dividing by d\sqrt{d} keeps the dot products in a reasonable range where softmax remains informative. For now, the basic formulation is sufficient to understand the core mechanism.

The softmax function also has an interesting normalization property: it computes a local competition. Each token ii does not have a global attention budget that it must divide among all other tokens in the sequence (which would be a simplex constraint across all ii and jj). Instead, for each query position ii, the weights from ii to all key positions jj must sum to 1. This means position ii always attends to something, even if no token is truly relevant. In practice, when no token is highly relevant, the attention spreads uniformly across all tokens, and the output is close to the average of all embeddings.

Stage 3: Weighted Aggregation

With attention weights in hand, we compute the output representation for each position as a weighted sum of all input embeddings:

yi=j=1nαijxj\mathbf{y}_i = \sum_{j=1}^{n} \alpha_{ij} \mathbf{x}_j

where:

  • yi\mathbf{y}_i: the output representation for position ii, now enriched with contextual information
  • αij\alpha_{ij}: the attention weight determining how much position jj contributes to position ii's output
  • xj\mathbf{x}_j: the input embedding at position jj

This formula is the heart of self-attention. Each output yi\mathbf{y}_i is a blend of all inputs, with the blending proportions determined by the learned attention weights. Tokens that are highly relevant to position ii contribute strongly; irrelevant tokens contribute little.

Notice that the output lives in the same vector space as the input: yiRd\mathbf{y}_i \in \mathbb{R}^d, just like xi\mathbf{x}_i. This is important for stacking multiple layers of self-attention. The output of one layer can serve directly as the input to the next, with no change in dimension. Each successive layer can build on the contextual representations computed by the previous one, creating increasingly abstract and task-relevant representations. This is exactly how transformers work: multiple self-attention layers applied in sequence, each one refining the representations produced by the previous layer.

Putting It All Together

The complete self-attention computation flows naturally from these three stages. For every position ii in the sequence:

  1. Compute dot products with all positions: sij=xixjs_{ij} = \mathbf{x}_i \cdot \mathbf{x}_j for j=1,,nj = 1, \ldots, n
  2. Apply softmax to get attention weights: αij=softmax(si1,si2,,sin)j\alpha_{ij} = \text{softmax}(s_{i1}, s_{i2}, \ldots, s_{in})_j
  3. Compute weighted sum: yi=j=1nαijxj\mathbf{y}_i = \sum_{j=1}^{n} \alpha_{ij} \mathbf{x}_j

Because each position's computation is independent of the others, we can process all nn positions in parallel. This parallelism is what makes self-attention so efficient on modern GPU hardware.

In matrix form, the entire computation collapses into three operations: a matrix multiplication to compute scores, a row-wise softmax, and another matrix multiplication to compute outputs. The notation also exposes the implementation: the entire self-attention operation can be executed as two large matrix multiplications, which GPUs and TPUs are specifically designed to perform as fast as possible. The theoretical O(n2d)O(n^2 d) complexity, which sounds expensive, is quite manageable in practice because modern accelerators can execute these matrix operations with extreme parallelism.

Implementation

Let's translate this mathematical framework into code. We'll implement a simple self-attention function that takes a sequence of embeddings and returns the contextual outputs along with the attention weights.

In[7]:
Code
def simple_self_attention(embeddings):
    """
    Simplified self-attention using dot product similarity.

    Args:
        embeddings: numpy array of shape (seq_len, embed_dim)

    Returns:
        output: numpy array of shape (seq_len, embed_dim)
        attention_weights: numpy array of shape (seq_len, seq_len)
    """
    # Step 1: Compute pairwise similarity scores (dot product)
    # Matrix multiplication gives us all n^2 dot products at once
    # scores[i,j] = x_i · x_j
    scores = embeddings @ embeddings.T

    # Step 2: Normalize with softmax (row-wise)
    # Subtract max for numerical stability (prevents overflow in exp)
    scores_stable = scores - scores.max(axis=1, keepdims=True)
    exp_scores = np.exp(scores_stable)
    attention_weights = exp_scores / exp_scores.sum(axis=1, keepdims=True)

    # Step 3: Compute weighted sum of embeddings
    # output[i] = sum_j alpha[i,j] * embeddings[j]
    output = attention_weights @ embeddings

    return output, attention_weights

Notice how the implementation mirrors the three-stage formula. The matrix multiplication embeddings @ embeddings.T computes all n2n^2 dot products simultaneously: entry (i,j)(i, j) contains xixj\mathbf{x}_i \cdot \mathbf{x}_j. The softmax is applied row-wise, so each row of attention weights sums to 1. Finally, multiplying the attention weights by the embeddings computes all weighted sums in parallel.

The numerical stability trick of subtracting the row maximum before exponentiating is worth understanding. The exponential function grows extremely quickly: e100e^{100} is a number so large it overflows standard 32-bit floating point. However, softmax has a mathematical property that allows us to subtract any constant from all inputs without changing the output. If we subtract the maximum value in each row, we ensure that the largest exponentiated value is e0=1e^0 = 1, and all other values are between 0 and 1. This does not change the softmax output but prevents numerical overflow.

Let's test this on a small sequence to see the attention mechanism in action:

In[8]:
Code
# Create simple embeddings for demonstration
np.random.seed(42)
seq_len, embed_dim = 4, 8
embeddings = np.random.randn(seq_len, embed_dim)

# Apply self-attention
output, attention_weights = simple_self_attention(embeddings)
Out[9]:
Console
Input shape: (4, 8)
Output shape: (4, 8)
Attention weights shape: (4, 4)

Attention weight matrix (rows sum to 1):
[[0.997 0.    0.    0.003]
 [0.    0.99  0.008 0.001]
 [0.    0.007 0.993 0.   ]
 [0.003 0.007 0.    0.99 ]]

Row sums: [1. 1. 1. 1.]

The attention weight matrix is n×nn \times n, where entry (i,j)(i, j) tells us how much position ii attends to position jj. Each row sums to exactly 1.0, confirming that softmax produces valid probability distributions. The output has the same shape as the input: each of our 4 tokens now has a new 8-dimensional representation that incorporates information from all other tokens.

Visualizing Self-Attention

A heatmap provides an intuitive view of self-attention patterns. Rows represent query positions (which token is gathering information), and columns represent key positions (which tokens are being attended to). Darker cells indicate stronger attention.

Out[10]:
Visualization
Heatmap showing attention weights between four positions, with strong diagonal weights near 1.0 and off-diagonal weights near zero.
Self-attention weight heatmap for a four-token sequence with random embeddings. Each row shows how one token distributes attention across all positions, with darker colors indicating stronger attention. Even with random embeddings, the softmax normalization ensures each row sums to 1, producing a valid probability distribution over positions.

In this random example, we see some diagonal emphasis where tokens attend to themselves, plus distributed attention to other positions. In trained models, these patterns become meaningful: related words attend strongly to each other, syntactic structures emerge, and semantic relationships become visible.

Researchers have spent considerable effort interpreting what trained attention patterns mean. In models like BERT, some attention heads learn to attend to the next token, some to the previous token, some to the sentence separator tokens. Other heads develop more linguistically interpretable patterns: there are heads that attend from verbs to subjects, from pronouns to antecedents, from nouns to modifying adjectives. This does not mean that each head has a single clean function. In practice, the patterns are messy and context-dependent. But the existence of interpretable patterns suggests that self-attention does learn to exploit syntactic and semantic structure.

The diagonal is informative. Random embeddings tend to produce some diagonal emphasis because the dot product of a vector with itself is always larger than with a random other vector. In trained models, the diagonal is often strong, meaning tokens attend significantly to themselves. This makes sense: a token's own embedding contains the most concentrated information about that token. The off-diagonal weights then represent how much additional context each token gathers from its neighbors.

Self-Attention vs Recurrence

Self-attention and recurrence represent fundamentally different approaches to sequence modeling. Understanding their trade-offs clarifies why transformers have largely replaced RNNs for most NLP tasks.

Parallelization: RNNs process tokens sequentially because each hidden state depends on the previous one. Self-attention computes all pairwise interactions simultaneously, enabling massive parallelization on GPUs. This difference dramatically accelerates training on modern hardware.

Long-range dependencies: In an RNN, information must flow through many timesteps to connect distant positions. Gradients can vanish or explode along this path. Self-attention connects any two positions directly, making it easier to learn long-range dependencies.

Computational complexity: Self-attention computes n2n^2 pairwise interactions for a sequence of length nn, where nn is the number of tokens. RNNs have linear complexity, meaning their computational cost grows proportionally to nn. For very long sequences, the quadratic cost of self-attention becomes prohibitive: doubling the sequence length quadruples the computation. This motivates efficient attention variants.

Positional information: RNNs inherently encode position through their sequential processing. Self-attention treats all positions symmetrically and requires explicit positional encodings to distinguish word order. We'll cover positional encodings in a later chapter.

It is worth pausing on the parallelization advantage, because it is easy to underestimate how important it is. The difference between O(n)O(n) and O(n2)O(n^2) operations sounds like RNNs should be faster, but this analysis ignores the sequential bottleneck. An RNN processing a sequence of length nn must execute nn sequential steps, because step tt depends on the output of step t1t-1. No amount of hardware parallelism can overcome this dependency. A modern GPU with thousands of cores cannot use most of them to process a single RNN sequence, because at each step, only one computation is active.

Self-attention, by contrast, computes all n2n^2 pairwise interactions simultaneously. With sufficient hardware, these can all be computed in parallel, making the wall-clock time essentially constant regardless of sequence length (up to memory constraints). In practice, the n2n^2 operations are organized as two matrix multiplications, each of which maps perfectly onto GPU tensor cores. This is why transformers can be trained on sequences of thousands of tokens in reasonable time, while training deep RNNs on sequences longer than a few hundred tokens was extremely slow.

The practical consequence of this difference was the scaling revolution. Transformers could be trained on much larger datasets in less time than RNNs, because more of the compute could be utilized in parallel. This, combined with the architectural improvements from self-attention, is why models like BERT and GPT-2 represented such dramatic jumps in capability compared to their RNN-based predecessors.

Memory requirements: Self-attention must store the entire n×nn \times n attention weight matrix during computation, requiring O(n2)O(n^2) memory. For a sequence of 10,000 tokens, this is 100 million weights, which requires several gigabytes of memory even in 16-bit precision. RNNs require only O(nd)O(nd) memory, where dd is the hidden state dimension, because only the current hidden state needs to be stored. This memory bottleneck is one of the key practical constraints on self-attention and has motivated research into memory-efficient attention variants.

Inductive biases: RNNs have a strong inductive bias toward local, recency-weighted processing. They naturally place more emphasis on recent tokens (the hidden state is more directly influenced by recent inputs) and require explicit mechanisms like LSTMs to maintain long-term information. Self-attention has a weaker, more uniform inductive bias: all positions are treated symmetrically, and the model must learn from data which positions are relevant. This makes self-attention more flexible but also means it requires more data to learn good patterns from scratch.

In[11]:
Code
# Compare computational patterns
def analyze_complexity(seq_lengths):
    """Compare RNN vs self-attention complexity."""
    results = []
    for n in seq_lengths:
        rnn_ops = n  # Sequential, linear in sequence length
        self_attn_ops = n * n  # All-pairs, quadratic
        results.append(
            {
                "seq_len": n,
                "rnn": rnn_ops,
                "self_attention": self_attn_ops,
                "ratio": self_attn_ops / rnn_ops,
            }
        )
    return results


seq_lengths = [10, 50, 100, 500, 1000]
complexity = analyze_complexity(seq_lengths)
Out[12]:
Visualization
Line plot showing linear RNN complexity and quadratic self-attention complexity diverging as sequence length increases.
Computational complexity scaling: RNN (linear O(n)) vs self-attention (quadratic O(n^2)). While self-attention requires dramatically more operations for long sequences, these operations are fully parallelizable. The quadratic curve illustrates why processing very long documents requires either hardware with large memory or efficient attention approximations.

The quadratic growth of self-attention is dramatic: at sequence length 1000, self-attention requires 1 million operations compared to just 1000 for an RNN. However, self-attention's operations are independent and can run in parallel on GPUs, while RNN operations must be sequential. This trade-off explains why transformers dominate despite higher theoretical complexity: parallelism wins on modern hardware.

To put concrete numbers on this: a typical transformer layer with sequence length 512 and embedding dimension 768 spends roughly 40% of its compute on the attention matrix multiplication and 60% on the feed-forward layers. The quadratic bottleneck is real but manageable for sequences of a few hundred to a few thousand tokens. For the long-context models that have emerged recently, with context windows of 32,000 or 128,000 tokens, efficient attention algorithms (such as FlashAttention, which reorganizes the computation to minimize memory bandwidth rather than total operations) are essential.

Building Intuition with a Worked Example

The formulas become clearer when we trace through a concrete example step by step. Let's process a three-word sequence, "I love coffee," using tiny 2-dimensional embeddings. With only 2 dimensions, we can easily verify each calculation by hand and visualize what's happening geometrically.

We'll assign each word an embedding that points in a different direction:

In[13]:
Code
# Three-word sequence with 2D embeddings
words = ["I", "love", "coffee"]
embeddings_2d = np.array(
    [
        [1.0, 0.0],  # "I" - points along first axis
        [0.5, 0.5],  # "love" - between axes (45 degrees)
        [0.0, 1.0],  # "coffee" - points along second axis
    ]
)

These embeddings form a simple geometric arrangement: "I" points east, "coffee" points north, and "love" points northeast, lying exactly between them. This setup will help us understand how the dot product captures similarity.

The geometric interpretation is instructive. The dot product xixj\mathbf{x}_i \cdot \mathbf{x}_j can be written as xixjcosθ|\mathbf{x}_i| |\mathbf{x}_j| \cos\theta, where θ\theta is the angle between the two vectors. Vectors pointing in the same direction (θ=0\theta = 0) have dot product equal to the product of their magnitudes. Perpendicular vectors (θ=90°\theta = 90°) have dot product zero. Vectors pointing in opposite directions have negative dot products. Our toy embeddings are set up so that "I" and "coffee" are perpendicular, making their dot product zero, while "love" makes a 45-degree angle with each, giving it identical dot products with both.

Out[14]:
Visualization
2D plot with three vectors as arrows from origin: I pointing right, coffee pointing up, love pointing diagonally.
2D embedding space showing the three word vectors. ''I'' points east along the x-axis, ''coffee'' points north along the y-axis, and ''love'' lies at 45 degrees between them. The geometric arrangement determines the dot product similarities: perpendicular vectors like ''I'' and ''coffee'' have zero dot product, while ''love'' has equal moderate similarity to both.

The geometric arrangement makes the dot product intuition clear: vectors pointing in similar directions have high dot products, while perpendicular vectors have zero dot product.

Step 1: Computing Similarity Scores

First, we compute the dot product between every pair of words. Remember, the dot product xixj\mathbf{x}_i \cdot \mathbf{x}_j measures how much two vectors point in the same direction.

In[15]:
Code
# Compute similarity scores (dot products)
scores_2d = embeddings_2d @ embeddings_2d.T
Out[16]:
Console
Similarity scores (dot products):
                 I     love   coffee
I          1.00    0.50    0.00
love       0.50    0.50    0.50
coffee     0.00    0.50    1.00

Let's interpret this matrix:

  • Diagonal entries (1.00, 0.50, 1.00): These are self-similarities. "I" and "coffee" have unit-length embeddings, so their self-dot-products are 1.0. "love" has length 0.52+0.52=0.50.71\sqrt{0.5^2 + 0.5^2} = \sqrt{0.5} \approx 0.71, giving a self-dot-product of 0.5.

  • "I" vs "coffee" (0.00): These vectors are perpendicular (orthogonal), so their dot product is zero. In embedding space, this means they share no directional similarity.

  • "love" vs others (0.50): "love" points between "I" and "coffee," giving it moderate similarity to both. The dot product of 0.5 reflects this intermediate relationship.

The asymmetry between "love" and itself (0.50) versus "I" and "coffee" and themselves (1.00) comes from vector length. The dot product is not normalized, so longer vectors have higher self-similarity. This is one reason why the scaled dot product version of self-attention (which we will study in the next chapter) sometimes normalizes embedding lengths. In this toy example, the unnormalized dot product is sufficient to see the main intuition.

Step 2: Applying Softmax

Raw dot products aren't suitable weights for averaging because they don't sum to 1. The softmax function maps each row into a probability distribution:

In[17]:
Code
# Apply softmax to get attention weights
def softmax_rows(x):
    exp_x = np.exp(x - x.max(axis=1, keepdims=True))
    return exp_x / exp_x.sum(axis=1, keepdims=True)


attention_2d = softmax_rows(scores_2d)
Out[18]:
Console
Attention weights (after softmax):
                 I     love   coffee
I         0.506   0.307   0.186
love      0.333   0.333   0.333
coffee    0.186   0.307   0.506

Now each row sums to 1.0, and we can interpret the values as "attention percentages":

  • "I" attends most to itself (about 58%), moderately to "love" (31%), and least to "coffee" (11%). This makes sense: "I" had the highest dot product with itself, moderate with "love," and zero with "coffee."

  • "love" distributes attention more evenly across all three words (about 33% each). Its embedding lies between the others, giving it similar dot products with everyone.

  • "coffee" mirrors "I": it attends mostly to itself, moderately to "love," and barely to "I."

The softmax has transformed our raw similarities into a meaningful attention distribution. Higher similarity scores become higher attention weights, but even zero-similarity pairs get some weight (the exponential of 0 is 1, not 0). This is an important property: softmax never produces exactly zero weights. Every token always attends at least a little to every other token, which prevents the model from completely ignoring any part of the input. The practical implication is that the information flow in self-attention is always fully dense, not sparse.

Notice also the symmetry in this particular example: the attention weight from "I" to "coffee" (0.11) equals the weight from "coffee" to "I" (0.11). This symmetry arises because our scores matrix is symmetric: sij=xixj=xjxi=sjis_{ij} = \mathbf{x}_i \cdot \mathbf{x}_j = \mathbf{x}_j \cdot \mathbf{x}_i = s_{ji}. In the full query-key-value formulation of self-attention (covered in the next chapter), separate learned projections break this symmetry, allowing "I" attending to "coffee" to have a different weight than "coffee" attending to "I." This asymmetry is linguistically meaningful: a pronoun attending to its antecedent is not the same relationship as the antecedent attending to the pronoun.

Step 3: Computing Contextual Outputs

Finally, we use these attention weights to compute a weighted average of all embeddings for each position:

In[19]:
Code
# Compute output representations
output_2d = attention_2d @ embeddings_2d
Out[20]:
Console
Output representations:
I: [0.660, 0.340]
love: [0.500, 0.500]
coffee: [0.340, 0.660]

Original vs Output comparison:
I: [1.0, 0.0] -> [0.660, 0.340]
love: [0.5, 0.5] -> [0.500, 0.500]
coffee: [0.0, 1.0] -> [0.340, 0.660]

The transformation is subtle but meaningful. Each word's representation has shifted toward the other words, with the amount of shift determined by the attention weights:

  • "I" started at [1.0, 0.0] and moved to approximately [0.73, 0.27]. It picked up some "northward" component from "love" and "coffee."

  • "love" started at [0.5, 0.5] and stayed close to its original position. Because it attended fairly evenly to all words, and it was already in the "middle," the weighted average didn't change it much.

  • "coffee" started at [0.0, 1.0] and moved to approximately [0.27, 0.73]. It picked up some "eastward" component from "I" and "love."

This is the essence of self-attention: each word's output is no longer just its own embedding, but a blend of all words' embeddings, weighted by relevance. The word "I" now "knows about" the context of "love" and "coffee." This contextual blending is what enables transformers to build rich, context-dependent representations.

In a real model with high-dimensional embeddings and learned projections, this blending is much more expressive. The model can choose to gather very specific types of information from context: syntactic information from one head, semantic information from another, positional information from a third. But the fundamental mechanism is the same weighted average you see in this toy example.

Out[21]:
Visualization
2D plot showing original and transformed embeddings with arrows indicating the shift direction for each word.
How self-attention transforms embeddings in the 'I love coffee' example. Original positions (hollow circles) shift toward the weighted average of all embeddings, producing contextual outputs (filled circles). 'I' and 'coffee' move substantially toward each other via the intermediate 'love' vector, while 'love' barely shifts because it was already centrally positioned.

The visualization captures the essence of self-attention geometrically. Each word's representation moves toward the center of mass of all words, weighted by attention. "I" and "coffee" shift significantly toward each other (via "love"), while "love" barely moves because it was already centrally positioned. After this transformation, all three words carry information about the full context.

What the Example Reveals

This worked example, despite its simplicity, illustrates several important properties of self-attention that generalize to real models.

First, the outputs are always convex combinations of the inputs. Because attention weights are non-negative and sum to 1, the output yi\mathbf{y}_i is a weighted average: it lies in the convex hull of all input embeddings. This means self-attention cannot produce representations that are "outside" the range of the inputs; it can only blend and interpolate. This is both a strength (it is a stable, well-behaved operation) and a limitation (it cannot extrapolate beyond what is present in the input). The feed-forward layers that follow self-attention in a transformer block are responsible for introducing the non-linearity and capacity to produce outputs that go beyond simple blending.

Second, the transformation is context-dependent. The attention weights, and therefore the output representations, change with every different input sequence. Run the same three-word sequence through a random permutation (say, "coffee I love") and the attention weights will be different, and the output representations will be different. This context-dependence is what makes self-attention fundamentally more powerful than any fixed transformation.

Third, the mechanism is symmetric in the simplified version here, but asymmetric in the full QKV formulation. When queries and keys are computed by separate learned projections (rather than using the raw embeddings for both), the relationship "how much does position ii attend to position jj" can differ from "how much does position jj attend to position ii." This asymmetry is linguistically important and is one reason why the full QKV formulation is more expressive.

Attention Patterns in Trained Models

While the worked example used random or hand-crafted embeddings, trained transformer models develop rich, interpretable attention patterns. Understanding what these patterns look like in practice helps build intuition for what self-attention is doing in models like BERT and GPT.

In BERT, researchers have visualized and analyzed the attention patterns of individual heads across its twelve layers. Several patterns emerge consistently. Some heads learn to attend predominantly to the next token or the previous token, effectively encoding local context. These heads are similar in function to a bigram model: they give each token information about its immediate neighbor. Other heads attend strongly to the separator tokens (the [CLS] and [SEP] tokens in BERT), which serve as aggregate representations of the entire sequence. Still other heads develop more linguistically structured patterns, with verbs attending to their subjects, determiners attending to their head nouns, and coreferent mentions attending to each other.

The emergence of these patterns is not guaranteed and is not the result of any explicit supervision signal telling the model "this head should learn dependency parsing." It arises entirely from the combination of the attention mechanism, the pretraining objective, and the optimization pressure of fitting a large training corpus. The model discovers that representing language well requires tracking syntactic and semantic relationships, and it distributes this work across its many attention heads.

In GPT-style autoregressive models, the attention patterns have a different character because causal masking prevents each position from attending to future positions. The pattern must be lower-triangular: position ii can only attend to positions 1,,i1, \ldots, i. Within this constraint, heads still develop specialized functions: some heads track long-range subject-verb agreement, some attend to the most recent noun phrase (tracking the current topic), and some attend to specific function words that signal discourse structure.

In practice, the learned attention patterns are noisier and more complex than the idealized examples in textbooks. Many heads attend to a diffuse mixture of positions. This contributes to the representation without any single head being primarily responsible for a specific linguistic function. The "division of labor" across heads is more statistical than categorical. But the overall picture is clear: self-attention learns to implement something resembling the kinds of dependency structures that linguists have described, because these structures are what the training data demands.

The Role of Self-Attention in the Transformer Architecture

Self-attention does not operate in isolation. In a transformer, each self-attention layer is followed by a position-wise feed-forward network, layer normalization, and residual connections. Understanding how these components interact helps clarify what self-attention's specific contribution is.

The residual connection is particularly important for understanding self-attention's role. Rather than replacing the input representations entirely, self-attention adds to them. The output of a self-attention layer is added back to its input:

zi=xi+SelfAttn(xi,X)\mathbf{z}_i = \mathbf{x}_i + \text{SelfAttn}(\mathbf{x}_i, \mathbf{X})

where SelfAttn(xi,X)\text{SelfAttn}(\mathbf{x}_i, \mathbf{X}) denotes the self-attention output for position ii given the full sequence X\mathbf{X}. This means each token retains its original representation and supplements it with contextual information gathered from the sequence. The self-attention output is a correction or augmentation, not a replacement.

This residual formulation has important consequences for learning and for interpretation. It means the gradient always has a direct path from the output to any earlier representation, without passing through the attention operation. This prevents vanishing gradients and allows very deep networks to be trained. It also means that in the early layers of a transformer, the representations are still relatively close to the original embeddings, with self-attention providing small contextual corrections. In later layers, the residual additions accumulate, producing representations that are substantially richer than the original embeddings.

The feed-forward network that follows each self-attention layer plays a complementary role. While self-attention blends information across positions, the feed-forward network operates independently on each position, applying the same learned transformation to each token's representation. The feed-forward network introduces non-linearity that self-attention lacks, and it provides the capacity to perform complex transformations on individual token representations after they have been enriched with context.

Layer normalization, applied before or after each sub-layer (depending on the specific architecture variant), keeps the activations in a stable range throughout the network. This stabilizes training in deep transformers: without normalization, the accumulation of residual additions would cause the representations to grow in magnitude, eventually making the softmax in the attention mechanism saturate and gradients vanish.

Together, these components create a system where self-attention handles the cross-position information flow and the feed-forward network handles the per-position transformation. Self-attention is responsible for asking and answering the question "what information from the sequence is relevant to this position?" while the feed-forward network is responsible for asking "given this enriched representation, what feature should I extract or computation should I perform?"

Limitations and Impact

Self-attention transformed NLP by enabling parallel processing and direct long-range connections. The transformer architecture, built on self-attention, powers models such as BERT and GPT. These models achieve state-of-the-art results across virtually all NLP benchmarks.

However, self-attention has significant limitations. The quadratic complexity in sequence length makes it expensive for long documents. Processing a 10,000-token document requires computing 100 million pairwise interactions. This has motivated research into efficient attention variants, including Longformer and BigBird alongside linear-attention mechanisms that reduce complexity while preserving much of self-attention's power.

The quadratic complexity also creates a memory bottleneck. During training, the entire attention weight matrix must be stored for the backward pass. For a batch of 32 sequences, each 2048 tokens long, with 12 attention heads, this is approximately 32 × 12 × 2048 × 2048 × 4 bytes ≈ 6 gigabytes for attention weights alone, before accounting for activations and gradients. This is one reason why very long context models require specialized hardware and training techniques.

Self-attention also lacks inherent positional awareness. Unlike RNNs, which process tokens in order, self-attention treats the sequence as a set. The sentence "dog bites man" would produce the same attention weights as "man bites dog" without explicit positional information. Transformers address this with positional encodings, but the need for this additional component reveals a fundamental limitation of the attention mechanism itself.

The position-agnostic nature of self-attention is also a limitation for generalization. A model trained on sequences up to length 512 may struggle with sequences of length 1024, not because 1024-length sequences are inherently harder, but because the positional encodings for positions 513-1024 were never seen during training. Research into relative positional encodings and rotary position embeddings (RoPE) has addressed some of these generalization issues, and modern models like GPT-4 can handle very long contexts, but the fundamental tension between self-attention's position-agnosticism and the importance of position in language remains an active area of research.

Self-attention is also not well-suited to online or streaming inference. Because the computation requires the full attention matrix, you cannot process a sequence incrementally as tokens arrive without either recomputing from scratch or caching the key and value matrices. The key-value cache is the standard solution for autoregressive generation (used in every GPT-style model), but it requires storing O(n)O(n) intermediate representations, which can be memory-intensive for very long sequences.

Despite these challenges, self-attention's benefits outweigh its costs for most NLP applications. The ability to train on massive datasets with full parallelization, combined with the capacity to model arbitrary dependencies, has made transformer-based models the dominant paradigm in modern language AI. The limitations have motivated a rich line of research into efficient attention, and many of the most important advances in the field since 2017 can be traced directly to the need to scale or extend the basic self-attention mechanism.

The impact of self-attention extends beyond NLP. Vision transformers (ViTs) apply self-attention to sequences of image patches, achieving state-of-the-art performance on image classification tasks. Transformers have been applied to protein structure prediction (AlphaFold2), audio synthesis (AudioLM), video understanding, and reinforcement learning. The mechanism's generality, its ability to model arbitrary pairwise relationships in any kind of structured sequence, is what makes it so broadly applicable. Self-attention applies beyond language; it is a general-purpose mechanism for building representations of structured data.

Summary

Self-attention is the mechanism that allows a sequence to attend to itself, enabling each position to gather information from all other positions. This simple idea changes how we build language models.

Key takeaways from this chapter:

  • Self-attention vs cross-attention: In cross-attention, one sequence attends to another. In self-attention, a sequence attends to itself, with each token serving in a QKV role simultaneously.
  • All-pairs interaction: Self-attention computes direct connections between all n2n^2 pairs of positions (where nn is the sequence length), eliminating the need for information to flow through intermediate states.
  • Contextual representations: By aggregating information from surrounding tokens, self-attention creates embeddings that capture word meaning in context, enabling disambiguation, coreference resolution, and syntactic awareness.
  • Parallelization: Unlike recurrent models, self-attention computes all interactions simultaneously, enabling efficient training on modern hardware and allowing the field to scale to much larger models and datasets.
  • Quadratic complexity: The all-pairs computation scales as O(n2)O(n^2), meaning computational cost grows with the square of sequence length nn. This makes self-attention expensive for very long sequences and has motivated research into efficient attention variants.
  • Position agnostic: Self-attention treats sequences as sets, requiring explicit positional encodings to capture word order. Without positional information, permuting the input tokens produces the same attention weights.
  • Residual integration: In transformer blocks, self-attention output is added to the input via residual connections, meaning each layer enriches rather than replaces the existing representations.

The next chapter covers how self-attention computes these interactions through QKV projections. These learned linear transformations give self-attention its full expressiveness, allowing the model to compute asymmetric, task-specific attention patterns and to specialize different projections for different aspects of context. Understanding the QKV formulation is essential for implementing and reasoning about transformer models.

Quiz

Ready to test your understanding? Take this quick quiz to reinforce what you've learned about self-attention.

Self-Attention Concept Quiz

Question 1 of 100 of 10 completed
What is the key difference between cross-attention and self-attention?

Comments

No comments yet. Be the first to share your thoughts!

Reference

Citation details

Cite or share this article.

BIBTEXAcademic
@misc{brenndoerfer2025selfattention, author = {Michael Brenndoerfer}, title = {Self-Attention Concept}, year = {2025}, url = {https://mbrenndoerfer.com/writing/self-attention-concept}, organization = {mbrenndoerfer.com}, note = {Accessed: 2026-09-15} }
APAAcademic
Michael Brenndoerfer (2025). Self-Attention Concept. Retrieved from https://mbrenndoerfer.com/writing/self-attention-concept
MLAAcademic
Michael Brenndoerfer. "Self-Attention Concept." 2026. Web. September 15, 2026. <https://mbrenndoerfer.com/writing/self-attention-concept>.
CHICAGOAcademic
Michael Brenndoerfer. "Self-Attention Concept." Accessed September 15, 2026. https://mbrenndoerfer.com/writing/self-attention-concept.
HARVARDAcademic
Michael Brenndoerfer (2025) 'Self-Attention Concept'. Available at: https://mbrenndoerfer.com/writing/self-attention-concept (Accessed: September 15, 2026).
SimpleBasic
Michael Brenndoerfer (2025). Self-Attention Concept. https://mbrenndoerfer.com/writing/self-attention-concept

About the author

Continue with the full handbook

This chapter is part of Language AI Handbook. Use the handbook page to browse the complete table of contents and continue reading in sequence.

Explore Language AI Handbook
Newsletter

Stay up to date

Get articles, book updates, and news delivered to your inbox.

No spam, unsubscribe anytime.

or

Join the community

Sign in to remove popups, track your reading progress, and join the discussion.