nemo_automodel.components.models.deepseek_v41.rope_triton
nemo_automodel.components.models.deepseek_v41.rope_triton
Fused Triton rotary embedding for DeepSeek V4.1, forward and backward in one kernel each.
_apply_rope in nemo_automodel.components.models.deepseek_v41.attention rotates the
last 2 * rotary_pairs channels of a [batch, sequence, channels] or
[batch, sequence, heads, channels] tensor as adjacent complex pairs and copies the remaining
channels. Eagerly that is a complex multiply plus torch.cat in the forward and several
zero-filled slice gradients in the backward, so every call streams the full tensor through
memory more than once. This module writes the copied and the rotated channels in a single
pass, and its backward rotates the incoming gradient by the conjugate in one pass as well.
angles never receives a gradient here; inputs whose angles require one, inputs that are
not on CUDA, and dtypes outside BF16/FP16/FP32 take the eager path.
Numerics follow the eager path by construction wherever PyTorch allows it:
- The frequencies come from the same
torch.polar(torch.ones_like(angles), angles)call the eager path runs, so thecos/sinbits are identical rather than relying on libdevice agreeing with the CUDA math library PyTorch was built with. They are computed once per forward call and saved for the backward, which is the same footprint as the eager path’s savedfrequencies. - The complex product
(x0 + i x1) * (c + i s)is evaluated in FP32 asr0 = fma(x0, c, -(x1 * s))andr1 = fma(x0, s, x1 * c).c10::complex<float>multiplies asa * c - b * danda * d + b * c, and nvcc contracts each expression into one FMA with the first product fused; the kernel spells that contraction out so the result does not depend on Triton’s FP-fusion default. The conjugate used byinverse=Trueand by every backward only negatess, which is exact and leaves the rounding pattern unchanged. If a GPU parity run ever reports one-ulp differences, the twotl.fmalines in_rope_kernelare the single place to adjust. - The FP32 result is rounded to
values.dtypewith round-to-nearest-even, exactly asTensor.torounds.
Module Contents
Classes
Functions
Data
API
Bases: Function
Rotate with the fused kernel and rotate the gradient by the conjugate frequency.
Eager rotation, mirroring attention._apply_rope so the fallback needs no circular import.
Parameters:
Tensor of shape [batch, sequence, channels] or [batch, sequence, heads, channels].
FP32 tensor of shape [batch, sequence, rotary_pairs].
Conjugate the rotation.
Returns: torch.Tensor
Tensor with the shape and dtype of values, in independent storage.
Run the fused kernel over values and return a new contiguous tensor.
Parameters:
CUDA tensor of shape [batch, sequence, channels] or [batch, sequence, heads, channels]. Any leading strides are read in place; a strided channel dimension is made contiguous first.
Contiguous FP32 tensor of shape [batch, sequence, pairs, 2].
Rotate by the conjugate frequency.
Returns: torch.Tensor
Contiguous tensor with the shape and dtype of values.
Copy the leading channels and rotate the trailing pairs of BLOCK_R rows.
Every row is read once as BLOCK_K adjacent channel pairs and written once. Pairs
before the rotary block are passed through tl.where rather than multiplied by a
unit frequency, so non-finite prefix values are copied bit for bit.
Parameters:
Input viewed as [batch, sequence, heads, channels] with a unit channel
stride; heads is 1 for three-dimensional inputs.
Contiguous FP32 tensor of shape [batch * sequence, pairs, 2] holding (cos, sin) per rotary pair.
Contiguous output of shape [rows, channels].
batch * sequence * heads.
Sequence length.
Head count, 1 for three-dimensional inputs.
Channel count.
Rotary pair count; the last 2 * pairs channels rotate.
Channel pairs preceding the rotary block, rounded up so the pair grid covers channel 0 (it then starts at channel -1 for an odd prefix, masked off).
Input batch stride in elements.
Input sequence stride in elements.
Input head stride in elements; ignored when heads is 1.
Rotate by the conjugate frequency.
Rows handled by one program.
Power-of-two pair extent per row, at least pair_offset + pairs.
Rotate the final channels of values with the fused Triton kernel.
Drop-in for attention._apply_rope: the last 2 * angles.shape[-1] channels are
rotated as adjacent pairs by exp(i * angles) (its conjugate when inverse) and the
remaining channels are copied, all in one pass. The backward rotates the gradient by the
conjugate in one pass; angles receives no gradient. Inputs that are not on CUDA, whose
angles require a gradient, or whose dtype is outside BF16/FP16/FP32 use the eager path.
Parameters:
Tensor of shape [batch, sequence, channels] or [batch, sequence, heads, channels]; non-contiguous inputs are accepted.
FP32 tensor of shape [batch, sequence, rotary_pairs].
Conjugate the rotation, as for the attention output.
Returns: torch.Tensor
New contiguous tensor with the shape and dtype of values.
Raises:
RuntimeError:valuesis on CUDA but Triton is not importable.ValueError:anglesdoes not describe an even rotary width withinvalues.