Quant Memo
Advanced

Rotary Position Embeddings (RoPE)

RoPE tells a transformer where a word sits in a sentence by rotating its vector, so that the angle between two words' vectors after rotation encodes exactly how far apart they are — a trick that lets attention scores depend only on relative position.

Prerequisites: The Self-Attention Mechanism, Sinusoidal Positional Encoding

Attention compares two word vectors with a dot product to decide how relevant one is to the other. But the raw dot product of two vectors knows nothing about where those words sit in the sentence — swap "the fund gained" and "gained the fund" and the same two vectors for "fund" and "gained" would produce the identical score, which is wrong, because word order changes meaning. A transformer needs some way to inject position into the comparison, and it needs that injection to survive being copied into every layer of a very deep network without exploding or degrading. RoPE solves this by rotating each word's vector by an angle proportional to its position, so position becomes baked into the geometry of the vector itself rather than added on as a separate number.

The analogy: clock hands instead of a printed timestamp

Imagine stamping every document with the literal time it was created, like "14:32:07," and having a clerk compare two documents by subtracting the timestamps. That works, but the clerk has to do arithmetic every time, and the numbers grow without bound as the day goes on. Now imagine instead giving each document a clock hand pointing at the time it was created. To find out how far apart two documents are in time, the clerk just looks at the angle between the two hands — no subtraction needed, and the angle stays bounded no matter how late in the day it gets, because it wraps around the clock face. RoPE gives every word vector a "clock hand" — it rotates the vector by an angle proportional to the word's position — so that comparing two words' vectors automatically reads off their relative position as an angle, with no separate bookkeeping.

The mechanism: rotating pairs of coordinates

Take a word's vector and split it into pairs of coordinates: (x1,x2)(x_1, x_2), (x3,x4)(x_3, x_4), and so on. RoPE rotates each pair by an angle θ\theta that depends on the word's position mm in the sequence and which pair it is:

(x1x2)=(cos(mθ)sin(mθ)sin(mθ)cos(mθ))(x1x2)\begin{pmatrix} x_1' \\ x_2' \end{pmatrix} = \begin{pmatrix} \cos(m\theta) & -\sin(m\theta) \\ \sin(m\theta) & \cos(m\theta) \end{pmatrix} \begin{pmatrix} x_1 \\ x_2 \end{pmatrix}

Here mm is the position of the word in the sentence (word 1, word 2, ...), θ\theta is a fixed angle assigned to this particular pair of coordinates (different pairs get different, geometrically spaced angles, so some pairs rotate fast and others slow), and the matrix is a standard 2D rotation — it turns the point (x1,x2)(x_1, x_2) by angle mθm\theta around the origin without changing its length. In plain English: each pair of numbers in the vector gets spun around like a clock hand, by an amount that grows with how far into the sentence the word appears.

The payoff shows up when two rotated vectors are compared by dot product. For a query at position mm and a key at position nn, the dot product of their rotated pairs depends only on (mn)θ(m-n)\theta — the difference in positions — not on mm and nn individually. Two words three apart get exactly the same positional contribution to their score whether they're words 4 and 7 or words 400 and 403. That is the entire design goal: bake in relative position, discard absolute position, without ever computing a subtraction.

word at position 3 word at position 7 angle ∝ (7−3) the angle between the two hands encodes their distance apart, not their absolute time
Each word's vector is rotated by an angle proportional to its position; the angle *between* two words' rotated vectors depends only on how far apart those positions are.

Drag the angle in the explorer below to see how a 2D rotation preserves a vector's length while changing its direction — that is exactly what each coordinate pair of a RoPE vector undergoes, just repeated across many pairs with different angles.

Matrix explorer
dashed = before · solid = after
det 1.25trace 2.50λ 1.81, 0.69area scales by 1.25×

Worked example 1: rotating a single pair by hand

