Recurrent Memory › Relative Position Encoding in Transformer-XL

Michael BrenndoerferUpdated July 6, 202515 min read
Language AI HandbookAll chapters
Part 18 of 67Long Context
Chapter 132Recurrent Memory › Relative Position Encoding in Transformer-XL
Reading section 6 of 14 · Relative Position Encoding in Transformer-XL · 15 minSection 6 of 14 · 15 min

Book contents

Section 6 of 14 · 15 min read

Recurrent Memory › Relative Position Encoding in Transformer-XLOne section · Sections in this chapter6 / 14 ↓
Reading tools Definitions & inline links

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

We've established that segment-level recurrence breaks absolute position encodings. A token at position 5 in the cached segment and position 5 in the current segment have the same absolute encoding, yet they are 8 positions apart from the perspective of the current segment. How do we fix this? The answer lies in rethinking what position information attention needs.

Attention computes a score between every query and every key to decide how much information should flow from each key to each query. Position information enters this computation to reflect the fact that two tokens at different positions should interact differently than two tokens at the same position. But the original formulation bakes in a specific assumption: that absolute position matters. Transformer-XL's relative position encoding challenges this assumption and replaces it with a more fundamental one: what matters is not where each token is, but how far apart the tokens are.

This changes the role of position information. The same pair of query and key content at a distance of 3 positions should produce the same position-influenced attention score regardless of whether that query is at absolute position 10 or absolute position 1000. The distance is always 3, so the position contribution to attention should always be the same. This property is called translation equivariance, and it is exactly what relative position encodings provide.

Think of relative position encoding as teaching the model about spatial relationships rather than absolute coordinates. Just as you naturally say "the store is two blocks north of here" rather than "the store is at GPS coordinates 37.7749, -122.4194," relative encodings describe relationships, not locations. Two tokens that are adjacent will always have a relative distance of 1, regardless of where they appear in the document.

Why Relative Distance Matters

When you read a sentence like "The cat sat on the mat because it was tired," you understand that "it" refers to "cat" not because of their absolute positions in the document, but because of their relative proximity. The pronoun comes shortly after its antecedent. This observation is the key insight: attention cares about how far apart tokens are, not where they are in absolute terms.

Consider two identical queries, one at position 10 and one at position 100, both attending to keys that are 3 positions before them. If the tokens involved have the same content, shouldn't these attention computations behave similarly? With absolute position encodings, they don't, because positions 7 and 97 have completely different encodings. With relative position encodings, they do, because "3 positions back" always means the same thing.

The implications for generalization are significant. If a model trained on sequences of length 512 learns that pronouns tend to refer to nouns within the previous 20 tokens, that pattern should generalize to any position in any sequence. Absolute position encodings undermine this generalization by making the same pattern look different at different absolute positions. Relative position encodings make the pattern position-agnostic, which is exactly what we want.

Decomposing Standard Attention

To understand how Transformer-XL achieves relative position encoding, we need to first dissect how position information enters standard attention. In the original transformer, the attention score between a query at position ii and a key at position jj starts as a simple dot product:

scoreij=qi⊤kj\text{score}_{ij} = \mathbf{q}_i^\top \mathbf{k}_j

where:

  • scoreij\text{score}_{ij}: the attention score determining how much position ii attends to position jj
  • qi\mathbf{q}_i: the query vector at position ii
  • kj\mathbf{k}_j: the key vector at position jj

But where does position come in? The original transformer adds position embeddings to token embeddings before projecting to queries and keys. So the query at position ii is Wq(xi+pi)W_q(\mathbf{x}_i + \mathbf{p}_i) and the key at position jj is Wk(xj+pj)W_k(\mathbf{x}_j + \mathbf{p}_j). Substituting these into the dot product and using the distributive property of matrix multiplication:

scoreij=(xi+pi)⊤Wq⊤Wk(xj+pj)\text{score}_{ij} = (\mathbf{x}_i + \mathbf{p}_i)^\top W_q^\top W_k (\mathbf{x}_j + \mathbf{p}_j)

where:

  • xi,xj\mathbf{x}_i, \mathbf{x}_j: token embeddings at positions ii and jj
  • pi,pj\mathbf{p}_i, \mathbf{p}_j: absolute position embeddings for positions ii and jj
  • Wq,WkW_q, W_k: learnable query and key projection matrices

