siglino-30M / rope.py
SofianChay's picture
Update SigLino siglino-30M (full content push)
e5f4b9e verified
Raw
History Blame Contribute Delete
4.74 kB
# RoPE (Rotary Position Embedding) implementation for Falcon Vision
# Includes 1D RoPE and 2D Golden RoPE for vision tokens
import torch
import einops as E
def precompute_freqs_cis(dim: int, end: int, theta: float = 10000.0) -> torch.Tensor:
"""Precompute frequency tensor for 1D rotary embeddings."""
freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim))
t = torch.arange(end, device=freqs.device)
freqs = torch.outer(t, freqs).float()
return torch.polar(torch.ones_like(freqs), freqs)
def reshape_for_broadcast(freqs_cis: torch.Tensor, x: torch.Tensor) -> torch.Tensor:
ndim = x.ndim
seqlen = x.shape[1]
freqs_cis = freqs_cis[:seqlen]
shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)]
return freqs_cis.view(*shape)
def apply_rotary_emb(
xq: torch.Tensor,
xk: torch.Tensor,
freqs_cis: torch.Tensor,
pos_t: torch.Tensor | None = None,
) -> tuple[torch.Tensor, torch.Tensor]:
"""Apply rotary embeddings to query and key tensors."""
xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2))
xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2))
if freqs_cis.ndim == 3:
freqs_cis = freqs_cis.unsqueeze(-2)
elif pos_t is not None:
freqs_cis = freqs_cis[pos_t.long()].unsqueeze(-2)
else:
freqs_cis = reshape_for_broadcast(freqs_cis, xq_)
xq_out = torch.view_as_real(xq_ * freqs_cis).flatten(3)
xk_out = torch.view_as_real(xk_ * freqs_cis).flatten(3)
return xq_out.type_as(xq), xk_out.type_as(xk)
def apply_3d_rotary_emb(
xq: torch.Tensor,
xk: torch.Tensor,
freqs_cis: torch.Tensor,
freqs_cis_2d: torch.Tensor | None,
pos_hw: torch.Tensor | None,
) -> tuple[torch.Tensor, torch.Tensor]:
"""Apply 3D rotary embeddings (1D temporal + 2D spatial)."""
xq_t, xq_hw = xq.chunk(chunks=2, dim=-1)
xk_t, xk_hw = xk.chunk(chunks=2, dim=-1)
pos_t = pos_hw[:, :, 0].clone() if pos_hw is not None else None
xq_t, xk_t = apply_rotary_emb(xq_t, xk_t, freqs_cis, pos_t=pos_t)
if freqs_cis_2d is not None and pos_hw is not None:
xq_hw = apply_golden_rotary_emb(xq_hw, freqs_cis_2d, pos_hw[..., 1:])
xk_hw = apply_golden_rotary_emb(xk_hw, freqs_cis_2d, pos_hw[..., 1:])
xq_out = torch.concat([xq_t, xq_hw], dim=-1).type_as(xq)
xk_out = torch.concat([xk_t, xk_hw], dim=-1).type_as(xk)
return xq_out, xk_out
def _phi(m: int) -> float:
x = 2.0
for _ in range(10):
x = (1 + x) ** (1.0 / (m + 1.0))
return x
def make_directions(n: int, d: int) -> torch.Tensor:
g = _phi(d)
alpha = (1.0 / g) ** torch.arange(1, d + 1, dtype=torch.float64)
i = torch.arange(1, n + 1, dtype=torch.float64).unsqueeze(1)
z = torch.fmod(i * alpha, 1.0)
directions = torch.erfinv(2.0 * z - 1.0)
directions = directions / directions.norm(dim=1, keepdim=True)
return directions.float()
def precompute_golden_freqs_cis(
n_heads: int,
head_dim: int,
min_freq: float,
max_freq: float,
pos_dim: int = 2,
p_zero_freqs: float = 0.0,
) -> torch.Tensor:
"""Precompute golden ratio based 2D frequencies for vision tokens."""
n_freqs = head_dim // 2
n_zero_freqs = round(p_zero_freqs * n_freqs)
omega_F = torch.cat((
torch.zeros(n_zero_freqs),
min_freq * (max_freq / min_freq) ** torch.linspace(0, 1, n_freqs - n_zero_freqs),
))
directions_hFP = make_directions(n_heads * n_freqs, pos_dim).reshape(n_heads, n_freqs, pos_dim)
return directions_hFP * omega_F.reshape(n_freqs, 1)
def apply_golden_freqs_cis_to_visual_pos(freqs_hFP: torch.Tensor, pos_BSP: torch.Tensor) -> torch.Tensor:
"""Apply golden frequencies to visual positions."""
img_mask_BS = E.reduce(~torch.isnan(pos_BSP), 'b s p -> b s', reduction='all')
pos_tP = pos_BSP[img_mask_BS].float()
theta_thF = torch.einsum('tp,hfp->thf', pos_tP, freqs_hFP)
return torch.polar(torch.ones_like(theta_thF), theta_thF)
def apply_golden_rotary_emb(
input_BShd: torch.Tensor,
freqs_cis_thF: torch.Tensor,
pos_BSP: torch.Tensor,
) -> torch.Tensor:
"""Apply golden rotary embedding to image tokens only."""
img_mask_BS = E.reduce(~torch.isnan(pos_BSP), 'b s p -> b s', reduction='all')
input_thd = input_BShd[img_mask_BS]
input_thd = torch.view_as_complex(
E.rearrange(input_thd.float(), "t h (d two) -> t h d two", two=2)
)
output_thd = input_thd * freqs_cis_thF
output_thd = torch.view_as_real(output_thd).flatten(-2).type_as(input_BShd)
img_mask_BS11 = E.rearrange(img_mask_BS, 'b s -> b s 1 1')
return input_BShd.masked_scatter(img_mask_BS11, output_thd)