Files
olivv-cs-ComfyUI-FunPack/modules/models/minimax_h3/rope.py
T

32 lines
1.4 KiB
Python

"""H3's rotary position encoding, undone and redone outside the model.
H3 turns the first `2*half` dims of every head's query by a per-row 2x2 matrix
(split-half: dim i pairs with i+half). A feature that averages queries across
rows, or adds one vector to all of them, has to work where the rows are NOT yet
turned -- otherwise the average cancels and the push points somewhere different
at every position. Mirrors comfy_kitchen's eager `apply_rope_split_half1`.
"""
import torch
def query_rotation(rope_freqs, seq_len):
"""-> rotate(x [..., n, D], rows slice, inverse=False), or None when
`rope_freqs` is not H3's [1, S, 1, half, 2, 2] table for this sequence."""
if not torch.is_tensor(rope_freqs) or rope_freqs.ndim != 6 \
or rope_freqs.shape[1] != seq_len or tuple(rope_freqs.shape[-2:]) != (2, 2):
return None
table = rope_freqs[0, :, 0] # [S, half, 2, 2]
def rotate(x, rows, inverse=False):
t = table[rows]
half = int(t.shape[-3])
rot = 2 * half
pairs = x[..., :rot].reshape(*x.shape[:-1], 2, half).movedim(-2, -1).float()
mat = t.float().transpose(-1, -2) if inverse else t.float()
out = (mat @ pairs.unsqueeze(-1)).squeeze(-1)
out = out.movedim(-1, -2).reshape(*x.shape[:-1], rot).to(x.dtype)
return torch.cat([out, x[..., rot:]], dim=-1)
return rotate