This is where the magic of algebra reveals hidden structure. When we expand this product using the distributive property, we get four distinct terms:

scoreij=xi⊤Wq⊤Wkxj⏟content-content+xi⊤Wq⊤Wkpj⏟content-position+pi⊤Wq⊤Wkxj⏟position-content+pi⊤Wq⊤Wkpj⏟position-position\text{score}_{ij} = \underbrace{\mathbf{x}_i^\top W_q^\top W_k \mathbf{x}_j}_{\text{content-content}} + \underbrace{\mathbf{x}_i^\top W_q^\top W_k \mathbf{p}_j}_{\text{content-position}} + \underbrace{\mathbf{p}_i^\top W_q^\top W_k \mathbf{x}_j}_{\text{position-content}} + \underbrace{\mathbf{p}_i^\top W_q^\top W_k \mathbf{p}_j}_{\text{position-position}}

Each term tells us something different about why one token might attend to another:

  • Content-content: "Does this token's meaning relate to that token's meaning?" This is pure semantic matching, independent of where the tokens appear.
  • Content-position: "Given what this token is looking for, does that position matter?" For example, a verb might preferentially attend to its subject, which typically precedes it.
  • Position-content: "Given where this token is, does that token's content matter more?" Early positions might attend differently than late positions.
  • Position-position: "Do these two positions have an inherent affinity?" Adjacent positions might naturally attend to each other.

Why does this decomposition matter? Because it shows us exactly which parts of the attention score use absolute positions. Terms (b), (c), and (d) all depend on pi\mathbf{p}_i or pj\mathbf{p}_j (or both), the absolute position embeddings. These are the terms we need to fix. Term (a) is already position-free and can stay as is.

From Absolute to Relative

The problem with this decomposition is that all position information uses absolute positions pi\mathbf{p}_i and pj\mathbf{p}_j. Transformer-XL's insight is that we can rewrite these terms to use relative position instead. The redesign makes two key changes:

  1. Replace the key's absolute position with relative distance: Instead of pj\mathbf{p}_j (the absolute position of the key), use ri−j\mathbf{r}_{i-j} (the relative distance from query to key).

  2. Replace the query's position with a learned global bias: The query's absolute position pi\mathbf{p}_i becomes learned vectors u\mathbf{u} and v\mathbf{v} that don't depend on position at all.

The first change makes sense because the key's absolute position is what we want to replace. We want to say "this key is 5 positions before this query" rather than "this key is at absolute position 47." The second change is more subtle: the query's absolute position would still be ambiguous across segment boundaries even after fixing the key's encoding, so we replace it with a global learned bias that captures the query's general tendency to prefer nearby or distant keys, independent of where in the document the query appears.

The resulting formula is:

scoreij=xi⊤Wq⊤Wk,Exj⏟(a)+xi⊤Wq⊤Wk,Rri−j⏟(b)+u⊤Wk,Exj⏟(c)+v⊤Wk,Rri−j⏟(d)\text{score}_{ij} = \underbrace{\mathbf{x}_i^\top W_q^\top W_{k,E} \mathbf{x}_j}_{(a)} + \underbrace{\mathbf{x}_i^\top W_q^\top W_{k,R} \mathbf{r}_{i-j}}_{(b)} + \underbrace{\mathbf{u}^\top W_{k,E} \mathbf{x}_j}_{(c)} + \underbrace{\mathbf{v}^\top W_{k,R} \mathbf{r}_{i-j}}_{(d)}

where:

  • xi,xj\mathbf{x}_i, \mathbf{x}_j: token embeddings at positions ii and jj, unchanged from before
  • ri−j\mathbf{r}_{i-j}: a sinusoidal encoding of the relative distance i−ji - j, not the absolute position
  • Wk,EW_{k,E}: key projection matrix for content (the "E" stands for embeddings)
  • Wk,RW_{k,R}: key projection matrix for relative positions (the "R" stands for relative)
  • u\mathbf{u}: a learned global bias for content attention, shared across all query positions
  • v\mathbf{v}: a learned global bias for position attention, also shared across all positions