Take the coordinate pair (x1,x2)=(1,0)(x_1, x_2) = (1, 0) at position m=2m=2, with angle θ=30°\theta = 30° for this pair, so the rotation angle is mθ=60°m\theta = 60°. Using cos60°=0.5\cos 60° = 0.5 and sin60°=0.866\sin 60° = 0.866:

x1=0.5(1)0.866(0)=0.5,x2=0.866(1)+0.5(0)=0.866x_1' = 0.5(1) - 0.866(0) = 0.5, \qquad x_2' = 0.866(1) + 0.5(0) = 0.866

The rotated pair is (0.5,0.866)(0.5, 0.866). Check the length: 0.52+0.8662=0.25+0.75=1.0\sqrt{0.5^2 + 0.866^2} = \sqrt{0.25+0.75} = 1.0 — unchanged from the original length of 11, exactly as a rotation should behave; only the direction moved.

Worked example 2: relative position survives, absolute position doesn't

Take two positions, m=5m=5 and n=2n=2, both with the same starting pair (1,0)(1,0) and the same per-pair angle θ=20°\theta=20°. Position 5's rotated pair uses angle 100°100°: (cos100°,sin100°)=(0.174,0.985)(\cos 100°, \sin 100°) = (-0.174, 0.985). Position 2's uses angle 40°40°: (cos40°,sin40°)=(0.766,0.643)(\cos 40°, \sin 40°) = (0.766, 0.643).

Their dot product is (0.174)(0.766)+(0.985)(0.643)=0.133+0.633=0.500(-0.174)(0.766) + (0.985)(0.643) = -0.133 + 0.633 = 0.500. Now compare positions 8 and 5 — the same gap of 3 — using angles 160°160° and 100°100°: (cos160°,sin160°)=(0.940,0.342)(\cos160°,\sin160°)=(-0.940,0.342) and (cos100°,sin100°)=(0.174,0.985)(\cos100°,\sin100°)=(-0.174,0.985). Dot product: (0.940)(0.174)+(0.342)(0.985)=0.164+0.337=0.500(-0.940)(-0.174)+(0.342)(0.985) = 0.164+0.337=0.500. Same gap, same dot product, even though the absolute positions were completely different — the calculation only ever "knew" a difference of 3θ=60°3\theta = 60°.

RoPE encodes position by rotation, not addition. Two words a fixed distance apart always contribute the same positional signal to their attention score, regardless of where in the sequence that pair sits — which is exactly the property a model needs to generalize to sentences longer than any it saw during training.

What this means in practice

RoPE is the default positional scheme in most modern large language models because it plays well with the KV cache — a cached key rotated for position 50 is still valid once the sequence reaches position 5000, since nothing about how it was rotated changes, only which query it's compared against — and because relative-position encoding tends to generalize better to sequence lengths longer than training. It also underlies "context extension" tricks: by rescaling θ\theta, engineers can stretch a model trained on short sequences to handle much longer ones, in effect slowing down the clock hands.

It's tempting to think RoPE adds a "position vector" to the word vector, the way the original sinusoidal scheme does. It does not add anything — it rotates the existing vector, which is why it preserves the vector's length exactly and only changes direction. Confusing the two schemes leads people to expect RoPE embeddings to be interpretable as separate "content" and "position" pieces that can be added or subtracted; they can't be separated that way, because rotation mixes them inside every coordinate pair.

Practice

  1. Rotate the pair (0,1)(0, 1) by 90°90° by hand using the rotation matrix, and confirm the length is unchanged.
  2. Why does the dot product between a rotated query and a rotated key depend only on mnm - n and not on mm or nn separately? Point to the step in the derivation where the individual angles would cancel.
  3. If a model was trained with sequences up to position 512 and θ\theta is halved at inference, does a fixed gap of 10 positions now correspond to a larger or smaller rotation angle than during training?

Related concepts

Practice in interviews

Further reading

  • Su et al., RoFormer: Enhanced Transformer with Rotary Position Embedding (2021)
ShareTwitterLinkedIn