flashmap 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flashmap/__init__.py +14 -0
- flashmap/configuration_flashmap.py +105 -0
- flashmap/modeling_flashmap.py +556 -0
- flashmap/sglang/__init__.py +78 -0
- flashmap/sglang/jump_bank.py +203 -0
- flashmap/sglang/kernels.py +457 -0
- flashmap/sglang/model.py +1076 -0
- flashmap/sglang/sampler.py +188 -0
- flashmap/sglang/tree.py +78 -0
- flashmap/sglang/tree_worker.py +396 -0
- flashmap/sglang/verify_attention.py +474 -0
- flashmap/vllm/__init__.py +268 -0
- flashmap/vllm/fold.py +128 -0
- flashmap/vllm/kernels.py +443 -0
- flashmap/vllm/model.py +881 -0
- flashmap/vllm/speculator.py +235 -0
- flashmap-0.1.0.dist-info/METADATA +152 -0
- flashmap-0.1.0.dist-info/RECORD +22 -0
- flashmap-0.1.0.dist-info/WHEEL +5 -0
- flashmap-0.1.0.dist-info/entry_points.txt +5 -0
- flashmap-0.1.0.dist-info/licenses/LICENSE +21 -0
- flashmap-0.1.0.dist-info/top_level.txt +1 -0
flashmap/vllm/kernels.py
ADDED
|
@@ -0,0 +1,443 @@
|
|
|
1
|
+
"""Triton kernels for FlashMap drafting in vLLM.
|
|
2
|
+
|
|
3
|
+
The FlashMap DiT normalizes with ``x * bf16(weight * rsqrt(mean(x^2) + eps))``
|
|
4
|
+
(the weight is ``1 + scale`` of the training code) and rotates interleaved pairs
|
|
5
|
+
``(2i, 2i + 1)`` in float32 before rounding back to bf16. These kernels reproduce
|
|
6
|
+
that rounding so that vLLM drafts what the reference implementation drafts. The
|
|
7
|
+
ones the draft step calls are registered as custom ops so torch.compile keeps
|
|
8
|
+
them whole.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
import torch
|
|
12
|
+
import triton
|
|
13
|
+
import triton.language as tl
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"block_self_attention",
|
|
17
|
+
"rms_norm",
|
|
18
|
+
"rms_norm_rope",
|
|
19
|
+
"rope_table",
|
|
20
|
+
"scatter_rows",
|
|
21
|
+
"seeded_normal",
|
|
22
|
+
"write_context_kv",
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def rope_table(max_positions: int, head_dim: int, base: float, device) -> torch.Tensor:
|
|
27
|
+
"""``(max_positions, head_dim / 2, 2)`` float32 table of ``(cos, sin)`` of
|
|
28
|
+
``position * base^(-2i / head_dim)``, as the training code computes them."""
|
|
29
|
+
inv_freq = 1.0 / (
|
|
30
|
+
base ** (torch.arange(0, head_dim, 2, device=device).float() / head_dim)
|
|
31
|
+
)
|
|
32
|
+
angles = torch.arange(max_positions, device=device).float()[:, None] * inv_freq
|
|
33
|
+
return torch.stack([angles.cos(), angles.sin()], dim=-1).contiguous()
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@triton.jit
|
|
37
|
+
def _rms_norm_kernel(x_ptr, weight_ptr, out_ptr, n_cols, eps, BLOCK: tl.constexpr):
|
|
38
|
+
row = tl.program_id(0).to(tl.int64)
|
|
39
|
+
cols = tl.arange(0, BLOCK)
|
|
40
|
+
mask = cols < n_cols
|
|
41
|
+
x = tl.load(x_ptr + row * n_cols + cols, mask=mask, other=0.0).to(tl.float32)
|
|
42
|
+
rms = tl.rsqrt(tl.sum(x * x, 0) / n_cols + eps)
|
|
43
|
+
weight = tl.load(weight_ptr + cols, mask=mask, other=0.0).to(tl.float32)
|
|
44
|
+
scale = (weight * rms).to(tl.bfloat16).to(tl.float32)
|
|
45
|
+
tl.store(out_ptr + row * n_cols + cols, (x * scale).to(tl.bfloat16), mask=mask)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
@torch.library.custom_op("flashmap_vllm::rms_norm", mutates_args=())
|
|
49
|
+
def rms_norm(x: torch.Tensor, weight: torch.Tensor, eps: float) -> torch.Tensor:
|
|
50
|
+
"""FlashMap RMSNorm of a bf16 ``x (..., C)``, in one launch."""
|
|
51
|
+
assert x.dtype == torch.bfloat16
|
|
52
|
+
x = x.contiguous()
|
|
53
|
+
out = torch.empty_like(x)
|
|
54
|
+
n_cols = x.shape[-1]
|
|
55
|
+
if x.numel():
|
|
56
|
+
_rms_norm_kernel[(x.numel() // n_cols,)](
|
|
57
|
+
x, weight, out, n_cols, eps, BLOCK=triton.next_power_of_2(n_cols)
|
|
58
|
+
)
|
|
59
|
+
return out
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@rms_norm.register_fake
|
|
63
|
+
def _(x, weight, eps):
|
|
64
|
+
return torch.empty_like(x)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@triton.jit
|
|
68
|
+
def _rms_norm_rope_kernel(
|
|
69
|
+
x_ptr,
|
|
70
|
+
weight_ptr,
|
|
71
|
+
cos_sin_ptr,
|
|
72
|
+
pos_ptr,
|
|
73
|
+
out_ptr,
|
|
74
|
+
eps,
|
|
75
|
+
H: tl.constexpr,
|
|
76
|
+
D: tl.constexpr,
|
|
77
|
+
):
|
|
78
|
+
# One program per (token, head) of a contiguous (tokens, H, D) input.
|
|
79
|
+
token = tl.program_id(0) // H
|
|
80
|
+
head = tl.program_id(0) % H
|
|
81
|
+
HALF: tl.constexpr = D // 2
|
|
82
|
+
i = tl.arange(0, HALF)
|
|
83
|
+
row = x_ptr + (token * H + head) * D
|
|
84
|
+
even = tl.load(row + 2 * i).to(tl.float32)
|
|
85
|
+
odd = tl.load(row + 2 * i + 1).to(tl.float32)
|
|
86
|
+
rms = tl.rsqrt((tl.sum(even * even, 0) + tl.sum(odd * odd, 0)) / D + eps)
|
|
87
|
+
w_even = tl.load(weight_ptr + 2 * i).to(tl.float32)
|
|
88
|
+
w_odd = tl.load(weight_ptr + 2 * i + 1).to(tl.float32)
|
|
89
|
+
even = (even * (w_even * rms).to(tl.bfloat16).to(tl.float32)).to(tl.bfloat16)
|
|
90
|
+
odd = (odd * (w_odd * rms).to(tl.bfloat16).to(tl.float32)).to(tl.bfloat16)
|
|
91
|
+
even = even.to(tl.float32)
|
|
92
|
+
odd = odd.to(tl.float32)
|
|
93
|
+
pos = tl.load(pos_ptr + token).to(tl.int64)
|
|
94
|
+
cos = tl.load(cos_sin_ptr + pos * D + 2 * i)
|
|
95
|
+
sin = tl.load(cos_sin_ptr + pos * D + 2 * i + 1)
|
|
96
|
+
out = out_ptr + (token * H + head) * D
|
|
97
|
+
tl.store(out + 2 * i, (even * cos - odd * sin).to(tl.bfloat16))
|
|
98
|
+
tl.store(out + 2 * i + 1, (odd * cos + even * sin).to(tl.bfloat16))
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
@torch.library.custom_op("flashmap_vllm::rms_norm_rope", mutates_args=())
|
|
102
|
+
def rms_norm_rope(
|
|
103
|
+
x: torch.Tensor,
|
|
104
|
+
weight: torch.Tensor,
|
|
105
|
+
cos_sin: torch.Tensor,
|
|
106
|
+
positions: torch.Tensor,
|
|
107
|
+
eps: float,
|
|
108
|
+
) -> torch.Tensor:
|
|
109
|
+
"""RMSNorm then RoPE at ``positions (tokens,)`` of ``x (tokens, heads, head_dim)``
|
|
110
|
+
with the ``rope_table`` ``cos_sin``, in one launch."""
|
|
111
|
+
tokens, heads, head_dim = x.shape
|
|
112
|
+
assert cos_sin.dtype == torch.float32 and cos_sin.is_contiguous()
|
|
113
|
+
x, positions = x.contiguous(), positions.contiguous()
|
|
114
|
+
out = torch.empty_like(x)
|
|
115
|
+
if tokens:
|
|
116
|
+
_rms_norm_rope_kernel[(tokens * heads,)](
|
|
117
|
+
x, weight, cos_sin, positions, out, eps, H=heads, D=head_dim
|
|
118
|
+
)
|
|
119
|
+
return out
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@rms_norm_rope.register_fake
|
|
123
|
+
def _(x, weight, cos_sin, positions, eps):
|
|
124
|
+
return torch.empty_like(x)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@triton.jit
|
|
128
|
+
def _block_self_attention_kernel(
|
|
129
|
+
qkv_ptr,
|
|
130
|
+
q_norm_ptr,
|
|
131
|
+
k_norm_ptr,
|
|
132
|
+
cos_sin_ptr,
|
|
133
|
+
pos_ptr,
|
|
134
|
+
out_ptr,
|
|
135
|
+
eps,
|
|
136
|
+
sm_scale,
|
|
137
|
+
T: tl.constexpr,
|
|
138
|
+
H: tl.constexpr,
|
|
139
|
+
D: tl.constexpr,
|
|
140
|
+
):
|
|
141
|
+
# One program per (block, head): the block's T queries attend to its T keys.
|
|
142
|
+
b = tl.program_id(0) // H
|
|
143
|
+
h = tl.program_id(0) % H
|
|
144
|
+
HALF: tl.constexpr = D // 2
|
|
145
|
+
t = tl.arange(0, T)[:, None]
|
|
146
|
+
i = tl.arange(0, HALF)[None, :]
|
|
147
|
+
d = tl.arange(0, D)[None, :]
|
|
148
|
+
# qkv is (blocks, T, 3, H, D); RoPE pairs dims (2i, 2i + 1).
|
|
149
|
+
row = qkv_ptr + (b * T + t) * (3 * H * D) + h * D
|
|
150
|
+
pos = tl.load(pos_ptr + b * T + t).to(tl.int64)
|
|
151
|
+
cos = tl.load(cos_sin_ptr + pos * D + 2 * i)
|
|
152
|
+
sin = tl.load(cos_sin_ptr + pos * D + 2 * i + 1)
|
|
153
|
+
|
|
154
|
+
q_even = tl.load(row + 2 * i).to(tl.float32)
|
|
155
|
+
q_odd = tl.load(row + 2 * i + 1).to(tl.float32)
|
|
156
|
+
k_even = tl.load(row + H * D + 2 * i).to(tl.float32)
|
|
157
|
+
k_odd = tl.load(row + H * D + 2 * i + 1).to(tl.float32)
|
|
158
|
+
|
|
159
|
+
q_rms = tl.rsqrt((tl.sum(q_even * q_even, 1) + tl.sum(q_odd * q_odd, 1)) / D + eps)[
|
|
160
|
+
:, None
|
|
161
|
+
]
|
|
162
|
+
k_rms = tl.rsqrt((tl.sum(k_even * k_even, 1) + tl.sum(k_odd * k_odd, 1)) / D + eps)[
|
|
163
|
+
:, None
|
|
164
|
+
]
|
|
165
|
+
qw_even = tl.load(q_norm_ptr + 2 * i).to(tl.float32)
|
|
166
|
+
qw_odd = tl.load(q_norm_ptr + 2 * i + 1).to(tl.float32)
|
|
167
|
+
kw_even = tl.load(k_norm_ptr + 2 * i).to(tl.float32)
|
|
168
|
+
kw_odd = tl.load(k_norm_ptr + 2 * i + 1).to(tl.float32)
|
|
169
|
+
q_even = (q_even * (qw_even * q_rms).to(tl.bfloat16).to(tl.float32)).to(tl.bfloat16)
|
|
170
|
+
q_odd = (q_odd * (qw_odd * q_rms).to(tl.bfloat16).to(tl.float32)).to(tl.bfloat16)
|
|
171
|
+
k_even = (k_even * (kw_even * k_rms).to(tl.bfloat16).to(tl.float32)).to(tl.bfloat16)
|
|
172
|
+
k_odd = (k_odd * (kw_odd * k_rms).to(tl.bfloat16).to(tl.float32)).to(tl.bfloat16)
|
|
173
|
+
q_even = q_even.to(tl.float32)
|
|
174
|
+
q_odd = q_odd.to(tl.float32)
|
|
175
|
+
k_even = k_even.to(tl.float32)
|
|
176
|
+
k_odd = k_odd.to(tl.float32)
|
|
177
|
+
|
|
178
|
+
q_rot_even = (q_even * cos - q_odd * sin).to(tl.bfloat16)
|
|
179
|
+
q_rot_odd = (q_odd * cos + q_even * sin).to(tl.bfloat16)
|
|
180
|
+
k_rot_even = (k_even * cos - k_odd * sin).to(tl.bfloat16)
|
|
181
|
+
k_rot_odd = (k_odd * cos + k_even * sin).to(tl.bfloat16)
|
|
182
|
+
|
|
183
|
+
scores = tl.dot(q_rot_even, tl.trans(k_rot_even)) + tl.dot(
|
|
184
|
+
q_rot_odd, tl.trans(k_rot_odd)
|
|
185
|
+
)
|
|
186
|
+
scores = scores * sm_scale
|
|
187
|
+
probs = tl.exp(scores - tl.max(scores, 1)[:, None])
|
|
188
|
+
denom = tl.sum(probs, 1)[:, None]
|
|
189
|
+
values = tl.load(row + 2 * H * D + d)
|
|
190
|
+
out = tl.dot(probs.to(tl.bfloat16), values) / denom
|
|
191
|
+
tl.store(out_ptr + (b * T + t) * (H * D) + h * D + d, out.to(tl.bfloat16))
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
@torch.library.custom_op("flashmap_vllm::block_self_attention", mutates_args=())
|
|
195
|
+
def block_self_attention(
|
|
196
|
+
qkv: torch.Tensor,
|
|
197
|
+
q_norm: torch.Tensor,
|
|
198
|
+
k_norm: torch.Tensor,
|
|
199
|
+
cos_sin: torch.Tensor,
|
|
200
|
+
positions: torch.Tensor,
|
|
201
|
+
eps: float,
|
|
202
|
+
) -> torch.Tensor:
|
|
203
|
+
"""Unmasked self-attention within each draft block, from its projected
|
|
204
|
+
``qkv (blocks, T, 3, heads, head_dim)``: q/k RMSNorms, RoPE at ``positions
|
|
205
|
+
(blocks * T,)``, softmax attention. Returns ``(blocks * T, heads * head_dim)``."""
|
|
206
|
+
blocks, block_size, _, heads, head_dim = qkv.shape
|
|
207
|
+
assert cos_sin.dtype == torch.float32 and cos_sin.is_contiguous()
|
|
208
|
+
qkv, positions = qkv.contiguous(), positions.contiguous()
|
|
209
|
+
out = torch.empty(
|
|
210
|
+
(blocks * block_size, heads * head_dim), dtype=qkv.dtype, device=qkv.device
|
|
211
|
+
)
|
|
212
|
+
if blocks:
|
|
213
|
+
_block_self_attention_kernel[(blocks * heads,)](
|
|
214
|
+
qkv,
|
|
215
|
+
q_norm,
|
|
216
|
+
k_norm,
|
|
217
|
+
cos_sin,
|
|
218
|
+
positions,
|
|
219
|
+
out,
|
|
220
|
+
eps,
|
|
221
|
+
head_dim**-0.5,
|
|
222
|
+
T=block_size,
|
|
223
|
+
H=heads,
|
|
224
|
+
D=head_dim,
|
|
225
|
+
)
|
|
226
|
+
return out
|
|
227
|
+
|
|
228
|
+
|
|
229
|
+
@block_self_attention.register_fake
|
|
230
|
+
def _(qkv, q_norm, k_norm, cos_sin, positions, eps):
|
|
231
|
+
blocks, block_size, _, heads, head_dim = qkv.shape
|
|
232
|
+
return qkv.new_empty((blocks * block_size, heads * head_dim))
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
@triton.jit
|
|
236
|
+
def _write_context_kv_kernel(
|
|
237
|
+
kv_ptr, # (tokens, L, 2, H, D) bf16, contiguous
|
|
238
|
+
pos_ptr, # (tokens,)
|
|
239
|
+
slot_ptr, # (tokens,) int64; negative = skip
|
|
240
|
+
k_norm_ptr, # (L, D)
|
|
241
|
+
cos_sin_ptr, # (max_positions, D / 2, 2) float32
|
|
242
|
+
cache_ptrs, # (L,) int64 data pointers of each layer's KV cache
|
|
243
|
+
scales_ptr, # (L, 2) float32 key and value scales of an fp8 cache
|
|
244
|
+
eps,
|
|
245
|
+
block_size,
|
|
246
|
+
stride_block,
|
|
247
|
+
stride_head,
|
|
248
|
+
stride_token,
|
|
249
|
+
v_offset,
|
|
250
|
+
L: tl.constexpr,
|
|
251
|
+
FP8: tl.constexpr,
|
|
252
|
+
H: tl.constexpr,
|
|
253
|
+
D: tl.constexpr,
|
|
254
|
+
):
|
|
255
|
+
# One program per (token, layer); all heads at once.
|
|
256
|
+
token = tl.program_id(0).to(tl.int64)
|
|
257
|
+
layer = tl.program_id(1)
|
|
258
|
+
slot = tl.load(slot_ptr + token).to(tl.int64)
|
|
259
|
+
if slot < 0:
|
|
260
|
+
return
|
|
261
|
+
HALF: tl.constexpr = D // 2
|
|
262
|
+
h = tl.arange(0, H)[:, None]
|
|
263
|
+
i = tl.arange(0, HALF)[None, :]
|
|
264
|
+
d = tl.arange(0, D)[None, :]
|
|
265
|
+
k_row = kv_ptr + (token * L + layer) * (2 * H * D) + h * D
|
|
266
|
+
v_row = k_row + H * D
|
|
267
|
+
even = tl.load(k_row + 2 * i).to(tl.float32)
|
|
268
|
+
odd = tl.load(k_row + 2 * i + 1).to(tl.float32)
|
|
269
|
+
rms = tl.rsqrt((tl.sum(even * even, 1) + tl.sum(odd * odd, 1)) / D + eps)[:, None]
|
|
270
|
+
w_even = tl.load(k_norm_ptr + layer * D + 2 * i).to(tl.float32)
|
|
271
|
+
w_odd = tl.load(k_norm_ptr + layer * D + 2 * i + 1).to(tl.float32)
|
|
272
|
+
even = (even * (w_even * rms).to(tl.bfloat16).to(tl.float32)).to(tl.bfloat16)
|
|
273
|
+
odd = (odd * (w_odd * rms).to(tl.bfloat16).to(tl.float32)).to(tl.bfloat16)
|
|
274
|
+
even = even.to(tl.float32)
|
|
275
|
+
odd = odd.to(tl.float32)
|
|
276
|
+
pos = tl.load(pos_ptr + token).to(tl.int64)
|
|
277
|
+
cos = tl.load(cos_sin_ptr + pos * D + 2 * i)
|
|
278
|
+
sin = tl.load(cos_sin_ptr + pos * D + 2 * i + 1)
|
|
279
|
+
|
|
280
|
+
key_out = even * cos - odd * sin
|
|
281
|
+
key_odd_out = odd * cos + even * sin
|
|
282
|
+
values = tl.load(v_row + d)
|
|
283
|
+
if FP8:
|
|
284
|
+
# e4m3 with per-tensor scales, as vLLM's fp8 KV caches store them.
|
|
285
|
+
k_scale = tl.load(scales_ptr + layer * 2)
|
|
286
|
+
v_scale = tl.load(scales_ptr + layer * 2 + 1)
|
|
287
|
+
cache = tl.load(cache_ptrs + layer).to(tl.pointer_type(tl.float8e4nv))
|
|
288
|
+
key_out = (key_out / k_scale).to(tl.float8e4nv)
|
|
289
|
+
key_odd_out = (key_odd_out / k_scale).to(tl.float8e4nv)
|
|
290
|
+
values = (values.to(tl.float32) / v_scale).to(tl.float8e4nv)
|
|
291
|
+
else:
|
|
292
|
+
cache = tl.load(cache_ptrs + layer).to(tl.pointer_type(tl.bfloat16))
|
|
293
|
+
key_out = key_out.to(tl.bfloat16)
|
|
294
|
+
key_odd_out = key_odd_out.to(tl.bfloat16)
|
|
295
|
+
dst = cache + (slot // block_size) * stride_block + h * stride_head
|
|
296
|
+
dst += (slot % block_size) * stride_token
|
|
297
|
+
tl.store(dst + 2 * i, key_out)
|
|
298
|
+
tl.store(dst + 2 * i + 1, key_odd_out)
|
|
299
|
+
tl.store(dst + v_offset + d, values)
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
def write_context_kv(
|
|
303
|
+
kv: torch.Tensor,
|
|
304
|
+
positions: torch.Tensor,
|
|
305
|
+
slots: torch.Tensor,
|
|
306
|
+
k_norm: torch.Tensor,
|
|
307
|
+
cos_sin: torch.Tensor,
|
|
308
|
+
cache_ptrs: torch.Tensor,
|
|
309
|
+
cache_strides: tuple[int, int, int, int],
|
|
310
|
+
block_size: int,
|
|
311
|
+
eps: float,
|
|
312
|
+
scales: torch.Tensor | None = None,
|
|
313
|
+
) -> None:
|
|
314
|
+
"""Write every layer's context keys (k-normed and rotated) and values for
|
|
315
|
+
``kv (tokens, layers, 2, heads, head_dim)`` into the paged KV caches at
|
|
316
|
+
``slots`` (negative slots are skipped), in one launch.
|
|
317
|
+
|
|
318
|
+
``cache_strides`` are ``(block, head, token, value offset)`` in elements of
|
|
319
|
+
the vLLM FlashAttention cache ``(blocks, heads, block_size, 2 * head_dim)``.
|
|
320
|
+
With ``scales (layers, 2)`` (each layer's key and value scale) the caches are
|
|
321
|
+
e4m3 and store ``key / k_scale`` and ``value / v_scale``.
|
|
322
|
+
"""
|
|
323
|
+
tokens, layers, _, heads, head_dim = kv.shape
|
|
324
|
+
if not tokens:
|
|
325
|
+
return
|
|
326
|
+
stride_block, stride_head, stride_token, v_offset = cache_strides
|
|
327
|
+
_write_context_kv_kernel[(tokens, layers)](
|
|
328
|
+
kv.contiguous(),
|
|
329
|
+
positions.contiguous(),
|
|
330
|
+
slots.contiguous(),
|
|
331
|
+
k_norm,
|
|
332
|
+
cos_sin,
|
|
333
|
+
cache_ptrs,
|
|
334
|
+
scales if scales is not None else k_norm,
|
|
335
|
+
eps,
|
|
336
|
+
block_size,
|
|
337
|
+
stride_block,
|
|
338
|
+
stride_head,
|
|
339
|
+
stride_token,
|
|
340
|
+
v_offset,
|
|
341
|
+
L=layers,
|
|
342
|
+
FP8=scales is not None,
|
|
343
|
+
H=heads,
|
|
344
|
+
D=head_dim,
|
|
345
|
+
)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
@triton.jit
|
|
349
|
+
def _seeded_normal_kernel(
|
|
350
|
+
seeds_ptr, # (max_num_reqs,) int64
|
|
351
|
+
rows_ptr, # (rows,) int32 request-state index per row; negative = unseeded
|
|
352
|
+
pos_ptr, # (rows,)
|
|
353
|
+
out_ptr, # (rows, n_cols) float32
|
|
354
|
+
n_cols,
|
|
355
|
+
scale,
|
|
356
|
+
BLOCK: tl.constexpr,
|
|
357
|
+
):
|
|
358
|
+
row = tl.program_id(0).to(tl.int64)
|
|
359
|
+
cols = tl.program_id(1) * BLOCK + tl.arange(0, BLOCK)
|
|
360
|
+
state = tl.load(rows_ptr + row)
|
|
361
|
+
seed = tl.load(seeds_ptr + tl.maximum(state, 0)).to(tl.int64)
|
|
362
|
+
seed = tl.where(state >= 0, seed, 0)
|
|
363
|
+
# Philox keyed by the request's seed and the row's position: the noise of a
|
|
364
|
+
# seeded request is reproducible whatever else is batched with it.
|
|
365
|
+
key = seed * 1000003 + tl.load(pos_ptr + row).to(tl.int64)
|
|
366
|
+
z = tl.randn(key, cols)
|
|
367
|
+
tl.store(out_ptr + row * n_cols + cols, z * scale, mask=cols < n_cols)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
def seeded_normal(
|
|
371
|
+
seeds: torch.Tensor,
|
|
372
|
+
rows: torch.Tensor,
|
|
373
|
+
positions: torch.Tensor,
|
|
374
|
+
n_cols: int,
|
|
375
|
+
scale: float = 1.0,
|
|
376
|
+
) -> torch.Tensor:
|
|
377
|
+
"""Standard normals ``(len(rows), n_cols)`` in float32, row ``i`` keyed by
|
|
378
|
+
``seeds[rows[i]]`` (0 where ``rows[i] < 0``) and ``positions[i]``."""
|
|
379
|
+
out = torch.empty(rows.shape[0], n_cols, dtype=torch.float32, device=rows.device)
|
|
380
|
+
if rows.shape[0]:
|
|
381
|
+
block = 1024
|
|
382
|
+
_seeded_normal_kernel[(rows.shape[0], triton.cdiv(n_cols, block))](
|
|
383
|
+
seeds,
|
|
384
|
+
rows.contiguous(),
|
|
385
|
+
positions.contiguous(),
|
|
386
|
+
out,
|
|
387
|
+
n_cols,
|
|
388
|
+
scale,
|
|
389
|
+
BLOCK=block,
|
|
390
|
+
)
|
|
391
|
+
return out
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
@triton.jit
|
|
395
|
+
def _scatter_rows_kernel(
|
|
396
|
+
src_ptr, # (rows, n_cols)
|
|
397
|
+
req_ptr, # (rows,) first index into dst; negative = skip
|
|
398
|
+
col_ptr, # (rows,) second index into dst
|
|
399
|
+
ids_ptr, # (n_cols,) third index into dst
|
|
400
|
+
dst_ptr, # (A, B, C), contiguous
|
|
401
|
+
n_cols,
|
|
402
|
+
stride_a,
|
|
403
|
+
stride_b,
|
|
404
|
+
BLOCK: tl.constexpr,
|
|
405
|
+
):
|
|
406
|
+
row = tl.program_id(0).to(tl.int64)
|
|
407
|
+
req = tl.load(req_ptr + row).to(tl.int64)
|
|
408
|
+
if req < 0:
|
|
409
|
+
return
|
|
410
|
+
col = tl.load(col_ptr + row).to(tl.int64)
|
|
411
|
+
j = tl.program_id(1) * BLOCK + tl.arange(0, BLOCK)
|
|
412
|
+
mask = j < n_cols
|
|
413
|
+
ids = tl.load(ids_ptr + j, mask=mask, other=0).to(tl.int64)
|
|
414
|
+
values = tl.load(src_ptr + row * n_cols + j, mask=mask)
|
|
415
|
+
dst = dst_ptr + req * stride_a + col * stride_b + ids
|
|
416
|
+
tl.store(dst, values.to(dst_ptr.dtype.element_ty), mask=mask)
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
def scatter_rows(
|
|
420
|
+
src: torch.Tensor,
|
|
421
|
+
req: torch.Tensor,
|
|
422
|
+
col: torch.Tensor,
|
|
423
|
+
ids: torch.Tensor,
|
|
424
|
+
dst: torch.Tensor,
|
|
425
|
+
) -> None:
|
|
426
|
+
"""``dst[req[i], col[i], ids] = src[i]`` for every row ``i`` with
|
|
427
|
+
``req[i] >= 0``: draft-vocabulary logits into a target-vocabulary cache."""
|
|
428
|
+
assert dst.is_contiguous()
|
|
429
|
+
assert dst.dim() == 3 # noqa: PLR2004
|
|
430
|
+
rows, n_cols = src.shape
|
|
431
|
+
if rows:
|
|
432
|
+
block = 1024
|
|
433
|
+
_scatter_rows_kernel[(rows, triton.cdiv(n_cols, block))](
|
|
434
|
+
src.contiguous(),
|
|
435
|
+
req.contiguous(),
|
|
436
|
+
col.contiguous(),
|
|
437
|
+
ids.contiguous(),
|
|
438
|
+
dst,
|
|
439
|
+
n_cols,
|
|
440
|
+
dst.stride(0),
|
|
441
|
+
dst.stride(1),
|
|
442
|
+
BLOCK=block,
|
|
443
|
+
)
|