Why does this formula make sense? Notice that every term that previously depended on pi\mathbf{p}_i or pj\mathbf{p}_j now depends on either a relative distance encoding ri−j\mathbf{r}_{i-j} or a global learned constant. The relative distance i−ji-j is the same for any pair of tokens separated by the same gap, regardless of their absolute positions. This means the formula produces the same attention contribution for identical content pairs at identical relative distances, regardless of where in the document those pairs appear.

Let's unpack each component:

  1. Term (a): Pure content-based attention. This is unchanged from standard attention. The word "cat" attends to "feline" because of semantic similarity, regardless of position.

  2. Term (b): Content-dependent distance preference. The query content determines how much the model cares about distance. A pronoun might strongly prefer nearby tokens, while a discourse marker might look further back.

  3. Term (c): Global content importance. Some tokens are just important regardless of the query's position. The beginning-of-sentence token might receive attention from everywhere.

  4. Term (d): Global distance preference. The model learns a general preference for certain distances. Typically, nearby tokens receive more attention than distant ones.

Terms (b) and (d) now depend on i−ji - j rather than on ii and jj separately. This means the position signal is the same whether we're at the start of the document or the end, whether we're attending within the current segment or reaching back into cached memory.

Building the Relative Encoding

With the theory in place, let's implement relative position encoding step by step. We need two components: (1) a function to generate sinusoidal encodings for each possible relative distance, and (2) a function to compute attention scores using the four-term formula.

The sinusoidal encoding for relative positions works similarly to absolute position encodings, but instead of encoding absolute positions 0, 1, 2, ..., we encode relative distances ..., -2, -1, 0, 1, 2, .... Negative distances mean the key is before the query; positive distances mean the key is after the query (though in causal attention, we only see non-positive distances). The sinusoidal function ensures smooth, gradual variation between nearby distances, so encodings for similar distances are similar vectors.

In[16]:
Code
import numpy as np


def sinusoidal_relative_encoding(max_distance: int, d_model: int) -> np.ndarray:
    """
    Generate sinusoidal encodings for relative positions.

    Unlike absolute encodings, these encode the distance between positions,
    allowing the same encoding for any pair at the same distance.
    """
    positions = np.arange(-max_distance, max_distance + 1)
    encodings = np.zeros((len(positions), d_model))

    for i, pos in enumerate(positions):
        for j in range(0, d_model, 2):
            div_term = 10000 ** (j / d_model)
            encodings[i, j] = np.sin(pos / div_term)
            if j + 1 < d_model:
                encodings[i, j + 1] = np.cos(pos / div_term)

    return positions, encodings


def relative_attention_scores(
    queries: np.ndarray,
    keys: np.ndarray,
    relative_encodings: np.ndarray,
    rel_positions: np.ndarray,
    u: np.ndarray,
    v: np.ndarray,
    W_k_E: np.ndarray,
    W_k_R: np.ndarray,
) -> np.ndarray:
    """
    Compute Transformer-XL style attention scores with relative positions.

    Args:
        queries: Query vectors, shape (L, d)
        keys: Key vectors (from extended context), shape (L+M, d)
        relative_encodings: Sinusoidal encodings indexed by distance
        rel_positions: Array mapping distance to encoding index
        u, v: Global bias vectors, shape (d,)
        W_k_E, W_k_R: Key projections for content and position

    Returns:
        Attention scores, shape (L, L+M)
    """
    L = queries.shape[0]
    K = keys.shape[0]  # L + M (current + cached)
    M = K - L  # Memory/cache length

    # Term (a): content-to-content
    term_a = queries @ W_k_E @ keys.T  # (L, K)

    # Term (b): content-to-relative-position
    # For each query position i and key position j, we need r_{i-j}
    term_b = np.zeros((L, K))
    for i in range(L):
        for j in range(K):
            # Relative distance: query position (0 to L-1) vs key position (-M to L-1)
            # Key positions 0 to M-1 correspond to cached tokens at positions -M to -1
            # Key positions M to M+L-1 correspond to current tokens at positions 0 to L-1
            if j < M:
                key_pos = j - M  # Negative for cached tokens
            else:
                key_pos = j - M  # 0 to L-1 for current tokens
            query_pos = i
            distance = query_pos - key_pos

            # Find encoding for this distance
            enc_idx = np.where(rel_positions == distance)[0]
            if len(enc_idx) > 0:
                r_ij = relative_encodings[enc_idx[0]]
                term_b[i, j] = queries[i] @ W_k_R @ r_ij

    # Term (c): global content bias
    term_c = u @ W_k_E @ keys.T  # (K,) broadcast to (L, K)
    term_c = np.tile(term_c, (L, 1))

    # Term (d): global position bias
    term_d = np.zeros((L, K))
    for i in range(L):
        for j in range(K):
            if j < M:
                key_pos = j - M
            else:
                key_pos = j - M
            query_pos = i
            distance = query_pos - key_pos

            enc_idx = np.where(rel_positions == distance)[0]
            if len(enc_idx) > 0:
                r_ij = relative_encodings[enc_idx[0]]
                term_d[i, j] = v @ W_k_R @ r_ij

    return term_a + term_b + term_c + term_d
