Module neuralops.attentions.nexus
NEXUS: Neural Efficient X-scoring Unified Sparse Attention.
============================================================= Hybrid sparse attention architecture combining multi-scale sparsity mechanisms: 1. XAttention antidiagonal block scoring (ICML 2025) - training-free block routing 2. SeerAttention learnable gating (NeurIPS 2025) - per-head block sparsity 3. DuSA dual-stage sparse (NeurIPS 2025) - intra-block dense + inter-block sparse 4. AnchorAttention stripe granularity (2025) - fine-grained intra-block band sparsity 5. Spectraformer random Fourier feature rectification (2025) - global linear fallback 6. Softpick rectified softmax (2025) - natural ~47% activation sparsity
Functions
def apply_rotary_pos_emb(q: torch.Tensor, k: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor) ‑> tuple[torch.Tensor, torch.Tensor]-
Expand source code
def apply_rotary_pos_emb( q: torch.Tensor, k: torch.Tensor, cos: torch.Tensor, sin: torch.Tensor, ) -> tuple[torch.Tensor, torch.Tensor]: if cos is None or sin is None: return q, k if cos.dim() == 2: cos = cos.unsqueeze(0).unsqueeze(0) sin = sin.unsqueeze(0).unsqueeze(0) elif cos.dim() == 3: cos = cos.unsqueeze(1) sin = sin.unsqueeze(1) while cos.dim() < q.dim(): cos = cos.unsqueeze(0) sin = sin.unsqueeze(0) if cos.shape[-2] != q.shape[-2]: raise ValueError(f"RoPE seq len mismatch: cos {cos.shape[-2]} vs q {q.shape[-2]}") rotary_dim = cos.shape[-1] head_dim = q.shape[-1] if rotary_dim <= head_dim: q_rot, q_pass = q[..., :rotary_dim], q[..., rotary_dim:] k_rot, k_pass = k[..., :rotary_dim], k[..., rotary_dim:] cos_q = cos.to(q_rot.dtype) sin_q = sin.to(q_rot.dtype) cos_k = cos.to(k_rot.dtype) sin_k = sin.to(k_rot.dtype) q_rot_embed = (q_rot * cos_q) + (_rotate_half(q_rot) * sin_q) k_rot_embed = (k_rot * cos_k) + (_rotate_half(k_rot) * sin_k) q = torch.cat([q_rot_embed, q_pass], dim=-1) if q_pass.numel() > 0 else q_rot_embed k = torch.cat([k_rot_embed, k_pass], dim=-1) if k_pass.numel() > 0 else k_rot_embed else: cos_cut = cos[..., :head_dim].to(q.dtype) sin_cut = sin[..., :head_dim].to(q.dtype) q = (q * cos_cut) + (_rotate_half(q) * sin_cut) cos_k = cos[..., :head_dim].to(k.dtype) sin_k = sin[..., :head_dim].to(k.dtype) k = (k * cos_k) + (_rotate_half(k) * sin_k) return q, k def inject_nexus(model: torch.nn.modules.module.Module | None = None,
layer: torch.nn.modules.module.Module | None = None,
model_config: Any = None,
comp_config: Any = None,
layer_idx: int = 0,
total_layers: int = 12,
old_attn: torch.nn.modules.module.Module | None = None,
**kwargs: Any) ‑> NEXUSAttention | torch.nn.modules.module.Module | None-
Expand source code
@ATTENTION_REGISTRY.register("inject_nexus") @ATTENTION_REGISTRY.register("nexus_inject") @ATTENTION_REGISTRY.register("inject_nexus_attention") @ATTENTION_REGISTRY.register("nexus_attention_inject") def inject_nexus( model: nn.Module | None = None, layer: nn.Module | None = None, model_config: Any = None, comp_config: Any = None, layer_idx: int = 0, total_layers: int = 12, old_attn: nn.Module | None = None, _depth: int = 0, **kwargs: Any, ) -> NEXUSAttention | nn.Module | None: if _depth > 8: logger.warning("inject_nexus: max recursion depth exceeded.") return None target = layer if layer is not None else model if target is None: return None cfg = model_config if cfg is None and hasattr(target, "config"): cfg = target.config layer_list = None if hasattr(target, "distilbert") and hasattr(target.distilbert, "transformer"): layer_list = target.distilbert.transformer.layer elif hasattr(target, "roberta") and hasattr(target.roberta, "encoder"): layer_list = target.roberta.encoder.layer elif hasattr(target, "transformer") and hasattr(target.transformer, "h"): layer_list = target.transformer.h elif hasattr(target, "model") and hasattr(target.model, "layers"): layer_list = target.model.layers elif hasattr(target, "encoder") and hasattr(target.encoder, "layer"): layer_list = target.encoder.layer elif ( hasattr(target, "bert") and hasattr(target.bert, "encoder") and hasattr(target.bert.encoder, "layer") ): layer_list = target.bert.encoder.layer elif hasattr(target, "layers") and isinstance(target.layers, (nn.ModuleList, list)): layer_list = target.layers if layer_list is not None: num_injected = 0 tot = len(layer_list) for idx, lyr in enumerate(layer_list): res = inject_nexus( layer=lyr, model_config=cfg, comp_config=comp_config, layer_idx=idx, total_layers=tot, _depth=_depth + 1, **kwargs, ) if res is not None: num_injected += 1 return target if num_injected > 0 else None try: src_attn = old_attn if src_attn is None and target is not None: for attr in ("attention", "self_attn", "attn", "self"): if hasattr(target, attr): cand = getattr(target, attr) if hasattr(cand, "self"): src_attn = cand.self else: src_attn = cand break if src_attn is None and target is not None and hasattr(target, "forward"): src_attn = target if src_attn is None: return None if isinstance(src_attn, NEXUSAttention) or "NEXUS" in src_attn.__class__.__name__: return None if hasattr(src_attn, "inner") and isinstance(src_attn.inner, NEXUSAttention): return None if hasattr(src_attn, "_wrapped_attention") and isinstance( src_attn._wrapped_attention, NEXUSAttention ): return None if target is not None: for attr in ("attention", "self_attn", "attn", "self"): cand = getattr(target, attr, None) if cand is None: continue if isinstance(cand, NEXUSAttention): return None if "NEXUS" in cand.__class__.__name__: return None if src_attn is not None: c_name = src_attn.__class__.__name__ if "DeltaNet" in c_name or "LinearAttention" in c_name: return None if cfg is None and hasattr(src_attn, "config"): cfg = src_attn.config nexus_cfg = kwargs.get("nexus_cfg") if nexus_cfg is None: nexus_cfg = NEXUSConfig( block_size=(getattr(comp_config, "block_size", 16) if comp_config else 16), top_k_blocks=(getattr(comp_config, "top_k_inter", 4) if comp_config else 4), xattn_enabled=True, seer_enabled=True, dual_stage_enabled=True, stripe_enabled=True, rectify_interval=( getattr(comp_config, "rectify_interval", 4) if comp_config else 4 ), rff_features=(getattr(comp_config, "rff_features", 128) if comp_config else 128), softpick_enabled=True, sparse_min_seq_len=8, enable_spectraformer=( getattr(comp_config, "enable_spectraformer", False) if comp_config else False ), dropout=getattr(comp_config, "dropout", 0.1) if comp_config else 0.1, ) new_attn = NEXUSAttention( model_config=cfg, nexus_cfg=nexus_cfg, layer_idx=layer_idx, total_layers=total_layers, pretrained_attn=src_attn, **kwargs, ) p = next(src_attn.parameters(), None) if p is not None: new_attn.to(device=p.device, dtype=p.dtype) if target is not None: if hasattr(target, "attention") and hasattr(target.attention, "self"): new_attn.is_nested_encoder = True if hasattr(new_attn, "dss_attn"): new_attn.dss_attn.is_nested_encoder = True target.attention.self = new_attn return new_attn if hasattr(target, "attention"): new_attn.is_nested_encoder = False if hasattr(new_attn, "dss_attn"): new_attn.dss_attn.is_nested_encoder = False target.attention = new_attn return new_attn if hasattr(target, "self_attn"): new_attn.is_nested_encoder = False target.self_attn = new_attn return new_attn if hasattr(target, "attn"): new_attn.is_nested_encoder = False target.attn = new_attn return new_attn if hasattr(target, "self"): new_attn.is_nested_encoder = True target.self = new_attn return new_attn target.attention = new_attn return new_attn return new_attn except Exception as e: logger.exception("inject_nexus failed: %s", e) return None def inject_nexus_attention(model: torch.nn.modules.module.Module | None = None,
layer: torch.nn.modules.module.Module | None = None,
model_config: Any = None,
comp_config: Any = None,
layer_idx: int = 0,
total_layers: int = 12,
old_attn: torch.nn.modules.module.Module | None = None,
**kwargs: Any) ‑> NEXUSAttention | torch.nn.modules.module.Module | None-
Expand source code
@ATTENTION_REGISTRY.register("inject_nexus") @ATTENTION_REGISTRY.register("nexus_inject") @ATTENTION_REGISTRY.register("inject_nexus_attention") @ATTENTION_REGISTRY.register("nexus_attention_inject") def inject_nexus( model: nn.Module | None = None, layer: nn.Module | None = None, model_config: Any = None, comp_config: Any = None, layer_idx: int = 0, total_layers: int = 12, old_attn: nn.Module | None = None, _depth: int = 0, **kwargs: Any, ) -> NEXUSAttention | nn.Module | None: if _depth > 8: logger.warning("inject_nexus: max recursion depth exceeded.") return None target = layer if layer is not None else model if target is None: return None cfg = model_config if cfg is None and hasattr(target, "config"): cfg = target.config layer_list = None if hasattr(target, "distilbert") and hasattr(target.distilbert, "transformer"): layer_list = target.distilbert.transformer.layer elif hasattr(target, "roberta") and hasattr(target.roberta, "encoder"): layer_list = target.roberta.encoder.layer elif hasattr(target, "transformer") and hasattr(target.transformer, "h"): layer_list = target.transformer.h elif hasattr(target, "model") and hasattr(target.model, "layers"): layer_list = target.model.layers elif hasattr(target, "encoder") and hasattr(target.encoder, "layer"): layer_list = target.encoder.layer elif ( hasattr(target, "bert") and hasattr(target.bert, "encoder") and hasattr(target.bert.encoder, "layer") ): layer_list = target.bert.encoder.layer elif hasattr(target, "layers") and isinstance(target.layers, (nn.ModuleList, list)): layer_list = target.layers if layer_list is not None: num_injected = 0 tot = len(layer_list) for idx, lyr in enumerate(layer_list): res = inject_nexus( layer=lyr, model_config=cfg, comp_config=comp_config, layer_idx=idx, total_layers=tot, _depth=_depth + 1, **kwargs, ) if res is not None: num_injected += 1 return target if num_injected > 0 else None try: src_attn = old_attn if src_attn is None and target is not None: for attr in ("attention", "self_attn", "attn", "self"): if hasattr(target, attr): cand = getattr(target, attr) if hasattr(cand, "self"): src_attn = cand.self else: src_attn = cand break if src_attn is None and target is not None and hasattr(target, "forward"): src_attn = target if src_attn is None: return None if isinstance(src_attn, NEXUSAttention) or "NEXUS" in src_attn.__class__.__name__: return None if hasattr(src_attn, "inner") and isinstance(src_attn.inner, NEXUSAttention): return None if hasattr(src_attn, "_wrapped_attention") and isinstance( src_attn._wrapped_attention, NEXUSAttention ): return None if target is not None: for attr in ("attention", "self_attn", "attn", "self"): cand = getattr(target, attr, None) if cand is None: continue if isinstance(cand, NEXUSAttention): return None if "NEXUS" in cand.__class__.__name__: return None if src_attn is not None: c_name = src_attn.__class__.__name__ if "DeltaNet" in c_name or "LinearAttention" in c_name: return None if cfg is None and hasattr(src_attn, "config"): cfg = src_attn.config nexus_cfg = kwargs.get("nexus_cfg") if nexus_cfg is None: nexus_cfg = NEXUSConfig( block_size=(getattr(comp_config, "block_size", 16) if comp_config else 16), top_k_blocks=(getattr(comp_config, "top_k_inter", 4) if comp_config else 4), xattn_enabled=True, seer_enabled=True, dual_stage_enabled=True, stripe_enabled=True, rectify_interval=( getattr(comp_config, "rectify_interval", 4) if comp_config else 4 ), rff_features=(getattr(comp_config, "rff_features", 128) if comp_config else 128), softpick_enabled=True, sparse_min_seq_len=8, enable_spectraformer=( getattr(comp_config, "enable_spectraformer", False) if comp_config else False ), dropout=getattr(comp_config, "dropout", 0.1) if comp_config else 0.1, ) new_attn = NEXUSAttention( model_config=cfg, nexus_cfg=nexus_cfg, layer_idx=layer_idx, total_layers=total_layers, pretrained_attn=src_attn, **kwargs, ) p = next(src_attn.parameters(), None) if p is not None: new_attn.to(device=p.device, dtype=p.dtype) if target is not None: if hasattr(target, "attention") and hasattr(target.attention, "self"): new_attn.is_nested_encoder = True if hasattr(new_attn, "dss_attn"): new_attn.dss_attn.is_nested_encoder = True target.attention.self = new_attn return new_attn if hasattr(target, "attention"): new_attn.is_nested_encoder = False if hasattr(new_attn, "dss_attn"): new_attn.dss_attn.is_nested_encoder = False target.attention = new_attn return new_attn if hasattr(target, "self_attn"): new_attn.is_nested_encoder = False target.self_attn = new_attn return new_attn if hasattr(target, "attn"): new_attn.is_nested_encoder = False target.attn = new_attn return new_attn if hasattr(target, "self"): new_attn.is_nested_encoder = True target.self = new_attn return new_attn target.attention = new_attn return new_attn return new_attn except Exception as e: logger.exception("inject_nexus failed: %s", e) return None def softpick(x: torch.Tensor, dim: int = -1, temperature: float = 1.0) ‑> torch.Tensor-
Expand source code
def softpick(x: torch.Tensor, dim: int = -1, temperature: float = 1.0) -> torch.Tensor: orig_dtype = x.dtype x_f = x.float() temp = max(temperature, 1e-6) m = x_f.max(dim=dim, keepdim=True).values m = torch.where(m < -1e3, torch.zeros_like(m), m) z = x_f - m exp_z = torch.exp(z / temp) exp_neg_m = torch.exp((-m) / temp).clamp(max=1e4) p = F.relu(exp_z - exp_neg_m) denom = p.sum(dim=dim, keepdim=True) zero_mask = denom <= 1e-8 if zero_mask.any(): fallback = F.softmax(x_f, dim=dim) p = torch.where(zero_mask, fallback, p / (denom + 1e-8)) else: p = p / denom return p.to(orig_dtype)
Classes
class DualStageStripeAttention (cfg: NEXUSConfig,
head_dim: int,
num_heads: int = 1,
is_decoder: bool = False,
is_nested_encoder: bool = False,
**kwargs)-
Expand source code
class DualStageStripeAttention(nn.Module): def __init__( self, cfg: NEXUSConfig, head_dim: int, num_heads: int = 1, is_decoder: bool = False, is_nested_encoder: bool = False, **kwargs, ) -> None: super().__init__() self.cfg = cfg self.head_dim = head_dim self.num_heads = num_heads self.is_decoder = is_decoder self.is_nested_encoder = is_nested_encoder self.xattn_scorer = XAttentionScorer() def _inter_block_topk(self, scores: torch.Tensor, top_k: int) -> torch.Tensor: B, H, nb, nb2 = scores.shape tk = min(top_k, nb2) scores_inter = scores.clone() min_dim = min(nb, nb2) diag_idx = torch.arange(min_dim, device=scores.device) scores_inter[:, :, diag_idx, diag_idx] = float("-inf") _, idx = scores_inter.topk(tk, dim=-1) mask = torch.zeros_like(scores, dtype=torch.bool).scatter_(-1, idx, True) mask[:, :, diag_idx, diag_idx] = True return mask def forward( self, Q: torch.Tensor, K: torch.Tensor, V: torch.Tensor, token_valid: torch.Tensor | None = None, seer_mask: torch.Tensor | None = None, ) -> torch.Tensor: B, H, N, D = Q.shape bs = self.cfg.block_size nb = (N + bs - 1) // bs top_k = self.cfg.top_k_blocks scale = D**-0.5 if self.cfg.xattn_enabled: block_scores = self.xattn_scorer.score_blocks(Q, K, bs, self.cfg.xattn_stride) inter_mask = self._inter_block_topk(block_scores, top_k) else: inter_mask = torch.ones(B, H, nb, nb, device=Q.device, dtype=torch.bool) if seer_mask is not None: inter_mask = inter_mask | seer_mask inter_mask[:, :, :, 0] = True diag_idx = torch.arange(nb, device=Q.device) inter_mask[:, :, diag_idx, diag_idx] = True scores = torch.matmul(Q.float(), K.float().transpose(-2, -1).contiguous()) * scale expanded_mask = inter_mask.repeat_interleave(bs, dim=2).repeat_interleave(bs, dim=3)[ :, :, :N, :N ] scores = scores.masked_fill(~expanded_mask, -10000.0) if self.cfg.stripe_enabled and N > 256: sw = self.cfg.stripe_width idx = torch.arange(N, device=Q.device) stripe_group = idx // sw q_stripe = stripe_group.unsqueeze(1) k_stripe = stripe_group.unsqueeze(0) stripe_mask = (q_stripe - k_stripe).abs() <= 1 scores = scores.masked_fill(~stripe_mask.unsqueeze(0).unsqueeze(0), -10000.0) if self.is_decoder: causal = torch.tril(torch.ones(N, N, device=Q.device, dtype=torch.bool)) scores = scores.masked_fill(~causal.unsqueeze(0).unsqueeze(0), -10000.0) if token_valid is not None: scores = scores.masked_fill((~token_valid.bool()).unsqueeze(1).unsqueeze(2), -10000.0) if self.cfg.softpick_enabled: attn = softpick(scores, dim=-1, temperature=self.cfg.softpick_temperature).to(Q.dtype) else: scores = torch.nan_to_num(scores, nan=-1e4, posinf=1e4, neginf=-1e4) attn = F.softmax(scores, dim=-1).to(Q.dtype) context = torch.matmul(attn, V) return contextBase class for all neural network modules.
Your models should also subclass this class.
Modules can also contain other Modules, allowing them to be nested in a tree structure. You can assign the submodules as regular attributes::
import torch.nn as nn import torch.nn.functional as F class Model(nn.Module): def __init__(self) -> None: super().__init__() self.conv1 = nn.Conv2d(1, 20, 5) self.conv2 = nn.Conv2d(20, 20, 5) def forward(self, x): x = F.relu(self.conv1(x)) return F.relu(self.conv2(x))Submodules assigned in this way will be registered, and will also have their parameters converted when you call :meth:
to, etc.Note
As per the example above, an
__init__()call to the parent class must be made before assignment on the child.:ivar training: Boolean represents whether this module is in training or evaluation mode. :vartype training: bool
Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Methods
def forward(self,
Q: torch.Tensor,
K: torch.Tensor,
V: torch.Tensor,
token_valid: torch.Tensor | None = None,
seer_mask: torch.Tensor | None = None) ‑> torch.Tensor-
Expand source code
def forward( self, Q: torch.Tensor, K: torch.Tensor, V: torch.Tensor, token_valid: torch.Tensor | None = None, seer_mask: torch.Tensor | None = None, ) -> torch.Tensor: B, H, N, D = Q.shape bs = self.cfg.block_size nb = (N + bs - 1) // bs top_k = self.cfg.top_k_blocks scale = D**-0.5 if self.cfg.xattn_enabled: block_scores = self.xattn_scorer.score_blocks(Q, K, bs, self.cfg.xattn_stride) inter_mask = self._inter_block_topk(block_scores, top_k) else: inter_mask = torch.ones(B, H, nb, nb, device=Q.device, dtype=torch.bool) if seer_mask is not None: inter_mask = inter_mask | seer_mask inter_mask[:, :, :, 0] = True diag_idx = torch.arange(nb, device=Q.device) inter_mask[:, :, diag_idx, diag_idx] = True scores = torch.matmul(Q.float(), K.float().transpose(-2, -1).contiguous()) * scale expanded_mask = inter_mask.repeat_interleave(bs, dim=2).repeat_interleave(bs, dim=3)[ :, :, :N, :N ] scores = scores.masked_fill(~expanded_mask, -10000.0) if self.cfg.stripe_enabled and N > 256: sw = self.cfg.stripe_width idx = torch.arange(N, device=Q.device) stripe_group = idx // sw q_stripe = stripe_group.unsqueeze(1) k_stripe = stripe_group.unsqueeze(0) stripe_mask = (q_stripe - k_stripe).abs() <= 1 scores = scores.masked_fill(~stripe_mask.unsqueeze(0).unsqueeze(0), -10000.0) if self.is_decoder: causal = torch.tril(torch.ones(N, N, device=Q.device, dtype=torch.bool)) scores = scores.masked_fill(~causal.unsqueeze(0).unsqueeze(0), -10000.0) if token_valid is not None: scores = scores.masked_fill((~token_valid.bool()).unsqueeze(1).unsqueeze(2), -10000.0) if self.cfg.softpick_enabled: attn = softpick(scores, dim=-1, temperature=self.cfg.softpick_temperature).to(Q.dtype) else: scores = torch.nan_to_num(scores, nan=-1e4, posinf=1e4, neginf=-1e4) attn = F.softmax(scores, dim=-1).to(Q.dtype) context = torch.matmul(attn, V) return contextDefine the computation performed at every call.
Should be overridden by all subclasses.
Note
Although the recipe for forward pass needs to be defined within this function, one should call the :class:
Moduleinstance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.
class NEXUSAttention (config: Any | None = None,
model_config: Any | None = None,
nexus_cfg: NEXUSConfig | None = None,
layer_idx: int = 0,
total_layers: int = 6,
pretrained_attn: torch.nn.modules.module.Module | None = None,
bert_mode: bool = False,
lora_rank: int = 16,
lora_alpha: float = 32.0,
is_decoder: bool | None = None,
**kwargs: Any)-
Expand source code
@ATTENTION_REGISTRY.register("nexus", supports_causal=True, supports_gqa=True) @ATTENTION_REGISTRY.register("nexus_attention", supports_causal=True, supports_gqa=True) @ATTENTION_REGISTRY.register("NEXUSAttention", supports_causal=True, supports_gqa=True) class NEXUSAttention(BaseAttention): supports_causal: bool = True supports_gqa: bool = True is_custom_attention: bool = True def __init__( self, config: Any | None = None, model_config: Any | None = None, nexus_cfg: NEXUSConfig | None = None, layer_idx: int = 0, total_layers: int = 6, pretrained_attn: nn.Module | None = None, bert_mode: bool = False, lora_rank: int = 16, lora_alpha: float = 32.0, is_decoder: bool | None = None, **kwargs: Any, ) -> None: if model_config is None: model_config = config super().__init__(model_config) self.num_heads: int = getattr( model_config, "num_attention_heads", getattr(model_config, "num_heads", kwargs.get("num_attention_heads", 4)), ) self.hidden_size: int = getattr(model_config, "hidden_size", kwargs.get("hidden_size", 768)) cfg_head_dim = getattr(model_config, "head_dim", None) if model_config else None adapter_head_dim = ( getattr(getattr(model_config, "adapter", None), "head_dim", None) if model_config else None ) self.head_dim: int = int( cfg_head_dim or adapter_head_dim or kwargs.get("head_dim") or (self.hidden_size // self.num_heads if self.num_heads > 0 else 64) ) self.all_head_size: int = self.num_heads * self.head_dim cfg_kv = ( getattr( model_config, "num_key_value_heads", getattr(model_config, "num_kv_heads", None), ) if model_config else None ) if cfg_kv is not None: self.num_kv_heads = int(cfg_kv) elif kwargs.get("num_kv_heads") is not None: self.num_kv_heads = int(kwargs["num_kv_heads"]) else: self.num_kv_heads = self.num_heads self.num_kv_heads = max(1, min(self.num_kv_heads, self.num_heads)) self.kv_repeat: int = self.num_heads // self.num_kv_heads self.kv_head_size: int = self.num_kv_heads * self.head_dim self.cfg: NEXUSConfig = nexus_cfg if nexus_cfg is not None else NEXUSConfig() self.layer_idx: int = layer_idx self.bert_mode: bool = bert_mode self.lora_rank: int = lora_rank self.lora_alpha: float = lora_alpha if is_decoder is not None: self.is_decoder = bool(is_decoder) else: _mt = str(getattr(model_config, "model_type", "") or "").lower() if model_config else "" self.is_decoder = ( bool( getattr(model_config, "is_decoder", False) or getattr(model_config, "causal", False) ) or any( _mt.startswith(p) for p in ( "gpt", "qwen", "llama", "mistral", "falcon", "bloom", "opt", ) ) if model_config else False ) self.is_nested_encoder: bool = False src_p = next(pretrained_attn.parameters(), None) if pretrained_attn is not None else None target_dtype = kwargs.get("dtype", src_p.dtype if src_p is not None else torch.float32) target_device = kwargs.get("device", src_p.device if src_p is not None else None) self.query = LoRALinear( self.hidden_size, self.all_head_size, bias=True, lora_rank=self.lora_rank, lora_alpha=self.lora_alpha, freeze_base=True, device=target_device, dtype=target_dtype, ) self.key = LoRALinear( self.hidden_size, self.kv_head_size, bias=True, lora_rank=self.lora_rank, lora_alpha=self.lora_alpha, freeze_base=True, device=target_device, dtype=target_dtype, ) self.value = LoRALinear( self.hidden_size, self.kv_head_size, bias=True, lora_rank=self.lora_rank, lora_alpha=self.lora_alpha, freeze_base=True, device=target_device, dtype=target_dtype, ) self.out_proj = LoRALinear( self.all_head_size, self.hidden_size, bias=True, lora_rank=self.lora_rank, lora_alpha=self.lora_alpha, freeze_base=True, device=target_device, dtype=target_dtype, ) self.dropout = nn.Dropout(self.cfg.dropout) # NX-04: pass is_decoder into DSS self.dss_attn = DualStageStripeAttention( self.cfg, self.head_dim, num_heads=self.num_heads, is_decoder=self.is_decoder, is_nested_encoder=self.is_nested_encoder, ) self.seer_gate: SeerGating | None = None if self.cfg.seer_enabled: self.seer_gate = SeerGating( self.head_dim, self.num_heads, self.cfg.seer_gate_rank, self.cfg.seer_top_k_blocks, self.cfg.seer_temperature, ) self.rect_interval = self.cfg.rectify_interval self.is_rectify = ( (self.rect_interval > 0) and (layer_idx % self.rect_interval == 0) and ((pretrained_attn is None) or getattr(self.cfg, "enable_spectraformer", False)) ) if self.is_rectify: self.spec_rectify: SpectraformerRectify | None = SpectraformerRectify( self.head_dim, self.cfg.rff_features ) else: self.spec_rectify = None if pretrained_attn is not None: self.copy_weights(pretrained_attn) if target_device is not None and target_dtype is not None: self.to(device=target_device, dtype=target_dtype) elif target_device is not None: self.to(device=target_device) elif target_dtype is not None: self.to(target_dtype) @property def q_proj(self): return self.query @property def k_proj(self): return self.key @property def v_proj(self): return self.value @property def q_lin(self): return self.query @property def k_lin(self): return self.key @property def v_lin(self): return self.value @property def out_lin(self): return self.out_proj @property def dense(self): return self.out_proj @property def o_proj(self): return self.out_proj def _reshape(self, x: torch.Tensor, n_heads: int | None = None) -> torch.Tensor: B, N, _ = x.shape heads = n_heads if n_heads is not None else self.num_heads return x.view(B, N, heads, self.head_dim).transpose(1, 2).contiguous() # NX-05: robust valid-mask extraction def _get_token_valid_mask(self, mask, B, N, device): if mask is None: return None if mask.dim() == 2: if mask.dtype == torch.bool: return mask.to(device) if mask.dtype.is_floating_point: return (mask > -1e4).to(device) return (mask > 0).to(device) if mask.dim() == 3: if mask.dtype == torch.bool: v = mask elif mask.dtype.is_floating_point: v = mask > -1e4 else: v = mask > 0 return v.any(dim=1).to(device) if mask.dim() == 4: if mask.dtype == torch.bool: v = mask elif mask.dtype.is_floating_point: v = mask > -1e4 else: v = mask > 0 return v.any(dim=-2).squeeze(1).to(device) return torch.ones(B, N, device=device, dtype=torch.bool) def copy_weights(self, src: Any) -> None: from neuralops.core.adapters import UniversalAdapter extracted: dict[str, tuple[torch.Tensor | None, torch.Tensor | None]] = { "q": (None, None), "k": (None, None), "v": (None, None), "o": (None, None), } for proj in ["q", "k", "v", "o"]: try: w, b = UniversalAdapter.get_weight_bias(src, proj) if w is not None: extracted[proj] = (w, b) except Exception: pass if hasattr(src, "c_attn") and ( extracted["q"][0] is None or extracted["k"][0] is None or extracted["v"][0] is None ): weight = src.c_attn.weight.data bias = getattr(src.c_attn, "bias", None) bias_data = bias.data if bias is not None else None if weight.dim() == 2 and weight.shape[1] == 3 * self.hidden_size: weight = weight.t().contiguous() split_size = weight.shape[0] // 3 q_w = weight[:split_size, :] k_w = weight[split_size : 2 * split_size, :] v_w = weight[2 * split_size :, :] q_b = bias_data[:split_size] if bias_data is not None else None k_b = bias_data[split_size : 2 * split_size] if bias_data is not None else None v_b = bias_data[2 * split_size :] if bias_data is not None else None extracted["q"] = (q_w, q_b) extracted["k"] = (k_w, k_b) extracted["v"] = (v_w, v_b) if hasattr(src, "c_proj") and extracted["o"][0] is None: w_o = src.c_proj.weight.data if ( w_o.dim() == 2 and w_o.shape[0] != self.hidden_size and w_o.shape[1] == self.hidden_size ): w_o = w_o.t().contiguous() b_o = getattr(src.c_proj, "bias", None) extracted["o"] = (w_o, b_o.data if b_o is not None else None) if hasattr(src, "self") and ( extracted["q"][0] is None or extracted["k"][0] is None or extracted["v"][0] is None ): s = src.self if hasattr(s, "query"): extracted["q"] = (s.query.weight.data, getattr(s.query, "bias", None)) if hasattr(s, "key"): extracted["k"] = (s.key.weight.data, getattr(s.key, "bias", None)) if hasattr(s, "value"): extracted["v"] = (s.value.weight.data, getattr(s.value, "bias", None)) if hasattr(src, "output") and hasattr(src.output, "dense") and extracted["o"][0] is None: dense = src.output.dense extracted["o"] = (dense.weight.data, getattr(dense, "bias", None)) named_map = { "q": ["q_proj", "q_lin", "query"], "k": ["k_proj", "k_lin", "key"], "v": ["v_proj", "v_lin", "value"], "o": ["o_proj", "out_proj", "out_lin", "dense"], } for proj, names in named_map.items(): if extracted[proj][0] is None: for name in names: if hasattr(src, name): layer = getattr(src, name) if hasattr(layer, "weight"): extracted[proj] = ( layer.weight.data, getattr(layer, "bias", None), ) break cls_name = src.__class__.__name__ has_out_proj = any( hasattr(src, attr) for attr in ( "dense", "out_proj", "c_proj", "out_lin", "o_proj", "wo", "o", "proj", ) ) is_nested = False if ( hasattr(src, "self") and hasattr(src.self, "query") or ( cls_name in ( "BertSelfAttention", "RobertaSelfAttention", "XLMRobertaSelfAttention", ) or (cls_name.endswith("SelfAttention") and not has_out_proj) ) and not has_out_proj ): is_nested = True self.is_nested_encoder = bool(is_nested) # NX-09: propagate to DSS if hasattr(self, "dss_attn"): self.dss_attn.is_nested_encoder = self.is_nested_encoder missing = [k for k in ["q", "k", "v"] if extracted[k][0] is None] if not self.is_nested_encoder and extracted["o"][0] is None: missing.append("o") if missing: logger.warning("Module copy_weights warning. Proceeding with initialized weights.") for proj_key in ["q", "k", "v"]: w = extracted[proj_key][0] if w is not None: norm = torch.linalg.norm(w.float()) if norm < 1e-4: logger.warning(f"NEXUSAttention extracted weight for {proj_key} near-zero norm") if extracted["o"][0] is not None: norm_o = torch.linalg.norm(extracted["o"][0].float()) if norm_o < 1e-4: logger.warning("NEXUSAttention output weight near-zero norm") def _orient(w: torch.Tensor, in_dim: int) -> torch.Tensor: if w.dim() == 2 and w.shape[1] != in_dim and w.shape[0] == in_dim: return w.t().contiguous() return w with torch.no_grad(): for proj_key, target in [ ("q", self.query), ("k", self.key), ("v", self.value), ("o", self.out_proj), ]: w, b = extracted[proj_key] if w is not None: in_dim = self.all_head_size if proj_key == "o" else self.hidden_size w_oriented = _orient(w, in_dim) target_w = target.weight out_d, in_d = target_w.shape src_out, src_in = w_oriented.shape if proj_key in ("k", "v"): if src_out == out_d: target_w.data.copy_(w_oriented) if b is not None and target.bias is not None: target.bias.data.copy_(b) elif src_out > out_d and src_out % out_d == 0: rep = src_out // out_d target_w.data.copy_(w_oriented.view(out_d, rep, -1).mean(dim=1)) if b is not None and target.bias is not None: target.bias.data.copy_(b.view(out_d, rep).mean(dim=1)) elif src_out < out_d and out_d % src_out == 0: rep = out_d // src_out target_w.data.copy_(w_oriented.repeat(rep, 1)) if b is not None and target.bias is not None: target.bias.data.copy_(b.repeat(rep)) else: target_w.data.zero_() target_w.data[: min(out_d, src_out), : min(in_d, src_in)].copy_( w_oriented[: min(out_d, src_out), : min(in_d, src_in)] ) if b is not None and target.bias is not None: target.bias.data.zero_() target.bias.data[: min(len(target.bias), len(b))].copy_( b[: min(len(target.bias), len(b))] ) else: target_w.data.zero_() target_w.data[: min(out_d, src_out), : min(in_d, src_in)].copy_( w_oriented[: min(out_d, src_out), : min(in_d, src_in)] ) if b is not None and target.bias is not None: b_val = b.data if isinstance(b, nn.Parameter) else b target.bias.data.zero_() target.bias.data[: min(len(target.bias), len(b_val))].copy_( b_val[: min(len(target.bias), len(b_val))] ) elif proj_key == "o" and self.is_nested_encoder: min_d = min(target.weight.shape[0], target.weight.shape[1]) target.weight.data.zero_() target.weight.data[:min_d, :min_d].fill_diagonal_(1.0) if target.bias is not None: target.bias.data.zero_() target.freeze_base_weights() if hasattr(src, "is_decoder"): self.is_decoder = bool(src.is_decoder) if hasattr(self, "dss_attn"): self.dss_attn.is_decoder = self.is_decoder def forward( self, hidden_states: torch.Tensor, attention_mask: torch.Tensor | None = None, head_mask: torch.Tensor | None = None, encoder_hidden_states: torch.Tensor | None = None, encoder_attention_mask: torch.Tensor | None = None, past_key_value: Any | None = None, output_attentions: bool | None = False, output_hidden_states: bool | None = False, return_dict: bool | None = True, position_embeddings: tuple[torch.Tensor, torch.Tensor] | None = None, layer_idx: int = 0, *args: Any, **kwargs: Any, ) -> tuple[torch.Tensor, torch.Tensor | None]: B, N, _ = hidden_states.shape H, D = self.num_heads, self.head_dim device = hidden_states.device dtype = hidden_states.dtype is_cross = encoder_hidden_states is not None kv_input = encoder_hidden_states if is_cross else hidden_states N_kv = kv_input.shape[1] Q = self._reshape(self.query(hidden_states), self.num_heads) K = self._reshape(self.key(kv_input), self.num_kv_heads) V = self._reshape(self.value(kv_input), self.num_kv_heads) # NX-08: RoPE with past_len offset if position_embeddings is None: position_embeddings = kwargs.get("position_embeddings") if position_embeddings is not None and not is_cross: cos, sin = position_embeddings past_len = 0 if past_key_value is not None: if isinstance(past_key_value, (tuple, list)) and len(past_key_value) >= 1: past_len = past_key_value[0].shape[-2] elif hasattr(past_key_value, "key_cache") and past_key_value.key_cache: past_len = past_key_value.key_cache[0].shape[-2] cos = cos[..., past_len : past_len + N, :] sin = sin[..., past_len : past_len + N, :] Q, K = apply_rotary_pos_emb(Q, K, cos, sin) if self.num_kv_heads < self.num_heads: K = repeat_kv(K, self.kv_repeat) V = repeat_kv(V, self.kv_repeat) eff_mask = encoder_attention_mask if is_cross else attention_mask if eff_mask is None: eff_mask = kwargs.get("attn_mask") token_valid = self._get_token_valid_mask(eff_mask, B, N_kv, device) is_causal = bool(self.is_decoder and not is_cross) min_seq_len = getattr(self.cfg, "sparse_min_seq_len", 8) use_dense = is_causal or is_cross or (min_seq_len >= N) or (self.dss_attn is None) if use_dense: scale = 1.0 / math.sqrt(D) scores = torch.matmul(Q.float(), K.float().transpose(-2, -1).contiguous()) * scale if is_causal: causal_diag = 1 + max(0, N_kv - N) causal_mask = ( torch.triu( torch.full((N, N_kv), float("-inf"), device=device, dtype=torch.float32), diagonal=causal_diag, ) .unsqueeze(0) .unsqueeze(0) ) scores = scores + causal_mask if eff_mask is not None: if eff_mask.dim() == 2: scores = scores + (eff_mask.unsqueeze(1).unsqueeze(2).float() - 1.0) * 10000.0 elif eff_mask.dim() == 3: scores = scores + eff_mask.unsqueeze(1).float() elif eff_mask.dim() == 4: scores = scores + eff_mask.float() scores = torch.nan_to_num(scores, nan=-1e4, posinf=1e4, neginf=-1e4) attn_weights = F.softmax(scores, dim=-1).to(dtype) attn_weights = self.dropout(attn_weights) if head_mask is not None: if head_mask.dim() == 1: head_mask = head_mask.view(1, -1, 1, 1) elif head_mask.dim() == 2: head_mask = head_mask.unsqueeze(-1).unsqueeze(-1) elif head_mask.dim() == 3: head_mask = head_mask[:, :, :1].unsqueeze(-1) attn_weights = attn_weights * head_mask context = torch.matmul(attn_weights, V) else: if self.is_rectify and self.spec_rectify is not None: context = self.spec_rectify(Q, K, V) else: seer_mask = None if self.seer_gate is not None: bs = self.cfg.block_size nb = (N + bs - 1) // bs seer_mask = self.seer_gate(Q, K, nb, training=self.training) context = self.dss_attn(Q, K, V, token_valid, seer_mask=seer_mask) if token_valid is not None: context = context * token_valid.unsqueeze(1).unsqueeze(-1).to(context.dtype) context = context.transpose(1, 2).contiguous().view(B, N, H * D) context = torch.nan_to_num(context, nan=0.0, posinf=1e4, neginf=-1e4) if self.is_nested_encoder: output = context else: output = self.out_proj(self.dropout(context)) return (output, None) def get_ortho_loss(self) -> torch.Tensor: return torch.tensor(0.0, device=self.query.weight.device)Every custom attention module must inherit from this.
Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- BaseAttention
- torch.nn.modules.module.Module
Class variables
var is_custom_attention : bool-
The type of the None singleton.
var supports_causal : bool-
The type of the None singleton.
var supports_gqa : bool-
The type of the None singleton.
Instance variables
prop dense-
Expand source code
@property def dense(self): return self.out_proj prop k_lin-
Expand source code
@property def k_lin(self): return self.key prop k_proj-
Expand source code
@property def k_proj(self): return self.key prop o_proj-
Expand source code
@property def o_proj(self): return self.out_proj prop out_lin-
Expand source code
@property def out_lin(self): return self.out_proj prop q_lin-
Expand source code
@property def q_lin(self): return self.query prop q_proj-
Expand source code
@property def q_proj(self): return self.query prop v_lin-
Expand source code
@property def v_lin(self): return self.value prop v_proj-
Expand source code
@property def v_proj(self): return self.value
Methods
def get_ortho_loss(self) ‑> torch.Tensor-
Expand source code
def get_ortho_loss(self) -> torch.Tensor: return torch.tensor(0.0, device=self.query.weight.device)
Inherited members
class NEXUSConfig (block_size: int = 16,
top_k_blocks: int = 4,
xattn_enabled: bool = True,
xattn_stride: int = 2,
seer_enabled: bool = True,
seer_gate_rank: int = 16,
seer_top_k_blocks: int = 4,
seer_temperature: float = 1.0,
dual_stage_enabled: bool = True,
intra_block_full: bool = True,
stripe_enabled: bool = True,
stripe_width: int = 4,
rectify_interval: int = 4,
rff_features: int = 128,
softpick_enabled: bool = True,
softpick_temperature: float = 1.0,
sparse_min_seq_len: int = 8,
enable_spectraformer: bool = False,
dropout: float = 0.1)-
Expand source code
@dataclass class NEXUSConfig: block_size: int = 16 top_k_blocks: int = 4 xattn_enabled: bool = True xattn_stride: int = 2 seer_enabled: bool = True seer_gate_rank: int = 16 seer_top_k_blocks: int = 4 seer_temperature: float = 1.0 dual_stage_enabled: bool = True intra_block_full: bool = True stripe_enabled: bool = True stripe_width: int = 4 rectify_interval: int = 4 rff_features: int = 128 softpick_enabled: bool = True softpick_temperature: float = 1.0 sparse_min_seq_len: int = 8 enable_spectraformer: bool = False dropout: float = 0.1NEXUSConfig(block_size: int = 16, top_k_blocks: int = 4, xattn_enabled: bool = True, xattn_stride: int = 2, seer_enabled: bool = True, seer_gate_rank: int = 16, seer_top_k_blocks: int = 4, seer_temperature: float = 1.0, dual_stage_enabled: bool = True, intra_block_full: bool = True, stripe_enabled: bool = True, stripe_width: int = 4, rectify_interval: int = 4, rff_features: int = 128, softpick_enabled: bool = True, softpick_temperature: float = 1.0, sparse_min_seq_len: int = 8, enable_spectraformer: bool = False, dropout: float = 0.1)
Instance variables
var block_size : int-
The type of the None singleton.
var dropout : float-
The type of the None singleton.
var dual_stage_enabled : bool-
The type of the None singleton.
var enable_spectraformer : bool-
The type of the None singleton.
var intra_block_full : bool-
The type of the None singleton.
var rectify_interval : int-
The type of the None singleton.
var rff_features : int-
The type of the None singleton.
var seer_enabled : bool-
The type of the None singleton.
var seer_gate_rank : int-
The type of the None singleton.
var seer_temperature : float-
The type of the None singleton.
var seer_top_k_blocks : int-
The type of the None singleton.
var softpick_enabled : bool-
The type of the None singleton.
var softpick_temperature : float-
The type of the None singleton.
var sparse_min_seq_len : int-
The type of the None singleton.
var stripe_enabled : bool-
The type of the None singleton.
var stripe_width : int-
The type of the None singleton.
var top_k_blocks : int-
The type of the None singleton.
var xattn_enabled : bool-
The type of the None singleton.
var xattn_stride : int-
The type of the None singleton.
class SeerGating (head_dim: int,
num_heads: int,
gate_rank: int,
top_k: int,
temperature: float = 1.0,
**kwargs)-
Expand source code
class SeerGating(nn.Module): def __init__( self, head_dim: int, num_heads: int, gate_rank: int, top_k: int, temperature: float = 1.0, **kwargs, ) -> None: super().__init__() self.num_heads = num_heads self.head_dim = head_dim self.top_k = top_k self.temperature = temperature self.q_pool = nn.Sequential( nn.Linear(head_dim, gate_rank), nn.GELU(), nn.Linear(gate_rank, gate_rank), ) self.k_pool = nn.Sequential( nn.Linear(head_dim, gate_rank), nn.GELU(), nn.Linear(gate_rank, gate_rank), ) def forward( self, Q: torch.Tensor, K: torch.Tensor, n_blocks: int, training: bool = True ) -> torch.Tensor: B, H, N, D = Q.shape gr = self.q_pool[0].out_features Q_pooled = Q.mean(dim=2) K_pooled = K.mean(dim=2) q_gate = self.q_pool(Q_pooled).view(B, H, 1, gr) k_gate = self.k_pool(K_pooled).view(B, H, gr, 1) gate_score = torch.sigmoid( torch.matmul(q_gate, k_gate).squeeze(-1).squeeze(-1) / self.temperature ) keep_per_head = torch.clamp((gate_score * n_blocks).long(), min=1, max=n_blocks) mask = torch.zeros(B, H, n_blocks, n_blocks, device=Q.device, dtype=torch.bool) diag_idx = torch.arange(n_blocks, device=Q.device) mask[:, :, diag_idx, diag_idx] = True mask[:, :, :, 0] = True for b in range(B): for h in range(H): k_keep = keep_per_head[b, h].item() if k_keep > 1 and n_blocks > 2: extra_needed = min(k_keep - 1, n_blocks - 1) if extra_needed > 0: mask[b, h, :, 1 : 1 + extra_needed] = True return maskBase class for all neural network modules.
Your models should also subclass this class.
Modules can also contain other Modules, allowing them to be nested in a tree structure. You can assign the submodules as regular attributes::
import torch.nn as nn import torch.nn.functional as F class Model(nn.Module): def __init__(self) -> None: super().__init__() self.conv1 = nn.Conv2d(1, 20, 5) self.conv2 = nn.Conv2d(20, 20, 5) def forward(self, x): x = F.relu(self.conv1(x)) return F.relu(self.conv2(x))Submodules assigned in this way will be registered, and will also have their parameters converted when you call :meth:
to, etc.Note
As per the example above, an
__init__()call to the parent class must be made before assignment on the child.:ivar training: Boolean represents whether this module is in training or evaluation mode. :vartype training: bool
Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Methods
def forward(self, Q: torch.Tensor, K: torch.Tensor, n_blocks: int, training: bool = True) ‑> torch.Tensor-
Expand source code
def forward( self, Q: torch.Tensor, K: torch.Tensor, n_blocks: int, training: bool = True ) -> torch.Tensor: B, H, N, D = Q.shape gr = self.q_pool[0].out_features Q_pooled = Q.mean(dim=2) K_pooled = K.mean(dim=2) q_gate = self.q_pool(Q_pooled).view(B, H, 1, gr) k_gate = self.k_pool(K_pooled).view(B, H, gr, 1) gate_score = torch.sigmoid( torch.matmul(q_gate, k_gate).squeeze(-1).squeeze(-1) / self.temperature ) keep_per_head = torch.clamp((gate_score * n_blocks).long(), min=1, max=n_blocks) mask = torch.zeros(B, H, n_blocks, n_blocks, device=Q.device, dtype=torch.bool) diag_idx = torch.arange(n_blocks, device=Q.device) mask[:, :, diag_idx, diag_idx] = True mask[:, :, :, 0] = True for b in range(B): for h in range(H): k_keep = keep_per_head[b, h].item() if k_keep > 1 and n_blocks > 2: extra_needed = min(k_keep - 1, n_blocks - 1) if extra_needed > 0: mask[b, h, :, 1 : 1 + extra_needed] = True return maskDefine the computation performed at every call.
Should be overridden by all subclasses.
Note
Although the recipe for forward pass needs to be defined within this function, one should call the :class:
Moduleinstance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.
class SpectraformerRectify (head_dim: int, rff_features: int = 128, **kwargs)-
Expand source code
class SpectraformerRectify(nn.Module): def __init__(self, head_dim: int, rff_features: int = 128, **kwargs) -> None: super().__init__() self.rff_features = rff_features proj_init = torch.randn(head_dim, rff_features) if head_dim <= rff_features: proj_q, _ = torch.linalg.qr(proj_init.T) proj_init = proj_q.T else: proj_q, _ = torch.linalg.qr(proj_init) proj_init = proj_q self.proj = nn.Parameter(proj_init / math.sqrt(head_dim)) def forward(self, Q: torch.Tensor, K: torch.Tensor, V: torch.Tensor) -> torch.Tensor: B, H, N, D = Q.shape F_dim = self.rff_features orig_dtype = Q.dtype Q, K, V = Q.float(), K.float(), V.float() proj = self.proj.to(Q.device).float() Q_proj = torch.matmul(F.normalize(Q, p=2, dim=-1), proj).clamp(max=11.0) K_proj = torch.matmul(F.normalize(K, p=2, dim=-1), proj).clamp(max=11.0) Q_feat = torch.exp(Q_proj) / math.sqrt(F_dim) K_feat = torch.exp(K_proj) / math.sqrt(F_dim) KV = torch.einsum("bhnf,bhnd->bhfd", K_feat, V) Z = K_feat.sum(dim=2) ctx = torch.einsum("bhnf,bhfd->bhnd", Q_feat, KV) norm = torch.einsum("bhnf,bhf->bhn", Q_feat, Z).unsqueeze(-1) # NX-03: clamp norm, not (norm + eps) return (ctx / norm.clamp(min=1e-5)).to(orig_dtype)Base class for all neural network modules.
Your models should also subclass this class.
Modules can also contain other Modules, allowing them to be nested in a tree structure. You can assign the submodules as regular attributes::
import torch.nn as nn import torch.nn.functional as F class Model(nn.Module): def __init__(self) -> None: super().__init__() self.conv1 = nn.Conv2d(1, 20, 5) self.conv2 = nn.Conv2d(20, 20, 5) def forward(self, x): x = F.relu(self.conv1(x)) return F.relu(self.conv2(x))Submodules assigned in this way will be registered, and will also have their parameters converted when you call :meth:
to, etc.Note
As per the example above, an
__init__()call to the parent class must be made before assignment on the child.:ivar training: Boolean represents whether this module is in training or evaluation mode. :vartype training: bool
Initialize internal Module state, shared by both nn.Module and ScriptModule.
Ancestors
- torch.nn.modules.module.Module
Methods
def forward(self, Q: torch.Tensor, K: torch.Tensor, V: torch.Tensor) ‑> torch.Tensor-
Expand source code
def forward(self, Q: torch.Tensor, K: torch.Tensor, V: torch.Tensor) -> torch.Tensor: B, H, N, D = Q.shape F_dim = self.rff_features orig_dtype = Q.dtype Q, K, V = Q.float(), K.float(), V.float() proj = self.proj.to(Q.device).float() Q_proj = torch.matmul(F.normalize(Q, p=2, dim=-1), proj).clamp(max=11.0) K_proj = torch.matmul(F.normalize(K, p=2, dim=-1), proj).clamp(max=11.0) Q_feat = torch.exp(Q_proj) / math.sqrt(F_dim) K_feat = torch.exp(K_proj) / math.sqrt(F_dim) KV = torch.einsum("bhnf,bhnd->bhfd", K_feat, V) Z = K_feat.sum(dim=2) ctx = torch.einsum("bhnf,bhfd->bhnd", Q_feat, KV) norm = torch.einsum("bhnf,bhf->bhn", Q_feat, Z).unsqueeze(-1) # NX-03: clamp norm, not (norm + eps) return (ctx / norm.clamp(min=1e-5)).to(orig_dtype)Define the computation performed at every call.
Should be overridden by all subclasses.
Note
Although the recipe for forward pass needs to be defined within this function, one should call the :class:
Moduleinstance afterwards instead of this since the former takes care of running the registered hooks while the latter silently ignores them.
class XAttentionScorer-
Expand source code
class XAttentionScorer: @staticmethod def score_blocks( Q: torch.Tensor, K: torch.Tensor, block_size: int, stride: int = 2 ) -> torch.Tensor: B, H, N, D = Q.shape n_blocks = (N + block_size - 1) // block_size Q_sample = Q[:, :, ::stride, :] K_sample = K[:, :, ::stride, :] N_s = Q_sample.size(2) scale = D**-0.5 attn_sample = torch.matmul(Q_sample, K_sample.transpose(-2, -1).contiguous()) * scale b_s = max(1, block_size // stride) target = n_blocks * b_s if N_s < target: pad = target - N_s attn_sample = F.pad(attn_sample, (0, pad, 0, pad), value=0.0) attn_sample = attn_sample[:, :, :target, :target] attn_blocks = attn_sample.view(B, H, n_blocks, b_s, n_blocks, b_s) scores = attn_blocks.mean(dim=(3, 5)) return scoresStatic methods
def score_blocks(Q: torch.Tensor, K: torch.Tensor, block_size: int, stride: int = 2) ‑> torch.Tensor-
Expand source code
@staticmethod def score_blocks( Q: torch.Tensor, K: torch.Tensor, block_size: int, stride: int = 2 ) -> torch.Tensor: B, H, N, D = Q.shape n_blocks = (N + block_size - 1) // block_size Q_sample = Q[:, :, ::stride, :] K_sample = K[:, :, ::stride, :] N_s = Q_sample.size(2) scale = D**-0.5 attn_sample = torch.matmul(Q_sample, K_sample.transpose(-2, -1).contiguous()) * scale b_s = max(1, block_size // stride) target = n_blocks * b_s if N_s < target: pad = target - N_s attn_sample = F.pad(attn_sample, (0, pad, 0, pad), value=0.0) attn_sample = attn_sample[:, :, :target, :target] attn_blocks = attn_sample.view(B, H, n_blocks, b_s, n_blocks, b_s) scores = attn_blocks.mean(dim=(3, 5)) return scores