mrope
Interleaved multimodal rotary position embedding, applied in place, loadable
through kernels. The reference baseline is transformers'
Qwen3_5TextRotaryEmbedding, matched to 3.1e-7 in fp32, with an fp64
rotation as the accuracy oracle.
A multimodal model needs three positions per token rather than one: an image
patch has a place in time, in height, and in width, so the rotary frequency
band is partitioned across those axes. The interleaved layout cycles them,
[THWTHW...], so each axis keeps a full spread of wavelengths. This kernel
applies all of it in one pass, one block per token with the angles computed
once into shared memory and reused across every head, and evaluates angles in
double precision, which is what keeps a 262,144-token context accurate where
the eager fp32 path has lost four orders of magnitude.
The kernel's own axis map probed live: 32 frequency dials colored time, height, width in the interleaved pattern, each phase advancing one axis and spinning only that axis's dials. At position 262,143 the kernel's angle errs 9e-8 radians against an exact reference; the fp32 eager path errs 8e-5.
Usage
import torch
from kernels import get_kernel
mrope = get_kernel("phanerozoic/mrope", version=1, trust_remote_code=True)
# q is [B, S, Hq, D], k is [B, S, Hk, D], pos is [3, B, S] int32 holding the
# time, height and width position of every token. Both rotate in place.
mrope.apply_mrope(q, k, pos, head_dim=256, partial_rotary_factor=0.25,
mrope_section=(11, 11, 10), rope_theta=1e7)
version selects the release branch; trust_remote_code is required by
kernels for publishers without the trusted-publisher mark.
API
| Symbol | Purpose |
|---|---|
apply_mrope(q, k, pos, head_dim, partial_rotary_factor, mrope_section, rope_theta) |
rotate in place; k may be None |
MRope(head_dim, partial_rotary_factor, mrope_section, rope_theta) |
module form holding the geometry |
axis_of_frequency(half, section) |
which position axis each frequency uses |
Method
Two details make this its own kernel rather than a case of ordinary RoPE.
Partial rotary: only the first head_dim * partial_rotary_factor channels
rotate, the rest pass through untouched; at head dimension 256 and factor
0.25 that is 64 rotated channels of 256. Interleaved sections: frequency j
uses the time position unless j % 3 == 1 and j < 3 * section[1] (height)
or j % 3 == 2 and j < 3 * section[2] (width); with sections [11, 11, 10]
over 32 frequencies that reduces exactly to j % 3. One block per
(batch, token) computes the 32 angles once into shared memory and reuses
them across every head of that token.
Measured
Against the eager transformers implementation, head dimension 256, 24 query and 4 key heads:
| batch | tokens | eager | this | speedup |
|---|---|---|---|---|
| 1 | 1 | 0.3107 ms | 0.0243 ms | 12.80x |
| 1 | 512 | 0.5334 ms | 0.0215 ms | 24.76x |
| 1 | 4,096 | 0.7179 ms | 0.1809 ms | 3.97x |
| 4 | 2,048 | 1.4754 ms | 0.4162 ms | 3.54x |
The eager path builds a [3, B, S, 32] frequency tensor, slices it three
ways, concatenates, takes a cosine and a sine, and runs four elementwise
passes; this kernel touches each element once.
Accuracy at long positions, against an independent fp64 rotation:
| position | this kernel | eager reference |
|---|---|---|
| 1,024 | 1.6e-8 | 2.1e-6 |
| 65,536 | 1.9e-8 | 1.4e-4 |
| 262,143 | 1.8e-8 | 7.2e-4 |
Angles are evaluated in double before being reduced to float; the eager reference computes them in float32, which loses the fractional part of a cycle at large positions.
Correctness
Verified against transformers 5.13:
- The frequency-to-axis assignment is
torch.equalto the reference slice construction, and per-axis counts equal the configured sections. - Output matches to 3.1e-7 relative in fp32 and 1.0e-3 in bf16, across batch 1 to 3, 8 to 512 tokens, grouped and ungrouped head counts, with distinct positions on all three axes.
- Moving only the height position changes exactly the frequencies assigned
to height, checked elementwise; each rotation pair keeps its magnitude to
1e-3; the tail beyond
rotary_dimis bitwise unchanged; position zero is the exact identity.
Requirements and limits
- NVIDIA GPU with compute capability 8.0+.
qandkcontiguous[B, S, H, D], bf16 or fp32, sharing a dtype;[B, H, S, D]tensors need a permute first.rotary_dim / 2at most 128; positions int32 (contexts to 2^31 tokens).- Forward only: RoPE is its own inverse up to a sign, so backward is a second call with negated positions.
References
Su et al., "RoFormer" (2021); Wang et al., "Qwen2-VL" (2024) for multimodal
rotary sections; the interleaved layout as implemented in transformers'
Qwen3_5TextRotaryEmbedding.
License
Apache-2.0.
- Downloads last month
- -
- OS
- linux
- Arch
- x86_64
- Kernel Builder
- 19aaa64





