Top-k and Sampling Operators¶
Every op on this page is used the same way: construct it once, then call it. The
constructor takes what the kernel is compiled with; the call takes the tensors.
Both are documented under each op — __init__ and forward, where forward is
what runs when you call op(...).
The top-k selector returns the indices of the largest scores in each row. The masks
set every logit a filter drops to -inf, so a softmax over the result renormalizes
over what is kept. The samplers draw from a distribution, and take the random seed
and offset as tensors so a draw is reproducible.
Top-k selection¶
tileops.attention.TopKSelectFwdOp
¶
The topk highest-scoring key positions of each query row's own window.
Row (b, s, g) selects from index_score[b, s, starts[b, s]:ends[b, s], g].
Two deviations from torch.topk, which returns its indices sorted:
- The indices come back in no particular order along the
topkaxis. Two calls on one input select the same positions and may place them in different slots. - A window holding fewer than
topkpositions fills the rest withseq_len_kv, one past the last key, which selects nothing.
__init__
¶
Build the op. Shapes and dtype are taken from each call.
Parameters:
-
topk(int) –Manifest
params.topk,int. -
target(Target, default:None) –Which set of kernels serves this op — a target name,
BUILTINfor the in-tree kernels, orNoneto decide from the input device.
forward
¶
Select each query row's topk highest-scoring keys inside its window.
Parameters:
-
index_score(Tensor) –Scores [batch, seq_len, seq_len_kv, kv_group],
float32. -
starts(Tensor) –First key of each row's window [batch, seq_len],
int32. -
ends(Tensor) –One past the last key of each row's window [batch, seq_len],
int32.
Returns:
-
Tensor–Selected key positions [batch, seq_len, kv_group, topk],
int32.
Logits masks¶
tileops.sampling.TopKMaskFwdOp
¶
Top-k logit filter: keeps the k[b] largest logits of row b, the rest -inf.
Every logit equal to the k[b]-th largest is kept, so a tie at the threshold keeps
more than k[b], and a row with k[b] >= V is returned unchanged, as FlashInfer's
top_k_mask_logits does. The output has the shape and dtype of logits, and each
kept logit is passed through bit for bit.
NaN ranks above every number, as torch.sort places it, and is masked wherever the
row is filtered, as logits >= kth is false at a NaN; a row with k[b] >= V keeps
its NaNs.
__init__
¶
Build the op. Shapes and dtypes are taken from each call.
Parameters:
-
target(Target, default:None) –Which set of kernels serves this op — a target name,
BUILTINfor the in-tree kernels, orNoneto decide from the input device.
forward
¶
Mask each row of logits to its k largest.
Parameters:
-
logits(Tensor) –[B, V]logits, float16, bfloat16 or float32. -
k(Tensor) –[B]int32 number of logits each row keeps, at least 1.
Returns:
-
Tensor–[B, V]logits oflogits' dtype,-infwhere masked.
tileops.sampling.MinPMaskFwdOp
¶
Min-p logit filter: masks every token less probable than min_p[b] times row b's top.
A token's probability is below min_p[b] * max(prob[b]) exactly when its logit is
below max_logit + log(min_p[b]); those logits become -inf and the rest pass
through bit for bit. 0 <= min_p <= 1 is the caller's obligation. The output has the
shape and dtype of logits.
min_p = 0 masks nothing, the value vLLM gives a request that disables min-p, and
min_p = 1 keeps only the logits equal to the row max. A row holding a NaN has a NaN
threshold, so every comparison against it is false and the row passes through whole, as
torch.amax and < leave it.
__init__
¶
Build the op. Shapes and dtypes are taken from each call.
Parameters:
-
target(Target, default:None) –Which set of kernels serves this op — a target name,
BUILTINfor the in-tree kernels, orNoneto decide from the input device.
forward
¶
Mask the tokens of each row of logits below its min_p threshold.
Parameters:
-
logits(Tensor) –[B, V]logits, float16, bfloat16 or float32. -
min_p(Tensor) –[B]float32 fraction of the row's top probability a token must reach.
Returns:
-
Tensor–[B, V]logits oflogits' dtype,-infwhere masked.
tileops.sampling.TopPMaskFwdOp
¶
Top-p logit filter: keeps the most probable tokens of row b until they hold p[b].
With prob = softmax(logits[b]), a token survives while the total probability of the
tokens strictly more probable than it is below p[b], so tokens tied at the boundary
are kept together, as FlashInfer's top_p_renorm_probs keeps them. Masked logits
become -inf; the rest pass through bit for bit. 0 <= p <= 1 is the caller's
obligation. The output has the shape and dtype of logits.
p = 0 masks the row whole. p = 1 keeps every token whose probability survives
the row's float32 sum, and masks the ones the sum rounds away with the zero-probability
ones. A row whose maximum is not finite, a NaN or an infinity among its logits, has an
all-NaN softmax, so nothing in it is masked and it passes through whole.
__init__
¶
Build the op. Shapes and dtypes are taken from each call.
Parameters:
-
target(Target, default:None) –Which set of kernels serves this op — a target name,
BUILTINfor the in-tree kernels, orNoneto decide from the input device.
forward
¶
Mask each row of logits to its top-p nucleus.
Parameters:
-
logits(Tensor) –[B, V]logits, float16, bfloat16 or float32. -
p(Tensor) –[B]float32 probability mass each row keeps.
Returns:
-
Tensor–[B, V]logits oflogits' dtype,-infwhere masked.
tileops.sampling.TopKTopPMaskFwdOp
¶
Top-k then top-p logit filter: TopPMaskFwdOp(TopKMaskFwdOp(logits, k), p).
The top-k filter of TopKMaskFwdOp runs first; top-p's probabilities are then the
softmax over the tokens it kept, with ties at either boundary kept together.
0 < p < 1 is the caller's obligation. The output has the shape and dtype of
logits, and each kept logit is passed through bit for bit, except a NaN, which comes
back as a quiet NaN rather than its own payload.
NaN ranks above every number, as torch.sort places it, so it is masked wherever
k filters the row; a row with k[b] >= V keeps its NaNs, and a row whose largest
surviving logit is NaN or +inf has no finite probability for top-p to compare, so
top-p removes nothing from it.
The top-p bound is settled from float32 weights summed in bin order, where the reference
sums them in sorted order, so the two can disagree only on a token whose exclusive
probability sits within a few rounding steps of p.
__init__
¶
Build the op. Shapes and dtypes are taken from each call.
Parameters:
-
target(Target, default:None) –Which set of kernels serves this op — a target name,
BUILTINfor the in-tree kernels, orNoneto decide from the input device.
forward
¶
Mask each row of logits to its top k, then to the top-p nucleus of those.
Parameters:
-
logits(Tensor) –[B, V]logits, float16, bfloat16 or float32. -
k(Tensor) –[B]int32 number of logits each row keeps, at least 1. -
p(Tensor) –[B]float32 probability mass each row keeps among its topk.
Returns:
-
Tensor–[B, V]logits oflogits' dtype,-infwhere masked.
Sampling¶
tileops.sampling.SamplingFromProbsFwdOp
¶
Categorical draw: one index per row, with probability proportional to probs[b].
The row need not sum to 1: the draw is scaled by the row's total. A zero-weight token is
never drawn. Each row finite, non-negative and with a positive total is the caller's
obligation. The draw is a function of the Philox state (seed, offset): the same pair
and inputs give the same samples. Which stream a pair selects belongs to the
implementation, so two implementations need not draw the same samples from one pair.
The in-tree kernel takes the stream workloads/sampling.py states: the row's uniform
is the first output word of Philox4x32-10 keyed by (seed, offset) and counted by the
row index. The counter names no launch fact, so the same pair and inputs give the same
samples whatever the batch and whatever grid the call takes.
__init__
¶
Build the op. Shapes and dtypes are taken from each call.
Parameters:
-
target(Target, default:None) –Which set of kernels serves this op — a target name,
BUILTINfor the in-tree kernels, orNoneto decide from the input device.
forward
¶
Draw one token per row of probs.
Parameters:
-
probs(Tensor) –[B, V]float32 unnormalized probabilities. -
seed(Tensor) –[1]int64 Philox seed. -
offset(Tensor) –[1]int64 Philox offset.
Returns:
-
Tensor–[B]int32 drawn indices.
tileops.sampling.ChainSpeculativeSamplingFwdOp
¶
Chain speculative sampling: verifies each request's N draft tokens in order.
Draft token i is accepted with probability min(1, target / draft) at its id, as
FlashInfer's chain_speculative_sampling tests u * draft < target. At the first
rejection a token is drawn from normalize(max(0, target - draft)) of that position
and the rest of the row is -1; when every draft is accepted a bonus token is drawn
from target row N. num_accepted is the accepted prefix length, the bonus
excluded. Every probability row finite, non-negative and normalized, and each draft
token of positive draft probability, is the caller's obligation.
The draws are a function of the Philox state (seed, offset): the same pair and
inputs give the same result. Which stream a pair selects belongs to the implementation,
so two implementations need not draw the same tokens from one pair.
The in-tree kernel takes the stream workloads/sampling.py states: uniform j of
a row is the first output word of Philox4x32-10 keyed by (seed, offset) and counted
by (j, row), draws 0 to N - 1 testing the drafts and draw N placing the
token. The counter names no launch fact and the acceptance test is the reference's own
float32 comparison, so num_accepted and the accepted prefix are the reference's
exactly, whatever the batch and whatever grid the call takes.
__init__
¶
Build the op. Shapes and dtypes are taken from each call.
Parameters:
-
target(Target, default:None) –Which set of kernels serves this op — a target name,
BUILTINfor the in-tree kernels, orNoneto decide from the input device.
forward
¶
Verify the draft chains and draw the token after each accepted prefix.
Parameters:
-
draft_probs(Tensor) –[B, N, V]float32 draft model probabilities. -
draft_token_ids(Tensor) –[B, N]int32 draft tokens, each in[0, V). -
target_probs(Tensor) –[B, N + 1, V]float32 target model probabilities. -
seed(Tensor) –[1]int64 Philox seed. -
offset(Tensor) –[1]int64 Philox offset.
Returns:
-
Tensor–output_token_ids,[B, N + 1]int32: the accepted drafts, the drawn token, -
Tensor–then
-1; andnum_accepted,[B]int32.