1+ import logging
12from abc import ABC , abstractmethod
23from enum import Enum
34from typing import Any , Dict , Optional , Tuple , Type , TypedDict
@@ -56,6 +57,8 @@ def forward(
5657
5758
5859ATTENTION_REGISTRY : Dict [str , Type [Attention ]] = {}
60+ _RECURRENT_GATED_DELTA_RULE_OP = None
61+ _TRIED_LOADING_RECURRENT_GATED_DELTA_RULE_OP = False
5962
6063
6164def register_attention (name : str ):
@@ -68,6 +71,38 @@ def decorator(cls: Type[Attention]):
6871 return decorator
6972
7073
74+ def _get_recurrent_gated_delta_rule_op ():
75+ global _RECURRENT_GATED_DELTA_RULE_OP
76+ global _TRIED_LOADING_RECURRENT_GATED_DELTA_RULE_OP
77+
78+ if _TRIED_LOADING_RECURRENT_GATED_DELTA_RULE_OP :
79+ return _RECURRENT_GATED_DELTA_RULE_OP
80+
81+ _TRIED_LOADING_RECURRENT_GATED_DELTA_RULE_OP = True
82+ try :
83+ _RECURRENT_GATED_DELTA_RULE_OP = (
84+ torch .ops .llama .recurrent_gated_delta_rule .default
85+ )
86+ return _RECURRENT_GATED_DELTA_RULE_OP
87+ except (AttributeError , RuntimeError ):
88+ pass
89+
90+ try :
91+ from executorch .extension .llm .custom_ops import custom_ops # noqa: F401
92+ except (ImportError , OSError , RuntimeError ):
93+ logging .debug ("Failed to import custom ops library" , exc_info = True )
94+ return None
95+
96+ try :
97+ _RECURRENT_GATED_DELTA_RULE_OP = (
98+ torch .ops .llama .recurrent_gated_delta_rule .default
99+ )
100+ except (AttributeError , RuntimeError ):
101+ _RECURRENT_GATED_DELTA_RULE_OP = None
102+
103+ return _RECURRENT_GATED_DELTA_RULE_OP
104+
105+
71106class KVCache (nn .Module ):
72107 def __init__ (
73108 self ,
@@ -762,28 +797,43 @@ def _apply_causal_conv(self, mixed_qkv: torch.Tensor) -> torch.Tensor:
762797 out = F .silu (out [:, :, - seq_len :]).to (mixed_qkv .dtype )
763798 return out .transpose (1 , 2 ).contiguous ()
764799
765- def _recurrent_gated_delta_rule (
800+ def _gated_delta_rule_op (
766801 self ,
767802 query : torch .Tensor ,
768803 key : torch .Tensor ,
769804 value : torch .Tensor ,
770805 g : torch .Tensor ,
771806 beta : torch .Tensor ,
772807 ) -> torch .Tensor :
773- # query/key/value: (batch, seq_len, num_heads, head_dim)
774- # g/beta: (batch, seq_len, num_heads)
775- initial_dtype = query .dtype
776- query = _l2norm (query , dim = - 1 , eps = 1e-6 )
777- key = _l2norm (key , dim = - 1 , eps = 1e-6 )
778- query , key , value , beta , g = [
779- x .transpose (1 , 2 ).contiguous ().to (torch .float32 )
780- for x in (query , key , value , beta , g )
781- ]
808+ batch_size = query .shape [0 ]
809+ recurrent_gated_delta_rule_op = _get_recurrent_gated_delta_rule_op ()
810+ if recurrent_gated_delta_rule_op is not None :
811+ return recurrent_gated_delta_rule_op (
812+ query ,
813+ key ,
814+ value ,
815+ g ,
816+ beta ,
817+ self .recurrent_state [:batch_size ],
818+ )
819+ return self ._naive_gated_delta_rule_op (
820+ query ,
821+ key ,
822+ value ,
823+ g ,
824+ beta ,
825+ )
782826
783- batch_size , num_heads , sequence_length , k_head_dim = key .shape
827+ def _naive_gated_delta_rule_op (
828+ self ,
829+ query : torch .Tensor ,
830+ key : torch .Tensor ,
831+ value : torch .Tensor ,
832+ g : torch .Tensor ,
833+ beta : torch .Tensor ,
834+ ) -> torch .Tensor :
835+ batch_size , num_heads , sequence_length , _ = key .shape
784836 v_head_dim = value .shape [- 1 ]
785- scale = 1.0 / (query .shape [- 1 ] ** 0.5 )
786- query = query * scale
787837
788838 core_attn_out = torch .zeros (
789839 batch_size ,
@@ -817,6 +867,36 @@ def _recurrent_gated_delta_rule(
817867 last_recurrent_state .to (self .recurrent_state .dtype )
818868 )
819869
870+ return core_attn_out
871+
872+ def _recurrent_gated_delta_rule (
873+ self ,
874+ query : torch .Tensor ,
875+ key : torch .Tensor ,
876+ value : torch .Tensor ,
877+ g : torch .Tensor ,
878+ beta : torch .Tensor ,
879+ ) -> torch .Tensor :
880+ # query/key/value: (batch, seq_len, num_heads, head_dim)
881+ # g/beta: (batch, seq_len, num_heads)
882+ initial_dtype = query .dtype
883+ query = _l2norm (query , dim = - 1 , eps = 1e-6 )
884+ key = _l2norm (key , dim = - 1 , eps = 1e-6 )
885+ query , key , value , beta , g = [
886+ x .transpose (1 , 2 ).contiguous ().to (torch .float32 )
887+ for x in (query , key , value , beta , g )
888+ ]
889+
890+ scale = 1.0 / (query .shape [- 1 ] ** 0.5 )
891+ query = query * scale
892+
893+ core_attn_out = self ._gated_delta_rule_op (
894+ query ,
895+ key ,
896+ value ,
897+ g ,
898+ beta ,
899+ )
820900 return core_attn_out .transpose (1 , 2 ).contiguous ().to (initial_dtype )
821901
822902 def forward (
0 commit comments