Thomas Piacentini
← Workshop

Python exercise

Rotary position embedding

Original text · English25 min

Rotary position embedding (RoPE) puts the position of a token into its query and key vectors. It turns each pair of coordinates by an angle that grows with the position. Then the attention score of a query and a key depends only on the distance between their positions. Most open language models use RoPE.

Task

Write two functions.

  1. rope_frequencies(d, base=10000.0) returns the frequency of each coordinate pair.
  2. apply_rope(x, positions, base=10000.0) returns a rotated copy of x.

The frequency of pair i is \theta_i = \text{base}^{-2i/d}, for i = 0, 1, \dots, \lfloor d/2 \rfloor - 1.

Pair i is the two adjacent coordinates 2i and 2i + 1. For the token at position p, let a = x_{2i}, b = x_{2i+1} and \phi = p \, \theta_i. The output pair is:

a' = a \cos\phi - b \sin\phi, \qquad b' = a \sin\phi + b \cos\phi

When d is odd, the last coordinate has no partner. Copy it to the output without a change.

Input and output

Name Type Shape Meaning
d int the size of the last axis
base float the base of the frequencies
x float array (..., T, d) the vectors of T tokens, with zero or more leading batch axes
positions int or float array (T,) the position of each token
  • rope_frequencies returns a float array of shape (d // 2,).
  • apply_rope returns a new float array with the shape of x.

Constraints

  • 1 <= T <= 64 and 2 <= d <= 128.
  • Positions are from 0 to 1000000.
  • The positions go with the second to last axis of x. Every leading axis gets the same rotation.
  • Use the pairs (0, 1), (2, 3), .... Do not pair coordinate i with coordinate i + d/2.
  • Do not change the input arrays.
  • Use numpy only.

Examples

python
rope_frequencies(8)
text
[1.    0.1   0.01  0.001]
python
x = np.array([[1.0, 0.0, 1.0, 0.0], [1.0, 0.0, 1.0, 0.0], [1.0, 0.0, 1.0, 0.0]])
apply_rope(x, np.arange(3))
text
[[ 1.          0.          1.          0.        ]
 [ 0.54030231  0.84147098  0.99995     0.00999983]
 [-0.41614684  0.90929743  0.99980001  0.01999867]]
python
q = np.array([[1.0, 2.0, 3.0, 4.0]])
k = np.array([[0.5, -1.0, 2.0, 1.0]])
apply_rope(q, [2])[0] @ apply_rope(k, [5])[0]
apply_rope(q, [10])[0] @ apply_rope(k, [13])[0]
text
11.912706599522757
11.912706599522759
Code and artifacts 13
What you take away

Saved in your notebook on this device.

Sources and limits

Reading checkpoints are self-reported. Test results are recorded separately and apply to the executed cases.

AI Engineering from Scratch · 3f9715c · MIT

Download this file ↓