The problem
Attention on its own ignores the order of the tokens. RoPE (rotary position embedding) adds it by rotating the queries and keys: the vector of the token at position is turned by an angle proportional to . Then the score of a query and a key depends on how far apart the two tokens are (the theory page shows why). You will write the rotation.
Pairs of numbers, turned like points in the plane
A vector of numbers is read as pairs of neighbours: , , and so on. Each pair is a point in the plane, and pair turns at its own speed :
At position , pair is rotated by the angle :
where:
- and are the two numbers of pair , and is the rotated vector;
- is the position of the token: ;
- base is usually . The exponent makes (the first pair turns 1 radian per position) and the later pairs turn more and more slowly.
These two lines are the standard rotation of a point around the origin: its distance from the origin does not change, only its direction.
Example. , base : two pairs, with speeds and . The same vector at positions 0, 1 and 2:
- Position 0: both angles are 0, nothing turns: .
- Position 1: pair 0 turns by 1 radian, pair 1 by : .
- Position 2: pair 0 turns by 2 radians, pair 1 by : .
For pair 0 at : . Pair 0 turns fast and tells nearby positions apart; pair 1 has barely moved, and changes noticeably only over hundreds of positions.
What to implement
apply_rope(x, positions, base=10000.0): x has shape and positions is an integer array of shape , the position of each row. Return the rotated array, same shape.
Requirements
- Pairs are adjacent dimensions , as in the RoFormer paper. (Some libraries pair dimension with instead; that is a different, equally valid layout, but not the one asked for.)
- Raise
ValueErrorif is odd. - No Python loops.
Hints
- Build the table of angles at once: positions as a column times the speeds as a row (broadcasting).
x[..., 0::2]is the first number of every pair andx[..., 1::2]the second. Compute both rotated halves, then write them back into an output array with the same slices.