CharlesCNorton
Add logits-processor source, tests, and model card
9aa33e7
Raw
History Blame
2.51 kB
"""logits-processor: the generation last-mile, loadable through `kernels`.
Two fused ops that every serving stack runs on the hot path:
- ``apply_token_bitmask`` - structured / guided decoding. Set the logits of
disallowed tokens to -inf from a packed allow-mask (XGrammar convention:
bit 1 = allowed), so the next softmax cannot pick them. This is the kernel
behind constrained JSON and tool-calling output.
- ``sample`` - temperature, then the intersection of top-k / top-p (nucleus) /
min-p filtering, then a multinomial draw, fused into one logits -> token op
with a counter-based RNG that is deterministic in ``(seed, row, offset)``.
``temperature <= 0`` is greedy (argmax).
Both take ``[B, V]`` logits in float / half / bf16. Sampling parameters are
per-row: pass a scalar to broadcast, or a length-B tensor for a heterogeneous
batch (continuous batching, per-request grammars).
"""
from typing import Union
import torch
from ._ops import ops
__all__ = ["apply_token_bitmask", "sample"]
Param = Union[float, int, torch.Tensor]
def _row(x: Param, B: int, device, dtype) -> torch.Tensor:
if isinstance(x, torch.Tensor):
return x.to(device=device, dtype=dtype).contiguous()
return torch.full((B,), x, device=device, dtype=dtype)
def apply_token_bitmask(logits: torch.Tensor, bitmask: torch.Tensor) -> torch.Tensor:
"""In place: set disallowed tokens' logits to -inf.
logits: ``[B, V]`` (float/half/bf16). bitmask: ``[B, ceil(V/32)]`` int32,
bit 1 = token allowed. Returns ``logits`` for chaining.
"""
ops.apply_token_bitmask_inplace(logits, bitmask.to(torch.int32).contiguous())
return logits
def sample(logits: torch.Tensor, temperature: Param = 1.0, top_k: Param = 0,
top_p: Param = 1.0, min_p: Param = 0.0, seed: int = 0,
offset: int = 0) -> torch.Tensor:
"""Fused temperature + top-k ∩ top-p ∩ min-p + multinomial sample.
top_k <= 0, top_p >= 1, and min_p <= 0 each disable that filter.
temperature <= 0 selects the argmax. Returns int64 token ids ``[B]``.
Same ``(seed, offset)`` and logits give the same tokens.
"""
assert logits.dim() == 2, "logits must be [B, V]"
B, dev = logits.size(0), logits.device
return ops.sample(
logits.contiguous(),
_row(temperature, B, dev, torch.float32),
_row(top_p, B, dev, torch.float32),
_row(top_k, B, dev, torch.int32),
_row(min_p, B, dev, torch.float32),
int(seed), int(offset),
)