Text Generation #
Score filtering, top-k sampling, logit extraction, decoding, and causal masks used by language-model examples.
Lower scores rank worse; equal scores prefer the smaller token id.
Instances For
Find the best indexed candidate in one pass, breaking ties by the smaller token id.
Instances For
Return up to k allowed, non-NaN score indices, largest first.
The result has min k vocabularySize slots; unused trailing slots contain none. Equal scores,
including signed zeros and infinities, prefer smaller token ids. A bounded heap uses
O(vocabularySize * log(k + 1)) time and O(min k vocabularySize) auxiliary storage.
The optional predicate filters token ids without replacing their scores by a finite sentinel. This matters when model logits are unbounded: a disallowed token must never become selectable merely because every allowed score is smaller than an arbitrary masking constant.
Example:
-- Highest scores first. `allowToken` filters rather than masking, so a banned token cannot become
-- selectable just because the masking constant happened to sit above every real score.
def best (scores : Tensor Float [256]) : Tensor (Option (Fin 256)) [8] :=
text.topK scores 8 (allowToken := fun token => token.val < 128)
Instances For
Greedy argmax, or none when no allowed non-NaN token exists. Equal scores prefer smaller token
ids. This scans the vocabulary once with constant auxiliary storage.
Example:
-- `none` means no allowed non-NaN score exists, which is a failure worth seeing rather than a
-- silent fall back to token zero.
def next (scores : Tensor Float [256]) : Option (Fin 256) :=
text.greedy? scores
Instances For
Apply a repetition penalty by subtracting
$\mathrm{repeatPenalty}\,\mathrm{count}(\mathrm{token})$ for tokens
appearing in recentTokens.
next validates the penalty and applies it to the logits before greedy selection or
temperature scaling.
Instances For
True for byte tokens in the printable ASCII range, plus newline.
Instances For
Escape one byte token for display inside a quoted string. Used only by formatBytes.
Instances For
Escape byte ids as a one-line quoted display string.
Example:
-- Generated bytes are not always valid UTF-8, so display escapes them instead of guessing:
-- `#[104, 105, 10]` prints as `"hi\n"`.
def display {n : Nat} (tokens : Tensor Nat [n]) : String := text.formatBytes tokens
Instances For
Stable softmax weight relative to a finite maximum and a positive finite temperature.
Instances For
Sample an indexed candidate sequence, storing weights once and never sorting the sequence.
Instances For
Sample an allowed token id using a positive finite temperature and top-k sampling.
NaNs and disallowed tokens are excluded. Ties at the cutoff prefer smaller token ids. If the maximum is infinite, return its smallest token id directly (also when every allowed score is negative infinity), avoiding undefined softmax normalization.
topK = 0 or topK ≥ vocabularySize samples the full vocabulary in token-id order in linear time.
A smaller positive cutoff samples the bounded heap's output in descending score order. Randomness
is deterministic given the scores, filter, temperature, cutoff, seed, and counter; the two traversal
orders can produce different tokens for the same random draw.
Instances For
Select the next token, rejecting an empty allow-list, a non-finite or negative repetition penalty,
or an invalid sampling temperature. Greedy decoding (topK = 1) ignores temperature.
Example:
-- One decoding policy shared by every text example: repeat penalty first, then greedy or top-k
-- sampling. `counter` keeps each step's randomness distinct while staying reproducible.
def next (scores : Tensor Float [256])
(options : text.GenerationOptions) (step : Nat) :
Except String (Fin 256) :=
text.next scores options (counter := step) (recentTokens := Tensor.full [0] 0)
Instances For
Autoregressively extend token ids with a model-provided score callback.
The callback receives an exact-length context window and the sequence position whose logits should
be used for the next token. The shared policy crops to the last sequenceLength tokens, pads,
applies repeat penalties, samples by top-k/temperature, and writes one token per step.
The output includes the prompt followed by exactly newTokenCount tokens. A zero-length model
context is rejected when generation is requested.
Example:
-- The model arrives as a callback: given an exact-length window and the position whose logits to
-- read, return that position's scores. Cropping, padding, penalties, and sampling stay here.
def generate (options : text.GenerationOptions)
(scoreWindow : Tensor Nat [16] → Fin 16 → IO (Tensor Float [256])) :
IO (Tensor Nat [(text.Tokenizer.byte.encode options.prompt).size + options.newTokenCount]) :=
text.generate 16 (paddingTokenId := 0)
(promptTokens := Tensor.from (text.Tokenizer.byte.encode options.prompt))
(options := options) (scoreWindow := scoreWindow)
Instances For
Decode a matrix of token logits by taking argmax independently at each sequence position.
The shape is (sequenceLength × vocabularySize), i.e. one logits vector per token position. This
helper is for inspection/debugging and is not differentiable.
Instances For
Decode logits as text, choosing the largest score at each sequence position.