from outlines_core import Guide
try:
import torch
except Exception as e:
raise ImportError(
"`torch` is required to use the kernels from"
"`outlines_core.kernels.torch. You can install "
"`torch` using the official guide at https://pytorch.org/get-started/locally/"
) from e
def allocate_token_bitmask(vocab_size: int) -> torch.Tensor:
return torch.full(
(1, (vocab_size + 31) // 32),
-1,
dtype=torch.int32,
pin_memory=torch.cuda.is_available(),
)
@torch.compile(dynamic=True)
def _apply_token_bitmask_inplace_kernel(logits, mask):
cutoff = 32 * mask.shape[1]
logits[:, cutoff:] = -torch.inf
bit_masks = (
(
torch.bitwise_right_shift(
mask.unsqueeze(-1),
torch.arange(32, device=mask.device, dtype=torch.int32),
)
& 1
)
.bool()
.view(mask.shape[0], -1)
.narrow(1, 0, logits.shape[1])
)
logits.masked_fill_(~bit_masks, -torch.inf)
def apply_token_bitmask_inplace(logits: torch.Tensor, mask: torch.Tensor) -> None:
if mask.dtype != torch.int32:
raise ValueError(
f"Invalid mask dtype: Expected `torch.int32`, but got `{mask.dtype}`."
)
elif mask.dim() != 2:
raise ValueError(
f"Invalid mask dimensions: Expected a 2D array, but got {mask.dim()}D."
)
elif logits.dim() != 2:
raise ValueError(
f"Invalid logits dimensions: Expected a 2D array, but got {logits.dim()}D."
)
elif mask.shape[0] != logits.shape[0]:
raise ValueError(
f"Invalid batch size: Expected `mask.shape[0]` ({mask.shape[0]}) to match `logits.shape[0]` ({logits.shape[0]})."
)
_apply_token_bitmask_inplace_kernel(logits, mask)
def fill_next_token_bitmask(guide: Guide, mask: torch.Tensor) -> None:
if mask.dtype != torch.int32:
raise ValueError(
f"Invalid mask dtype: Expected `torch.int32`, but got `{mask.dtype}`."
)
elif mask.dim() != 2:
raise ValueError(
f"Invalid mask dimensions: Expected a 2D array, but got {mask.dim()}D."
)
elif mask.shape[0] != 1:
raise ValueError(
f"Invalid batch size: Batch mask writes are not supported. Expected shape[0] == 1, but got shape {mask.shape}."
)
elif not mask.is_contiguous():
raise ValueError(
"Mask array must be contiguous in memory. Use `mask.contiguous()` to fix it."
)
elif mask.device != torch.device("cpu"):
raise ValueError(
f"Invalid device: Expected `mask` tensor to be on device `cpu`, but found it on `{mask.device}`."
)
guide.write_mask_into(mask.data_ptr(), mask.numel(), mask.element_size())