main
py 146 lines 4.96 KB
Raw
1 # SPDX-License-Identifier: Apache-2.0
2 # SPDX-FileCopyrightText: Copyright contributors to the vLLM project
3
4 # Copyright (c) 2024, Tri Dao, Albert Gu.
5 # Adapted from https://github.com/state-spaces/mamba/blob/v2.2.4/mamba_ssm/ops/triton/ssd_state_passing.py
6
7 # ruff: noqa: E501
8
9 import torch
10
11 from vllm.model_executor.layers.mamba.ops.triton_helpers import fast_exp
12 from vllm.triton_utils import tl, triton
13
14
15 @triton.autotune(
16 configs=[
17 triton.Config({"BLOCK_SIZE": 64}),
18 triton.Config({"BLOCK_SIZE": 128}),
19 triton.Config({"BLOCK_SIZE": 256}),
20 triton.Config({"BLOCK_SIZE": 512}),
21 triton.Config({"BLOCK_SIZE": 1024}),
22 triton.Config({"BLOCK_SIZE": 2048}),
23 ],
24 key=["dim"],
25 )
26 @triton.jit
27 def _state_passing_fwd_kernel(
28 # Pointers to matrices
29 states_ptr,
30 out_ptr,
31 dA_cs_ptr,
32 initstates_ptr,
33 last_chunk_indices_ptr,
34 # Matrix dimensions
35 dim: tl.constexpr,
36 chunk_size: tl.constexpr,
37 # Strides
38 stride_states_chunk: tl.int64,
39 stride_states_head: tl.int64,
40 stride_states_dim: tl.constexpr,
41 stride_out_chunk: tl.int64,
42 stride_out_head: tl.int64,
43 stride_out_dim: tl.constexpr,
44 stride_dA_cs_head: tl.int64,
45 stride_dA_cs_chunk: tl.int64,
46 stride_dA_cs_csize: tl.constexpr,
47 stride_initstates_batch: tl.int64,
48 stride_initstates_head: tl.int64,
49 stride_initstates_dim: tl.constexpr,
50 # Meta-parameters
51 HAS_INITSTATES: tl.constexpr,
52 BLOCK_SIZE: tl.constexpr,
53 ):
54 pid_m = tl.program_id(axis=0)
55 pid_b = tl.program_id(axis=1)
56 pid_h = tl.program_id(axis=2)
57
58 # Derive this sequence's chunk range from last_chunk_indices
59 chunk_end = tl.load(last_chunk_indices_ptr + pid_b) + 1
60 chunk_start = (
61 tl.load(last_chunk_indices_ptr + pid_b - 1, mask=pid_b > 0, other=-1) + 1
62 )
63
64 # Offset pointers to this sequence's first chunk
65 states_ptr += chunk_start * stride_states_chunk + pid_h * stride_states_head
66 dA_cs_ptr += (
67 pid_h * stride_dA_cs_head
68 + chunk_start * stride_dA_cs_chunk
69 + (chunk_size - 1) * stride_dA_cs_csize
70 )
71 out_ptr += chunk_start * stride_out_chunk + pid_h * stride_out_head
72
73 offs_m = pid_m * BLOCK_SIZE + tl.arange(0, BLOCK_SIZE)
74 states_ptrs = states_ptr + offs_m * stride_states_dim
75 out_ptrs = out_ptr + offs_m * stride_out_dim
76
77 # Load initial state once — no per-chunk branching needed
78 if HAS_INITSTATES:
79 initstates_ptrs = (
80 initstates_ptr
81 + pid_b * stride_initstates_batch
82 + pid_h * stride_initstates_head
83 + offs_m * stride_initstates_dim
84 )
85 states = tl.load(initstates_ptrs, mask=offs_m < dim, other=0.0).to(tl.float32)
86 else:
87 states = tl.zeros((BLOCK_SIZE,), dtype=tl.float32)
88
89 # Loop over only this sequence's chunks — branchless
90 nchunks_this_seq = chunk_end - chunk_start
91 for _ in range(nchunks_this_seq):
92 new_states = tl.load(states_ptrs, mask=offs_m < dim, other=0.0).to(tl.float32)
93 dA_cs = tl.load(dA_cs_ptr).to(tl.float32)
94 states = fast_exp(dA_cs) * states + new_states
95 tl.store(out_ptrs, states, mask=offs_m < dim)
96
97 states_ptrs += stride_states_chunk
98 dA_cs_ptr += stride_dA_cs_chunk
99 out_ptrs += stride_out_chunk
100
101
102 def _state_passing_fwd(
103 states,
104 dA_cumsum,
105 last_chunk_indices,
106 initial_states=None,
107 out_dtype=None,
108 ):
109 nchunks, nheads, dim = states.shape
110 chunk_size = dA_cumsum.shape[-1]
111 batch = last_chunk_indices.shape[0]
112 assert dA_cumsum.shape == (nheads, nchunks, chunk_size)
113 out_dtype = states.dtype if out_dtype is None else out_dtype
114 out = torch.empty((nchunks, nheads, dim), device=states.device, dtype=out_dtype)
115
116 initial_states_strides = (
117 (initial_states.stride(0), initial_states.stride(1), initial_states.stride(2))
118 if initial_states is not None
119 else (0, 0, 0)
120 )
121
122 grid = lambda META: (triton.cdiv(dim, META["BLOCK_SIZE"]), batch, nheads)
123 with torch.accelerator.device_index(states.device.index):
124 _state_passing_fwd_kernel[grid](
125 states_ptr=states,
126 out_ptr=out,
127 dA_cs_ptr=dA_cumsum,
128 initstates_ptr=initial_states,
129 last_chunk_indices_ptr=last_chunk_indices,
130 dim=dim,
131 chunk_size=chunk_size,
132 stride_states_chunk=states.stride(0),
133 stride_states_head=states.stride(1),
134 stride_states_dim=states.stride(2),
135 stride_out_chunk=out.stride(0),
136 stride_out_head=out.stride(1),
137 stride_out_dim=out.stride(2),
138 stride_dA_cs_head=dA_cumsum.stride(0),
139 stride_dA_cs_chunk=dA_cumsum.stride(1),
140 stride_dA_cs_csize=dA_cumsum.stride(2),
141 stride_initstates_batch=initial_states_strides[0],
142 stride_initstates_head=initial_states_strides[1],
143 stride_initstates_dim=initial_states_strides[2],
144 HAS_INITSTATES=initial_states is not None,
145 )
146 return out