Skip to content

Position and rotary embeddings

Rotating vectors so attention knows who is near whom

Chapter 8 of 21 · II. The transformer · about 40 minutes. Builds on: 6. Attention.

Look back at the formula O=softmax⁡(QK⊤/d)VO = \operatorname{softmax}(QK^{\top} / \sqrt{d})V. If you shuffle the rows of XX, the rows of QQ, KK, VV shuffle the same way, and the output rows shuffle identically. Attention is permutation-equivariant: “dog bites man” and “man bites dog” would produce the same bag of vectors. Position must be injected deliberately.

Approaches, in historical order:

  • Absolute encodings added to the embedding: fixed sinusoids at many frequencies , or a learned vector per position. Simple, but the model must learn relations between positions indirectly and does not extend to longer sequences than it saw.
  • Attention biases: ALiBi subtracts a penalty proportional to the distance |i−ji - j| from each score, with a different slope per head. No extra parameters, and extrapolates better than absolute encodings.
  • Rotary embeddings (RoPE) : rotate queries and keys by a position-dependent angle. This is used by Llama, DeepSeek, gpt-oss and most current open models.

A rotation of the plane by angle φ\varphi is the matrix

R(φ)=(cos⁡φ−sin⁡φsin⁡φcos⁡φ)R(\varphi)=\begin{pmatrix}\cos\varphi&-\sin\varphi\\\sin\varphi&\cos\varphi\end{pmatrix}

Facts used below: R(a)R(b)=R(a+b)R(a)R(b)=R(a+b); R(a)⊤=R(−a)R(a)^{\top}=R(-a) (the transpose is the inverse); and rotations preserve lengths and dot products, so ⟨Ru,Rv⟩=⟨u,v⟩\langle Ru,Rv\rangle=\langle u,v\rangle.

We want a score between a query at position mm and a key at position nn that depends on the two vectors and on the offset m−nm - n, and on nothing else. Split the dd components of qq and kk into d/2d / 2 pairs, and treat each pair as a point in the plane. Rotate the pair at position mm by angle m⋅θm\cdot \theta:

q~=R(mθ) q,k~=R(nθ) k\tilde q=R(m\theta)\,q,\qquad\tilde k=R(n\theta)\,k

Then the score for that pair is

⟨R(mθ)q,  R(nθ)k⟩=q⊤R(mθ)⊤R(nθ) k=q⊤R(−mθ) R(nθ) k=q⊤R((n−m)θ) k\begin{aligned} \bigl\langle R(m\theta)q,\;R(n\theta)k\bigr\rangle&=q^{\top}R(m\theta)^{\top}R(n\theta)\,k\\ &=q^{\top}R(-m\theta)\,R(n\theta)\,k\\ &=q^{\top}R\bigl((n-m)\theta\bigr)\,k \end{aligned}

It depends only on n−mn - m. Nothing about absolute position survives; the model sees relative offset for free. The full score is the sum over all pairs, each pair using its own rotation speed:

θi=base−2i/d,i=0,1,…,d2−1\theta_i=\text{base}^{-2i/d},\qquad i=0,1,\dots,\tfrac d2-1

The original paper uses base = 10,000.

Think of d/2d / 2 clocks. Pair 0 spins fastest (θ=1\theta = 1 radian per token) and can tell neighbors apart; the last pair spins very slowly and distinguishes tokens only thousands of positions apart. The wavelength of pair ii is λi=2\lambda _{i} = 2π/θi\theta _{i} tokens per full turn. Position is applied to queries and keys only, never to values, and it is applied afresh in every layer. Check the identity numerically:

Implementation is cheap: rotating each pair is two multiply-adds with precomputed cosines and sines, so no matrices are materialized.

A model trained on sequences up to length LL has only ever seen rotation angles up to L⋅θL\cdot \theta. At position beyond LL the slow clocks show angles never seen in training, and quality collapses. Several methods adapt a trained RoPE model to a longer window L′=s⋅LL' = s\cdot L (ss = the extension factor).

squeeze the new positions into the old range by using m/sm / s in place of mm. Every angle stays within the trained range, but all clocks are slowed by the same factor, so the fast clocks lose their ability to tell neighbors apart, and a short fine-tune is needed to recover.

YaRN treats each frequency according to how many full turns it makes inside the original window, r=L/λr = L / \lambda:

  • Slow clocks (r<αr < \alpha, they never completed one turn in training): interpolate fully, divide the frequency by ss.
  • Fast clocks (r>βr > \beta, they turned many times): leave unchanged; they encode local order and were seen at all phases.
  • Between: blend linearly with a ramp γ(r)=(r−α)/(β−α)\gamma (r) = (r - \alpha) / (\beta - \alpha); the new frequency is (1−γ)⋅θ/s+γ⋅θ(1 - \gamma)\cdot \theta / s + \gamma \cdot \theta. The paper finds α=1\alpha = 1 and β=32\beta = 32 work well for the Llama family.

YaRN also multiplies attention logits by a temperature correction: both qq and kk are scaled by 1/t=0.1\sqrt{1 / t} = 0.1·ln(ss) + 1, so logits scale by 1/t1 / t. It is applied inside the rotary tables, so it adds no inference cost. Explore the frequency treatment:

Real examples from published configurations: gpt-oss-120b was extended from a 4,096 window by YaRN with factor 32 to 131,072 tokens , and DeepSeek-V3 used YaRN with factor 40 across two 1,000-step fine-tuning phases to reach 128K . Both multiply to exactly the window the config reports (4,096×32=131,0724,096 \times 32 = 131,072; 4,096×40=163,8404,096 \times 40 = 163,840).

Having a long window is not the same as using it well. found that models retrieve information best from the start and end of a long prompt and worse from the middle.

Prove the identity ⟨R(mθ)q, R(nθ)k⟩ = ⟨q, R((n−m)θ)k⟩.

⟨R(mθ)q,R(nθ)k⟩=q⊤R(mθ)⊤R(nθ)k=q⊤R(−mθ)R(nθ)k=q⊤R((n−m)θ)k\langle R(m\theta)q,R(n\theta)k\rangle=q^{\top}R(m\theta)^{\top}R(n\theta)k=q^{\top}R(-m\theta)R(n\theta)k=q^{\top}R((n-m)\theta)k.

With base 10,000 and d = 64, what is the longest wavelength?

θ\theta for the last pair (i=31i=31) is 10,000−62/64≈1.3×10−410{,}000^{-62/64}\approx1.3\times10^{-4}, so λ=2π/θ≈47,000\lambda=2\pi/\theta\approx47{,}000 tokens.

Why does YaRN leave the fastest frequencies unchanged?

They complete many turns in the original window, so the model has seen every phase of them; compressing them would destroy the fine resolution needed to tell adjacent tokens apart.

  • RoPE.
  • ALiBi, a different route to length extrapolation.
  • Position interpolation.
  • YaRN: sections 3.1–3.4 contain the formulas.
  • How models actually use long contexts.