Positional encodings: sinusoidal, learned, RoPE and ALiBi
Before this lesson: lesson 09 (attention and its permutation equivariance) and linear-algebra lesson 04 (rotations and orthogonal matrices). The deeper box on RoPE uses complex numbers (foundations track). Time: about 65 minutes, plus the notebook.
Why this matters #
Without positions, "dog bites man" and "man bites dog" give the same set of output vectors. Every sequence model therefore needs a positional encoding, and the choice has large practical effects. RoPE is used by most open large language models (LLaMA, Mistral, Qwen) and by protein language models such as ESM-2. ALiBi is used by BLOOM and MPT. Learned absolute embeddings are used by GPT-2, BERT and the vision transformer. When a company extends a model from a 4k to a 128k context, the main change is in the positional encoding. In science, the same question decides how a model handles weather fields (latitude matters, longitude almost does not) or seismic records of different lengths.
1. Predict first #
2. The picture #
One frequency: a point on a circle #
Put position on a circle: . Moving from to turns the point by the angle , and this is the same turn for every . So " steps later" is one fixed rotation. But one circle is not enough: and land on the same point.
Many frequencies: the hands of a clock #
A clock solves the same problem with several hands. The second hand is fast: it separates nearby times, but it repeats every minute. The hour hand is slow: it changes little from one minute to the next, but it does not repeat within a day. Together the hands give every time of the day a different reading. The sinusoidal encoding uses many circles with frequencies from fast to slow, with base , one circle for each pair of dimensions.
Move the position . The heatmap shows the encodings of 64 positions (columns) in 32 dimensions (rows): orange is positive, blue is negative. The yellow column and the clock hands show position : fast pairs turn quickly, slow pairs hardly move. The chart shows the dot product of with every other position. Notice that the bump moves with but keeps its shape: the dot product depends only on the offset .
For the sinusoidal encoding, what does the dot product depend on?
Each pair gives , so the dot product is , a function of only. It equals only for .
Two places to put position #
- Add a position vector to the input (absolute). Token enters the network as . The score between two tokens can then depend on both absolute positions.
- Change the score so that it depends on the offset only (relative). RoPE rotates the query and the key; ALiBi adds a penalty to the logit.
RoPE on one pair, with numbers #
Take one pair of dimensions with frequency , a query content and a key content . RoPE turns the query at position by the angle and the key at position by , with the rotation matrix .
- Positions : and . The score is .
- Positions : and . The score is again.
Both vectors turned by 5 more radians, so the angle between them did not change, and neither did the dot product. The score depends only on .
Press "Shift both by +1" several times. The query and the key turn together, the angle between them stays, and the log shows the same score each time. Then press "Swap m and n": the offset changes sign and the score changes, so RoPE can tell "before" from "after". Drag the faint tips to change the contents and .
In one RoPE pair, the score of a query at position 5 and a key at position 2 is . The same contents are placed at positions 105 and 102. What is the new score?
Both vectors are turned by an extra . A common rotation keeps the angle between two vectors and their lengths, so the dot product is unchanged. Only the offset matters.
3. Definitions and main results #
Notation. The encoding acts on vectors of even dimension . Pair is the coordinates , for (counting from 0). Pair has the frequency with base , so is the fastest pair. The wavelength is the number of positions for one full turn. is the rotation by . Positions start at .
Learned absolute embeddings #
A table is trained with the model, and row is added to token at the input (GPT-2, BERT, the vision transformer). It has parameters. Limit: there is no row for , so the model cannot run on longer inputs. In the original transformer, learned and sinusoidal encodings gave nearly the same results (Vaswani et al., Table 3, row E).
Sinusoidal encodings #
Definition. and , for . The vector is added to token at the input (). The wavelengths form a geometric sequence from to almost .
Theorem (a shift is a rotation). For every and , , with
which does not depend on .
Proof.
- Fix pair and write . The angle-addition formulas give and .
- In matrix form, with and . The matrix depends on only.
- Stack the pairs to get .
Each block is the rotation , so is orthogonal and . A consequence: , a function of the offset only (the quiz of section 2).
Why this does not make attention relative. With additive encodings, the score of tokens and is with . It has four terms: content–content , content–position , position–content , and position–position . Only the last one can depend on alone, and only for special (for example ). The shift property makes relative attention learnable; it does not force it.
RoPE (rotary position embedding) #
Definition. For a vector at position , with
RoPE is applied in every layer, to the queries and the keys of each head after the projections (, the head size). It never touches the values, and it adds nothing to the residual stream.
Theorem (RoPE scores are relative). , a function of , and only.
Proof.
- A rotation is orthogonal, , and rotations compose: .
- Block-diagonal matrices are transposed and multiplied block by block. So , and , because in pair : .
- .
Properties.
- is orthogonal, so RoPE keeps the norms of and , and . RoPE has no parameters.
- Why not the values: the output would carry the absolute position of every key, because the rotations of different keys do not cancel in the sum. Position should change where a head looks, not what it moves.
- Two layouts. The RoFormer paper pairs the coordinates ("interleaved"); GPT-NeoX and the Hugging Face LLaMA code pair ("half-split"). The mathematics is the same, but mixing the two layouts when loading weights breaks a model without any error message.
- With these frequencies, an upper bound of the score decreases as grows (RoFormer §3.4.3): a mild preference for nearby tokens.
RoPE as complex multiplication
Write pair of as one complex number . The rotation by is multiplication by , so RoPE is . For two vectors, with the pairs of . Then
which depends on only. Implementations use this form: torch.view_as_complex, multiply,
view_as_real.
RoPE with and frequencies . The query and key contents are . What is the score at offset ?
In each pair, . So the score is . Each pair adds its own term; the fast pair alone gives and the slow pair alone gives .
The frequency schedule and longer contexts #
The fastest pair () turns once every positions: it separates neighbours well, but it repeats. The slowest pair turns once in about positions: it is coarse, but it does not repeat. Take a LLaMA-style head (, ) trained on tokens. The slowest pair has . Up to position 4096 it turns by rad, only 7.5% of a turn. 18 of the 64 pairs never complete a turn during training. Beyond , these pairs show angles that the model has never seen. This is why RoPE extrapolates poorly: in the experiments of Press et al., a RoPE model trained on 512 tokens improved only up to about 200 tokens beyond its training length.
Each dot is one pair of a RoPE head; its height is the wavelength (positions per turn, log scale). Pairs above the aqua line never complete a turn in training. With and no change, the magenta pairs see angles they never saw. Switch to "position interpolation": no magenta dots remain, but the fastest pair now turns only rad between neighbours. Switch to "base scaling": the fast pairs stay as they were and the slowest pair is slowed by exactly .
Two ways to extend the context, at a high level (both are followed by a short fine-tune on long sequences):
- Position interpolation (Chen et al. 2023): for a new length , use the positions instead of . Every angle stays inside the range seen in training. With a short fine-tune (within 1000 steps), it extended LLaMA models to 32k tokens. The cost: neighbouring tokens are separated less by the fast pairs.
- Base scaling: raise . This slows mainly the slow pairs, and the fastest pair () does not change. Code Llama raised from to , was fine-tuned on 16k-token sequences, and works with inputs up to 100k tokens. "NTK-aware" scaling uses , which slows the slowest pair by exactly . YaRN chooses the stretch for each frequency separately.
A RoPE model was trained with . You use position interpolation to run it on tokens. What changes?
Position interpolation divides every position by . The largest angle of every pair is then the same as in training. The price is resolution: the fastest pair turns rad between neighbours instead of 1 rad. Raising is a different method (base scaling), and RoPE has no learned embeddings.
ALiBi (attention with linear biases) #
ALiBi uses no position embeddings at all. It adds a fixed penalty to the causal logits of head :
with the slopes for ( a power of 2; the reference code uses a slightly different rule otherwise). For the slopes are . The slopes are fixed, not learned.
Reading the penalty. The bias multiplies the softmax weight of a key at distance by . So head has a half-life of positions: 1.4 for , and 177 for . Steep heads look at the last few tokens; flat heads look far back.
Theorem (the softmax ignores a row constant). Adding instead of to row gives the same attention weights.
Proof.
- The two biases differ by , which is the same for every key of row .
- For any constant , .
So an implementation can add the same vector to every row, which is easy to precompute. In the experiments of Press et al., a 1.3B-parameter model trained on 1024 tokens reached, on 2048 tokens, the perplexity of a sinusoidal model trained on 2048 tokens, while training 11% faster and using 11% less memory. The price is a fixed bias towards recent tokens.
Pick a head and a query row. The matrix shows the bias of the selected head (masked future cells are grey); the bars show the attention weights of the yellow query row when all content scores are 0. The chart shows the factor for every head (the selected head in yellow). Switch the bias form to : the matrix changes, but the weights do not.
An ALiBi model has heads. Which slopes does it use?
with gives for : from to . The slopes are fixed before training; the paper found that learned slopes did not extrapolate well. Different slopes give heads with different ranges.
Comparison #
| Scheme | Where position enters | Parameters | The score depends on | Beyond the training length |
|---|---|---|---|---|
| Learned absolute | added to the input | content and absolute positions | not defined beyond | |
| Sinusoidal | added to the input | 0 | content and absolute positions | defined, but stops improving after 20–50 extra tokens (Press et al.) |
| RoPE | rotates and in every layer | 0 | content and | degrades; extend by interpolation or base scaling, plus a short fine-tune |
| ALiBi | bias on the logits in every layer | 0 | content and (linear penalty) | extrapolates well (train short, test long) |
Answers to section 1. (1) Learned absolute: positions 2048–4095 have no embedding, so the model cannot process them at all. RoPE: the model runs, because the rotations are defined for every position, but the slow pairs reach angles never seen in training, and the quality drops soon after 2048 tokens unless the context is extended (interpolation or a larger base, plus a short fine-tune). (2) Exactly : both vectors turn by an extra in every pair, and the score depends only on .
4. Worked example #
(a) Sinusoidal, , . The frequencies are and . Then
The two blocks of are and . Block 1 times : and . So ✓.
(b) RoPE with the same frequencies. Take : the same content at two positions. In each pair, , so the score is with :
| fast pair | slow pair | score | |
|---|---|---|---|
| 0 | 1.000 | 1.000 | 2.000 |
| 1 | 0.540 | 1.000 | 1.540 |
| 3 | −0.990 | 1.000 | 0.010 |
| 100 | 0.862 | 0.540 | 1.403 |
Positions and give the same score, 0.010: only the offset counts. The fast pair alone scores almost like (0.862 vs 1): it aliases, because 100 is close to 16 full turns (). The slow pair separates them (0.540 vs 1). For this and , the RoPE score equals of the sinusoidal encoding.
(c) ALiBi, . A key 100 positions back gets the bias in head 1, a weight factor : invisible. In head 8 the bias is , a factor of 0.68: still clearly visible.
(d) Extending a context. A head with , , trained on , run on ():
- no change: the slowest pair turns by rad, four times the largest angle it saw (0.47 rad);
- position interpolation: the slowest pair turns by rad, as in training, and the fastest pair turns rad between neighbours instead of 1 rad;
- NTK-aware base scaling: ; the fastest pair still turns 1 rad between neighbours, and the slowest pair turns by rad up to .
5. In code #
NumPy checks the worked example and the two theorems. The notebook builds the same functions as exercises.
import numpy as np
from scipy.special import softmax
def freqs(d, base=1e4):
return base ** (-2 * np.arange(d // 2) / d) # theta_i, i = 0 .. d/2 - 1
def sinusoidal(T, d, base=1e4):
ang = np.arange(T)[:, None] * freqs(d, base) # (T, d/2)
pe = np.empty((T, d))
pe[:, 0::2], pe[:, 1::2] = np.sin(ang), np.cos(ang)
return pe
def rope(x, pos, base=1e4):
"""Rotate the pairs (2i, 2i+1) of row x[t] by the angle pos[t] * theta_i."""
ang = np.asarray(pos, float)[:, None] * freqs(x.shape[1], base)
c, s = np.cos(ang), np.sin(ang)
out = np.empty_like(x)
out[:, 0::2] = c * x[:, 0::2] - s * x[:, 1::2]
out[:, 1::2] = s * x[:, 0::2] + c * x[:, 1::2]
return out
# (a) PE(t + k) = M_k PE(t), with the 2x2 blocks [[cos, sin], [-sin, cos]]
pe, th, k = sinusoidal(50, 4), freqs(4), 7
blk = lambda a: np.array([[np.cos(a), np.sin(a)], [-np.sin(a), np.cos(a)]])
M = np.block([[blk(th[0] * k), np.zeros((2, 2))], [np.zeros((2, 2)), blk(th[1] * k)]])
print(pe[1].round(3), np.allclose(pe[k:], pe[:-k] @ M.T)) # [0.841 0.54 0.01 1. ] True
# (b) RoPE scores depend on n - m only: the table of the worked example
q = np.array([[1., 0., 1., 0.]])
score = lambda m, n: (rope(q, [m]) @ rope(q, [n]).T).item()
print([round(score(0, d), 3) for d in (0, 1, 3, 100)]) # [2.0, 1.54, 0.01, 1.403]
print(round(score(5, 2), 3), round(score(105, 102), 3)) # 0.01 0.01
# (c) ALiBi: slopes, and -m(i - j) or +m j give the same softmax in row i
H, i = 8, 5
m = 2.0 ** (-8 * np.arange(1, H + 1) / H)
print(1 / m) # [ 2. 4. 8. 16. 32. 64. 128. 256.]
s, j = np.random.default_rng(0).normal(size=i + 1), np.arange(i + 1)
print(np.allclose(softmax(s - m[1] * (i - j)), softmax(s + m[1] * j))) # True
# (d) the frequency schedule of a d = 128 head trained on L = 4096 tokens
th, L = freqs(128), 4096
print((2 * np.pi / th > L).sum(), round(th[-1] * L, 2)) # 18 0.47
6. Where it shows up #
- Language models. RoPE is the default in most open LLMs (the LLaMA family, Mistral, Qwen). Long-context versions raise the base (LLaMA 3 uses ) or interpolate positions, then fine-tune briefly. BLOOM and MPT use ALiBi. GPT-2 and BERT use learned absolute embeddings; T5 adds a learned bias for each bucket of relative distances.
- Vision. The vision transformer uses learned position embeddings for its patches (lesson 11). Diffusion transformers (DiT) add fixed 2-D sine–cosine embeddings. A 2-D RoPE splits the pairs between the row and the column index.
- Proteins. ESM-2 and many later protein language models use RoPE, so that a model trained on short sequences runs on longer proteins.
- Weather and climate. Pangu-Weather replaces the relative position bias of the Swin transformer with an "Earth-specific" bias: separate parameters for each latitude and pressure level, shared along longitude. The dynamics are close to invariant along longitude but not along latitude or height, so a relative scheme fits one axis and an absolute scheme the others.
- Time series and seismology. When only time offsets matter and record lengths vary, a relative scheme (RoPE, ALiBi) is the natural choice.
7. Common mistakes #
- RoPE on the values or on the residual stream. The relative property holds only for the scores .
- Interleaved vs half-split layout mixed between the weights and the code.
- Frequencies computed with the model width instead of the head size . RoPE is applied per head.
- Expecting sinusoidal encodings to extrapolate because they are defined for every . The network after them has never seen those vectors.
- "Sinusoidal encodings make attention relative." The dot product is relative, but the full score has three more terms that are not.
- Forgetting the row-constant argument. The ALiBi bias is not "wrong"; it differs from only by a constant in each row.
8. Check yourself #
- RoPE with , , and . Give the score
for and for .
Answer
Pair 0 gives and pair 1 gives , with , and . So the score is . For : , score . For : . The sign of the offset matters: RoPE can tell "before" from "after". - Why is RoPE applied to queries and keys, but not to values?
Answer
Only the score is relative. Rotated values would put the absolute position of each key into the output, and the rotations of different keys do not cancel in the weighted sum. Position should decide where a head looks, not change what it moves. - ALiBi with heads: give the slopes and their half-lives.
Answer
: . Half-lives : 2.8, 11.1, 44.4 and 177.4 positions. - A head with and is trained on tokens. How many of its 32 pairs
never complete a turn during training?
Answer
Pair has wavelength . It is longer than 2048 when , that is , so : pairs 21 to 31, which is 11 pairs. - Write the attention score with additive position vectors as four terms. Which term can depend
on the offset only?
Answer
. Only the position–position term can depend on alone, and only for special , for example with sinusoidal . - A model with uses learned absolute embeddings for positions. How
many parameters do they have, and what happens at position 2048?
Answer
parameters. Position 2048 (counting from 0) has no row in the table, so the model cannot process it.
Write the sinusoidal positional encoding.
, , with and .
How is related to for the sinusoidal encoding?
, where is block-diagonal with rotations by ; it does not depend on .
What is the main limit of learned absolute position embeddings?
There is no embedding for positions , so the model cannot process longer inputs.
Define RoPE.
Rotate pair of each query and key at position by the angle : with . Applied per head, in every layer, not to values.
Why is a RoPE score relative?
, because .
Which RoPE pair rotates fastest, and how fast?
Pair , with rad per position (one turn every positions).
Why does RoPE degrade beyond the training length, and what is position interpolation?
Slow pairs never complete a turn in training, so longer inputs bring new angles. Position interpolation uses positions , which keeps every angle in the trained range.
Give the ALiBi logit and its slopes for heads.
for , with fixed slopes ( for ).
Why may ALiBi add instead of ?
The two differ by , a constant in row , and the softmax ignores a constant added to a whole row.
9. Interview angle #
- "How does RoPE work, and why is it relative?" — Rotate each pair of and by ; , so the score depends on . No parameters, values untouched.
- "Extend a 4k-context model to 32k." — Position interpolation or base scaling (NTK-aware, YaRN), then a short fine-tune on long data; evaluate long-range retrieval (for example passkey retrieval), not only perplexity.
- "Why does ALiBi extrapolate?" — The penalty is a fixed function of distance, so longer inputs bring no new kind of position signal. The cost is a bias towards recent tokens.
- "Sinusoidal or learned embeddings?" — Nearly the same quality in the original transformer; learned ones cannot go beyond ; neither extrapolates well.
- "Your RoPE model gives garbage after loading weights from another library." — Check the pair layout (interleaved vs half-split) and that the frequencies use the head size.
10. Practice #
The notebook for this lesson runs in Colab. Five exercises, each with a check cell and a folded solution:
- The sinusoidal encoding and the shift matrix ; check .
- RoPE on a array of queries or keys; check that norms are kept and that scores depend on the offset only.
- ALiBi slopes and the bias tensor; check the row-constant argument.
- Position interpolation: RoPE angles beyond , with and without interpolation.
- Build by hand a RoPE attention head that always attends tokens back, and use it to copy a token sequence; without positions the same head cannot do it.
11. Watch and read #
- Vaswani et al., Attention Is All You Need (2017): §3.5 (sinusoidal positional encoding) and Table 3, row (E) (learned vs sinusoidal).
- Su et al., RoFormer: Enhanced Transformer with Rotary Position Embedding: §3.2 (the 2-D case and the general form) and §3.4 (derivation, efficient implementation, long-term decay).
- EleutherAI, Rotary Embeddings: A Relative Revolution: intuition, derivation and code.
- Press, Smith, Lewis, Train Short, Test Long (ALiBi): §2.2 (how sinusoidal, rotary and T5-bias models extrapolate) and §3 (the method and its slopes).
- Chen et al., Extending Context Window of Large Language Models via Positional Interpolation (2023), and Peng et al., YaRN (2023), for context extension.
- Simon Prince, Understanding Deep Learning (free PDF), §12.3.1 (absolute and relative positional encodings).
Runs in your browser with nothing to install. The notebook repeats the key demos and has exercises with checks; solutions are inside, folded.
No Google account needed: Python runs inside your browser. The first start downloads about 40 MB; your changes are saved in this browser only.