Architecture

Rotary position embeddings

RoPE encodes position by rotating vectors, and the rotation cancels. Move a query and a key together and watch the attention score refuse to change.

Frequency base
Query position 64
Key position 40
Move both
FREQUENCY BANDS: FAST HANDS LEFT, SLOW HANDS RIGHT1.00rad/token0.75rad/token0.56rad/token0.42rad/token0.32rad/token0.24rad/token0.18rad/token0.13rad/tokenquery at 64key at 40SCORE vs RELATIVE DISTANCE, FOR EVERY ABSOLUTE POSITION AT ONCE+24-128-64064128
24tokens
Relative distance
-3.4649
Score
-3.4649
Shift both by 37
54.4ktokens, d=128
Slowest band period

The original setting. The slowest band takes roughly 54,000 tokens to complete one turn, far more than the few thousand these models were trained on, so the model never observes a full period of it.

A transformer has no inherent notion of order. Attention is a sum over positions, and a sum does not care what order you write it in, so position has to be put in by hand. The obvious approaches add something to the embedding, which works but has a nagging problem: what the model learns about position five does not automatically transfer to position five thousand.

Rotary embeddings take a different route. Split the vector into two-dimensional slices and rotate each slice by an angle proportional to its position, with a different rate for each slice. Nothing is added. The vector is turned.

The payoff is what happens when a rotated query meets a rotated key. Rotating one vector by m and another by n and taking their dot product gives exactly the same answer as rotating one of them by m minus n and leaving the other alone. Absolute positions go in and only their difference comes out. Use the move-both buttons: the two score readouts stay identical however far along the sequence you slide, which is why the score curve at the bottom is a single curve rather than a family of them.

The frequency base decides how far this stays useful, though not for the reason it first appears. Each band is a hand on a clock, and at base ten thousand the slowest hand takes roughly fifty thousand tokens to complete a turn, far beyond the few thousand these models were originally trained on. Ambiguity from wrap-around is therefore not the binding problem.

The binding problem is the opposite. Because those slow bands have wavelengths longer than the training window, the model never observes a full period of them, so relative distances past what it was trained on produce phase values it has simply never encountered, and attention behaves badly on inputs it has no experience of. Raising the base stretches every wavelength, which keeps the fast bands recognisable while moving the slow ones further from the region that has never been seen. That is why long-context models raise the base to hundreds of thousands, and they do it alongside continued training on long documents rather than instead of it.

Base 100 shows the wrap-around failure directly, which is a real effect even though it is not the one that limits real models: every band cycles so quickly that distant positions produce the same set of angles.

The maths

Band frequencies
θi  =  base2i/d,i=0,,d21\theta_i \;=\; \text{base}^{-2i/d}, \qquad i = 0, \ldots, \tfrac{d}{2} - 1

Each two-dimensional slice of the vector turns at its own rate. The eight dials sample the bands of a 64-dimensional slice; the period stat is quoted at d = 128, where the slowest band at base 10,000 takes roughly 54,000 tokens per turn.

The rotation
Rm  =  (cosmθsinmθsinmθcosmθ)R_m \;=\; \begin{pmatrix} \cos m\theta & -\sin m\theta \\ \sin m\theta & \cos m\theta \end{pmatrix}

Position m rotates each slice by m times its band frequency. Nothing is added to the vector; it is turned, which preserves its length.

The invariance
Rmq,Rnk  =  qRmRnk  =  qRnmk\langle R_m \mathbf{q},\, R_n \mathbf{k} \rangle \;=\; \mathbf{q}^{\top} R_m^{\top} R_n \mathbf{k} \;=\; \mathbf{q}^{\top} R_{n-m} \mathbf{k}

Rotations compose by adding angles and transposing negates one, so the two absolute positions collapse into their difference. This is the one-line proof behind the move-both buttons refusing to change the score.

Related terms

More visualisations

Building with language models?

These explainers come out of the work. If you want the same thinking applied to your own system, that is what I do.

See how I can help