| |
|
|
| from __future__ import annotations |
|
|
| import warnings |
| from typing import TYPE_CHECKING |
|
|
| import torch |
| import torch.nn as nn |
| import torch.nn.functional as F |
| import torch.utils.checkpoint |
| from einops import rearrange, repeat |
| from transformers.utils import logging |
|
|
| from fla.layers.utils import get_unpad_data, index_first_axis, pad_input, unpad_input |
| from fla.modules import RMSNorm, RotaryEmbedding, ShortConvolution |
| from fla.modules.layernorm_gated import RMSNormGated |
| from fla.ops.gla import chunk_gla, fused_chunk_gla, fused_recurrent_gla |
|
|
| if TYPE_CHECKING: |
| from transformers.processing_utils import Unpack |
|
|
| from fla.models.utils import Cache |
|
|
| try: |
| from flash_attn import flash_attn_func, flash_attn_varlen_func |
| except ImportError: |
| warnings.warn( |
| "Flash Attention is not installed. Please install it via `pip install flash-attn --no-build-isolation`", |
| category=ImportWarning, |
| ) |
| flash_attn_func = None |
|
|
| logger = logging.get_logger(__name__) |
|
|
|
|
| def align_multiple(value, multiple_size=8): |
| if value % multiple_size != 0: |
| value += multiple_size - (value % multiple_size) |
| return value |
|
|
|
|
| def autocast_to_fp16(x): |
| if x.dtype not in {torch.float16, torch.bfloat16}: |
| return x.to(dtype=torch.bfloat16) |
| else: |
| return x |
|
|
|
|
| class RodimusAttention(nn.Module): |
| def __init__( |
| self, |
| block_type: str = 'rodimus', |
| mode: str = 'chunk', |
| hidden_size: int = 1024, |
| input_gate_low_rank: float | str | None = 'auto', |
| expand_ratio: int = 64, |
| use_short_conv: bool = True, |
| conv_size: int = 4, |
| conv_bias: bool = True, |
| norm_eps: float = 1e-5, |
| k_norm_eps: float | None = None, |
| residual_in_fp32: bool = True, |
| layer_idx: int = None, |
| ): |
| super().__init__() |
|
|
| self.block_type = block_type |
| self.mode = mode |
| self.hidden_size = hidden_size |
| self.d_inner = align_multiple(int(self.hidden_size * 2), 8) |
|
|
| self.expand_ratio = expand_ratio |
| self.input_gate_low_rank = max(self.hidden_size // 64, 16) if input_gate_low_rank == "auto" else input_gate_low_rank |
|
|
| self.use_short_conv = use_short_conv |
| self.conv_size = conv_size |
| self.conv_bias = conv_bias |
|
|
| self.norm_eps = norm_eps |
| self.k_norm_eps = k_norm_eps if k_norm_eps is not None else 1e-12 |
| self.mem_size = expand_ratio |
|
|
| self.residual_in_fp32 = residual_in_fp32 |
| self.layer_idx = layer_idx |
|
|
| assert mode in ['chunk', 'fused_recurrent', 'fused_chunk'], f"Not supported mode `{mode}`." |
|
|
| self.gate_proj = nn.Linear(self.hidden_size, self.d_inner, bias=False) |
| self.up_proj = nn.Linear(self.hidden_size, self.d_inner, bias=False) |
| self.activation_norm = RMSNormGated(hidden_size=self.d_inner, eps=norm_eps, norm_before_gate=False) |
| self.down_proj = nn.Linear(self.d_inner, self.hidden_size, bias=False) |
|
|
| if use_short_conv: |
| self.short_conv = ShortConvolution( |
| hidden_size=self.d_inner, |
| kernel_size=conv_size, |
| bias=conv_bias, |
| activation='silu', |
| ) |
|
|
| self.residual_weight = nn.Parameter(torch.ones( |
| (self.d_inner, ), dtype=torch.float32 if self.residual_in_fp32 else None), requires_grad=True) |
|
|
| self.k_proj = nn.Linear(self.d_inner, self.mem_size, bias=False) |
| self.q_proj = nn.Linear(self.d_inner, self.mem_size, bias=False) |
|
|
| self.g_gate_proj = nn.Linear(self.d_inner, self.mem_size, bias=True) |
| self.tau_gate_proj = nn.Linear(self.d_inner, self.mem_size, bias=True) |
| self.i_gate_proj = nn.Sequential( |
| nn.Linear(self.d_inner, self.input_gate_low_rank, bias=False), |
| nn.Linear(self.input_gate_low_rank, self.d_inner, bias=True), |
| nn.Sigmoid(), |
| ) |
|
|
| def forward( |
| self, |
| hidden_states: torch.Tensor, |
| attention_mask: torch.Tensor | None = None, |
| past_key_values: Cache | None = None, |
| use_cache: bool | None = False, |
| output_attentions: bool | None = False, |
| **kwargs: Unpack[dict], |
| ) -> tuple[torch.Tensor, torch.Tensor | None, Cache | None]: |
| if attention_mask is not None: |
| assert len(attention_mask.shape) == 2, ( |
| "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] " |
| "for padding purposes (0 indicating padding). " |
| "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed." |
| ) |
|
|
| batch_size, q_len, _ = hidden_states.shape |
| |
| mode = 'fused_recurrent' if hidden_states.shape[1] == 1 else self.mode |
|
|
| last_state = None |
| if past_key_values is not None and len(past_key_values) > self.layer_idx: |
| last_state = past_key_values[self.layer_idx] |
|
|
| cu_seqlens = kwargs.get('cu_seqlens') |
| if attention_mask is not None: |
| indices, cu_seqlens, _ = get_unpad_data(attention_mask[:, -q_len:]) |
| hidden_states = index_first_axis(rearrange(hidden_states, "b s ... -> (b s) ..."), indices).unsqueeze(0) |
|
|
| hidden_states, final_gate = self.up_proj(hidden_states), self.gate_proj(hidden_states) |
|
|
| if self.use_short_conv: |
| conv_state = None |
| if last_state is not None: |
| conv_state = last_state['conv_state'] |
| shift_hidden_states, conv_state = self.short_conv( |
| x=hidden_states, |
| cache=conv_state, |
| output_final_state=use_cache, |
| cu_seqlens=cu_seqlens, |
| ) |
| else: |
| shift_hidden_states = hidden_states |
|
|
| q = self.q_proj(shift_hidden_states) |
| k = self.k_proj(shift_hidden_states) |
| v = self.i_gate_proj(hidden_states) * hidden_states |
|
|
| g_gate = F.linear(shift_hidden_states, self.g_gate_proj.weight) + self.g_gate_proj.bias.float() |
| tau_gate = F.linear(shift_hidden_states, self.tau_gate_proj.weight) + self.tau_gate_proj.bias.float() |
|
|
| g_gate = F.softplus(g_gate) |
| it_gate = g_gate |
| rt_gate_log = -g_gate |
|
|
| tau_gate = F.sigmoid(tau_gate) |
| it_gate = it_gate ** tau_gate |
| rt_gate_log = rt_gate_log * tau_gate |
|
|
| k = F.normalize(k.float(), dim=-1, eps=self.k_norm_eps) * it_gate |
| q, k, v, rt_gate_log = map(lambda x: x.unsqueeze(1).transpose(1, 2), (q, k, v, rt_gate_log)) |
|
|
| recurrent_state = last_state['recurrent_state'] if last_state is not None else None |
| if mode == 'fused_recurrent': |
| o, recurrent_state = fused_recurrent_gla( |
| q=q, |
| k=k, |
| v=v, |
| gk=rt_gate_log, |
| initial_state=recurrent_state, |
| output_final_state=use_cache, |
| cu_seqlens=cu_seqlens, |
| head_first=False, |
| ) |
| elif mode == 'fused_chunk': |
| o, recurrent_state = fused_chunk_gla( |
| q=q, |
| k=k, |
| v=v, |
| g=rt_gate_log, |
| initial_state=recurrent_state, |
| output_final_state=use_cache, |
| head_first=False, |
| ) |
| elif mode == 'chunk': |
| q, k, rt_gate_log = map(lambda x: x.to(v.dtype), (q, k, rt_gate_log)) |
| o, recurrent_state = chunk_gla( |
| q=q, |
| k=k, |
| v=v, |
| g=rt_gate_log, |
| initial_state=recurrent_state, |
| output_final_state=use_cache, |
| cu_seqlens=cu_seqlens, |
| head_first=False, |
| ) |
| else: |
| raise NotImplementedError(f"Not supported mode `{mode}`.") |
|
|
| rodimus_caches = None |
| if past_key_values is not None: |
| if self.block_type == 'rodimus': |
| past_key_values.update( |
| recurrent_state=recurrent_state, |
| conv_state=conv_state if self.use_short_conv else None, |
| layer_idx=self.layer_idx, |
| offset=q_len, |
| ) |
| else: |
| rodimus_caches = (recurrent_state, conv_state if self.use_short_conv else None) |
|
|
| o = (o.transpose(1, 2).squeeze(1) + (shift_hidden_states.float() |
| if self.residual_in_fp32 else shift_hidden_states) * self.residual_weight).to(o.dtype) |
|
|
| o = self.activation_norm(o, final_gate) |
| o = self.down_proj(o) |
|
|
| if attention_mask is not None: |
| o = pad_input(o.squeeze(0), indices, batch_size, q_len) |
|
|
| if self.block_type == 'rodimus': |
| return o, None, past_key_values |
| else: |
| return o, None, (past_key_values, rodimus_caches) |
|
|
|
|
| class SlidingWindowSharedKeyAttention(nn.Module): |
| def __init__( |
| self, |
| hidden_size: int = 2048, |
| num_heads: int = 32, |
| qkv_bias: bool = False, |
| qk_norm: bool = False, |
| window_size: int = 2048, |
| rope_theta: float | None = 10000., |
| max_position_embeddings: int | None = None, |
| layer_idx: int = None, |
| ): |
| super().__init__() |
|
|
| self.hidden_size = hidden_size |
| self.num_heads = num_heads |
| self.head_dim = self.hidden_size // self.num_heads |
| self.qkv_bias = qkv_bias |
| self.qk_norm = qk_norm |
|
|
| self.window_size = window_size |
| self.rope_theta = rope_theta |
| self.max_position_embeddings = max_position_embeddings |
| self.layer_idx = layer_idx |
|
|
| self.q_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=self.qkv_bias) |
| self.k_proj = nn.Linear(self.hidden_size, self.head_dim, bias=self.qkv_bias) |
| self.v_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=self.qkv_bias) |
| self.o_proj = nn.Linear(self.hidden_size, self.hidden_size, bias=False) |
|
|
| if qk_norm: |
| self.q_norm = RMSNorm(self.head_dim) |
| self.k_norm = RMSNorm(self.head_dim) |
|
|
| self.rotary = RotaryEmbedding(dim=self.head_dim, base=self.rope_theta) |
|
|
| def forward( |
| self, |
| hidden_states: torch.Tensor, |
| attention_mask: torch.LongTensor | None = None, |
| past_key_values: Cache | None = None, |
| output_attentions: bool = False, |
| use_cache: bool = False, |
| **kwargs, |
| ) -> tuple[torch.Tensor, torch.Tensor | None, tuple[torch.Tensor] | None]: |
| rodimus_caches = kwargs.get('rodimus_caches') |
|
|
| if attention_mask is not None: |
| assert len(attention_mask.shape) == 2, ( |
| "Expected attention_mask as a 0-1 matrix with shape [batch_size, seq_len] " |
| "for padding purposes (0 indicating padding). " |
| "Arbitrary attention masks of shape [batch_size, seq_len, seq_len] are not allowed." |
| ) |
|
|
| batch_size, q_len, _ = hidden_states.size() |
|
|
| q = rearrange(self.q_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim) |
| k = rearrange(self.k_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim) |
| v = rearrange(self.v_proj(hidden_states), '... (h d) -> ... h d', d=self.head_dim) |
|
|
| if self.qk_norm: |
| q, k = self.q_norm(q), self.k_norm(k) |
|
|
| |
| cu_seqlens = kwargs.get('cu_seqlens') |
|
|
| seqlen_offset, max_seqlen = 0, q.shape[1] |
| if past_key_values is not None: |
| seqlen_offset = past_key_values.get_seq_length(self.layer_idx) |
| max_seqlen = q.shape[1] + seqlen_offset |
|
|
| if attention_mask is not None: |
| |
| seqlen_offset = seqlen_offset + attention_mask.sum(-1) - attention_mask.shape[-1] |
| max_seqlen = q.shape[1] + max(seqlen_offset) |
|
|
| if self.max_position_embeddings is not None: |
| max_seqlen = max(max_seqlen, self.max_position_embeddings) |
| q, k = self.rotary(q, k, seqlen_offset=seqlen_offset, max_seqlen=max_seqlen, cu_seqlens=cu_seqlens) |
|
|
| if past_key_values is not None: |
| if rodimus_caches is not None: |
| recurrent_state, conv_state = rodimus_caches |
| else: |
| recurrent_state, conv_state = None, None |
|
|
| cache_has_content = past_key_values.get_seq_length(self.layer_idx) > 0 |
| k_cached, v_cached = past_key_values.update( |
| recurrent_state=recurrent_state, |
| conv_state=conv_state, |
| attn_state=[k.flatten(-2, -1), v.flatten(-2, -1)], |
| layer_idx=self.layer_idx, |
| offset=q_len, |
| cache_kwargs=dict(window_size=self.window_size), |
| )['attn_state'] |
| if cache_has_content: |
| k, v = k_cached, v_cached |
| k = rearrange(k, '... (h d) -> ... h d', d=self.head_dim) |
| v = rearrange(v, '... (h d) -> ... h d', d=self.head_dim) |
|
|
| if flash_attn_func is None: |
| raise ImportError("Please install Flash Attention via `pip install flash-attn --no-build-isolation` first") |
|
|
| q, k, v = map(autocast_to_fp16, (q, k, v)) |
| k = repeat(k, "... h d -> ... (n h) d", n=self.num_heads) |
| |
| if attention_mask is not None: |
| q, (k, v), indices_q, cu_seqlens, max_seq_lens = unpad_input( |
| q=q, |
| states=(k, v), |
| attention_mask=attention_mask[:, -max(self.window_size, q_len):], |
| q_len=q_len, |
| ) |
| cu_seqlens_q, cu_seqlens_k = cu_seqlens |
| max_seqlen_q, max_seqlen_k = max_seq_lens |
| o = flash_attn_varlen_func( |
| q, k, v, |
| cu_seqlens_q=cu_seqlens_q, |
| cu_seqlens_k=cu_seqlens_k, |
| max_seqlen_q=max_seqlen_q, |
| max_seqlen_k=max_seqlen_k, |
| causal=True, |
| window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0), |
| ) |
| o = pad_input(o, indices_q, batch_size, q_len) |
| elif cu_seqlens is not None: |
| o = flash_attn_varlen_func( |
| q.squeeze(0), k.squeeze(0), v.squeeze(0), |
| cu_seqlens_q=cu_seqlens, |
| cu_seqlens_k=cu_seqlens, |
| max_seqlen_q=max_seqlen, |
| max_seqlen_k=max_seqlen, |
| causal=True, |
| window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0), |
| ).unsqueeze(0) |
| else: |
| o = flash_attn_func( |
| q, k, v, |
| causal=True, |
| window_size=(-1, -1) if self.window_size is None else (self.window_size-1, 0), |
| ) |
| o = o.reshape(batch_size, q_len, -1) |
| o = self.o_proj(o.to(dtype=self.o_proj.weight.dtype)) |
|
|
| if not output_attentions: |
| attentions = None |
|
|
| return o, attentions, past_key_values |
|
|