Recurrent Memory › Relative Position Encoding in Transformer-XL
Language AI HandbookAll chapters 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 and a key at position starts as a simple dot product:
where:
- : the attention score determining how much position attends to position
- : the query vector at position
- : the key vector at position
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 is and the key at position is . Substituting these into the dot product and using the distributive property of matrix multiplication:
where:
- : token embeddings at positions and
- : absolute position embeddings for positions and
- : 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:
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 or (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 and . Transformer-XL's insight is that we can rewrite these terms to use relative position instead. The redesign makes two key changes:
-
Replace the key's absolute position with relative distance: Instead of (the absolute position of the key), use (the relative distance from query to key).
-
Replace the query's position with a learned global bias: The query's absolute position becomes learned vectors and 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:
where:
- : token embeddings at positions and , unchanged from before
- : a sinusoidal encoding of the relative distance , not the absolute position
- : key projection matrix for content (the "E" stands for embeddings)
- : key projection matrix for relative positions (the "R" stands for relative)
- : a learned global bias for content attention, shared across all query positions
- : 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 or now depends on either a relative distance encoding or a global learned constant. The relative distance 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:
-
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.
-
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.
-
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.
-
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 rather than on and 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.
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# 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
)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:


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.

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.