In[17]:
Code
# Demonstrate relative position encoding
rng = np.random.default_rng(42)

L = 4  # Current segment length
M = 4  # Cached segment length
d = 8  # Model dimension

# Generate relative position encodings
max_dist = L + M
rel_positions, rel_encodings = sinusoidal_relative_encoding(max_dist, d)

# Random queries and keys (in practice, these come from token embeddings)
queries = rng.standard_normal((L, d)) * 0.5
keys = rng.standard_normal((L + M, d)) * 0.5

# Learned parameters
u = rng.standard_normal(d) * 0.1
v = rng.standard_normal(d) * 0.1
W_k_E = np.eye(d) + rng.standard_normal((d, d)) * 0.1
W_k_R = np.eye(d) + rng.standard_normal((d, d)) * 0.1

scores = relative_attention_scores(
    queries, keys, rel_encodings, rel_positions, u, v, W_k_E, W_k_R
)
Out[18]:
Console
Attention score matrix shape: (4, 8)

Scores for query position 0 (first token of current segment):
  To cached positions (distances 4-7): [ 0.8931239  -0.1445392   1.11760926 -0.10404486]
  To current positions (distances 0-3): [-1.67922564 -0.77753701  0.42740559  0.55614617]

Scores for query position 3 (last token of current segment):
  To cached positions (distances 7-10): [-0.25324454  0.19148481  0.02378098 -0.03696258]
  To current positions (distances 0-3): [-0.56254582  0.31803436 -0.76636984 -0.96564079]

The scores vary based on both content similarity and relative distance. Notice that the scores to cached positions (which are further away) differ from scores to current positions (which are closer). The relative position encoding ensures consistent treatment of distance regardless of absolute segment boundaries. A token attending to something 3 positions back receives the same position signal whether that's within the current segment or reaching into the cached memory.

To better understand how these four terms contribute to the final attention score, let's decompose them for a single query-key pair across different relative distances:

Out[19]:
Visualization
Bar chart showing individual contributions of the four attention terms (content-to-content, content-to-position, bias-to-content, bias-to-position) at each relative distance.
Individual contributions of the four attention terms at each relative distance. Content-to-content (a) shows token-specific variation based on semantic similarity. The position-related terms (b, c, d) show systematic patterns tied to distance.
Stacked bar chart showing combined attention scores broken down by the four term contributions at each relative distance.
Combined attention score with stacked breakdown showing how content and position terms interact across relative distances. The peak at distance 0 reflects both high self-similarity and maximum position bias.

The visualization shows how content similarity (term a) provides the base signal, while position terms (b, c, d) modulate attention based on distance. The strong preference for position 0 (self-attention) reflects both high content similarity and the global position bias favoring nearby tokens.

Out[20]:
Visualization
Heatmap showing encoding similarity between relative positions from -8 to 8, with high similarity along the diagonal.
Relative position encoding similarity matrix showing how the sinusoidal encoding captures distance relationships. Nearby relative positions have highly similar encodings (warm colors along the diagonal), with similarity decaying smoothly as the distance between positions increases. This smooth decay allows the attention mechanism to naturally prefer nearby tokens while still accessing distant context when semantically relevant.

The similarity matrix shows that encodings for nearby relative positions are similar, gradually diverging for larger distances. This smooth decay allows the attention mechanism to naturally prefer nearby tokens while still accessing distant context when needed. The negative similarities at large distances reflect the oscillatory nature of sinusoidal functions, which ensures that encodings for distant positions become distinct vectors rather than faded versions of nearby ones.