Skip to content

Commit b53dd1b

Browse files
committed
support flash_attention
1 parent 76c08c7 commit b53dd1b

13 files changed

Lines changed: 1183 additions & 50 deletions

File tree

include/llaisys/ops.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@ __C {
1313
__export void llaisysROPE(llaisysTensor_t out, llaisysTensor_t in, llaisysTensor_t pos_ids, float theta);
1414
__export void llaisysSelfAttention(llaisysTensor_t attn_val, llaisysTensor_t q, llaisysTensor_t k, llaisysTensor_t v, float scale);
1515
__export void llaisysSwiGLU(llaisysTensor_t out, llaisysTensor_t gate, llaisysTensor_t up);
16+
17+
// Flash Attention with causal masking and GQA support
18+
// Behavior matches torch.nn.functional.scaled_dot_product_attention
19+
__export void llaisysFlashAttention(
20+
llaisysTensor_t out, // Output tensor [batch, seq_len, num_heads, head_dim]
21+
llaisysTensor_t q, // Query [batch, seq_len, num_q_heads, head_dim]
22+
llaisysTensor_t k, // Key [batch, kv_len, num_kv_heads, head_dim]
23+
llaisysTensor_t v, // Value [batch, kv_len, num_kv_heads, head_dim]
24+
float scale, // Scale factor (default: 1/sqrt(head_dim))
25+
bool is_causal, // Enable causal masking
26+
bool enable_gqa // Enable Grouped Query Attention
27+
);
1628
}
1729

1830
#endif

python/llaisys/libllaisys/ops.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from .tensor import llaisysTensor_t
2-
from ctypes import c_float
2+
from ctypes import c_float, c_bool
33

44
def load_ops(lib):
55
lib.llaisysAdd.argtypes = [llaisysTensor_t, llaisysTensor_t, llaisysTensor_t]
@@ -34,3 +34,14 @@ def load_ops(lib):
3434

3535
lib.llaisysSwiGLU.argtypes = [llaisysTensor_t, llaisysTensor_t, llaisysTensor_t]
3636
lib.llaisysSwiGLU.restype = None
37+
38+
lib.llaisysFlashAttention.argtypes = [
39+
llaisysTensor_t, # out
40+
llaisysTensor_t, # q
41+
llaisysTensor_t, # k
42+
llaisysTensor_t, # v
43+
c_float, # scale
44+
c_bool, # is_causal
45+
c_bool # enable_gqa
46+
]
47+
lib.llaisysFlashAttention.restype = None

python/llaisys/models/qwen2.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,19 @@ class Qwen2:
1717

1818
DEFAULT_MODEL_ID = "deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B"
1919

20-
def __init__(self, model_path: Optional[Union[str, Path]] = None, device: DeviceType = DeviceType.CPU):
20+
def __init__(
21+
self,
22+
model_path: Optional[Union[str, Path]] = None,
23+
device: DeviceType = DeviceType.CPU,
24+
max_seq_len: Optional[int] = None
25+
):
2126
"""Initialize Qwen2 model.
2227
2328
Args:
2429
model_path: Path to model directory. If None, downloads default model.
2530
device: Device type for inference.
31+
max_seq_len: Maximum sequence length. If None, uses model's default.
32+
Set this to a larger value (e.g., 8192, 16384) for longer contexts.
2633
2734
Raises:
2835
ValueError: If unsupported device is specified.
@@ -40,6 +47,13 @@ def __init__(self, model_path: Optional[Union[str, Path]] = None, device: Device
4047
config = self._load_config()
4148
self._init_model_params(config)
4249

50+
# Override max sequence length if specified
51+
if max_seq_len is not None:
52+
if max_seq_len <= 0:
53+
raise ValueError(f"max_seq_len must be positive, got {max_seq_len}")
54+
print(f"[Qwen2] Overriding max_position_embeddings: {self.max_position_embeddings}{max_seq_len}")
55+
self.max_position_embeddings = max_seq_len
56+
4357
self.data_type = DataType.F32 if device == DeviceType.CPU else DataType.BF16
4458

4559
self._create_model()

python/llaisys/ops.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from .libllaisys import LIB_LLAISYS
22
from .tensor import Tensor
3-
from ctypes import c_float, c_int
3+
from ctypes import c_float, c_int, c_bool
44

55

66
class Ops:
@@ -53,3 +53,36 @@ def self_attention(attn_val: Tensor, q: Tensor, k: Tensor, v: Tensor, scale: flo
5353
@staticmethod
5454
def swiglu(out: Tensor, gate: Tensor, up: Tensor):
5555
LIB_LLAISYS.llaisysSwiGLU(out.lib_tensor(), gate.lib_tensor(), up.lib_tensor())
56+
57+
@staticmethod
58+
def flash_attention(
59+
out: Tensor,
60+
q: Tensor,
61+
k: Tensor,
62+
v: Tensor,
63+
scale: float = 0.0,
64+
is_causal: bool = False,
65+
enable_gqa: bool = False
66+
):
67+
"""
68+
Flash Attention with causal masking and GQA support.
69+
Behavior matches torch.nn.functional.scaled_dot_product_attention.
70+
71+
Args:
72+
out: Output tensor [batch, seq_len, num_q_heads, head_dim]
73+
q: Query tensor [batch, seq_len, num_q_heads, head_dim]
74+
k: Key tensor [batch, kv_len, num_kv_heads, head_dim]
75+
v: Value tensor [batch, kv_len, num_kv_heads, head_dim]
76+
scale: Scale factor (default: 1/sqrt(head_dim))
77+
is_causal: Enable causal masking
78+
enable_gqa: Enable Grouped Query Attention
79+
"""
80+
LIB_LLAISYS.llaisysFlashAttention(
81+
out.lib_tensor(),
82+
q.lib_tensor(),
83+
k.lib_tensor(),
84+
v.lib_tensor(),
85+
c_float(scale),
86+
c_bool(is_causal),
87+
c_bool(enable_gqa)
88+
)

0 commit comments

Comments
 (0)